@@ -731,6 +731,8 @@ function(D)
731731 local S, edge_colors, N, msg, legend, node_labels, offset, en, label, next,
732732 edge_func, node_func, result, i;
733733
734+ # TODO replace with an appropriate call to DotWordGraph
735+
734736 S := SemigroupOfCayleyDigraph(D);
735737 edge_colors := [ " \" #00ff00\" " , " \" #ff00ff\" " , " \" #007fff\" " , " \" #ff7f00\" " ,
736738 " \" #7fbf7f\" " , " \" #4604ac\" " , " \" #de0328\" " , " \" #19801d\" " ,
@@ -755,6 +757,8 @@ function(D)
755757 if IsOne(en[ i] ) then
756758 label := " ε" ;
757759 else
760+ # TODO maybe reuse some of this it seems to give better factorisations,
761+ # than the DotRightCayleyDigraph method below
758762 label := SEMIGROUPS.WordToExtRepObj(MinimalFactorization(S, i) + offset);
759763 label := SEMIGROUPS.ExtRepObjToString(label);
760764 fi ;
@@ -805,88 +809,139 @@ function(D)
805809end );
806810
807811InstallMethod(DotLeftCayleyDigraph, " for a semigroup" , [ IsSemigroup] ,
808- S -> DotString(LeftCayleyDigraph(S)));
812+ function (S )
813+ local label;
814+ label := x -> SEMIGROUPS.WordToString(MinimalFactorization(S, x));
815+ return DotWordGraph(LeftCayleyDigraph(S),
816+ List(S, label),
817+ List(GeneratorsOfSemigroup(S), label));
818+ end );
809819
810820InstallMethod(DotRightCayleyDigraph, " for a semigroup" , [ IsSemigroup] ,
811- S -> DotString(RightCayleyDigraph(S)));
821+ function (S )
822+ local label;
823+
824+ # TODO handle monoids
825+ # ToExtRepObj := SEMIGROUPS.WordToExtRepObj;
826+ # ToString := SEMIGROUPS.ExtRepObjToString;
827+ # label := x -> ToString(ToExtRepObj(MinimalFactorization(S, x)));
828+ # Current the above approach doesn't work becase labels aren't put into
829+ # quotes " by default and so an error is given for this at present.
830+ # TODO delete the next line when graphviz is fixed.
831+ label := x -> SEMIGROUPS.WordToString(MinimalFactorization(S, x));
832+ return DotWordGraph(RightCayleyDigraph(S),
833+ List(S, label),
834+ List(GeneratorsOfSemigroup(S), label));
835+ end );
812836
813- InstallMethod(DotWordGraph, " for a word graph and list of edge labels" ,
814- [ IsDigraph, IsList, IsList] ,
837+ InstallMethod(DotWordGraph,
838+ " for a word graph, list of node labels, and list of edge labels" ,
839+ [ IsDigraph, IsHomogeneousList, IsHomogeneousList] ,
815840function (D, node_labels, edge_labels )
816- local M, N, edge_colors, msg, legend, label, next, node_func, edge_func, result, v, i;
841+ local M, N, msg, edge_colors, dot, mm, pos, targets, e, legend, subgraph,
842+ key, key2, label, next, str, m, n, i;
843+
844+ # TODO have some options, like include the legend, maybe fancy labels
817845
818- if IsNullDigraph (D) then
846+ if not DigraphHasAVertex (D) then
819847 # Word graphs must have at least one node . . .
820- ErrorNoReturn(" TODO3" );
848+ ErrorNoReturn(" The 1st argument (a digraph) must have at least one vertex" );
849+ elif not IsOutRegularDigraph(D) then
850+ ErrorNoReturn(" The 1st argument (a digraph) must be out-regular" );
821851 fi ;
822852
823853 M := DigraphNrVertices(D);
824854 N := Length(OutNeighboursOfVertex(D, 1 ));
825-
826- if not IsOutRegularDigraph(D) then
827- ErrorNoReturn(" TODO1" );
855+ if Length(node_labels) <> M then
856+ msg := " Expected the 2nd argument (a list) to have length " ;
857+ Append(msg, " {}, but found {}" );
858+ ErrorNoReturn(StringFormatted(msg), M, Length(node_labels));
859+ elif not IsString(node_labels[ 1 ] ) then
860+ ErrorNoReturn(" TODO" );
828861 elif Length(edge_labels) <> N then
829- ErrorNoReturn(" TODO2" );
862+ msg := " Expected the 3rd argument (a list) to have length " ;
863+ Append(msg, " {}, but found {}" );
864+ ErrorNoReturn(msg, M, Length(edge_labels));
865+ elif not IsString(edge_labels[ 1 ] ) then
866+ ErrorNoReturn(" TODO" );
830867 fi ;
831868
832- edge_colors := [ " \" #00ff00\" " , " \" #ff00ff\" " , " \" #007fff\" " , " \" #ff7f00\" " ,
833- " \" #7fbf7f\" " , " \" #4604ac\" " , " \" #de0328\" " , " \" #19801d\" " ,
834- " \" #d881f5\" " , " \" #00ffff\" " , " \" #ffff00\" " , " \" #00ff7f\" " ,
835- " \" #ad5867\" " , " \" #85f610\" " , " \" #84e9f5\" " , " \" #f5c778\" " ,
836- " \" #207090\" " , " \" #764ef3\" " , " \" #7b4c00\" " , " \" #0000ff\" " ,
837- " \" #b80c9a\" " , " \" #601045\" " , " \" #29b7c0\" " , " \" #839f12" ] ;
869+ # TODO longer list here
870+ edge_colors := [ " #00ff00" , " #ff00ff" , " #007fff" , " #ff7f00" ,
871+ " #7fbf7f" , " #4604ac" , " #de0328" , " #19801d" ,
872+ " #d881f5" , " #00ffff" , " #ffff00" , " #00ff7f" ,
873+ " #ad5867" , " #85f610" , " #84e9f5" , " #f5c778" ,
874+ " #207090" , " #764ef3" , " #7b4c00" , " #0000ff" ,
875+ " #b80c9a" , " #601045" , " #29b7c0" , " #839f12" ] ;
838876
839877 if N > Length(edge_colors) then
840- msg := Concatenation(" the out-degree of every vertex in the 1st argument (a digraph) " ,
841- " must have at most {}, found {}" );
878+ msg := Concatenation(" the out-degree of every vertex in the 1st argument " ,
879+ " (a digraph) must be at most {}, found {}" );
842880 ErrorNoReturn(StringFormatted(msg, Length(edge_colors), N));
843881 fi ;
844882
845- # node_labels := ["ε"];
883+ dot := GV_Digraph(" WordGraph" );
884+ GV_SetAttr(dot, " node [shape=\" box\" ]" );
885+ for m in [ 1 .. M] do
886+ mm := GV_AddNode(dot, m);
887+ GV_SetAttr(mm, " label" , node_labels[ m] );
888+ pos := Position(edge_labels, node_labels[ m] );
889+ if pos <> fail then
890+ GV_SetAttr(mm, " color" , edge_colors[ pos] );
891+ GV_SetAttr(mm, " style" , " filled" );
892+ fi ;
893+ od ;
846894
847- # for v in [2 .. M] do
848- # Add(node_labels, edge_labels{DigraphPath(D, 1, v)[2]});
849- # od;
895+ for m in [ 1 .. M] do
896+ targets := OutNeighboursOfVertex(D, m);
897+ for n in [ 1 .. N] do
898+ e := GV_AddEdge(dot, m, targets[ n] );
899+ GV_SetAttr(e, " color" , edge_colors[ n] );
900+ od ;
901+ od ;
850902
851- legend := " node [shape=plaintext]\n subgraph cluster_01 {\n label=\" Legend\"\n " ;
852- Append(legend, " key2 [label=<<table border=\" 0\" cellpadding=\" 2\" " );
853- Append(legend, " cellspacing=\" 0\" cellborder=\" 0\" >\n " );
903+ legend := GV_AddContext(dot, " legend" );
904+ GV_SetAttr(legend, " node [shape=plaintext]" );
905+ subgraph := GV_AddSubgraph(legend, " legend" );
906+ key := GV_AddNode(subgraph, " key" );
907+ key2 := GV_AddNode(subgraph, " key2" );
854908
909+ label := Concatenation(" <<table border=\" 0\" cellpadding=\" 2\" " ,
910+ " cellspacing=\" 0\" " ,
911+ " cellborder=\" 0\" >\n " );
855912 for i in [ 1 .. N] do
856- Append(legend ,
913+ Append(label ,
857914 StringFormatted(" <tr><td port=\" i{}\" > </td></tr>\n " ,
858915 i));
859916 od ;
860- Append(legend, " </table>>]\n " );
861- Append(legend, " key [label=<<table border=\" 0\" cellpadding=\" 2\" " );
862- Append(legend, " cellspacing=\" 0\" cellborder=\" 0\" >\n " );
917+ Append(label, " </table>>\n " );
918+ GV_SetAttr(key2, " label" , label);
863919
920+ # TODO remove code dupl
921+ label := Concatenation(" <<table border=\" 0\" cellpadding=\" 2\" " ,
922+ " cellspacing=\" 0\" " ,
923+ " cellborder=\" 0\" >\n " );
864924 for i in [ 1 .. N] do
865- label := [ edge_labels[ i]] ;
866- next := " <tr><td align=\" right\" " ;
867- Append(next, StringFormatted(" port=\" i{}\" >{} </td></tr>\n " , i, label));
868- Append(legend, next);
925+ next := " <tr><td align=\" right\" " ;
926+ Append(next, StringFormatted(" port=\" i{}\" >{} </td></tr>\n " ,
927+ i,
928+ edge_labels[ i] ));
929+ Append(label, next);
869930 od ;
931+ Append(label, " </table>>\n " );
870932
871- Append(legend , " </table>>] \n\n " );
933+ GV_SetAttr(key , " label " , label );
872934
873935 for i in [ 1 .. N] do
874- next := StringFormatted( " key:i{1}:e -> key2:i{1}:w [color={2}, " ,
875- i ,
876- edge_colors [ i ] );
877- Append(next , " constraint=false] \n " );
878- Append(legend, next );
936+ e := GV_AddEdge(subgraph ,
937+ StringFormatted( " key:i{}:e " , i) ,
938+ StringFormatted( " key2:i{}:w " , i) );
939+ GV_SetAttr(e , " color " , edge_colors [ i ] );
940+ GV_SetAttr(e, " constraint " , false );
879941 od ;
880- Append(legend, " }\n " );
881-
882- node_func := i -> StringFormatted(" [label=\" {}\" ]" , node_labels[ i] );
883- edge_func := { i, j} -> StringFormatted(" [color={}]" , edge_colors[ j] );
884942
885- result := DIGRAPHS_DotDigraph(D, [ node_func] , [ edge_func] );
886- result := SplitString(result, " \n " );
887- result[ 3 ] := " subgraph 00 {" ;
888- Add(result, " node [shape=box]" , 3 );
889- Add(result, legend);
890- Add(result, " }" );
891- return JoinStringsWithSeparator(result, " \n " );
943+ str := GV_String(dot);
944+ # TODO remove the next two lines, these work around some issues in graphviz
945+ str := ReplacedString(str, " --" , " ->" );
946+ return Concatenation(" //dot\n " , str);
892947end );
0 commit comments