From e83ebfe4becbc9156dca6062b9fa33075e1938d0 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Fri, 3 May 2024 17:46:43 +0100 Subject: [PATCH] Updates for the Digraphs package --- PackageInfo.g | 31 +- etc/gaplint.sh | 4 + etc/tst-local-vars.py | 40 ++ examples/{angles.gi => angles.g} | 18 +- examples/btree.g | 39 ++ examples/btree.gi | 27 -- examples/{cluster.gi => cluster.g} | 12 + examples/{cluster_edge.gi => cluster_edge.g} | 15 +- examples/colors.g | 35 ++ examples/colors.gi | 23 - examples/{er.gi => er.g} | 14 +- examples/{fsm.gi => fsm.g} | 14 +- examples/{g_c_n.gi => g_c_n.g} | 14 +- examples/hello.g | 17 + examples/hello.gi | 6 - examples/{process.gi => process.g} | 13 + examples/{rank_same.gi => rank_same.g} | 12 + examples/structs.g | 55 +++ examples/structs.gi | 43 -- ...traffic_lights_WIP.gi => traffic_lights.g} | 18 +- examples/{unix.gi => unix.g} | 14 +- gap/dot.gd | 18 + gap/dot.gi | 424 +++++++++++++++--- gap/splash.gi | 73 +-- init.g | 16 +- makedoc.g | 18 +- read.g | 16 +- tst/dot.tst | 30 +- tst/edge.tst | 11 +- tst/examples/angles.tst | 88 ++++ tst/examples/btree.tst | 98 ++++ tst/examples/cluster.tst | 113 +++++ tst/examples/cluster_edge.tst | 86 ++++ tst/examples/colors.tst | 71 +++ tst/examples/er.tst | 161 +++++++ tst/examples/fsm.tst | 114 +++++ tst/examples/g_c_n.tst | 52 +++ tst/examples/hello.tst | 32 ++ tst/examples/process.tst | 79 ++++ tst/examples/rank_same.tst | 83 ++++ tst/examples/structs.tst | 108 +++++ tst/examples/traffic_lights.tst | 127 ++++++ tst/examples/unix.tst | 349 ++++++++++++++ tst/graph.tst | 13 +- tst/node.tst | 15 +- tst/subgraph.tst | 43 +- tst/testall.g | 10 +- 47 files changed, 2427 insertions(+), 285 deletions(-) create mode 100755 etc/gaplint.sh create mode 100755 etc/tst-local-vars.py rename examples/{angles.gi => angles.g} (76%) create mode 100644 examples/btree.g delete mode 100644 examples/btree.gi rename examples/{cluster.gi => cluster.g} (77%) rename examples/{cluster_edge.gi => cluster_edge.g} (65%) create mode 100644 examples/colors.g delete mode 100644 examples/colors.gi rename examples/{er.gi => er.g} (83%) rename examples/{fsm.gi => fsm.g} (80%) rename examples/{g_c_n.gi => g_c_n.g} (58%) create mode 100644 examples/hello.g delete mode 100644 examples/hello.gi rename examples/{process.gi => process.g} (65%) rename examples/{rank_same.gi => rank_same.g} (62%) create mode 100644 examples/structs.g delete mode 100644 examples/structs.gi rename examples/{traffic_lights_WIP.gi => traffic_lights.g} (77%) rename examples/{unix.gi => unix.g} (85%) create mode 100644 tst/examples/angles.tst create mode 100644 tst/examples/btree.tst create mode 100644 tst/examples/cluster.tst create mode 100644 tst/examples/cluster_edge.tst create mode 100644 tst/examples/colors.tst create mode 100644 tst/examples/er.tst create mode 100644 tst/examples/fsm.tst create mode 100644 tst/examples/g_c_n.tst create mode 100644 tst/examples/hello.tst create mode 100644 tst/examples/process.tst create mode 100644 tst/examples/rank_same.tst create mode 100644 tst/examples/structs.tst create mode 100644 tst/examples/traffic_lights.tst create mode 100644 tst/examples/unix.tst diff --git a/PackageInfo.g b/PackageInfo.g index 74e51c1..d06bb2e 100644 --- a/PackageInfo.g +++ b/PackageInfo.g @@ -1,12 +1,13 @@ -# -# graphviz: This package facilitates the creation of graph descriptions in the -# DOT language of the Graphviz graph drawing software from GAP -# -# This file contains package meta data. For additional information on -# the meaning and correct usage of these fields, please consult the -# manual of the "Example" package as well as the comments in its -# PackageInfo.g file. -# +############################################################################# +## +## PackageInfo.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + SetPackageInfo(rec( PackageName := "graphviz", @@ -26,6 +27,18 @@ Persons := [ PostalAddress := Concatenation("Mathematical Institute, North Haugh,", " St Andrews, Fife, KY16 9SS, Scotland"), Place := "St Andrews", + Institution := "University of St Andrews"), + rec( + FirstNames := "Matthew", + LastName := "Pancer", + WWWHome := "?", + Email := "mp322@st-andrews.ac.uk", + IsAuthor := true, + IsMaintainer := true, + PostalAddress := Concatenation("Mathematical Institute, North Haugh,", + " St Andrews, Fife, KY16 9SS, Scotland"), + # TODO correct? Or should be cs? + Place := "St Andrews", Institution := "University of St Andrews")], SourceRepository := rec(Type := "git", diff --git a/etc/gaplint.sh b/etc/gaplint.sh new file mode 100755 index 0000000..0d8af69 --- /dev/null +++ b/etc/gaplint.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -e + +gaplint --disable W004 $@ *.g gap/* read.g init.g PackageInfo.g makedoc.g tst/testall.g tst/*.tst tst/examples/*.tst diff --git a/etc/tst-local-vars.py b/etc/tst-local-vars.py new file mode 100755 index 0000000..915c453 --- /dev/null +++ b/etc/tst-local-vars.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +""" +This simple script adds the local variables used in a GAP tst file to the top +of the file. +""" +import os +import re +import sys +import textwrap + +import yaml +from bs4 import BeautifulSoup + + +def main(): + if sys.version_info[0] < 3: + raise Exception("Python 3 is required") + args = sys.argv[1:] + pattern1 = re.compile(r"(\w+)\s*:=") + pattern2 = re.compile(r"for (\w+) in") + for fname in args: + lvars = [] + with open(fname, "r") as f: + lines = f.read() + lvars.extend([x.group(1) for x in re.finditer(pattern1, lines)]) + lvars.extend([x.group(1) for x in re.finditer(pattern2, lines)]) + lvars = ", ".join(sorted([*{*lvars}])) + lvars = [x if x[-1] != "," else x[:-1] for x in textwrap.wrap(lvars, width=72)] + lvars = [""] + ["#@local " + x for x in lvars] + lines = lines.split("\n") + pos = next(i for i in range(len(lines)) if "START_TEST" in lines[i]) + lines = lines[:pos] + lvars + lines[pos:] + lines = "\n".join(lines) + with open(fname, "w") as f: + print(f"Writing local variables to {fname}...") + f.write(lines) + + +if __name__ == "__main__": + main() diff --git a/examples/angles.gi b/examples/angles.g similarity index 76% rename from examples/angles.gi rename to examples/angles.g index 723cafa..219b20f 100644 --- a/examples/angles.gi +++ b/examples/angles.g @@ -1,3 +1,13 @@ +############################################################################# +## +## angles.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + # https://graphviz.readthedocs.io/en/stable/examples.html # https://www.graphviz.org/Gallery/gradient/angles.html @@ -21,7 +31,7 @@ for pair in pairs do od; GraphvizSetAttr(cluster1, "label", - "\"Linear Angle Variations (white to black gradient)\""); + "Linear Angle Variations (white to black gradient)"); cluster2 := GraphvizAddSubgraph(g, "cluster_2"); GraphvizSetAttr(cluster2, "fontcolor", "white"); @@ -38,7 +48,9 @@ for pair in pairs do pair[1], pair[2])); od; GraphvizSetAttr(cluster2, "label", - "\"Radial Angle Variations (white to black gradient)\""); + "Radial Angle Variations (white to black gradient)"); GraphvizAddEdge(g, "n5", "n14"); -Print(AsString(g), "\n"); +Print(AsString(g)); +Splash(g); +QUIT; diff --git a/examples/btree.g b/examples/btree.g new file mode 100644 index 0000000..2596c68 --- /dev/null +++ b/examples/btree.g @@ -0,0 +1,39 @@ +############################################################################# +## +## btree.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +# https://graphviz.org/Gallery/directed/unix.html +LoadPackage("graphviz"); + +s := GraphvizDigraph("g"); +GraphvizSetAttr(s, "node [shape=record, height=.1]"); + +GraphvizSetAttr(GraphvizAddNode(s, "node0"), "label", " | G|"); +GraphvizSetAttr(GraphvizAddNode(s, "node1"), "label", " | E|"); +GraphvizSetAttr(GraphvizAddNode(s, "node2"), "label", " | B|"); +GraphvizSetAttr(GraphvizAddNode(s, "node3"), "label", " | F|"); +GraphvizSetAttr(GraphvizAddNode(s, "node4"), "label", " | R|"); +GraphvizSetAttr(GraphvizAddNode(s, "node5"), "label", " | H|"); +GraphvizSetAttr(GraphvizAddNode(s, "node6"), "label", " | Y|"); +GraphvizSetAttr(GraphvizAddNode(s, "node7"), "label", " | A|"); +GraphvizSetAttr(GraphvizAddNode(s, "node8"), "label", " | C|"); + +GraphvizAddEdge(s, "node0:f2", "node4:f1"); +GraphvizAddEdge(s, "node0:f0", "node1:f1"); +GraphvizAddEdge(s, "node1:f0", "node2:f1"); +GraphvizAddEdge(s, "node1:f2", "node3:f1"); +GraphvizAddEdge(s, "node2:f2", "node8:f1"); +GraphvizAddEdge(s, "node2:f0", "node7:f1"); +GraphvizAddEdge(s, "node4:f2", "node6:f1"); +GraphvizAddEdge(s, "node4:f0", "node5:f1"); + +Print(AsString(s)); +Splash(s); +QUIT; diff --git a/examples/btree.gi b/examples/btree.gi deleted file mode 100644 index c8ea6d6..0000000 --- a/examples/btree.gi +++ /dev/null @@ -1,27 +0,0 @@ -# https://graphviz.readthedocs.io/en/stable/examples.html -# """https://graphviz.org/Gallery/directed/unix.html""" -LoadPackage("graphviz"); - -s := GraphvizDigraph("g"); -GraphvizSetAttr(s, "node [shape=record, height=.1]"); - -GraphvizSetAttr(GraphvizAddNode(s, "node0"), "label", "\" | G| \""); -GraphvizSetAttr(GraphvizAddNode(s, "node1"), "label", "\" | E| \""); -GraphvizSetAttr(GraphvizAddNode(s, "node2"), "label", "\" | B| \""); -GraphvizSetAttr(GraphvizAddNode(s, "node3"), "label", "\" | F| \""); -GraphvizSetAttr(GraphvizAddNode(s, "node4"), "label", "\" | R| \""); -GraphvizSetAttr(GraphvizAddNode(s, "node5"), "label", "\" | H| \""); -GraphvizSetAttr(GraphvizAddNode(s, "node6"), "label", "\" | Y| \""); -GraphvizSetAttr(GraphvizAddNode(s, "node7"), "label", "\" | A| \""); -GraphvizSetAttr(GraphvizAddNode(s, "node8"), "label", "\" | C| \""); - -GraphvizAddEdge(s, "node0:f2", "node4:f1"); -GraphvizAddEdge(s, "node0:f0", "node1:f1"); -GraphvizAddEdge(s, "node1:f0", "node2:f1"); -GraphvizAddEdge(s, "node1:f2", "node3:f1"); -GraphvizAddEdge(s, "node2:f2", "node8:f1"); -GraphvizAddEdge(s, "node2:f0", "node7:f1"); -GraphvizAddEdge(s, "node4:f2", "node6:f1"); -GraphvizAddEdge(s, "node4:f0", "node5:f1"); - -Print(AsString(s)); diff --git a/examples/cluster.gi b/examples/cluster.g similarity index 77% rename from examples/cluster.gi rename to examples/cluster.g index 1b70802..0460bd4 100644 --- a/examples/cluster.gi +++ b/examples/cluster.g @@ -1,3 +1,13 @@ +############################################################################# +## +## cluster.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + # https://graphviz.readthedocs.io/en/stable/examples.html LoadPackage("graphviz"); graph := GraphvizDigraph("G"); @@ -31,3 +41,5 @@ GraphvizSetAttr(graph["start"], "shape", "Mdiamond"); GraphvizSetAttr(graph["end"], "shape", "Msquare"); Print(AsString(graph)); +Splash(graph); +QUIT; diff --git a/examples/cluster_edge.gi b/examples/cluster_edge.g similarity index 65% rename from examples/cluster_edge.gi rename to examples/cluster_edge.g index 813bf88..9ce9556 100644 --- a/examples/cluster_edge.gi +++ b/examples/cluster_edge.g @@ -1,5 +1,15 @@ +############################################################################# +## +## cluster_edge.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + # https://graphviz.readthedocs.io/en/stable/examples.html -# """https://www.graphviz.org/pdf/dotguide.pdf, Figure 20""" +# https://www.graphviz.org/pdf/dotguide.pdf, Figure 20 LoadPackage("graphviz"); @@ -28,4 +38,5 @@ GraphvizSetAttr(e, "ltail", "cluster0"); GraphvizAddEdge(g, "d", "h"); -Print(AsString(g)); +Splash(g); +QUIT; diff --git a/examples/colors.g b/examples/colors.g new file mode 100644 index 0000000..9a6f2e5 --- /dev/null +++ b/examples/colors.g @@ -0,0 +1,35 @@ +############################################################################# +## +## colors.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +# https://graphviz.org/docs/attr-types/color + +LoadPackage("graphviz"); +g := GraphvizGraph(); + +node := GraphvizAddNode(g, "RGB: #40e0d0"); +GraphvizSetAttr(node, "style", "filled"); +GraphvizSetAttr(node, "fillcolor", "\"#40e0d0\""); + +node := GraphvizAddNode(g, "RGBA: #ff000042"); +GraphvizSetAttr(node, "style", "filled"); +GraphvizSetAttr(node, "fillcolor", "\"#ff000042\""); + +node := GraphvizAddNode(g, "HSV: 0.051 0.718 0.627"); +GraphvizSetAttr(node, "style", "filled"); +GraphvizSetAttr(node, "fillcolor", "0.051 0.718 0.627"); + +node := GraphvizAddNode(g, "name: deeppink"); +GraphvizSetAttr(node, "style", "filled"); +GraphvizSetAttr(node, "fillcolor", "deeppink"); + +Print(AsString(g)); +Splash(g); +QUIT; diff --git a/examples/colors.gi b/examples/colors.gi deleted file mode 100644 index 2a9c9bc..0000000 --- a/examples/colors.gi +++ /dev/null @@ -1,23 +0,0 @@ -# https://graphviz.readthedocs.io/en/stable/examples.html -# """https://graphviz.org/docs/attr-types/color""" - -LoadPackage("graphviz"); -g := GraphvizGraph(); - -node := GraphvizAddNode(g, "RGB #40e0d0"); -GraphvizSetAttr(node, "style", "filled"); -GraphvizSetAttr(node, "fillcolor", "#40e0d0"); - -node := GraphvizAddNode(g, "RGBA #ff000042"); -GraphvizSetAttr(node, "style", "filled"); -GraphvizSetAttr(node, "fillcolor", "#ff000042"); - -node := GraphvizAddNode(g, "HSV 0.051 0.718 0.627"); -GraphvizSetAttr(node, "style", "filled"); -GraphvizSetAttr(node, "fillcolor", "0.051 0.718 0.627"); - -node := GraphvizAddNode(g, "name deeppink"); -GraphvizSetAttr(node, "style", "filled"); -GraphvizSetAttr(node, "fillcolor", "deeppink"); - -Print(AsString(g)); diff --git a/examples/er.gi b/examples/er.g similarity index 83% rename from examples/er.gi rename to examples/er.g index dea5a6d..2025c07 100644 --- a/examples/er.gi +++ b/examples/er.g @@ -1,5 +1,15 @@ +############################################################################# +## +## er.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + # https://graphviz.readthedocs.io/en/stable/examples.html -# """https://graphviz.org/Gallery/undirected/ER.html""" +# https://graphviz.org/Gallery/undirected/ER.html LoadPackage("graphviz"); e := GraphvizGraph("ER"); GraphvizSetAttr(e, "engine=\"neato\""); @@ -49,3 +59,5 @@ GraphvizSetAttr(e, "label=\"Entity Relation Diagram\ndrawn by NEATO\""); GraphvizSetAttr(e, "fontsize=\"20\""); Print(AsString(e)); +Splash(e); +QUIT; diff --git a/examples/fsm.gi b/examples/fsm.g similarity index 80% rename from examples/fsm.gi rename to examples/fsm.g index 3ba54ad..46a8126 100644 --- a/examples/fsm.gi +++ b/examples/fsm.g @@ -1,5 +1,15 @@ +############################################################################# +## +## fsm.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + # https://graphviz.readthedocs.io/en/stable/examples.html -# """https://graphviz.org/Gallery/directed/fsm.html""" +# https://graphviz.org/Gallery/directed/fsm.html LoadPackage("graphviz"); f := GraphvizDigraph("finite_state_machine"); @@ -31,3 +41,5 @@ GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_8", "LR_6"), "label", "\"S(b)\""); GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_8", "LR_5"), "label", "\"S(a)\""); Print(AsString(f)); +Splash(f); +QUIT; diff --git a/examples/g_c_n.gi b/examples/g_c_n.g similarity index 58% rename from examples/g_c_n.gi rename to examples/g_c_n.g index 5a083f1..1a47f7b 100644 --- a/examples/g_c_n.gi +++ b/examples/g_c_n.g @@ -1,5 +1,15 @@ +############################################################################# +## +## g_c_n.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + # https://graphviz.readthedocs.io/en/stable/examples.html -# """https://www.graphviz.org/Gallery/gradient/g_c_n.html""" +# https://www.graphviz.org/Gallery/gradient/g_c_n.html LoadPackage("graphviz"); @@ -16,3 +26,5 @@ GraphvizSetAttr(cluster1, Concatenation( GraphvizAddNode(cluster1, "anode"); Print(AsString(g)); +Splash(g); +QUIT; diff --git a/examples/hello.g b/examples/hello.g new file mode 100644 index 0000000..917c5bd --- /dev/null +++ b/examples/hello.g @@ -0,0 +1,17 @@ +############################################################################# +## +## hello.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +LoadPackage("graphviz"); +graph := GraphvizDigraph("G"); +GraphvizAddEdge(graph, "hello", "world"); +Print(AsString(graph)); +Splash(graph); +QUIT; diff --git a/examples/hello.gi b/examples/hello.gi deleted file mode 100644 index 51ec486..0000000 --- a/examples/hello.gi +++ /dev/null @@ -1,6 +0,0 @@ -# https://graphviz.readthedocs.io/en/stable/examples.html -LoadPackage("graphviz"); -graph := GraphvizDigraph("G"); -GraphvizAddEdge(graph, "hello", "world"); -Print(AsString(graph)); - diff --git a/examples/process.gi b/examples/process.g similarity index 65% rename from examples/process.gi rename to examples/process.g index c82ae2e..d9242dc 100644 --- a/examples/process.gi +++ b/examples/process.g @@ -1,4 +1,15 @@ +############################################################################# +## +## process.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + # https://graphviz.readthedocs.io/en/stable/examples.html + LoadPackage("graphviz"); graph := GraphvizGraph("G"); GraphvizSetAttr(graph, "engine=\"sfdp\""); @@ -16,3 +27,5 @@ GraphvizAddEdge(graph, "runswap", "new"); GraphvizAddEdge(graph, "runswap", "runmem"); GraphvizAddEdge(graph, "new", "runmem"); Print(AsString(graph)); +Splash(graph); +QUIT; diff --git a/examples/rank_same.gi b/examples/rank_same.g similarity index 62% rename from examples/rank_same.gi rename to examples/rank_same.g index 64824a2..6dd8ca0 100644 --- a/examples/rank_same.gi +++ b/examples/rank_same.g @@ -1,3 +1,13 @@ +############################################################################# +## +## rank_same.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + # https://graphviz.readthedocs.io/en/stable/examples.html # https://stackoverflow.com/questions/25734244 @@ -23,3 +33,5 @@ GraphvizAddEdge(g, "C", "D"); GraphvizAddEdge(g, "X", "Y"); Print(AsString(g)); +Splash(g); +QUIT; diff --git a/examples/structs.g b/examples/structs.g new file mode 100644 index 0000000..a764a7e --- /dev/null +++ b/examples/structs.g @@ -0,0 +1,55 @@ +############################################################################# +## +## structs.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +# https://graphviz.org/Gallery/directed/unix.html +LoadPackage("graphviz"); + +s := GraphvizDigraph("structs"); +GraphvizSetAttr(s, "node [shape=\"plaintext\"]"); + +GraphvizSetAttr(GraphvizAddNode(s, "struct1"), "label", +"""< + + + + +
leftmiddleright
>"""); +GraphvizSetAttr(GraphvizAddNode(s, "struct2"), "label", +"""< + + + + +
onetwo
>"""); +GraphvizSetAttr(GraphvizAddNode(s, "struct3"), "label", +"""< + + + + + + + + + + + + + + +
hello
world
bgh
cde
f
>"""); + +GraphvizAddEdge(s, "struct1:f1", "struct2:f0"); +GraphvizAddEdge(s, "struct1:f2", "struct3:here"); + +Print(AsString(s)); +Splash(s); +QUIT; diff --git a/examples/structs.gi b/examples/structs.gi deleted file mode 100644 index 24f13fc..0000000 --- a/examples/structs.gi +++ /dev/null @@ -1,43 +0,0 @@ -# # https://graphviz.readthedocs.io/en/stable/examples.html -# # """https://graphviz.org/Gallery/directed/unix.html""" -LoadPackage("graphviz"); - -s := GraphvizDigraph("structs"); -GraphvizSetAttr(s, "node [shape=\"plaintext\"]"); - -GraphvizSetAttr(GraphvizAddNode(s, "struct1"), "label", -"""< - - - - -
leftmiddleright
>"""); -GraphvizSetAttr(GraphvizAddNode(s, "struct2"), "label", -"""< - - - - -
onetwo
>"""); -GraphvizSetAttr(GraphvizAddNode(s, "struct3"), "label", -"""< - - - - - - - - - - - - - - -
hello
world
bgh
cde
f
>"""); - -GraphvizAddEdge(s, "struct1:f1", "struct2:f0"); -GraphvizAddEdge(s, "struct1:f2", "struct3:here"); - -Print(AsString(s)); diff --git a/examples/traffic_lights_WIP.gi b/examples/traffic_lights.g similarity index 77% rename from examples/traffic_lights_WIP.gi rename to examples/traffic_lights.g index 410872a..1162f2a 100644 --- a/examples/traffic_lights_WIP.gi +++ b/examples/traffic_lights.g @@ -1,5 +1,15 @@ +############################################################################# +## +## traffic_lights.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + # https://graphviz.readthedocs.io/en/stable/examples.html -# """https://graphviz.org/Gallery/directed/unix.html""" +# https://graphviz.org/Gallery/directed/unix.html LoadPackage("graphviz"); t := GraphvizDigraph("TrafficLights"); @@ -46,9 +56,11 @@ od; GraphvizSetAttr(t, "overlap=\"false\""); GraphvizSetAttr(t, -"""label=\"PetriNet Model TrafficLights -Extracted from ConceptBase and laid out by Graphviz\" +"""label="PetriNet Model TrafficLights +Extracted from ConceptBase and laid out by Graphviz" """); GraphvizSetAttr(t, "fontsize=12"); Print(AsString(t)); +Splash(t); +QUIT; diff --git a/examples/unix.gi b/examples/unix.g similarity index 85% rename from examples/unix.gi rename to examples/unix.g index f5c7aed..65abf5a 100644 --- a/examples/unix.gi +++ b/examples/unix.g @@ -1,5 +1,15 @@ +############################################################################# +## +## unix.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + # https://graphviz.readthedocs.io/en/stable/examples.html -# """https://graphviz.org/Gallery/directed/unix.html""" +# https://graphviz.org/Gallery/directed/unix.html LoadPackage("graphviz"); u := GraphvizDigraph("unix"); @@ -57,3 +67,5 @@ GraphvizAddEdge(u, "System V.0", "System V.2"); GraphvizAddEdge(u, "System V.2", "System V.3"); Print(AsString(u)); +Splash(u); +QUIT; diff --git a/gap/dot.gd b/gap/dot.gd index 51d2f20..48cf367 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -1,3 +1,13 @@ +############################################################################# +## +## dot.gd +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + #! @Chapter #! @ChapterTitle An introduction to the DOT language and Graphviz. #! This chapter explains what the DOT and graphviz are, @@ -78,6 +88,7 @@ DeclareOperation("GraphvizAttrs", [IsGVObject]); #! @Description Gets the nodes of the provided graphviz graph. #! Node names can only be [a-zA-Z0-9_£] TODO check exact docs. DeclareOperation("GraphvizNodes", [IsGVGraph]); +DeclareOperation("GraphvizNode", [IsGVGraph, IsObject]); #! @Arguments graph #! @Returns the subgraphs of the provided graphviz graph. @@ -98,6 +109,7 @@ DeclareOperation("GraphvizFindGraph", [IsGVGraph, IsObject]); #! @Returns the edges of the provided graphviz graph. #! @Description Gets the edges of the provided graphviz graph. DeclareOperation("GraphvizEdges", [IsGVGraph]); +DeclareOperation("GraphvizEdges", [IsGVGraph, IsObject, IsObject]); #! @Subsection For only edges. @@ -182,6 +194,7 @@ DeclareOperation("GraphvizSetAttr", [IsGVObject, IsObject]); #! Updates the label of the object. #! If a label already exists and a new value is provided, the old value will #! be overwritten. +# TODO remove DeclareOperation("GraphvizSetLabel", [IsGVObject, IsObject]); #! @Arguments obj, color @@ -190,6 +203,7 @@ DeclareOperation("GraphvizSetLabel", [IsGVObject, IsObject]); #! Updates the color of the object. #! If a color already exists and a new value is provided, the old value will #! be overwritten. +# TODO remove DeclareOperation("GraphvizSetColor", [IsGVObject, IsObject]); #! @Arguments obj, attr @@ -208,3 +222,7 @@ DeclareOperation("AsString", [IsGVGraph]); #! Unimplemented operation which depending packages can implement. #! Should output the graphviz package representation of the object. DeclareOperation("Graphviz", [IsObject]); + +DeclareOperation("GraphvizSetNodeColors", [IsGVGraph, IsList]); +DeclareOperation("GraphvizSetNodeLabels", [IsGVGraph, IsList]); +DeclareGlobalFunction("ErrorFormatted"); diff --git a/gap/dot.gi b/gap/dot.gi index d91fb55..0ec12d9 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -1,10 +1,59 @@ -# ############################################################################## +############################################################################# +## +## dot.gi +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +############################################################################# # Private functionality -# ############################################################################## +############################################################################# + +BindGlobal("NumberOfSubstrings", +function(string, substring) + local pos, count; + + pos := 0; + count := 0; + while pos <= Length(string) and pos <> fail do + pos := PositionSublist(string, substring, pos); + if pos <> fail then + count := count + 1; + fi; + od; + return count; +end); + +InstallGlobalFunction(ErrorFormatted, +function(arg...) + local pos, fmt, n, msg; + + pos := PositionProperty(arg, x -> not IsString(x)); + if pos = fail then + pos := Length(arg) + 1; + fi; + fmt := Concatenation(arg{[1 .. pos - 1]}); + n := NumberOfSubstrings(fmt, "{}"); + arg := Concatenation([Concatenation(arg{[1 .. Length(arg) - n]})], + arg{[Length(arg) - n + 1 .. Length(arg)]}); + msg := CallFuncList(StringFormatted, arg); + # RemoveCharacters(msg, "\\\n"); + ErrorInner( + rec(context := ParentLVars(GetCurrentLVars()), + mayReturnVoid := false, + mayReturnObj := false, + lateMessage := "type 'quit;' to quit to outer loop", + printThisStatement := false), + [msg]); +end); DeclareOperation("GV_GetCounter", [IsGVGraph]); DeclareOperation("GV_IncCounter", [IsGVGraph]); DeclareCategory("IsGV_Map", IsObject); +DeclareAttribute("Size", IsGV_Map); DeclareOperation("GV_StringifyGraphHead", [IsGVGraph]); DeclareOperation("GV_StringifyDigraphHead", [IsGVGraph]); @@ -52,6 +101,122 @@ BindGlobal("GV_KNOWN_ATTRS", [ "z" ]); +BindGlobal("GV_ValidColorNames", + ["aliceblue", "antiquewhite", "antiquewhite1", "antiquewhite2", + "antiquewhite3", "antiquewhite4", "aquamarine", "aquamarine1", "aquamarine2", + "aquamarine3", "aquamarine4", "azure", "azure1", "azure2", "azure3", + "azure4", "beige", "bisque", "bisque1", "bisque2", "bisque3", "bisque4", + "black", "blanchedalmond", "blue", "blue1", "blue2", "blue3", "blue4", + "blueviolet", "brown", "brown1", "brown2", "brown3", "brown4", "burlywood", + "burlywood1", "burlywood2", "burlywood3", "burlywood4", "cadetblue", + "cadetblue1", "cadetblue2", "cadetblue3", "cadetblue4", "chartreuse", + "chartreuse1", "chartreuse2", "chartreuse3", "chartreuse4", "chocolate", + "chocolate1", "chocolate2", "chocolate3", "chocolate4", "coral", "coral1", + "coral2", "coral3", "coral4", "cornflowerblue", "cornsilk", "cornsilk1", + "cornsilk2", "cornsilk3", "cornsilk4", "crimson", "cyan", "cyan1", "cyan2", + "cyan3", "cyan4", "darkgoldenrod", "darkgoldenrod1", "darkgoldenrod2", + "darkgoldenrod3", "darkgoldenrod4", "darkgreen", "darkkhaki", + "darkolivegreen", "darkolivegreen1", "darkolivegreen2", "darkolivegreen3", + "darkolivegreen4", "darkorange", "darkorange1", "darkorange2", "darkorange3", + "darkorange4", "darkorchid", "darkorchid1", "darkorchid2", "darkorchid3", + "darkorchid4", "darksalmon", "darkseagreen", "darkseagreen1", + "darkseagreen2", "darkseagreen3", "darkseagreen4", "darkslateblue", + "darkslategray", "darkslategray1", "darkslategray2", "darkslategray3", + "darkslategray4", "darkslategrey", "darkturquoise", "darkviolet", "deeppink", + "deeppink1", "deeppink2", "deeppink3", "deeppink4", "deepskyblue", + "deepskyblue1", "deepskyblue2", "deepskyblue3", "deepskyblue4", "dimgray", + "dimgrey", "dodgerblue", "dodgerblue1", "dodgerblue2", "dodgerblue3", + "dodgerblue4", "firebrick", "firebrick1", "firebrick2", "firebrick3", + "firebrick4", "floralwhite", "forestgreen", "gainsboro", "ghostwhite", + "gold", "gold1", "gold2", "gold3", "gold4", "goldenrod", "goldenrod1", + "goldenrod2", "goldenrod3", "goldenrod4", "gray", "gray0", "gray1", "gray10", + "gray100", "gray11", "gray12", "gray13", "gray14", "gray15", "gray16", + "gray17", "gray18", "gray19", "gray2", "gray20", "gray21", "gray22", + "gray23", "gray24", "gray25", "gray26", "gray27", "gray28", "gray29", + "gray3", "gray30", "gray31", "gray32", "gray33", "gray34", "gray35", + "gray36", "gray37", "gray38", "gray39", "gray4", "gray40", "gray41", + "gray42", "gray43", "gray44", "gray45", "gray46", "gray47", "gray48", + "gray49", "gray5", "gray50", "gray51", "gray52", "gray53", "gray54", + "gray55", "gray56", "gray57", "gray58", "gray59", "gray6", "gray60", + "gray61", "gray62", "gray63", "gray64", "gray65", "gray66", "gray67", + "gray68", "gray69", "gray7", "gray70", "gray71", "gray72", "gray73", + "gray74", "gray75", "gray76", "gray77", "gray78", "gray79", "gray8", + "gray80", "gray81", "gray82", "gray83", "gray84", "gray85", "gray86", + "gray87", "gray88", "gray89", "gray9", "gray90", "gray91", "gray92", + "gray93", "gray94", "gray95", "gray96", "gray97", "gray98", "gray99", + "green", "green1", "green2", "green3", "green4", "greenyellow", "grey", + "grey0", "grey1", "grey10", "grey100", "grey11", "grey12", "grey13", + "grey14", "grey15", "grey16", "grey17", "grey18", "grey19", "grey2", + "grey20", "grey21", "grey22", "grey23", "grey24", "grey25", "grey26", + "grey27", "grey28", "grey29", "grey3", "grey30", "grey31", "grey32", + "grey33", "grey34", "grey35", "grey36", "grey37", "grey38", "grey39", + "grey4", "grey40", "grey41", "grey42", "grey43", "grey44", "grey45", + "grey46", "grey47", "grey48", "grey49", "grey5", "grey50", "grey51", + "grey52", "grey53", "grey54", "grey55", "grey56", "grey57", "grey58", + "grey59", "grey6", "grey60", "grey61", "grey62", "grey63", "grey64", + "grey65", "grey66", "grey67", "grey68", "grey69", "grey7", "grey70", + "grey71", "grey72", "grey73", "grey74", "grey75", "grey76", "grey77", + "grey78", "grey79", "grey8", "grey80", "grey81", "grey82", "grey83", + "grey84", "grey85", "grey86", "grey87", "grey88", "grey89", "grey9", + "grey90", "grey91", "grey92", "grey93", "grey94", "grey95", "grey96", + "grey97", "grey98", "grey99", "honeydew", "honeydew1", "honeydew2", + "honeydew3", "honeydew4", "hotpink", "hotpink1", "hotpink2", "hotpink3", + "hotpink4", "indianred", "indianred1", "indianred2", "indianred3", + "indianred4", "indigo", "invis", "ivory", "ivory1", "ivory2", "ivory3", + "ivory4", "khaki", "khaki1", "khaki2", "khaki3", "khaki4", "lavender", + "lavenderblush", "lavenderblush1", "lavenderblush2", "lavenderblush3", + "lavenderblush4", "lawngreen", "lemonchiffon", "lemonchiffon1", + "lemonchiffon2", "lemonchiffon3", "lemonchiffon4", "lightblue", "lightblue1", + "lightblue2", "lightblue3", "lightblue4", "lightcoral", "lightcyan", + "lightcyan1", "lightcyan2", "lightcyan3", "lightcyan4", "lightgoldenrod", + "lightgoldenrod1", "lightgoldenrod2", "lightgoldenrod3", "lightgoldenrod4", + "lightgoldenrodyellow", "lightgray", "lightgrey", "lightpink", "lightpink1", + "lightpink2", "lightpink3", "lightpink4", "lightsalmon", "lightsalmon1", + "lightsalmon2", "lightsalmon3", "lightsalmon4", "lightseagreen", + "lightskyblue", "lightskyblue1", "lightskyblue2", "lightskyblue3", + "lightskyblue4", "lightslateblue", "lightslategray", "lightslategrey", + "lightsteelblue", "lightsteelblue1", "lightsteelblue2", "lightsteelblue3", + "lightsteelblue4", "lightyellow", "lightyellow1", "lightyellow2", + "lightyellow3", "lightyellow4", "limegreen", "linen", "magenta", "magenta1", + "magenta2", "magenta3", "magenta4", "maroon", "maroon1", "maroon2", + "maroon3", "maroon4", "mediumaquamarine", "mediumblue", "mediumorchid", + "mediumorchid1", "mediumorchid2", "mediumorchid3", "mediumorchid4", + "mediumpurple", "mediumpurple1", "mediumpurple2", "mediumpurple3", + "mediumpurple4", "mediumseagreen", "mediumslateblue", "mediumspringgreen", + "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", + "mistyrose", "mistyrose1", "mistyrose2", "mistyrose3", "mistyrose4", + "moccasin", "navajowhite", "navajowhite1", "navajowhite2", "navajowhite3", + "navajowhite4", "navy", "navyblue", "none", "oldlace", "olivedrab", + "olivedrab1", "olivedrab2", "olivedrab3", "olivedrab4", "orange", "orange1", + "orange2", "orange3", "orange4", "orangered", "orangered1", "orangered2", + "orangered3", "orangered4", "orchid", "orchid1", "orchid2", "orchid3", + "orchid4", "palegoldenrod", "palegreen", "palegreen1", "palegreen2", + "palegreen3", "palegreen4", "paleturquoise", "paleturquoise1", + "paleturquoise2", "paleturquoise3", "paleturquoise4", "palevioletred", + "palevioletred1", "palevioletred2", "palevioletred3", "palevioletred4", + "papayawhip", "peachpuff", "peachpuff1", "peachpuff2", "peachpuff3", + "peachpuff4", "peru", "pink", "pink1", "pink2", "pink3", "pink4", "plum", + "plum1", "plum2", "plum3", "plum4", "powderblue", "purple", "purple1", + "purple2", "purple3", "purple4", "red", "red1", "red2", "red3", "red4", + "rosybrown", "rosybrown1", "rosybrown2", "rosybrown3", "rosybrown4", + "royalblue", "royalblue1", "royalblue2", "royalblue3", "royalblue4", + "saddlebrown", "salmon", "salmon1", "salmon2", "salmon3", "salmon4", + "sandybrown", "seagreen", "seagreen1", "seagreen2", "seagreen3", "seagreen4", + "seashell", "seashell1", "seashell2", "seashell3", "seashell4", "sienna", + "sienna1", "sienna2", "sienna3", "sienna4", "skyblue", "skyblue1", + "skyblue2", "skyblue3", "skyblue4", "slateblue", "slateblue1", "slateblue2", + "slateblue3", "slateblue4", "slategray", "slategray1", "slategray2", + "slategray3", "slategray4", "slategrey", "snow", "snow1", "snow2", "snow3", + "snow4", "springgreen", "springgreen1", "springgreen2", "springgreen3", + "springgreen4", "steelblue", "steelblue1", "steelblue2", "steelblue3", + "steelblue4", "tan", "tan1", "tan2", "tan3", "tan4", "thistle", "thistle1", + "thistle2", "thistle3", "thistle4", "tomato", "tomato1", "tomato2", + "tomato3", "tomato4", "transparent", "turquoise", "turquoise1", "turquoise2", + "turquoise3", "turquoise4", "violet", "violetred", "violetred1", + "violetred2", "violetred3", "violetred4", "wheat", "wheat1", "wheat2", + "wheat3", "wheat4", "white", "whitesmoke", "yellow", "yellow1", "yellow2", + "yellow3", "yellow4", "yellowgreen"]); + # code from the GAP standard library InstallMethod(GV_Pluralize, "for an integer and a string", @@ -135,7 +300,7 @@ end); ############################################################################### # Family + type -# ############################################################################## +############################################################################### BindGlobal("GV_ObjectFamily", NewFamily("GV_ObjectFamily", @@ -171,9 +336,14 @@ BindGlobal("GV_ContextType", NewType(GV_ObjectFamily, IsComponentObjectRep and IsAttributeStoringRep)); -# ############################################################################## +InstallMethod(\=, "for IsGVNode and IsGVNode", +[IsGVNode, IsGVNode], +{n1, n2} -> GraphvizName(n1) = GraphvizName(n2)); + +############################################################################### # Constuctors etc -# ############################################################################## +############################################################################### + DeclareOperation("GV_Node", [IsGVGraph, IsString]); DeclareOperation("GV_Edge", [IsGVGraph, IsGVNode, IsGVNode]); DeclareOperation("GV_Graph", [IsGVGraph, IsString]); @@ -184,13 +354,12 @@ DeclareOperation("GV_Map", []); InstallMethod(GV_Map, "for no args", [], {} -> Objectify(GV_MapType, rec(Data := rec()))); -InstallMethod(GV_Node, -"for a string", +InstallMethod(GV_Node, "for a string", [IsGVGraph, IsString], function(graph, name) local out; if Length(name) = 0 then - return ErrorNoReturn("Node name cannot be empty."); + ErrorNoReturn("the 2nd argument (string/node name) cannot be empty"); fi; out := Objectify(GV_NodeType, rec( @@ -317,6 +486,7 @@ InstallMethod(GraphvizDigraph, "for no args", [], {} -> GraphvizDigraph("")); # ########################################################### # Graphviz Map Functions # ########################################################### + InstallOtherMethod(\[\], "for a graphviz map and an object", [IsGV_Map, IsObject], @@ -354,12 +524,14 @@ InstallMethod(GV_MapNames, "for a graphviz map", InstallMethod(ViewString, "for a graphviz map", [IsGV_Map], m -> String(m!.Data)); -# ########################################################### +InstallMethod(Size, "for a graphviz map", +[IsGV_Map], m -> Length(GV_MapNames(m))); + +############################################################ # Stringify -# ########################################################### -InstallMethod(ViewString, -"for a graphviz node", -[IsGVNode], +############################################################ + +InstallMethod(ViewString, "for a graphviz node", [IsGVNode], n -> StringFormatted("", GraphvizName(n))); InstallMethod(ViewString, "for a graphviz edge", [IsGVEdge], @@ -368,7 +540,8 @@ function(e) head := GraphvizHead(e); tail := GraphvizTail(e); return StringFormatted("", - GraphvizName(head), GraphvizName(tail)); + GraphvizName(head), + GraphvizName(tail)); end); InstallMethod(ViewString, "for a graphviz graph", [IsGVGraph], @@ -377,7 +550,8 @@ function(g) result := ""; edges := Length(GraphvizEdges(g)); - nodes := Length(GV_MapNames(GraphvizNodes(g))); + nodes := + Length(GV_MapNames(GraphvizNodes(g))); if IsGVDigraph(g) then kind := "digraph"; @@ -402,32 +576,42 @@ end); ############################################################ # Getters ############################################################ -InstallMethod(GraphvizName, -"for a graphviz object", -[IsGVObject], -x -> x!.Name); -InstallMethod(GraphvizAttrs, -"for a graphviz object", -[IsGVObject], +InstallMethod(GraphvizName, "for a graphviz object", [IsGVObject], x -> x!.Name); + +InstallMethod(GraphvizAttrs, "for a graphviz object", [IsGVObject], x -> x!.Attrs); -InstallMethod(GraphvizNodes, -"for a graphviz graph", -[IsGVGraph], +# TODO remove, the returned value is mutable, looks like a record but isn't +# one. Mutability is a problem, since if we do GraphvizNodes(gv)[1] := 2; then +# the object is corrupt. +InstallMethod(GraphvizNodes, "for a graphviz graph", [IsGVGraph], x -> x!.Nodes); +InstallMethod(GraphvizNode, "for a graphviz graph and object", +[IsGVGraph, IsObject], {gv, obj} -> gv!.Nodes[String(obj)]); + +# TODO remove for the same reason as GraphvizNodes, unless we can make the list +# immutable or return a copy. +InstallMethod(GraphvizEdges, "for a graphviz graph", +[IsGVGraph], x -> x!.Edges); + InstallMethod(GraphvizEdges, -"for a graphviz graph", -[IsGVGraph], -x -> x!.Edges); +"for a graphviz graph, object, and object", +[IsGVGraph, IsObject, IsObject], +function(gv, head, tail) + head := GraphvizNode(gv, head); + tail := GraphvizNode(gv, tail); + # TODO if head = fail then... + return Filtered(GraphvizEdges(gv), x -> GraphvizHead(x) = head and + GraphvizTail(x) = tail); +end); -InstallMethod(GraphvizSubgraphs, -"for a graphviz graph", -[IsGVGraph], +InstallMethod(GraphvizSubgraphs, "for a graphviz graph", [IsGVGraph], x -> x!.Subgraphs); InstallMethod(GraphvizTail, "for a graphviz edge", [IsGVEdge], x -> x!.Tail); + InstallMethod(GraphvizHead, "for a graphviz edge", [IsGVEdge], x -> x!.Head); InstallMethod(GraphvizGetSubgraph, @@ -447,15 +631,13 @@ function(x) x!.Counter := x!.Counter + 1; end); -InstallMethod(GV_GetCounter, -"for a graphviz graph", -[IsGVGraph], +InstallMethod(GV_GetCounter, "for a graphviz graph", [IsGVGraph], x -> x!.Counter); # Converting strings DeclareOperation("GV_EnsureString", [IsObject]); -# TODO required? +# TODO required? Replace with AsString InstallMethod(GV_EnsureString, "for an object", [IsObject], ViewString); @@ -543,6 +725,7 @@ InstallMethod(GV_GetParent, [IsGVGraph], graph -> graph!.Parent); DeclareOperation("GV_GraphTreeSearch", [IsGVGraph, IsFunction]); + InstallMethod(GV_GraphTreeSearch, "for a graphviz graph and a predicate", [IsGVGraph, IsFunction], @@ -621,9 +804,10 @@ function(g, n) return graph[n]; end); -# ########################################################### +############################################################ # Setters -# ########################################################### +############################################################ + InstallMethod(GraphvizSetName, "for a graphviz object and string", [IsGVGraph, IsString], function(x, name) @@ -648,8 +832,14 @@ end); InstallMethod(GraphvizSetAttr, "for a graphviz object, object and object", [IsGVObject, IsObject, IsObject], function(x, name, value) + local msg; + if not name in GV_KNOWN_ATTRS then - Print(StringFormatted("[WARNING] Unknown attribute {}\n", name)); + msg := Concatenation( + StringFormatted("unknown attribute \"{}\", the", name), + " graphviz object may no longer be valid, it can", + " be removed using GraphvizRemoveAttr"); + Info(InfoWarning, 1, msg); fi; GraphvizAttrs(x)[String(name)] := String(value); return x; @@ -658,22 +848,27 @@ end); InstallMethod(GraphvizSetAttr, "for a graphviz graph, object and object", [IsGVGraph, IsObject, IsObject], function(x, name, value) - local attrs, string; + local attrs, string, msg; - # display warning if not known attribute if not name in GV_KNOWN_ATTRS then - Print(StringFormatted("[WARNING] Unknown attribute {}\n", name)); + msg := Concatenation( + StringFormatted("unknown attribute \"{}\", the", name), + " graphviz object may no longer be valid, it can", + " be removed using GraphvizRemoveAttr"); + Info(InfoWarning, 1, msg); fi; attrs := GraphvizAttrs(x); + name := String(name); + value := String(value); if ' ' in name then - name := StringFormatted("{}", name); + name := StringFormatted("\"{}\"", name); fi; if ' ' in value then - value := StringFormatted("{}", value); + value := StringFormatted("\"{}\"", value); fi; - string := StringFormatted("{}={}", String(name), String(value)); + string := StringFormatted("{}={}", name, value); Add(attrs, string); return x; end); @@ -711,7 +906,7 @@ function(x, node) found := GV_FindGraphWithNode(x, name); if found <> fail then error := "Already node with name {} in graph {}."; - return ErrorNoReturn(StringFormatted(error, name, GraphvizName(found))); + ErrorNoReturn(StringFormatted(error, name, GraphvizName(found))); fi; nodes[name] := node; @@ -766,14 +961,15 @@ function(x, edge) # make sure the nodes exist / are the same as existing ones if hg <> fail and not IsIdenticalObj(head, hg[head_name]) then - error := "Different node in graph {} with name {}."; - return ErrorNoReturn(StringFormatted(error, - GraphvizName(hg), - head_name)); + # TODO improve + ErrorFormatted("Different node in graph {} with name {}", + GraphvizName(hg), + head_name); fi; if tg <> fail and not IsIdenticalObj(tail, tg[tail_name]) then + # TODO improve error := "Different node in graph {} with name {}."; - return ErrorNoReturn(StringFormatted(error, + ErrorNoReturn(StringFormatted(error, GraphvizName(tg), tail_name)); fi; @@ -845,7 +1041,7 @@ function(graph, name) subgraphs := GraphvizSubgraphs(graph); if IsBound(subgraphs[name]) then error := "The graph already contains a subgraph with name {}."; - return ErrorNoReturn(StringFormatted(error, name)); + ErrorNoReturn(StringFormatted(error, name)); fi; if IsGVDigraph(graph) then @@ -853,7 +1049,7 @@ function(graph, name) elif IsGVGraph(graph) then subgraph := GV_Graph(graph, name); else - return ErrorNoReturn("Filter must be a filter for a graph category."); + ErrorNoReturn("Filter must be a filter for a graph category."); fi; subgraphs[name] := subgraph; @@ -882,7 +1078,7 @@ function(graph, name) subgraphs := GraphvizSubgraphs(graph); if IsBound(subgraphs[name]) then error := "The graph already contains a subgraph with name {}."; - return ErrorNoReturn(StringFormatted(error, name)); + ErrorNoReturn(StringFormatted(error, name)); fi; ctx := GV_Context(graph, name); @@ -905,10 +1101,13 @@ InstallMethod(GraphvizRemoveNode, "for a graphviz graph and node", [IsGVGraph, IsGVNode], {g, node} -> GraphvizRemoveNode(g, GraphvizName(node))); +# TODO GraphvizRemoveEdges(gv, n1, n2) + InstallMethod(GraphvizRemoveNode, "for a graphviz graph and a string", [IsGVGraph, IsString], function(g, name) local nodes; + # TODO error if there's no such node nodes := GraphvizNodes(g); Unbind(nodes[name]); @@ -1016,13 +1215,34 @@ graph -> StringFormatted("subgraph {} {{\n", GraphvizName(graph))); InstallMethod(GV_StringifyContextHead, "for a string", [IsGVContext], graph -> StringFormatted("// {} context \n", GraphvizName(graph))); +BindGlobal("GV_StringifyNodeName", +function(node) + local name, old; + + Assert(0, IsGVNode(node)); + name := GraphvizName(node); + if (ForAny("- .+", x -> x in name) + or (IsDigitChar(First(name)) and IsAlphaChar(Last(name)))) + and not StartsWith(name, "\"") then + old := name; + name := StringFormatted("\"{}\"", name); + Info(InfoWarning, + 1, + "invalid node name ", + old, + " using ", + name, + " instead"); + fi; + return name; +end); + # @ Return DOT node statement line. InstallMethod(GV_StringifyNode, "for string and record", [IsGVNode], function(node) - local attrs, name; - - name := GraphvizName(node); + local name, attrs; + name := GV_StringifyNodeName(node); attrs := GraphvizAttrs(node); return StringFormatted("\t{}{}\n", name, GV_StringifyNodeEdgeAttrs(attrs)); end); @@ -1033,8 +1253,8 @@ function(edge, edge_str) local head, tail, attrs; Assert(0, IsGVEdge(edge)); Assert(0, IsString(edge_str)); - head := GraphvizName(GraphvizHead(edge)); - tail := GraphvizName(GraphvizTail(edge)); + head := GV_StringifyNodeName(GraphvizHead(edge)); + tail := GV_StringifyNodeName(GraphvizTail(edge)); attrs := GraphvizAttrs(edge); # handle : syntax @@ -1166,16 +1386,19 @@ function(graph, is_subgraph) elif IsGVGraph(graph) or IsGVDigraph(graph) then Append(result, GV_StringifySubgraphHead(graph)); else - return ErrorNoReturn("Invalid subgraph type."); + ErrorNoReturn("Invalid subgraph type."); fi; elif IsGVDigraph(graph) then + Append(result, "//dot\n"); Append(result, GV_StringifyDigraphHead(graph)); elif IsGVGraph(graph) then + Append(result, "//dot\n"); Append(result, GV_StringifyGraphHead(graph)); elif IsGVContext(graph) then + Append(result, "//dot\n"); Append(result, GV_StringifyContextHead(graph)); else - return ErrorNoReturn("Invalid graph type."); + ErrorNoReturn("Invalid graph type."); fi; Append(result, GV_StringifyGraphAttrs(graph)); @@ -1193,7 +1416,7 @@ function(graph, is_subgraph) Append(result, GV_StringifyEdge(obj, "--")); fi; else - return ErrorNoReturn("Invalid graphviz object type."); + ErrorNoReturn("Invalid graphviz object type."); fi; od; @@ -1212,3 +1435,82 @@ end); InstallMethod(AsString, "for a graphviz graph", [IsGVGraph], graph -> GV_StringifyGraph(graph, false)); + +BindGlobal("GV_IsValidRGBColor", +function(str) + local valid, i; + + valid := "0123456789ABCDEFabcdef"; + + if Length(str) <> 7 or str[1] <> '#' then + return false; + fi; + + for i in [2 .. 7] do + if not str[i] in valid then + return false; + fi; + od; + return true; +end); + +BindGlobal("GV_IsValidColor", +c -> IsString(c) and (GV_IsValidRGBColor(c) or c in GV_ValidColorNames)); + +BindGlobal("GV_ErrorIfNotValidColor", +function(c) + if not GV_IsValidColor(c) then + if IsString(c) then + c := StringFormatted("\"{}\"", c); + fi; + ErrorFormatted("invalid color {} ({}), ", + "valid colors are RGB values or names from ", + "the GraphViz 2.44.1 X11 Color Scheme", + " http://graphviz.org/doc/info/colors.html", + c, + TNAM_OBJ(c)); + fi; +end); + +BindGlobal("GV_ErrorIfNotNodeColoring", +function(gv, colors) + local N; + N := Size(GraphvizNodes(gv)); + if Length(colors) <> N then + ErrorFormatted( + "the number of node colors must be the same as the number", + " of nodes, expected {} but found {}", N, Length(colors)); + fi; + Perform(colors, GV_ErrorIfNotValidColor); +end); + +InstallMethod(GraphvizSetNodeLabels, +"for a graphviz graph and list of colors", +[IsGVGraph, IsList], +function(gv, labels) + local nodes, i; + # TODO error if labels and nodes aren't same size + # TODO GV_ErrorIfNotValidLabel + nodes := GraphvizNodes(gv); + for i in [1 .. Size(nodes)] do + GraphvizSetAttr(nodes[i], "label", labels[i]); + od; + return gv; +end); + +InstallMethod(GraphvizSetNodeColors, +"for a graphviz graph and list of colors", +[IsGVGraph, IsList], +function(gv, colors) + local nodes, i; + + GV_ErrorIfNotNodeColoring(gv, colors); + + nodes := GraphvizNodes(gv); + + for i in [1 .. Size(nodes)] do + GraphvizSetAttr(nodes[i], "color", colors[i]); + GraphvizSetAttr(nodes[i], "style", "filled"); + od; + return gv; +end); diff --git a/gap/splash.gi b/gap/splash.gi index 517e017..4effacb 100644 --- a/gap/splash.gi +++ b/gap/splash.gi @@ -1,22 +1,24 @@ +# TODO file header +# TODO rename file to remove "i" suffix -if not IsBound(Splash) then # This function is written by A. Egri-Nagy +if not IsBound(Splash) then BindGlobal("VizViewers", ["xpdf", "xdg-open", "open", "evince", "okular", "gv"]); BindGlobal("Splash", - function(arg) - local str, opt, path, dir, tdir, file, viewer, inn, filetype, out, + function(arg...) + local str, opt, path, dir, tdir, file, viewer, type, inn, filetype, out, engine; - if not IsString(arg[1]) and not IsGVGraph(arg[1]) then - ErrorNoReturn("the 1st argument must be a string or graphviz graph."); - fi; - - if IsString(arg[1]) then - str := arg[1]; + if IsEmpty(arg) then + ErrorNoReturn("the must be at least 1 argument, found none"); + elif not IsString(arg[1]) and not IsGVGraph(arg[1]) then + ErrorFormatted("the 1st argument must be a string or ", + "graphviz graph, found {}", TNAM_OBJ(arg[1])); elif IsGVGraph(arg[1]) then - str := AsString(arg[1]); + arg[1] := AsString(arg[1]); fi; + str := arg[1]; opt := rec(); if IsBound(arg[2]) and IsRecord(arg[2]) then @@ -25,13 +27,11 @@ if not IsBound(Splash) then # This function is written by A. Egri-Nagy ErrorNoReturn("the 2nd argument must be a record,"); fi; - # path - path := UserHomeExpand("~/"); # default + path := UserHomeExpand("~/"); if IsBound(opt.path) then path := opt.path; fi; - # directory if IsBound(opt.directory) then if not opt.directory in DirectoryContents(path) then Exec(Concatenation("mkdir ", path, opt.directory)); @@ -40,28 +40,27 @@ if not IsBound(Splash) then # This function is written by A. Egri-Nagy elif IsBound(opt.path) then if not "tmp.viz" in DirectoryContents(path) then tdir := Directory(Concatenation(path, "/", "tmp.viz")); - dir := Filename(tdir, ""); + dir := Filename(tdir, ""); fi; else tdir := DirectoryTemporary(); - dir := Filename(tdir, ""); + dir := Filename(tdir, ""); fi; - # file - file := "vizpicture"; # default + # TODO use the graphs name + file := "vizpicture"; if IsBound(opt.filename) then file := opt.filename; fi; - # 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), ","); + TNAM_OBJ(viewer)); elif Filename(DirectoriesSystemPrograms(), viewer) = fail then ErrorNoReturn("the viewer \"", viewer, "\" specified in the option ", - "`viewer` is not available,"); + "`viewer` is not available"); fi; else viewer := First(VizViewers, x -> @@ -73,17 +72,29 @@ if not IsBound(Splash) then # This function is written by A. Egri-Nagy fi; fi; - inn := Concatenation(dir, file, ".dot"); + 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 + inn := Concatenation(dir, file, ".dot"); + fi; - # output type and name - filetype := "pdf"; # default - if IsBound(opt.filetype) and IsString(opt.filetype) then + filetype := "pdf"; + 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 + engine := "dot"; if IsBound(opt.engine) then engine := opt.engine; if not engine in ["dot", "neato", "twopi", "circo", @@ -95,11 +106,13 @@ if not IsBound(Splash) then # This function is written by A. Egri-Nagy fi; fi; - # Write and compile the file FileString(inn, str); - # Requires GAP >= 4.11: - # Exec(StringFormatted("{} -T {} {} -o {}", engine, filetype, inn, out)); - Exec(Concatenation(engine, " -T", filetype, " ", inn, " -o ", out)); + if type = "latex" then + Exec(Concatenation("cd ", dir, ";", + "pdflatex ", file, " 2>/dev/null 1>/dev/null")); + else + Exec(Concatenation(engine, " -T", filetype, " ", inn, " -o ", out)); + fi; Exec(Concatenation(viewer, " ", out, " 2>/dev/null 1>/dev/null &")); end); fi; diff --git a/init.g b/init.g index a252105..2d54325 100644 --- a/init.g +++ b/init.g @@ -1,9 +1,11 @@ -# -# graphviz: This package facilitates the creation of graph descriptions in the -# DOT language of the Graphviz graph drawing software from GAP -# -# Reading the declaration part of the package. -# +############################################################################# +## +## init.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## ReadPackage("graphviz", "gap/dot.gd"); -ReadPackage("graphviz", "gap/defaults.gd"); \ No newline at end of file diff --git a/makedoc.g b/makedoc.g index b846e95..a04d383 100644 --- a/makedoc.g +++ b/makedoc.g @@ -1,9 +1,15 @@ -# -# graphviz: This package facilitates the creation of graph descriptions in the -# DOT language of the Graphviz graph drawing software from GAP -# -# This file is a script which compiles the package manual. -# +############################################################################# +## +## makedoc.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +## This file is a script which compiles the package manual. + if fail = LoadPackage("AutoDoc", "2022.10.20") then Error("AutoDoc version 2022.10.20 or newer is required."); fi; diff --git a/read.g b/read.g index bd72a88..4dbac1a 100644 --- a/read.g +++ b/read.g @@ -1,10 +1,12 @@ -# -# graphviz: This package facilitates the creation of graph descriptions in the -# DOT language of the Graphviz graph drawing software from GAP -# -# Reading the implementation part of the package. -# - +############################################################################# +## +## read.g +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## ReadPackage("graphviz", "gap/dot.gi"); ReadPackage("graphviz", "gap/splash.gi"); ReadPackage("graphviz", "gap/defaults.gi"); diff --git a/tst/dot.tst b/tst/dot.tst index 522e34a..4f0c708 100644 --- a/tst/dot.tst +++ b/tst/dot.tst @@ -1,12 +1,14 @@ ############################################################################# ## -## standard/dot.tst -## Copyright (C) 2022 James D. Mitchell +## dot.tst +## Copyright (C) 2024 Matthew Pancer ## ## Licensing information can be found in the README file of this package. ## ############################################################################# ## + +#@local a, b, color, e, g, label, n, shape gap> START_TEST("graphviz package: dot.tst"); gap> LoadPackage("graphviz", false);; @@ -34,7 +36,7 @@ gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "test");; gap> GraphvizSetAttrs(n, rec(color := "red", label := "lab"));; gap> AsString(g); -"graph {\n\ttest [color=red, label=lab]\n}\n" +"//dot\ngraph {\n\ttest [color=red, label=lab]\n}\n" # Test stringify with edge (digraphs) gap> g := GraphvizDigraph();; @@ -45,7 +47,8 @@ gap> GraphvizSetAttrs(b, rec(color := "red"));; gap> e := GraphvizAddEdge(g, a, b);; gap> GraphvizSetAttrs(e, rec(color := "green"));; gap> AsString(g); -"digraph {\n\ta [color=blue]\n\tb [color=red]\n\ta -> b [color=green]\n}\n" +"//dot\ndigraph {\n\ta [color=blue]\n\tb [color=red]\n\ta -> b [color=green]\ +\n}\n" # Test stringify with edge (graph) gap> g := GraphvizGraph();; @@ -56,24 +59,25 @@ gap> GraphvizSetAttrs(b, rec(color := "red"));; gap> e := GraphvizAddEdge(g, a, b);; gap> GraphvizSetAttrs(e, rec(color := "green"));; gap> AsString(g); -"graph {\n\ta [color=blue]\n\tb [color=red]\n\ta -- b [color=green]\n}\n" +"//dot\ngraph {\n\ta [color=blue]\n\tb [color=red]\n\ta -- b [color=green]\n}\ +\n" # Test stringify empty gap> g := GraphvizGraph();; gap> AsString(g); -"graph {\n}\n" +"//dot\ngraph {\n}\n" # Test unknown attributes (node) gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "n");; gap> GraphvizSetAttr(n, "test", "false"); -[WARNING] Unknown attribute test +#I unknown attribute "test", the graphviz object may no longer be valid, it can be removed using GraphvizRemoveAttr # Test unknown attributes (graph) gap> g := GraphvizGraph();; gap> GraphvizSetAttr(g, "test", "false"); -[WARNING] Unknown attribute test +#I unknown attribute "test", the graphviz object may no longer be valid, it can be removed using GraphvizRemoveAttr # Test strngifying labels with ">>" inside (node attrs) @@ -81,24 +85,24 @@ gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "node");; gap> GraphvizSetAttr(n, "label", ">>hello");; gap> AsString(g); -"graph {\n\tnode [label=\">>hello\"]\n}\n" +"//dot\ngraph {\n\tnode [label=\">>hello\"]\n}\n" gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "node");; gap> GraphvizSetAttr(n, "label", "before>>hello");; gap> AsString(g); -"graph {\n\tnode [label=\"before>>hello\"]\n}\n" +"//dot\ngraph {\n\tnode [label=\"before>>hello\"]\n}\n" # Test strngifying labels with ">>" inside (edge attrs) gap> g := GraphvizGraph();; gap> e := GraphvizAddEdge(g, "a", "b");; gap> GraphvizSetAttr(e, "label", ">>hello");; gap> AsString(g); -"graph {\n\ta\n\tb\n\ta -- b [label=\">>hello\"]\n}\n" +"//dot\ngraph {\n\ta\n\tb\n\ta -- b [label=\">>hello\"]\n}\n" gap> g := GraphvizGraph();; gap> e := GraphvizAddEdge(g, "a", "b");; gap> GraphvizSetAttr(e, "label", "before>>hello");; gap> AsString(g); -"graph {\n\ta\n\tb\n\ta -- b [label=\"before>>hello\"]\n}\n" +"//dot\ngraph {\n\ta\n\tb\n\ta -- b [label=\"before>>hello\"]\n}\n" # -gap> STOP_TEST("Digraphs package: standard/oper.tst", 0); +gap> STOP_TEST("graphviz package: dot.tst", 0); diff --git a/tst/edge.tst b/tst/edge.tst index 8cd7a95..7ed6407 100644 --- a/tst/edge.tst +++ b/tst/edge.tst @@ -1,13 +1,15 @@ ############################################################################# ## -## standard/dot.tst -## Copyright (C) 2022 James D. Mitchell +## dot.tst +## Copyright (C) 2024 Matthew Pancer ## ## Licensing information can be found in the README file of this package. ## ############################################################################# ## -gap> START_TEST("graphviz package: dot.tst"); + +#@local a, a1, a2, ab, b, c, cd, color, d, e, e1, e2, g, g1, label, n +gap> START_TEST("graphviz package: edge.tst"); gap> LoadPackage("graphviz", false);; # Test edge constructor @@ -81,7 +83,7 @@ gap> a2 := GraphvizAddNode(g1, "a");; gap> c := GraphvizAddNode(g1, "c");; gap> e1 := GraphvizAddEdge(g, d, a1);; gap> e2 := GraphvizAddEdge(g, a2, c);; -Error, Different node in graph with name a. +Error, Different node in graph with name a gap> GraphvizEdges(g); [ ] @@ -153,3 +155,4 @@ gap> GraphvizAttrs(n); rec( color := "red" ) # +gap> STOP_TEST("graphviz package: edge.tst", 0); diff --git a/tst/examples/angles.tst b/tst/examples/angles.tst new file mode 100644 index 0000000..003d431 --- /dev/null +++ b/tst/examples/angles.tst @@ -0,0 +1,88 @@ +############################################################################# +## +## examples/angles.tst +## Copyright (C) 2024 James D. Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +# https://www.graphviz.org/Gallery/gradient/angles.html + +#@local cluster1, cluster2, g, node, pair, pairs +gap> START_TEST("graphviz package: examples/angles.tst"); +gap> LoadPackage("graphviz"); +true +gap> g := GraphvizDigraph("G"); + +gap> GraphvizSetAttr(g, "bgcolor", "blue"); + +gap> cluster1 := GraphvizAddSubgraph(g, "cluster_1"); + +gap> GraphvizSetAttr(cluster1, "fontcolor", "white"); + +gap> GraphvizSetAttr(cluster1, Concatenation("node[shape=circle, style=filled,", +> "fillcolor=\"white:black\", gradientangle=360, label=\"n9:n360\",", +> "fontcolor=black]")); + +gap> GraphvizAddNode(cluster1, "n9"); + +gap> pairs := ListN([8, 7 .. 1], [315, 270 .. 0], {x, y} -> [x, y]); +[ [ 8, 315 ], [ 7, 270 ], [ 6, 225 ], [ 5, 180 ], [ 4, 135 ], [ 3, 90 ], + [ 2, 45 ], [ 1, 0 ] ] +gap> for pair in pairs do +> node := GraphvizAddNode(cluster1, StringFormatted("n{}", pair[1])); +> GraphvizSetAttr(node, "gradientangle", StringFormatted("{}", pair[2])); +> GraphvizSetAttr(node, "label", +> StringFormatted("\"n{}:{}\"", pair[1], pair[2])); +> od; +gap> GraphvizSetAttr(cluster1, +> "label", +> "Linear Angle Variations (white to black gradient)"); + +gap> cluster2 := GraphvizAddSubgraph(g, "cluster_2"); + +gap> GraphvizSetAttr(cluster2, "fontcolor", "white"); + +gap> GraphvizSetAttr(cluster2, Concatenation("node[shape=circle, style=radial,", +> "fillcolor=\"white:black\", gradientangle=360,", +> "label=\"n9:n360\", fontcolor=black]")); + +gap> GraphvizAddNode(cluster2, "n18"); + +gap> pairs := ListN([17, 16 .. 10], [315, 270 .. 0], {x, y} -> [x, y]); +[ [ 17, 315 ], [ 16, 270 ], [ 15, 225 ], [ 14, 180 ], [ 13, 135 ], + [ 12, 90 ], [ 11, 45 ], [ 10, 0 ] ] +gap> for pair in pairs do +> node := GraphvizAddNode(cluster2, StringFormatted("n{}", pair[1])); +> GraphvizSetAttr(node, "gradientangle", StringFormatted("{}", pair[2])); +> GraphvizSetAttr(node, "label", StringFormatted("\"n{}:{}\"", +> pair[1], pair[2])); +> od; +gap> GraphvizSetAttr(cluster2, "label", +> "Radial Angle Variations (white to black gradient)"); + +gap> GraphvizAddEdge(g, "n5", "n14"); + +gap> AsString(g); +"//dot\ndigraph G {\n\tbgcolor=blue \nsubgraph cluster_1 {\n\tfontcolor=white \ +node[shape=circle, style=filled,fillcolor=\"white:black\", gradientangle=360, \ +label=\"n9:n360\",fontcolor=black] label=\"Linear Angle Variations (white to b\ +lack gradient)\" \n\tn9\n\tn8 [gradientangle=315, label=\"n8:315\"]\n\tn7 [gra\ +dientangle=270, label=\"n7:270\"]\n\tn6 [gradientangle=225, label=\"n6:225\"]\ +\n\tn5 [gradientangle=180, label=\"n5:180\"]\n\tn4 [gradientangle=135, label=\ +\"n4:135\"]\n\tn3 [gradientangle=90, label=\"n3:90\"]\n\tn2 [gradientangle=45,\ + label=\"n2:45\"]\n\tn1 [gradientangle=0, label=\"n1:0\"]\n}\nsubgraph cluster\ +_2 {\n\tfontcolor=white node[shape=circle, style=radial,fillcolor=\"white:blac\ +k\", gradientangle=360,label=\"n9:n360\", fontcolor=black] label=\"Radial Angl\ +e Variations (white to black gradient)\" \n\tn18\n\tn17 [gradientangle=315, la\ +bel=\"n17:315\"]\n\tn16 [gradientangle=270, label=\"n16:270\"]\n\tn15 [gradien\ +tangle=225, label=\"n15:225\"]\n\tn14 [gradientangle=180, label=\"n14:180\"]\n\ +\tn13 [gradientangle=135, label=\"n13:135\"]\n\tn12 [gradientangle=90, label=\ +\"n12:90\"]\n\tn11 [gradientangle=45, label=\"n11:45\"]\n\tn10 [gradientangle=\ +0, label=\"n10:0\"]\n}\n\tn5 -> n14\n}\n" + +# +gap> STOP_TEST("graphviz package: angles.tst"); diff --git a/tst/examples/btree.tst b/tst/examples/btree.tst new file mode 100644 index 0000000..89fc708 --- /dev/null +++ b/tst/examples/btree.tst @@ -0,0 +1,98 @@ +############################################################################# +## +## btree.tst +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +# https://graphviz.org/Gallery/directed/unix.html + +#@local s +gap> START_TEST("graphviz package: examples/btree.tst"); +gap> LoadPackage("graphviz"); +true + +# +gap> s := GraphvizDigraph("g"); + +gap> GraphvizSetAttr(s, "node [shape=record, height=.1]"); + +gap> GraphvizSetAttr(GraphvizAddNode(s, "node0"), "label", " | G|"); + +gap> GraphvizSetAttr(GraphvizAddNode(s, "node1"), "label", " | E|"); + +gap> GraphvizSetAttr(GraphvizAddNode(s, "node2"), "label", " | B|"); + +gap> GraphvizSetAttr(GraphvizAddNode(s, "node3"), "label", " | F|"); + +gap> GraphvizSetAttr(GraphvizAddNode(s, "node4"), "label", " | R|"); + +gap> GraphvizSetAttr(GraphvizAddNode(s, "node5"), "label", " | H|"); + +gap> GraphvizSetAttr(GraphvizAddNode(s, "node6"), "label", " | Y|"); + +gap> GraphvizSetAttr(GraphvizAddNode(s, "node7"), "label", " | A|"); + +gap> GraphvizSetAttr(GraphvizAddNode(s, "node8"), "label", " | C|"); + +gap> GraphvizAddEdge(s, "node0:f2", "node4:f1"); + +gap> GraphvizAddEdge(s, "node0:f0", "node1:f1"); + +gap> GraphvizAddEdge(s, "node1:f0", "node2:f1"); + +gap> GraphvizAddEdge(s, "node1:f2", "node3:f1"); + +gap> GraphvizAddEdge(s, "node2:f2", "node8:f1"); + +gap> GraphvizAddEdge(s, "node2:f0", "node7:f1"); + +gap> GraphvizAddEdge(s, "node4:f2", "node6:f1"); + +gap> GraphvizAddEdge(s, "node4:f0", "node5:f1"); + +gap> Print(AsString(s)); +//dot +digraph g { + node [shape=record, height=.1] + node0 [label=" | G|"] + node1 [label=" | E|"] + node2 [label=" | B|"] + node3 [label=" | F|"] + node4 [label=" | R|"] + node5 [label=" | H|"] + node6 [label=" | Y|"] + node7 [label=" | A|"] + node8 [label=" | C|"] + node0:f2 + node4:f1 + node0:f2 -> node4:f1 + node0:f0 + node1:f1 + node0:f0 -> node1:f1 + node1:f0 + node2:f1 + node1:f0 -> node2:f1 + node1:f2 + node3:f1 + node1:f2 -> node3:f1 + node2:f2 + node8:f1 + node2:f2 -> node8:f1 + node2:f0 + node7:f1 + node2:f0 -> node7:f1 + node4:f2 + node6:f1 + node4:f2 -> node6:f1 + node4:f0 + node5:f1 + node4:f0 -> node5:f1 +} + +# +gap> STOP_TEST("graphviz package: btree.tst"); diff --git a/tst/examples/cluster.tst b/tst/examples/cluster.tst new file mode 100644 index 0000000..323c3ba --- /dev/null +++ b/tst/examples/cluster.tst @@ -0,0 +1,113 @@ +############################################################################# +## +## cluster.tst +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html + +#@local cluster0, cluster1, graph +gap> START_TEST("graphviz package: examples/cluster.tst"); +gap> LoadPackage("graphviz"); +true +gap> graph := GraphvizDigraph("G"); + + +# +gap> cluster0 := GraphvizAddSubgraph(graph, "cluster_0"); + +gap> GraphvizSetAttr(cluster0, "color=\"lightgrey\""); + +gap> GraphvizSetAttr(cluster0, "style=\"filled\""); + +gap> GraphvizSetAttr(cluster0, "node [color=\"white\", style=\"filled\"]"); + +gap> GraphvizAddEdge(cluster0, "a0", "a1"); + +gap> GraphvizAddEdge(cluster0, "a1", "a2"); + +gap> GraphvizAddEdge(cluster0, "a2", "a3"); + +gap> GraphvizSetAttr(cluster0, "label=\"process #1\""); + + +# +gap> cluster1 := GraphvizAddSubgraph(graph, "cluster_1"); + +gap> GraphvizSetAttr(cluster1, "color=\"blue\""); + +gap> GraphvizSetAttr(cluster1, "node [style=\"filled\"]"); + +gap> GraphvizAddEdge(cluster1, "b0", "b1"); + +gap> GraphvizAddEdge(cluster1, "b1", "b2"); + +gap> GraphvizAddEdge(cluster1, "b2", "b3"); + +gap> GraphvizSetAttr(cluster1, "label=\"process #2\""); + + +# +gap> GraphvizAddEdge(graph, "start", "a0"); + +gap> GraphvizAddEdge(graph, "start", "b0"); + +gap> GraphvizAddEdge(graph, "a1", "b3"); + +gap> GraphvizAddEdge(graph, "b2", "a3"); + +gap> GraphvizAddEdge(graph, "a3", "a0"); + +gap> GraphvizAddEdge(graph, "a3", "end"); + +gap> GraphvizAddEdge(graph, "b3", "end"); + + +# +gap> GraphvizSetAttr(graph["start"], "shape", "Mdiamond"); + +gap> GraphvizSetAttr(graph["end"], "shape", "Msquare"); + + +# +gap> Print(AsString(graph)); +//dot +digraph G { +subgraph cluster_0 { + color="lightgrey" style="filled" node [color="white", style="filled"] label="\ +process #1" + a0 + a1 + a0 -> a1 + a2 + a1 -> a2 + a3 + a2 -> a3 +} +subgraph cluster_1 { + color="blue" node [style="filled"] label="process #2" + b0 + b1 + b0 -> b1 + b2 + b1 -> b2 + b3 + b2 -> b3 +} + start [shape=Mdiamond] + start -> a0 + start -> b0 + a1 -> b3 + b2 -> a3 + a3 -> a0 + end [shape=Msquare] + a3 -> end + b3 -> end +} + +# +gap> STOP_TEST("graphviz package: cluster.tst"); diff --git a/tst/examples/cluster_edge.tst b/tst/examples/cluster_edge.tst new file mode 100644 index 0000000..8e426ee --- /dev/null +++ b/tst/examples/cluster_edge.tst @@ -0,0 +1,86 @@ +############################################################################# +## +## cluster_edge.tst +## Copyright (C) 2024 James D. Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +# https://www.graphviz.org/pdf/dotguide.pdf, Figure 20 + +#@local cluster0, cluster1, e, g +gap> START_TEST("graphviz package: examples/cluster_edge.tst"); +gap> LoadPackage("graphviz"); +true + +# +gap> g := GraphvizDigraph("G"); + +gap> GraphvizSetAttr(g, "compound=true"); + +gap> cluster0 := GraphvizAddSubgraph(g, "cluster0"); + +gap> GraphvizAddEdge(cluster0, "a", "b"); + +gap> GraphvizAddEdge(cluster0, "a", "c"); + +gap> GraphvizAddEdge(cluster0, "b", "d"); + +gap> GraphvizAddEdge(cluster0, "c", "d"); + +gap> cluster1 := GraphvizAddSubgraph(g, "cluster1"); + +gap> GraphvizAddEdge(cluster1, "e", "g"); + +gap> GraphvizAddEdge(cluster1, "e", "f"); + +gap> GraphvizSetAttr(GraphvizAddEdge(g, "b", "f"), "lhead", "cluster1"); + +gap> GraphvizAddEdge(g, "d", "e"); + +gap> e := GraphvizAddEdge(g, "c", "g"); + +gap> GraphvizSetAttr(e, "ltail", "cluster0"); + +gap> GraphvizSetAttr(e, "lhead", "cluster1"); + +gap> e := GraphvizAddEdge(g, "c", "e"); + +gap> GraphvizSetAttr(e, "ltail", "cluster0"); + +gap> GraphvizAddEdge(g, "d", "h"); + +gap> Print(AsString(g)); +//dot +digraph G { + compound=true +subgraph cluster0 { + a + b + a -> b + c + a -> c + d + b -> d + c -> d +} +subgraph cluster1 { + e + g + e -> g + f + e -> f +} + b -> f [lhead=cluster1] + d -> e + c -> g [lhead=cluster1, ltail=cluster0] + c -> e [ltail=cluster0] + h + d -> h +} + +# +gap> STOP_TEST("graphviz package: cluster_edge.tst"); diff --git a/tst/examples/colors.tst b/tst/examples/colors.tst new file mode 100644 index 0000000..6751064 --- /dev/null +++ b/tst/examples/colors.tst @@ -0,0 +1,71 @@ +############################################################################# +## +## colors.tst +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +# https://graphviz.org/docs/attr-types/color + + +#@local g, node +gap> START_TEST("graphviz package: examples/colors.tst"); +gap> LoadPackage("graphviz"); +true + +# +gap> g := GraphvizGraph(); + + +# +gap> node := GraphvizAddNode(g, "RGB: #40e0d0"); + +gap> GraphvizSetAttr(node, "style", "filled"); + +gap> GraphvizSetAttr(node, "fillcolor", "\"#40e0d0\""); + + +# +gap> node := GraphvizAddNode(g, "RGBA: #ff000042"); + +gap> GraphvizSetAttr(node, "style", "filled"); + +gap> GraphvizSetAttr(node, "fillcolor", "\"#ff000042\""); + + +# +gap> node := GraphvizAddNode(g, "HSV: 0.051 0.718 0.627"); + +gap> GraphvizSetAttr(node, "style", "filled"); + +gap> GraphvizSetAttr(node, "fillcolor", "0.051 0.718 0.627"); + + +# +gap> node := GraphvizAddNode(g, "name: deeppink"); + +gap> GraphvizSetAttr(node, "style", "filled"); + +gap> GraphvizSetAttr(node, "fillcolor", "deeppink"); + + +# +gap> Print(AsString(g)); +#I invalid node name RGB: #40e0d0 using "RGB: #40e0d0" instead +#I invalid node name RGBA: #ff000042 using "RGBA: #ff000042" instead +#I invalid node name HSV: 0.051 0.718 0.627 using "HSV: 0.051 0.718 0.627" instead +#I invalid node name name: deeppink using "name: deeppink" instead +//dot +graph { + "RGB: #40e0d0" [fillcolor="#40e0d0", style=filled] + "RGBA: #ff000042" [fillcolor="#ff000042", style=filled] + "HSV: 0.051 0.718 0.627" [fillcolor="0.051 0.718 0.627", style=filled] + "name: deeppink" [fillcolor=deeppink, style=filled] +} + +# +gap> STOP_TEST("graphviz package: colors.tst"); diff --git a/tst/examples/er.tst b/tst/examples/er.tst new file mode 100644 index 0000000..f784fb5 --- /dev/null +++ b/tst/examples/er.tst @@ -0,0 +1,161 @@ +############################################################################# +## +## er.tst +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +# https://graphviz.org/Gallery/undirected/ER.html + +#@local context1, context2, e, label, len, start +gap> START_TEST("graphviz package: examples/er.tst"); +gap> LoadPackage("graphviz"); +true +gap> e := GraphvizGraph("ER"); + +gap> GraphvizSetAttr(e, "engine=\"neato\""); + + +# +gap> start := GraphvizAddContext(e, "context_start"); + +gap> GraphvizSetAttr(start, "node[shape=\"box\"]"); + +gap> GraphvizAddNode(start, "course"); + +gap> GraphvizAddNode(start, "institute"); + +gap> GraphvizAddNode(start, "student"); + + +# +gap> context1 := GraphvizAddContext(e, "context1"); + +gap> GraphvizSetAttr(context1, "node [shape=\"ellipse\"]"); + +gap> GraphvizSetAttr(GraphvizAddNode(context1, "name0"), "label", "name"); + +gap> GraphvizSetAttr(GraphvizAddNode(context1, "name1"), "label", "name"); + +gap> GraphvizSetAttr(GraphvizAddNode(context1, "name2"), "label", "name"); + +gap> GraphvizAddNode(context1, "code"); + +gap> GraphvizAddNode(context1, "grade"); + +gap> GraphvizAddNode(context1, "number"); + + +# +gap> context2 := GraphvizAddContext(e, "context2"); + +gap> GraphvizSetAttr(context2, +> "node [shape=\"diamond\", style=\"filled\", color=\"lightgrey\"]"); + +gap> GraphvizAddNode(context2, "C-I"); + +gap> GraphvizAddNode(context2, "S-C"); + +gap> GraphvizAddNode(context2, "S-I"); + + +# +gap> GraphvizAddEdge(e, "name0", "course"); + +gap> GraphvizAddEdge(e, "code", "course"); + +gap> GraphvizSetAttrs(GraphvizAddEdge(e, "C-I", "course"), +> rec(label := "n", len := "1.00")); + +gap> GraphvizSetAttrs(GraphvizAddEdge(e, "institute", "C-I"), +> rec(label := "1", len := "1.00")); + +gap> GraphvizAddEdge(e, "name1", "institute"); + +gap> GraphvizSetAttrs(GraphvizAddEdge(e, "S-I", "institute"), +> rec(label := "1", len := "1.00")); + +gap> GraphvizSetAttrs(GraphvizAddEdge(e, "student", "S-I"), +> rec(label := "n", len := "1.00")); + +gap> GraphvizAddEdge(e, "grade", "student"); + +gap> GraphvizAddEdge(e, "name2", "student"); + +gap> GraphvizAddEdge(e, "number", "student"); + +gap> GraphvizSetAttrs(GraphvizAddEdge(e, "S-C", "student"), +> rec(label := "m", len := "1.00")); + +gap> GraphvizSetAttrs(GraphvizAddEdge(e, "course", "S-C"), +> rec(label := "n", len := "1.00")); + + +# +gap> GraphvizSetAttr(e, "label=\"Entity Relation Diagram\ndrawn by NEATO\""); + +gap> GraphvizSetAttr(e, "fontsize=\"20\""); + + +# +gap> Print(AsString(e)); +#I invalid node name C-I using "C-I" instead +#I invalid node name S-C using "S-C" instead +#I invalid node name S-I using "S-I" instead +#I invalid node name C-I using "C-I" instead +#I invalid node name C-I using "C-I" instead +#I invalid node name S-I using "S-I" instead +#I invalid node name S-I using "S-I" instead +#I invalid node name S-C using "S-C" instead +#I invalid node name S-C using "S-C" instead +//dot +graph ER { + engine="neato" label="Entity Relation Diagram +drawn by NEATO" fontsize="20" +// context_start context + node[shape="box"] + course + institute + student + engine="neato" label="Entity Relation Diagram +drawn by NEATO" fontsize="20" + +// context1 context + node [shape="ellipse"] + name0 [label=name] + name1 [label=name] + name2 [label=name] + code + grade + number + engine="neato" label="Entity Relation Diagram +drawn by NEATO" fontsize="20" + +// context2 context + node [shape="diamond", style="filled", color="lightgrey"] + "C-I" + "S-C" + "S-I" + engine="neato" label="Entity Relation Diagram +drawn by NEATO" fontsize="20" + + name0 -- course + code -- course + "C-I" -- course [label=n, len=1.00] + institute -- "C-I" [label=1, len=1.00] + name1 -- institute + "S-I" -- institute [label=1, len=1.00] + student -- "S-I" [label=n, len=1.00] + grade -- student + name2 -- student + number -- student + "S-C" -- student [label=m, len=1.00] + course -- "S-C" [label=n, len=1.00] +} + +# +gap> STOP_TEST("graphviz package: er.tst"); diff --git a/tst/examples/fsm.tst b/tst/examples/fsm.tst new file mode 100644 index 0000000..19d3023 --- /dev/null +++ b/tst/examples/fsm.tst @@ -0,0 +1,114 @@ +############################################################################# +## +## fsm.tst +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +# https://graphviz.org/Gallery/directed/fsm.html + +#@local f, nodes, terminals +gap> START_TEST("graphviz package: examples/fsm.tst"); +gap> LoadPackage("graphviz"); +true + +# +gap> f := GraphvizDigraph("finite_state_machine"); + +gap> GraphvizSetAttr(f, "rankdir=LR"); + +gap> GraphvizSetAttr(f, "size=\"8,5\""); + + +# +gap> terminals := GraphvizAddContext(f, "terminals"); + +gap> GraphvizSetAttr(terminals, "node [shape=doublecircle]"); + +gap> GraphvizAddNode(terminals, "LR_0"); + +gap> GraphvizAddNode(terminals, "LR_3"); + +gap> GraphvizAddNode(terminals, "LR_4"); + +gap> GraphvizAddNode(terminals, "LR_8"); + + +# +gap> nodes := GraphvizAddContext(f, "nodes"); + +gap> GraphvizSetAttr(nodes, "node [shape=circle]"); + +gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_0", "LR_2"), "label", "\"SS(B)\""); + +gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_0", "LR_1"), "label", "\"SS(S)\""); + +gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_1", "LR_3"), "label", "\"S($end)\""); + +gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_2", "LR_6"), "label", "\"SS(b)\""); + +gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_2", "LR_5"), "label", "\"SS(a)\""); + +gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_2", "LR_4"), "label", "\"S(A)\""); + +gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_5", "LR_7"), "label", "\"S(b)\""); + +gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_5", "LR_5"), "label", "\"S(a)\""); + +gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_6", "LR_6"), "label", "\"S(b)\""); + +gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_6", "LR_5"), "label", "\"S(a)\""); + +gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_7", "LR_8"), "label", "\"S(b)\""); + +gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_7", "LR_5"), "label", "\"S(a)\""); + +gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_8", "LR_6"), "label", "\"S(b)\""); + +gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_8", "LR_5"), "label", "\"S(a)\""); + + +# +gap> Print(AsString(f)); +//dot +digraph finite_state_machine { + rankdir=LR size="8,5" +// terminals context + node [shape=doublecircle] + LR_0 + LR_3 + LR_4 + LR_8 + rankdir=LR size="8,5" + +// nodes context + node [shape=circle] + LR_2 + LR_0 -> LR_2 [label="SS(B)"] + LR_1 + LR_0 -> LR_1 [label="SS(S)"] + LR_1 -> LR_3 [label="S($end)"] + LR_6 + LR_2 -> LR_6 [label="SS(b)"] + LR_5 + LR_2 -> LR_5 [label="SS(a)"] + LR_2 -> LR_4 [label="S(A)"] + LR_7 + LR_5 -> LR_7 [label="S(b)"] + LR_5 -> LR_5 [label="S(a)"] + LR_6 -> LR_6 [label="S(b)"] + LR_6 -> LR_5 [label="S(a)"] + LR_7 -> LR_8 [label="S(b)"] + LR_7 -> LR_5 [label="S(a)"] + LR_8 -> LR_6 [label="S(b)"] + LR_8 -> LR_5 [label="S(a)"] + rankdir=LR size="8,5" + +} + +# +gap> STOP_TEST("graphviz package: fsm.tst"); diff --git a/tst/examples/g_c_n.tst b/tst/examples/g_c_n.tst new file mode 100644 index 0000000..e8e6f41 --- /dev/null +++ b/tst/examples/g_c_n.tst @@ -0,0 +1,52 @@ +############################################################################# +## +## g_c_n.tst +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +# https://www.graphviz.org/Gallery/gradient/g_c_n.html + +#@local cluster1, g +gap> START_TEST("graphviz package: examples/g_c_n.tst"); +gap> LoadPackage("graphviz"); +true + +# +gap> g := GraphvizGraph("G"); + +gap> GraphvizSetAttr(g, +> "bgcolor=\"purple:pink\" label=\"agraph\" fontcolor=\"white\""); + +gap> cluster1 := GraphvizAddSubgraph(g, "cluster1"); + +gap> GraphvizSetAttr(cluster1, Concatenation( +> "fillcolor=\"blue:cyan\" label=\"acluster\" fontcolor=\"white\"", +> "style=\"filled\" gradientangle=270\n")); + +gap> GraphvizSetAttr(cluster1, Concatenation( +> "node [shape=box, fillcolor=\"red:yellow\",", +> " style=\"filled\", gradientangle=90]")); + +gap> GraphvizAddNode(cluster1, "anode"); + + +# +gap> Print(AsString(g)); +//dot +graph G { + bgcolor="purple:pink" label="agraph" fontcolor="white" +subgraph cluster1 { + fillcolor="blue:cyan" label="acluster" fontcolor="white"style="filled" gradie\ +ntangle=270 + node [shape=box, fillcolor="red:yellow", style="filled", gradientangle=90] + anode +} +} + +# +gap> STOP_TEST("graphviz package: g_c_n.tst"); diff --git a/tst/examples/hello.tst b/tst/examples/hello.tst new file mode 100644 index 0000000..e8e3f4e --- /dev/null +++ b/tst/examples/hello.tst @@ -0,0 +1,32 @@ +############################################################################# +## +## hello.tst +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html + +#@local graph +gap> START_TEST("graphviz package: examples/hello.tst"); +gap> LoadPackage("graphviz"); +true + +# +gap> graph := GraphvizDigraph("G"); + +gap> GraphvizAddEdge(graph, "hello", "world"); + +gap> Print(AsString(graph)); +//dot +digraph G { + hello + world + hello -> world +} + +# +gap> STOP_TEST("graphviz package: hello.tst"); diff --git a/tst/examples/process.tst b/tst/examples/process.tst new file mode 100644 index 0000000..18f0524 --- /dev/null +++ b/tst/examples/process.tst @@ -0,0 +1,79 @@ +############################################################################# +## +## process.tst +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html + + +#@local graph +gap> START_TEST("graphviz package: examples/process.tst"); +gap> LoadPackage("graphviz"); +true + +# +gap> graph := GraphvizGraph("G"); + +gap> GraphvizSetAttr(graph, "engine=\"sfdp\""); + + +# +gap> GraphvizAddEdge(graph, "run", "intr"); + +gap> GraphvizAddEdge(graph, "intr", "runbl"); + +gap> GraphvizAddEdge(graph, "runbl", "run"); + +gap> GraphvizAddEdge(graph, "run", "kernel"); + +gap> GraphvizAddEdge(graph, "kernel", "zombie"); + +gap> GraphvizAddEdge(graph, "kernel", "sleep"); + +gap> GraphvizAddEdge(graph, "kernel", "runmem"); + +gap> GraphvizAddEdge(graph, "sleep", "swap"); + +gap> GraphvizAddEdge(graph, "swap", "runswap"); + +gap> GraphvizAddEdge(graph, "runswap", "new"); + +gap> GraphvizAddEdge(graph, "runswap", "runmem"); + +gap> GraphvizAddEdge(graph, "new", "runmem"); + +gap> Print(AsString(graph)); +//dot +graph G { + engine="sfdp" + run + intr + run -- intr + runbl + intr -- runbl + runbl -- run + kernel + run -- kernel + zombie + kernel -- zombie + sleep + kernel -- sleep + runmem + kernel -- runmem + swap + sleep -- swap + runswap + swap -- runswap + new + runswap -- new + runswap -- runmem + new -- runmem +} + +# +gap> STOP_TEST("graphviz package: process.tst"); diff --git a/tst/examples/rank_same.tst b/tst/examples/rank_same.tst new file mode 100644 index 0000000..611c2b0 --- /dev/null +++ b/tst/examples/rank_same.tst @@ -0,0 +1,83 @@ +############################################################################# +## +## rank_same.tst +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +# https://stackoverflow.com/questions/25734244 + + +#@local g, s1, s2 +gap> START_TEST("graphviz package: examples/rank_same.tst"); +gap> LoadPackage("graphviz"); +true + +# +gap> g := GraphvizDigraph(); + + +# +gap> s1 := GraphvizAddSubgraph(g); + +gap> GraphvizSetAttr(s1, "rank=same"); + +gap> GraphvizAddNode(s1, "A"); + +gap> GraphvizAddNode(s1, "X"); + + +# +gap> GraphvizAddNode(g, "C"); + + +# +gap> s2 := GraphvizAddSubgraph(g); + +gap> GraphvizSetAttr(s2, "rank=same"); + +gap> GraphvizAddNode(s2, "B"); + +gap> GraphvizAddNode(s2, "D"); + +gap> GraphvizAddNode(s2, "Y"); + + +# +gap> GraphvizAddEdge(g, "A", "B"); + +gap> GraphvizAddEdge(g, "A", "C"); + +gap> GraphvizAddEdge(g, "C", "D"); + +gap> GraphvizAddEdge(g, "X", "Y"); + + +# +gap> Print(AsString(g)); +//dot +digraph { +subgraph no_name_1 { + rank=same + A + X +} + C +subgraph no_name_3 { + rank=same + B + D + Y +} + A -> B + A -> C + C -> D + X -> Y +} + +# +gap> STOP_TEST("graphviz package: rank_same.tst"); diff --git a/tst/examples/structs.tst b/tst/examples/structs.tst new file mode 100644 index 0000000..d979d25 --- /dev/null +++ b/tst/examples/structs.tst @@ -0,0 +1,108 @@ +############################################################################# +## +## structs.tst +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +# https://graphviz.org/Gallery/directed/unix.html + +#@local s +gap> START_TEST("graphviz package: examples/structs.tst"); +gap> LoadPackage("graphviz"); +true +gap> s := GraphvizDigraph("structs"); + +gap> GraphvizSetAttr(s, "node [shape=\"plaintext\"]"); + + +# +gap> GraphvizSetAttr(GraphvizAddNode(s, "struct1"), "label", +> """< +> +> +> +> +>
leftmiddleright
>"""); + +gap> GraphvizSetAttr(GraphvizAddNode(s, "struct2"), "label", +> """< +> +> +> +> +>
onetwo
>"""); + +gap> GraphvizSetAttr(GraphvizAddNode(s, "struct3"), "label", +> """< +> +> +> +> +> +> +> +> +> +> +> +> +> +> +>
hello
world
bgh
cde
f
>"""); + + +# +gap> GraphvizAddEdge(s, "struct1:f1", "struct2:f0"); + +gap> GraphvizAddEdge(s, "struct1:f2", "struct3:here"); + + +# +gap> Print(AsString(s)); +//dot +digraph structs { + node [shape="plaintext"] + struct1 [label=< + + + + +
leftmiddleright
>] + struct2 [label=< + + + + +
onetwo
>] + struct3 [label=< + + + + + + + + + + + + + + +
hello
world
bgh
cde
f
>] + struct1:f1 + struct2:f0 + struct1:f1 -> struct2:f0 + struct1:f2 + struct3:here + struct1:f2 -> struct3:here +} + +# +gap> STOP_TEST("graphviz package: structs.tst"); diff --git a/tst/examples/traffic_lights.tst b/tst/examples/traffic_lights.tst new file mode 100644 index 0000000..a5ad65e --- /dev/null +++ b/tst/examples/traffic_lights.tst @@ -0,0 +1,127 @@ +############################################################################# +## +## traffic_lights.tst +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +# https://graphviz.org/Gallery/directed/unix.html + +#@local ctx1, ctx2, i, j, pair, t +gap> START_TEST("graphviz package: examples/traffic_lights.tst"); +gap> LoadPackage("graphviz"); +true +gap> t := GraphvizDigraph("TrafficLights"); + +gap> GraphvizSetAttr(t, "engine=neato"); + + +# +gap> ctx1 := GraphvizAddSubgraph(t, "ctx1"); + +gap> GraphvizSetAttr(ctx1, "node [shape=\"box\"]"); + +gap> for i in [2, 1] do +> GraphvizAddNode(ctx1, StringFormatted("gy{}", i)); +> GraphvizAddNode(ctx1, StringFormatted("yr{}", i)); +> GraphvizAddNode(ctx1, StringFormatted("rg{}", i)); +> od; + +# +gap> ctx2 := GraphvizAddSubgraph(t, "ctx2"); + +gap> GraphvizSetAttr(ctx2, "node [shape=\"circle\", fixedsize=true, width=0.9]"); + +gap> for i in [2, 1] do +> GraphvizAddNode(ctx2, StringFormatted("green{}", i)); +> GraphvizAddNode(ctx2, StringFormatted("yellow{}", i)); +> GraphvizAddNode(ctx2, StringFormatted("red{}", i)); +> GraphvizAddNode(ctx2, StringFormatted("safe{}", i)); +> od; + +# +gap> pair := fail; +fail +gap> for pair in [[2, 1], [1, 2]] do +> i := pair[1]; +> j := pair[2]; +> GraphvizAddEdge( +> t, StringFormatted("gy{}", i), StringFormatted("yellow{}", i)); +> GraphvizAddEdge( +> t, StringFormatted("rg{}", i), StringFormatted("green{}", i)); +> GraphvizAddEdge( +> t, StringFormatted("yr{}", i), StringFormatted("safe{}", j)); +> GraphvizAddEdge( +> t, StringFormatted("yr{}", i), StringFormatted("red{}", i)); +> GraphvizAddEdge( +> t, StringFormatted("safe{}", i), StringFormatted("rg{}", i)); +> GraphvizAddEdge( +> t, StringFormatted("green{}", i), StringFormatted("gy{}", i)); +> GraphvizAddEdge( +> t, StringFormatted("yellow{}", i), StringFormatted("yr{}", i)); +> GraphvizAddEdge( +> t, StringFormatted("red{}", i), StringFormatted("rg{}", i)); +> od; + +# +gap> GraphvizSetAttr(t, "overlap=\"false\""); + +gap> GraphvizSetAttr(t, +> """label="PetriNet Model TrafficLights +> Extracted from ConceptBase and laid out by Graphviz" +> """); + +gap> GraphvizSetAttr(t, "fontsize=12"); + + +# +gap> Print(AsString(t)); +//dot +digraph TrafficLights { + engine=neato overlap="false" label="PetriNet Model TrafficLights +Extracted from ConceptBase and laid out by Graphviz" + fontsize=12 +subgraph ctx1 { + node [shape="box"] + gy2 + yr2 + rg2 + gy1 + yr1 + rg1 +} +subgraph ctx2 { + node [shape="circle", fixedsize=true, width=0.9] + green2 + yellow2 + red2 + safe2 + green1 + yellow1 + red1 + safe1 +} + gy2 -> yellow2 + rg2 -> green2 + yr2 -> safe1 + yr2 -> red2 + safe2 -> rg2 + green2 -> gy2 + yellow2 -> yr2 + red2 -> rg2 + gy1 -> yellow1 + rg1 -> green1 + yr1 -> safe2 + yr1 -> red1 + safe1 -> rg1 + green1 -> gy1 + yellow1 -> yr1 + red1 -> rg1 +} + +# +gap> STOP_TEST("graphviz package: traffic_lights.tst"); diff --git a/tst/examples/unix.tst b/tst/examples/unix.tst new file mode 100644 index 0000000..aad2786 --- /dev/null +++ b/tst/examples/unix.tst @@ -0,0 +1,349 @@ +############################################################################# +## +## unix.tst +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# https://graphviz.readthedocs.io/en/stable/examples.html +# https://graphviz.org/Gallery/directed/unix.html + +#@local u +gap> START_TEST("graphviz package: examples/unix.tst"); +gap> LoadPackage("graphviz"); +true + +# +gap> u := GraphvizDigraph("unix"); + +gap> GraphvizSetAttr( +> u, "node [color=\"lightblue2\", style=\"filled\", size=\"6,6\"]"); + + +# +gap> GraphvizAddEdge(u, "5th Edition", "6th Edition"); + +gap> GraphvizAddEdge(u, "5th Edition", "PWB 1.0"); + +gap> GraphvizAddEdge(u, "6th Edition", "LSX"); + +gap> GraphvizAddEdge(u, "6th Edition", "1 BSD"); + +gap> GraphvizAddEdge(u, "6th Edition", "Mini Unix"); + +gap> GraphvizAddEdge(u, "6th Edition", "Wollongong"); + +gap> GraphvizAddEdge(u, "6th Edition", "Interdata"); + +gap> GraphvizAddEdge(u, "Unix/TS 3.0", "Interdata"); + +gap> GraphvizAddEdge(u, "Interdata", "PWB 2.0"); + +gap> GraphvizAddEdge(u, "Interdata", "7th Edition"); + +gap> GraphvizAddEdge(u, "7th Edition", "8th Edition"); + +gap> GraphvizAddEdge(u, "7th Edition", "32V"); + +gap> GraphvizAddEdge(u, "7th Edition", "V7M"); + +gap> GraphvizAddEdge(u, "7th Edition", "Ultrix-11"); + +gap> GraphvizAddEdge(u, "7th Edition", "Xenix"); + +gap> GraphvizAddEdge(u, "7th Edition", "UniPlus+"); + +gap> GraphvizAddEdge(u, "V7M", "Ultrix-11"); + +gap> GraphvizAddEdge(u, "8th Edition", "9th Edition"); + +gap> GraphvizAddEdge(u, "1 BSD", "2 BSD"); + +gap> GraphvizAddEdge(u, "2 BSD", "2.8 BSD"); + +gap> GraphvizAddEdge(u, "2.8 BSD", "Ultrix-11"); + +gap> GraphvizAddEdge(u, "2.8 BSD", "2.9 BSD"); + +gap> GraphvizAddEdge(u, "32V", "3 BSD"); + +gap> GraphvizAddEdge(u, "3 BSD", "4 BSD"); + +gap> GraphvizAddEdge(u, "4 BSD", "4.1 BSD"); + +gap> GraphvizAddEdge(u, "4.1 BSD", "4.2 BSD"); + +gap> GraphvizAddEdge(u, "4.1 BSD", "2.8 BSD"); + +gap> GraphvizAddEdge(u, "4.1 BSD", "8th Edition"); + +gap> GraphvizAddEdge(u, "4.2 BSD", "4.3 BSD"); + +gap> GraphvizAddEdge(u, "4.2 BSD", "Ultrix-32"); + +gap> GraphvizAddEdge(u, "PWB 1.0", "PWB 1.2"); + +gap> GraphvizAddEdge(u, "PWB 1.0", "USG 1.0"); + +gap> GraphvizAddEdge(u, "PWB 1.2", "PWB 2.0"); + +gap> GraphvizAddEdge(u, "USG 1.0", "CB Unix 1"); + +gap> GraphvizAddEdge(u, "USG 1.0", "USG 2.0"); + +gap> GraphvizAddEdge(u, "CB Unix 1", "CB Unix 2"); + +gap> GraphvizAddEdge(u, "CB Unix 2", "CB Unix 3"); + +gap> GraphvizAddEdge(u, "CB Unix 3", "Unix/TS++"); + +gap> GraphvizAddEdge(u, "CB Unix 3", "PDP-11 Sys V"); + +gap> GraphvizAddEdge(u, "USG 2.0", "USG 3.0"); + +gap> GraphvizAddEdge(u, "USG 3.0", "Unix/TS 3.0"); + +gap> GraphvizAddEdge(u, "PWB 2.0", "Unix/TS 3.0"); + +gap> GraphvizAddEdge(u, "Unix/TS 1.0", "Unix/TS 3.0"); + +gap> GraphvizAddEdge(u, "Unix/TS 3.0", "TS 4.0"); + +gap> GraphvizAddEdge(u, "Unix/TS++", "TS 4.0"); + +gap> GraphvizAddEdge(u, "CB Unix 3", "TS 4.0"); + +gap> GraphvizAddEdge(u, "TS 4.0", "System V.0"); + +gap> GraphvizAddEdge(u, "System V.0", "System V.2"); + +gap> GraphvizAddEdge(u, "System V.2", "System V.3"); + + +# +gap> Print(AsString(u)); +#I invalid node name 5th Edition using "5th Edition" instead +#I invalid node name 6th Edition using "6th Edition" instead +#I invalid node name 5th Edition using "5th Edition" instead +#I invalid node name 6th Edition using "6th Edition" instead +#I invalid node name PWB 1.0 using "PWB 1.0" instead +#I invalid node name 5th Edition using "5th Edition" instead +#I invalid node name PWB 1.0 using "PWB 1.0" instead +#I invalid node name 6th Edition using "6th Edition" instead +#I invalid node name 1 BSD using "1 BSD" instead +#I invalid node name 6th Edition using "6th Edition" instead +#I invalid node name 1 BSD using "1 BSD" instead +#I invalid node name Mini Unix using "Mini Unix" instead +#I invalid node name 6th Edition using "6th Edition" instead +#I invalid node name Mini Unix using "Mini Unix" instead +#I invalid node name 6th Edition using "6th Edition" instead +#I invalid node name 6th Edition using "6th Edition" instead +#I invalid node name Unix/TS 3.0 using "Unix/TS 3.0" instead +#I invalid node name Unix/TS 3.0 using "Unix/TS 3.0" instead +#I invalid node name PWB 2.0 using "PWB 2.0" instead +#I invalid node name PWB 2.0 using "PWB 2.0" instead +#I invalid node name 7th Edition using "7th Edition" instead +#I invalid node name 7th Edition using "7th Edition" instead +#I invalid node name 8th Edition using "8th Edition" instead +#I invalid node name 7th Edition using "7th Edition" instead +#I invalid node name 8th Edition using "8th Edition" instead +#I invalid node name 32V using "32V" instead +#I invalid node name 7th Edition using "7th Edition" instead +#I invalid node name 32V using "32V" instead +#I invalid node name 7th Edition using "7th Edition" instead +#I invalid node name Ultrix-11 using "Ultrix-11" instead +#I invalid node name 7th Edition using "7th Edition" instead +#I invalid node name Ultrix-11 using "Ultrix-11" instead +#I invalid node name 7th Edition using "7th Edition" instead +#I invalid node name UniPlus+ using "UniPlus+" instead +#I invalid node name 7th Edition using "7th Edition" instead +#I invalid node name UniPlus+ using "UniPlus+" instead +#I invalid node name Ultrix-11 using "Ultrix-11" instead +#I invalid node name 9th Edition using "9th Edition" instead +#I invalid node name 8th Edition using "8th Edition" instead +#I invalid node name 9th Edition using "9th Edition" instead +#I invalid node name 2 BSD using "2 BSD" instead +#I invalid node name 1 BSD using "1 BSD" instead +#I invalid node name 2 BSD using "2 BSD" instead +#I invalid node name 2.8 BSD using "2.8 BSD" instead +#I invalid node name 2 BSD using "2 BSD" instead +#I invalid node name 2.8 BSD using "2.8 BSD" instead +#I invalid node name 2.8 BSD using "2.8 BSD" instead +#I invalid node name Ultrix-11 using "Ultrix-11" instead +#I invalid node name 2.9 BSD using "2.9 BSD" instead +#I invalid node name 2.8 BSD using "2.8 BSD" instead +#I invalid node name 2.9 BSD using "2.9 BSD" instead +#I invalid node name 3 BSD using "3 BSD" instead +#I invalid node name 32V using "32V" instead +#I invalid node name 3 BSD using "3 BSD" instead +#I invalid node name 4 BSD using "4 BSD" instead +#I invalid node name 3 BSD using "3 BSD" instead +#I invalid node name 4 BSD using "4 BSD" instead +#I invalid node name 4.1 BSD using "4.1 BSD" instead +#I invalid node name 4 BSD using "4 BSD" instead +#I invalid node name 4.1 BSD using "4.1 BSD" instead +#I invalid node name 4.2 BSD using "4.2 BSD" instead +#I invalid node name 4.1 BSD using "4.1 BSD" instead +#I invalid node name 4.2 BSD using "4.2 BSD" instead +#I invalid node name 4.1 BSD using "4.1 BSD" instead +#I invalid node name 2.8 BSD using "2.8 BSD" instead +#I invalid node name 4.1 BSD using "4.1 BSD" instead +#I invalid node name 8th Edition using "8th Edition" instead +#I invalid node name 4.3 BSD using "4.3 BSD" instead +#I invalid node name 4.2 BSD using "4.2 BSD" instead +#I invalid node name 4.3 BSD using "4.3 BSD" instead +#I invalid node name Ultrix-32 using "Ultrix-32" instead +#I invalid node name 4.2 BSD using "4.2 BSD" instead +#I invalid node name Ultrix-32 using "Ultrix-32" instead +#I invalid node name PWB 1.2 using "PWB 1.2" instead +#I invalid node name PWB 1.0 using "PWB 1.0" instead +#I invalid node name PWB 1.2 using "PWB 1.2" instead +#I invalid node name USG 1.0 using "USG 1.0" instead +#I invalid node name PWB 1.0 using "PWB 1.0" instead +#I invalid node name USG 1.0 using "USG 1.0" instead +#I invalid node name PWB 1.2 using "PWB 1.2" instead +#I invalid node name PWB 2.0 using "PWB 2.0" instead +#I invalid node name CB Unix 1 using "CB Unix 1" instead +#I invalid node name USG 1.0 using "USG 1.0" instead +#I invalid node name CB Unix 1 using "CB Unix 1" instead +#I invalid node name USG 2.0 using "USG 2.0" instead +#I invalid node name USG 1.0 using "USG 1.0" instead +#I invalid node name USG 2.0 using "USG 2.0" instead +#I invalid node name CB Unix 2 using "CB Unix 2" instead +#I invalid node name CB Unix 1 using "CB Unix 1" instead +#I invalid node name CB Unix 2 using "CB Unix 2" instead +#I invalid node name CB Unix 3 using "CB Unix 3" instead +#I invalid node name CB Unix 2 using "CB Unix 2" instead +#I invalid node name CB Unix 3 using "CB Unix 3" instead +#I invalid node name Unix/TS++ using "Unix/TS++" instead +#I invalid node name CB Unix 3 using "CB Unix 3" instead +#I invalid node name Unix/TS++ using "Unix/TS++" instead +#I invalid node name PDP-11 Sys V using "PDP-11 Sys V" instead +#I invalid node name CB Unix 3 using "CB Unix 3" instead +#I invalid node name PDP-11 Sys V using "PDP-11 Sys V" instead +#I invalid node name USG 3.0 using "USG 3.0" instead +#I invalid node name USG 2.0 using "USG 2.0" instead +#I invalid node name USG 3.0 using "USG 3.0" instead +#I invalid node name USG 3.0 using "USG 3.0" instead +#I invalid node name Unix/TS 3.0 using "Unix/TS 3.0" instead +#I invalid node name PWB 2.0 using "PWB 2.0" instead +#I invalid node name Unix/TS 3.0 using "Unix/TS 3.0" instead +#I invalid node name Unix/TS 1.0 using "Unix/TS 1.0" instead +#I invalid node name Unix/TS 1.0 using "Unix/TS 1.0" instead +#I invalid node name Unix/TS 3.0 using "Unix/TS 3.0" instead +#I invalid node name TS 4.0 using "TS 4.0" instead +#I invalid node name Unix/TS 3.0 using "Unix/TS 3.0" instead +#I invalid node name TS 4.0 using "TS 4.0" instead +#I invalid node name Unix/TS++ using "Unix/TS++" instead +#I invalid node name TS 4.0 using "TS 4.0" instead +#I invalid node name CB Unix 3 using "CB Unix 3" instead +#I invalid node name TS 4.0 using "TS 4.0" instead +#I invalid node name System V.0 using "System V.0" instead +#I invalid node name TS 4.0 using "TS 4.0" instead +#I invalid node name System V.0 using "System V.0" instead +#I invalid node name System V.2 using "System V.2" instead +#I invalid node name System V.0 using "System V.0" instead +#I invalid node name System V.2 using "System V.2" instead +#I invalid node name System V.3 using "System V.3" instead +#I invalid node name System V.2 using "System V.2" instead +#I invalid node name System V.3 using "System V.3" instead +//dot +digraph unix { + node [color="lightblue2", style="filled", size="6,6"] + "5th Edition" + "6th Edition" + "5th Edition" -> "6th Edition" + "PWB 1.0" + "5th Edition" -> "PWB 1.0" + LSX + "6th Edition" -> LSX + "1 BSD" + "6th Edition" -> "1 BSD" + "Mini Unix" + "6th Edition" -> "Mini Unix" + Wollongong + "6th Edition" -> Wollongong + Interdata + "6th Edition" -> Interdata + "Unix/TS 3.0" + "Unix/TS 3.0" -> Interdata + "PWB 2.0" + Interdata -> "PWB 2.0" + "7th Edition" + Interdata -> "7th Edition" + "8th Edition" + "7th Edition" -> "8th Edition" + "32V" + "7th Edition" -> "32V" + V7M + "7th Edition" -> V7M + "Ultrix-11" + "7th Edition" -> "Ultrix-11" + Xenix + "7th Edition" -> Xenix + "UniPlus+" + "7th Edition" -> "UniPlus+" + V7M -> "Ultrix-11" + "9th Edition" + "8th Edition" -> "9th Edition" + "2 BSD" + "1 BSD" -> "2 BSD" + "2.8 BSD" + "2 BSD" -> "2.8 BSD" + "2.8 BSD" -> "Ultrix-11" + "2.9 BSD" + "2.8 BSD" -> "2.9 BSD" + "3 BSD" + "32V" -> "3 BSD" + "4 BSD" + "3 BSD" -> "4 BSD" + "4.1 BSD" + "4 BSD" -> "4.1 BSD" + "4.2 BSD" + "4.1 BSD" -> "4.2 BSD" + "4.1 BSD" -> "2.8 BSD" + "4.1 BSD" -> "8th Edition" + "4.3 BSD" + "4.2 BSD" -> "4.3 BSD" + "Ultrix-32" + "4.2 BSD" -> "Ultrix-32" + "PWB 1.2" + "PWB 1.0" -> "PWB 1.2" + "USG 1.0" + "PWB 1.0" -> "USG 1.0" + "PWB 1.2" -> "PWB 2.0" + "CB Unix 1" + "USG 1.0" -> "CB Unix 1" + "USG 2.0" + "USG 1.0" -> "USG 2.0" + "CB Unix 2" + "CB Unix 1" -> "CB Unix 2" + "CB Unix 3" + "CB Unix 2" -> "CB Unix 3" + "Unix/TS++" + "CB Unix 3" -> "Unix/TS++" + "PDP-11 Sys V" + "CB Unix 3" -> "PDP-11 Sys V" + "USG 3.0" + "USG 2.0" -> "USG 3.0" + "USG 3.0" -> "Unix/TS 3.0" + "PWB 2.0" -> "Unix/TS 3.0" + "Unix/TS 1.0" + "Unix/TS 1.0" -> "Unix/TS 3.0" + "TS 4.0" + "Unix/TS 3.0" -> "TS 4.0" + "Unix/TS++" -> "TS 4.0" + "CB Unix 3" -> "TS 4.0" + "System V.0" + "TS 4.0" -> "System V.0" + "System V.2" + "System V.0" -> "System V.2" + "System V.3" + "System V.2" -> "System V.3" +} + +# +gap> STOP_TEST("graphviz package: unix.tst"); diff --git a/tst/graph.tst b/tst/graph.tst index 0679058..dcffd6c 100644 --- a/tst/graph.tst +++ b/tst/graph.tst @@ -1,13 +1,15 @@ ############################################################################# ## -## standard/dot.tst -## Copyright (C) 2022 James D. Mitchell +## graph.tst +## Copyright (C) 2024 Matthew Pancer ## ## Licensing information can be found in the README file of this package. ## ############################################################################# ## -gap> START_TEST("graphviz package: dot.tst"); + +#@local a, ab, b, c, cd, d, g, n, n1, n2, x +gap> START_TEST("graphviz package: graph.tst"); gap> LoadPackage("graphviz", false);; # Test graph constructor @@ -175,9 +177,9 @@ gap> g := GraphvizGraph();; gap> GraphvizSetAttr(g, "color", "red");; gap> GraphvizSetAttr(g, "color", "blue");; gap> AsString(g); -"graph {\n\tcolor=red color=blue \n}\n" +"//dot\ngraph {\n\tcolor=red color=blue \n}\n" -# # Test removing attributes from a graph +# # Test removing attributes from a graph TODO uncomment or delete # gap> g := GraphvizGraph();; # gap> GraphvizSetAttr(g, "color", "red");; # gap> GraphvizSetAttr(g, "shape", "circle");; @@ -240,3 +242,4 @@ gap> GraphvizAttrs(g); [ "color=red" ] # +gap> STOP_TEST("graphviz package: graph.tst", 0); diff --git a/tst/node.tst b/tst/node.tst index 17600d4..6388f06 100644 --- a/tst/node.tst +++ b/tst/node.tst @@ -1,13 +1,15 @@ ############################################################################# ## -## standard/dot.tst -## Copyright (C) 2022 James D. Mitchell +## node.tst +## Copyright (C) 2024 Matthew Pancer ## ## Licensing information can be found in the README file of this package. ## ############################################################################# ## -gap> START_TEST("graphviz package: dot.tst"); + +#@local color, g, label, n, s, shape +gap> START_TEST("graphviz package: node.tst"); gap> LoadPackage("graphviz", false);; # Test node constructor @@ -26,7 +28,7 @@ gap> n := GraphvizAddNode(GraphvizGraph(), " "); # Test making a node with empty name fails gap> n := GraphvizAddNode(GraphvizGraph(), ""); -Error, Node name cannot be empty. +Error, the 2nd argument (string/node name) cannot be empty # Test whitespace in node names gap> n := GraphvizAddNode(GraphvizGraph(), "a a "); @@ -53,14 +55,14 @@ rec( shape := "circle" ) gap> g := GraphvizGraph();; gap> GraphvizAddNode(g, "test:colon");; gap> AsString(g); -"graph {\n\ttest:colon\n}\n" +"//dot\ngraph {\n\ttest:colon\n}\n" # Test non-string name containing ':' gap> g := GraphvizGraph();; gap> GraphvizAddNode(g, 111); gap> AsString(g); -"graph {\n\t111\n}\n" +"//dot\ngraph {\n\t111\n}\n" # Test removing a node with a non-string name gap> g := GraphvizGraph();; @@ -111,3 +113,4 @@ gap> GraphvizAddNode(s, n); Error, Cannot add node objects directly to graphs. Please use the node's name. # +gap> STOP_TEST("graphviz package: node.tst", 0); diff --git a/tst/subgraph.tst b/tst/subgraph.tst index 1d1ae4c..94d0bc3 100644 --- a/tst/subgraph.tst +++ b/tst/subgraph.tst @@ -1,13 +1,16 @@ ############################################################################# ## -## standard/dot.tst -## Copyright (C) 2022 James D. Mitchell +## subgraph.tst +## Copyright (C) 2024 Matthew Pancer ## ## Licensing information can be found in the README file of this package. ## ############################################################################# ## -gap> START_TEST("graphviz package: dot.tst"); + +#@local a, a1, a2, a3, b, b1, b2, b3, c, child, ctx, g, main, n, o, parent, s +#@local s1, s11, s2, sibling +gap> START_TEST("graphviz package: subgraph.tst"); gap> LoadPackage("graphviz", false);; # Test creating subgraphs (named) @@ -132,8 +135,8 @@ gap> GraphvizSetAttr(s, "color", "red");; gap> GraphvizSetAttr(s, "node [color=red]");; gap> GraphvizSetAttr(s, "edge [color=red]");; gap> AsString(g); -"digraph {\nsubgraph a {\n\tcolor=red node [color=red] edge [color=red] \n}\n\ -\tx\n\ty\n\tx -> y\n}\n" +"//dot\ndigraph {\nsubgraph a {\n\tcolor=red node [color=red] edge [color=red\ +] \n}\n\tx\n\ty\n\tx -> y\n}\n" # Test stringifying subgraph graph gap> g := GraphvizGraph();; @@ -143,8 +146,8 @@ gap> GraphvizSetAttr(s, "color", "red");; gap> GraphvizSetAttr(s, "node [color=red]");; gap> GraphvizSetAttr(s, "edge [color=red]");; gap> AsString(g); -"graph {\nsubgraph a {\n\tcolor=red node [color=red] edge [color=red] \n}\n\t\ -x\n\ty\n\tx -- y\n}\n" +"//dot\ngraph {\nsubgraph a {\n\tcolor=red node [color=red] edge [color=red] \ +\n}\n\tx\n\ty\n\tx -- y\n}\n" # Test stringifying subgraph context (graph) gap> g := GraphvizGraph();; @@ -154,8 +157,8 @@ gap> GraphvizSetAttr(s, "color", "red");; gap> GraphvizSetAttr(s, "node [color=red]");; gap> GraphvizSetAttr(s, "edge [color=red]");; gap> AsString(g); -"graph {\n// a context \n\tcolor=red node [color=red] edge [color=red] \n\n\t\ -x\n\ty\n\tx -- y\n}\n" +"//dot\ngraph {\n// a context \n\tcolor=red node [color=red] edge [color=red]\ + \n\n\tx\n\ty\n\tx -- y\n}\n" # Test stringifying subgraph context (digraph) gap> g := GraphvizDigraph();; @@ -165,14 +168,14 @@ gap> GraphvizSetAttr(s, "color", "red");; gap> GraphvizSetAttr(s, "node [color=red]");; gap> GraphvizSetAttr(s, "edge [color=red]");; gap> AsString(g); -"digraph {\n// a context \n\tcolor=red node [color=red] edge [color=red] \n\n\ -\tx\n\ty\n\tx -> y\n}\n" +"//dot\ndigraph {\n// a context \n\tcolor=red node [color=red] edge [color=re\ +d] \n\n\tx\n\ty\n\tx -> y\n}\n" # Test stringifying subgraph w/o name gap> g := GraphvizDigraph();; gap> s := GraphvizAddSubgraph(g);; gap> AsString(g); -"digraph {\nsubgraph no_name_1 {\n}\n}\n" +"//dot\ndigraph {\nsubgraph no_name_1 {\n}\n}\n" # finding a node in a sibling graph gap> g := GraphvizDigraph();; @@ -242,9 +245,9 @@ gap> GraphvizSetAttr(g, "edge[color=blue]");; gap> GraphvizSetAttr(ctx, "node[color=red]");; gap> GraphvizAddNode(ctx, "a");; gap> AsString(g); -"digraph {\n\tcolor=green edge [label=testing123] node[color=blue] edge[color\ -=blue] \n// no_name_1 context \n\tnode[color=red] \n\ta\n\tcolor=green edge [l\ -abel=testing123] node[color=blue] edge[color=blue] \n\n}\n" +"//dot\ndigraph {\n\tcolor=green edge [label=testing123] node[color=blue] edg\ +e[color=blue] \n// no_name_1 context \n\tnode[color=red] \n\ta\n\tcolor=green \ +edge [label=testing123] node[color=blue] edge[color=blue] \n\n}\n" # Test adding subgraphs with the same name gap> g := GraphvizDigraph();; @@ -288,7 +291,7 @@ gap> g := GraphvizGraph();; gap> s1 := GraphvizAddSubgraph(g, "a");; gap> s2 := GraphvizAddSubgraph(s1, "c");; gap> AsString(g); -"graph {\nsubgraph a {\nsubgraph c {\n}\n}\n}\n" +"//dot\ngraph {\nsubgraph a {\nsubgraph c {\n}\n}\n}\n" # Test subgraphs with non-string names gap> g := GraphvizGraph();; @@ -357,7 +360,8 @@ gap> parent := GraphvizAddContext(g, "parent");; gap> ctx := GraphvizAddContext(parent, "ctx");; gap> GraphvizAddEdge(ctx, "a", "b");; gap> AsString(g); -"graph g {\n// parent context \n// ctx context \n\ta\n\tb\n\ta -- b\n\n\n}\n" +"//dot\ngraph g {\n// parent context \n// ctx context \n\ta\n\tb\n\ta -- b\n\n\ +\n}\n" # Test nested contexts have correct edge types (digraph) gap> g := GraphvizDigraph("g");; @@ -365,8 +369,8 @@ gap> parent := GraphvizAddContext(g, "parent");; gap> ctx := GraphvizAddContext(parent, "ctx");; gap> GraphvizAddEdge(ctx, "a", "b");; gap> AsString(g); -"digraph g {\n// parent context \n// ctx context \n\ta\n\tb\n\ta -> b\n\n\n}\n\ -" +"//dot\ndigraph g {\n// parent context \n// ctx context \n\ta\n\tb\n\ta -> b\n\ +\n\n}\n" # Test finding subgraph (non-string name) gap> g := GraphvizGraph("r");; @@ -377,3 +381,4 @@ gap> IsIdenticalObj(o, s); true # +gap> STOP_TEST("graphviz package: subgraph.tst", 0); diff --git a/tst/testall.g b/tst/testall.g index d891b2f..a5ad9d1 100644 --- a/tst/testall.g +++ b/tst/testall.g @@ -1,10 +1,6 @@ -# -# graphviz: This package facilitates the creation of graph descriptions in the -# DOT language of the Graphviz graph drawing software from GAP -# -# This file runs package tests. It is also referenced in the package -# metadata in PackageInfo.g. -# +# This file runs package tests. It is also referenced in the package metadata +# in PackageInfo.g. + LoadPackage("graphviz"); TestDirectory(DirectoriesPackageLibrary("graphviz", "tst"),