makeFUNC[type_]:=Module[{syms,symbolsDOMAIN,symbolsRANGE,domain,range,e1,e2,e1NOT,v1coor,v2coor,domainLABLE,rangeLABLE,list,list2,shift,n,index,same,drop,degen1,degen2},

syms={CharacterRange["α","ω"],CharacterRange["a","z"],CharacterRange["Α","Ω"],CharacterRange["A","Z"]};
{symbolsDOMAIN,symbolsRANGE}=RandomSample[syms,2];

Which[type=="1to1 and not Onto"  ,
domain=RandomSample[Range@Length@symbolsDOMAIN, 10];
range=RandomSample[Range@Length@symbolsRANGE,  15];
e1=RandomSample[domain,n=RandomInteger[{1,8}]];
e2=RandomSample[range,n];,

type=="not 1to1 and not Onto" ,
domain=RandomSample[Range@Length@symbolsDOMAIN, 10];
range=RandomSample[Range@Length@symbolsRANGE,  15];
e1=RandomSample[domain,n=RandomInteger[{5,8}]];
e2=RandomSample[range,n];,


type=="not 1to1 and Onto" ,
n=RandomInteger[{3,10}];
domain=RandomSample[Range@Length@symbolsDOMAIN, 15];
range=RandomSample[Range@Length@symbolsRANGE,  n];
e1=RandomSample[domain,15];
e2=RandomSample[range,n];,

type=="not function"  ,
domain=RandomSample[Range@Length@symbolsDOMAIN, 10];
range=RandomSample[Range@Length@symbolsRANGE,  15];
e1=RandomSample[domain,n=RandomInteger[{4,8}]];
e2=RandomSample[range,n];,


True, (*1to1 and onto*)
n=RandomInteger[{3,15}];
domain=RandomSample[Range@Length@symbolsDOMAIN,n];
range=RandomSample[Range@Length@symbolsRANGE,  n];
e1=RandomSample[domain,n];
e2=RandomSample[range,n];

];



(*KLUDGE: change the layout here by adjusting shift*)
v1coor=Table[{0,i+shift}, {i,1,Length@domain}];
v2coor=Table[{5,i}+{0,-2}, {i,1,Length@range}];

v1coor=RandomSample[v1coor,Length@v1coor];
v2coor=RandomSample[v2coor,Length@v2coor];

domainLABLE=Table[Text[symbolsDOMAIN[[i]],v1coor[[i]]+{-0.3,0}],{i,1,Length@e1}];
rangeLABLE=Table[Text[symbolsRANGE[[range[[i]]]],v2coor[[i]]+{0.3,0}],{i,1,Length@range}];

Which[

type=="1to1 and not Onto",
list=Arrow/@Table[{v1coor[[i]],v2coor[[i]]},{i,1,n}];
list=Table[Tooltip[list[[i]],"f("<>symbolsDOMAIN[[i]]<>")="<>symbolsRANGE[[range[[i]]]]], {i,1,n}];

,

type=="1to1 and Onto",
list=Arrow/@Table[{v1coor[[i]],v2coor[[i]]},{i,1,n}];
list=Table[Tooltip[list[[i]],"f("<>symbolsDOMAIN[[i]]<>")="<>symbolsRANGE[[range[[i]]]]], {i,1,n}];

,

type=="not 1to1 and not Onto" ,
same=RandomSample[Range[n],4];
index=Range[n];
index[[same[[1]]]]=index[[same[[2]]]];
index[[same[[3]]]]=index[[same[[4]]]];

list=Arrow/@Table[{v1coor[[i]],v2coor[[index[[i]]]]},{i,1,n}];
list=Table[Tooltip[list[[i]],"f("<>symbolsDOMAIN[[index[[i]]]]<>")="<>symbolsRANGE[[range[[index[[i]]]]]]], {i,1,n}];
,

type=="not 1to1 and Onto" ,
index=Table[If[i≤n, i, Mod[i,n]+1],{i,1,15}];

list=Arrow/@Table[{v1coor[[i]],v2coor[[index[[i]]]]},{i,1,15}];
list=Table[Tooltip[list[[i]],"f("<>symbolsDOMAIN[[i]]<>")="<>symbolsRANGE[[range[[index[[i]]]]]]], {i,1,15}];
,

type=="not function"  ,


list=Table[{v1coor[[i]],v2coor[[i]]},{i,1,n}];
{degen1,degen2}=RandomSample[Range[2,Length@list],2];
list=list~Join~{{list[[degen1]][[1]],list[[degen2]][[2]]}};

list=Arrow/@list;

list2=Table[Tooltip[list[[i]],"f("<>symbolsDOMAIN[[i]]<>")="<>symbolsRANGE[[range[[i]]]]], {i,1,Length@list-1}];
list=list2~Join~{Tooltip[list[[Length@list]],"f("<>symbolsDOMAIN[[degen1]]<>")="<>symbolsRANGE[[range[[degen2]]]]]};
list=Drop[list,{RandomInteger[{2,Length@list-2}]}];


];


shift=RandomInteger[{0,2}];
<|
"plot"->Graphics[{Opacity@0,Point[v1coor],Point[v2coor],Opacity@1,domainLABLE,rangeLABLE,Blue,list}],
"domain"->symbolsDOMAIN[[Range[Length@e1]]],
"range"->symbolsRANGE[[range]]

|>


]

"

f=makeFUNC["not function"];
f["plot"]
f["domain"]
f["range"]

f=makeFUNC["not 1to1 and Onto"];
f["plot"]
f["domain"]
f["range"]

f=makeFUNC["not 1to1 and not Onto" ];
f["plot"]
f["domain"]
f["range"]

f=makeFUNC["1to1 and not Onto"];
f["plot"]
f["domain"]
f["range"]

f=makeFUNC["1to1 and Onto"];
f["plot"]
f["domain"]
f["range"]

makeTubeArrow[p1_,p2_, mid_]:=Arrow[Tube@BSplineCurve[{p1,mid,p2}]];
makeArrow[p1_,p2_, mid_]:=Arrow[BSplineCurve[{p1,mid,p2}]];

(* might return less n, due to duplicates*)
randCirc[rad_,n_]:=Module[{x,y},

x=DeleteDuplicates@RandomReal[{-0.9*rad,0.9*rad},n];
y=Table[Sqrt[rad-x^2][[i]]*((-1)^RandomInteger[{1,100}]),{i,1,Length@x}];

Table[RandomReal[{1/4,2/3}]*{x[[i]],y[[i]]},{i,1,Length@x}]

];

(* assume a < b *)
randInterval[a_,b_,n_]:=DeleteDuplicates@RandomReal[{a,b},n];


(* might return less n, due to duplicates*)
randSphere[rad_,n_]:=Module[{x,y,z},

x=DeleteDuplicates@RandomReal[{-0.9*rad,0.9*rad},n];
y=(rad-x^2)/RandomInteger[{2,4}];
z=Table[Sqrt[rad-(x^2+y^2)][[i]]*((-1)^RandomInteger[{1,100}]),{i,1,Length@x}];

Table[RandomReal[{1/4,2/3}]*{x[[i]],y[[i]],z[[i]]},{i,1,Length@x}]

];


(* list has to be longer than one *)
funcRandomChoice[list_]:=DynamicModule[{f,prev,trig,g},

(*prev had to be used somehow the f was cached *)
Panel@Column[{
Button["Again",
If[Length@list > 1, While[f==prev,prev=f;f=RandomChoice@list], f=list[[1]]];prev=f;trig=True,Method->"Queued"],

(* If is necessary to avoid execution of f upon moving of the window*)
Dynamic[If[trig==True,trig=False;g=f[],g ]]
}],

Initialization:>(f=RandomChoice@list;prev=f;trig=True;


makeTubeArrow[p1_,p2_, mid_]:=Arrow[Tube@BSplineCurve[{p1,mid,p2}]];
makeArrow[p1_,p2_, mid_]:=Arrow[BSplineCurve[{p1,mid,p2}]];

(* might return less n, due to duplicates*)
randCirc[rad_,n_]:=Module[{x,y},

x=DeleteDuplicates@RandomReal[{-0.9*rad,0.9*rad},n];
y=Table[Sqrt[rad-x^2][[i]]*((-1)^RandomInteger[{1,100}]),{i,1,Length@x}];

Table[RandomReal[{1/4,2/3}]*{x[[i]],y[[i]]},{i,1,Length@x}]

];

(* assume a < b *)
randInterval[a_,b_,n_]:=DeleteDuplicates@RandomReal[{a,b},n];


(* might return less n, due to duplicates*)
randSphere[rad_,n_]:=Module[{x,y,z},

x=DeleteDuplicates@RandomReal[{-0.9*rad,0.9*rad},n];
y=(rad-x^2)/RandomInteger[{2,4}];
z=Table[Sqrt[rad-(x^2+y^2)][[i]]*((-1)^RandomInteger[{1,100}]),{i,1,Length@x}];

Table[RandomReal[{1/4,2/3}]*{x[[i]],y[[i]],z[[i]]},{i,1,Length@x}]

];


m1[]:=DynamicModule[{set1,set2,g1,g2,points,points2,coors,trans,arrows},
(* 1-1 and on-to*)

Column[{
set1=Join[#,{0}]&/@CirclePoints[1,30];

trans=TranslationTransform[{3,0,0}];
set2=trans@(Join[#,{0}]&/@CirclePoints[1,30]);

g1=ListPlot3D[set1,Mesh->None, Axes->False,Boxed->False];
g2=ListPlot3D[set2,Mesh->None, Axes->False,Boxed->False];

coors=Join[#,{0.016}]&/@randCirc[1,RandomInteger[{2,6}]];
points=Point/@coors;
points2=Point/@(trans/@coors);

arrows=Table[makeTubeArrow[points[[i]][[1]], points2[[i]][[1]], (points[[i]][[1]]+ points2[[i]][[1]]+{0,0,1})/2],{i,1,Length@points}];

"One-to-One and Onto Function",
,
Show[g1,g2,Graphics3D[{PointSize[Large],Cyan,points,points2,LightGreen,Arrowheads[Medium],arrows}], PlotRange->All,ImageSize->500,AspectRatio->1/2]
}]

];


m2[]:=DynamicModule[{set1,set2,g1,g2,points,points2,coors,coors2,trans,arrows},
(*1-1 and not on-to *)

Column[{
set1=Join[#,{0}]&/@CirclePoints[1,30];

trans=TranslationTransform[{3,0,0}];
set2=trans@(Join[#,{0}]&/@CirclePoints[1,30]);

g1=ListPlot3D[set1,Mesh->None, Axes->False,Boxed->False];
g2=ListPlot3D[set2,Mesh->None, Axes->False,Boxed->False];

coors=Join[#,{0.016}]&/@randCirc[1,RandomInteger[{2,6}]];
coors2=Join[#,{0.016}]&/@randCirc[1,7];
points=Point/@coors;
points2=Point/@(trans/@coors2);

arrows=Table[makeTubeArrow[points[[i]][[1]], points2[[i]][[1]], (points[[i]][[1]]+ points2[[i]][[1]]+{0,0,1})/2],{i,1,Length@points}];

"One-to-One but not Onto Function",

Show[g1,g2,Graphics3D[{PointSize[Large],Cyan,points,points2,LightGreen,Arrowheads[Medium],arrows}], PlotRange->All,ImageSize->500,AspectRatio->1/2]}]
];

m3[]:=DynamicModule[{set1,set2,g1,g2,points,points2,coors,coors2,trans,arrows},

Column[{
(* not 1-1 and on-to*)
set1=Join[#,{0}]&/@CirclePoints[1,30];

trans=TranslationTransform[{3,0,0}];
set2=trans@(Join[#,{0}]&/@CirclePoints[1,30]);

g1=ListPlot3D[set1,Mesh->None, Axes->False,Boxed->False];
g2=ListPlot3D[set2,Mesh->None, Axes->False,Boxed->False];

coors=Join[#,{0.016}]&/@randCirc[1,6];
coors2=RandomChoice[Join[#,{0.016}]&/@randCirc[1,RandomInteger[{1,3}]],6];
points=Point/@coors;
points2=Point/@(trans/@coors2);

arrows=Table[makeTubeArrow[points[[i]][[1]], points2[[i]][[1]], (points[[i]][[1]]+ points2[[i]][[1]]+{0,0,1})/2],{i,1,Length@points}];

"Not One-to-One but Onto Function",

Show[g1,g2,Graphics3D[{PointSize[Large],Cyan,points,points2,LightGreen,Arrowheads[Medium],arrows}], PlotRange->All,ImageSize->500,AspectRatio->1/2]}]

];


m4[]:=DynamicModule[{set1,set2,g1,g2,points,points2,coors,coors2,trans,arrows},

Column[{
coors=Join[{#},{0,0}]&/@randInterval[0,1,5];
coors2=Join[{#},{0,0}]&/@randInterval[0,1,5];

trans=TranslationTransform[{1,0.4,0.5}];
points=Point/@coors;
points2=Point/@(trans/@coors2);

g1=Graphics3D[Line[{{0,0,0},{1,0,0}}]];
g2=Graphics3D[Line[trans/@{{0,0,0},{1,0,0}}]];

arrows=Table[makeTubeArrow[points[[i]][[1]], points2[[i]][[1]], (points[[i]][[1]]+ points2[[i]][[1]]+{0,0,1})/2],{i,1,Length@points}];

"Function from an interval to another interval",
Show[g1,g2,Graphics3D[{PointSize[Large],Cyan,points,points2,LightGreen,Arrowheads[Medium],arrows}], PlotRange->All,ImageSize->500,Axes->False,Boxed->False]
}]

];

m5[]:=DynamicModule[{set1,set2,g1,g2,points,points2,coors,coors2,trans,arrows,a},

Column[{

a=RandomInteger[{1,4}];
coors=Join[{#},{0,0}]&/@randInterval[0,1,5];
coors2={Cos[Pi*#[[1]]/2],Sin[Pi*#[[1]]/2],Sin[a*Pi*#[[1]]/2]}&/@(Join[{#},{0,0}]&/@randInterval[0,1,5]);

trans=TranslationTransform[{1,0.4,0.5}];
points=Point/@coors;
points2=Point/@(trans/@coors2);

g1=Graphics3D[Line[{{0,0,0},{1,0,0}}]];
g2=ParametricPlot3D[trans[{Cos[Pi*t/2],Sin[Pi*t/2],Sin[a*Pi*t/2]}],{t,0,1}];

arrows=Table[makeTubeArrow[points[[i]][[1]], points2[[i]][[1]], (points[[i]][[1]]+ points2[[i]][[1]]+{0,0,1})/2],{i,1,Length@points}];

"Function from an interval to a curve",

Show[g1,g2,Graphics3D[{PointSize[Large],Cyan,points,points2,LightGreen,Arrowheads[Medium],arrows}], PlotRange->All,ImageSize->500,Axes->False,Boxed->False]
}]

];

m6[]:=DynamicModule[{set1,set2,g1,g2,points,points2,coors,coors2,trans,arrows,a},

Column[{

coors=randSphere[1,5];
coors2=randSphere[1,5];

trans=TranslationTransform[{4,0, 0}];
points=Point/@coors;
points2=Point/@(trans/@coors2);

g1=Graphics3D[{Opacity[.7],Sphere[{0,0,0},1]}];
g2=Graphics3D[{Opacity[0.5],Sphere[trans@{0,0,0},1]}];

arrows=Table[makeTubeArrow[points[[i]][[1]], points2[[i]][[1]], (points[[i]][[1]]+ points2[[i]][[1]]+{0,0,1})/2],{i,1,Length@points}];

"Function from Sphere to Sphere",
Show[g1,g2,Graphics3D[{PointSize[Large],Cyan,points,points2,LightGreen,Arrowheads[Medium],arrows}], PlotRange->All,ImageSize->500,Axes->False,Boxed->False]
}]


];


m7[]:=DynamicModule[{pt},

Panel@Column[{
Dynamic[{First[pt],Sin[First[pt]]}],
LocatorPane[Dynamic[pt],Plot[Sin[x],{x,0,10},Epilog->{PointSize[Large],Point[Dynamic[{First[pt],Sin[First[pt]]}]]},ImageSize->500],Appearance->None]
}]

];


m8[]:=DynamicModule[{pts={{0,0},{1,1},{2,0},{3,2}}},

Panel@Column[{
Dynamic[pts],
LocatorPane[Dynamic[pts],Dynamic[Plot[InterpolatingPolynomial[pts,x],{x,0,3},PlotRange->3,ImageSize->500]]]
}]

];

m9[]:=DynamicModule[{pt,pt0,tmp},


Panel@Column[{
Dynamic@pt0[[1]],
pt0=RandomReal[{-5,5},{1,2}];LocatorPane[Dynamic[pt0],Dynamic@ListLinePlot[{{0,pt0[[1]][[2]]},pt0[[1]],{pt0[[1]][[1]],0}},PlotRange->{{-5,5},{-5,5}},ImageSize->500]]
}]
];





)


];

expr=Column[{Pane@"Set Theoretic Model",Spacer@100,funcRandomChoice[{m1, m2, m3}],
Spacer@100, Pane@"Interval Model",funcRandomChoice[{m4, m5, m6}],Spacer@100,Pane@"Cartesian Model",funcRandomChoice[{m9}],Spacer@100,Pane@"Parametric Graphed Model",funcRandomChoice[{m7,m8}]}];

CDFDeploy[ToFileName[{$UserDocumentsDirectory},"Functions.cdf"],expr,
"Method"->"Standalone"];

expr