diff --git a/.github/workflows/manual.yml b/.github/workflows/manual.yml index f487b0287..1f4bf16e6 100644 --- a/.github/workflows/manual.yml +++ b/.github/workflows/manual.yml @@ -38,7 +38,14 @@ jobs: - uses: gap-actions/setup-gap@v3 with: gap-version: latest + - name: Build GraphvizForGAP manual . . . + run: | + git clone https://github.com/digraphs/graphviz.git "${GAPROOT}/pkg/graphviz" + cd "${GAPROOT}/pkg/graphviz" + NOPDF=1 $GAP makedoc.g - uses: gap-actions/build-pkg-docs@v2 + with: + use-latex: true - name: Upload compiled manuals . . . uses: actions/upload-artifact@v7 with: diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 5cce2c273..f0d4dd244 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -41,11 +41,6 @@ jobs: pkgs-to-clone: https://github.com/digraphs/graphviz.git https://github.com/gap-packages/NautyTracesInterface.git pkgs-to-build: io orb datastructures profiling grape NautyTracesInterface - - gap-version: v4.11 # Note: NautyTracesInterface requires GAP 4.12 - mode: default # There wouldn't be much point testing GAP v4.11 with only needed packages. The only difference is whether Grape is loaded. - pkgs-to-clone: https://github.com/digraphs/graphviz.git - pkgs-to-build: io* orb* datastructures* profiling* grape* - steps: - uses: actions/checkout@v7 - name: Output g++ version . . . diff --git a/PackageInfo.g b/PackageInfo.g index fc2385239..0f4be548b 100644 --- a/PackageInfo.g +++ b/PackageInfo.g @@ -568,9 +568,10 @@ PackageDoc := rec( ), Dependencies := rec( - GAP := ">=4.11.0", + GAP := ">=4.12.0", NeededOtherPackages := [["IO", ">=4.5.1"], ["orb", ">=4.8.2"], + ["GraphvizForGAP", ">=0.0.0"], ["datastructures", ">=0.2.5"]], SuggestedOtherPackages := [["GAPDoc", ">=1.6.3"], ["GRAPE", ">=4.8.1"], diff --git a/README.md b/README.md index ac6707a7b..21fdbab41 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ For questions, remarks, suggestions, and issues please use the ## Installation It is assumed that you have a working copy of [GAP][] with version number -4.11.0 or higher. The most up-to-date version of GAP, and instructions on how +4.12.0 or higher. The most up-to-date version of GAP, and instructions on how to install it, can be obtained from the [main GAP webpage](https://www.gap-system.org). diff --git a/doc/display.xml b/doc/display.xml index df8da62f4..26d16200d 100644 --- a/doc/display.xml +++ b/doc/display.xml @@ -1,414 +1,334 @@ ############################################################################# ## #W display.xml -#Y Copyright (C) 2011-17 James D. Mitchell +#Y Copyright (C) 2014-24 James D. Mitchell ## ## Licensing information can be found in the README file of this package. ## ############################################################################# ## +<#GAPDoc Label="DotDigraph"> + + + + A string. + + WARNING! As of v2.0.0 of &Digraphs; these functions are + deprecated in favour of: + + + + + They return the strings + AsString(GraphvizDigraph(D)) and + AsString(GraphvizGraph(D)), respectively. + DotSymmetricDigraph requires D to be symmetric. + + +<#/GAPDoc> -<#GAPDoc Label="Splash"> +<#GAPDoc Label="GraphvizDigraph"> - - Nothing. + + + A &GRAPHVIZFORGAP; object. - This function attempts to convert the string str into a pdf - document and open this document, i.e. to splash it all over your monitor.

+ and return + mutable &GAP; objects representing graphviz objects, which provide a + flexible means of tailoring pictures of graphs and digraphs to your + needs. +

+ + GraphvizDigraph and GraphvizGraph produce &GRAPHVIZFORGAP; + objects representing the digraph D. Vertices are displayed as + circles, numbered consistently with D. For GraphvizDigraph, + edges are displayed as arrowed lines between vertices, with the arrowhead + of each line pointing towards the range of the edge. For + GraphvizGraph, edges are displayed without an arrowhead. + GraphvizGraph requires D to be symmetric; see + . +

+ + To display the result, use + . Its documentation + describes the optional record controlling the output directory, + filename, viewer, rendering engine, and file type. + Splash(GraphvizDigraph(D)); +]]> + To write the Graphviz source to a file, use + FileString("digraph.dot", AsString(GraphvizDigraph(D))); + see . +

- The string str must correspond to a valid dot or - LaTeX text file and you must have have GraphViz and - pdflatex installed on your computer. For details about these file - formats, see https://www.latex-project.org and - https://www.graphviz.org.

+ D := CompleteDigraph(IsMutable, 4); + +gap> gv := GraphvizGraph(D); + +gap> AsString(gv); +"//dot\ngraph hgn {\n\tnode [shape=circle] \n\t1\n\t2\n\t3\n\t4\n\t2 -\ +- 1\n\t3 -- 1\n\t3 -- 2\n\t4 -- 1\n\t4 -- 2\n\t4 -- 3\n}\n" +gap> DigraphRemoveEdge(D, 1, 3); + +gap> gv := GraphvizDigraph(D); + +gap> AsString(gv); +"//dot\ndigraph hgn {\n\tnode [shape=circle] \n\t1\n\t2\n\t3\n\t4\n\t1\ + -> 2\n\t1 -> 4\n\t2 -> 1\n\t2 -> 3\n\t2 -> 4\n\t3 -> 1\n\t3 -> 2\n\t3\ + -> 4\n\t4 -> 1\n\t4 -> 2\n\t4 -> 3\n}\n" +]]> + + +<#/GAPDoc> + +<#GAPDoc Label="GraphvizColoredDigraph"> + + + + + + + + A &GRAPHVIZFORGAP; object. + + These operations produce colored &GRAPHVIZFORGAP; objects representing + the digraph D according to the specified colors. The variants ending + in Graph require D to be symmetric. + For all of these functions valid colors are strings containing: + + RGB + + An RGB color code consisting of 6 hexadecimal digits preceded by + a #. For example, #ff00ff. + + GraphViz 2.4.11 X11 Color Scheme + + One of the color strings specified at: + http://graphviz.org/doc/info/colors.html + + - This function is provided to allow convenient, immediate viewing of the - pictures produced by the function .

+ GraphvizVertexColoredDigraph and GraphvizVertexColoredGraph + require their argument colors to be a list of length equal to the + number of vertices of D consisting of strings representing colors + as described above. +

- The optional second argument opts should be a record with - components corresponding to various options, given below. + GraphvizEdgeColoredDigraph and GraphvizEdgeColoredGraph + require their argument colors to be a list of lists with the same + shape of the out-neighbours of the digraph D consisting of strings + representing colors as described above. +

+ GraphvizColoredDigraph and GraphvizColoredGraph require + their arguments: - path - - this should be a string representing the path to the directory where - you want Splash to do its work. The default value of this - option is "~/". - - - directory - - this should be a string representing the name of the directory in - path where you want Splash to do its work. This function - will create this directory if does not already exist.

- - The default value of this option is "tmp.viz" if the option - path is present, and the result of - is used otherwise. - - - filename - - this should be a string representing the name of the file where - str will be written. The default value of this option is - "vizpicture". - - - viewer - - this should be a string representing the name of the program which - should open the files produced by GraphViz or pdflatex. - - - type - - this option can be used to specify that the string str contains - a &LaTeX; or dot document. You can specify this option in - str directly by making the first line "%latex" or - "//dot". There is no default value for this option, this - option must be specified in str or in opt.type. - - - engine - - this option can be used to specify the GraphViz engine to use - to render a dot document. The valid choices are "dot", - "neato", "circo", "twopi", "fdp", - "sfdp", and "patchwork". Please refer to the - GraphViz documentation for details on these engines. - The default value for this option is "dot", and it - must be specified in opt.engine. - - - filetype - - this should be a string representing the type of file which - Splash should produce. For &LaTeX; files, this option is - ignored and the default value "pdf" is used. - + vert_colors + + to represent vertex colors as described for + GraphvizVertexColoredDigraph; + + edge_colors + + to represent edge colors as described for + GraphvizEdgeColoredDigraph; + - This function was written by Attila Egri-Nagy and Manuel Delgado with some - minor changes by J. D. Mitchell.

- Splash(DotDigraph(RandomDigraph(4))); -]]> + See the &GRAPHVIZFORGAP; package documentation for more details. +

+ + See also + D := Digraph([[2], [1, 3], [2]]); + +gap> vert_colors := ["blue", "pink", "purple"];; +gap> edge_colors := [["green"], ["green", "red"], ["red"]];; +gap> GraphvizVertexColoredDigraph(D, vert_colors); + +gap> GraphvizVertexColoredGraph(D, vert_colors); + +gap> GraphvizEdgeColoredDigraph(D, edge_colors); + +gap> GraphvizEdgeColoredGraph(D, edge_colors); + +gap> GraphvizColoredDigraph(D, vert_colors, edge_colors); + +gap> GraphvizColoredGraph(D, vert_colors, edge_colors); + +]]> <#/GAPDoc> -<#GAPDoc Label="DotDigraph"> +<#GAPDoc Label="DotColoredDigraph"> - - - - - - + + + + + + A string. - DotDigraph produces a graphical representation of the digraph - digraph. Vertices are displayed as circles, numbered consistently - with digraph. Edges are displayed as arrowed lines between - vertices, with the arrowhead of each line pointing towards the range - of the edge.

- - DotColoredDigraph differs from DotDigraph only in - that the values in given in the two lists are used to color the vertices and - edges of the graph when displayed. The list for vertex colours should be - a list of length equal to the number of vertices, containing strings that - are accepted by the graphviz software, which is the one used for graph - representation. The list for edge colours should be a list of lists - with the same shape of the outneighbours of the digraph that contains strings - that correspond to colours accepted by the graphviz software. If the lists - are not the appropriate size, or have holes then the function will return - an error.

- - DotColoredEdgeLabelledDigraph differs from DotColoredDigraph - only in that the values given in the third list labels is used to - label the edges of the graph when displayed. The list labels should - be a list of equal length to the lists for vertex and edge colours. If the - lists are not the appropriate size, or have holes, then the function will - return an error.

- - DotVertexColoredDigraph differs from DotDigraph only in - that the values in given in the list are used to color the vertices - of the graph when displayed. The list for vertex colours should be - a list of length equal to the number of vertices, containing strings that - are accepted by the graphviz software, which is the one used for graph - representation. If the list is not the appropriate size, or has holes - then the function will return an error.

- - DotEdgeColoredDigraph differs from DotDigraph only in - that the values in given in the list are used to color the vertices and - edges of the graph when displayed. The list for edge colours should be a list - of lists with the same shape of the outneighbours of the digraph that contains - strings that correspond to colours accepted by the graphviz software. If the - list is not the appropriate size, or has holes then the function will return - an error.

- - DotVertexLabelledDigraph differs from DotDigraph only in - that the values in are used to label - the vertices in the produced picture rather than the numbers 1 to - the number of vertices of the digraph.

- - The output is in dot format (also known as GraphViz) - format. For details about this file format, and information about how to - display or edit this format see https://www.graphviz.org.

- - The string returned by DotDigraph or - DotVertexLabelledDigraph can be written to a file using - the command .

- - See also .

+ WARNING! As of v2.0.0 of &Digraphs; these functions are + deprecated in favour of the following operations, respectively: + + + + + + + + + Each takes the same arguments as its replacement and returns + AsString applied to the resulting &GRAPHVIZFORGAP; object. + For example, + DotColoredDigraph(D, vert_colors, edge_colors) returns + AsString(GraphvizColoredDigraph(D, vert_colors, edge_colors)). + The DotSymmetric variants require D to be symmetric. + + +<#/GAPDoc> + +<#GAPDoc Label="GraphvizVertexLabelledDigraph"> + + + + A &GRAPHVIZFORGAP; object. + + These operations produce the same pictures as + and , + respectively, using to label the + vertices instead of their numbers. Labels are converted to strings. + GraphvizVertexLabelledGraph requires D to be symmetric. +

+ + Use to set the vertex labels. + The resulting object can be displayed using + . D := CompleteDigraph(4); - -gap> vertcolors := ["blue", "green", "red", "yellow"];; -gap> Print(DotVertexLabelledDigraph(D)); -//dot -digraph hgn{ -node [shape=circle] -1 [label="1"] -2 [label="2"] -3 [label="3"] -4 [label="4"] -1 -> 2 -1 -> 3 -1 -> 4 -2 -> 1 -2 -> 3 -2 -> 4 -3 -> 1 -3 -> 2 -3 -> 4 -4 -> 1 -4 -> 2 -4 -> 3 -} -gap> Print(DotVertexColoredDigraph(D, vertcolors)); -//dot -digraph hgn{ -node [shape=circle] -1[color=blue, style=filled] -2[color=green, style=filled] -3[color=red, style=filled] -4[color=yellow, style=filled] -1 -> 2 -1 -> 3 -1 -> 4 -2 -> 1 -2 -> 3 -2 -> 4 -3 -> 1 -3 -> 2 -3 -> 4 -4 -> 1 -4 -> 2 -4 -> 3 -} -gap> colors := ["lightblue", "pink", "purple"];; -gap> edgecolors := ListWithIdenticalEntries(4, colors);; -gap> Print(DotEdgeColoredDigraph(D, edgecolors)); -//dot -digraph hgn{ -node [shape=circle] -1 -2 -3 -4 -1 -> 2[color=lightblue] -1 -> 3[color=pink] -1 -> 4[color=purple] -2 -> 1[color=lightblue] -2 -> 3[color=pink] -2 -> 4[color=purple] -3 -> 1[color=lightblue] -3 -> 2[color=pink] -3 -> 4[color=purple] -4 -> 1[color=lightblue] -4 -> 2[color=pink] -4 -> 3[color=purple] -} -gap> Print(DotColoredDigraph(D, vertcolors, edgecolors)); -//dot -digraph hgn{ -node [shape=circle] -1[color=blue, style=filled] -2[color=green, style=filled] -3[color=red, style=filled] -4[color=yellow, style=filled] -1 -> 2[color=lightblue] -1 -> 3[color=pink] -1 -> 4[color=purple] -2 -> 1[color=lightblue] -2 -> 3[color=pink] -2 -> 4[color=purple] -3 -> 1[color=lightblue] -3 -> 2[color=pink] -3 -> 4[color=purple] -4 -> 1[color=lightblue] -4 -> 2[color=pink] -4 -> 3[color=purple] -} -gap> FileString("k4.dot", DotDigraph(D)); -133 -gap> D := Digraph([[2, 3], [1, 3], [1]]); - -gap> vertcolors := ["blue", "red", "green"];; -gap> edgecolors := [["orange", "yellow"], ["orange", -> "pink"], ["yellow"]];; -gap> Print(DotColoredDigraph(D, vertcolors, edgecolors)); -//dot -digraph hgn{ -node [shape=circle] -1[color=blue, style=filled] -2[color=red, style=filled] -3[color=green, style=filled] -1 -> 2[color=orange] -1 -> 3[color=yellow] -2 -> 1[color=orange] -2 -> 3[color=pink] -3 -> 1[color=yellow] -} -gap> FileString("digraph.dot", DotDigraph(D)); -82]]> +gap> D := Digraph([[2], [1]]);; +gap> SetDigraphVertexLabels(D, ["left", "right"]); +gap> GraphvizVertexLabelledDigraph(D); + +gap> GraphvizVertexLabelledGraph(D); + +]]> - <#/GAPDoc> +<#/GAPDoc> -<#GAPDoc Label="DotSymmetricDigraph"> +<#GAPDoc Label="DotVertexLabelledDigraph"> - - - - + A string. - This function produces a graphical representation of the symmetric - digraph digraph. DotSymmetricDigraph will return an - error if digraph is not a symmetric digraph. See - .

- - The function DotSymmetricColoredDigraph differs from DotDigraph - only in that the values given in the two lists are used to color the vertices - and edges of the graph when displayed. The list for vertex colours should be - a list of length equal to the number of vertices, containing strings that - are accepted by the graphviz software, which is the one used for graph - representation. The list for edge colours should be a list of lists - with the same shape of the outneighbours of the digraph that contains strings - that correspond to colours accepted by the graphviz software. - If the list is not the appropriate size, or has holes then the function - will return an error.

- - The function DotSymmetricVertexColoredDigraph differs from DotDigraph - only in that the values in given in the list is used to color the vertices - of the graph when displayed. The list for vertex colours should be - a list of length equal to the number of vertices, containing strings that - are accepted by the graphviz software, which is the one used for graph - representation. If the list is not the appropriate size, or has holes - then the function will return an error.

- - The function DotSymmetricEdgeColoredDigraph differs from DotDigraph - only in that the values given in the list are used to color the edges - of the graph when displayed. The list for edge colours should be - a list of lists with the same shape of the outneighbours, containing strings that - are accepted by the graphviz software, which is the one used for graph - representation. If the list is not the appropriate size, or has holes - then the function will return an error.

- - Vertices are displayed as circles, numbered consistently with - digraph. Since digraph is symmetric, for every non-loop - edge there is a complementary edge with opposite source and range. - DotSymmetricDigraph displays each pair of complementary edges - as a single line between the relevant vertices, with no arrowhead.

- - The output is in dot format (also known as GraphViz) - format. For details about this file format, and information about how - to display or edit this format see - https://www.graphviz.org.

- - The string returned by DotSymmetricDigraph can be written to a - file using the command .

+ WARNING! As of v2.0.0 of &Digraphs; this function is + deprecated in favour of: + + + + It returns + AsString(GraphvizVertexLabelledDigraph(D)), using + as the vertex labels. + + +<#/GAPDoc> +<#GAPDoc Label="GraphvizColoredEdgeLabelledDigraph"> + + + A &GRAPHVIZFORGAP; object. + + This operation produces the same picture as + , with labels on the edges. + The arguments vert_colors and edge_colors specify colors + as described there. The argument labels must be a list of lists + with the same shape as OutNeighbours(D): + labels[i][j] labels the edge from vertex i to + OutNeighbours(D)[i][j]. +

+ + See also for displaying edge + weights and highlighting a path. D := Digraph([[2], [1, 3], [2]]); - -gap> IsSymmetricDigraph(D); -true -gap> vertcolors := ["blue", "pink", "purple"];; -gap> edgecolors := [["green"], ["green", "red"], ["red"]];; -gap> Print(DotSymmetricColoredDigraph(D, vertcolors, edgecolors)); -//dot -graph hgn{ -node [shape=circle] - -1[color=blue, style=filled] -2[color=pink, style=filled] -3[color=purple, style=filled] -1 -- 2[color=green] -2 -- 3[color=red] -} -gap> Print(DotSymmetricVertexColoredDigraph(D, vertcolors)); -//dot -graph hgn{ -node [shape=circle] - -1[color=blue, style=filled] -2[color=pink, style=filled] -3[color=purple, style=filled] -1 -- 2 -2 -- 3 -} - -gap> Print(DotSymmetricEdgeColoredDigraph(D, edgecolors)); -//dot -graph hgn{ -node [shape=circle] - -1 -2 -3 -1 -- 2[color=green] -2 -- 3[color=red] -} +gap> D := Digraph([[2], [3], []]);; +gap> vert_colors := ["blue", "red", "green"];; +gap> edge_colors := [["black"], ["black"], []];; +gap> labels := [[5], [7], []];; +gap> GraphvizColoredEdgeLabelledDigraph(D, vert_colors, +> edge_colors, labels); + ]]> <#/GAPDoc> +<#GAPDoc Label="DotColoredEdgeLabelledDigraph"> + + + A string. + + WARNING! As of v2.0.0 of &Digraphs; this function is + deprecated in favour of: + + + + It takes the same arguments and returns + AsString(GraphvizColoredEdgeLabelledDigraph(D, vert_colors, + edge_colors, labels)). In particular, both edge_colors and + labels have the same shape as OutNeighbours(D). + + +<#/GAPDoc> + <#GAPDoc Label="DotPartialOrderDigraph"> A string. - This function produces a graphical representation of a partial order - digraph digraph. DotPartialOrderDigraph will return an error - if digraph is not a partial order digraph. See .

+ WARNING! As of v2.0.0 of &Digraphs; these functions are + deprecated in favour of: + + + + It returns + AsString(GraphvizPartialOrderDigraph(digraph)). + + +<#/GAPDoc> - Since digraph is a partial order, it is both reflexive and - transitive. The output of DotPartialOrderDigraph is the - of the - of digraph.

+<#GAPDoc Label="GraphvizPartialOrderDigraph"> + + + A &GRAPHVIZFORGAP; object. + + This function produces a &GRAPHVIZFORGAP; object representing a partial + order digraph D. GraphvizPartialOrderDigraph will return an + error if D is not a partial order digraph. See .

- The output is in dot format (also known as GraphViz) - format. For details about this file format, and information about how - to display or edit this format see - https://www.graphviz.org.

+ Since D is a partial order, it is both reflexive and + transitive. The output of GraphvizPartialOrderDigraph is the + of the + of D.

- The string returned by DotPartialOrderDigraph can be written to a - file using the command .

+ See the &GRAPHVIZFORGAP; package documentation for more details. +

+ See also poset := Digraph([[1, 4], [2], [2, 3, 4], [4]]); +gap> D := Digraph([[1, 4], [2], [2, 3, 4], [4]]); -gap> IsPartialOrderDigraph(poset); +gap> IsPartialOrderDigraph(D); true -gap> FileString("poset.dot", DotPartialOrderDigraph(poset)); -70]]> +gap> GraphvizPartialOrderDigraph(D); +]]> <#/GAPDoc> @@ -419,67 +339,192 @@ gap> FileString("poset.dot", DotPartialOrderDigraph(poset)); A string. - This function produces a graphical representation of a preorder - digraph digraph. DotPreorderDigraph will return an error - if digraph is not a preorder digraph. See WARNING! As of v2.0.0 of &Digraphs; these functions are + deprecated in favour of: + + + + + They return + AsString(GraphvizPreorderDigraph(digraph)). + + +<#/GAPDoc> + +<#GAPDoc Label="GraphvizPreorderDigraph"> + + + + A &GRAPHVIZFORGAP; object. + + These functions produce &GRAPHVIZFORGAP; objects representing a preorder + digraph D. These functions will give an error + if D is not a preorder digraph. See .

A preorder digraph is reflexive and transitive but in general it is not anti-symmetric and may have strongly connected components containing more than one vertex. The - Q obtained by forming the quotient of digraph by the + Q obtained by forming the quotient of D by the partition of its vertices into the strongly connected components satisfies . Thus every vertex of - Q corresponds to a strongly connected component of digraph. - The output of DotPreorderDigraph displays the + Q corresponds to a strongly connected component of D. + The output of GraphvizPreorderDigraph displays the of Q with vertices displayed as rounded rectangles labelled by all of the vertices - of digraph in the corresponding strongly connected component.

+ of D in the corresponding strongly connected component. +

- The output is in dot format (also known as GraphViz) - format. For details about this file format, and information about how - to display or edit this format see - https://www.graphviz.org.

+ See the &GRAPHVIZFORGAP; package documentation for more details. +

- The string returned by DotPreorderDigraph can be written to a - file using the command .

+ See also preset := Digraph([[1, 2, 4, 5], [1, 2, 4, 5], [3, 4], [4], +gap> D := Digraph([[1, 2, 4, 5], [1, 2, 4, 5], [3, 4], [4], > [1, 2, 4, 5]]); -gap> IsPreorderDigraph(preset); +gap> IsPreorderDigraph(D); true -gap> FileString("preset.dot", DotPreorderDigraph(preset)); -179]]> +gap> GraphvizPreorderDigraph(D); +]]> <#/GAPDoc> <#GAPDoc Label="DotHighlightedDigraph"> - + A string. - DotHighlightedDigraph produces a graphical representation of the - digraph digraph, where the vertices in the list verts, and - edges between them, are drawn with colour colour1 and all other - vertices and edges in digraph are drawn with colour colour2. - If colour1 and colour2 are not given then - DotHighlightedDigraph uses black and grey respectively.

+ WARNING! As of v2.0.0 of &Digraphs; these functions are + deprecated in favour of: + + + + + It takes the same arguments as GraphvizHighlightedDigraph + and returns AsString applied to the resulting &GRAPHVIZFORGAP; + object. The default colors are "black" and "grey". + + +<#/GAPDoc> - Note that DotHighlightedDigraph does not validate the colours - colour1 and colour2 - consult the GraphViz documentation to - see what is available. +<#GAPDoc Label="GraphvizHighlightedDigraph"> + + + + A &GRAPHVIZFORGAP; object. + + These functions produce &GRAPHVIZFORGAP; objects representing the digraph + D, where the vertices in the list verts, and edges + between them, are drawn with color color1 and all other vertices + and edges in D are drawn with color color2. If + color1 and color2 are not given, then these functions + use "black" and "grey" respectively. +

- See for more details on the output.

+ See and + for more details on the output. digraph := Digraph([[2, 3], [2], [1, 3]]); +gap> D := Digraph([[2, 3], [2], [1, 3]]); -gap> FileString("my_digraph.dot", DotHighlightedDigraph(digraph, -> [1, 2], "red", "black")); -264]]> +gap> GraphvizHighlightedDigraph(D, [1, 2], "red", "black"); + +gap> D := DigraphSymmetricClosure(D); + +gap> GraphvizHighlightedGraph(D, [1, 2], "red", "black"); +]]> <#/GAPDoc> + +<#GAPDoc Label="GraphvizEdgeWeightedDigraph"> + + + A string. + + These operations produces &GRAPHVIZFORGAP; objects representing the + edge-weighted digraph digraph, in dot format. Its output will + be similar to that of , but the diagram will + also show the weights of the digraph's edges.

+ + If the optional argument path is specified, it should be a list of + lists describing a path in digraph, in the format described in . If specified, the path's edges will be highlighted in + the diagram, as will its start and end vertices.

+ + If the optional argument colors is specified, it should be a record + containing any of the following components: + + + + vert: the colour of ordinary vertices (default "grey"); + + + edge: the colour of ordinary edges (default "black"); + + + highlight: the colour of any edges on path, if any + (default "blue"); + + + source: the colour of the first vertex in path, if any + (default "yellowgreen"); + + + dest: the colour of the final vertex in path, if any + (default "lightpink"). + + + + Each value in the record should be a string representing a colour + understood by the GraphViz software. For details about this format, + see https://www.graphviz.org. If any of the above components are + not specified, or if no colors argument is given, the default value + will be used.

+ + The output of this operation can be passed to + to + attempt to display it graphically on the computer's screen.

+ + gr := EdgeWeightedDigraph([[2], [3], []], [[10], [15], []]);; +gap> path := EdgeWeightedDigraphShortestPath(gr, 2, 3); +[ [ 2, 3 ], [ 1 ] ] +gap> Print(AsString(GraphvizEdgeWeightedDigraph(gr, path))); +//dot +digraph hgn { + node [shape=circle] + 1 [color=gray, style=filled] + 2 [color=yellowgreen, style=filled] + 3 [color=lightpink, style=filled] + 1 -> 2 [color=black, label=10] + 2 -> 3 [color=blue, label=15] +} +]]> + + +<#/GAPDoc> + +<#GAPDoc Label="DotEdgeWeightedDigraph"> + + + A string. + + WARNING! As of v2.0.0 of &Digraphs; these functions are + deprecated in favour of: + + . + + + DotEdgeWeightedDigraph takes the same arguments as GraphvizHighlightedDigraph + and returns AsString applied to the resulting &GRAPHVIZFORGAP; + object. + + +<#/GAPDoc> diff --git a/doc/weights.xml b/doc/weights.xml index cc569a088..b42c261cb 100644 --- a/doc/weights.xml +++ b/doc/weights.xml @@ -365,69 +365,3 @@ gap> RandomUniqueEdgeWeightedDigraph(IsEulerianDigraph, 5, 1 / 3); <#/GAPDoc> -<#GAPDoc Label="DotEdgeWeightedDigraph"> - - - A string. - - This operation produces a graphical representation of the edge-weighted - digraph digraph, in dot format. Its output will be similar to - that of , but the diagram will also show the weights - of the digraph's edges.

- - If the optional argument path is specified, it should be a list of - lists describing a path in digraph, in the format described in . If specified, the path's edges will be highlighted in - the diagram, as will its start and end vertices.

- - If the optional argument colors is specified, it should be a record - containing any of the following components: - - - - vert: the colour of ordinary vertices (default "grey"); - - - edge: the colour of ordinary edges (default "black"); - - - highlight: the colour of any edges on path, if any - (default "blue"); - - - source: the colour of the first vertex in path, if any - (default "yellowgreen"); - - - dest: the colour of the final vertex in path, if any - (default "lightpink"). - - - - Each value in the record should be a string representing a colour understood - by the GraphViz software. For details about this format, see - https://www.graphviz.org. If any of the above components are not - specified, or if no colors argument is given, the default value will - be used.

- - The output of this operation can be passed to to - attempt to display it graphically on the computer's screen.

- - gr := EdgeWeightedDigraph([[2], [3], []], [[10], [15], []]); - -gap> path := EdgeWeightedDigraphShortestPath(g, 2, 3); -[ [ 2, 3 ], [ 1 ] ] -gap> Print(DotEdgeWeightedDigraph(gr, path)); -//dot -digraph hgn{ -node [shape=circle] -1[color=gray, style=filled] -2[color=yellowgreen, style=filled] -3[color=lightpink, style=filled] -1 -> 2[color=black, label=10] -2 -> 3[color=blue, label=15] -}]]> - - -<#/GAPDoc> diff --git a/doc/z-chap5.xml b/doc/z-chap5.xml index 491deb4c8..b97a694b3 100644 --- a/doc/z-chap5.xml +++ b/doc/z-chap5.xml @@ -35,7 +35,6 @@ <#Include Label="DigraphMinimumCut"> <#Include Label="DigraphMinimumCutSet"> <#Include Label="RandomUniqueEdgeWeightedDigraph"> - <#Include Label="DotEdgeWeightedDigraph">

Orders diff --git a/doc/z-chap9.xml b/doc/z-chap9.xml index a3599c40a..682fd0c04 100644 --- a/doc/z-chap9.xml +++ b/doc/z-chap9.xml @@ -1,12 +1,29 @@ Visualising and IO
Visualising a digraph - <#Include Label="Splash"> + <#Include Label="GraphvizDigraph"> <#Include Label="DotDigraph"> - <#Include Label="DotSymmetricDigraph"> + + <#Include Label="GraphvizColoredDigraph"> + <#Include Label="DotColoredDigraph"> + + <#Include Label="GraphvizVertexLabelledDigraph"> + <#Include Label="DotVertexLabelledDigraph"> + + <#Include Label="GraphvizColoredEdgeLabelledDigraph"> + <#Include Label="DotColoredEdgeLabelledDigraph"> + + <#Include Label="GraphvizPartialOrderDigraph"> <#Include Label="DotPartialOrderDigraph"> + + <#Include Label="GraphvizPreorderDigraph"> <#Include Label="DotPreorderDigraph"> + + <#Include Label="GraphvizHighlightedDigraph"> <#Include Label="DotHighlightedDigraph"> + + <#Include Label="GraphvizEdgeWeightedDigraph"> + <#Include Label="DotEdgeWeightedDigraph">
Reading and writing digraphs to a file diff --git a/etc/code-coverage-test-gap.py b/etc/code-coverage-test-gap.py index f52bbdf31..11c6e5666 100755 --- a/etc/code-coverage-test-gap.py +++ b/etc/code-coverage-test-gap.py @@ -71,7 +71,7 @@ _GAP_COMMANDS.extend( [ "UncoverageLineByLine();;", - rf"LoadPackage(\"profiling\", false);;", + r"LoadPackage(\"profiling\", false);;", rf"filesdir := \"{getcwd()}{_PROFILE_DIR}\";;", rf"outdir := \"{_DIR}\";;", rf"x := ReadLineByLineProfile(\"{_DIR}/profile.gz\");;", diff --git a/gap/deprecated.gd b/gap/deprecated.gd new file mode 100644 index 000000000..2e2e3e6f2 --- /dev/null +++ b/gap/deprecated.gd @@ -0,0 +1,43 @@ +############################################################################# +## +## deprecated.gd +## Copyright (C) 2024 James D. Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +DeclareAttribute("DotDigraph", IsDigraph); +DeclareAttribute("DotSymmetricDigraph", IsDigraph); + +DeclareOperation("DotSymmetricVertexColoredDigraph", [IsDigraph, IsList]); +DeclareOperation("DotVertexColoredDigraph", [IsDigraph, IsList]); + +DeclareOperation("DotEdgeColoredDigraph", [IsDigraph, IsList]); +DeclareOperation("DotSymmetricEdgeColoredDigraph", [IsDigraph, IsList]); + +DeclareOperation("DotColoredDigraph", [IsDigraph, IsList, IsList]); +DeclareOperation("DotSymmetricColoredDigraph", [IsDigraph, IsList, IsList]); + +DeclareOperation("DotVertexLabelledDigraph", [IsDigraph]); + +DeclareAttribute("DotPartialOrderDigraph", IsDigraph); +DeclareAttribute("DotPreorderDigraph", IsDigraph); + +DeclareSynonym("DotQuasiorderDigraph", DotPreorderDigraph); + +DeclareOperation("DotHighlightedDigraph", [IsDigraph, IsList]); +DeclareOperation("DotHighlightedDigraph", + [IsDigraph, IsList, IsString, IsString]); +DeclareOperation("DotHighlightedGraph", [IsDigraph, IsList]); +DeclareOperation("DotHighlightedGraph", + [IsDigraph, IsList, IsString, IsString]); + +DeclareOperation("DotColoredEdgeLabelledDigraph", + [IsDigraph, IsList, IsList, IsList]); + +DeclareOperation("DotEdgeWeightedDigraph", [IsDigraph]); +DeclareOperation("DotEdgeWeightedDigraph", [IsDigraph, IsList]); +DeclareOperation("DotEdgeWeightedDigraph", [IsDigraph, IsRecord]); +DeclareOperation("DotEdgeWeightedDigraph", [IsDigraph, IsList, IsRecord]); diff --git a/gap/deprecated.gi b/gap/deprecated.gi new file mode 100644 index 000000000..f344b127e --- /dev/null +++ b/gap/deprecated.gi @@ -0,0 +1,162 @@ +############################################################################# +## +## deprecated.gi +## Copyright (C) 2024 James D. Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +BindGlobal("_PrintDeprecated", function(old, arg...) + Info(InfoWarning, 1, "`", old, "` is deprecated and will be removed in v3", + " use `", Concatenation(List(arg, String)), "` instead!"); +end); + +InstallMethod(DotDigraph, "for a digraph", [IsDigraph], +function(D) + _PrintDeprecated("DotDigraph", "GraphvizDigraph"); + return AsString(GraphvizDigraph(D)); +end); + +InstallMethod(DotSymmetricDigraph, "for a digraph", [IsDigraph], +function(D) + _PrintDeprecated("DotSymmetricDigraph", "GraphvizGraph"); + return AsString(GraphvizGraph(D)); +end); + +InstallMethod(DotSymmetricVertexColoredDigraph, +"for a digraph and list of colors", +[IsDigraph, IsHomogeneousList], +function(D, colors) + _PrintDeprecated("DotSymmetricVertexColoredDigraph", + "GraphvizVertexColoredGraph"); + return AsString(GraphvizVertexColoredGraph(D, colors)); +end); + +InstallMethod(DotVertexColoredDigraph, "for a digraph and a list", +[IsDigraph, IsList], +function(D, colors) + _PrintDeprecated("DotVertexColoredDigraph", + "GraphvizVertexColoredDigraph"); + return AsString(GraphvizVertexColoredDigraph(D, colors)); +end); + +InstallMethod(DotSymmetricEdgeColoredDigraph, +"for a digraph and list of colors", +[IsDigraph, IsHomogeneousList], +function(D, colors) + _PrintDeprecated("DotSymmetricEdgeColoredDigraph", + "GraphvizEdgeColoredGraph"); + return AsString(GraphvizEdgeColoredGraph(D, colors)); +end); + +InstallMethod(DotEdgeColoredDigraph, "for a digraph and a list", +[IsDigraph, IsList], +function(D, colors) + _PrintDeprecated("DotEdgeColoredDigraph", + "GraphvizEdgeColoredDigraph"); + return AsString(GraphvizEdgeColoredDigraph(D, colors)); +end); + +InstallMethod(DotSymmetricColoredDigraph, +"for a digraph, vertex colors, and edge colors", +[IsDigraph, IsHomogeneousList, IsHomogeneousList], +function(D, n_colors, e_colors) + _PrintDeprecated("DotSymmetricColoredDigraph", + "GraphvizColoredGraph"); + return AsString(GraphvizColoredGraph(D, n_colors, e_colors)); +end); + +InstallMethod(DotColoredDigraph, +"for a digraph, vertex colors, and edge colors", +[IsDigraph, IsHomogeneousList, IsHomogeneousList], +function(D, n_colors, e_colors) + _PrintDeprecated("DotColoredDigraph", + "GraphvizColoredDigraph"); + return AsString(GraphvizColoredDigraph(D, n_colors, e_colors)); +end); + +InstallMethod(DotVertexLabelledDigraph, "for a digraph", [IsDigraph], +function(D) + _PrintDeprecated("DotVertexLabelledDigraph", + "GraphvizVertexLabelledDigraph"); + return AsString(GraphvizVertexLabelledDigraph(D)); +end); + +InstallMethod(DotPartialOrderDigraph, "for a digraph", [IsDigraph], +function(D) + _PrintDeprecated("DotPartialOrderDigraph", + "GraphvizPartialOrderDigraph"); + return AsString(GraphvizPartialOrderDigraph(D)); +end); + +InstallMethod(DotPreorderDigraph, "for a digraph", [IsDigraph], +function(D) + _PrintDeprecated("DotPreorderDigraph", + "GraphvizPreorderDigraph"); + return AsString(GraphvizPreorderDigraph(D)); +end); + +InstallMethod(DotHighlightedDigraph, +"for a digraph, list, and two strings", +[IsDigraph, IsList, IsString, IsString], +function(D, hi_verts, hi, lo) + _PrintDeprecated("DotHighlightedDigraph", + "GraphvizHighlightedDigraph"); + return AsString(GraphvizHighlightedDigraph(D, hi_verts, hi, lo)); +end); + +InstallMethod(DotHighlightedDigraph, "for a digraph and list", +[IsDigraph, IsList], +function(D, list) + _PrintDeprecated("DotHighlightedDigraph", + "GraphvizHighlightedDigraph"); + return AsString(GraphvizHighlightedDigraph(D, list, "black", "grey")); +end); + +InstallMethod(DotColoredEdgeLabelledDigraph, +"for a digraph by out-neighbours and three lists", +[IsDigraphByOutNeighboursRep, IsList, IsList, IsList], +function(D, vert, edge, weight) + _PrintDeprecated("DotColoredEdgeLabelledDigraph", + "GraphvizColoredEdgeLabelledDigraph"); + return AsString(GraphvizColoredEdgeLabelledDigraph(D, vert, edge, weight)); +end); + +############################################################################# +# Weighted digraphs +############################################################################# + +InstallMethod(DotEdgeWeightedDigraph, "for a digraph", +[IsDigraph], +function(digraph) + _PrintDeprecated("DotEdgeWeightedDigraph", + "GraphvizEdgeWeightedDigraph"); + return AsString(GraphvizEdgeWeightedDigraph(digraph)); +end); + +InstallMethod(DotEdgeWeightedDigraph, "for a digraph and a list", +[IsDigraph, IsList], +function(digraph, path) + _PrintDeprecated("DotEdgeWeightedDigraph", + "GraphvizEdgeWeightedDigraph"); + return AsString(GraphvizEdgeWeightedDigraph(digraph, path)); +end); + +InstallMethod(DotEdgeWeightedDigraph, "for a digraph and a record", +[IsDigraph, IsRecord], +function(digraph, colors) + _PrintDeprecated("DotEdgeWeightedDigraph", + "GraphvizEdgeWeightedDigraph"); + return AsString(GraphvizEdgeWeightedDigraph(digraph, colors)); +end); + +InstallMethod(DotEdgeWeightedDigraph, "for a digraph, a list, and a record", +[IsDigraph, IsList, IsRecord], +function(digraph, path, colors) + _PrintDeprecated("DotEdgeWeightedDigraph", + "GraphvizEdgeWeightedDigraph"); + return AsString(GraphvizEdgeWeightedDigraph( + digraph, path, colors)); +end); diff --git a/gap/display.gd b/gap/display.gd index 5e0f381e5..d904d9e65 100644 --- a/gap/display.gd +++ b/gap/display.gd @@ -1,27 +1,81 @@ -############################################################################# +############################################################################ ## ## display.gd -## Copyright (C) 2017-19 James D. Mitchell +## Copyright (C) 2017-26 James D. Mitchell ## ## Licensing information can be found in the README file of this package. ## ############################################################################# ## -DeclareAttribute("DotDigraph", IsDigraph); -DeclareOperation("DotColoredDigraph", [IsDigraph, IsList, IsList]); -DeclareOperation("DotColoredEdgeLabelledDigraph", - [IsDigraph, IsList, IsList, IsList]); -DeclareOperation("DotVertexColoredDigraph", [IsDigraph, IsList]); -DeclareOperation("DotEdgeColoredDigraph", [IsDigraph, IsList]); -DeclareOperation("DotVertexLabelledDigraph", [IsDigraph]); -DeclareAttribute("DotSymmetricDigraph", IsDigraph); -DeclareOperation("DotSymmetricColoredDigraph", [IsDigraph, IsList, IsList]); -DeclareOperation("DotSymmetricVertexColoredDigraph", [IsDigraph, IsList]); -DeclareOperation("DotSymmetricEdgeColoredDigraph", [IsDigraph, IsList]); -DeclareAttribute("DotPartialOrderDigraph", IsDigraph); -DeclareAttribute("DotPreorderDigraph", IsDigraph); -DeclareSynonym("DotQuasiorderDigraph", DotPreorderDigraph); -DeclareOperation("DotHighlightedDigraph", [IsDigraph, IsList]); -DeclareOperation("DotHighlightedDigraph", +############################################################################# +# Graphs and digraphs +############################################################################# + +DeclareOperation("GraphvizDigraph", [IsDigraph]); +DeclareOperation("GraphvizGraph", [IsDigraph]); + +############################################################################# +# Vertex coloured graphs and digraphs +############################################################################# + +DeclareOperation("GraphvizVertexColoredDigraph", [IsDigraph, IsList]); +DeclareOperation("GraphvizVertexColoredGraph", [IsDigraph, IsList]); + +############################################################################# +# Edge coloured graphs and digraphs +############################################################################# + +DeclareOperation("GraphvizEdgeColoredDigraph", [IsDigraph, IsList]); +DeclareOperation("GraphvizEdgeColoredGraph", [IsDigraph, IsList]); + +############################################################################# +# Vertex and edge coloured graphs and digraphs +############################################################################# + +DeclareOperation("GraphvizColoredDigraph", [IsDigraph, IsList, IsList]); +DeclareOperation("GraphvizColoredGraph", [IsDigraph, IsList, IsList]); + +############################################################################# +# Vertex labelled graphs and digraphs +############################################################################# + +DeclareOperation("GraphvizVertexLabelledDigraph", [IsDigraph]); +DeclareOperation("GraphvizVertexLabelledGraph", [IsDigraph]); + +############################################################################# +# Edge labelled graphs and digraphs +############################################################################# + +DeclareOperation("GraphvizColoredEdgeLabelledDigraph", +[IsDigraph, IsList, IsList, IsList]); +# TODO impl DeclareOperation("GraphvizColoredEdgeLabelledGraph", [IsDigraph]); + +############################################################################# +# Partial and preorder digraphs +############################################################################# + +DeclareAttribute("GraphvizPartialOrderDigraph", IsDigraph); +DeclareAttribute("GraphvizPreorderDigraph", IsDigraph); + +DeclareSynonym("GraphvizQuasiorderDigraph", GraphvizPreorderDigraph); + +############################################################################# +# Highlighted subdigraphs +############################################################################# + +DeclareOperation("GraphvizHighlightedDigraph", [IsDigraph, IsList]); +DeclareOperation("GraphvizHighlightedDigraph", + [IsDigraph, IsList, IsString, IsString]); +DeclareOperation("GraphvizHighlightedGraph", [IsDigraph, IsList]); +DeclareOperation("GraphvizHighlightedGraph", [IsDigraph, IsList, IsString, IsString]); + +############################################################################# +# Weighted digraphs +############################################################################# + +DeclareOperation("GraphvizEdgeWeightedDigraph", [IsDigraph]); +DeclareOperation("GraphvizEdgeWeightedDigraph", [IsDigraph, IsList]); +DeclareOperation("GraphvizEdgeWeightedDigraph", [IsDigraph, IsRecord]); +DeclareOperation("GraphvizEdgeWeightedDigraph", [IsDigraph, IsList, IsRecord]); diff --git a/gap/display.gi b/gap/display.gi index 64c230d33..833754a4c 100644 --- a/gap/display.gi +++ b/gap/display.gi @@ -1,531 +1,406 @@ ############################################################################# ## ## display.gi -## Copyright (C) 2014-21 James D. Mitchell +## Copyright (C) 2014-24 James D. Mitchell ## ## Licensing information can be found in the README file of this package. ## ############################################################################# ## -# AN's code, adapted by WW - -BindGlobal("DIGRAPHS_DotDigraph", -function(D, node_funcs, edge_funcs) - local str, out, i, func, j, l; - str := "//dot\n"; - Append(str, "digraph hgn{\n"); - Append(str, "node [shape=circle]\n"); - for i in DigraphVertices(D) do - Append(str, StringFormatted("{}", i)); - for func in node_funcs do - Append(str, func(i)); - od; - Append(str, "\n"); + +# TODO: +# * add graph6 string or whatever as a comment at the start of the string +# * check JupyterInterface Splash function +# * for edge colored non-digraphs, should ensure that the edge colors are +# symmetric, i.e. the same colors for x -> y and y -> x + +############################################################################# +# Graphs and digraphs +############################################################################# + +InstallOtherMethod(GraphvizDigraph, "for a digraph by out-neighbours", +[IsDigraphByOutNeighboursRep], +function(D) + local gv, x, y; + gv := GraphvizDigraph("hgn"); + GraphvizSetAttr(gv, "node [shape=circle]"); + for x in DigraphVertices(D) do + GraphvizAddNode(gv, x); od; - out := OutNeighbours(D); - for i in DigraphVertices(D) do - l := Length(out[i]); - for j in [1 .. l] do - Append(str, StringFormatted("{} -> {}", i, out[i][j])); - for func in edge_funcs do - Append(str, func(i, j)); - od; - Append(str, "\n"); + for x in DigraphVertices(D) do + for y in OutNeighboursOfVertexNC(D, x) do + GraphvizAddEdge(gv, x, y); od; od; - Append(str, "}\n"); - return str; -end); - -BindGlobal("DIGRAPHS_ValidRGBValue", -function(str) - local l, chars, x, i; - l := Length(str); - x := 0; - chars := "0123456789ABCDEFabcdef"; - if l = 7 then - if str[1] = '#' then - for i in [2 .. l] do - if str[i] in chars then - x := x + 1; - fi; - od; - fi; - fi; - return x = (l - 1); -end); - -BindGlobal("DIGRAPHS_GraphvizColorsList", fail); - -BindGlobal("DIGRAPHS_GraphvizColors", -function() - local f; - if DIGRAPHS_GraphvizColorsList = fail then - f := IO_File(Concatenation(DIGRAPHS_Dir(), "/data/colors.p")); - MakeReadWriteGlobal("DIGRAPHS_GraphvizColorsList"); - DIGRAPHS_GraphvizColorsList := IO_Unpickle(f); - MakeReadOnlyGlobal("DIGRAPHS_GraphvizColorsList"); - IO_Close(f); - fi; - return DIGRAPHS_GraphvizColorsList; + return gv; end); -BindGlobal("DIGRAPHS_ValidVertColors", -function(D, verts) - local v, sum, colors, col; - v := DigraphVertices(D); - sum := 0; - if Length(verts) <> Length(v) then - ErrorNoReturn("the number of vertex colors must be the same as the number", - " of vertices, expected ", Length(v), " but found ", Length(verts), ""); +InstallOtherMethod(GraphvizGraph, "for a digraph by out-neighbours", +[IsDigraphByOutNeighboursRep], +function(D) + local gv, x, y; + if not IsSymmetricDigraph(D) then + ErrorNoReturn("the argument (a digraph) must be symmetric"); fi; - colors := DIGRAPHS_GraphvizColors(); - if Length(verts) = Length(v) then - for col in verts do - if not IsString(col) then - ErrorNoReturn("expected a string"); - elif DIGRAPHS_ValidRGBValue(col) = false and - (col in colors) = false then - ErrorNoReturn("expected RGB Value or valid color name as defined", - " by GraphViz 2.44.1 X11 Color Scheme", - " http://graphviz.org/doc/info/colors.html"); - else - sum := sum + 1; + gv := GraphvizGraph("hgn"); + GraphvizSetAttr(gv, "node [shape=circle]"); + for x in DigraphVertices(D) do + GraphvizAddNode(gv, x); + od; + for x in DigraphVertices(D) do + for y in OutNeighboursOfVertexNC(D, x) do + if x >= y then + GraphvizAddEdge(gv, x, y); fi; od; - if sum = Length(verts) then - return true; - fi; - fi; + od; + return gv; end); -BindGlobal("DIGRAPHS_ValidEdgeColors", -function(D, edge) - local out, l, counter, sum, colors, v, col; - out := OutNeighbours(D); - l := Length(edge); - counter := 0; - sum := 0; - colors := DIGRAPHS_GraphvizColors(); - if Length(edge) <> Length(out) then - ErrorNoReturn("the list of edge colors needs to have the", - " same shape as the out-neighbours of the digraph"); - else - for v in [1 .. l] do - sum := 0; - if Length(out[v]) <> Length(edge[v]) then - ErrorNoReturn("the list of edge colors needs to have the", - " same shape as the out-neighbours of the digraph"); - else - for col in edge[v] do - if not IsString(col) then - ErrorNoReturn("expected a string"); - elif DIGRAPHS_ValidRGBValue(col) = false and - (col in colors) = false then - ErrorNoReturn("expected RGB Value or valid color name as defined", - " by GraphViz 2.44.1 X11 Color Scheme", - " http://graphviz.org/doc/info/colors.html"); - else - sum := sum + 1; - fi; - od; - if sum = Length(edge[v]) then - counter := counter + 1; - fi; - fi; - od; - if counter = Length(edge) then - return true; - fi; - fi; -end); +############################################################################# +# Vertex coloured graphs and digraphs +############################################################################# -InstallMethod(DotDigraph, "for a digraph by out-neighbours", -[IsDigraphByOutNeighboursRep], -D -> DIGRAPHS_DotDigraph(D, [], [])); - -InstallMethod(DotColoredDigraph, -"for a digraph by out-neighbours and two lists", -[IsDigraphByOutNeighboursRep, IsList, IsList], -function(D, vert, edge) - local vert_func, edge_func; - if DIGRAPHS_ValidVertColors(D, vert) - and DIGRAPHS_ValidEdgeColors(D, edge) then - vert_func := i -> StringFormatted("[color={}, style=filled]", vert[i]); - edge_func := {i, j} -> StringFormatted("[color={}]", edge[i][j]); - return DIGRAPHS_DotDigraph(D, [vert_func], [edge_func]); - fi; -end); +InstallMethod(GraphvizVertexColoredDigraph, "for a digraph and a list", +[IsDigraph, IsList], +{D, colors} -> GraphvizSetNodeColors(GraphvizDigraph(D), colors)); -InstallMethod(DotColoredEdgeLabelledDigraph, -"for a digraph by out-neighbours and three lists", -[IsDigraphByOutNeighboursRep, IsList, IsList, IsList], -function(D, vert, edge, weight) - local vert_func, edge_func; - # See https://graphs.grevian.org/example - if DIGRAPHS_ValidVertColors(D, vert) - and DIGRAPHS_ValidEdgeColors(D, edge) then - vert_func := i -> StringFormatted("[color={}, style=filled]", vert[i]); - edge_func := {i, j} -> StringFormatted("[color={}, label={}]", - edge[i][j], weight[i][j]); - return DIGRAPHS_DotDigraph(D, [vert_func], [edge_func]); - fi; -end); +InstallMethod(GraphvizVertexColoredGraph, "for a digraph and a list", +[IsDigraph, IsList], +# IsSymmetricDigraph checked by GraphvizGraph +{D, colors} -> GraphvizSetNodeColors(GraphvizGraph(D), colors)); -InstallMethod(DotVertexColoredDigraph, -"for a digraph by out-neighbours and a list", -[IsDigraphByOutNeighboursRep, IsList], -function(D, vert) - local func; - if DIGRAPHS_ValidVertColors(D, vert) then - func := i -> StringFormatted("[color={}, style=filled]", vert[i]); - return DIGRAPHS_DotDigraph(D, [func], []); - fi; -end); +############################################################################# +# Edge coloured graphs and digraphs +############################################################################# -InstallMethod(DotEdgeColoredDigraph, -"for a digraph by out-neighbours and a list", -[IsDigraphByOutNeighboursRep, IsList], -function(D, edge) - local func; - if DIGRAPHS_ValidEdgeColors(D, edge) then - func := {i, j} -> StringFormatted("[color={}]", edge[i][j]); - return DIGRAPHS_DotDigraph(D, [], [func]); +# This function is here rather than graphviz b/c otherwise if D has multiple +# edges we can't reliably get the corresponding graphviz edge from the head and +# tail of the edge from gv. +BindGlobal("DIGRAPHS_ErrorIfNotEdgeColoring", +function(D, colors) + local out, i; + + out := OutNeighbours(D); + if Length(colors) <> Length(out) then + ErrorFormatted("the 2nd argument (edge colors) must have ", + "the same number of entries as the 1st argument ", + "(a digraph) has nodes, expected {} but found {}", + Length(out), + Length(colors)); fi; + for i in [1 .. Length(colors)] do + if not IsList(colors[i]) then + ErrorFormatted("the 2nd argument (edge colors) must be ", + "a list of lists, found {} in position {}", + TNAM_OBJ(colors[i]), + i); + elif Length(out[i]) <> Length(colors[i]) then + ErrorFormatted("the 2nd argument (edge colors) must have ", + "the same shape as the out neighbours of the 1st ", + "argument (a digraph), in position {} expected ", + "a list of length {} but found list of length {}", + i, + Length(out[i]), + Length(colors[i])); + fi; + Perform(colors[i], ErrorIfNotValidColor); + od; end); -InstallMethod(DotVertexLabelledDigraph, "for a digraph by out-neighbours", -[IsDigraphByOutNeighboursRep], -function(D) - local func; - func := i -> StringFormatted(" [label=\"{}\"]", DigraphVertexLabel(D, i)); - return DIGRAPHS_DotDigraph(D, [func], []); -end); +BindGlobal("DIGRAPHS_AddEdgesAndColorsNC", +function(D, gv, colors) + local out, e, n, i; -BindGlobal("DIGRAPHS_DotSymmetricDigraph", -function(D, node_funcs, edge_funcs) - local out, str, i, j, func; - if not IsSymmetricDigraph(D) then - ErrorNoReturn("the argument must be a symmetric digraph,"); - fi; - out := OutNeighbours(D); - str := "//dot\n"; - Append(str, "graph hgn{\n"); - Append(str, "node [shape=circle]\n\n"); - for i in DigraphVertices(D) do - Append(str, StringFormatted("{}", i)); - for func in node_funcs do - Append(str, func(i)); - od; - Append(str, "\n"); - od; - for i in DigraphVertices(D) do - for j in [1 .. Length(out[i])] do - if out[i][j] >= i then - Append(str, StringFormatted("{} -- {}", i, out[i][j])); - for func in edge_funcs do - Append(str, func(i, j)); - od; - Append(str, "\n"); + # This duplicates code in the GraphvizDigraph function because otherwise if D + # has multiple edges we can't reliably get the corresponding graphviz edge + # from the head and tail of the edge from gv. + out := OutNeighbours(D); + for n in DigraphVertices(D) do + for i in [1 .. Length(out[n])] do + if IsGraphvizDigraph(gv) or n >= out[n][i] then + e := GraphvizAddEdge(gv, n, out[n][i]); + GraphvizSetAttr(e, "color", colors[n][i]); fi; od; od; - Append(str, "}\n"); - return str; + return gv; end); -InstallMethod(DotSymmetricDigraph, "for a digraph by out-neighbours", -[IsDigraphByOutNeighboursRep], -D -> DIGRAPHS_DotSymmetricDigraph(D, [], [])); - -InstallMethod(DotSymmetricColoredDigraph, -"for a digraph by out-neighbours and two lists", -[IsDigraphByOutNeighboursRep, IsList, IsList], -function(D, vert, edge) - local vert_func, edge_func; - if DIGRAPHS_ValidVertColors(D, vert) - and DIGRAPHS_ValidEdgeColors(D, edge) then - vert_func := i -> StringFormatted("[color={}, style=filled]", vert[i]); - edge_func := {i, j} -> StringFormatted("[color={}]", edge[i][j]); - return DIGRAPHS_DotSymmetricDigraph(D, [vert_func], [edge_func]); - fi; -end); - -InstallMethod(DotSymmetricVertexColoredDigraph, +InstallMethod(GraphvizEdgeColoredDigraph, "for a digraph by out-neighbours and a list", [IsDigraphByOutNeighboursRep, IsList], -function(D, vert) - local func; - if DIGRAPHS_ValidVertColors(D, vert) then - func := i -> StringFormatted ("[color={}, style=filled]", vert[i]); - return DIGRAPHS_DotSymmetricDigraph(D, [func], []); - fi; +function(D, colors) + local gv; + DIGRAPHS_ErrorIfNotEdgeColoring(D, colors); + gv := GraphvizDigraph(NullDigraph(DigraphNrVertices(D))); + return DIGRAPHS_AddEdgesAndColorsNC(D, gv, colors); end); -InstallMethod(DotSymmetricEdgeColoredDigraph, +InstallMethod(GraphvizEdgeColoredGraph, "for a digraph by out-neighbours and a list", [IsDigraphByOutNeighboursRep, IsList], -function(D, edge) - local func; - if DIGRAPHS_ValidEdgeColors(D, edge) then - func := {i, j} -> StringFormatted("[color={}]", edge[i][j]); - return DIGRAPHS_DotSymmetricDigraph(D, [], [func]); +function(D, colors) + local gv; + if not IsSymmetricDigraph(D) then + ErrorNoReturn("the argument (a digraph) must be symmetric"); fi; + DIGRAPHS_ErrorIfNotEdgeColoring(D, colors); + gv := GraphvizGraph(NullDigraph(DigraphNrVertices(D))); + return DIGRAPHS_AddEdgesAndColorsNC(D, gv, colors); end); -# AN's code - -if not IsBound(Splash) then # This function is written by A. Egri-Nagy - BindGlobal("VizViewers", - ["xpdf", "xdg-open", "open", "evince", "okular", "gv"]); - - BindGlobal("Splash", - function(arg...) - local str, opt, path, dir, tdir, file, viewer, type, inn, filetype, out, - engine; +############################################################################# +# Vertex and edge coloured graphs and digraphs +############################################################################# - if not IsString(arg[1]) then - ErrorNoReturn("the 1st argument must be a string,"); - fi; - str := arg[1]; +InstallMethod(GraphvizColoredDigraph, +"for a digraph, list, and list", +[IsDigraph, IsList, IsList], +{D, n_colors, e_colors} -> GraphvizSetNodeColors( + GraphvizEdgeColoredDigraph(D, e_colors), + n_colors)); + +InstallMethod(GraphvizColoredGraph, +"for a digraph, list, and list", +[IsDigraph, IsList, IsList], +# IsSymmetricDigraph checked by GraphvizEdgeColoredGraph +{D, n_colors, e_colors} -> GraphvizSetNodeColors( + GraphvizEdgeColoredGraph(D, e_colors), + n_colors)); - opt := rec(); - if IsBound(arg[2]) and IsRecord(arg[2]) then - opt := arg[2]; - elif IsBound(arg[2]) then - ErrorNoReturn("the 2nd argument must be a record,"); - fi; +############################################################################# +# Vertex labelled graphs and digraphs +############################################################################# - # path - path := UserHomeExpand("~/"); # default - if IsBound(opt.path) then - path := opt.path; - fi; +InstallMethod(GraphvizVertexLabelledDigraph, "for a digraph", +[IsDigraph], +D -> GraphvizSetNodeLabels(GraphvizDigraph(D), DigraphVertexLabels(D))); - # directory - if IsBound(opt.directory) then - if not opt.directory in DirectoryContents(path) then - Exec(Concatenation("mkdir ", path, opt.directory)); - fi; - dir := Concatenation(path, opt.directory, "/"); - elif IsBound(opt.path) then - if not "tmp.viz" in DirectoryContents(path) then - tdir := Directory(Concatenation(path, "/", "tmp.viz")); - dir := Filename(tdir, ""); - fi; - else - tdir := DirectoryTemporary(); - dir := Filename(tdir, ""); - fi; +InstallMethod(GraphvizVertexLabelledGraph, "for a digraph", +[IsDigraph], +# symmetry checked in GraphvizGraph +D -> GraphvizSetNodeLabels(GraphvizGraph(D), DigraphVertexLabels(D))); - # file - file := "vizpicture"; # default - if IsBound(opt.filename) then - file := opt.filename; - fi; +############################################################################# +# Edge labelled graphs and digraphs +############################################################################# - # viewer - if IsBound(opt.viewer) then - viewer := opt.viewer; - if not IsString(viewer) then - ErrorNoReturn("the option `viewer` must be a string, not an ", - TNAM_OBJ(viewer), ","); - elif Filename(DirectoriesSystemPrograms(), viewer) = fail then - ErrorNoReturn("the viewer \"", viewer, "\" specified in the option ", - "`viewer` is not available,"); - fi; - else - viewer := First(VizViewers, x -> - Filename(DirectoriesSystemPrograms(), x) <> fail); - if viewer = fail then - ErrorNoReturn("none of the default viewers ", VizViewers, - " is available, please specify an available viewer", - " in the options record component `viewer`,"); - fi; - fi; +# TODO maybe don't include this? - # type - if IsBound(opt.type) and (opt.type = "latex" or opt.type = "dot") then - type := opt.type; - elif Length(str) >= 6 and str{[1 .. 6]} = "%latex" then - type := "latex"; - elif Length(str) >= 5 and str{[1 .. 5]} = "//dot" then - type := "dot"; - else - ErrorNoReturn("the component \"type\" of the 2nd argument ", - " must be \"dot\" or \"latex\","); - fi; - if type = "latex" then - inn := Concatenation(dir, file, ".tex"); - else # type = "dot" - inn := Concatenation(dir, file, ".dot"); - fi; +InstallMethod(GraphvizColoredEdgeLabelledDigraph, +"for a digraph, vertex colors, edge colors, and edge labels", +[IsDigraph, IsList, IsList, IsList], +function(D, n_colors, e_colors, weights) + local gv, out, edge, v, i; - # output type and name - filetype := "pdf"; # default - if IsBound(opt.filetype) and IsString(opt.filetype) and type <> "latex" then - filetype := opt.filetype; - fi; - out := Concatenation(dir, file, ".", filetype); - - # engine - engine := "dot"; # default - if IsBound(opt.engine) then - engine := opt.engine; - if not engine in ["dot", "neato", "twopi", "circo", - "fdp", "sfdp", "patchwork"] then - ErrorNoReturn("the component \"engine\" of the 2nd argument ", - " must be one of: \"dot\", \"neato\", ", - "\"twopi\", \"circo\", \"fdp\", \"sfdp\", ", - "or \"patchwork\""); - fi; - fi; + DIGRAPHS_ErrorIfNotEdgeColoring(D, e_colors); + gv := GraphvizVertexColoredDigraph( + NullDigraph(DigraphNrVertices(D)), n_colors); + out := OutNeighbours(D); - # Write and compile the file - FileString(inn, str); - if type = "latex" then - # Requires GAP >= 4.11: - # Exec(StringFormatted("cd {}; pdflatex {} 2>/dev/null 1>/dev/null", dir); - Exec(Concatenation("cd ", dir, ";", - "pdflatex -interaction=nonstopmode ", - file, - " 2>/dev/null 1>/dev/null")); - else # type = "dot" - # Requires GAP >= 4.11: - # Exec(StringFormatted("{} -T {} {} -o {}", engine, filetype, inn, out)); - Exec(Concatenation(engine, " -T", filetype, " ", inn, " -o ", out)); - fi; - Exec(Concatenation(viewer, " ", out, " 2>/dev/null 1>/dev/null &")); - end); -fi; + for v in DigraphVertices(D) do + for i in [1 .. Length(out[v])] do + edge := GraphvizAddEdge(gv, v, out[v][i]); + GraphvizSetAttr(edge, "color", e_colors[v][i]); + GraphvizSetAttr(edge, "label", weights[v][i]); + od; + od; + return gv; +end); -# CR's code +############################################################################# +# Partial and preorder digraphs +############################################################################# -InstallMethod(DotPartialOrderDigraph, "for a partial order digraph", +InstallMethod(GraphvizPartialOrderDigraph, "for a partial order digraph", [IsDigraph], function(D) if not IsPartialOrderDigraph(D) then - ErrorNoReturn("the argument must be a partial order digraph,"); + ErrorNoReturn("the argument (a digraph) must be a partial order"); fi; D := DigraphMutableCopyIfMutable(D); - return DotDigraph(DigraphReflexiveTransitiveReduction(D)); + return GraphvizDigraph(DigraphReflexiveTransitiveReduction(D)); end); -InstallMethod(DotPreorderDigraph, "for a preorder digraph", +InstallMethod(GraphvizPreorderDigraph, "for a preorder digraph", [IsDigraph], function(D) - local comps, quo, red, str, c, x, e; + local comps, gv, label, node, nodes, c, x, e; + if not IsPreorderDigraph(D) then - ErrorNoReturn("the argument must be a preorder digraph,"); + ErrorNoReturn("the argument (a digraph) must be a preorder"); fi; # Quotient by the strongly connected components to get a partial order # D and draw this without loops or edges implied by transitivity. - D := DigraphMutableCopyIfMutable(D); - comps := DigraphStronglyConnectedComponents(D).comps; - quo := DigraphRemoveAllMultipleEdges(QuotientDigraph(D, comps)); - red := DigraphReflexiveTransitiveReduction(quo); + comps := DigraphStronglyConnectedComponents(D).comps; + D := DigraphMutableCopy(D); + DigraphRemoveAllMultipleEdges(QuotientDigraph(D, comps)); + DigraphReflexiveTransitiveReduction(D); - str := "//dot\n"; - Append(str, "digraph graphname {\n"); - Append(str, "node [shape=Mrecord, height=0.5, fixedsize=true]"); - Append(str, "ranksep=1;\n"); + gv := GraphvizDigraph("graphname"); + GraphvizSetAttr(gv, "node [shape=\"Mrecord\"]"); + GraphvizSetAttr(gv, "height=\"0.5\""); + GraphvizSetAttr(gv, "fixedsize=\"true\""); + GraphvizSetAttr(gv, "ranksep=\"1\""); - # Each vertex of the quotient D is labelled by its preimage. for c in [1 .. Length(comps)] do - Append(str, String(c)); - Append(str, " [label=\""); - Append(str, String(comps[c][1])); + + label := "\""; + Append(label, String(comps[c][1])); for x in comps[c]{[2 .. Length(comps[c])]} do - Append(str, "|"); - Append(str, String(x)); + Append(label, "|"); + Append(label, String(x)); od; - Append(str, "\", width="); - Append(str, String(Float(Length(comps[c]) / 2))); - Append(str, "]\n"); + Append(label, "\""); + + node := GraphvizAddNode(gv, c); + GraphvizSetAttr(node, "label", label); + GraphvizSetAttr(node, "width", Float(Length(comps[c]) / 2)); od; - # Add the edges of the quotient D. - for e in DigraphEdges(red) do - Append(str, Concatenation(String(e[1]), " -> ", String(e[2]), "\n")); + nodes := GraphvizNodes(gv); + for e in DigraphEdges(D) do + GraphvizAddEdge(gv, nodes[e[1]], nodes[e[2]]); od; - Append(str, "}"); - return str; + return gv; end); -InstallMethod(DotHighlightedDigraph, "for a digraph and list", -[IsDigraph, IsList], -{D, list} -> DotHighlightedDigraph(D, list, "black", "grey")); +############################################################################# +# Highlighted subdigraphs +############################################################################# -InstallMethod(DotHighlightedDigraph, -"for a digraph by out-neighbours, list, and two strings", -[IsDigraphByOutNeighboursRep, IsList, IsString, IsString], -function(D, highverts, highcolour, lowcolour) - local lowverts, out, str, i, j; - - if not IsSubset(DigraphVertices(D), highverts) then - ErrorNoReturn("the 2nd argument must be a list of vertices ", - "of the 1st argument ,"); - elif IsEmpty(highcolour) then - ErrorNoReturn("the 3rd argument must be a string ", - "containing the name of a colour,"); - elif IsEmpty(lowcolour) then - ErrorNoReturn("the 4th argument must be a string ", - "containing the name of a colour,"); +BindGlobal("DIGRAPHS_GraphvizHighlight", +function(D, gv, hi_verts, hi, lo) + local node, color, out, nodes, edge, v, i, j; + + if not IsSubset(DigraphVertices(D), hi_verts) then + ErrorNoReturn("the 2nd argument (list) must consist of vertices ", + "of the 1st argument (a digraph)"); fi; + ErrorIfNotValidColor(hi); + ErrorIfNotValidColor(lo); - lowverts := Difference(DigraphVertices(D), highverts); - out := OutNeighbours(D); - str := "//dot\n"; + GraphvizSetAttr(gv, "shape", "circle"); - Append(str, "digraph hgn{\n"); + for v in DigraphVertices(D) do + node := GraphvizAddNode(gv, v); + if v in hi_verts then + color := hi; + else + color := lo; + fi; + GraphvizSetAttr(node, "color", color); + od; - Append(str, "subgraph lowverts{\n"); - Append(str, Concatenation("node [shape=circle, color=", - lowcolour, - "]\n edge [color=", - lowcolour, - "]\n")); + out := OutNeighbours(D); + nodes := GraphvizNodes(gv); - for i in lowverts do - Append(str, Concatenation(String(i), "\n")); + for i in DigraphVertices(D) do + for j in out[i] do + if IsGraphvizDigraph(gv) or i >= j then + edge := GraphvizAddEdge(gv, nodes[i], nodes[j]); + if i in hi_verts and j in hi_verts then + color := hi; + else + color := lo; + fi; + GraphvizSetAttr(edge, "color", color); + fi; + od; od; - Append(str, "}\n"); + return gv; +end); - Append(str, "subgraph highverts{\n"); - Append(str, Concatenation("node [shape=circle, color=", - highcolour, - "]\n edge [color=", - highcolour, - "]\n")); +InstallMethod(GraphvizHighlightedDigraph, +"for a digraph by out-neighbours, list, and two strings", +[IsDigraphByOutNeighboursRep, IsList, IsString, IsString], +{D, hi_verts, hi, lo} -> +DIGRAPHS_GraphvizHighlight(D, GraphvizDigraph(), hi_verts, hi, lo)); - for i in highverts do - Append(str, Concatenation(String(i), "\n")); - od; +InstallMethod(GraphvizHighlightedDigraph, "for a digraph and list", +[IsDigraph, IsList], +{D, list} -> GraphvizHighlightedDigraph(D, list, "black", "grey")); - Append(str, "}\n"); +InstallMethod(GraphvizHighlightedGraph, +"for a digraph by out-neighbours, list, and two strings", +[IsDigraphByOutNeighboursRep, IsList, IsString, IsString], +function(D, hi_verts, hi, lo) + if not IsSymmetricDigraph(D) then + ErrorNoReturn("the argument (a digraph) must be symmetric"); + fi; + return DIGRAPHS_GraphvizHighlight(D, GraphvizGraph(), hi_verts, hi, lo); +end); - Append(str, "subgraph lowverts{\n"); - for i in lowverts do - for j in out[i] do - Append(str, Concatenation(String(i), " -> ", String(j), "\n")); - od; - od; - Append(str, "}\n"); +InstallMethod(GraphvizHighlightedGraph, "for a digraph and list", +[IsDigraph, IsList], +# IsSymmetricDigraph checked in GraphvizHighlightedGraph +{D, list} -> GraphvizHighlightedGraph(D, list, "black", "grey")); - Append(str, "subgraph highverts{\n"); - for i in highverts do - for j in out[i] do - Append(str, Concatenation(String(i), " -> ", String(j))); - if j in lowverts then - Append(str, Concatenation(" [color=", lowcolour, "]")); - fi; - Append(str, "\n"); - od; +############################################################################# +# Weighted digraphs +############################################################################# + +InstallMethod(GraphvizEdgeWeightedDigraph, "for a digraph", +[IsDigraph], +digraph -> GraphvizEdgeWeightedDigraph(digraph, [[], []], rec())); + +InstallMethod(GraphvizEdgeWeightedDigraph, "for a digraph and a list", +[IsDigraph, IsList], +{digraph, path} -> GraphvizEdgeWeightedDigraph(digraph, path, rec())); + +InstallMethod(GraphvizEdgeWeightedDigraph, "for a digraph and a record", +[IsDigraph, IsRecord], +{digraph, colors} -> GraphvizEdgeWeightedDigraph(digraph, [[], []], colors)); + +# TODO JDM is not completely sure this is implemented in the spirit of the +# other functions in this file. + +InstallMethod(GraphvizEdgeWeightedDigraph, +"for a digraph, a list, and a record", +[IsDigraph, IsList, IsRecord], +function(digraph, path, colors) + local default_colors, edge, vert, source, dest, name, vertColours, + edgeColours, path_verts, path_edge_indices, path_length, i; + + # Use default colours for any that aren't specified + default_colors := rec(highlight := "blue", + edge := "black", + vert := "gray", + source := "yellowgreen", + dest := "lightpink"); + for name in RecNames(colors) do + if IsBound(default_colors.(name)) then + default_colors.(name) := colors.(name); + else + Error("the 3rd argument contains unsupported option ", + "named '", name, "'"); + fi; od; - Append(str, "}\n}\n"); + colors := default_colors; + + # fill with basic colours + vertColours := ListWithIdenticalEntries(DigraphNrVertices(digraph), + colors.vert); + edgeColours := List(OutNeighbours(digraph), + outs_u -> List(outs_u, _ -> colors.edge)); + + # highlight the path + path_verts := path[1]; + path_edge_indices := path[2]; + path_length := Length(path_edge_indices); + if not IsEmpty(path_verts) then + for i in [1 .. path_length] do + edgeColours[path_verts[i]][path_edge_indices[i]] := colors.highlight; + od; + vertColours[path_verts[1]] := colors.source; + vertColours[path_verts[path_length + 1]] := colors.dest; + fi; - return str; + # draw with the weights as labels + return GraphvizColoredEdgeLabelledDigraph(digraph, + vertColours, edgeColours, EdgeWeights(digraph)); end); diff --git a/gap/weights.gd b/gap/weights.gd index 423950b61..4bcacf378 100644 --- a/gap/weights.gd +++ b/gap/weights.gd @@ -54,8 +54,3 @@ DeclareOperation("RandomUniqueEdgeWeightedDigraph", DeclareOperation("RandomUniqueEdgeWeightedDigraph", [IsFunction, IsPosInt, IsRat]); -# 7. Drawing edge weighted digraphs -DeclareOperation("DotEdgeWeightedDigraph", [IsDigraph]); -DeclareOperation("DotEdgeWeightedDigraph", [IsDigraph, IsList]); -DeclareOperation("DotEdgeWeightedDigraph", [IsDigraph, IsRecord]); -DeclareOperation("DotEdgeWeightedDigraph", [IsDigraph, IsList, IsRecord]); diff --git a/gap/weights.gi b/gap/weights.gi index dc1081fcf..93030fe01 100644 --- a/gap/weights.gi +++ b/gap/weights.gi @@ -905,58 +905,3 @@ DIGRAPHS_RandomEdgeWeightedDigraphFilt); # 7. Drawing edge weighted digraphs ############################################################################# -InstallMethod(DotEdgeWeightedDigraph, "for a digraph", -[IsDigraph], -digraph -> DotEdgeWeightedDigraph(digraph, [[], []], rec())); - -InstallMethod(DotEdgeWeightedDigraph, "for a digraph and a list", -[IsDigraph, IsList], -{digraph, path} -> DotEdgeWeightedDigraph(digraph, path, rec())); - -InstallMethod(DotEdgeWeightedDigraph, "for a digraph and a record", -[IsDigraph, IsRecord], -{digraph, colors} -> DotEdgeWeightedDigraph(digraph, [[], []], colors)); - -InstallMethod(DotEdgeWeightedDigraph, "for a digraph, a list, and a record", -[IsDigraph, IsList, IsRecord], -function(digraph, path, colors) - local default_colors, edge, vert, source, dest, name, vertColours, - edgeColours, path_verts, path_edge_indices, path_length, i; - - # Use default colours for any that aren't specified - default_colors := rec(highlight := "blue", - edge := "black", - vert := "gray", - source := "yellowgreen", - dest := "lightpink"); - for name in RecNames(colors) do - if IsBound(default_colors.(name)) then - default_colors.(name) := colors.(name); - else - Error("3rd arg contains unsupported option named '", name, "'"); - fi; - od; - colors := default_colors; - - # fill with basic colours - vertColours := ListWithIdenticalEntries(DigraphNrVertices(digraph), - colors.vert); - edgeColours := List(OutNeighbours(digraph), - outs_u -> List(outs_u, _ -> colors.edge)); - - # highlight the path - path_verts := path[1]; - path_edge_indices := path[2]; - path_length := Length(path_edge_indices); - if not IsEmpty(path_verts) then - for i in [1 .. path_length] do - edgeColours[path_verts[i]][path_edge_indices[i]] := colors.highlight; - od; - vertColours[path_verts[1]] := colors.source; - vertColours[path_verts[path_length + 1]] := colors.dest; - fi; - - # draw with the weights as labels - return DotColoredEdgeLabelledDigraph(digraph, vertColours, edgeColours, - EdgeWeights(digraph)); -end); diff --git a/init.g b/init.g index 20ed2f3dd..b61165fc4 100644 --- a/init.g +++ b/init.g @@ -64,5 +64,6 @@ ReadPackage("digraphs", "gap/cliques.gd"); ReadPackage("digraphs", "gap/planar.gd"); ReadPackage("digraphs", "gap/examples.gd"); ReadPackage("digraphs", "gap/weights.gd"); +ReadPackage("digraphs", "gap/deprecated.gd"); DeclareInfoClass("InfoDigraphs"); diff --git a/read.g b/read.g index 40ae189c5..50f8815c5 100644 --- a/read.g +++ b/read.g @@ -47,3 +47,4 @@ ReadPackage("digraphs", "gap/cliques.gi"); ReadPackage("digraphs", "gap/planar.gi"); ReadPackage("digraphs", "gap/examples.gi"); ReadPackage("digraphs", "gap/weights.gi"); +ReadPackage("digraphs", "gap/deprecated.gi"); diff --git a/tst/standard/display.tst b/tst/standard/display.tst new file mode 100644 index 000000000..a6d09ee31 --- /dev/null +++ b/tst/standard/display.tst @@ -0,0 +1,700 @@ +############################################################################# +## +#W standard/display.tst +#Y Copyright (C) 2014-24 James D. Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## +gap> START_TEST("Digraphs package: standard/display.tst"); +gap> LoadPackage("digraphs", false);; + +# +gap> DIGRAPHS_StartTest(); + +# Display and PrintString and String +gap> Digraph([]); + +gap> Digraph([[]]); + +gap> Digraph([[1]]); + +gap> Digraph([[2], []]); + +gap> gr := Digraph([[1, 2], [2], []]); + +gap> PrintString(gr); +"DigraphFromDigraph6String(\"&Bq?\")" +gap> String(gr); +"DigraphFromDigraph6String(\"&Bq?\")" +gap> gr := Digraph([[2], [1], [], [3]]); + +gap> PrintString(gr); +"DigraphFromDigraph6String(\"&CQ?G\")" +gap> String(gr); +"DigraphFromDigraph6String(\"&CQ?G\")" +gap> r := rec(DigraphVertices := [1, 2, 3], +> DigraphSource := [1, 2], +> DigraphRange := [2, 3]);; +gap> gr := Digraph(r); + +gap> PrintString(gr); +"ChainDigraph(3)" +gap> String(gr); +"ChainDigraph(3)" + +# DotDigraph and DotSymmetricDigraph +gap> r := rec(DigraphVertices := [1 .. 3], DigraphSource := [1, 1, 1, 1], +> DigraphRange := [1, 2, 2, 3]);; +gap> gr := Digraph(r); + +gap> dot := DotDigraph(gr);; +gap> dot{[1 .. 50]}; +"//dot\ndigraph hgn {\n\tnode [shape=circle] \n\t1\n\t2\n\t3" +gap> dot{[51 .. 75]}; +"\n\t1 -> 1\n\t1 -> 2\n\t1 -> 2\n" +gap> r := rec(DigraphVertices := [1 .. 8], +> DigraphSource := [1, 1, 2, 2, 3, 4, 4, 4, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 8, +> 8], +> DigraphRange := [6, 7, 1, 6, 5, 1, 4, 8, 1, 3, 6, 6, 7, 7, 1, 4, 4, 5, 7, 5, +> 6]);; +gap> gr1 := Digraph(r); + +gap> DotDigraph(gr1){[50 .. 109]}; +"3\n\t4\n\t5\n\t6\n\t7\n\t8\n\t1 -> 6\n\t1 -> 7\n\t2 -> 1\n\t2 -> 6\n\t3 -> 5\ +\n\t4 " +gap> adj := [[2], [1, 3], [2, 3, 4], [3]]; +[ [ 2 ], [ 1, 3 ], [ 2, 3, 4 ], [ 3 ] ] +gap> gr2 := Digraph(adj); + +gap> DotDigraph(gr2){[11 .. 75]}; +"aph hgn {\n\tnode [shape=circle] \n\t1\n\t2\n\t3\n\t4\n\t1 -> 2\n\t2 -> 1\n\t\ +2 ->" +gap> DotSymmetricDigraph(gr2){[12 .. 70]}; +" hgn {\n\tnode [shape=circle] \n\t1\n\t2\n\t3\n\t4\n\t2 -- 1\n\t3 -- 2\n\t3" +gap> DotSymmetricDigraph(gr1); +Error, the argument (a digraph) must be symmetric + +#DotColoredDigraph and DotSymmetriColoredDigraph +# TODO fix the colors here! +gap> D := CompleteDigraph(4); + +gap> vertcolors := [];; +gap> vertcolors[1] := "blue";; vertcolors[2] := "red";; +gap> vertcolors[3] := "green";; vertcolors[4] := "yellow";; +gap> edgecolors := [];; +gap> edgecolors[1] := [];; edgecolors[2] := [];; +gap> edgecolors[3] := [];; edgecolors[4] := [];; +gap> edgecolors[1][1] := "lightblue";; +gap> edgecolors[1][2] := "pink";; +gap> edgecolors[1][3] := "purple";; +gap> edgecolors[2][1] := "lightblue";; +gap> edgecolors[2][2] := "pink";; +gap> edgecolors[2][3] := "purple";; +gap> edgecolors[3][1] := "lightblue";; +gap> edgecolors[3][2] := "pink";; +gap> edgecolors[3][3] := "purple";; +gap> edgecolors[4][1] := "lightblue";; +gap> edgecolors[4][2] := "pink";; +gap> edgecolors[4][3] := "purple";; +gap> DotColoredDigraph(D, vertcolors, edgecolors){[1 .. 30]}; +"//dot\ndigraph hgn {\n\tnode [sha" +gap> D := Digraph([[2], [1, 3], [2]]); + +gap> vertcolors := [];; +gap> vertcolors[1] := "blue";; +gap> vertcolors[2] := "pink";; +gap> vertcolors[3] := "purple";; +gap> edgecolors := [];; +gap> edgecolors[1] := [];; edgecolors[2] := [];; +gap> edgecolors[3] := [];; +gap> edgecolors[1][1] := "green";; +gap> edgecolors[2][1] := "green";; +gap> edgecolors[3][1] := "red";; edgecolors[2][2] := "red";; +gap> DotSymmetricColoredDigraph(D, vertcolors, edgecolors); +"//dot\ngraph hgn {\n\tnode [shape=circle] \n\t1 [color=blue, style=filled]\n\ +\t2 [color=pink, style=filled]\n\t3 [color=purple, style=filled]\n\t2 -- 1 [co\ +lor=green]\n\t3 -- 2 [color=red]\n}\n" +gap> D := Digraph([[2, 3], [1, 3], [1]]); + +gap> vertcolors := [];; +gap> vertcolors[1] := "blue";; vertcolors[2] := "red";; +gap> vertcolors[3] := "green";; +gap> edgecolors := [];; +gap> edgecolors[1] := [];; edgecolors[2] := [];; +gap> edgecolors[3] := [];; +gap> edgecolors[1][1] := "orange";; edgecolors[1][2] := "yellow";; +gap> edgecolors[2][1] := "orange";; edgecolors[2][2] := "pink";; +gap> edgecolors[3][1] := "yellow";; +gap> DotColoredDigraph(D, vertcolors, edgecolors); +"//dot\ndigraph hgn {\n\tnode [shape=circle] \n\t1 [color=blue, style=filled]\ +\n\t2 [color=red, style=filled]\n\t3 [color=green, style=filled]\n\t1 -> 2 [co\ +lor=orange]\n\t1 -> 3 [color=yellow]\n\t2 -> 1 [color=orange]\n\t2 -> 3 [color\ +=pink]\n\t3 -> 1 [color=yellow]\n}\n" +gap> D := Digraph(IsMutableDigraph, [[2, 3], [1, 3], [1]]); + +gap> vertcolors := [];; +gap> vertcolors[1] := "blue";; vertcolors[2] := "red";; +gap> vertcolors[3] := "green";; +gap> edgecolors := [];; +gap> edgecolors[1] := [];; edgecolors[2] := [];; +gap> edgecolors[3] := [];; +gap> edgecolors[1][1] := "orange";; edgecolors[1][2] := "yellow";; +gap> edgecolors[2][1] := "orange";; edgecolors[2][2] := "pink";; +gap> edgecolors[3][1] := "yellow";; +gap> DotColoredDigraph(D, vertcolors, edgecolors);; +gap> D; + +gap> D := Digraph([[2, 4], [1, 3], [2], [1]]); + +gap> vertcolors := ["blue", "red", "green", "yellow"];; +gap> edgecolors := ListWithIdenticalEntries(3, +> ["orange", "orange", "orange"]);; +#@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") +gap> DotSymmetricColoredDigraph(D, vertcolors, edgecolors); +Error, the 2nd argument (edge colors) must have the same number of entries as \ +the 1st argument (a digraph) has nodes, expected 4 but found 3 +#@else +gap> DotSymmetricColoredDigraph(D, vertcolors, edgecolors); +Error, the 2nd argument (edge colors) must have the same number of entries as \ +the 1st\ + argument (a digraph) has nodes, expected 4 but found 3 +#@fi +gap> D := Digraph(IsMutableDigraph, [[2, 4], [1, 3], [2], [1]]); + +gap> vertcolors := ["blue", "red", "green", "yellow"];; +gap> edgecolors := ListWithIdenticalEntries(3, +> ["orange", "orange", "orange"]);; +#@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") +gap> DotSymmetricColoredDigraph(D, vertcolors, edgecolors); +Error, the 2nd argument (edge colors) must have the same number of entries as \ +the 1st argument (a digraph) has nodes, expected 4 but found 3 +#@else +gap> DotSymmetricColoredDigraph(D, vertcolors, edgecolors); +Error, the 2nd argument (edge colors) must have the same number of entries as \ +the 1st\ + argument (a digraph) has nodes, expected 4 but found 3 +#@fi +gap> D; + +gap> D := CompleteDigraph(4);; +gap> vertcolors := ["blue", "banana", "green", "yellow"];; +gap> edgecolors := ListWithIdenticalEntries(4, +> ["lightblue", "pink", "purple"]);; +#@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") +gap> DotColoredDigraph(D, vertcolors, edgecolors); +Error, invalid color "banana" (list (string)), valid colors are RGB values or \ +names from the GraphViz 2.44.1 X11 Color Scheme http://graphviz.org/doc/info/c\ +olors.html +#@else +gap> DotColoredDigraph(D, vertcolors, edgecolors); +Error, invalid color "banana" (list (string)), valid colors are RGB values or \ +names from the GraphViz 2.44.1 X11 Color Sch\ +eme http://graphviz.org/doc/info/colors.html +#@fi +gap> D := CompleteDigraph(4); + +gap> vertcolors := ["blue", "red", "green"];; +gap> edgecolors := ListWithIdenticalEntries(4, +> ["lightblue", "pink", "purple"]);; +#@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") +gap> DotColoredDigraph(D, vertcolors, edgecolors); +Error, the number of node colors must be the same as the number of nodes, expe\ +cted 4 but found 3 +#@else +gap> DotColoredDigraph(D, vertcolors, edgecolors); +Error, the number of node colors must be the same as the number of nodes, expe\ +cted 4 but found 3 +#@fi +gap> D := CompleteDigraph(4); + +gap> vertcolors := [2, 1, 1, 3];; +gap> edgecolors := ListWithIdenticalEntries(4, +> ["lightblue", "pink", "purple"]);; +#@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") +gap> DotColoredDigraph(D, vertcolors, edgecolors); +Error, invalid color 2 (integer), valid colors are RGB values or names from th\ +e GraphViz 2.44.1 X11 Color Scheme http://graphviz.org/doc/info/colors.html +#@else +gap> DotColoredDigraph(D, vertcolors, edgecolors); +Error, invalid color 2 (integer), valid colors are RGB values or names from th\ +e GraphViz 2.44.1 X11 Color Sch\ +eme http://graphviz.org/doc/info/colors.html +#@fi +gap> D := CompleteDigraph(4); + +gap> vertcolors := ["#AB3487", "#DF4738", "#4BF234", "#AF34C9"];; +gap> edgecolors := ListWithIdenticalEntries(4, +> ["lightblue", "pink", "purple"]);; +gap> Print(DotColoredDigraph(D, vertcolors, edgecolors)); +//dot +digraph hgn { + node [shape=circle] + 1 [color="#AB3487", style=filled] + 2 [color="#DF4738", style=filled] + 3 [color="#4BF234", style=filled] + 4 [color="#AF34C9", style=filled] + 1 -> 2 [color=lightblue] + 1 -> 3 [color=pink] + 1 -> 4 [color=purple] + 2 -> 1 [color=lightblue] + 2 -> 3 [color=pink] + 2 -> 4 [color=purple] + 3 -> 1 [color=lightblue] + 3 -> 2 [color=pink] + 3 -> 4 [color=purple] + 4 -> 1 [color=lightblue] + 4 -> 2 [color=pink] + 4 -> 3 [color=purple] +} +gap> D := CompleteDigraph(4); + +gap> vertcolors := [];; +gap> vertcolors[1] := "blue";; vertcolors[2] := "red";; +gap> vertcolors[3] := "green";; vertcolors[4] := "yellow";; +gap> edgecolors := [];; +gap> edgecolors[1] := [];; edgecolors[2] := [];; +gap> edgecolors[3] := [];; edgecolors[4] := [];; +gap> edgecolors[1][1] := "banana";; +gap> edgecolors[1][2] := "pink";; +gap> edgecolors[1][3] := "purple";; +gap> edgecolors[2][1] := "lightblue";; +gap> edgecolors[2][2] := "pink";; +gap> edgecolors[2][3] := "purple";; +gap> edgecolors[3][1] := "cherry";; +gap> edgecolors[3][2] := "pink";; +gap> edgecolors[3][3] := "purple";; +gap> edgecolors[4][1] := "lightblue";; +gap> edgecolors[4][2] := "pink";; +gap> edgecolors[4][3] := "purple";; +#@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") +gap> DotColoredDigraph(D, vertcolors, edgecolors); +Error, invalid color "banana" (list (string)), valid colors are RGB values or \ +names from the GraphViz 2.44.1 X11 Color Scheme http://graphviz.org/doc/info/c\ +olors.html +#@else +gap> DotColoredDigraph(D, vertcolors, edgecolors); +Error, invalid color "banana" (list (string)), valid colors are RGB values or \ +names from the GraphViz 2.44.1 X11 Color Sch\ +eme http://graphviz.org/doc/info/colors.html +#@fi +gap> D := CompleteDigraph(4); + +gap> vertcolors := [];; +gap> vertcolors[1] := "blue";; vertcolors[2] := "red";; +gap> vertcolors[3] := "green";; vertcolors[4] := "yellow";; +gap> edgecolors := [];; +gap> edgecolors[1] := [];; edgecolors[2] := [];; +gap> edgecolors[3] := [];; edgecolors[4] := [];; +gap> edgecolors[1][1] := "lightblue";; +gap> edgecolors[1][2] := "pink";; +gap> edgecolors[1][3] := "purple";; +gap> edgecolors[2][1] := "lightblue";; +gap> edgecolors[2][2] := "pink";; +gap> edgecolors[2][3] := "purple";; +gap> edgecolors[3][1] := "lightblue";; +gap> edgecolors[3][2] := "pink";; +gap> edgecolors[3][3] := "purple";; +gap> edgecolors[4][1] := "lightblue";; +gap> edgecolors[4][2] := "pink";; +#@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") +gap> DotColoredDigraph(D, vertcolors, edgecolors); +Error, the 2nd argument (edge colors) must have the same shape as the out neig\ +hbours of the 1st argument (a digraph), in position 4 expected a list of lengt\ +h 3 but found list of length 2 +#@else +gap> DotColoredDigraph(D, vertcolors, edgecolors); +Error, the 2nd argument (edge colors) must have the same shape as the out neig\ +hbours \ +of the 1st argument (a digraph), in position 4 expected a list of length 3 but\ + found list of length 2 +#@fi + +# DotVertexColoredDigraph +gap> D := CompleteDigraph(4); + +gap> vertcolors := [];; +gap> vertcolors[1] := "blue";; vertcolors[2] := "red";; +gap> vertcolors[3] := "green";; vertcolors[4] := "yellow";; +gap> Print(DotVertexColoredDigraph(D, vertcolors)); +//dot +digraph hgn { + node [shape=circle] + 1 [color=blue, style=filled] + 2 [color=red, style=filled] + 3 [color=green, style=filled] + 4 [color=yellow, style=filled] + 1 -> 2 + 1 -> 3 + 1 -> 4 + 2 -> 1 + 2 -> 3 + 2 -> 4 + 3 -> 1 + 3 -> 2 + 3 -> 4 + 4 -> 1 + 4 -> 2 + 4 -> 3 +} +gap> D := EmptyDigraph(3); + +gap> vertcolors := [];; +gap> vertcolors[1] := "blue";; vertcolors[2] := "red";; +gap> vertcolors[3] := "green";; +gap> edgecolors := [];; +gap> edgecolors[1] := [];; edgecolors[2] := [];; +gap> edgecolors[3] := [];; +gap> DotVertexColoredDigraph(D, vertcolors); +"//dot\ndigraph hgn {\n\tnode [shape=circle] \n\t1 [color=blue, style=filled]\ +\n\t2 [color=red, style=filled]\n\t3 [color=green, style=filled]\n}\n" + +# DotEdgeColoredDigraph +gap> D := CompleteDigraph(4); + +gap> edgecolors := [];; +gap> edgecolors[1] := [];; edgecolors[2] := [];; +gap> edgecolors[3] := [];; edgecolors[4] := [];; +gap> edgecolors[1][1] := "lightblue";; +gap> edgecolors[1][2] := "pink";; +gap> edgecolors[1][3] := "purple";; +gap> edgecolors[2][1] := "lightblue";; +gap> edgecolors[2][2] := "pink";; +gap> edgecolors[2][3] := "purple";; +gap> edgecolors[3][1] := "lightblue";; +gap> edgecolors[3][2] := "pink";; +gap> edgecolors[3][3] := "purple";; +gap> edgecolors[4][1] := "lightblue";; +gap> edgecolors[4][2] := "pink";; +gap> edgecolors[4][3] := "purple";; +gap> DotEdgeColoredDigraph(D, edgecolors); +"//dot\ndigraph hgn {\n\tnode [shape=circle] \n\t1\n\t2\n\t3\n\t4\n\t1 -> 2 [c\ +olor=lightblue]\n\t1 -> 3 [color=pink]\n\t1 -> 4 [color=purple]\n\t2 -> 1 [col\ +or=lightblue]\n\t2 -> 3 [color=pink]\n\t2 -> 4 [color=purple]\n\t3 -> 1 [color\ +=lightblue]\n\t3 -> 2 [color=pink]\n\t3 -> 4 [color=purple]\n\t4 -> 1 [color=l\ +ightblue]\n\t4 -> 2 [color=pink]\n\t4 -> 3 [color=purple]\n}\n" +#@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") +gap> DotEdgeColoredDigraph(CycleDigraph(3), []); +Error, the 2nd argument (edge colors) must have the same number of entries as \ +the 1st argument (a digraph) has nodes, expected 3 but found 0 +gap> DotEdgeColoredDigraph(CycleDigraph(3), [[fail, fail], [fail], [fail]]); +Error, the 2nd argument (edge colors) must have the same shape as the out neig\ +hbours of the 1st argument (a digraph), in position 1 expected a list of lengt\ +h 1 but found list of length 2 +#@else +gap> DotEdgeColoredDigraph(CycleDigraph(3), []); +Error, the 2nd argument (edge colors) must have the same number of entries as \ +the 1st\ + argument (a digraph) has nodes, expected 3 but found 0 +#@fi +#@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") +gap> DotEdgeColoredDigraph(CycleDigraph(3), [[fail], [fail], [fail]]); +Error, invalid color fail (boolean or fail), valid colors are RGB values or na\ +mes from the GraphViz 2.44.1 X11 Color Scheme http://graphviz.org/doc/info/col\ +ors.html +#@else +gap> DotEdgeColoredDigraph(CycleDigraph(3), [[fail], [fail], [fail]]); +Error, invalid color fail (boolean or fail), valid colors are RGB values or na\ +mes from the GraphViz 2.44.1 X11 Color Sch\ +eme http://graphviz.org/doc/info/colors.html +#@fi + +# DotSymmetricVertexColoredDigraph +gap> D := Digraph([[2], [1, 3], [2]]); + +gap> vertcolors := [];; +gap> vertcolors[1] := "blue";; +gap> vertcolors[2] := "pink";; +gap> vertcolors[3] := "purple";; +gap> DotSymmetricVertexColoredDigraph(D, vertcolors); +"//dot\ngraph hgn {\n\tnode [shape=circle] \n\t1 [color=blue, style=filled]\n\ +\t2 [color=pink, style=filled]\n\t3 [color=purple, style=filled]\n\t2 -- 1\n\t\ +3 -- 2\n}\n" + +# DotSymmetricEdgeColoredDigraph +gap> D := Digraph([[2], [1, 3], [2]]); + +gap> edgecolors := [];; +gap> edgecolors[1] := [];; edgecolors[2] := [];; +gap> edgecolors[3] := [];; +gap> edgecolors[1][1] := "green";; edgecolors[2][1] := "green";; +gap> edgecolors[2][2] := "red";; edgecolors[3][1] := "red";; +gap> DotSymmetricEdgeColoredDigraph(D, edgecolors); +"//dot\ngraph hgn {\n\tnode [shape=circle] \n\t1\n\t2\n\t3\n\t2 -- 1 [color=gr\ +een]\n\t3 -- 2 [color=red]\n}\n" + +# DotVertexLabelledDigraph +gap> r := rec(DigraphVertices := [1 .. 3], DigraphSource := [1, 1, 1, 1], +> DigraphRange := [1, 2, 2, 3]);; +gap> gr := Digraph(r); + +gap> dot := DotVertexLabelledDigraph(gr);; +gap> dot; +"//dot\ndigraph hgn {\n\tnode [shape=circle] \n\t1 [label=\"1\"]\n\t2 [label=\ +\"2\"]\n\t3 [label=\"3\"]\n\t1 -> 1\n\t1 -> 2\n\t1 -> 2\n\t1 -> 3\n}\n" +gap> SetDigraphVertexLabel(gr, 1, 2); +gap> dot := DotVertexLabelledDigraph(gr);; +gap> dot; +"//dot\ndigraph hgn {\n\tnode [shape=circle] \n\t1 [label=\"2\"]\n\t2 [label=\ +\"2\"]\n\t3 [label=\"3\"]\n\t1 -> 1\n\t1 -> 2\n\t1 -> 2\n\t1 -> 3\n}\n" + +# Splash +gap> Splash(1); +Error, the 1st argument must be a string or graphviz graph, found integer +gap> Splash("string", 0); +Error, the 2nd argument must be a record +gap> Splash("string"); +Error, the component "type" of the 2nd argument must be "dot" or "\ +latex", +gap> Splash("string", rec(path := "~/", filename := "filename")); +Error, the component "type" of the 2nd argument must be "dot" or "\ +latex", +gap> Splash("string", rec(viewer := "bad")); +Error, the viewer "bad" specified in the option `viewer` is not available +gap> Splash("string", rec(type := "dot", engine := "dott")); +Error, the component "engine" of the 2nd argument must be one of: "\ +dot", "neato", "twopi", "circo", "fdp", "sfdp", or "patchwork" +gap> tmpdir := Filename(DirectoryTemporary(), "");; +gap> Splash("string", +> rec(path := tmpdir, +> directory := "digraphs_temporary_directory")); +Error, the component "type" of the 2nd argument must be "dot" or "\ +latex", +gap> Splash("%latex", rec(filetype := "latex", engine := fail)); +Error, the component "engine" of the 2nd argument must be one of: "\ +dot", "neato", "twopi", "circo", "fdp", "sfdp", or "patchwork" +gap> Splash("//dot", rec(filetype := "pdf", engine := fail)); +Error, the component "engine" of the 2nd argument must be one of: "\ +dot", "neato", "twopi", "circo", "fdp", "sfdp", or "patchwork" +gap> MakeReadWriteGlobal("VizViewers"); +gap> VizViewers_backup := ShallowCopy(VizViewers);; +gap> VizViewers := ["nonexistent-viewer"];; +gap> Splash("//dot"); +Error, none of the default viewers [ "nonexistent-viewer" + ] is available, please specify an available viewer in the options record comp\ +onent `viewer`, +gap> VizViewers := VizViewers_backup;; +gap> MakeReadOnlyGlobal("VizViewers"); + +# DotPartialOrderDigraph +gap> gr := Digraph([[1], [1, 2], [1, 3], [1, 4], [1 .. 5], [1 .. 6], +> [1, 2, 3, 4, 5, 7], [1, 8]]);; +gap> Print(DotPartialOrderDigraph(gr)); +//dot +digraph hgn { + node [shape=circle] + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 2 -> 1 + 3 -> 1 + 4 -> 1 + 5 -> 2 + 5 -> 3 + 5 -> 4 + 6 -> 5 + 7 -> 5 + 8 -> 1 +} +gap> gr := Digraph([[1], [2], [1, 3], [2, 4], [1, 2, 3, 4, 5], [1, 2, 3, 6]]);; +gap> Print(DotPartialOrderDigraph(gr)); +//dot +digraph hgn { + node [shape=circle] + 1 + 2 + 3 + 4 + 5 + 6 + 3 -> 1 + 4 -> 2 + 5 -> 3 + 5 -> 4 + 6 -> 3 + 6 -> 2 +} +gap> gr := Digraph([[1], []]);; +gap> DotPartialOrderDigraph(gr); +Error, the argument (a digraph) must be a partial order + +# DotPreorderDigraph and DotQuasiorderDigraph +gap> DotPreorderDigraph(CompleteDigraph(5)); +Error, the argument (a digraph) must be a preorder +gap> gr := Digraph([[1], [1, 2], [1, 3], [1, 4], [1 .. 5], [1 .. 6], +> [1, 2, 3, 4, 5, 7], [1, 8]]);; +gap> Print(DotPreorderDigraph(gr), "\n"); +//dot +digraph graphname { + node [shape="Mrecord"] height="0.5" fixedsize="true" ranksep="1" + 1 [label="1", width=0.5] + 2 [label="2", width=0.5] + 3 [label="3", width=0.5] + 4 [label="4", width=0.5] + 5 [label="5", width=0.5] + 6 [label="6", width=0.5] + 7 [label="7", width=0.5] + 8 [label="8", width=0.5] + 2 -> 1 + 3 -> 1 + 4 -> 1 + 5 -> 2 + 5 -> 3 + 5 -> 4 + 6 -> 5 + 7 -> 5 + 8 -> 1 +} + +gap> gr := Concatenation("&X_?_A]|^Vr[nHpmVcy~zy[A????_???G??B]nhtmvcwvJq\\^~", +> "|m??_AEx]Rb[nHo??__vJy[??A??O_aV~^Zb]njo???_???GZdxMLy}n_");; +gap> gr := DigraphFromDigraph6String(gr);; +gap> Print(DotPreorderDigraph(gr){[1 .. 94]}, "\n"); +//dot +digraph graphname { + node [shape="Mrecord"] height="0.5" fixedsize="true" ranksep="1" + +gap> gr := DigraphDisjointUnion(CompleteDigraph(10), +> CompleteDigraph(5), +> CycleDigraph(2));; +gap> gr := DigraphReflexiveTransitiveClosure(DigraphAddEdge(gr, [10, 11]));; +gap> IsPreorderDigraph(gr); +true +gap> Print(DotPreorderDigraph(gr), "\n"); +//dot +digraph graphname { + node [shape="Mrecord"] height="0.5" fixedsize="true" ranksep="1" + 1 [label="11|12|13|14|15", width=2.5] + 2 [label="1|2|3|4|5|6|7|8|9|10", width=5.] + 3 [label="16|17", width=1.] + 2 -> 1 +} + + +# DotHighlightedDigraph +gap> gr := Digraph([[2, 3], [2], [1, 3]]); + +gap> Print(DotHighlightedDigraph(gr, [1, 2], "red", "black")); +//dot +digraph { + shape=circle + 1 [color=red] + 2 [color=red] + 3 [color=black] + 1 -> 2 [color=red] + 1 -> 3 [color=black] + 2 -> 2 [color=red] + 3 -> 1 [color=black] + 3 -> 3 [color=black] +} +gap> D := CycleDigraph(5);; +gap> DotHighlightedDigraph(D, [10], "black", "grey"); +Error, the 2nd argument (list) must consist of vertices of the 1st argument (a\ + digraph) +#@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") +gap> DotHighlightedDigraph(D, [1], "", "grey"); +Error, invalid color "" (list (string)), valid colors are RGB values or names \ +from the GraphViz 2.44.1 X11 Color Scheme http://graphviz.org/doc/info/colors.\ +html +#@else +gap> DotHighlightedDigraph(D, [1], "", "grey"); +Error, invalid color "" (list (string)), valid colors are RGB values or names \ +from the GraphViz 2.44.1 X11 Color Sch\ +eme http://graphviz.org/doc/info/colors.html +#@fi +#@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") +gap> DotHighlightedDigraph(D, [1], "black", ""); +Error, invalid color "" (list (string)), valid colors are RGB values or names \ +from the GraphViz 2.44.1 X11 Color Scheme http://graphviz.org/doc/info/colors.\ +html +#@else +gap> DotHighlightedDigraph(D, [1], "black", ""); +Error, invalid color "" (list (string)), valid colors are RGB values or names \ +from the GraphViz 2.44.1 X11 Color Sch\ +eme http://graphviz.org/doc/info/colors.html +#@fi +gap> Print(DotHighlightedDigraph(D, Filtered(DigraphVertices(D), IsEvenInt))); +//dot +digraph { + shape=circle + 1 [color=grey] + 2 [color=black] + 3 [color=grey] + 4 [color=black] + 5 [color=grey] + 1 -> 2 [color=grey] + 2 -> 3 [color=grey] + 3 -> 4 [color=grey] + 4 -> 5 [color=grey] + 5 -> 1 [color=grey] +} + +# Splash +gap> Splash(DotDigraph(RandomDigraph(10)), rec(viewer := 1)); +Error, the option `viewer` must be a string, not an integer +gap> Splash(DotDigraph(RandomDigraph(10)), rec(viewer := "asdfasfa")); +Error, the viewer "asdfasfa" specified in the option `viewer` is not available + +# Test errors +gap> GraphvizEdgeColoredGraph(ChainDigraph(3), ["blue"]); +Error, the argument (a digraph) must be symmetric +gap> D := DigraphSymmetricClosure(ChainDigraph(3));; +gap> GraphvizVertexLabelledGraph(D); + +gap> GraphvizEdgeColoredGraph(D, List(DigraphVertices(D), ReturnFail)); +Error, the 2nd argument (edge colors) must be a list of lists, found boolean o\ +r fail in position 1 +gap> GraphvizHighlightedDigraph(D, [2]); + +gap> GraphvizHighlightedGraph(D, [2]); + +gap> Print(AsString(last)); +//dot +graph { + shape=circle + 1 [color=grey] + 2 [color=black] + 3 [color=grey] + 2 -- 1 [color=grey] + 3 -- 2 [color=grey] +} +gap> GraphvizHighlightedGraph(D, [1, 2], "red", "blue"); + +gap> Print(AsString(last)); +//dot +graph { + shape=circle + 1 [color=red] + 2 [color=red] + 3 [color=blue] + 2 -- 1 [color=red] + 3 -- 2 [color=blue] +} +gap> GraphvizHighlightedGraph(ChainDigraph(3), [1, 2], "red", "blue"); +Error, the argument (a digraph) must be symmetric +gap> D := Digraph([[], [1, 1]]);; +gap> GraphvizHighlightedDigraph(D, [2]); + + +# DIGRAPHS_UnbindVariables +gap> Unbind(D); +gap> Unbind(adj); +gap> Unbind(backup); +gap> Unbind(dot); +gap> Unbind(edgecolors); +gap> Unbind(gr); +gap> Unbind(gr1); +gap> Unbind(gr2); +gap> Unbind(r); +gap> Unbind(tmpdir); +gap> Unbind(vertcolors); + +# +gap> DIGRAPHS_StopTest(); +gap> STOP_TEST("Digraphs package: standard/display.tst", 0); diff --git a/tst/standard/weights.tst b/tst/standard/weights.tst index 036dac4d0..8963587c9 100644 --- a/tst/standard/weights.tst +++ b/tst/standard/weights.tst @@ -511,39 +511,46 @@ true gap> gr := EdgeWeightedDigraph([[2], []], [[10], []]);; gap> Print(DotEdgeWeightedDigraph(gr)); //dot -digraph hgn{ -node [shape=circle] -1[color=gray, style=filled] -2[color=gray, style=filled] -1 -> 2[color=black, label=10] +digraph hgn { + node [shape=circle] + 1 [color=gray, style=filled] + 2 [color=gray, style=filled] + 1 -> 2 [color=black, label=10] } gap> Print(DotEdgeWeightedDigraph(gr, rec(vert := "orange"))); //dot -digraph hgn{ -node [shape=circle] -1[color=orange, style=filled] -2[color=orange, style=filled] -1 -> 2[color=black, label=10] +digraph hgn { + node [shape=circle] + 1 [color=orange, style=filled] + 2 [color=orange, style=filled] + 1 -> 2 [color=black, label=10] } +# Parallel edges and loops retain distinct weights when highlighting a path. +gap> gr := EdgeWeightedDigraph([[1, 2, 1, 2], []], [[3, 10, 7, 20], []]);; +gap> path := [[1, 2], [4]];; +gap> List(GraphvizEdges(GraphvizEdgeWeightedDigraph(gr, path)), +> e -> [GraphvizAttrs(e)["color"], GraphvizAttrs(e)["label"]]); +[ [ "black", "3" ], [ "black", "10" ], [ "black", "7" ], [ "blue", "20" ] ] + # Cycle example gap> gr := EdgeWeightedDigraph(CycleDigraph(5), [[10], [4], [8], [2], [8]]);; gap> path := DigraphPath(gr, 3, 1); [ [ 3, 4, 5, 1 ], [ 1, 1, 1 ] ] gap> Print(DotEdgeWeightedDigraph(gr, path, rec(highlight := "red"))); //dot -digraph hgn{ -node [shape=circle] -1[color=lightpink, style=filled] -2[color=gray, style=filled] -3[color=yellowgreen, style=filled] -4[color=gray, style=filled] -5[color=gray, style=filled] -1 -> 2[color=black, label=10] -2 -> 3[color=black, label=4] -3 -> 4[color=red, label=8] -4 -> 5[color=red, label=2] -5 -> 1[color=red, label=8] +digraph hgn { + node [shape=circle] + 1 [color=lightpink, style=filled] + 2 [color=gray, style=filled] + 3 [color=yellowgreen, style=filled] + 4 [color=gray, style=filled] + 5 [color=gray, style=filled] + 1 -> 2 [color=black, label=10] + 2 -> 3 [color=black, label=4] + 3 -> 4 [color=red, label=8] + 4 -> 5 [color=red, label=2] + 5 -> 1 [color=red, label=8] } # Large example @@ -555,28 +562,28 @@ gap> path := EdgeWeightedDigraphShortestPath(gr, 1, 2); [ [ 1, 7, 6, 2 ], [ 2, 1, 2 ] ] gap> Print(DotEdgeWeightedDigraph(gr, path)); //dot -digraph hgn{ -node [shape=circle] -1[color=yellowgreen, style=filled] -2[color=lightpink, style=filled] -3[color=gray, style=filled] -4[color=gray, style=filled] -5[color=gray, style=filled] -6[color=gray, style=filled] -7[color=gray, style=filled] -1 -> 5[color=black, label=8] -1 -> 7[color=blue, label=4] -2 -> 5[color=black, label=12] -3 -> 1[color=black, label=11] -3 -> 3[color=black, label=2] -3 -> 6[color=black, label=10] -4 -> 1[color=black, label=3] -4 -> 3[color=black, label=7] -5 -> 4[color=black, label=9] -5 -> 5[color=black, label=13] -6 -> 1[color=black, label=1] -6 -> 2[color=blue, label=6] -7 -> 6[color=blue, label=5] +digraph hgn { + node [shape=circle] + 1 [color=yellowgreen, style=filled] + 2 [color=lightpink, style=filled] + 3 [color=gray, style=filled] + 4 [color=gray, style=filled] + 5 [color=gray, style=filled] + 6 [color=gray, style=filled] + 7 [color=gray, style=filled] + 1 -> 5 [color=black, label=8] + 1 -> 7 [color=blue, label=4] + 2 -> 5 [color=black, label=12] + 3 -> 1 [color=black, label=11] + 3 -> 3 [color=black, label=2] + 3 -> 6 [color=black, label=10] + 4 -> 1 [color=black, label=3] + 4 -> 3 [color=black, label=7] + 5 -> 4 [color=black, label=9] + 5 -> 5 [color=black, label=13] + 6 -> 1 [color=black, label=1] + 6 -> 2 [color=blue, label=6] + 7 -> 6 [color=blue, label=5] } # Bad arguments @@ -585,7 +592,7 @@ gap> DotEdgeWeightedDigraph( > [[1, 2], [3, 4], [5, 6]], > rec(vert := "blue", mrblobby := "pink") > ); -Error, 3rd arg contains unsupported option named 'mrblobby' +Error, the 3rd argument contains unsupported option named 'mrblobby' # gap> DIGRAPHS_StopTest();