CSG Free Form Generative AI

Symbolic Training Data

Clear[a,b]
booles2=Quiet@DeleteDuplicates@Groupings[Permutations[{a,b}],{And,Or,And[#1,Not[#2]]&,Xor}->2];

boolesfunc2=ToExpression/@Map[(StringReplace[ToString[#],{"a"->"#1","b"->"#2"," "->""}]<>"&")&,booles2]

Length@booles2

Clear[a,b,c]

booles3=Quiet@DeleteDuplicates@Groupings[Permutations[{a,b,c}],{And,Or,And[#1,Not[#2]]&,Xor}->2]

Length@booles3

boolesfunc3=ToExpression/@Map[(StringReplace[ToString[#],{"a"->"#1","b"->"#2","c"->"#3"," "->""}]<>"&")&,booles3]

booles4=Quiet@DeleteDuplicates@Groupings[Permutations[{a,b,c,d}],{And,Or,And[#1,Not[#2]]&,Xor}->2];

Length@booles4

vars={a,b,c,d};
regs={{Ball,var[trans][Ball[var[center],var[radius]]]},{Cylinder,var[trans][Cylinder[var[v],var[radius]]]},{Cube,var[trans][Cube[var[center],var[length]]]}};

regs={{myBall,myBall[var]},{myCylinder,myCylinder[var]},{myCube,myCube[var]}};
regions=Flatten[Table[

{var,region[[1]],region[[2]]}/.{var->vars}

,{vars,{a,b,c}},{region,regs}],1];


input1=Quiet[Flatten[Table[If[reg1[[1]]=!=reg2[[1]],ToString@reg1[[1]]<>":"<>ToString@reg1[[2]]<>", "<>ToString@reg2[[1]]<>":"<>ToString@reg2[[2]]<>", "<>StringReplace[ToString[boole[Sequence@@{reg1[[1]],reg2[[1]]}]]," "->""]<>" ⟹ "<>StringReplace[ToString@BooleanRegion[boole,{reg1[[3]],reg2[[3]]}]," "->""]<>";;;",Nothing],{boole,boolesfunc2},{reg1 ,regions},{reg2 ,regions}],2]];


input2=Quiet[Flatten[Table[If[reg1[[1]]=!=reg2[[1]]&&reg2[[1]]=!=reg3[[1]]&&reg1[[1]]=!=reg3[[1]],ToString@reg1[[1]]<>":"<>ToString@reg1[[2]]<>", "<>ToString@reg2[[1]]<>":"<>ToString@reg2[[2]]<>", "<>ToString@reg3[[1]]<>":"<>ToString@reg3[[2]]<>", "<>StringReplace[ToString[boole[Sequence@@{reg1[[1]],reg2[[1]],reg3[[1]]}]]," "->""]<>" ⟹ "<>StringReplace[ToString@BooleanRegion[boole,{reg1[[3]],reg2[[3]],reg3[[3]]}]," "->""]<>";;;",Nothing],{boole,boolesfunc3},{reg1 ,regions},{reg2 ,regions},{reg3 ,regions}],3]];

input=Join[input1,input2];

pad=StringLength@Last@SortBy[input, StringLength]+3;
trainingData=RandomSample@(StringPadRight[#,pad]&/@input);
Length@trainingData

characters=Union[Flatten@Characters[StringTrim/@trainingData]]
Length@characters

predict=NetChain[{UnitVectorLayer[],GatedRecurrentLayer[128],GatedRecurrentLayer[128],NetMapOperator[LinearLayer[]],SoftmaxLayer[]}]

teacherForcingNet=NetGraph[

<|"predict"->predict,"predict2"->predict,"rest"->SequenceRestLayer[],"rest2"->SequenceRestLayer[],"most"->SequenceMostLayer[],
"most2"->SequenceMostLayer[],"reverse"->SequenceReverseLayer[],"reverse2"->SequenceReverseLayer[],
"loss"->CrossEntropyLossLayer["Index"],"loss2"->CrossEntropyLossLayer["Index"]|>,

{
NetPort["Input"]->"most"->"predict"->NetPort["loss","Input"],NetPort["Input"]->"rest"->NetPort["loss","Target"],
NetPort["Input"]->"most2"->"reverse"->"predict2"->NetPort["loss2","Input"],
NetPort["Input"]->"rest2"->"reverse2"->NetPort["loss2","Target"]
},

"Input"->NetEncoder[{"Characters",characters}]]

teacherForcingNet=NetGraph[
<|"predict"->predict,"rest"->SequenceRestLayer[],"most"->SequenceMostLayer[],"loss"->CrossEntropyLossLayer["Index"]|>,
{NetPort["Input"]->"most"->"predict"->NetPort["loss","Input"],NetPort["Input"]->"rest"->NetPort["loss","Target"]},
"Input"->NetEncoder[{"Characters",characters}]]

At least 40 rounds

result=NetTrain[teacherForcingNet,<|"Input"->trainingData|>,All,BatchSize->64,MaxTrainingRounds->5,TargetDevice->"CPU",ValidationSet->Scaled[0.1]]

result["Properties"]

Extract the prediction chain from the results:

trained=NetExtract[result["TrainedNet"],"predict"]

Build a single-character prediction chain from it, to use the NestList [ ] for keep generating the next character:

predictNet=NetJoin[
NetTake[trained,3,"Input"->Automatic],
{SequenceLastLayer[],NetExtract[trained,{4,"Net"}],SoftmaxLayer[]},
"Input"->NetEncoder[{"Characters",characters}],
"Output"->NetDecoder[{"Class",characters}]]

generate[net_,start_,len_]:=StringJoin@NestList[NetStateObject[net],start,len]
generateSample[net_,start_,len_]:=Block[{obj=NetStateObject[net]},
StringJoin@NestList[obj[#,"RandomSample"]&,start,len]]

output=StringTrim@generateSample[predictNet,"a:Cylinder, a||(c&&b) ⟹ ",pad]

output=StringTrim@generateSample[predictNet,"b:myBall, c:myCylinder, a:myBall, a&&!(b&&!c) ",pad]

output=StringTrim@generateSample[predictNet,"c:Cube, a:Cube, b:Cylinder, a||(c&&b) ⟹ ",pad]

output=StringTrim@generateSample[predictNet,"b:ball, a&&!b ⟹ ",pad]

output=StringTrim@generateSample[predictNet,"a&&!b ⟹ ",180]

BooleanRegion[And[#1,Not[#2]]&,{a[trans][Cylinder[a[axis],a[radius]]],b[trans][Ball[b[center],b[radius]]]}]

binding=<|
trans->TransformationFunction[],
axis->{},
radius->r,


|>;