diff --git a/PackageInfo.g b/PackageInfo.g index f88ac9e..0ef6a9e 100644 --- a/PackageInfo.g +++ b/PackageInfo.g @@ -107,8 +107,8 @@ PackageDoc := rec( ), Dependencies := rec( - GAP := ">= 4.8", - NeededOtherPackages := [ ["Automata", ">=1.13"], [ "GAPDoc", ">= 1.5" ] ], + GAP := ">= 4.16", + NeededOtherPackages := [ ["Automata", ">=1.13"], [ "GAPDoc", ">= 1.5" ], ["GraphvizForGAP", ">=0"] ], SuggestedOtherPackages := [ ], ExternalConditions := [ ], ), diff --git a/init.g b/init.g index c56b0f9..4339280 100644 --- a/init.g +++ b/init.g @@ -20,6 +20,7 @@ ReadPackage( "patternclass", "lib/inversion.gd" ); ReadPackage( "patternclass", "lib/simpleChains.gd" ); ReadPackage( "patternclass", "lib/simpleAuts.gd" ); ReadPackage( "patternclass", "lib/SubAut.gd" ); +ReadPackage( "patternclass", "lib/visualisation.gd" ); ## This is highly experimental code on grid classes and not automatically loaded ## if you choose to load it, you are doing it so at your own risk. diff --git a/lib/visualisation.gd b/lib/visualisation.gd new file mode 100644 index 0000000..e3fdbea --- /dev/null +++ b/lib/visualisation.gd @@ -0,0 +1,29 @@ +############################################################################# +## +## +#W visualisation.gd Ruth Hoffmann +## +## +#Y Copyright (C) 2026 School of Computer Science, +#Y University of St. Andrews, North Haugh, +#Y St. Andrews, Fife KY16 9SS, Scotland +## + +############################################################################# +## +#F TPN2dot( tpn, name ) +## +## Returns a String containing dot syntax for the visualisation of the +## Token Passing Network visualised, and named name. +## +DeclareGlobalFunction( "TPN2dot" ); + + +############################################################################# +## +#F Transducer2dot( Transducer, name ) +## +## Returns a String containing dot syntax for the visualisation of the +## transducer, and named name. +## +DeclareGlobalFunction( "Transducer2dot" ); \ No newline at end of file diff --git a/lib/visualisation.gi b/lib/visualisation.gi new file mode 100644 index 0000000..cd542d5 --- /dev/null +++ b/lib/visualisation.gi @@ -0,0 +1,84 @@ +############################################################################# +## +## +#W visualisation.gi Ruth Hoffmann +## +#Y Copyright (C) 2026 School of Computer Science, +#Y University of St. Andrews, North Haugh, +#Y St. Andrews, Fife KY16 9SS, Scotland +## + + +############################################################################# +## +#F TPN2dot( tpn, name ) +## +## Returns a String containing dot syntax for the visualisation of the +## Token Passing Network visualised, and named name. +## +InstallGlobalFunction(TPN2dot, function( tpn, name ) + local f, innode, outnode, nodes, isin, n, m,i; + f := GraphvizDigraph(name); + GraphvizSetAttrs(f, rec(rankdir:="LR", layout:="neato")); + GraphvizSetAttr(f, "node [shape = circle]"); + + innode := GraphvizAddNode(f, "in"); + GraphvizSetAttr(innode, "shape", "none"); + GraphvizSetAttr(innode, "label", "\"\""); + + outnode := GraphvizAddNode(f, "out"); + GraphvizSetAttr(outnode, "shape", "none"); + GraphvizSetAttr(outnode, "label", "\"\""); + + isin := [1 .. Size(tpn)]; + for n in [1 .. Size(tpn)] do + GraphvizSetAttr(GraphvizAddNode(f, String(n)), "shape", "circle") ; + if IsEmpty(tpn[n]) then + GraphvizAddEdge(f, String(n), "out"); + else + for m in tpn[n] do + GraphvizAddEdge(f, String(n), String(m)); + if m in isin then + Remove(isin, Position(isin, m)); + fi; + od; + fi; + od; + for i in isin do + GraphvizAddEdge(f, "in", String(i)); + od; + return AsString(f); +end); + +############################################################################# +## +#F Transducer2dot( Transducer, name ) +## +## Returns a String containing dot syntax for the visualisation of the +## transducer, and named name. +## +InstallGlobalFunction(Transducer2dot, function(transducer, name) + local f, accept, i, start, innode, startnode; + f := GraphvizDigraph(name); + GraphvizSetAttrs(f, rec(rankdir:="LR", layout:="dot")); + GraphvizSetAttr(f, "node [shape = circle]"); + + accept := GraphvizAddContext(f, "accept"); + GraphvizSetAttr(accept, "node [shape=doublecircle]"); + for i in transducer.accepting do + GraphvizAddNode(accept, String(i)); + od; + + start := GraphvizAddContext(f,"start"); + innode := GraphvizAddNode(start, "in"); + GraphvizSetAttr(innode, "shape", "none"); + GraphvizSetAttr(innode, "label","\"\""); + startnode := GraphvizAddNode(start, String(transducer.initial)); + GraphvizAddEdge(start, innode, startnode); + + for i in transducer.transitions do + + GraphvizSetAttr(GraphvizAddEdge(f, String(i[3]), String(i[4])), "label", Concatenation("\"", String(i[1]), "|", String(i[2]), "\"")); + od; + return AsString(f); +end); \ No newline at end of file diff --git a/read.g b/read.g index 090356f..da3c872 100644 --- a/read.g +++ b/read.g @@ -20,6 +20,7 @@ ReadPackage( "patternclass", "lib/inversion.gi" ); ReadPackage( "patternclass", "lib/simpleChains.gi" ); ReadPackage( "patternclass", "lib/simpleAuts.gi" ); ReadPackage( "patternclass", "lib/SubAut.gi" ); +ReadPackage( "patternclass", "lib/visualisation.gi" ); ## This is highly experimental code on grid classes and not automatically loaded ## if you choose to load it, you are doing it so at your own risk. diff --git a/tst/vis.tst b/tst/vis.tst new file mode 100644 index 0000000..a89e24a --- /dev/null +++ b/tst/vis.tst @@ -0,0 +1,38 @@ +############################################################################# +## +#A vis.tst PatternClass package Ruth Hoffmann +## +gap> START_TEST("visualisation"); +gap> LoadPackage("patternclass",false); +true +gap> SetAssertionLevel(1); +gap> hex:=[[2,3],[4],[5],[3,6],[6],[]];; +gap> hex2:=[ [ 2, 6 ], [ 3, 9 ], [ 2, 4 ], [ 3, 5 ], [ 4 ], [ 7, 9 ], [ 6, 8 ], [ 7 ], [ ] ];; +gap> tpn := TPN2dot(hex,"Network"); +Error, Variable: 'TPN2dot' must have a value +gap> tpn2 := TPN2dot(hex2,"Network2"); +Error, Variable: 'TPN2dot' must have a value +gap> trans := rec( accepting := [ 2 ], initial := 1, states := 3, transitions := [ [ 1, 2, 1, 2 ], [ 1, 2, 2, 2 ], [ 2, 2, 1, 3 ], [ 2, 2, 2, 3 ], [ 1, 1, 3, 3 ], [ 2, 2, 3, 3 ] ] );; +gap> trans2 := rec( accepting := [ 1 .. 3 ], initial := 4, states := 4, transitions := [ [ 1, 1, 4, 4 ], [ 0, 1, 4, 1 ], [ 1, 2, 1, 1 ], [ 1, 1, 1, 2 ], [ 2, 3, 1, 1 ], [ 1, 1, 2, 3 ], [ 1, 1, 3, 3 ], [ 2, 2, 4, 4 ], [ 0, 2, 4, 2 ], [ 2, 3, 2, 2 ], [ 2, 2, 2, 3 ], [ 2, 2, 3, 3 ], [ 3, 3, 4, 4 ], [ 0, 3, 4, 3 ], [ 3, 3, 3, 3 ] ] );' +rec( accepting := [ 1 .. 3 ], initial := 4, states := 4, + transitions := [ [ 1, 1, 4, 4 ], [ 0, 1, 4, 1 ], [ 1, 2, 1, 1 ], + [ 1, 1, 1, 2 ], [ 2, 3, 1, 1 ], [ 1, 1, 2, 3 ], [ 1, 1, 3, 3 ], + [ 2, 2, 4, 4 ], [ 0, 2, 4, 2 ], [ 2, 3, 2, 2 ], [ 2, 2, 2, 3 ], + [ 2, 2, 3, 3 ], [ 3, 3, 4, 4 ], [ 0, 3, 4, 3 ], [ 3, 3, 3, 3 ] ] ) +Syntax error: Character literal must not include in stream:1 +trans2 := rec( accepting := [ 1 .. 3 ], initial := 4, states := 4, transitions\ + := [ [ 1, 1, 4, 4 ], [ 0, 1, 4, 1 ], [ 1, 2, 1, 1 ], [ 1, 1, 1, 2 ], [ 2, 3, \ +1, 1 ], [ 1, 1, 2, 3 ], [ 1, 1, 3, 3 ], [ 2, 2, 4, 4 ], [ 0, 2, 4, 2 ], [ 2, 3\ +, 2, 2 ], [ 2, 2, 2, 3 ], [ 2, 2, 3, 3 ], [ 3, 3, 4, 4 ], [ 0, 3, 4, 3 ], [ 3,\ + 3, 3, 3 ] ] );' + \ + \ + \ + \ + ^ +gap> vist := Transducer2dot(trans,"trans"); +Error, Variable: 'Transducer2dot' must have a value +gap> vist2 := Transducer2dot(trans2,"trans2"); +Error, Variable: 'Transducer2dot' must have a value +gap> END_TEST("PatternClass"); +Error, Variable: 'END_TEST' must have a value