Skip to content

Commit

Permalink
display: add methods for drawing Cayley graphs
Browse files Browse the repository at this point in the history
Using dot or tikz, for digraphs and semigroups.
  • Loading branch information
James Mitchell committed Jul 22, 2017
1 parent 272aa00 commit b63a1c6
Show file tree
Hide file tree
Showing 5 changed files with 272 additions and 2 deletions.
111 changes: 109 additions & 2 deletions doc/display.xml
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,23 @@
</Item>
<Mark>pbrs</Mark>
<Item>
If <A>obj</A> is a PBR, then <C>TikzString</C> returns a graphical
representation <A>obj</A>; see Section <Ref Sect = "section-blocks"/>.
If <A>obj</A> is a <Ref Oper="PBR"/>, then <C>TikzString</C> returns a
graphical representation <A>obj</A>; see Chapter <Ref Sect =
"Partitioned binary relations (PBRs)"/>.
</Item>
<Mark>Cayley graphs</Mark>
<Item>
If <A>obj</A> is a <Ref Oper="Digraph" BookName="digraphs"/> in the
category <Ref Filt="IsCayleyDigraph" BookName="digraphs"/>, then
<C>TikzString</C> returns a picture of <A>obj</A>. No attempt is made
whatsoever to produce a sensible picture of the digraph <A>obj</A>,
in fact, the vertices are all given the same coordinates. Human
intervention is required to produce a meaningful picture from the
value returned by this method. It is intended to make the task of
drawing such a Cayley graph more straightforward by providing
everything except the final layout of the graph. Please use <Ref
Oper="DotString"/> if you want an automatically laid out diagram of
the digraph <A>obj</A>.
</Item>
</List>

Expand Down Expand Up @@ -288,6 +303,30 @@ gap> FileString("t3.dot", DotString(S));
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DotStringDigraph">
<ManSection>
<Oper Name="DotString" Arg="digraph" Label="for a Cayley digraph"/>
<Returns>A string.</Returns>
<Description>
If <A>digraph</A> is a <Ref Oper="Digraph" BookName="digraphs"/> in the
category <Ref Filt="IsCayleyDigraph" BookName="digraphs"/>, then
<C>DotString</C> returns a graphical representation of <A>digraph</A>.
The output is in <C>dot</C> format (also known
as <C>GraphViz</C>) format. For details about this file format, and
information about how to display or edit this format see
<URL>http://www.graphviz.org</URL>.
<P/>

The string returned by <C>DotString</C> can be written to a file using
the command <Ref Func="FileString" BookName="GAPDoc"/>.<P/>

See also <Ref Oper="DotLeftCayleyDigraph"/> and <Ref
Oper="TikzLeftCayleyDigraph"/>.
</Description>
</ManSection>
<#/GAPDoc>


<#GAPDoc Label="DotSemilatticeOfIdempotents">
<ManSection>
<Attr Name="DotSemilatticeOfIdempotents" Arg="S"/>
Expand Down Expand Up @@ -341,3 +380,71 @@ d{pmatrix}"]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="TikzLeftCayleyDigraph">
<ManSection>
<Oper Name="TikzLeftCayleyDigraph" Arg="S"/>
<Oper Name="TikzRightCayleyDigraph" Arg="S"/>
<Returns>A string.</Returns>
<Description>
If <A>S</A> is a semigroup in the representation
<Ref Filt="IsEnumerableSemigroupRep"/>, then <C>TikzLeftCayleyDigraph</C>
is simply short for <C>TikzString(LeftCayleyDigraph(<A>S</A>))</C>.<P/>

<C>TikzRightCayleyDigraph</C> can be used to produce a tikz string for
the right Cayley graph of <A>S</A>.<P/>

See <Ref Oper="TikzString"/> for more details, and see also
<Ref Oper="DotLeftCayleyDigraph"/>.

<Log><![CDATA[
gap> TikzLeftCayleyDigraph(Semigroup(IdentityTransformation));
"\\begin{tikzpicture}[scale=1, auto, \n vertex/.style={c\
ircle, draw, thick, fill=white, minimum size=0.65cm},\n \
edge/.style={arrows={-angle 90}, thick},\n loop/.style={\
min distance=5mm,looseness=5,arrows={-angle 90},thick}]\n\
\n % Vertices . . .\n \\node [vertex] (a) at (0, 0) {};\
\n \\node at (0, 0) {$a$};\n\n % Edges . . .\n \\path[\
->] (a) edge [loop]\n node {$a$} (a);\n\\end{ti\
kzpicture}"
gap> TikzRightCayleyDigraph(Semigroup(IdentityTransformation));
"\\begin{tikzpicture}[scale=1, auto, \n vertex/.style={c\
ircle, draw, thick, fill=white, minimum size=0.65cm},\n \
edge/.style={arrows={-angle 90}, thick},\n loop/.style={\
min distance=5mm,looseness=5,arrows={-angle 90},thick}]\n\
\n % Vertices . . .\n \\node [vertex] (a) at (0, 0) {};\
\n \\node at (0, 0) {$a$};\n\n % Edges . . .\n \\path[\
->] (a) edge [loop]\n node {$a$} (a);\n\\end{ti\
kzpicture}"]]></Log>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DotLeftCayleyDigraph">
<ManSection>
<Oper Name="DotLeftCayleyDigraph" Arg="S"/>
<Oper Name="DotRightCayleyDigraph" Arg="S"/>
<Returns>A string.</Returns>
<Description>
If <A>S</A> is a semigroup in the representation <Ref
Filt="IsEnumerableSemigroupRep"/>, then <C>DotLeftCayleyDigraph</C> is
simply short for <C>DotString(LeftCayleyDigraph(<A>S</A>))</C>.<P/>

<C>DotRightCayleyDigraph</C> can be used to produce a dot string for
the right Cayley graph of <A>S</A>.<P/>

See <Ref Oper="DotString"/> for more details, and see also
<Ref Oper="TikzLeftCayleyDigraph"/>.

<Log><![CDATA[
gap> DotLeftCayleyDigraph(Semigroup(IdentityTransformation));
"//dot\ndigraph hgn{\nnode [shape=circle]\n1 [label=\"a\"]\n1 -> 1\n}\
\n"
gap> DotRightCayleyDigraph(Semigroup(IdentityTransformation));
"//dot\ndigraph hgn{\nnode [shape=circle]\n1 [label=\"a\"]\n1 -> 1\n}\
\n"]]></Log>
</Description>
</ManSection>
<#/GAPDoc>


3 changes: 3 additions & 0 deletions doc/z-chap18.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@
BookName = "GAPDoc"/> or viewed using <Ref Func = "Splash"/>.

<#Include Label = "DotString"/>
<#Include Label = "DotStringDigraph"/>
<#Include Label = "DotSemilatticeOfIdempotents"/>
<#Include Label = "DotLeftCayleyDigraph">

</Section>

Expand Down Expand Up @@ -81,6 +83,7 @@
BookName = "GAPDoc"/> or viewed using <Ref Func = "Splash"/>.

<#Include Label = "TikzString">
<#Include Label = "TikzLeftCayleyDigraph">

</Section>

Expand Down
6 changes: 6 additions & 0 deletions gap/tools/display.gd
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,10 @@ DeclareOperation("DotString", [IsObject, IsRecord]);
DeclareOperation("TexString", [IsObject]);
DeclareOperation("TexString", [IsObject, IsObject]);

DeclareOperation("TikzLeftCayleyDigraph", [IsSemigroup]);
DeclareOperation("TikzRightCayleyDigraph", [IsSemigroup]);

DeclareOperation("DotLeftCayleyDigraph", [IsSemigroup]);
DeclareOperation("DotRightCayleyDigraph", [IsSemigroup]);

DeclareAttribute("DotSemilatticeOfIdempotents", IsInverseSemigroup);
98 changes: 98 additions & 0 deletions gap/tools/display.gi
Original file line number Diff line number Diff line change
Expand Up @@ -735,3 +735,101 @@ function(coll)
deg := DegreeOfTransformationCollection(coll);
return JoinStringsWithSeparator(List(coll, x -> TexString(x, deg)), "\n");
end);

InstallMethod(TikzLeftCayleyDigraph, "for a semigroup", [IsSemigroup],
function(S)
return TikzString(LeftCayleyDigraph(S));
end);

InstallMethod(TikzRightCayleyDigraph, "for a semigroup", [IsSemigroup],
function(S)
return TikzString(RightCayleyDigraph(S));
end);

InstallMethod(TikzString, "for a Cayley digraph", [IsCayleyDigraph],
function(digraph)
local S, vertex, edge, str, nbs, x, from, gen;

S := SemigroupOfCayleyDigraph(digraph);
if not IsEnumerableSemigroupRep(S) or Size(S) > 26 then
TryNextMethod();
fi;

vertex := function(x)
local word, name, label;
word := MinimalFactorization(S, x);
name := SEMIGROUPS.WordToString(word);
label := SEMIGROUPS.ExtRepObjToString(SEMIGROUPS.WordToExtRepObj(word));
return Concatenation(" \\node [vertex] (", name, ") at (0, 0) {};\n",
" \\node at (0, 0) {$", label, "$};\n\n");
end;

edge := function(from, to, gen)
local word;
word := MinimalFactorization(S, AsListCanonical(S)[from]);
from := SEMIGROUPS.WordToString(word);
word := MinimalFactorization(S, AsListCanonical(S)[to]);
to := SEMIGROUPS.WordToString(word);
gen := SEMIGROUPS.WordToString([gen]);
if from <> to then
return Concatenation(" \\path[->] (", from,
") edge [edge] node {$", gen, "$} (",
to, ");\n");
else
return Concatenation(" \\path[->] (", from,
") edge [loop]\n",
" node {$", gen, "$} (", to, ");\n");
fi;
end;

str := "";

Append(str, "\\begin{tikzpicture}[scale=1, auto, \n");
Append(str, " vertex/.style={circle, draw, thick, fill=white, minimum");
Append(str, " size=0.65cm},\n");
Append(str, " edge/.style={arrows={-angle 90}, thick},\n");
Append(str, " loop/.style={min distance=5mm,looseness=5,");
Append(str, "arrows={-angle 90},thick}]\n\n");

Append(str, " % Vertices . . .\n");
for x in AsListCanonical(S) do
Append(str, vertex(x));
od;

Append(str, " % Edges . . .\n");
nbs := OutNeighbours(digraph);
for from in [1 .. Size(S)] do
for gen in [1 .. Size(nbs[from])] do
Append(str, edge(from, nbs[from][gen], gen));
od;
od;

Append(str, "\\end{tikzpicture}");
return str;
end);

InstallMethod(DotString, "for a Cayley digraph", [IsCayleyDigraph],
function(digraph)
local S, li, label, i;
S := SemigroupOfCayleyDigraph(digraph);
if not IsEnumerableSemigroupRep(S) or Size(S) > 26 then
TryNextMethod();
fi;
li := AsListCanonical(S);
for i in [1 .. Size(S)] do
label := SEMIGROUPS.WordToExtRepObj(MinimalFactorization(S, li[i]));
label := SEMIGROUPS.ExtRepObjToString(label);
SetDigraphVertexLabel(digraph, i, label);
od;
return DotVertexLabelledDigraph(digraph);
end);

InstallMethod(DotLeftCayleyDigraph, "for a semigroup", [IsSemigroup],
function(S)
return DotString(LeftCayleyDigraph(S));
end);

InstallMethod(DotRightCayleyDigraph, "for a semigroup", [IsSemigroup],
function(S)
return DotString(RightCayleyDigraph(S));
end);
56 changes: 56 additions & 0 deletions tst/standard/display.tst
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,62 @@ Error, Semigroups: TexString: usage,
the second argument (the degree) should be at least the degree of the first ar\
gument (a transformation),

# Tikz/DotLeft/RightCayleyDigraph
gap> TikzLeftCayleyDigraph(FullTransformationMonoid(2));
"\\begin{tikzpicture}[scale=1, auto, \n vertex/.style={circle, draw, thick, f\
ill=white, minimum size=0.65cm},\n edge/.style={arrows={-angle 90}, thick},\n\
loop/.style={min distance=5mm,looseness=5,arrows={-angle 90},thick}]\n\n % \
Vertices . . .\n \\node [vertex] (a) at (0, 0) {};\n \\node at (0, 0) {$a$};\
\n\n \\node [vertex] (b) at (0, 0) {};\n \\node at (0, 0) {$b$};\n\n \\node\
[vertex] (c) at (0, 0) {};\n \\node at (0, 0) {$c$};\n\n \\node [vertex] (c\
b) at (0, 0) {};\n \\node at (0, 0) {$cb$};\n\n % Edges . . .\n \\path[->] \
(a) edge [loop]\n node {$a$} (a);\n \\path[->] (a) edge [edge] node\
{$b$} (b);\n \\path[->] (a) edge [edge] node {$c$} (c);\n \\path[->] (b) ed\
ge [loop]\n node {$a$} (b);\n \\path[->] (b) edge [edge] node {$b$}\
(a);\n \\path[->] (b) edge [edge] node {$c$} (cb);\n \\path[->] (c) edge [l\
oop]\n node {$a$} (c);\n \\path[->] (c) edge [loop]\n nod\
e {$b$} (c);\n \\path[->] (c) edge [loop]\n node {$c$} (c);\n \\pa\
th[->] (cb) edge [loop]\n node {$a$} (cb);\n \\path[->] (cb) edge [\
loop]\n node {$b$} (cb);\n \\path[->] (cb) edge [loop]\n \
node {$c$} (cb);\n\\end{tikzpicture}"
gap> TikzRightCayleyDigraph(FullTransformationMonoid(2));
"\\begin{tikzpicture}[scale=1, auto, \n vertex/.style={circle, draw, thick, f\
ill=white, minimum size=0.65cm},\n edge/.style={arrows={-angle 90}, thick},\n\
loop/.style={min distance=5mm,looseness=5,arrows={-angle 90},thick}]\n\n % \
Vertices . . .\n \\node [vertex] (a) at (0, 0) {};\n \\node at (0, 0) {$a$};\
\n\n \\node [vertex] (b) at (0, 0) {};\n \\node at (0, 0) {$b$};\n\n \\node\
[vertex] (c) at (0, 0) {};\n \\node at (0, 0) {$c$};\n\n \\node [vertex] (c\
b) at (0, 0) {};\n \\node at (0, 0) {$cb$};\n\n % Edges . . .\n \\path[->] \
(a) edge [loop]\n node {$a$} (a);\n \\path[->] (a) edge [edge] node\
{$b$} (b);\n \\path[->] (a) edge [edge] node {$c$} (c);\n \\path[->] (b) ed\
ge [loop]\n node {$a$} (b);\n \\path[->] (b) edge [edge] node {$b$}\
(a);\n \\path[->] (b) edge [edge] node {$c$} (c);\n \\path[->] (c) edge [lo\
op]\n node {$a$} (c);\n \\path[->] (c) edge [edge] node {$b$} (cb);\
\n \\path[->] (c) edge [loop]\n node {$c$} (c);\n \\path[->] (cb) \
edge [loop]\n node {$a$} (cb);\n \\path[->] (cb) edge [edge] node {\
$b$} (c);\n \\path[->] (cb) edge [edge] node {$c$} (c);\n\\end{tikzpicture}"
gap> DotRightCayleyDigraph(FullTransformationMonoid(2));
"//dot\ndigraph hgn{\nnode [shape=circle]\n1 [label=\"a\"]\n2 [label=\"b\"]\n3\
[label=\"c\"]\n4 [label=\"cb\"]\n1 -> 1\n1 -> 2\n1 -> 3\n2 -> 2\n2 -> 1\n2 ->\
3\n3 -> 3\n3 -> 4\n3 -> 3\n4 -> 4\n4 -> 3\n4 -> 3\n}\n"
gap> DotLeftCayleyDigraph(FullTransformationMonoid(2));
"//dot\ndigraph hgn{\nnode [shape=circle]\n1 [label=\"a\"]\n2 [label=\"b\"]\n3\
[label=\"c\"]\n4 [label=\"cb\"]\n1 -> 1\n1 -> 2\n1 -> 3\n2 -> 2\n2 -> 1\n2 ->\
4\n3 -> 3\n3 -> 3\n3 -> 3\n4 -> 4\n4 -> 4\n4 -> 4\n}\n"
gap> S := LeftZeroSemigroup(27);;
gap> DotLeftCayleyDigraph(S);
Error, no method found! For debugging hints type ?Recovery from NoMethodFound
Error, no 2nd choice method found for `DotString' on 1 arguments
gap> TikzLeftCayleyDigraph(S);
Error, no method found! For debugging hints type ?Recovery from NoMethodFound
Error, no 2nd choice method found for `TikzString' on 1 arguments
gap> DotRightCayleyDigraph(S);
Error, no method found! For debugging hints type ?Recovery from NoMethodFound
Error, no 2nd choice method found for `DotString' on 1 arguments
gap> TikzRightCayleyDigraph(S);
Error, no method found! For debugging hints type ?Recovery from NoMethodFound
Error, no 2nd choice method found for `TikzString' on 1 arguments

#
gap> SEMIGROUPS.StopTest();
gap> STOP_TEST("Semigroups package: standard/display.tst");

0 comments on commit b63a1c6

Please sign in to comment.