From 8f02bf0b94b8fd5c8a6ada9fa86acd76fc2d5915 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Mon, 13 May 2024 10:21:13 +0100 Subject: [PATCH 01/38] Separate IsGVGraph and IsGVDigraph --- gap/dot.gd | 51 ++++++++------ gap/dot.gi | 190 +++++++++++++++++++++++++------------------------- gap/splash.gi | 4 +- 3 files changed, 125 insertions(+), 120 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index 3921015..86c50b3 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -35,12 +35,15 @@ #! objects. These are graphs, digraphs, nodes and edges respectively. #! All are direct subcategories of IsGVObject excluding IsGVDigraph which is a #! subcategory of is GVGraph. + +# TODO replace GV -> graphviz DeclareCategory("IsGVObject", IsObject); -DeclareCategory("IsGVGraph", IsGVObject); +DeclareCategory("IsGVGraphOrDigraph", IsGVObject); # TODO change to IsGVObject below, since digraphs aren't a special kind of # graph, unless I'm (JDM) mistaken? -DeclareCategory("IsGVDigraph", IsGVGraph); -DeclareCategory("IsGVContext", IsGVGraph); +DeclareCategory("IsGVGraph", IsGVGraphOrDigraph); +DeclareCategory("IsGVDigraph", IsGVGraphOrDigraph); +DeclareCategory("IsGVContext", IsGVGraphOrDigraph); DeclareCategory("IsGVNode", IsGVObject); DeclareCategory("IsGVEdge", IsGVObject); #! @EndGroup @@ -87,14 +90,14 @@ DeclareOperation("GraphvizAttrs", [IsGVObject]); #! @Returns the nodes of the provided graphviz graph. #! @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]); +DeclareOperation("GraphvizNodes", [IsGVGraphOrDigraph]); +DeclareOperation("GraphvizNode", [IsGVGraphOrDigraph, IsObject]); #! @Arguments graph #! @Returns the subgraphs of the provided graphviz graph. #! @Description gets the subgraphs of a provided graphviz graph. -DeclareOperation("GraphvizSubgraphs", [IsGVGraph]); -DeclareOperation("GraphvizGetSubgraph", [IsGVGraph, IsObject]); +DeclareOperation("GraphvizSubgraphs", [IsGVGraphOrDigraph]); +DeclareOperation("GraphvizGetSubgraph", [IsGVGraphOrDigraph, IsObject]); #! @Arguments graph, name #! @Returns a graph with the provided name. @@ -103,13 +106,13 @@ DeclareOperation("GraphvizGetSubgraph", [IsGVGraph, IsObject]); #! with the provided name. #! It returns the graph if it exists. #! If no such graph exists then it will return fail. -DeclareOperation("GraphvizFindGraph", [IsGVGraph, IsObject]); +DeclareOperation("GraphvizFindGraph", [IsGVGraphOrDigraph, IsObject]); #! @Arguments graph #! @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]); +DeclareOperation("GraphvizEdges", [IsGVGraphOrDigraph]); +DeclareOperation("GraphvizEdges", [IsGVGraphOrDigraph, IsObject, IsObject]); #! @Subsection For only edges. @@ -131,13 +134,13 @@ DeclareOperation("GraphvizTail", [IsGVEdge]); #! @Arguments graph, name #! @Returns the modified graph. #! @Description Sets the name of a graphviz graph or digraph. -DeclareOperation("GraphvizSetName", [IsGVGraph, IsObject]); +DeclareOperation("GraphvizSetName", [IsGVGraphOrDigraph, IsObject]); #! @Arguments graph, node #! @Returns the modified graph. #! @Description Adds a node to the graph. #! If a node with the same name is already present the operation fails. -DeclareOperation("GraphvizAddNode", [IsGVGraph, IsObject]); +DeclareOperation("GraphvizAddNode", [IsGVGraphOrDigraph, IsObject]); #! @Arguments graph, edge #! @Returns the modified graph. @@ -145,35 +148,35 @@ DeclareOperation("GraphvizAddNode", [IsGVGraph, IsObject]); #! If no nodes with the same name are in the graph then the edge's nodes will be #! added to the graph. If different nodes with the same name are in the graph #! then the operation fails. -DeclareOperation("GraphvizAddEdge", [IsGVGraph, IsObject, IsObject]); +DeclareOperation("GraphvizAddEdge", [IsGVGraphOrDigraph, IsObject, IsObject]); #! @Arguments graph, filter, name #! @Returns the new subgraph. #! @Description Adds a subgraph to a graph. -DeclareOperation("GraphvizAddSubgraph", [IsGVGraph, IsObject]); -DeclareOperation("GraphvizAddSubgraph", [IsGVGraph]); +DeclareOperation("GraphvizAddSubgraph", [IsGVGraphOrDigraph, IsObject]); +DeclareOperation("GraphvizAddSubgraph", [IsGVGraphOrDigraph]); #! @Arguments graph, filter, name #! @Returns the new context. #! @Description Adds a context to a graph. -DeclareOperation("GraphvizAddContext", [IsGVGraph, IsObject]); -DeclareOperation("GraphvizAddContext", [IsGVGraph]); +DeclareOperation("GraphvizAddContext", [IsGVGraphOrDigraph, IsObject]); +DeclareOperation("GraphvizAddContext", [IsGVGraphOrDigraph]); #! @Arguments graph, node #! @Returns the modified graph. #! @Description Removes the node from the graph. -DeclareOperation("GraphvizRemoveNode", [IsGVGraph, IsObject]); +DeclareOperation("GraphvizRemoveNode", [IsGVGraphOrDigraph, IsObject]); #! @Arguments graph, predicate #! @Returns the modified graph. #! @Description Filters the graph's edges using the provided predicate. -DeclareOperation("GraphvizFilterEdges", [IsGVGraph, IsFunction]); +DeclareOperation("GraphvizFilterEdges", [IsGVGraphOrDigraph, IsFunction]); #! @Arguments graph, head_name, tail_name #! @Returns the modified graph. #! @Description Filters the graph's edges, removing edges between nodes with #! the specified names. -DeclareOperation("GraphvizFilterEnds", [IsGVGraph, IsObject, IsObject]); +DeclareOperation("GraphvizFilterEnds", [IsGVGraphOrDigraph, IsObject, IsObject]); #! @Subsection For modifying object attributes. @@ -214,7 +217,9 @@ DeclareOperation("GraphvizRemoveAttr", [IsGVObject, IsObject]); #! @Section Outputting #! @Arguments graph #! @Returns the dot representation of the graphviz object. -DeclareOperation("AsString", [IsGVGraph]); +DeclareOperation("AsString", [IsGVGraphOrDigraph]); + +# TODO PrintObj #! @Arguments obj #! @Returns the graphviz representation of the object. @@ -223,6 +228,6 @@ DeclareOperation("AsString", [IsGVGraph]); #! Should output the graphviz package representation of the object. DeclareOperation("Graphviz", [IsObject]); -DeclareOperation("GraphvizSetNodeColors", [IsGVGraph, IsList]); -DeclareOperation("GraphvizSetNodeLabels", [IsGVGraph, IsList]); +DeclareOperation("GraphvizSetNodeColors", [IsGVGraphOrDigraph, IsList]); +DeclareOperation("GraphvizSetNodeLabels", [IsGVGraphOrDigraph, IsList]); DeclareGlobalFunction("ErrorFormatted"); diff --git a/gap/dot.gi b/gap/dot.gi index 2dfa745..82f3bcd 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -50,21 +50,21 @@ function(arg...) [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]); -DeclareOperation("GV_StringifySubgraphHead", [IsGVGraph]); -DeclareOperation("GV_StringifyContextHead", [IsGVGraph]); +DeclareOperation("GV_GetCounter", [IsGVGraphOrDigraph]); +DeclareOperation("GV_IncCounter", [IsGVGraphOrDigraph]); +DeclareCategory("GV_IsMap", IsObject); +DeclareAttribute("Size", GV_IsMap); + +DeclareOperation("GV_StringifyGraphHead", [IsGVGraphOrDigraph]); +DeclareOperation("GV_StringifyDigraphHead", [IsGVGraphOrDigraph]); +DeclareOperation("GV_StringifySubgraphHead", [IsGVGraphOrDigraph]); +DeclareOperation("GV_StringifyContextHead", [IsGVGraphOrDigraph]); DeclareOperation("GV_StringifyNode", [IsGVNode]); -DeclareOperation("GV_StringifyGraphAttrs", [IsGVGraph]); -DeclareOperation("GV_StringifyNodeEdgeAttrs", [IsGV_Map]); -DeclareOperation("GV_StringifyGraph", [IsGVGraph, IsBool]); +DeclareOperation("GV_StringifyGraphAttrs", [IsGVGraphOrDigraph]); +DeclareOperation("GV_StringifyNodeEdgeAttrs", [GV_IsMap]); +DeclareOperation("GV_StringifyGraph", [IsGVGraphOrDigraph, IsBool]); -DeclareOperation("GV_FindNode", [IsGVGraph, IsObject]); +DeclareOperation("GV_FindNode", [IsGVGraphOrDigraph, IsObject]); ## COPY OF GAP PLURALIZE TO ALLOW OLD VERSIONS OF GAP TO USE THE PACKAGE DeclareOperation("GV_Pluralize", [IsInt, IsString]); @@ -307,7 +307,7 @@ BindGlobal("GV_ObjectFamily", IsGVObject)); BindGlobal("GV_MapType", NewType(GV_ObjectFamily, - IsGV_Map and + GV_IsMap and IsComponentObjectRep and IsAttributeStoringRep)); @@ -344,18 +344,18 @@ InstallMethod(\=, "for IsGVNode and IsGVNode", # Constructors etc ############################################################################### -DeclareOperation("GV_Node", [IsGVGraph, IsString]); -DeclareOperation("GV_Edge", [IsGVGraph, IsGVNode, IsGVNode]); -DeclareOperation("GV_Graph", [IsGVGraph, IsString]); +DeclareOperation("GV_Node", [IsGVGraphOrDigraph, IsString]); +DeclareOperation("GV_Edge", [IsGVGraphOrDigraph, IsGVNode, IsGVNode]); +DeclareOperation("GV_Graph", [IsGVGraphOrDigraph, IsString]); DeclareOperation("GV_Digraph", [IsGVDigraph, IsString]); -DeclareOperation("GV_Context", [IsGVGraph, IsString]); +DeclareOperation("GV_Context", [IsGVGraphOrDigraph, IsString]); DeclareOperation("GV_Map", []); InstallMethod(GV_Map, "for no args", [], {} -> Objectify(GV_MapType, rec(Data := rec()))); InstallMethod(GV_Node, "for a string", -[IsGVGraph, IsString], +[IsGVGraphOrDigraph, IsString], function(graph, name) local out; if Length(name) = 0 then @@ -371,7 +371,7 @@ function(graph, name) end); InstallMethod(GV_Edge, "for two graphviz nodes", -[IsGVGraph, IsGVNode, IsGVNode], +[IsGVGraphOrDigraph, IsGVNode, IsGVNode], function(graph, head, tail) local out; out := Objectify(GV_EdgeType, @@ -403,7 +403,7 @@ end); InstallMethod(GV_Graph, "for a graphviz graph and a string", -[IsGVGraph, IsString], +[IsGVGraphOrDigraph, IsString], function(parent, name) local out; @@ -417,7 +417,7 @@ end); InstallMethod(GV_Context, "for a string and a positive integer", -[IsGVGraph, IsString], +[IsGVGraphOrDigraph, IsString], function(parent, name) local out; @@ -489,7 +489,7 @@ InstallMethod(GraphvizDigraph, "for no args", [], {} -> GraphvizDigraph("")); InstallOtherMethod(\[\], "for a graphviz map and an object", -[IsGV_Map, IsObject], +[GV_IsMap, IsObject], function(m, o) if IsBound(m[o]) then return m!.Data.(o); @@ -499,33 +499,33 @@ end); InstallOtherMethod(\[\]\:\=, "for a graphviz map and two objects", -[IsGV_Map, IsObject, IsObject], +[GV_IsMap, IsObject, IsObject], function(m, key, val) m!.Data.(key) := val; end); InstallOtherMethod(Unbind\[\], "for a graphviz map and an object", -[IsGV_Map, IsObject], +[GV_IsMap, IsObject], function(m, key) Unbind(m!.Data.(key)); end); InstallOtherMethod(IsBound\[\], "for a graphviz map and an object", -[IsGV_Map, IsObject], +[GV_IsMap, IsObject], {m, key} -> IsBound(m!.Data.(key))); -DeclareOperation("GV_MapNames", [IsGV_Map]); +DeclareOperation("GV_MapNames", [GV_IsMap]); InstallMethod(GV_MapNames, "for a graphviz map", -[IsGV_Map], m -> RecNames(m!.Data)); +[GV_IsMap], m -> RecNames(m!.Data)); -InstallMethod(ViewString, "for a graphviz map", [IsGV_Map], +InstallMethod(ViewString, "for a graphviz map", [GV_IsMap], m -> String(m!.Data)); InstallMethod(Size, "for a graphviz map", -[IsGV_Map], m -> Length(GV_MapNames(m))); +[GV_IsMap], m -> Length(GV_MapNames(m))); ############################################################ # Stringify @@ -544,7 +544,7 @@ function(e) GraphvizName(tail)); end); -InstallMethod(ViewString, "for a graphviz graph", [IsGVGraph], +InstallMethod(ViewString, "for a graphviz graph", [IsGVGraphOrDigraph], function(g) local result, edges, nodes, kind; @@ -585,20 +585,20 @@ x -> x!.Attrs); # 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], +InstallMethod(GraphvizNodes, "for a graphviz graph", [IsGVGraphOrDigraph], x -> x!.Nodes); InstallMethod(GraphvizNode, "for a graphviz graph and object", -[IsGVGraph, IsObject], {gv, obj} -> gv!.Nodes[String(obj)]); +[IsGVGraphOrDigraph, 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); +[IsGVGraphOrDigraph], x -> x!.Edges); InstallMethod(GraphvizEdges, "for a graphviz graph, object, and object", -[IsGVGraph, IsObject, IsObject], +[IsGVGraphOrDigraph, IsObject, IsObject], function(gv, head, tail) head := GraphvizNode(gv, head); tail := GraphvizNode(gv, tail); @@ -607,7 +607,7 @@ function(gv, head, tail) GraphvizTail(x) = tail); end); -InstallMethod(GraphvizSubgraphs, "for a graphviz graph", [IsGVGraph], +InstallMethod(GraphvizSubgraphs, "for a graphviz graph", [IsGVGraphOrDigraph], x -> x!.Subgraphs); InstallMethod(GraphvizTail, "for a graphviz edge", [IsGVEdge], x -> x!.Tail); @@ -616,22 +616,22 @@ InstallMethod(GraphvizHead, "for a graphviz edge", [IsGVEdge], x -> x!.Head); InstallMethod(GraphvizGetSubgraph, "for a graphviz graph and string", -[IsGVGraph, IsString], +[IsGVGraphOrDigraph, IsString], {x, name} -> GraphvizSubgraphs(x)[name]); InstallMethod(GraphvizGetSubgraph, "for a graphviz graph and an object", -[IsGVGraph, IsObject], +[IsGVGraphOrDigraph, IsObject], {x, o} -> GraphvizSubgraphs(x)[ViewString(o)]); InstallMethod(GV_IncCounter, "for a graphviz graph", -[IsGVGraph], +[IsGVGraphOrDigraph], function(x) x!.Counter := x!.Counter + 1; end); -InstallMethod(GV_GetCounter, "for a graphviz graph", [IsGVGraph], +InstallMethod(GV_GetCounter, "for a graphviz graph", [IsGVGraphOrDigraph], x -> x!.Counter); # Converting strings @@ -703,32 +703,32 @@ end); InstallOtherMethod(\[\], "for a graphviz graph and string", -[IsGVGraph, IsString], +[IsGVGraphOrDigraph, IsString], {graph, node} -> GraphvizNodes(graph)[node]); InstallOtherMethod(\[\], "for a graphviz graph and string", -[IsGVGraph, IsObject], +[IsGVGraphOrDigraph, IsObject], {g, o} -> g[ViewString(o)]); -DeclareOperation("GV_HasNode", [IsGVGraph, IsObject]); +DeclareOperation("GV_HasNode", [IsGVGraphOrDigraph, IsObject]); InstallMethod(GV_HasNode, "for a graphviz graph", -[IsGVGraph, IsString], +[IsGVGraphOrDigraph, IsString], {g, name} -> name in GV_MapNames(GraphvizNodes(g))); -DeclareOperation("GV_GetParent", [IsGVGraph]); +DeclareOperation("GV_GetParent", [IsGVGraphOrDigraph]); InstallMethod(GV_GetParent, "for a graphviz graph", -[IsGVGraph], graph -> graph!.Parent); +[IsGVGraphOrDigraph], graph -> graph!.Parent); -DeclareOperation("GV_GraphTreeSearch", [IsGVGraph, IsFunction]); +DeclareOperation("GV_GraphTreeSearch", [IsGVGraphOrDigraph, IsFunction]); InstallMethod(GV_GraphTreeSearch, "for a graphviz graph and a predicate", -[IsGVGraph, IsFunction], +[IsGVGraphOrDigraph, IsFunction], function(graph, pred) local seen, to_visit, g, key, subgraph, parent; seen := [graph]; @@ -753,7 +753,7 @@ function(graph, pred) # add parent if not visited parent := GV_GetParent(g); - if not IsGVGraph(parent) then + if not IsGVGraphOrDigraph(parent) then continue; fi; if not ForAny(seen, s -> IsIdenticalObj(s, parent)) then @@ -765,16 +765,16 @@ function(graph, pred) return fail; end); -DeclareOperation("GV_FindGraphWithNode", [IsGVGraph, IsString]); +DeclareOperation("GV_FindGraphWithNode", [IsGVGraphOrDigraph, IsString]); InstallMethod(GV_FindGraphWithNode, "for a graphviz graph and a node", -[IsGVGraph, IsString], +[IsGVGraphOrDigraph, IsString], {g, n} -> GV_GraphTreeSearch(g, v -> v[n] <> fail)); -DeclareOperation("GV_GetRoot", [IsGVGraph]); +DeclareOperation("GV_GetRoot", [IsGVGraphOrDigraph]); InstallMethod(GV_GetRoot, "for a graphviz graph", -[IsGVGraph], +[IsGVGraphOrDigraph], function(graph) while GV_GetParent(graph) <> fail do graph := GV_GetParent(graph); @@ -784,17 +784,17 @@ end); InstallMethod(GraphvizFindGraph, "for a graphviz graph and a string", -[IsGVGraph, IsString], +[IsGVGraphOrDigraph, IsString], {g, s} -> GV_GraphTreeSearch(g, v -> GraphvizName(v) = s)); InstallMethod(GraphvizFindGraph, "for a graphviz graph and a string", -[IsGVGraph, IsObject], +[IsGVGraphOrDigraph, IsObject], {g, o} -> GraphvizFindGraph(g, ViewString(o))); InstallMethod(GV_FindNode, "for a graphviz graph and a string", -[IsGVGraph, IsString], +[IsGVGraphOrDigraph, IsString], function(g, n) local graph; graph := GV_FindGraphWithNode(g, n); @@ -809,14 +809,14 @@ end); ############################################################ InstallMethod(GraphvizSetName, "for a graphviz object and string", -[IsGVGraph, IsString], +[IsGVGraphOrDigraph, IsString], function(x, name) x!.Name := name; return x; end); InstallMethod(GraphvizSetName, "for a graphviz object and string", -[IsGVGraph, IsObject], +[IsGVGraphOrDigraph, IsObject], {g, o} -> GraphvizSetName(g, ViewString(o))); InstallMethod(GraphvizSetAttrs, "for a graphviz object and record", @@ -846,7 +846,7 @@ function(x, name, value) end); InstallMethod(GraphvizSetAttr, "for a graphviz graph, object and object", -[IsGVGraph, IsObject, IsObject], +[IsGVGraphOrDigraph, IsObject, IsObject], function(x, name, value) local attrs, string, msg; @@ -874,7 +874,7 @@ function(x, name, value) end); InstallMethod(GraphvizSetAttr, "for a graphviz object, object and object", -[IsGVGraph, IsObject], +[IsGVGraphOrDigraph, IsObject], function(x, value) local attrs; attrs := GraphvizAttrs(x); @@ -893,10 +893,10 @@ InstallMethod(GraphvizSetColor, [IsGVObject, IsObject], {x, color} -> GraphvizSetAttr(x, "color", color)); -DeclareOperation("GV_AddNode", [IsGVGraph, IsGVNode]); +DeclareOperation("GV_AddNode", [IsGVGraphOrDigraph, IsGVNode]); InstallMethod(GV_AddNode, "for a graphviz graph and node", -[IsGVGraph, IsGVNode], +[IsGVGraphOrDigraph, IsGVNode], function(x, node) local found, error, name, nodes; name := GraphvizName(node); @@ -914,7 +914,7 @@ function(x, node) end); InstallMethod(GraphvizAddNode, "for a graphviz graph and string", -[IsGVGraph, IsString], +[IsGVGraphOrDigraph, IsString], function(x, name) local node; node := GV_Node(x, name); @@ -924,7 +924,7 @@ end); # TODO required? InstallMethod(GraphvizAddNode, "for a graphviz graph and string", -[IsGVGraph, IsGVNode], +[IsGVGraphOrDigraph, IsGVNode], function(_, __) # gaplint: disable=analyse-lvars local error; error := "Cannot add node objects directly to graphs. "; @@ -934,13 +934,13 @@ end); InstallMethod(GraphvizAddNode, "for a graphviz graph and string", -[IsGVGraph, IsObject], +[IsGVGraphOrDigraph, IsObject], {x, name} -> GraphvizAddNode(x, ViewString(name))); -DeclareOperation("GV_AddEdge", [IsGVGraph, IsGVEdge]); +DeclareOperation("GV_AddEdge", [IsGVGraphOrDigraph, IsGVEdge]); InstallMethod(GV_AddEdge, "for a graphviz graph and edge", -[IsGVGraph, IsGVEdge], +[IsGVGraphOrDigraph, IsGVEdge], function(x, edge) local head, head_name, tail_name, tail, hg, error, tg; @@ -980,7 +980,7 @@ end); InstallMethod(GraphvizAddEdge, "for a graphviz graph and two graphviz nodes", -[IsGVGraph, IsGVNode, IsGVNode], +[IsGVGraphOrDigraph, IsGVNode, IsGVNode], function(x, head, tail) local edge, head_name, tail_name; @@ -1002,7 +1002,7 @@ end); InstallMethod(GraphvizAddEdge, "for a graphviz graph and two strings", -[IsGVGraph, IsString, IsString], +[IsGVGraphOrDigraph, IsString, IsString], function(x, head, tail) local head_node, tail_node; @@ -1021,7 +1021,7 @@ end); InstallMethod(GraphvizAddEdge, "for a graphviz graph and two objects", -[IsGVGraph, IsObject, IsObject], +[IsGVGraphOrDigraph, IsObject, IsObject], function(x, o1, o2) if not IsString(o1) then o1 := ViewString(o1); @@ -1034,7 +1034,7 @@ end); InstallMethod(GraphvizAddSubgraph, "for a graphviz graph and string", -[IsGVGraph, IsString], +[IsGVGraphOrDigraph, IsString], function(graph, name) local error, subgraphs, subgraph; @@ -1046,7 +1046,7 @@ function(graph, name) if IsGVDigraph(graph) then subgraph := GV_Digraph(graph, name); - elif IsGVGraph(graph) then + elif IsGVGraph(graph) or IsGVContext(graph) then subgraph := GV_Graph(graph, name); else ErrorNoReturn("Filter must be a filter for a graph category."); @@ -1058,12 +1058,12 @@ end); InstallMethod(GraphvizAddSubgraph, "for a graphviz graph and an object", -[IsGVGraph, IsObject], +[IsGVGraphOrDigraph, IsObject], {g, o} -> GraphvizAddSubgraph(g, ViewString(o))); InstallMethod(GraphvizAddSubgraph, "for a grpahviz graph", -[IsGVGraph], +[IsGVGraphOrDigraph], function(graph) return GraphvizAddSubgraph(graph, StringFormatted("no_name_{}", String(GV_GetCounter(graph)))); @@ -1071,7 +1071,7 @@ end); InstallMethod(GraphvizAddContext, "for a graphviz graph and a string", -[IsGVGraph, IsString], +[IsGVGraphOrDigraph, IsString], function(graph, name) local ctx, error, subgraphs; @@ -1088,23 +1088,23 @@ end); InstallMethod(GraphvizAddContext, "for a graphviz graph", -[IsGVGraph], +[IsGVGraphOrDigraph], g -> GraphvizAddContext(g, StringFormatted("no_name_{}", String(GV_GetCounter(g))))); InstallMethod(GraphvizAddContext, "for a graphviz graph and an object", -[IsGVGraph, IsObject], +[IsGVGraphOrDigraph, IsObject], {g, o} -> GraphvizAddContext(g, ViewString(o))); InstallMethod(GraphvizRemoveNode, "for a graphviz graph and node", -[IsGVGraph, IsGVNode], +[IsGVGraphOrDigraph, IsGVNode], {g, node} -> GraphvizRemoveNode(g, GraphvizName(node))); # TODO GraphvizRemoveEdges(gv, n1, n2) InstallMethod(GraphvizRemoveNode, "for a graphviz graph and a string", -[IsGVGraph, IsString], +[IsGVGraphOrDigraph, IsString], function(g, name) local nodes; # TODO error if there's no such node @@ -1124,11 +1124,11 @@ function(g, name) end); InstallMethod(GraphvizRemoveNode, "for a graphviz graph and a string", -[IsGVGraph, IsObject], +[IsGVGraphOrDigraph, IsObject], {g, o} -> GraphvizRemoveNode(g, ViewString(o))); InstallMethod(GraphvizFilterEdges, "for a graphviz graph and edge filter", -[IsGVGraph, IsFunction], +[IsGVGraphOrDigraph, IsFunction], function(g, filter) local edge, idx, edges; @@ -1146,7 +1146,7 @@ function(g, filter) end); InstallMethod(GraphvizFilterEnds, "for a graphviz graph and two strings", -[IsGVGraph, IsString, IsString], +[IsGVGraphOrDigraph, IsString, IsString], function(g, hn, tn) GraphvizFilterEdges(g, function(e) @@ -1165,7 +1165,7 @@ function(g, hn, tn) end); InstallMethod(GraphvizFilterEnds, "for a graphviz graph and two strings", -[IsGVGraph, IsObject, IsObject], +[IsGVGraphOrDigraph, IsObject, IsObject], function(g, o1, o2) if not IsString(o1) then o1 := ViewString(o1); @@ -1187,7 +1187,7 @@ function(obj, attr) end); InstallMethod(GraphvizRemoveAttr, "for a graphviz graph and an object", -[IsGVGraph, IsObject], +[IsGVGraphOrDigraph, IsObject], function(obj, attr) local attrs; attrs := GraphvizAttrs(obj); @@ -1200,7 +1200,7 @@ end); # ############################################################################## # @ Return DOT graph head line. -InstallMethod(GV_StringifyGraphHead, "for a string", [IsGVGraph], +InstallMethod(GV_StringifyGraphHead, "for a string", [IsGVGraphOrDigraph], graph -> StringFormatted("graph {} {{\n", GraphvizName(graph))); # @ Return DOT digraph head line. @@ -1208,7 +1208,7 @@ InstallMethod(GV_StringifyDigraphHead, "for a string", [IsGVDigraph], graph -> StringFormatted("digraph {} {{\n", GraphvizName(graph))); # @ Return DOT subgraph head line. -InstallMethod(GV_StringifySubgraphHead, "for a string", [IsGVGraph], +InstallMethod(GV_StringifySubgraphHead, "for a string", [IsGVGraphOrDigraph], graph -> StringFormatted("subgraph {} {{\n", GraphvizName(graph))); # @ Return DOT subgraph head line. @@ -1267,7 +1267,7 @@ end); InstallMethod(GV_StringifyGraphAttrs, "for a graphviz graph", -[IsGVGraph], +[IsGVGraphOrDigraph], function(graph) local result, attrs, kv; attrs := GraphvizAttrs(graph); @@ -1286,7 +1286,7 @@ end); InstallMethod(GV_StringifyNodeEdgeAttrs, "for a GV_Map", -[IsGV_Map], +[GV_IsMap], function(attrs) local result, keys, key, val, n, i, tmp; @@ -1351,10 +1351,10 @@ InstallMethod(GV_GetIdx, [IsGVObject], x -> x!.Idx); -DeclareOperation("GV_ConstructHistory", [IsGVGraph]); +DeclareOperation("GV_ConstructHistory", [IsGVGraphOrDigraph]); InstallMethod(GV_ConstructHistory, "for a graphviz graph", -[IsGVGraph], +[IsGVGraphOrDigraph], function(graph) local nodes, edges, subs, node_hist, edge_hist, subs_hist, hist; @@ -1375,7 +1375,7 @@ end); InstallMethod(GV_StringifyGraph, "for a graphviz graph and a string", -[IsGVGraph, IsBool], +[IsGVGraphOrDigraph, IsBool], function(graph, is_subgraph) local result, obj; result := ""; @@ -1406,7 +1406,7 @@ function(graph, is_subgraph) # Add child graphviz objects for obj in GV_ConstructHistory(graph) do - if IsGVGraph(obj) then + if IsGVGraphOrDigraph(obj) then Append(result, GV_StringifyGraph(obj, true)); elif IsGVNode(obj) then Append(result, GV_StringifyNode(obj)); @@ -1434,7 +1434,7 @@ function(graph, is_subgraph) end); InstallMethod(AsString, "for a graphviz graph", -[IsGVGraph], +[IsGVGraphOrDigraph], graph -> GV_StringifyGraph(graph, false)); BindGlobal("GV_IsValidRGBColor", @@ -1487,7 +1487,7 @@ end); InstallMethod(GraphvizSetNodeLabels, "for a graphviz graph and list of colors", -[IsGVGraph, IsList], +[IsGVGraphOrDigraph, IsList], function(gv, labels) local nodes, i; # TODO error if labels and nodes aren't same size @@ -1501,7 +1501,7 @@ end); InstallMethod(GraphvizSetNodeColors, "for a graphviz graph and list of colors", -[IsGVGraph, IsList], +[IsGVGraphOrDigraph, IsList], function(gv, colors) local nodes, i; diff --git a/gap/splash.gi b/gap/splash.gi index 4effacb..17cb9be 100644 --- a/gap/splash.gi +++ b/gap/splash.gi @@ -12,10 +12,10 @@ if not IsBound(Splash) then 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 + elif not IsString(arg[1]) and not IsGVGraphOrDigraph(arg[1]) then ErrorFormatted("the 1st argument must be a string or ", "graphviz graph, found {}", TNAM_OBJ(arg[1])); - elif IsGVGraph(arg[1]) then + elif IsGVGraphOrDigraph(arg[1]) then arg[1] := AsString(arg[1]); fi; str := arg[1]; From 73573811c4c563bca387e02e58cd172da5e18328 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Mon, 13 May 2024 10:24:20 +0100 Subject: [PATCH 02/38] Separate file for ErrorFormatted --- gap/dot.gd | 1 - gap/dot.gi | 37 ------------------------------------- gap/error.gd | 11 +++++++++++ gap/error.gi | 47 +++++++++++++++++++++++++++++++++++++++++++++++ init.g | 1 + read.g | 3 ++- 6 files changed, 61 insertions(+), 39 deletions(-) create mode 100644 gap/error.gd create mode 100644 gap/error.gi diff --git a/gap/dot.gd b/gap/dot.gd index 86c50b3..5d36e3b 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -230,4 +230,3 @@ DeclareOperation("Graphviz", [IsObject]); DeclareOperation("GraphvizSetNodeColors", [IsGVGraphOrDigraph, IsList]); DeclareOperation("GraphvizSetNodeLabels", [IsGVGraphOrDigraph, IsList]); -DeclareGlobalFunction("ErrorFormatted"); diff --git a/gap/dot.gi b/gap/dot.gi index 82f3bcd..259ad57 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -12,43 +12,6 @@ # 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", [IsGVGraphOrDigraph]); DeclareOperation("GV_IncCounter", [IsGVGraphOrDigraph]); diff --git a/gap/error.gd b/gap/error.gd new file mode 100644 index 0000000..56fea6d --- /dev/null +++ b/gap/error.gd @@ -0,0 +1,11 @@ +############################################################################# +## +## error.gd +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +DeclareGlobalFunction("ErrorFormatted"); diff --git a/gap/error.gi b/gap/error.gi new file mode 100644 index 0000000..605e83c --- /dev/null +++ b/gap/error.gi @@ -0,0 +1,47 @@ +############################################################################# +## +## error.gi +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +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); diff --git a/init.g b/init.g index 2d54325..7d8d023 100644 --- a/init.g +++ b/init.g @@ -8,4 +8,5 @@ ############################################################################# ## +ReadPackage("graphviz", "gap/error.gd"); ReadPackage("graphviz", "gap/dot.gd"); diff --git a/read.g b/read.g index 4dbac1a..794be60 100644 --- a/read.g +++ b/read.g @@ -7,6 +7,7 @@ ## ############################################################################# ## + ReadPackage("graphviz", "gap/dot.gi"); +ReadPackage("graphviz", "gap/error.gi"); ReadPackage("graphviz", "gap/splash.gi"); -ReadPackage("graphviz", "gap/defaults.gi"); From bb6572d4f065818daf06ed81aacc590843fb8a23 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Mon, 13 May 2024 10:26:49 +0100 Subject: [PATCH 03/38] Remove redundant funcs --- gap/dot.gd | 18 ------------------ gap/dot.gi | 10 ---------- tst/edge.tst | 6 +++--- tst/graph.tst | 4 ++-- tst/node.tst | 4 ++-- 5 files changed, 7 insertions(+), 35 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index 5d36e3b..e82e0b6 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -191,24 +191,6 @@ DeclareOperation("GraphvizSetAttrs", [IsGVObject, IsRecord]); DeclareOperation("GraphvizSetAttr", [IsGVObject, IsObject, IsObject]); DeclareOperation("GraphvizSetAttr", [IsGVObject, IsObject]); -#! @Arguments obj, label -#! @Returns the modified object. -#! @Description -#! 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 -#! @Returns the modified object. -#! @Description -#! 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 #! @Returns the modified object. #! @Description Removes an attribute from the object provided. diff --git a/gap/dot.gi b/gap/dot.gi index 259ad57..13f6d3c 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -846,16 +846,6 @@ function(x, value) return x; end); -InstallMethod(GraphvizSetLabel, -"for a graphviz object and an object", -[IsGVObject, IsObject], -{x, label} -> GraphvizSetAttr(x, "label", label)); - -InstallMethod(GraphvizSetColor, -"for a graphviz object and an object", -[IsGVObject, IsObject], -{x, color} -> GraphvizSetAttr(x, "color", color)); - DeclareOperation("GV_AddNode", [IsGVGraphOrDigraph, IsGVNode]); InstallMethod(GV_AddNode, "for a graphviz graph and node", diff --git a/tst/edge.tst b/tst/edge.tst index 5f5f8d4..c0117db 100644 --- a/tst/edge.tst +++ b/tst/edge.tst @@ -143,16 +143,16 @@ gap> n["color"]; # Test set label (edge) gap> g := GraphvizGraph();; gap> n := GraphvizAddEdge(g, "n", "m");; -gap> GraphvizSetLabel(n, "test");; +gap> GraphvizSetAttr(n, "label", "test");; gap> GraphvizAttrs(n); rec( label := "test" ) # Test set color (edge) gap> g := GraphvizGraph();; gap> n := GraphvizAddEdge(g, "n", "m");; -gap> GraphvizSetColor(n, "red");; +gap> GraphvizSetAttr(n, "color", "red");; gap> GraphvizAttrs(n); rec( color := "red" ) # -gap> STOP_TEST("graphviz package: edge.tst", 0); +gap> STOP_TEST("graphviz package: edge.tst"); diff --git a/tst/graph.tst b/tst/graph.tst index a0aea1d..175d1d1 100644 --- a/tst/graph.tst +++ b/tst/graph.tst @@ -231,13 +231,13 @@ gap> GraphvizSetName(g, ["a"]); # Test set label (graph) gap> g := GraphvizGraph();; -gap> GraphvizSetLabel(g, "test");; +gap> GraphvizSetAttr(g, "label", "test");; gap> GraphvizAttrs(g); [ "label=test" ] # Test set color (graph) gap> g := GraphvizGraph();; -gap> GraphvizSetColor(g, "red");; +gap> GraphvizSetAttr(g, "color", "red");; gap> GraphvizAttrs(g); [ "color=red" ] diff --git a/tst/node.tst b/tst/node.tst index 6388f06..92dc589 100644 --- a/tst/node.tst +++ b/tst/node.tst @@ -94,14 +94,14 @@ gap> n["color"]; # Test set label (node) gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "n");; -gap> GraphvizSetLabel(n, "test");; +gap> GraphvizSetAttr(n, "label", "test");; gap> GraphvizAttrs(n); rec( label := "test" ) # Test set color (node) gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "n");; -gap> GraphvizSetColor(n, "red");; +gap> GraphvizSetAttr(n, "color", "red");; gap> GraphvizAttrs(n); rec( color := "red" ) From fbd0390894f1d9664c4a86199aa274086c78c055 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Mon, 13 May 2024 10:51:09 +0100 Subject: [PATCH 04/38] Reorganise files --- gap/dot.gd | 2 + gap/dot.gi | 934 ++------------------------------------------------ gap/gv.gd | 216 ++++++++++++ gap/gv.gi | 679 ++++++++++++++++++++++++++++++++++++ gap/splash.gd | 0 init.g | 1 + read.g | 1 + 7 files changed, 926 insertions(+), 907 deletions(-) create mode 100644 gap/gv.gd create mode 100644 gap/gv.gi create mode 100644 gap/splash.gd diff --git a/gap/dot.gd b/gap/dot.gd index e82e0b6..57891d0 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -212,3 +212,5 @@ DeclareOperation("Graphviz", [IsObject]); DeclareOperation("GraphvizSetNodeColors", [IsGVGraphOrDigraph, IsList]); DeclareOperation("GraphvizSetNodeLabels", [IsGVGraphOrDigraph, IsList]); + +DeclareGlobalFunction("ErrorIfNotValidColor"); diff --git a/gap/dot.gi b/gap/dot.gi index 13f6d3c..510f54a 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -9,401 +9,10 @@ ## ############################################################################# -# Private functionality +# Constructors ############################################################################# - -DeclareOperation("GV_GetCounter", [IsGVGraphOrDigraph]); -DeclareOperation("GV_IncCounter", [IsGVGraphOrDigraph]); -DeclareCategory("GV_IsMap", IsObject); -DeclareAttribute("Size", GV_IsMap); - -DeclareOperation("GV_StringifyGraphHead", [IsGVGraphOrDigraph]); -DeclareOperation("GV_StringifyDigraphHead", [IsGVGraphOrDigraph]); -DeclareOperation("GV_StringifySubgraphHead", [IsGVGraphOrDigraph]); -DeclareOperation("GV_StringifyContextHead", [IsGVGraphOrDigraph]); -DeclareOperation("GV_StringifyNode", [IsGVNode]); -DeclareOperation("GV_StringifyGraphAttrs", [IsGVGraphOrDigraph]); -DeclareOperation("GV_StringifyNodeEdgeAttrs", [GV_IsMap]); -DeclareOperation("GV_StringifyGraph", [IsGVGraphOrDigraph, IsBool]); - -DeclareOperation("GV_FindNode", [IsGVGraphOrDigraph, IsObject]); - -## COPY OF GAP PLURALIZE TO ALLOW OLD VERSIONS OF GAP TO USE THE PACKAGE -DeclareOperation("GV_Pluralize", [IsInt, IsString]); - -BindGlobal("GV_KNOWN_ATTRS", [ - "_background", "area", "arrowhead", "arrowsize", "arrowtail", "bb", - "beautify", "bgcolor", "center", "charset", "class", "cluster", "clusterrank", - "color", "colorscheme", "comment", "compound", "concentrate", "constraint", - "Damping", "decorate", "defaultdist", "dim", "dimen", "dir", - "diredgeconstraints", "distortion", "dpi", "edgehref", "edgetarget", - "edgetooltip", "edgeURL", "epsilon", "esep", "fillcolor", "fixedsize", - "fontcolor", "fontname", "fontnames", "fontpath", "fontsize", "forcelabels", - "gradientangle", "group", "head_lp", "headclip", "headhref", "headlabel", - "headport", "headtarget", "headtooltip", "headURL", "height", "href", "id", - "image", "imagepath", "imagepos", "imagescale", "inputscale", "K", "label", - "label_scheme", "labelangle", "labeldistance", "labelfloat", "labelfontcolor", - "labelfontname", "labelfontsize", "labelhref", "labeljust", "labelloc", - "labeltarget", "labeltooltip", "labelURL", "landscape", "layer", - "layerlistsep", "layers", "layerselect", "layersep", "layout", "len", - "levels", "levelsgap", "lhead", "lheight", "linelength", "lp", "ltail", - "lwidth", "margin", "maxiter", "mclimit", "mindist", "minlen", "mode", - "model", "newrank", "nodesep", "nojustify", "normalize", "notranslate", - "nslimit", "nslimit1", "oneblock", "ordering", "orientation", "outputorder", - "overlap", "overlap_scaling", "overlap_shrink", "pack", "packmode", "pad", - "page", "pagedir", "pencolor", "penwidth", "peripheries", "pin", "pos", - "quadtree", "quantum", "rank", "rankdir", "ranksep", "ratio", "rects", - "regular", "remincross", "repulsiveforce", "resolution", "root", "rotate", - "rotation", "samehead", "sametail", "samplepoints", "scale", "searchsize", - "sep", "shape", "shapefile", "showboxes", "sides", "size", "skew", - "smoothing", "sortv", "splines", "start", "style", "stylesheet", "tail_lp", - "tailclip", "tailhref", "taillabel", "tailport", "tailtarget", "tailtooltip", - "tailURL", "target", "TBbalance", "tooltip", "truecolor", "URL", "vertices", - "viewport", "voro_margin", "weight", "width", "xdotversion", "xlabel", "xlp", - "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", -[IsInt, IsString], -function(args...) - local nargs, i, count, include_num, str, len, out; - - nargs := Length(args); - if nargs >= 1 and IsInt(args[1]) and args[1] >= 0 then - i := 2; - count := args[1]; - include_num := true; - else - i := 1; - include_num := false; # if not given, assume pluralization is wanted. - fi; - - if not (nargs in [i, i + 1] and - IsString(args[i]) and - (nargs = i or IsString(args[i + 1]))) then - ErrorNoReturn("Usage: GV_Pluralize([, ][, ])"); - fi; - - str := args[i]; - len := Length(str); - - if len = 0 then - ErrorNoReturn("the argument must be a non-empty string"); - elif include_num and count = 1 then # no pluralization needed - return Concatenation("\>1\< ", str); - elif nargs = i + 1 then # pluralization given - out := args[i + 1]; - elif len <= 2 then - out := Concatenation(str, "s"); - - # Guess and return the plural form of . - # Inspired by the "Ruby on Rails" inflection rules. - - # Uncountable nouns - elif str in ["equipment", "information"] then - out := str; - - # Irregular plurals - elif str = "axis" then - out := "axes"; - elif str = "child" then - out := "children"; - elif str = "person" then - out := "people"; - - # Peculiar endings - elif EndsWith(str, "ix") or EndsWith(str, "ex") then - out := Concatenation(str{[1 .. len - 2]}, "ices"); - elif EndsWith(str, "x") then - out := Concatenation(str, "es"); - elif EndsWith(str, "tum") or EndsWith(str, "ium") then - out := Concatenation(str{[1 .. len - 2]}, "a"); - elif EndsWith(str, "sis") then - out := Concatenation(str{[1 .. len - 3]}, "ses"); - elif EndsWith(str, "fe") and not EndsWith(str, "ffe") then - out := Concatenation(str{[1 .. len - 2]}, "ves"); - elif EndsWith(str, "lf") or EndsWith(str, "rf") or EndsWith(str, "loaf") then - out := Concatenation(str{[1 .. len - 1]}, "ves"); - elif EndsWith(str, "y") and not str[len - 1] in "aeiouy" then - out := Concatenation(str{[1 .. len - 1]}, "ies"); - elif str{[len - 1, len]} in ["ch", "ss", "sh"] then - out := Concatenation(str, "es"); - elif EndsWith(str, "s") then - out := str; - - # Default to appending 's' - else - out := Concatenation(str, "s"); - fi; - - if include_num then - return Concatenation("\>", String(args[1]), "\< ", out); - fi; - return out; -end); - -############################################################################### -# Family + type -############################################################################### - -BindGlobal("GV_ObjectFamily", - NewFamily("GV_ObjectFamily", - IsGVObject)); - -BindGlobal("GV_MapType", NewType(GV_ObjectFamily, - GV_IsMap and - IsComponentObjectRep and - IsAttributeStoringRep)); - -BindGlobal("GV_DigraphType", NewType(GV_ObjectFamily, - IsGVDigraph and - IsComponentObjectRep and - IsAttributeStoringRep)); - -BindGlobal("GV_GraphType", NewType(GV_ObjectFamily, - IsGVGraph and - IsComponentObjectRep and - IsAttributeStoringRep)); - -BindGlobal("GV_NodeType", NewType(GV_ObjectFamily, - IsGVNode and - IsComponentObjectRep and - IsAttributeStoringRep)); - -BindGlobal("GV_EdgeType", NewType(GV_ObjectFamily, - IsGVEdge and - IsComponentObjectRep and - IsAttributeStoringRep)); - -BindGlobal("GV_ContextType", NewType(GV_ObjectFamily, - IsGVContext and - IsComponentObjectRep and - IsAttributeStoringRep)); - -InstallMethod(\=, "for IsGVNode and IsGVNode", -[IsGVNode, IsGVNode], -{n1, n2} -> GraphvizName(n1) = GraphvizName(n2)); - -############################################################################### -# Constructors etc -############################################################################### - -DeclareOperation("GV_Node", [IsGVGraphOrDigraph, IsString]); -DeclareOperation("GV_Edge", [IsGVGraphOrDigraph, IsGVNode, IsGVNode]); -DeclareOperation("GV_Graph", [IsGVGraphOrDigraph, IsString]); -DeclareOperation("GV_Digraph", [IsGVDigraph, IsString]); -DeclareOperation("GV_Context", [IsGVGraphOrDigraph, IsString]); -DeclareOperation("GV_Map", []); - -InstallMethod(GV_Map, "for no args", -[], {} -> Objectify(GV_MapType, rec(Data := rec()))); - -InstallMethod(GV_Node, "for a string", -[IsGVGraphOrDigraph, IsString], -function(graph, name) - local out; - if Length(name) = 0 then - ErrorNoReturn("the 2nd argument (string/node name) cannot be empty"); - fi; - out := Objectify(GV_NodeType, - rec( - Name := name, - Attrs := GV_Map(), - Idx := GV_GetCounter(graph))); - GV_IncCounter(graph); - return out; -end); - -InstallMethod(GV_Edge, "for two graphviz nodes", -[IsGVGraphOrDigraph, IsGVNode, IsGVNode], -function(graph, head, tail) - local out; - out := Objectify(GV_EdgeType, - rec( - Name := "", - Head := head, - Tail := tail, - Attrs := GV_Map(), - Idx := GV_GetCounter(graph))); - GV_IncCounter(graph); - return out; -end); - -# Graph constructors - -InstallMethod(GV_Digraph, -"for a graphviz digraph and a string", -[IsGVDigraph, IsString], -function(parent, name) - local out; - - out := GraphvizDigraph(name); - out!.Parent := parent; - out!.Idx := GV_GetCounter(parent); - - GV_IncCounter(parent); - return out; -end); - -InstallMethod(GV_Graph, -"for a graphviz graph and a string", -[IsGVGraphOrDigraph, IsString], -function(parent, name) - local out; - - out := GraphvizGraph(name); - out!.Parent := parent; - out!.Idx := GV_GetCounter(parent); - - GV_IncCounter(parent); - return out; -end); - -InstallMethod(GV_Context, -"for a string and a positive integer", -[IsGVGraphOrDigraph, IsString], -function(parent, name) - local out; - - out := Objectify(GV_ContextType, - rec( - Name := name, - Subgraphs := GV_Map(), - Nodes := GV_Map(), - Edges := [], - Attrs := [], - Parent := parent, - Idx := GV_GetCounter(parent), - Counter := 1)); - - GV_IncCounter(parent); - return out; -end); - -# public constructors - -InstallMethod(GraphvizGraph, -"for a string", -[IsString], +InstallMethod(GraphvizGraph, "for a string", [IsString], function(name) return Objectify(GV_GraphType, rec( @@ -417,14 +26,12 @@ function(name) Counter := 1)); end); -InstallMethod(GraphvizGraph, -"for an object", -[IsObject], +InstallMethod(GraphvizGraph, "for no args", [], {} -> GraphvizGraph("")); + +InstallMethod(GraphvizGraph, "for an object", [IsObject], o -> GraphvizGraph(ViewString(o))); -InstallMethod(GraphvizDigraph, -"for a string", -[IsString], +InstallMethod(GraphvizDigraph, "for a string", [IsString], function(name) return Objectify(GV_DigraphType, rec( @@ -438,57 +45,10 @@ function(name) Counter := 1)); end); -InstallMethod(GraphvizDigraph, -"for an object", -[IsObject], -o -> GraphvizDigraph(ViewString(o))); - -InstallMethod(GraphvizGraph, "for no args", [], {} -> GraphvizGraph("")); InstallMethod(GraphvizDigraph, "for no args", [], {} -> GraphvizDigraph("")); -# ########################################################### -# Graphviz Map Functions -# ########################################################### - -InstallOtherMethod(\[\], -"for a graphviz map and an object", -[GV_IsMap, IsObject], -function(m, o) - if IsBound(m[o]) then - return m!.Data.(o); - fi; - return fail; -end); - -InstallOtherMethod(\[\]\:\=, -"for a graphviz map and two objects", -[GV_IsMap, IsObject, IsObject], -function(m, key, val) - m!.Data.(key) := val; -end); - -InstallOtherMethod(Unbind\[\], -"for a graphviz map and an object", -[GV_IsMap, IsObject], -function(m, key) - Unbind(m!.Data.(key)); -end); - -InstallOtherMethod(IsBound\[\], -"for a graphviz map and an object", -[GV_IsMap, IsObject], -{m, key} -> IsBound(m!.Data.(key))); - -DeclareOperation("GV_MapNames", [GV_IsMap]); - -InstallMethod(GV_MapNames, "for a graphviz map", -[GV_IsMap], m -> RecNames(m!.Data)); - -InstallMethod(ViewString, "for a graphviz map", [GV_IsMap], -m -> String(m!.Data)); - -InstallMethod(Size, "for a graphviz map", -[GV_IsMap], m -> Length(GV_MapNames(m))); +InstallMethod(GraphvizDigraph, "for an object", [IsObject], +o -> GraphvizDigraph(ViewString(o))); ############################################################ # Stringify @@ -545,17 +105,12 @@ InstallMethod(GraphvizName, "for a graphviz object", [IsGVObject], x -> x!.Name) InstallMethod(GraphvizAttrs, "for a graphviz object", [IsGVObject], x -> x!.Attrs); -# 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", [IsGVGraphOrDigraph], x -> x!.Nodes); InstallMethod(GraphvizNode, "for a graphviz graph and object", [IsGVGraphOrDigraph, 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", [IsGVGraphOrDigraph], x -> x!.Edges); @@ -587,29 +142,6 @@ InstallMethod(GraphvizGetSubgraph, [IsGVGraphOrDigraph, IsObject], {x, o} -> GraphvizSubgraphs(x)[ViewString(o)]); -InstallMethod(GV_IncCounter, -"for a graphviz graph", -[IsGVGraphOrDigraph], -function(x) - x!.Counter := x!.Counter + 1; -end); - -InstallMethod(GV_GetCounter, "for a graphviz graph", [IsGVGraphOrDigraph], -x -> x!.Counter); - -# Converting strings - -DeclareOperation("GV_EnsureString", [IsObject]); -# TODO required? Replace with AsString -InstallMethod(GV_EnsureString, -"for an object", -[IsObject], ViewString); - -InstallMethod(GV_EnsureString, -"for a string", -[IsString], -x -> x); - # Accessing node attributes InstallOtherMethod(\[\], @@ -674,77 +206,6 @@ InstallOtherMethod(\[\], [IsGVGraphOrDigraph, IsObject], {g, o} -> g[ViewString(o)]); -DeclareOperation("GV_HasNode", [IsGVGraphOrDigraph, IsObject]); - -InstallMethod(GV_HasNode, -"for a graphviz graph", -[IsGVGraphOrDigraph, IsString], -{g, name} -> name in GV_MapNames(GraphvizNodes(g))); - -DeclareOperation("GV_GetParent", [IsGVGraphOrDigraph]); - -InstallMethod(GV_GetParent, -"for a graphviz graph", -[IsGVGraphOrDigraph], graph -> graph!.Parent); - -DeclareOperation("GV_GraphTreeSearch", [IsGVGraphOrDigraph, IsFunction]); - -InstallMethod(GV_GraphTreeSearch, -"for a graphviz graph and a predicate", -[IsGVGraphOrDigraph, IsFunction], -function(graph, pred) - local seen, to_visit, g, key, subgraph, parent; - seen := [graph]; - to_visit := [graph]; - - while Length(to_visit) > 0 do - g := Remove(to_visit, Length(to_visit)); - - # Check this graph - if pred(g) then - return g; - fi; - - # add subgraphs to list of to visit if not visited - for key in GV_MapNames(GraphvizSubgraphs(g)) do - subgraph := GraphvizSubgraphs(g)[key]; - if not ForAny(seen, s -> IsIdenticalObj(s, subgraph)) then - Add(seen, subgraph); - Add(to_visit, subgraph); - fi; - od; - - # add parent if not visited - parent := GV_GetParent(g); - if not IsGVGraphOrDigraph(parent) then - continue; - fi; - if not ForAny(seen, s -> IsIdenticalObj(s, parent)) then - Add(seen, parent); - Add(to_visit, parent); - fi; - od; - - return fail; -end); - -DeclareOperation("GV_FindGraphWithNode", [IsGVGraphOrDigraph, IsString]); -InstallMethod(GV_FindGraphWithNode, -"for a graphviz graph and a node", -[IsGVGraphOrDigraph, IsString], -{g, n} -> GV_GraphTreeSearch(g, v -> v[n] <> fail)); - -DeclareOperation("GV_GetRoot", [IsGVGraphOrDigraph]); -InstallMethod(GV_GetRoot, -"for a graphviz graph", -[IsGVGraphOrDigraph], -function(graph) - while GV_GetParent(graph) <> fail do - graph := GV_GetParent(graph); - od; - return graph; -end); - InstallMethod(GraphvizFindGraph, "for a graphviz graph and a string", [IsGVGraphOrDigraph, IsString], @@ -755,18 +216,6 @@ InstallMethod(GraphvizFindGraph, [IsGVGraphOrDigraph, IsObject], {g, o} -> GraphvizFindGraph(g, ViewString(o))); -InstallMethod(GV_FindNode, -"for a graphviz graph and a string", -[IsGVGraphOrDigraph, IsString], -function(g, n) - local graph; - graph := GV_FindGraphWithNode(g, n); - if graph = fail then - return graph; - fi; - return graph[n]; -end); - ############################################################ # Setters ############################################################ @@ -846,26 +295,6 @@ function(x, value) return x; end); -DeclareOperation("GV_AddNode", [IsGVGraphOrDigraph, IsGVNode]); -InstallMethod(GV_AddNode, -"for a graphviz graph and node", -[IsGVGraphOrDigraph, IsGVNode], -function(x, node) - local found, error, name, nodes; - name := GraphvizName(node); - nodes := GraphvizNodes(x); - - # dont add if already node with the same name - found := GV_FindGraphWithNode(x, name); - if found <> fail then - error := "Already node with name {} in graph {}."; - ErrorNoReturn(StringFormatted(error, name, GraphvizName(found))); - fi; - - nodes[name] := node; - return x; -end); - InstallMethod(GraphvizAddNode, "for a graphviz graph and string", [IsGVGraphOrDigraph, IsString], function(x, name) @@ -890,47 +319,6 @@ InstallMethod(GraphvizAddNode, [IsGVGraphOrDigraph, IsObject], {x, name} -> GraphvizAddNode(x, ViewString(name))); -DeclareOperation("GV_AddEdge", [IsGVGraphOrDigraph, IsGVEdge]); -InstallMethod(GV_AddEdge, -"for a graphviz graph and edge", -[IsGVGraphOrDigraph, IsGVEdge], -function(x, edge) - local head, head_name, tail_name, tail, hg, error, tg; - - head := GraphvizHead(edge); - tail := GraphvizTail(edge); - head_name := GraphvizName(head); - tail_name := GraphvizName(tail); - hg := GV_FindGraphWithNode(x, head_name); - tg := GV_FindGraphWithNode(x, tail_name); - - # if not already existing, add the nodes to the graph - if hg = fail then - GV_AddNode(x, head); - fi; - if tg = fail then - GV_AddNode(x, tail); - fi; - - # make sure the nodes exist / are the same as existing ones - if hg <> fail and not IsIdenticalObj(head, hg[head_name]) then - # 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 {}."; - ErrorNoReturn(StringFormatted(error, - GraphvizName(tg), - tail_name)); - fi; - - Add(x!.Edges, edge); - return x; -end); - InstallMethod(GraphvizAddEdge, "for a graphviz graph and two graphviz nodes", [IsGVGraphOrDigraph, IsGVNode, IsGVNode], @@ -1148,295 +536,12 @@ function(obj, attr) return obj; end); -# ############################################################################## -# Stringifying -# ############################################################################## - -# @ Return DOT graph head line. -InstallMethod(GV_StringifyGraphHead, "for a string", [IsGVGraphOrDigraph], -graph -> StringFormatted("graph {} {{\n", GraphvizName(graph))); - -# @ Return DOT digraph head line. -InstallMethod(GV_StringifyDigraphHead, "for a string", [IsGVDigraph], -graph -> StringFormatted("digraph {} {{\n", GraphvizName(graph))); - -# @ Return DOT subgraph head line. -InstallMethod(GV_StringifySubgraphHead, "for a string", [IsGVGraphOrDigraph], -graph -> StringFormatted("subgraph {} {{\n", GraphvizName(graph))); - -# @ Return DOT subgraph head line. -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 name, attrs; - name := GV_StringifyNodeName(node); - attrs := GraphvizAttrs(node); - return StringFormatted("\t{}{}\n", name, GV_StringifyNodeEdgeAttrs(attrs)); -end); - -# @ Return DOT graph edge statement line. -BindGlobal("GV_StringifyEdge", -function(edge, edge_str) - local head, tail, attrs; - Assert(0, IsGVEdge(edge)); - Assert(0, IsString(edge_str)); - head := GV_StringifyNodeName(GraphvizHead(edge)); - tail := GV_StringifyNodeName(GraphvizTail(edge)); - attrs := GraphvizAttrs(edge); - - # handle : syntax - return StringFormatted("\t{} {} {}{}\n", - head, - edge_str, - tail, - GV_StringifyNodeEdgeAttrs(attrs)); -end); - -InstallMethod(GV_StringifyGraphAttrs, -"for a graphviz graph", -[IsGVGraphOrDigraph], -function(graph) - local result, attrs, kv; - attrs := GraphvizAttrs(graph); - result := ""; - - if Length(attrs) <> 0 then - Append(result, "\t"); - for kv in attrs do - Append(result, - StringFormatted("{} ", kv)); - od; - Append(result, "\n"); - fi; - return result; -end); - -InstallMethod(GV_StringifyNodeEdgeAttrs, -"for a GV_Map", -[GV_IsMap], -function(attrs) - local result, keys, key, val, n, i, tmp; - - result := ""; - n := Length(GV_MapNames(attrs)); - keys := SSortedList(GV_MapNames(attrs)); - - if n <> 0 then - Append(result, " ["); - for i in [1 .. n - 1] do - key := keys[i]; - val := attrs[key]; - - tmp := Chomp(val); - if "label" = key and StartsWith(tmp, "<<") and EndsWith(tmp, ">>") then - val := StringFormatted("{}", val); - else - if ' ' in key then - key := StringFormatted("\"{}\"", key); - fi; - if ' ' in val or '>' in val or '^' in val or '#' in val then - # TODO avoid code duplication here, and below - val := StringFormatted("\"{}\"", val); - fi; - fi; - - Append(result, - StringFormatted("{}={}, ", - key, - val)); - od; - - # handle last element - key := keys[n]; - val := attrs[key]; - - tmp := Chomp(val); - if "label" = key and StartsWith(tmp, "<<") and EndsWith(tmp, ">>") then - val := StringFormatted("{}", val); - else - if ' ' in key then - key := StringFormatted("\"{}\"", key); - fi; - if ' ' in val or '>' in val or '^' in val or '#' in val then - # TODO what are the allowed things in the value? - val := StringFormatted("\"{}\"", val); - fi; - fi; - - Append(result, - StringFormatted("{}={}]", - key, - val)); - fi; - - return result; -end); - -DeclareOperation("GV_GetIdx", [IsGVObject]); -InstallMethod(GV_GetIdx, -"for a graphviz object", -[IsGVObject], -x -> x!.Idx); - -DeclareOperation("GV_ConstructHistory", [IsGVGraphOrDigraph]); -InstallMethod(GV_ConstructHistory, -"for a graphviz graph", -[IsGVGraphOrDigraph], -function(graph) - local nodes, edges, subs, node_hist, edge_hist, subs_hist, hist; - - nodes := GraphvizNodes(graph); - edges := GraphvizEdges(graph); - subs := GraphvizSubgraphs(graph); - - node_hist := List(GV_MapNames(nodes), n -> [GV_GetIdx(nodes[n]), nodes[n]]); - subs_hist := List(GV_MapNames(subs), s -> [GV_GetIdx(subs[s]), subs[s]]); - edge_hist := List(edges, e -> [GV_GetIdx(e), e]); - - hist := Concatenation(node_hist, edge_hist, subs_hist); - SortBy(hist, v -> v[1]); - - Apply(hist, x -> x[2]); - return hist; -end); - -InstallMethod(GV_StringifyGraph, -"for a graphviz graph and a string", -[IsGVGraphOrDigraph, IsBool], -function(graph, is_subgraph) - local result, obj; - result := ""; - - # get the correct head to use - if is_subgraph then - if IsGVContext(graph) then - Append(result, GV_StringifyContextHead(graph)); - elif IsGVGraph(graph) or IsGVDigraph(graph) then - Append(result, GV_StringifySubgraphHead(graph)); - else - 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 - ErrorNoReturn("Invalid graph type."); - fi; - - Append(result, GV_StringifyGraphAttrs(graph)); - - # Add child graphviz objects - for obj in GV_ConstructHistory(graph) do - if IsGVGraphOrDigraph(obj) then - Append(result, GV_StringifyGraph(obj, true)); - elif IsGVNode(obj) then - Append(result, GV_StringifyNode(obj)); - elif IsGVEdge(obj) then - if IsGVDigraph(GV_GetRoot(graph)) then - Append(result, GV_StringifyEdge(obj, "->")); - else - Append(result, GV_StringifyEdge(obj, "--")); - fi; - else - ErrorNoReturn("Invalid graphviz object type."); - fi; - od; - - if IsGVContext(graph) then - # reset attributes following the context - if GV_GetParent(graph) <> fail then - Append(result, GV_StringifyGraphAttrs(GV_GetParent(graph))); - fi; - Append(result, "\n"); - else - Append(result, "}\n"); - fi; - return result; -end); +######################################################################## +# Stringify +######################################################################## InstallMethod(AsString, "for a graphviz graph", -[IsGVGraphOrDigraph], -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); +[IsGVGraphOrDigraph], graph -> GV_StringifyGraph(graph, false)); InstallMethod(GraphvizSetNodeLabels, "for a graphviz graph and list of colors", @@ -1468,3 +573,18 @@ function(gv, colors) od; return gv; end); + +InstallGlobalFunction(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); diff --git a/gap/gv.gd b/gap/gv.gd new file mode 100644 index 0000000..ec6461b --- /dev/null +++ b/gap/gv.gd @@ -0,0 +1,216 @@ +############################################################################# +## +## gv.gd +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +## This file contains declarations of the internal/private functions for the +## graphviz package. + +DeclareOperation("GV_GetCounter", [IsGVGraphOrDigraph]); +DeclareOperation("GV_IncCounter", [IsGVGraphOrDigraph]); +DeclareCategory("GV_IsMap", IsObject); +DeclareAttribute("Size", GV_IsMap); + +DeclareOperation("GV_StringifyGraphHead", [IsGVGraphOrDigraph]); +DeclareOperation("GV_StringifyDigraphHead", [IsGVGraphOrDigraph]); +DeclareOperation("GV_StringifySubgraphHead", [IsGVGraphOrDigraph]); +DeclareOperation("GV_StringifyContextHead", [IsGVGraphOrDigraph]); +DeclareOperation("GV_StringifyNode", [IsGVNode]); +DeclareOperation("GV_StringifyGraphAttrs", [IsGVGraphOrDigraph]); +DeclareOperation("GV_StringifyNodeEdgeAttrs", [GV_IsMap]); +DeclareOperation("GV_StringifyGraph", [IsGVGraphOrDigraph, IsBool]); + +DeclareOperation("GV_FindNode", [IsGVGraphOrDigraph, IsObject]); + +DeclareOperation("GV_Pluralize", [IsInt, IsString]); + +DeclareOperation("GV_Node", [IsGVGraphOrDigraph, IsString]); +DeclareOperation("GV_Edge", [IsGVGraphOrDigraph, IsGVNode, IsGVNode]); +DeclareOperation("GV_Graph", [IsGVGraphOrDigraph, IsString]); +DeclareOperation("GV_Digraph", [IsGVDigraph, IsString]); +DeclareOperation("GV_Context", [IsGVGraphOrDigraph, IsString]); +DeclareOperation("GV_Map", []); +DeclareOperation("GV_MapNames", [GV_IsMap]); + +# TODO required? Replace with AsString or just String? +DeclareOperation("GV_EnsureString", [IsObject]); + +DeclareOperation("GV_HasNode", [IsGVGraphOrDigraph, IsObject]); + +DeclareOperation("GV_GetParent", [IsGVGraphOrDigraph]); +DeclareOperation("GV_GraphTreeSearch", [IsGVGraphOrDigraph, IsFunction]); +DeclareOperation("GV_FindGraphWithNode", [IsGVGraphOrDigraph, IsString]); +DeclareOperation("GV_GetRoot", [IsGVGraphOrDigraph]); +DeclareOperation("GV_AddNode", [IsGVGraphOrDigraph, IsGVNode]); +DeclareOperation("GV_AddEdge", [IsGVGraphOrDigraph, IsGVEdge]); +DeclareOperation("GV_GetIdx", [IsGVObject]); +DeclareOperation("GV_ConstructHistory", [IsGVGraphOrDigraph]); + +DeclareGlobalFunction("GV_IsValidColor"); +DeclareGlobalFunction("GV_ErrorIfNotNodeColoring"); + +BindGlobal("GV_ObjectFamily", + NewFamily("GV_ObjectFamily", IsGVObject)); + +BindGlobal("GV_DigraphType", NewType(GV_ObjectFamily, + IsGVDigraph and + IsComponentObjectRep and + IsAttributeStoringRep)); + +BindGlobal("GV_GraphType", NewType(GV_ObjectFamily, + IsGVGraph and + IsComponentObjectRep and + IsAttributeStoringRep)); + +BindGlobal("GV_KNOWN_ATTRS", [ + "_background", "area", "arrowhead", "arrowsize", "arrowtail", "bb", + "beautify", "bgcolor", "center", "charset", "class", "cluster", "clusterrank", + "color", "colorscheme", "comment", "compound", "concentrate", "constraint", + "Damping", "decorate", "defaultdist", "dim", "dimen", "dir", + "diredgeconstraints", "distortion", "dpi", "edgehref", "edgetarget", + "edgetooltip", "edgeURL", "epsilon", "esep", "fillcolor", "fixedsize", + "fontcolor", "fontname", "fontnames", "fontpath", "fontsize", "forcelabels", + "gradientangle", "group", "head_lp", "headclip", "headhref", "headlabel", + "headport", "headtarget", "headtooltip", "headURL", "height", "href", "id", + "image", "imagepath", "imagepos", "imagescale", "inputscale", "K", "label", + "label_scheme", "labelangle", "labeldistance", "labelfloat", "labelfontcolor", + "labelfontname", "labelfontsize", "labelhref", "labeljust", "labelloc", + "labeltarget", "labeltooltip", "labelURL", "landscape", "layer", + "layerlistsep", "layers", "layerselect", "layersep", "layout", "len", + "levels", "levelsgap", "lhead", "lheight", "linelength", "lp", "ltail", + "lwidth", "margin", "maxiter", "mclimit", "mindist", "minlen", "mode", + "model", "newrank", "nodesep", "nojustify", "normalize", "notranslate", + "nslimit", "nslimit1", "oneblock", "ordering", "orientation", "outputorder", + "overlap", "overlap_scaling", "overlap_shrink", "pack", "packmode", "pad", + "page", "pagedir", "pencolor", "penwidth", "peripheries", "pin", "pos", + "quadtree", "quantum", "rank", "rankdir", "ranksep", "ratio", "rects", + "regular", "remincross", "repulsiveforce", "resolution", "root", "rotate", + "rotation", "samehead", "sametail", "samplepoints", "scale", "searchsize", + "sep", "shape", "shapefile", "showboxes", "sides", "size", "skew", + "smoothing", "sortv", "splines", "start", "style", "stylesheet", "tail_lp", + "tailclip", "tailhref", "taillabel", "tailport", "tailtarget", "tailtooltip", + "tailURL", "target", "TBbalance", "tooltip", "truecolor", "URL", "vertices", + "viewport", "voro_margin", "weight", "width", "xdotversion", "xlabel", "xlp", + "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"]); diff --git a/gap/gv.gi b/gap/gv.gi new file mode 100644 index 0000000..185aa4b --- /dev/null +++ b/gap/gv.gi @@ -0,0 +1,679 @@ +############################################################################# +## +## gv.gi +## Copyright (C) 2024 James Mitchell +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# code from the GAP standard library +InstallMethod(GV_Pluralize, +"for an integer and a string", +[IsInt, IsString], +function(args...) + local nargs, i, count, include_num, str, len, out; + + nargs := Length(args); + if nargs >= 1 and IsInt(args[1]) and args[1] >= 0 then + i := 2; + count := args[1]; + include_num := true; + else + i := 1; + include_num := false; # if not given, assume pluralization is wanted. + fi; + + if not (nargs in [i, i + 1] and + IsString(args[i]) and + (nargs = i or IsString(args[i + 1]))) then + ErrorNoReturn("Usage: GV_Pluralize([, ][, ])"); + fi; + + str := args[i]; + len := Length(str); + + if len = 0 then + ErrorNoReturn("the argument must be a non-empty string"); + elif include_num and count = 1 then # no pluralization needed + return Concatenation("\>1\< ", str); + elif nargs = i + 1 then # pluralization given + out := args[i + 1]; + elif len <= 2 then + out := Concatenation(str, "s"); + + # Guess and return the plural form of . + # Inspired by the "Ruby on Rails" inflection rules. + + # Uncountable nouns + elif str in ["equipment", "information"] then + out := str; + + # Irregular plurals + elif str = "axis" then + out := "axes"; + elif str = "child" then + out := "children"; + elif str = "person" then + out := "people"; + + # Peculiar endings + elif EndsWith(str, "ix") or EndsWith(str, "ex") then + out := Concatenation(str{[1 .. len - 2]}, "ices"); + elif EndsWith(str, "x") then + out := Concatenation(str, "es"); + elif EndsWith(str, "tum") or EndsWith(str, "ium") then + out := Concatenation(str{[1 .. len - 2]}, "a"); + elif EndsWith(str, "sis") then + out := Concatenation(str{[1 .. len - 3]}, "ses"); + elif EndsWith(str, "fe") and not EndsWith(str, "ffe") then + out := Concatenation(str{[1 .. len - 2]}, "ves"); + elif EndsWith(str, "lf") or EndsWith(str, "rf") or EndsWith(str, "loaf") then + out := Concatenation(str{[1 .. len - 1]}, "ves"); + elif EndsWith(str, "y") and not str[len - 1] in "aeiouy" then + out := Concatenation(str{[1 .. len - 1]}, "ies"); + elif str{[len - 1, len]} in ["ch", "ss", "sh"] then + out := Concatenation(str, "es"); + elif EndsWith(str, "s") then + out := str; + + # Default to appending 's' + else + out := Concatenation(str, "s"); + fi; + + if include_num then + return Concatenation("\>", String(args[1]), "\< ", out); + fi; + return out; +end); + +############################################################################### +# Family + type +############################################################################### + +BindGlobal("GV_MapType", NewType(GV_ObjectFamily, + GV_IsMap and + IsComponentObjectRep and + IsAttributeStoringRep)); + +BindGlobal("GV_NodeType", NewType(GV_ObjectFamily, + IsGVNode and + IsComponentObjectRep and + IsAttributeStoringRep)); + +BindGlobal("GV_EdgeType", NewType(GV_ObjectFamily, + IsGVEdge and + IsComponentObjectRep and + IsAttributeStoringRep)); + +BindGlobal("GV_ContextType", NewType(GV_ObjectFamily, + IsGVContext and + IsComponentObjectRep and + IsAttributeStoringRep)); + +InstallMethod(\=, "for IsGVNode and IsGVNode", +[IsGVNode, IsGVNode], +{n1, n2} -> GraphvizName(n1) = GraphvizName(n2)); + +############################################################################### +# Constructors etc +############################################################################### + + +InstallMethod(GV_Map, "for no args", +[], {} -> Objectify(GV_MapType, rec(Data := rec()))); + +InstallMethod(GV_Node, "for a string", +[IsGVGraphOrDigraph, IsString], +function(graph, name) + local out; + if Length(name) = 0 then + ErrorNoReturn("the 2nd argument (string/node name) cannot be empty"); + fi; + out := Objectify(GV_NodeType, + rec( + Name := name, + Attrs := GV_Map(), + Idx := GV_GetCounter(graph))); + GV_IncCounter(graph); + return out; +end); + +InstallMethod(GV_Edge, "for two graphviz nodes", +[IsGVGraphOrDigraph, IsGVNode, IsGVNode], +function(graph, head, tail) + local out; + out := Objectify(GV_EdgeType, + rec( + Name := "", + Head := head, + Tail := tail, + Attrs := GV_Map(), + Idx := GV_GetCounter(graph))); + GV_IncCounter(graph); + return out; +end); + +# Graph constructors + +InstallMethod(GV_Digraph, +"for a graphviz digraph and a string", +[IsGVDigraph, IsString], +function(parent, name) + local out; + + out := GraphvizDigraph(name); + out!.Parent := parent; + out!.Idx := GV_GetCounter(parent); + + GV_IncCounter(parent); + return out; +end); + +InstallMethod(GV_Graph, +"for a graphviz graph and a string", +[IsGVGraphOrDigraph, IsString], +function(parent, name) + local out; + + out := GraphvizGraph(name); + out!.Parent := parent; + out!.Idx := GV_GetCounter(parent); + + GV_IncCounter(parent); + return out; +end); + +InstallMethod(GV_Context, +"for a string and a positive integer", +[IsGVGraphOrDigraph, IsString], +function(parent, name) + local out; + + out := Objectify(GV_ContextType, + rec( + Name := name, + Subgraphs := GV_Map(), + Nodes := GV_Map(), + Edges := [], + Attrs := [], + Parent := parent, + Idx := GV_GetCounter(parent), + Counter := 1)); + + GV_IncCounter(parent); + return out; +end); + +############################################################ +# Graphviz Map Functions +############################################################ + +InstallOtherMethod(\[\], +"for a graphviz map and an object", +[GV_IsMap, IsObject], +function(m, o) + if IsBound(m[o]) then + return m!.Data.(o); + fi; + return fail; +end); + +InstallOtherMethod(\[\]\:\=, +"for a graphviz map and two objects", +[GV_IsMap, IsObject, IsObject], +function(m, key, val) + m!.Data.(key) := val; +end); + +InstallOtherMethod(Unbind\[\], +"for a graphviz map and an object", +[GV_IsMap, IsObject], +function(m, key) + Unbind(m!.Data.(key)); +end); + +InstallOtherMethod(IsBound\[\], +"for a graphviz map and an object", +[GV_IsMap, IsObject], +{m, key} -> IsBound(m!.Data.(key))); + + +InstallMethod(GV_MapNames, "for a graphviz map", +[GV_IsMap], m -> RecNames(m!.Data)); + +InstallMethod(ViewString, "for a graphviz map", [GV_IsMap], +m -> String(m!.Data)); + +InstallMethod(Size, "for a graphviz map", +[GV_IsMap], m -> Length(GV_MapNames(m))); + +# ?? + +InstallMethod(GV_IncCounter, +"for a graphviz graph", +[IsGVGraphOrDigraph], +function(x) + x!.Counter := x!.Counter + 1; +end); + +InstallMethod(GV_GetCounter, "for a graphviz graph", [IsGVGraphOrDigraph], +x -> x!.Counter); + +# Converting strings + +InstallMethod(GV_EnsureString, +"for an object", +[IsObject], ViewString); + +InstallMethod(GV_EnsureString, +"for a string", +[IsString], +x -> x); + +# Nodes + +InstallMethod(GV_HasNode, +"for a graphviz graph", +[IsGVGraphOrDigraph, IsString], +{g, name} -> name in GV_MapNames(GraphvizNodes(g))); + +InstallMethod(GV_GetParent, +"for a graphviz graph", +[IsGVGraphOrDigraph], graph -> graph!.Parent); + +InstallMethod(GV_GraphTreeSearch, +"for a graphviz graph and a predicate", +[IsGVGraphOrDigraph, IsFunction], +function(graph, pred) + local seen, to_visit, g, key, subgraph, parent; + seen := [graph]; + to_visit := [graph]; + + while Length(to_visit) > 0 do + g := Remove(to_visit, Length(to_visit)); + + # Check this graph + if pred(g) then + return g; + fi; + + # add subgraphs to list of to visit if not visited + for key in GV_MapNames(GraphvizSubgraphs(g)) do + subgraph := GraphvizSubgraphs(g)[key]; + if not ForAny(seen, s -> IsIdenticalObj(s, subgraph)) then + Add(seen, subgraph); + Add(to_visit, subgraph); + fi; + od; + + # add parent if not visited + parent := GV_GetParent(g); + if not IsGVGraphOrDigraph(parent) then + continue; + fi; + if not ForAny(seen, s -> IsIdenticalObj(s, parent)) then + Add(seen, parent); + Add(to_visit, parent); + fi; + od; + + return fail; +end); + +InstallMethod(GV_FindGraphWithNode, +"for a graphviz graph and a node", +[IsGVGraphOrDigraph, IsString], +{g, n} -> GV_GraphTreeSearch(g, v -> v[n] <> fail)); + +InstallMethod(GV_GetRoot, +"for a graphviz graph", +[IsGVGraphOrDigraph], +function(graph) + while GV_GetParent(graph) <> fail do + graph := GV_GetParent(graph); + od; + return graph; +end); + +InstallMethod(GV_FindNode, +"for a graphviz graph and a string", +[IsGVGraphOrDigraph, IsString], +function(g, n) + local graph; + graph := GV_FindGraphWithNode(g, n); + if graph = fail then + return graph; + fi; + return graph[n]; +end); + +InstallMethod(GV_AddNode, +"for a graphviz graph and node", +[IsGVGraphOrDigraph, IsGVNode], +function(x, node) + local found, error, name, nodes; + name := GraphvizName(node); + nodes := GraphvizNodes(x); + + # dont add if already node with the same name + found := GV_FindGraphWithNode(x, name); + if found <> fail then + error := "Already node with name {} in graph {}."; + ErrorNoReturn(StringFormatted(error, name, GraphvizName(found))); + fi; + + nodes[name] := node; + return x; +end); + +InstallMethod(GV_AddEdge, +"for a graphviz graph and edge", +[IsGVGraphOrDigraph, IsGVEdge], +function(x, edge) + local head, head_name, tail_name, tail, hg, error, tg; + + head := GraphvizHead(edge); + tail := GraphvizTail(edge); + head_name := GraphvizName(head); + tail_name := GraphvizName(tail); + hg := GV_FindGraphWithNode(x, head_name); + tg := GV_FindGraphWithNode(x, tail_name); + + # if not already existing, add the nodes to the graph + if hg = fail then + GV_AddNode(x, head); + fi; + if tg = fail then + GV_AddNode(x, tail); + fi; + + # make sure the nodes exist / are the same as existing ones + if hg <> fail and not IsIdenticalObj(head, hg[head_name]) then + # 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 {}."; + ErrorNoReturn(StringFormatted(error, + GraphvizName(tg), + tail_name)); + fi; + + Add(x!.Edges, edge); + return x; +end); + +############################################################################### +# Stringifying +############################################################################### + +# @ Return DOT graph head line. +InstallMethod(GV_StringifyGraphHead, "for a string", [IsGVGraphOrDigraph], +graph -> StringFormatted("graph {} {{\n", GraphvizName(graph))); + +# @ Return DOT digraph head line. +InstallMethod(GV_StringifyDigraphHead, "for a string", [IsGVDigraph], +graph -> StringFormatted("digraph {} {{\n", GraphvizName(graph))); + +# @ Return DOT subgraph head line. +InstallMethod(GV_StringifySubgraphHead, "for a string", [IsGVGraphOrDigraph], +graph -> StringFormatted("subgraph {} {{\n", GraphvizName(graph))); + +# @ Return DOT subgraph head line. +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 name, attrs; + name := GV_StringifyNodeName(node); + attrs := GraphvizAttrs(node); + return StringFormatted("\t{}{}\n", name, GV_StringifyNodeEdgeAttrs(attrs)); +end); + +# @ Return DOT graph edge statement line. +BindGlobal("GV_StringifyEdge", +function(edge, edge_str) + local head, tail, attrs; + Assert(0, IsGVEdge(edge)); + Assert(0, IsString(edge_str)); + head := GV_StringifyNodeName(GraphvizHead(edge)); + tail := GV_StringifyNodeName(GraphvizTail(edge)); + attrs := GraphvizAttrs(edge); + + # handle : syntax + return StringFormatted("\t{} {} {}{}\n", + head, + edge_str, + tail, + GV_StringifyNodeEdgeAttrs(attrs)); +end); + +InstallMethod(GV_StringifyGraphAttrs, +"for a graphviz graph", +[IsGVGraphOrDigraph], +function(graph) + local result, attrs, kv; + attrs := GraphvizAttrs(graph); + result := ""; + + if Length(attrs) <> 0 then + Append(result, "\t"); + for kv in attrs do + Append(result, + StringFormatted("{} ", kv)); + od; + Append(result, "\n"); + fi; + return result; +end); + +InstallMethod(GV_StringifyNodeEdgeAttrs, +"for a GV_Map", +[GV_IsMap], +function(attrs) + local result, keys, key, val, n, i, tmp; + + result := ""; + n := Length(GV_MapNames(attrs)); + keys := SSortedList(GV_MapNames(attrs)); + + if n <> 0 then + Append(result, " ["); + for i in [1 .. n - 1] do + key := keys[i]; + val := attrs[key]; + + tmp := Chomp(val); + if "label" = key and StartsWith(tmp, "<<") and EndsWith(tmp, ">>") then + val := StringFormatted("{}", val); + else + if ' ' in key then + key := StringFormatted("\"{}\"", key); + fi; + if ' ' in val or '>' in val or '^' in val or '#' in val then + # TODO avoid code duplication here, and below + val := StringFormatted("\"{}\"", val); + fi; + fi; + + Append(result, + StringFormatted("{}={}, ", + key, + val)); + od; + + # handle last element + key := keys[n]; + val := attrs[key]; + + tmp := Chomp(val); + if "label" = key and StartsWith(tmp, "<<") and EndsWith(tmp, ">>") then + val := StringFormatted("{}", val); + else + if ' ' in key then + key := StringFormatted("\"{}\"", key); + fi; + if ' ' in val or '>' in val or '^' in val or '#' in val then + # TODO what are the allowed things in the value? + val := StringFormatted("\"{}\"", val); + fi; + fi; + + Append(result, + StringFormatted("{}={}]", + key, + val)); + fi; + + return result; +end); + +InstallMethod(GV_GetIdx, +"for a graphviz object", +[IsGVObject], +x -> x!.Idx); + +InstallMethod(GV_ConstructHistory, +"for a graphviz graph", +[IsGVGraphOrDigraph], +function(graph) + local nodes, edges, subs, node_hist, edge_hist, subs_hist, hist; + + nodes := GraphvizNodes(graph); + edges := GraphvizEdges(graph); + subs := GraphvizSubgraphs(graph); + + node_hist := List(GV_MapNames(nodes), n -> [GV_GetIdx(nodes[n]), nodes[n]]); + subs_hist := List(GV_MapNames(subs), s -> [GV_GetIdx(subs[s]), subs[s]]); + edge_hist := List(edges, e -> [GV_GetIdx(e), e]); + + hist := Concatenation(node_hist, edge_hist, subs_hist); + SortBy(hist, v -> v[1]); + + Apply(hist, x -> x[2]); + return hist; +end); + +InstallMethod(GV_StringifyGraph, +"for a graphviz graph and a string", +[IsGVGraphOrDigraph, IsBool], +function(graph, is_subgraph) + local result, obj; + result := ""; + + # get the correct head to use + if is_subgraph then + if IsGVContext(graph) then + Append(result, GV_StringifyContextHead(graph)); + elif IsGVGraph(graph) or IsGVDigraph(graph) then + Append(result, GV_StringifySubgraphHead(graph)); + else + 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 + ErrorNoReturn("Invalid graph type."); + fi; + + Append(result, GV_StringifyGraphAttrs(graph)); + + # Add child graphviz objects + for obj in GV_ConstructHistory(graph) do + if IsGVGraphOrDigraph(obj) then + Append(result, GV_StringifyGraph(obj, true)); + elif IsGVNode(obj) then + Append(result, GV_StringifyNode(obj)); + elif IsGVEdge(obj) then + if IsGVDigraph(GV_GetRoot(graph)) then + Append(result, GV_StringifyEdge(obj, "->")); + else + Append(result, GV_StringifyEdge(obj, "--")); + fi; + else + ErrorNoReturn("Invalid graphviz object type."); + fi; + od; + + if IsGVContext(graph) then + # reset attributes following the context + if GV_GetParent(graph) <> fail then + Append(result, GV_StringifyGraphAttrs(GV_GetParent(graph))); + fi; + Append(result, "\n"); + else + Append(result, "}\n"); + fi; + return result; +end); + +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); + +InstallGlobalFunction(GV_IsValidColor, +c -> IsString(c) and (GV_IsValidRGBColor(c) or c in GV_ValidColorNames)); + +InstallGlobalFunction(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, ErrorIfNotValidColor); +end); diff --git a/gap/splash.gd b/gap/splash.gd new file mode 100644 index 0000000..e69de29 diff --git a/init.g b/init.g index 7d8d023..b6ccf00 100644 --- a/init.g +++ b/init.g @@ -10,3 +10,4 @@ ReadPackage("graphviz", "gap/error.gd"); ReadPackage("graphviz", "gap/dot.gd"); +ReadPackage("graphviz", "gap/gv.gd"); diff --git a/read.g b/read.g index 794be60..a13f5fb 100644 --- a/read.g +++ b/read.g @@ -10,4 +10,5 @@ ReadPackage("graphviz", "gap/dot.gi"); ReadPackage("graphviz", "gap/error.gi"); +ReadPackage("graphviz", "gap/gv.gi"); ReadPackage("graphviz", "gap/splash.gi"); From 39d0b0c821fea48cdd26c7d912f444fa340a151f Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Mon, 13 May 2024 10:53:41 +0100 Subject: [PATCH 05/38] etc: add code-coverage-test-gap.py --- etc/code-coverage-test-gap.py | 107 ++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100755 etc/code-coverage-test-gap.py diff --git a/etc/code-coverage-test-gap.py b/etc/code-coverage-test-gap.py new file mode 100755 index 0000000..e50ea5a --- /dev/null +++ b/etc/code-coverage-test-gap.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 +""" +This is a simple script to run code coverage for some test files. +""" +# pylint: disable=invalid-name + +import argparse +import os +import re +import subprocess +import sys +import tempfile + +from os.path import exists, isdir, isfile +from os import getcwd + +_ERR_PREFIX = "\033[31mcode-coverage-test-gap.py: error: " +_INFO_PREFIX = "\033[0m\033[1m" + +_PARSER = argparse.ArgumentParser( + prog="code-coverage-test-gap.py", usage="%(prog)s [options]" +) +_PARSER.add_argument( + "tstfiles", + nargs="+", + type=str, + help="the test files you want to check code coverage for" + + "(must be at least one)", +) +_PARSER.add_argument( + "--gap-root", + nargs="?", + type=str, + help="the gap root directory (default: ~/gap)", + default="~/gap/", +) +_PARSER.add_argument( + "--open", + nargs="?", + type=str, + help=("open the html page for this file (default: None)"), + default=None, +) + +_ARGS = _PARSER.parse_args() +if not _ARGS.gap_root[-1] == "/": + _ARGS.gap_root += "/" + +if exists("gap") and isdir("gap"): + _PROFILE_DIR = "/gap/" +elif exists("lib") and isdir("lib"): + _PROFILE_DIR = "/lib/" +else: + sys.exit(f"{_ERR_PREFIX}no directory gap or lib to profile!\033[0m") + +_ARGS.gap_root = os.path.expanduser(_ARGS.gap_root) +if not (exists(_ARGS.gap_root) and isdir(_ARGS.gap_root)): + sys.exit(f"{_ERR_PREFIX}can't find GAP root directory!\033[0m") + +for f in _ARGS.tstfiles: + if not (exists(f) and isfile(f)): + sys.exit(f"{_ERR_PREFIX}{f} does not exist!\033[0m") + +_DIR = tempfile.mkdtemp() +print(f"{_INFO_PREFIX}Using temporary directory: {_DIR}\033[0m") + +_COMMANDS = 'echo "' +_COMMANDS += "".join(rf"Test(\"{f}\");;\n" for f in _ARGS.tstfiles) +_COMMANDS += rf"""UncoverageLineByLine();; +LoadPackage(\"profiling\", false);; +filesdir := \"{getcwd()}{_PROFILE_DIR}\";;\n""" + +_COMMANDS += rf"outdir := \"{_DIR}\";;\n" +_COMMANDS += rf"x := ReadLineByLineProfile(\"{_DIR}/profile.gz\");;\n" +_COMMANDS += 'OutputAnnotatedCodeCoverageFiles(x, filesdir, outdir);"' + +_RUN_GAP = f"{_ARGS.gap_root}/gap -A -m 1g -T --cover {_DIR}/profile.gz" + +with subprocess.Popen(_COMMANDS, stdout=subprocess.PIPE, shell=True) as pro1: + try: + with subprocess.Popen(_RUN_GAP, stdin=pro1.stdout, shell=True) as pro2: + pro2.wait() + except KeyboardInterrupt: + pro1.terminate() + pro1.wait() + sys.exit("\033[31mKilled!\033[0m") + except (subprocess.CalledProcessError, IOError, OSError): + sys.exit(_ERR_PREFIX + "Something went wrong calling GAP!\033[0m") + + +def rewrite_fname(fname: str) -> str: + return fname.replace("/", "_") + + +suffix = "" +if _ARGS.open: + filename = f"{_DIR}/{rewrite_fname(getcwd())}/{rewrite_fname(_ARGS.open)}.html" + p = re.compile(r"") + with open(filename, "r", encoding="utf-8") as f: + m = p.search(f.read()) + if m: + suffix += "#line" + m.group(1) +else: + filename = _DIR + "/index.html" +print(f"{_INFO_PREFIX}\nSUCCESS!\033[0m") +print(f"{_INFO_PREFIX} See {filename}") +sys.exit(0) From 3e436747c6ee08ac32b97e2cf77ba99e5c996b93 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Mon, 13 May 2024 11:27:16 +0100 Subject: [PATCH 06/38] Improve error messages --- gap/dot.gi | 19 ++++++++++--------- tst/graph.tst | 22 ---------------------- 2 files changed, 10 insertions(+), 31 deletions(-) diff --git a/gap/dot.gi b/gap/dot.gi index 510f54a..cbba2c2 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -28,9 +28,6 @@ end); InstallMethod(GraphvizGraph, "for no args", [], {} -> GraphvizGraph("")); -InstallMethod(GraphvizGraph, "for an object", [IsObject], -o -> GraphvizGraph(ViewString(o))); - InstallMethod(GraphvizDigraph, "for a string", [IsString], function(name) return Objectify(GV_DigraphType, @@ -47,9 +44,6 @@ end); InstallMethod(GraphvizDigraph, "for no args", [], {} -> GraphvizDigraph("")); -InstallMethod(GraphvizDigraph, "for an object", [IsObject], -o -> GraphvizDigraph(ViewString(o))); - ############################################################ # Stringify ############################################################ @@ -119,10 +113,17 @@ InstallMethod(GraphvizEdges, [IsGVGraphOrDigraph, IsObject, IsObject], function(gv, head, tail) head := GraphvizNode(gv, head); + if head = fail then + ErrorNoReturn("the 2nd argument (head of an edge) is not a node ", + "of the 1st argument (a graphviz graph or digraph)"); + fi; tail := GraphvizNode(gv, tail); - # TODO if head = fail then... - return Filtered(GraphvizEdges(gv), x -> GraphvizHead(x) = head and - GraphvizTail(x) = tail); + if tail = fail then + ErrorNoReturn("the 2nd argument (head of an edge) is not a node ", + "of the 1st argument (a graphviz graph or digraph)"); + fi; + return Filtered(GraphvizEdges(gv), + x -> GraphvizHead(x) = head and GraphvizTail(x) = tail); end); InstallMethod(GraphvizSubgraphs, "for a graphviz graph", [IsGVGraphOrDigraph], diff --git a/tst/graph.tst b/tst/graph.tst index 175d1d1..dcdd261 100644 --- a/tst/graph.tst +++ b/tst/graph.tst @@ -208,28 +208,6 @@ gap> g[1]; gap> g[["a"]]; - -# Test making a graph with a non-string name -gap> g := GraphvizGraph(11); - - -# Test setting a graph name to a non-string value -gap> g := GraphvizGraph(11); - -gap> GraphvizSetName(g, ["a"]); - - -# Test making a digraph with a non-string name -gap> g := GraphvizDigraph(11); - - -# Test setting a digraph name to a non-string value -gap> g := GraphvizDigraph(11); - -gap> GraphvizSetName(g, ["a"]); - - -# Test set label (graph) gap> g := GraphvizGraph();; gap> GraphvizSetAttr(g, "label", "test");; gap> GraphvizAttrs(g); From 2b85ffd1e421227dfafb1eb6b90921f323dba420 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Mon, 13 May 2024 11:29:22 +0100 Subject: [PATCH 07/38] Replace GV with Graphviz in some places --- gap/dot.gd | 85 +++++++++++++++++------------------ gap/dot.gi | 120 +++++++++++++++++++++++++------------------------- gap/gv.gd | 54 +++++++++++------------ gap/gv.gi | 84 +++++++++++++++++------------------ gap/splash.gi | 4 +- 5 files changed, 172 insertions(+), 175 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index 57891d0..8856d38 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -30,22 +30,19 @@ #! @Section Graphviz Categories #! @BeginGroup Filters -#! @Description Every object in graphviz belongs to the IsGVObject category. -#! The categories following it are for further specificity on the type of -#! objects. These are graphs, digraphs, nodes and edges respectively. -#! All are direct subcategories of IsGVObject excluding IsGVDigraph which is a -#! subcategory of is GVGraph. - -# TODO replace GV -> graphviz -DeclareCategory("IsGVObject", IsObject); -DeclareCategory("IsGVGraphOrDigraph", IsGVObject); -# TODO change to IsGVObject below, since digraphs aren't a special kind of -# graph, unless I'm (JDM) mistaken? -DeclareCategory("IsGVGraph", IsGVGraphOrDigraph); -DeclareCategory("IsGVDigraph", IsGVGraphOrDigraph); -DeclareCategory("IsGVContext", IsGVGraphOrDigraph); -DeclareCategory("IsGVNode", IsGVObject); -DeclareCategory("IsGVEdge", IsGVObject); +#! @Description Every object in graphviz belongs to the IsGraphvizObject +#! category. The categories following it are for further specificity on the +#! type of objects. These are graphs, digraphs, nodes and edges respectively. +#! All are direct subcategories of IsGraphvizObject excluding IsGraphvizDigraph +#! which is a subcategory of is IsGraphvizGraph. + +DeclareCategory("IsGraphvizObject", IsObject); +DeclareCategory("IsGraphvizGraphOrDigraph", IsGraphvizObject); +DeclareCategory("IsGraphvizGraph", IsGraphvizGraphOrDigraph); +DeclareCategory("IsGraphvizDigraph", IsGraphvizGraphOrDigraph); +DeclareCategory("IsGraphvizContext", IsGraphvizGraphOrDigraph); +DeclareCategory("IsGraphvizNode", IsGraphvizObject); +DeclareCategory("IsGraphvizEdge", IsGraphvizObject); #! @EndGroup #! @Section Constructors @@ -77,12 +74,12 @@ DeclareOperation("GraphvizDigraph", []); #! @Arguments obj #! @Returns the name of the provided graphviz object #! @Description Gets the name of the provided graphviz object. -DeclareOperation("GraphvizName", [IsGVObject]); +DeclareOperation("GraphvizName", [IsGraphvizObject]); #! @Arguments obj #! @Returns the attributes of the provided graphviz object #! @Description Gets the attributes of the provided graphviz object. -DeclareOperation("GraphvizAttrs", [IsGVObject]); +DeclareOperation("GraphvizAttrs", [IsGraphvizObject]); #! @Subsection For only graphs and digraphs. @@ -90,14 +87,14 @@ DeclareOperation("GraphvizAttrs", [IsGVObject]); #! @Returns the nodes of the provided graphviz graph. #! @Description Gets the nodes of the provided graphviz graph. #! Node names can only be [a-zA-Z0-9_£] TODO check exact docs. -DeclareOperation("GraphvizNodes", [IsGVGraphOrDigraph]); -DeclareOperation("GraphvizNode", [IsGVGraphOrDigraph, IsObject]); +DeclareOperation("GraphvizNodes", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GraphvizNode", [IsGraphvizGraphOrDigraph, IsObject]); #! @Arguments graph #! @Returns the subgraphs of the provided graphviz graph. #! @Description gets the subgraphs of a provided graphviz graph. -DeclareOperation("GraphvizSubgraphs", [IsGVGraphOrDigraph]); -DeclareOperation("GraphvizGetSubgraph", [IsGVGraphOrDigraph, IsObject]); +DeclareOperation("GraphvizSubgraphs", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GraphvizGetSubgraph", [IsGraphvizGraphOrDigraph, IsObject]); #! @Arguments graph, name #! @Returns a graph with the provided name. @@ -106,25 +103,25 @@ DeclareOperation("GraphvizGetSubgraph", [IsGVGraphOrDigraph, IsObject]); #! with the provided name. #! It returns the graph if it exists. #! If no such graph exists then it will return fail. -DeclareOperation("GraphvizFindGraph", [IsGVGraphOrDigraph, IsObject]); +DeclareOperation("GraphvizFindGraph", [IsGraphvizGraphOrDigraph, IsObject]); #! @Arguments graph #! @Returns the edges of the provided graphviz graph. #! @Description Gets the edges of the provided graphviz graph. -DeclareOperation("GraphvizEdges", [IsGVGraphOrDigraph]); -DeclareOperation("GraphvizEdges", [IsGVGraphOrDigraph, IsObject, IsObject]); +DeclareOperation("GraphvizEdges", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GraphvizEdges", [IsGraphvizGraphOrDigraph, IsObject, IsObject]); #! @Subsection For only edges. #! @Arguments edge #! @Returns the head of the provided graphviz edge. #! @Description Gets the head of the provided graphviz graph. -DeclareOperation("GraphvizHead", [IsGVEdge]); +DeclareOperation("GraphvizHead", [IsGraphvizEdge]); #! @Arguments edge #! @Returns the head of the provided graphviz tail. #! @Description Gets the tail of the provided graphviz graph. -DeclareOperation("GraphvizTail", [IsGVEdge]); +DeclareOperation("GraphvizTail", [IsGraphvizEdge]); #! @Section Set Operations #! This section covers operations for modifying graphviz objects. @@ -134,13 +131,13 @@ DeclareOperation("GraphvizTail", [IsGVEdge]); #! @Arguments graph, name #! @Returns the modified graph. #! @Description Sets the name of a graphviz graph or digraph. -DeclareOperation("GraphvizSetName", [IsGVGraphOrDigraph, IsObject]); +DeclareOperation("GraphvizSetName", [IsGraphvizGraphOrDigraph, IsObject]); #! @Arguments graph, node #! @Returns the modified graph. #! @Description Adds a node to the graph. #! If a node with the same name is already present the operation fails. -DeclareOperation("GraphvizAddNode", [IsGVGraphOrDigraph, IsObject]); +DeclareOperation("GraphvizAddNode", [IsGraphvizGraphOrDigraph, IsObject]); #! @Arguments graph, edge #! @Returns the modified graph. @@ -148,35 +145,35 @@ DeclareOperation("GraphvizAddNode", [IsGVGraphOrDigraph, IsObject]); #! If no nodes with the same name are in the graph then the edge's nodes will be #! added to the graph. If different nodes with the same name are in the graph #! then the operation fails. -DeclareOperation("GraphvizAddEdge", [IsGVGraphOrDigraph, IsObject, IsObject]); +DeclareOperation("GraphvizAddEdge", [IsGraphvizGraphOrDigraph, IsObject, IsObject]); #! @Arguments graph, filter, name #! @Returns the new subgraph. #! @Description Adds a subgraph to a graph. -DeclareOperation("GraphvizAddSubgraph", [IsGVGraphOrDigraph, IsObject]); -DeclareOperation("GraphvizAddSubgraph", [IsGVGraphOrDigraph]); +DeclareOperation("GraphvizAddSubgraph", [IsGraphvizGraphOrDigraph, IsObject]); +DeclareOperation("GraphvizAddSubgraph", [IsGraphvizGraphOrDigraph]); #! @Arguments graph, filter, name #! @Returns the new context. #! @Description Adds a context to a graph. -DeclareOperation("GraphvizAddContext", [IsGVGraphOrDigraph, IsObject]); -DeclareOperation("GraphvizAddContext", [IsGVGraphOrDigraph]); +DeclareOperation("GraphvizAddContext", [IsGraphvizGraphOrDigraph, IsObject]); +DeclareOperation("GraphvizAddContext", [IsGraphvizGraphOrDigraph]); #! @Arguments graph, node #! @Returns the modified graph. #! @Description Removes the node from the graph. -DeclareOperation("GraphvizRemoveNode", [IsGVGraphOrDigraph, IsObject]); +DeclareOperation("GraphvizRemoveNode", [IsGraphvizGraphOrDigraph, IsObject]); #! @Arguments graph, predicate #! @Returns the modified graph. #! @Description Filters the graph's edges using the provided predicate. -DeclareOperation("GraphvizFilterEdges", [IsGVGraphOrDigraph, IsFunction]); +DeclareOperation("GraphvizFilterEdges", [IsGraphvizGraphOrDigraph, IsFunction]); #! @Arguments graph, head_name, tail_name #! @Returns the modified graph. #! @Description Filters the graph's edges, removing edges between nodes with #! the specified names. -DeclareOperation("GraphvizFilterEnds", [IsGVGraphOrDigraph, IsObject, IsObject]); +DeclareOperation("GraphvizFilterEnds", [IsGraphvizGraphOrDigraph, IsObject, IsObject]); #! @Subsection For modifying object attributes. @@ -187,19 +184,19 @@ DeclareOperation("GraphvizFilterEnds", [IsGVGraphOrDigraph, IsObject, IsObject]) #! All current attributes remain. #! If an attribute already exists and a new value is provided, the old value #! will be overwritten. -DeclareOperation("GraphvizSetAttrs", [IsGVObject, IsRecord]); -DeclareOperation("GraphvizSetAttr", [IsGVObject, IsObject, IsObject]); -DeclareOperation("GraphvizSetAttr", [IsGVObject, IsObject]); +DeclareOperation("GraphvizSetAttrs", [IsGraphvizObject, IsRecord]); +DeclareOperation("GraphvizSetAttr", [IsGraphvizObject, IsObject, IsObject]); +DeclareOperation("GraphvizSetAttr", [IsGraphvizObject, IsObject]); #! @Arguments obj, attr #! @Returns the modified object. #! @Description Removes an attribute from the object provided. -DeclareOperation("GraphvizRemoveAttr", [IsGVObject, IsObject]); +DeclareOperation("GraphvizRemoveAttr", [IsGraphvizObject, IsObject]); #! @Section Outputting #! @Arguments graph #! @Returns the dot representation of the graphviz object. -DeclareOperation("AsString", [IsGVGraphOrDigraph]); +DeclareOperation("AsString", [IsGraphvizGraphOrDigraph]); # TODO PrintObj @@ -210,7 +207,7 @@ DeclareOperation("AsString", [IsGVGraphOrDigraph]); #! Should output the graphviz package representation of the object. DeclareOperation("Graphviz", [IsObject]); -DeclareOperation("GraphvizSetNodeColors", [IsGVGraphOrDigraph, IsList]); -DeclareOperation("GraphvizSetNodeLabels", [IsGVGraphOrDigraph, IsList]); +DeclareOperation("GraphvizSetNodeColors", [IsGraphvizGraphOrDigraph, IsList]); +DeclareOperation("GraphvizSetNodeLabels", [IsGraphvizGraphOrDigraph, IsList]); DeclareGlobalFunction("ErrorIfNotValidColor"); diff --git a/gap/dot.gi b/gap/dot.gi index cbba2c2..5549b4d 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -48,10 +48,10 @@ InstallMethod(GraphvizDigraph, "for no args", [], {} -> GraphvizDigraph("")); # Stringify ############################################################ -InstallMethod(ViewString, "for a graphviz node", [IsGVNode], +InstallMethod(ViewString, "for a graphviz node", [IsGraphvizNode], n -> StringFormatted("", GraphvizName(n))); -InstallMethod(ViewString, "for a graphviz edge", [IsGVEdge], +InstallMethod(ViewString, "for a graphviz edge", [IsGraphvizEdge], function(e) local head, tail; head := GraphvizHead(e); @@ -61,7 +61,7 @@ function(e) GraphvizName(tail)); end); -InstallMethod(ViewString, "for a graphviz graph", [IsGVGraphOrDigraph], +InstallMethod(ViewString, "for a graphviz graph", [IsGraphvizGraphOrDigraph], function(g) local result, edges, nodes, kind; @@ -70,9 +70,9 @@ function(g) nodes := Length(GV_MapNames(GraphvizNodes(g))); - if IsGVDigraph(g) then + if IsGraphvizDigraph(g) then kind := "digraph"; - elif IsGVContext(g) then + elif IsGraphvizContext(g) then kind := "context"; else kind := "graph"; @@ -94,23 +94,23 @@ end); # Getters ############################################################ -InstallMethod(GraphvizName, "for a graphviz object", [IsGVObject], x -> x!.Name); +InstallMethod(GraphvizName, "for a graphviz object", [IsGraphvizObject], x -> x!.Name); -InstallMethod(GraphvizAttrs, "for a graphviz object", [IsGVObject], +InstallMethod(GraphvizAttrs, "for a graphviz object", [IsGraphvizObject], x -> x!.Attrs); -InstallMethod(GraphvizNodes, "for a graphviz graph", [IsGVGraphOrDigraph], +InstallMethod(GraphvizNodes, "for a graphviz graph", [IsGraphvizGraphOrDigraph], x -> x!.Nodes); InstallMethod(GraphvizNode, "for a graphviz graph and object", -[IsGVGraphOrDigraph, IsObject], {gv, obj} -> gv!.Nodes[String(obj)]); +[IsGraphvizGraphOrDigraph, IsObject], {gv, obj} -> gv!.Nodes[String(obj)]); InstallMethod(GraphvizEdges, "for a graphviz graph", -[IsGVGraphOrDigraph], x -> x!.Edges); +[IsGraphvizGraphOrDigraph], x -> x!.Edges); InstallMethod(GraphvizEdges, "for a graphviz graph, object, and object", -[IsGVGraphOrDigraph, IsObject, IsObject], +[IsGraphvizGraphOrDigraph, IsObject, IsObject], function(gv, head, tail) head := GraphvizNode(gv, head); if head = fail then @@ -126,47 +126,47 @@ function(gv, head, tail) x -> GraphvizHead(x) = head and GraphvizTail(x) = tail); end); -InstallMethod(GraphvizSubgraphs, "for a graphviz graph", [IsGVGraphOrDigraph], +InstallMethod(GraphvizSubgraphs, "for a graphviz graph", [IsGraphvizGraphOrDigraph], x -> x!.Subgraphs); -InstallMethod(GraphvizTail, "for a graphviz edge", [IsGVEdge], x -> x!.Tail); +InstallMethod(GraphvizTail, "for a graphviz edge", [IsGraphvizEdge], x -> x!.Tail); -InstallMethod(GraphvizHead, "for a graphviz edge", [IsGVEdge], x -> x!.Head); +InstallMethod(GraphvizHead, "for a graphviz edge", [IsGraphvizEdge], x -> x!.Head); InstallMethod(GraphvizGetSubgraph, "for a graphviz graph and string", -[IsGVGraphOrDigraph, IsString], +[IsGraphvizGraphOrDigraph, IsString], {x, name} -> GraphvizSubgraphs(x)[name]); InstallMethod(GraphvizGetSubgraph, "for a graphviz graph and an object", -[IsGVGraphOrDigraph, IsObject], +[IsGraphvizGraphOrDigraph, IsObject], {x, o} -> GraphvizSubgraphs(x)[ViewString(o)]); # Accessing node attributes InstallOtherMethod(\[\], "for a graphviz node and a string", -[IsGVNode, IsString], +[IsGraphvizNode, IsString], {node, key} -> GraphvizAttrs(node)[key]); InstallOtherMethod(\[\], "for a graphviz node and an object", -[IsGVNode, IsObject], +[IsGraphvizNode, IsObject], {node, key} -> node[GV_EnsureString(key)]); # Setting node attributes InstallOtherMethod(\[\]\:\=, "for a graphviz node and two strings", -[IsGVNode, IsString, IsString], +[IsGraphvizNode, IsString, IsString], function(node, key, val) GraphvizAttrs(node)[key] := val; end); InstallOtherMethod(\[\]\:\=, "for a graphviz node and two strings", -[IsGVNode, IsObject, IsObject], +[IsGraphvizNode, IsObject, IsObject], function(node, key, val) node[GV_EnsureString(key)] := GV_EnsureString(val); end); @@ -175,46 +175,46 @@ end); InstallOtherMethod(\[\], "for a graphviz node and a string", -[IsGVEdge, IsString], +[IsGraphvizEdge, IsString], {edge, key} -> GraphvizAttrs(edge)[key]); InstallOtherMethod(\[\], "for a graphviz node and an object", -[IsGVEdge, IsObject], +[IsGraphvizEdge, IsObject], {edge, key} -> edge[GV_EnsureString(key)]); InstallOtherMethod(\[\]\:\=, "for a graphviz node and a string", -[IsGVEdge, IsString, IsString], +[IsGraphvizEdge, IsString, IsString], function(edge, key, val) GraphvizAttrs(edge)[key] := val; end); InstallOtherMethod(\[\]\:\=, "for a graphviz node and an object", -[IsGVEdge, IsObject, IsObject], +[IsGraphvizEdge, IsObject, IsObject], function(edge, key, val) edge[GV_EnsureString(key)] := GV_EnsureString(val); end); InstallOtherMethod(\[\], "for a graphviz graph and string", -[IsGVGraphOrDigraph, IsString], +[IsGraphvizGraphOrDigraph, IsString], {graph, node} -> GraphvizNodes(graph)[node]); InstallOtherMethod(\[\], "for a graphviz graph and string", -[IsGVGraphOrDigraph, IsObject], +[IsGraphvizGraphOrDigraph, IsObject], {g, o} -> g[ViewString(o)]); InstallMethod(GraphvizFindGraph, "for a graphviz graph and a string", -[IsGVGraphOrDigraph, IsString], +[IsGraphvizGraphOrDigraph, IsString], {g, s} -> GV_GraphTreeSearch(g, v -> GraphvizName(v) = s)); InstallMethod(GraphvizFindGraph, "for a graphviz graph and a string", -[IsGVGraphOrDigraph, IsObject], +[IsGraphvizGraphOrDigraph, IsObject], {g, o} -> GraphvizFindGraph(g, ViewString(o))); ############################################################ @@ -222,18 +222,18 @@ InstallMethod(GraphvizFindGraph, ############################################################ InstallMethod(GraphvizSetName, "for a graphviz object and string", -[IsGVGraphOrDigraph, IsString], +[IsGraphvizGraphOrDigraph, IsString], function(x, name) x!.Name := name; return x; end); InstallMethod(GraphvizSetName, "for a graphviz object and string", -[IsGVGraphOrDigraph, IsObject], +[IsGraphvizGraphOrDigraph, IsObject], {g, o} -> GraphvizSetName(g, ViewString(o))); InstallMethod(GraphvizSetAttrs, "for a graphviz object and record", -[IsGVObject, IsRecord], +[IsGraphvizObject, IsRecord], function(x, attrs) local name; for name in RecNames(attrs) do @@ -243,7 +243,7 @@ function(x, attrs) end); InstallMethod(GraphvizSetAttr, "for a graphviz object, object and object", -[IsGVObject, IsObject, IsObject], +[IsGraphvizObject, IsObject, IsObject], function(x, name, value) local msg; @@ -259,7 +259,7 @@ function(x, name, value) end); InstallMethod(GraphvizSetAttr, "for a graphviz graph, object and object", -[IsGVGraphOrDigraph, IsObject, IsObject], +[IsGraphvizGraphOrDigraph, IsObject, IsObject], function(x, name, value) local attrs, string, msg; @@ -287,7 +287,7 @@ function(x, name, value) end); InstallMethod(GraphvizSetAttr, "for a graphviz object, object and object", -[IsGVGraphOrDigraph, IsObject], +[IsGraphvizGraphOrDigraph, IsObject], function(x, value) local attrs; attrs := GraphvizAttrs(x); @@ -297,7 +297,7 @@ function(x, value) end); InstallMethod(GraphvizAddNode, "for a graphviz graph and string", -[IsGVGraphOrDigraph, IsString], +[IsGraphvizGraphOrDigraph, IsString], function(x, name) local node; node := GV_Node(x, name); @@ -307,7 +307,7 @@ end); # TODO required? InstallMethod(GraphvizAddNode, "for a graphviz graph and string", -[IsGVGraphOrDigraph, IsGVNode], +[IsGraphvizGraphOrDigraph, IsGraphvizNode], function(_, __) # gaplint: disable=analyse-lvars local error; error := "Cannot add node objects directly to graphs. "; @@ -317,12 +317,12 @@ end); InstallMethod(GraphvizAddNode, "for a graphviz graph and string", -[IsGVGraphOrDigraph, IsObject], +[IsGraphvizGraphOrDigraph, IsObject], {x, name} -> GraphvizAddNode(x, ViewString(name))); InstallMethod(GraphvizAddEdge, "for a graphviz graph and two graphviz nodes", -[IsGVGraphOrDigraph, IsGVNode, IsGVNode], +[IsGraphvizGraphOrDigraph, IsGraphvizNode, IsGraphvizNode], function(x, head, tail) local edge, head_name, tail_name; @@ -344,7 +344,7 @@ end); InstallMethod(GraphvizAddEdge, "for a graphviz graph and two strings", -[IsGVGraphOrDigraph, IsString, IsString], +[IsGraphvizGraphOrDigraph, IsString, IsString], function(x, head, tail) local head_node, tail_node; @@ -363,7 +363,7 @@ end); InstallMethod(GraphvizAddEdge, "for a graphviz graph and two objects", -[IsGVGraphOrDigraph, IsObject, IsObject], +[IsGraphvizGraphOrDigraph, IsObject, IsObject], function(x, o1, o2) if not IsString(o1) then o1 := ViewString(o1); @@ -376,7 +376,7 @@ end); InstallMethod(GraphvizAddSubgraph, "for a graphviz graph and string", -[IsGVGraphOrDigraph, IsString], +[IsGraphvizGraphOrDigraph, IsString], function(graph, name) local error, subgraphs, subgraph; @@ -386,9 +386,9 @@ function(graph, name) ErrorNoReturn(StringFormatted(error, name)); fi; - if IsGVDigraph(graph) then + if IsGraphvizDigraph(graph) then subgraph := GV_Digraph(graph, name); - elif IsGVGraph(graph) or IsGVContext(graph) then + elif IsGraphvizGraph(graph) or IsGraphvizContext(graph) then subgraph := GV_Graph(graph, name); else ErrorNoReturn("Filter must be a filter for a graph category."); @@ -400,12 +400,12 @@ end); InstallMethod(GraphvizAddSubgraph, "for a graphviz graph and an object", -[IsGVGraphOrDigraph, IsObject], +[IsGraphvizGraphOrDigraph, IsObject], {g, o} -> GraphvizAddSubgraph(g, ViewString(o))); InstallMethod(GraphvizAddSubgraph, "for a grpahviz graph", -[IsGVGraphOrDigraph], +[IsGraphvizGraphOrDigraph], function(graph) return GraphvizAddSubgraph(graph, StringFormatted("no_name_{}", String(GV_GetCounter(graph)))); @@ -413,7 +413,7 @@ end); InstallMethod(GraphvizAddContext, "for a graphviz graph and a string", -[IsGVGraphOrDigraph, IsString], +[IsGraphvizGraphOrDigraph, IsString], function(graph, name) local ctx, error, subgraphs; @@ -430,23 +430,23 @@ end); InstallMethod(GraphvizAddContext, "for a graphviz graph", -[IsGVGraphOrDigraph], +[IsGraphvizGraphOrDigraph], g -> GraphvizAddContext(g, StringFormatted("no_name_{}", String(GV_GetCounter(g))))); InstallMethod(GraphvizAddContext, "for a graphviz graph and an object", -[IsGVGraphOrDigraph, IsObject], +[IsGraphvizGraphOrDigraph, IsObject], {g, o} -> GraphvizAddContext(g, ViewString(o))); InstallMethod(GraphvizRemoveNode, "for a graphviz graph and node", -[IsGVGraphOrDigraph, IsGVNode], +[IsGraphvizGraphOrDigraph, IsGraphvizNode], {g, node} -> GraphvizRemoveNode(g, GraphvizName(node))); # TODO GraphvizRemoveEdges(gv, n1, n2) InstallMethod(GraphvizRemoveNode, "for a graphviz graph and a string", -[IsGVGraphOrDigraph, IsString], +[IsGraphvizGraphOrDigraph, IsString], function(g, name) local nodes; # TODO error if there's no such node @@ -466,11 +466,11 @@ function(g, name) end); InstallMethod(GraphvizRemoveNode, "for a graphviz graph and a string", -[IsGVGraphOrDigraph, IsObject], +[IsGraphvizGraphOrDigraph, IsObject], {g, o} -> GraphvizRemoveNode(g, ViewString(o))); InstallMethod(GraphvizFilterEdges, "for a graphviz graph and edge filter", -[IsGVGraphOrDigraph, IsFunction], +[IsGraphvizGraphOrDigraph, IsFunction], function(g, filter) local edge, idx, edges; @@ -488,14 +488,14 @@ function(g, filter) end); InstallMethod(GraphvizFilterEnds, "for a graphviz graph and two strings", -[IsGVGraphOrDigraph, IsString, IsString], +[IsGraphvizGraphOrDigraph, IsString, IsString], function(g, hn, tn) GraphvizFilterEdges(g, function(e) local head, tail, tmp; head := GraphvizHead(e); tail := GraphvizTail(e); - if IsGVDigraph(g) then + if IsGraphvizDigraph(g) then return tn <> GraphvizName(tail) or hn <> GraphvizName(head); else tmp := tn <> GraphvizName(tail) or hn <> GraphvizName(head); @@ -507,7 +507,7 @@ function(g, hn, tn) end); InstallMethod(GraphvizFilterEnds, "for a graphviz graph and two strings", -[IsGVGraphOrDigraph, IsObject, IsObject], +[IsGraphvizGraphOrDigraph, IsObject, IsObject], function(g, o1, o2) if not IsString(o1) then o1 := ViewString(o1); @@ -520,7 +520,7 @@ function(g, o1, o2) end); InstallMethod(GraphvizRemoveAttr, "for a graphviz object and an object", -[IsGVObject, IsObject], +[IsGraphvizObject, IsObject], function(obj, attr) local attrs; attrs := GraphvizAttrs(obj); @@ -529,7 +529,7 @@ function(obj, attr) end); InstallMethod(GraphvizRemoveAttr, "for a graphviz graph and an object", -[IsGVGraphOrDigraph, IsObject], +[IsGraphvizGraphOrDigraph, IsObject], function(obj, attr) local attrs; attrs := GraphvizAttrs(obj); @@ -542,11 +542,11 @@ end); ######################################################################## InstallMethod(AsString, "for a graphviz graph", -[IsGVGraphOrDigraph], graph -> GV_StringifyGraph(graph, false)); +[IsGraphvizGraphOrDigraph], graph -> GV_StringifyGraph(graph, false)); InstallMethod(GraphvizSetNodeLabels, "for a graphviz graph and list of colors", -[IsGVGraphOrDigraph, IsList], +[IsGraphvizGraphOrDigraph, IsList], function(gv, labels) local nodes, i; # TODO error if labels and nodes aren't same size @@ -560,7 +560,7 @@ end); InstallMethod(GraphvizSetNodeColors, "for a graphviz graph and list of colors", -[IsGVGraphOrDigraph, IsList], +[IsGraphvizGraphOrDigraph, IsList], function(gv, colors) local nodes, i; diff --git a/gap/gv.gd b/gap/gv.gd index ec6461b..9af7225 100644 --- a/gap/gv.gd +++ b/gap/gv.gd @@ -11,59 +11,59 @@ ## This file contains declarations of the internal/private functions for the ## graphviz package. -DeclareOperation("GV_GetCounter", [IsGVGraphOrDigraph]); -DeclareOperation("GV_IncCounter", [IsGVGraphOrDigraph]); +DeclareOperation("GV_GetCounter", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GV_IncCounter", [IsGraphvizGraphOrDigraph]); DeclareCategory("GV_IsMap", IsObject); DeclareAttribute("Size", GV_IsMap); -DeclareOperation("GV_StringifyGraphHead", [IsGVGraphOrDigraph]); -DeclareOperation("GV_StringifyDigraphHead", [IsGVGraphOrDigraph]); -DeclareOperation("GV_StringifySubgraphHead", [IsGVGraphOrDigraph]); -DeclareOperation("GV_StringifyContextHead", [IsGVGraphOrDigraph]); -DeclareOperation("GV_StringifyNode", [IsGVNode]); -DeclareOperation("GV_StringifyGraphAttrs", [IsGVGraphOrDigraph]); +DeclareOperation("GV_StringifyGraphHead", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GV_StringifyDigraphHead", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GV_StringifySubgraphHead", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GV_StringifyContextHead", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GV_StringifyNode", [IsGraphvizNode]); +DeclareOperation("GV_StringifyGraphAttrs", [IsGraphvizGraphOrDigraph]); DeclareOperation("GV_StringifyNodeEdgeAttrs", [GV_IsMap]); -DeclareOperation("GV_StringifyGraph", [IsGVGraphOrDigraph, IsBool]); +DeclareOperation("GV_StringifyGraph", [IsGraphvizGraphOrDigraph, IsBool]); -DeclareOperation("GV_FindNode", [IsGVGraphOrDigraph, IsObject]); +DeclareOperation("GV_FindNode", [IsGraphvizGraphOrDigraph, IsObject]); DeclareOperation("GV_Pluralize", [IsInt, IsString]); -DeclareOperation("GV_Node", [IsGVGraphOrDigraph, IsString]); -DeclareOperation("GV_Edge", [IsGVGraphOrDigraph, IsGVNode, IsGVNode]); -DeclareOperation("GV_Graph", [IsGVGraphOrDigraph, IsString]); -DeclareOperation("GV_Digraph", [IsGVDigraph, IsString]); -DeclareOperation("GV_Context", [IsGVGraphOrDigraph, IsString]); +DeclareOperation("GV_Node", [IsGraphvizGraphOrDigraph, IsString]); +DeclareOperation("GV_Edge", [IsGraphvizGraphOrDigraph, IsGraphvizNode, IsGraphvizNode]); +DeclareOperation("GV_Graph", [IsGraphvizGraphOrDigraph, IsString]); +DeclareOperation("GV_Digraph", [IsGraphvizDigraph, IsString]); +DeclareOperation("GV_Context", [IsGraphvizGraphOrDigraph, IsString]); DeclareOperation("GV_Map", []); DeclareOperation("GV_MapNames", [GV_IsMap]); # TODO required? Replace with AsString or just String? DeclareOperation("GV_EnsureString", [IsObject]); -DeclareOperation("GV_HasNode", [IsGVGraphOrDigraph, IsObject]); +DeclareOperation("GV_HasNode", [IsGraphvizGraphOrDigraph, IsObject]); -DeclareOperation("GV_GetParent", [IsGVGraphOrDigraph]); -DeclareOperation("GV_GraphTreeSearch", [IsGVGraphOrDigraph, IsFunction]); -DeclareOperation("GV_FindGraphWithNode", [IsGVGraphOrDigraph, IsString]); -DeclareOperation("GV_GetRoot", [IsGVGraphOrDigraph]); -DeclareOperation("GV_AddNode", [IsGVGraphOrDigraph, IsGVNode]); -DeclareOperation("GV_AddEdge", [IsGVGraphOrDigraph, IsGVEdge]); -DeclareOperation("GV_GetIdx", [IsGVObject]); -DeclareOperation("GV_ConstructHistory", [IsGVGraphOrDigraph]); +DeclareOperation("GV_GetParent", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GV_GraphTreeSearch", [IsGraphvizGraphOrDigraph, IsFunction]); +DeclareOperation("GV_FindGraphWithNode", [IsGraphvizGraphOrDigraph, IsString]); +DeclareOperation("GV_GetRoot", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GV_AddNode", [IsGraphvizGraphOrDigraph, IsGraphvizNode]); +DeclareOperation("GV_AddEdge", [IsGraphvizGraphOrDigraph, IsGraphvizEdge]); +DeclareOperation("GV_GetIdx", [IsGraphvizObject]); +DeclareOperation("GV_ConstructHistory", [IsGraphvizGraphOrDigraph]); DeclareGlobalFunction("GV_IsValidColor"); DeclareGlobalFunction("GV_ErrorIfNotNodeColoring"); BindGlobal("GV_ObjectFamily", - NewFamily("GV_ObjectFamily", IsGVObject)); + NewFamily("GV_ObjectFamily", IsGraphvizObject)); BindGlobal("GV_DigraphType", NewType(GV_ObjectFamily, - IsGVDigraph and + IsGraphvizDigraph and IsComponentObjectRep and IsAttributeStoringRep)); BindGlobal("GV_GraphType", NewType(GV_ObjectFamily, - IsGVGraph and + IsGraphvizGraph and IsComponentObjectRep and IsAttributeStoringRep)); diff --git a/gap/gv.gi b/gap/gv.gi index 185aa4b..b109058 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -99,22 +99,22 @@ BindGlobal("GV_MapType", NewType(GV_ObjectFamily, IsAttributeStoringRep)); BindGlobal("GV_NodeType", NewType(GV_ObjectFamily, - IsGVNode and + IsGraphvizNode and IsComponentObjectRep and IsAttributeStoringRep)); BindGlobal("GV_EdgeType", NewType(GV_ObjectFamily, - IsGVEdge and + IsGraphvizEdge and IsComponentObjectRep and IsAttributeStoringRep)); BindGlobal("GV_ContextType", NewType(GV_ObjectFamily, - IsGVContext and + IsGraphvizContext and IsComponentObjectRep and IsAttributeStoringRep)); -InstallMethod(\=, "for IsGVNode and IsGVNode", -[IsGVNode, IsGVNode], +InstallMethod(\=, "for IsGraphvizNode and IsGraphvizNode", +[IsGraphvizNode, IsGraphvizNode], {n1, n2} -> GraphvizName(n1) = GraphvizName(n2)); ############################################################################### @@ -126,7 +126,7 @@ InstallMethod(GV_Map, "for no args", [], {} -> Objectify(GV_MapType, rec(Data := rec()))); InstallMethod(GV_Node, "for a string", -[IsGVGraphOrDigraph, IsString], +[IsGraphvizGraphOrDigraph, IsString], function(graph, name) local out; if Length(name) = 0 then @@ -142,7 +142,7 @@ function(graph, name) end); InstallMethod(GV_Edge, "for two graphviz nodes", -[IsGVGraphOrDigraph, IsGVNode, IsGVNode], +[IsGraphvizGraphOrDigraph, IsGraphvizNode, IsGraphvizNode], function(graph, head, tail) local out; out := Objectify(GV_EdgeType, @@ -160,7 +160,7 @@ end); InstallMethod(GV_Digraph, "for a graphviz digraph and a string", -[IsGVDigraph, IsString], +[IsGraphvizDigraph, IsString], function(parent, name) local out; @@ -174,7 +174,7 @@ end); InstallMethod(GV_Graph, "for a graphviz graph and a string", -[IsGVGraphOrDigraph, IsString], +[IsGraphvizGraphOrDigraph, IsString], function(parent, name) local out; @@ -188,7 +188,7 @@ end); InstallMethod(GV_Context, "for a string and a positive integer", -[IsGVGraphOrDigraph, IsString], +[IsGraphvizGraphOrDigraph, IsString], function(parent, name) local out; @@ -254,12 +254,12 @@ InstallMethod(Size, "for a graphviz map", InstallMethod(GV_IncCounter, "for a graphviz graph", -[IsGVGraphOrDigraph], +[IsGraphvizGraphOrDigraph], function(x) x!.Counter := x!.Counter + 1; end); -InstallMethod(GV_GetCounter, "for a graphviz graph", [IsGVGraphOrDigraph], +InstallMethod(GV_GetCounter, "for a graphviz graph", [IsGraphvizGraphOrDigraph], x -> x!.Counter); # Converting strings @@ -277,16 +277,16 @@ x -> x); InstallMethod(GV_HasNode, "for a graphviz graph", -[IsGVGraphOrDigraph, IsString], +[IsGraphvizGraphOrDigraph, IsString], {g, name} -> name in GV_MapNames(GraphvizNodes(g))); InstallMethod(GV_GetParent, "for a graphviz graph", -[IsGVGraphOrDigraph], graph -> graph!.Parent); +[IsGraphvizGraphOrDigraph], graph -> graph!.Parent); InstallMethod(GV_GraphTreeSearch, "for a graphviz graph and a predicate", -[IsGVGraphOrDigraph, IsFunction], +[IsGraphvizGraphOrDigraph, IsFunction], function(graph, pred) local seen, to_visit, g, key, subgraph, parent; seen := [graph]; @@ -311,7 +311,7 @@ function(graph, pred) # add parent if not visited parent := GV_GetParent(g); - if not IsGVGraphOrDigraph(parent) then + if not IsGraphvizGraphOrDigraph(parent) then continue; fi; if not ForAny(seen, s -> IsIdenticalObj(s, parent)) then @@ -325,12 +325,12 @@ end); InstallMethod(GV_FindGraphWithNode, "for a graphviz graph and a node", -[IsGVGraphOrDigraph, IsString], +[IsGraphvizGraphOrDigraph, IsString], {g, n} -> GV_GraphTreeSearch(g, v -> v[n] <> fail)); InstallMethod(GV_GetRoot, "for a graphviz graph", -[IsGVGraphOrDigraph], +[IsGraphvizGraphOrDigraph], function(graph) while GV_GetParent(graph) <> fail do graph := GV_GetParent(graph); @@ -340,7 +340,7 @@ end); InstallMethod(GV_FindNode, "for a graphviz graph and a string", -[IsGVGraphOrDigraph, IsString], +[IsGraphvizGraphOrDigraph, IsString], function(g, n) local graph; graph := GV_FindGraphWithNode(g, n); @@ -352,7 +352,7 @@ end); InstallMethod(GV_AddNode, "for a graphviz graph and node", -[IsGVGraphOrDigraph, IsGVNode], +[IsGraphvizGraphOrDigraph, IsGraphvizNode], function(x, node) local found, error, name, nodes; name := GraphvizName(node); @@ -371,7 +371,7 @@ end); InstallMethod(GV_AddEdge, "for a graphviz graph and edge", -[IsGVGraphOrDigraph, IsGVEdge], +[IsGraphvizGraphOrDigraph, IsGraphvizEdge], function(x, edge) local head, head_name, tail_name, tail, hg, error, tg; @@ -414,26 +414,26 @@ end); ############################################################################### # @ Return DOT graph head line. -InstallMethod(GV_StringifyGraphHead, "for a string", [IsGVGraphOrDigraph], +InstallMethod(GV_StringifyGraphHead, "for a string", [IsGraphvizGraphOrDigraph], graph -> StringFormatted("graph {} {{\n", GraphvizName(graph))); # @ Return DOT digraph head line. -InstallMethod(GV_StringifyDigraphHead, "for a string", [IsGVDigraph], +InstallMethod(GV_StringifyDigraphHead, "for a string", [IsGraphvizDigraph], graph -> StringFormatted("digraph {} {{\n", GraphvizName(graph))); # @ Return DOT subgraph head line. -InstallMethod(GV_StringifySubgraphHead, "for a string", [IsGVGraphOrDigraph], +InstallMethod(GV_StringifySubgraphHead, "for a string", [IsGraphvizGraphOrDigraph], graph -> StringFormatted("subgraph {} {{\n", GraphvizName(graph))); # @ Return DOT subgraph head line. -InstallMethod(GV_StringifyContextHead, "for a string", [IsGVContext], +InstallMethod(GV_StringifyContextHead, "for a string", [IsGraphvizContext], graph -> StringFormatted("// {} context \n", GraphvizName(graph))); BindGlobal("GV_StringifyNodeName", function(node) local name, old; - Assert(0, IsGVNode(node)); + Assert(0, IsGraphvizNode(node)); name := GraphvizName(node); if (ForAny("- .+", x -> x in name) or (IsDigitChar(First(name)) and IsAlphaChar(Last(name)))) @@ -453,7 +453,7 @@ end); # @ Return DOT node statement line. InstallMethod(GV_StringifyNode, "for string and record", -[IsGVNode], +[IsGraphvizNode], function(node) local name, attrs; name := GV_StringifyNodeName(node); @@ -465,7 +465,7 @@ end); BindGlobal("GV_StringifyEdge", function(edge, edge_str) local head, tail, attrs; - Assert(0, IsGVEdge(edge)); + Assert(0, IsGraphvizEdge(edge)); Assert(0, IsString(edge_str)); head := GV_StringifyNodeName(GraphvizHead(edge)); tail := GV_StringifyNodeName(GraphvizTail(edge)); @@ -481,7 +481,7 @@ end); InstallMethod(GV_StringifyGraphAttrs, "for a graphviz graph", -[IsGVGraphOrDigraph], +[IsGraphvizGraphOrDigraph], function(graph) local result, attrs, kv; attrs := GraphvizAttrs(graph); @@ -561,12 +561,12 @@ end); InstallMethod(GV_GetIdx, "for a graphviz object", -[IsGVObject], +[IsGraphvizObject], x -> x!.Idx); InstallMethod(GV_ConstructHistory, "for a graphviz graph", -[IsGVGraphOrDigraph], +[IsGraphvizGraphOrDigraph], function(graph) local nodes, edges, subs, node_hist, edge_hist, subs_hist, hist; @@ -587,27 +587,27 @@ end); InstallMethod(GV_StringifyGraph, "for a graphviz graph and a string", -[IsGVGraphOrDigraph, IsBool], +[IsGraphvizGraphOrDigraph, IsBool], function(graph, is_subgraph) local result, obj; result := ""; # get the correct head to use if is_subgraph then - if IsGVContext(graph) then + if IsGraphvizContext(graph) then Append(result, GV_StringifyContextHead(graph)); - elif IsGVGraph(graph) or IsGVDigraph(graph) then + elif IsGraphvizGraph(graph) or IsGraphvizDigraph(graph) then Append(result, GV_StringifySubgraphHead(graph)); else ErrorNoReturn("Invalid subgraph type."); fi; - elif IsGVDigraph(graph) then + elif IsGraphvizDigraph(graph) then Append(result, "//dot\n"); Append(result, GV_StringifyDigraphHead(graph)); - elif IsGVGraph(graph) then + elif IsGraphvizGraph(graph) then Append(result, "//dot\n"); Append(result, GV_StringifyGraphHead(graph)); - elif IsGVContext(graph) then + elif IsGraphvizContext(graph) then Append(result, "//dot\n"); Append(result, GV_StringifyContextHead(graph)); else @@ -618,12 +618,12 @@ function(graph, is_subgraph) # Add child graphviz objects for obj in GV_ConstructHistory(graph) do - if IsGVGraphOrDigraph(obj) then + if IsGraphvizGraphOrDigraph(obj) then Append(result, GV_StringifyGraph(obj, true)); - elif IsGVNode(obj) then + elif IsGraphvizNode(obj) then Append(result, GV_StringifyNode(obj)); - elif IsGVEdge(obj) then - if IsGVDigraph(GV_GetRoot(graph)) then + elif IsGraphvizEdge(obj) then + if IsGraphvizDigraph(GV_GetRoot(graph)) then Append(result, GV_StringifyEdge(obj, "->")); else Append(result, GV_StringifyEdge(obj, "--")); @@ -633,7 +633,7 @@ function(graph, is_subgraph) fi; od; - if IsGVContext(graph) then + if IsGraphvizContext(graph) then # reset attributes following the context if GV_GetParent(graph) <> fail then Append(result, GV_StringifyGraphAttrs(GV_GetParent(graph))); diff --git a/gap/splash.gi b/gap/splash.gi index 17cb9be..b959344 100644 --- a/gap/splash.gi +++ b/gap/splash.gi @@ -12,10 +12,10 @@ if not IsBound(Splash) then if IsEmpty(arg) then ErrorNoReturn("the must be at least 1 argument, found none"); - elif not IsString(arg[1]) and not IsGVGraphOrDigraph(arg[1]) then + elif not IsString(arg[1]) and not IsGraphvizGraphOrDigraph(arg[1]) then ErrorFormatted("the 1st argument must be a string or ", "graphviz graph, found {}", TNAM_OBJ(arg[1])); - elif IsGVGraphOrDigraph(arg[1]) then + elif IsGraphvizGraphOrDigraph(arg[1]) then arg[1] := AsString(arg[1]); fi; str := arg[1]; From 99c6639f1f4b9407d4d807d64ac58f1b365409b3 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Mon, 13 May 2024 12:02:18 +0100 Subject: [PATCH 08/38] Fix description strings --- gap/dot.gd | 13 ++++ gap/dot.gi | 206 ++++++++++++++++++++++++++++----------------------- gap/gv.gi | 11 +-- tst/node.tst | 3 +- 4 files changed, 132 insertions(+), 101 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index 8856d38..e082948 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -211,3 +211,16 @@ DeclareOperation("GraphvizSetNodeColors", [IsGraphvizGraphOrDigraph, IsList]); DeclareOperation("GraphvizSetNodeLabels", [IsGraphvizGraphOrDigraph, IsList]); DeclareGlobalFunction("ErrorIfNotValidColor"); + +# TODO doc +DeclareOperation("\[\]", [IsGraphvizNode, IsObject]); +# TODO doc +DeclareOperation("\[\]\:\=", [IsGraphvizNode, IsObject, IsObject]); + +# TODO doc +DeclareOperation("\[\]", [IsGraphvizEdge, IsObject]); +# TODO doc +DeclareOperation("\[\]\:\=", [IsGraphvizEdge, IsObject, IsObject]); + +# TODO doc +DeclareOperation("\[\]", [IsGraphvizGraphOrDigraph, IsObject]); diff --git a/gap/dot.gi b/gap/dot.gi index 5549b4d..961a991 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -8,9 +8,9 @@ ############################################################################# ## -############################################################################# +######################################################################## # Constructors -############################################################################# +######################################################################## InstallMethod(GraphvizGraph, "for a string", [IsString], function(name) @@ -44,9 +44,9 @@ end); InstallMethod(GraphvizDigraph, "for no args", [], {} -> GraphvizDigraph("")); -############################################################ -# Stringify -############################################################ +######################################################################## +# ViewString +######################################################################## InstallMethod(ViewString, "for a graphviz node", [IsGraphvizNode], n -> StringFormatted("", GraphvizName(n))); @@ -61,7 +61,7 @@ function(e) GraphvizName(tail)); end); -InstallMethod(ViewString, "for a graphviz graph", [IsGraphvizGraphOrDigraph], +InstallMethod(ViewString, "for a graphviz (di)graph", [IsGraphvizGraphOrDigraph], function(g) local result, edges, nodes, kind; @@ -94,22 +94,23 @@ end); # Getters ############################################################ -InstallMethod(GraphvizName, "for a graphviz object", [IsGraphvizObject], x -> x!.Name); +InstallMethod(GraphvizName, "for a graphviz object", [IsGraphvizObject], +x -> x!.Name); InstallMethod(GraphvizAttrs, "for a graphviz object", [IsGraphvizObject], x -> x!.Attrs); -InstallMethod(GraphvizNodes, "for a graphviz graph", [IsGraphvizGraphOrDigraph], +InstallMethod(GraphvizNodes, "for a graphviz (di)graph", [IsGraphvizGraphOrDigraph], x -> x!.Nodes); -InstallMethod(GraphvizNode, "for a graphviz graph and object", +InstallMethod(GraphvizNode, "for a graphviz (di)graph and object", [IsGraphvizGraphOrDigraph, IsObject], {gv, obj} -> gv!.Nodes[String(obj)]); -InstallMethod(GraphvizEdges, "for a graphviz graph", +InstallMethod(GraphvizEdges, "for a graphviz (di)graph", [IsGraphvizGraphOrDigraph], x -> x!.Edges); InstallMethod(GraphvizEdges, -"for a graphviz graph, object, and object", +"for a graphviz (di)graph, object, and object", [IsGraphvizGraphOrDigraph, IsObject, IsObject], function(gv, head, tail) head := GraphvizNode(gv, head); @@ -126,111 +127,122 @@ function(gv, head, tail) x -> GraphvizHead(x) = head and GraphvizTail(x) = tail); end); -InstallMethod(GraphvizSubgraphs, "for a graphviz graph", [IsGraphvizGraphOrDigraph], -x -> x!.Subgraphs); +InstallMethod(GraphvizSubgraphs, "for a graphviz (di)graph", +[IsGraphvizGraphOrDigraph], x -> x!.Subgraphs); -InstallMethod(GraphvizTail, "for a graphviz edge", [IsGraphvizEdge], x -> x!.Tail); +InstallMethod(GraphvizTail, "for a graphviz edge", [IsGraphvizEdge], +x -> x!.Tail); -InstallMethod(GraphvizHead, "for a graphviz edge", [IsGraphvizEdge], x -> x!.Head); +InstallMethod(GraphvizHead, "for a graphviz edge", [IsGraphvizEdge], +x -> x!.Head); InstallMethod(GraphvizGetSubgraph, -"for a graphviz graph and string", +"for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsString], {x, name} -> GraphvizSubgraphs(x)[name]); InstallMethod(GraphvizGetSubgraph, -"for a graphviz graph and an object", +"for a graphviz (di)graph and an object", [IsGraphvizGraphOrDigraph, IsObject], -{x, o} -> GraphvizSubgraphs(x)[ViewString(o)]); +{x, o} -> GraphvizSubgraphs(x)[String(o)]); # Accessing node attributes -InstallOtherMethod(\[\], +InstallMethod(\[\], "for a graphviz node and a string", [IsGraphvizNode, IsString], {node, key} -> GraphvizAttrs(node)[key]); -InstallOtherMethod(\[\], +InstallMethod(\[\], "for a graphviz node and an object", [IsGraphvizNode, IsObject], -{node, key} -> node[GV_EnsureString(key)]); +{node, key} -> node[String(key)]); # Setting node attributes -InstallOtherMethod(\[\]\:\=, +InstallMethod(\[\]\:\=, "for a graphviz node and two strings", [IsGraphvizNode, IsString, IsString], function(node, key, val) GraphvizAttrs(node)[key] := val; end); -InstallOtherMethod(\[\]\:\=, +InstallMethod(\[\]\:\=, "for a graphviz node and two strings", [IsGraphvizNode, IsObject, IsObject], function(node, key, val) - node[GV_EnsureString(key)] := GV_EnsureString(val); + node[String(key)] := String(val); end); # Accessing edge attributes -InstallOtherMethod(\[\], -"for a graphviz node and a string", +InstallMethod(\[\], +"for a graphviz edge and a string", [IsGraphvizEdge, IsString], {edge, key} -> GraphvizAttrs(edge)[key]); -InstallOtherMethod(\[\], -"for a graphviz node and an object", +InstallMethod(\[\], +"for a graphviz edge and an object", [IsGraphvizEdge, IsObject], -{edge, key} -> edge[GV_EnsureString(key)]); +{edge, key} -> edge[String(key)]); -InstallOtherMethod(\[\]\:\=, -"for a graphviz node and a string", +InstallMethod(\[\]\:\=, +"for a graphviz edge and a string", [IsGraphvizEdge, IsString, IsString], function(edge, key, val) GraphvizAttrs(edge)[key] := val; end); -InstallOtherMethod(\[\]\:\=, -"for a graphviz node and an object", +InstallMethod(\[\]\:\=, +"for a graphviz edge and an object", [IsGraphvizEdge, IsObject, IsObject], function(edge, key, val) edge[GV_EnsureString(key)] := GV_EnsureString(val); end); -InstallOtherMethod(\[\], -"for a graphviz graph and string", +# Accessor for graphs and digraphs + +# TODO remove either this or GraphvizNode(gv, name); +InstallMethod(\[\], +"for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsString], {graph, node} -> GraphvizNodes(graph)[node]); -InstallOtherMethod(\[\], -"for a graphviz graph and string", +InstallMethod(\[\], +"for a graphviz (di)graph and object", [IsGraphvizGraphOrDigraph, IsObject], -{g, o} -> g[ViewString(o)]); +{g, o} -> g[String(o)]); + +# TODO is this named appropriately? Should it be FindSubgraph? InstallMethod(GraphvizFindGraph, -"for a graphviz graph and a string", +"for a graphviz (di)graph and a string", [IsGraphvizGraphOrDigraph, IsString], {g, s} -> GV_GraphTreeSearch(g, v -> GraphvizName(v) = s)); InstallMethod(GraphvizFindGraph, -"for a graphviz graph and a string", +"for a graphviz (di)graph and a string", [IsGraphvizGraphOrDigraph, IsObject], -{g, o} -> GraphvizFindGraph(g, ViewString(o))); +{g, o} -> GraphvizFindGraph(g, String(o))); ############################################################ -# Setters +# GraphvizSetName ############################################################ -InstallMethod(GraphvizSetName, "for a graphviz object and string", +InstallMethod(GraphvizSetName, "for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsString], function(x, name) x!.Name := name; return x; end); -InstallMethod(GraphvizSetName, "for a graphviz object and string", +InstallMethod(GraphvizSetName, "for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsObject], -{g, o} -> GraphvizSetName(g, ViewString(o))); +{g, o} -> GraphvizSetName(g, String(o))); + +############################################################ +# GraphvizSetAttr(s) +############################################################ InstallMethod(GraphvizSetAttrs, "for a graphviz object and record", [IsGraphvizObject, IsRecord], @@ -242,23 +254,22 @@ function(x, attrs) return x; end); -InstallMethod(GraphvizSetAttr, "for a graphviz object, object and object", +# TODO combine this and the next method +InstallMethod(GraphvizSetAttr, "for a graphviz object, object, and object", [IsGraphvizObject, IsObject, IsObject], function(x, name, value) - local msg; if not name in GV_KNOWN_ATTRS then - msg := Concatenation( - StringFormatted("unknown attribute \"{}\", the", name), - " graphviz object may no longer be valid, it can", - " be removed using GraphvizRemoveAttr"); - Info(InfoWarning, 1, msg); + Info(InfoWarning, 1, + StringFormatted("unknown attribute \"{}\", the", name), + " graphviz object may no longer be valid, it can", + " be removed using GraphvizRemoveAttr"); fi; GraphvizAttrs(x)[String(name)] := String(value); return x; end); -InstallMethod(GraphvizSetAttr, "for a graphviz graph, object and object", +InstallMethod(GraphvizSetAttr, "for a graphviz (di)graph, object and object", [IsGraphvizGraphOrDigraph, IsObject, IsObject], function(x, name, value) local attrs, string, msg; @@ -278,6 +289,7 @@ function(x, name, value) name := StringFormatted("\"{}\"", name); fi; if ' ' in value then + # Replace with call to GV_QuoteName or whatever TODO value := StringFormatted("\"{}\"", value); fi; @@ -286,7 +298,7 @@ function(x, name, value) return x; end); -InstallMethod(GraphvizSetAttr, "for a graphviz object, object and object", +InstallMethod(GraphvizSetAttr, "for a graphviz (di)graph and object", [IsGraphvizGraphOrDigraph, IsObject], function(x, value) local attrs; @@ -296,7 +308,11 @@ function(x, value) return x; end); -InstallMethod(GraphvizAddNode, "for a graphviz graph and string", +############################################################ +# GraphvizAddNode +############################################################ + +InstallMethod(GraphvizAddNode, "for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsString], function(x, name) local node; @@ -305,23 +321,25 @@ function(x, name) return node; end); -# TODO required? -InstallMethod(GraphvizAddNode, "for a graphviz graph and string", +InstallMethod(GraphvizAddNode, "for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsGraphvizNode], -function(_, __) # gaplint: disable=analyse-lvars - local error; - error := "Cannot add node objects directly to graphs. "; - error := Concatenation(error, "Please use the node's name."); - ErrorNoReturn(error); +function(gv, name) # gaplint: disable=analyse-lvars + ErrorNoReturn("it is not currently possible to add Graphviz node ", + "objects directly to Graphviz graphs or digraphs, use ", + "the node's name instead"); end); InstallMethod(GraphvizAddNode, -"for a graphviz graph and string", +"for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsObject], -{x, name} -> GraphvizAddNode(x, ViewString(name))); +{x, name} -> GraphvizAddNode(x, String(name))); + +############################################################ +# GraphvizAddEdge +############################################################ InstallMethod(GraphvizAddEdge, -"for a graphviz graph and two graphviz nodes", +"for a graphviz (di)graph and two graphviz nodes", [IsGraphvizGraphOrDigraph, IsGraphvizNode, IsGraphvizNode], function(x, head, tail) local edge, head_name, tail_name; @@ -343,7 +361,7 @@ function(x, head, tail) end); InstallMethod(GraphvizAddEdge, -"for a graphviz graph and two strings", +"for a graphviz (di)graph and two strings", [IsGraphvizGraphOrDigraph, IsString, IsString], function(x, head, tail) local head_node, tail_node; @@ -362,20 +380,24 @@ function(x, head, tail) end); InstallMethod(GraphvizAddEdge, -"for a graphviz graph and two objects", +"for a graphviz (di)graph and two objects", [IsGraphvizGraphOrDigraph, IsObject, IsObject], function(x, o1, o2) if not IsString(o1) then - o1 := ViewString(o1); + o1 := String(o1); fi; if not IsString(o2) then - o2 := ViewString(o2); + o2 := String(o2); fi; return GraphvizAddEdge(x, o1, o2); end); +############################################################ +# GraphvizAddSubgraph +############################################################ + InstallMethod(GraphvizAddSubgraph, -"for a graphviz graph and string", +"for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsString], function(graph, name) local error, subgraphs, subgraph; @@ -399,20 +421,18 @@ function(graph, name) end); InstallMethod(GraphvizAddSubgraph, -"for a graphviz graph and an object", +"for a graphviz (di)graph and an object", [IsGraphvizGraphOrDigraph, IsObject], -{g, o} -> GraphvizAddSubgraph(g, ViewString(o))); +{g, o} -> GraphvizAddSubgraph(g, String(o))); -InstallMethod(GraphvizAddSubgraph, -"for a grpahviz graph", +InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph", [IsGraphvizGraphOrDigraph], -function(graph) - return GraphvizAddSubgraph(graph, StringFormatted("no_name_{}", - String(GV_GetCounter(graph)))); -end); +graph -> GraphvizAddSubgraph(graph, + StringFormatted("no_name_{}", + GV_GetCounter(graph)))); InstallMethod(GraphvizAddContext, -"for a graphviz graph and a string", +"for a graphviz (di)graph and a string", [IsGraphvizGraphOrDigraph, IsString], function(graph, name) local ctx, error, subgraphs; @@ -429,23 +449,23 @@ function(graph, name) end); InstallMethod(GraphvizAddContext, -"for a graphviz graph", +"for a graphviz (di)graph", [IsGraphvizGraphOrDigraph], g -> GraphvizAddContext(g, StringFormatted("no_name_{}", String(GV_GetCounter(g))))); InstallMethod(GraphvizAddContext, -"for a graphviz graph and an object", +"for a graphviz (di)graph and an object", [IsGraphvizGraphOrDigraph, IsObject], -{g, o} -> GraphvizAddContext(g, ViewString(o))); +{g, o} -> GraphvizAddContext(g, String(o))); -InstallMethod(GraphvizRemoveNode, "for a graphviz graph and node", +InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph and node", [IsGraphvizGraphOrDigraph, IsGraphvizNode], {g, node} -> GraphvizRemoveNode(g, GraphvizName(node))); # TODO GraphvizRemoveEdges(gv, n1, n2) -InstallMethod(GraphvizRemoveNode, "for a graphviz graph and a string", +InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph and a string", [IsGraphvizGraphOrDigraph, IsString], function(g, name) local nodes; @@ -465,11 +485,11 @@ function(g, name) return g; end); -InstallMethod(GraphvizRemoveNode, "for a graphviz graph and a string", +InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph and a string", [IsGraphvizGraphOrDigraph, IsObject], -{g, o} -> GraphvizRemoveNode(g, ViewString(o))); +{g, o} -> GraphvizRemoveNode(g, String(o))); -InstallMethod(GraphvizFilterEdges, "for a graphviz graph and edge filter", +InstallMethod(GraphvizFilterEdges, "for a graphviz (di)graph and edge filter", [IsGraphvizGraphOrDigraph, IsFunction], function(g, filter) local edge, idx, edges; @@ -487,7 +507,9 @@ function(g, filter) return g; end); -InstallMethod(GraphvizFilterEnds, "for a graphviz graph and two strings", +# TODO remove? + +InstallMethod(GraphvizFilterEnds, "for a graphviz (di)graph and two strings", [IsGraphvizGraphOrDigraph, IsString, IsString], function(g, hn, tn) GraphvizFilterEdges(g, @@ -506,14 +528,14 @@ function(g, hn, tn) return g; end); -InstallMethod(GraphvizFilterEnds, "for a graphviz graph and two strings", +InstallMethod(GraphvizFilterEnds, "for a graphviz (di)graph and two objects", [IsGraphvizGraphOrDigraph, IsObject, IsObject], function(g, o1, o2) if not IsString(o1) then - o1 := ViewString(o1); + o1 := String(o1); fi; if not IsString(o2) then - o2 := ViewString(o2); + o2 := String(o2); fi; GraphvizFilterEnds(g, o1, o2); @@ -528,7 +550,7 @@ function(obj, attr) return obj; end); -InstallMethod(GraphvizRemoveAttr, "for a graphviz graph and an object", +InstallMethod(GraphvizRemoveAttr, "for a graphviz (di)graph and an object", [IsGraphvizGraphOrDigraph, IsObject], function(obj, attr) local attrs; diff --git a/gap/gv.gi b/gap/gv.gi index b109058..0c2d9c8 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -264,14 +264,9 @@ x -> x!.Counter); # Converting strings -InstallMethod(GV_EnsureString, -"for an object", -[IsObject], ViewString); - -InstallMethod(GV_EnsureString, -"for a string", -[IsString], -x -> x); +InstallMethod(GV_EnsureString, "for an object", [IsObject], String); + +InstallMethod(GV_EnsureString, "for a string", [IsString], IdFunc); # Nodes diff --git a/tst/node.tst b/tst/node.tst index 92dc589..9a8a506 100644 --- a/tst/node.tst +++ b/tst/node.tst @@ -110,7 +110,8 @@ gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "n");; gap> s := GraphvizGraph();; gap> GraphvizAddNode(s, n); -Error, Cannot add node objects directly to graphs. Please use the node's name. +Error, it is not currently possible to add Graphviz node objects directly to G\ +raphviz graphs or digraphs, use the node's name instead # gap> STOP_TEST("graphviz package: node.tst", 0); From e6a7d22ed7888cbe855b9b17f3bdbe042a34b952 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Tue, 14 May 2024 09:09:40 +0100 Subject: [PATCH 09/38] More cleanups --- gap/dot.gd | 10 +-- gap/dot.gi | 163 +++++++++++++++++++++-------------------------- gap/gv.gd | 3 +- gap/gv.gi | 5 +- tst/subgraph.tst | 3 +- 5 files changed, 83 insertions(+), 101 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index e082948..cc38809 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -88,7 +88,6 @@ DeclareOperation("GraphvizAttrs", [IsGraphvizObject]); #! @Description Gets the nodes of the provided graphviz graph. #! Node names can only be [a-zA-Z0-9_£] TODO check exact docs. DeclareOperation("GraphvizNodes", [IsGraphvizGraphOrDigraph]); -DeclareOperation("GraphvizNode", [IsGraphvizGraphOrDigraph, IsObject]); #! @Arguments graph #! @Returns the subgraphs of the provided graphviz graph. @@ -109,7 +108,8 @@ DeclareOperation("GraphvizFindGraph", [IsGraphvizGraphOrDigraph, IsObject]); #! @Returns the edges of the provided graphviz graph. #! @Description Gets the edges of the provided graphviz graph. DeclareOperation("GraphvizEdges", [IsGraphvizGraphOrDigraph]); -DeclareOperation("GraphvizEdges", [IsGraphvizGraphOrDigraph, IsObject, IsObject]); +DeclareOperation("GraphvizEdges", +[IsGraphvizGraphOrDigraph, IsObject, IsObject]); #! @Subsection For only edges. @@ -145,7 +145,8 @@ DeclareOperation("GraphvizAddNode", [IsGraphvizGraphOrDigraph, IsObject]); #! If no nodes with the same name are in the graph then the edge's nodes will be #! added to the graph. If different nodes with the same name are in the graph #! then the operation fails. -DeclareOperation("GraphvizAddEdge", [IsGraphvizGraphOrDigraph, IsObject, IsObject]); +DeclareOperation("GraphvizAddEdge", +[IsGraphvizGraphOrDigraph, IsObject, IsObject]); #! @Arguments graph, filter, name #! @Returns the new subgraph. @@ -173,7 +174,8 @@ DeclareOperation("GraphvizFilterEdges", [IsGraphvizGraphOrDigraph, IsFunction]); #! @Returns the modified graph. #! @Description Filters the graph's edges, removing edges between nodes with #! the specified names. -DeclareOperation("GraphvizFilterEnds", [IsGraphvizGraphOrDigraph, IsObject, IsObject]); +DeclareOperation("GraphvizFilterEnds", +[IsGraphvizGraphOrDigraph, IsObject, IsObject]); #! @Subsection For modifying object attributes. diff --git a/gap/dot.gi b/gap/dot.gi index 961a991..f83b620 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -8,9 +8,9 @@ ############################################################################# ## -######################################################################## +############################################################################# # Constructors -######################################################################## +############################################################################# InstallMethod(GraphvizGraph, "for a string", [IsString], function(name) @@ -44,9 +44,9 @@ end); InstallMethod(GraphvizDigraph, "for no args", [], {} -> GraphvizDigraph("")); -######################################################################## +############################################################################# # ViewString -######################################################################## +############################################################################# InstallMethod(ViewString, "for a graphviz node", [IsGraphvizNode], n -> StringFormatted("", GraphvizName(n))); @@ -90,9 +90,9 @@ function(g) return result; end); -############################################################ +############################################################################# # Getters -############################################################ +############################################################################# InstallMethod(GraphvizName, "for a graphviz object", [IsGraphvizObject], x -> x!.Name); @@ -100,11 +100,8 @@ x -> x!.Name); InstallMethod(GraphvizAttrs, "for a graphviz object", [IsGraphvizObject], x -> x!.Attrs); -InstallMethod(GraphvizNodes, "for a graphviz (di)graph", [IsGraphvizGraphOrDigraph], -x -> x!.Nodes); - -InstallMethod(GraphvizNode, "for a graphviz (di)graph and object", -[IsGraphvizGraphOrDigraph, IsObject], {gv, obj} -> gv!.Nodes[String(obj)]); +InstallMethod(GraphvizNodes, "for a graphviz (di)graph", +[IsGraphvizGraphOrDigraph], x -> x!.Nodes); InstallMethod(GraphvizEdges, "for a graphviz (di)graph", [IsGraphvizGraphOrDigraph], x -> x!.Edges); @@ -113,12 +110,12 @@ InstallMethod(GraphvizEdges, "for a graphviz (di)graph, object, and object", [IsGraphvizGraphOrDigraph, IsObject, IsObject], function(gv, head, tail) - head := GraphvizNode(gv, head); + head := GraphvizNodes(gv)[head]; if head = fail then ErrorNoReturn("the 2nd argument (head of an edge) is not a node ", "of the 1st argument (a graphviz graph or digraph)"); fi; - tail := GraphvizNode(gv, tail); + tail := GraphvizNodes(gv)[tail]; if tail = fail then ErrorNoReturn("the 2nd argument (head of an edge) is not a node ", "of the 1st argument (a graphviz graph or digraph)"); @@ -136,39 +133,35 @@ x -> x!.Tail); InstallMethod(GraphvizHead, "for a graphviz edge", [IsGraphvizEdge], x -> x!.Head); -InstallMethod(GraphvizGetSubgraph, -"for a graphviz (di)graph and string", +# TODO remove the next two? + +InstallMethod(GraphvizGetSubgraph, "for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsString], {x, name} -> GraphvizSubgraphs(x)[name]); -InstallMethod(GraphvizGetSubgraph, -"for a graphviz (di)graph and an object", +InstallMethod(GraphvizGetSubgraph, "for a graphviz (di)graph and an object", [IsGraphvizGraphOrDigraph, IsObject], {x, o} -> GraphvizSubgraphs(x)[String(o)]); # Accessing node attributes -InstallMethod(\[\], -"for a graphviz node and a string", +InstallMethod(\[\], "for a graphviz node and a string", [IsGraphvizNode, IsString], {node, key} -> GraphvizAttrs(node)[key]); -InstallMethod(\[\], -"for a graphviz node and an object", +InstallMethod(\[\], "for a graphviz node and an object", [IsGraphvizNode, IsObject], {node, key} -> node[String(key)]); # Setting node attributes -InstallMethod(\[\]\:\=, -"for a graphviz node and two strings", +InstallMethod(\[\]\:\=, "for a graphviz node and two strings", [IsGraphvizNode, IsString, IsString], function(node, key, val) GraphvizAttrs(node)[key] := val; end); -InstallMethod(\[\]\:\=, -"for a graphviz node and two strings", +InstallMethod(\[\]\:\=, "for a graphviz node and two strings", [IsGraphvizNode, IsObject, IsObject], function(node, key, val) node[String(key)] := String(val); @@ -176,25 +169,21 @@ end); # Accessing edge attributes -InstallMethod(\[\], -"for a graphviz edge and a string", +InstallMethod(\[\], "for a graphviz edge and a string", [IsGraphvizEdge, IsString], {edge, key} -> GraphvizAttrs(edge)[key]); -InstallMethod(\[\], -"for a graphviz edge and an object", +InstallMethod(\[\], "for a graphviz edge and an object", [IsGraphvizEdge, IsObject], {edge, key} -> edge[String(key)]); -InstallMethod(\[\]\:\=, -"for a graphviz edge and a string", +InstallMethod(\[\]\:\=, "for a graphviz edge and a string", [IsGraphvizEdge, IsString, IsString], function(edge, key, val) GraphvizAttrs(edge)[key] := val; end); -InstallMethod(\[\]\:\=, -"for a graphviz edge and an object", +InstallMethod(\[\]\:\=, "for a graphviz edge and an object", [IsGraphvizEdge, IsObject, IsObject], function(edge, key, val) edge[GV_EnsureString(key)] := GV_EnsureString(val); @@ -203,13 +192,11 @@ end); # Accessor for graphs and digraphs # TODO remove either this or GraphvizNode(gv, name); -InstallMethod(\[\], -"for a graphviz (di)graph and string", +InstallMethod(\[\], "for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsString], {graph, node} -> GraphvizNodes(graph)[node]); -InstallMethod(\[\], -"for a graphviz (di)graph and object", +InstallMethod(\[\], "for a graphviz (di)graph and object", [IsGraphvizGraphOrDigraph, IsObject], {g, o} -> g[String(o)]); @@ -225,9 +212,9 @@ InstallMethod(GraphvizFindGraph, [IsGraphvizGraphOrDigraph, IsObject], {g, o} -> GraphvizFindGraph(g, String(o))); -############################################################ +############################################################################# # GraphvizSetName -############################################################ +############################################################################# InstallMethod(GraphvizSetName, "for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsString], @@ -240,9 +227,9 @@ InstallMethod(GraphvizSetName, "for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsObject], {g, o} -> GraphvizSetName(g, String(o))); -############################################################ +############################################################################# # GraphvizSetAttr(s) -############################################################ +############################################################################# InstallMethod(GraphvizSetAttrs, "for a graphviz object and record", [IsGraphvizObject, IsRecord], @@ -308,9 +295,9 @@ function(x, value) return x; end); -############################################################ +############################################################################# # GraphvizAddNode -############################################################ +############################################################################# InstallMethod(GraphvizAddNode, "for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsString], @@ -334,9 +321,9 @@ InstallMethod(GraphvizAddNode, [IsGraphvizGraphOrDigraph, IsObject], {x, name} -> GraphvizAddNode(x, String(name))); -############################################################ +############################################################################# # GraphvizAddEdge -############################################################ +############################################################################# InstallMethod(GraphvizAddEdge, "for a graphviz (di)graph and two graphviz nodes", @@ -382,46 +369,42 @@ end); InstallMethod(GraphvizAddEdge, "for a graphviz (di)graph and two objects", [IsGraphvizGraphOrDigraph, IsObject, IsObject], -function(x, o1, o2) - if not IsString(o1) then - o1 := String(o1); - fi; - if not IsString(o2) then - o2 := String(o2); - fi; - return GraphvizAddEdge(x, o1, o2); -end); +{gv, o1, o2} -> GraphvizAddEdge(gv, String(o1), String(o2))); -############################################################ +############################################################################# # GraphvizAddSubgraph -############################################################ +############################################################################# -InstallMethod(GraphvizAddSubgraph, -"for a graphviz (di)graph and string", +InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsString], -function(graph, name) - local error, subgraphs, subgraph; +function(gv, name) + local subgraphs, subgraph; - subgraphs := GraphvizSubgraphs(graph); + subgraphs := GraphvizSubgraphs(gv); if IsBound(subgraphs[name]) then - error := "The graph already contains a subgraph with name {}."; - ErrorNoReturn(StringFormatted(error, name)); + ErrorFormatted("the 1st argument (a graphviz (di)graph) already has ", + " a subgraph with name \"{}\"", name); fi; - if IsGraphvizDigraph(graph) then - subgraph := GV_Digraph(graph, name); - elif IsGraphvizGraph(graph) or IsGraphvizContext(graph) then - subgraph := GV_Graph(graph, name); - else - ErrorNoReturn("Filter must be a filter for a graph category."); + # TODO why are the graph and context cases conflated here? + # Shouldn't this be something like + # if IsGraphvizContext(gv) then + # root := GraphvizRoot(gv); + # else + # root := gv; + # fi; + # Then use root instead of gv below? + if IsGraphvizDigraph(gv) then + subgraph := GV_Digraph(gv, name); + elif IsGraphvizGraph(gv) or IsGraphvizContext(gv) then + subgraph := GV_Graph(gv, name); fi; subgraphs[name] := subgraph; return subgraph; end); -InstallMethod(GraphvizAddSubgraph, -"for a graphviz (di)graph and an object", +InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph and an object", [IsGraphvizGraphOrDigraph, IsObject], {g, o} -> GraphvizAddSubgraph(g, String(o))); @@ -435,12 +418,15 @@ InstallMethod(GraphvizAddContext, "for a graphviz (di)graph and a string", [IsGraphvizGraphOrDigraph, IsString], function(graph, name) - local ctx, error, subgraphs; + local subgraphs, ctx; subgraphs := GraphvizSubgraphs(graph); + # TODO is GraphvizSubgraphs appropriately named? It seems to contain both + # contexts and subgraphs, rather than just subgraphs as the name suggests if IsBound(subgraphs[name]) then - error := "The graph already contains a subgraph with name {}."; - ErrorNoReturn(StringFormatted(error, name)); + # TODO why are we talking about subgraphs in the error? + ErrorFormatted("the 1st argument (a graphviz (di)graph) already has ", + " a subgraph with name \"{}\"", name); fi; ctx := GV_Context(graph, name); @@ -451,8 +437,7 @@ end); InstallMethod(GraphvizAddContext, "for a graphviz (di)graph", [IsGraphvizGraphOrDigraph], -g -> GraphvizAddContext(g, StringFormatted("no_name_{}", - String(GV_GetCounter(g))))); +g -> GraphvizAddContext(g, StringFormatted("no_name_{}", GV_GetCounter(g)))); InstallMethod(GraphvizAddContext, "for a graphviz (di)graph and an object", @@ -469,7 +454,7 @@ InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph and a string", [IsGraphvizGraphOrDigraph, IsString], function(g, name) local nodes; - # TODO error if there's no such node + # TODO error if there's no such node? nodes := GraphvizNodes(g); Unbind(nodes[name]); @@ -528,18 +513,11 @@ function(g, hn, tn) return g; end); +# TODO remove? + InstallMethod(GraphvizFilterEnds, "for a graphviz (di)graph and two objects", [IsGraphvizGraphOrDigraph, IsObject, IsObject], -function(g, o1, o2) - if not IsString(o1) then - o1 := String(o1); - fi; - if not IsString(o2) then - o2 := String(o2); - fi; - - GraphvizFilterEnds(g, o1, o2); -end); +{gv, o1, o2} -> GraphvizFilterEnds(gv, String(o1), String(o2))); InstallMethod(GraphvizRemoveAttr, "for a graphviz object and an object", [IsGraphvizObject, IsObject], @@ -559,15 +537,16 @@ function(obj, attr) return obj; end); -######################################################################## +############################################################################# # Stringify -######################################################################## +############################################################################# -InstallMethod(AsString, "for a graphviz graph", +# TODO AsString -> String +InstallMethod(AsString, "for a graphviz (di)graph", [IsGraphvizGraphOrDigraph], graph -> GV_StringifyGraph(graph, false)); InstallMethod(GraphvizSetNodeLabels, -"for a graphviz graph and list of colors", +"for a graphviz (di)graph and list of colors", [IsGraphvizGraphOrDigraph, IsList], function(gv, labels) local nodes, i; @@ -581,7 +560,7 @@ function(gv, labels) end); InstallMethod(GraphvizSetNodeColors, -"for a graphviz graph and list of colors", +"for a graphviz (di)graph and list of colors", [IsGraphvizGraphOrDigraph, IsList], function(gv, colors) local nodes, i; diff --git a/gap/gv.gd b/gap/gv.gd index 9af7225..3658ce0 100644 --- a/gap/gv.gd +++ b/gap/gv.gd @@ -30,7 +30,8 @@ DeclareOperation("GV_FindNode", [IsGraphvizGraphOrDigraph, IsObject]); DeclareOperation("GV_Pluralize", [IsInt, IsString]); DeclareOperation("GV_Node", [IsGraphvizGraphOrDigraph, IsString]); -DeclareOperation("GV_Edge", [IsGraphvizGraphOrDigraph, IsGraphvizNode, IsGraphvizNode]); +DeclareOperation("GV_Edge", +[IsGraphvizGraphOrDigraph, IsGraphvizNode, IsGraphvizNode]); DeclareOperation("GV_Graph", [IsGraphvizGraphOrDigraph, IsString]); DeclareOperation("GV_Digraph", [IsGraphvizDigraph, IsString]); DeclareOperation("GV_Context", [IsGraphvizGraphOrDigraph, IsString]); diff --git a/gap/gv.gi b/gap/gv.gi index 0c2d9c8..4395d86 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -121,7 +121,6 @@ InstallMethod(\=, "for IsGraphvizNode and IsGraphvizNode", # Constructors etc ############################################################################### - InstallMethod(GV_Map, "for no args", [], {} -> Objectify(GV_MapType, rec(Data := rec()))); @@ -240,7 +239,6 @@ InstallOtherMethod(IsBound\[\], [GV_IsMap, IsObject], {m, key} -> IsBound(m!.Data.(key))); - InstallMethod(GV_MapNames, "for a graphviz map", [GV_IsMap], m -> RecNames(m!.Data)); @@ -417,7 +415,8 @@ InstallMethod(GV_StringifyDigraphHead, "for a string", [IsGraphvizDigraph], graph -> StringFormatted("digraph {} {{\n", GraphvizName(graph))); # @ Return DOT subgraph head line. -InstallMethod(GV_StringifySubgraphHead, "for a string", [IsGraphvizGraphOrDigraph], +InstallMethod(GV_StringifySubgraphHead, "for a string", +[IsGraphvizGraphOrDigraph], graph -> StringFormatted("subgraph {} {{\n", GraphvizName(graph))); # @ Return DOT subgraph head line. diff --git a/tst/subgraph.tst b/tst/subgraph.tst index 94d0bc3..fe7141f 100644 --- a/tst/subgraph.tst +++ b/tst/subgraph.tst @@ -253,7 +253,8 @@ edge [label=testing123] node[color=blue] edge[color=blue] \n\n}\n" gap> g := GraphvizDigraph();; gap> s1 := GraphvizAddSubgraph(g, "a");; gap> s2 := GraphvizAddSubgraph(g, "a"); -Error, The graph already contains a subgraph with name a. +Error, the 1st argument (a graphviz (di)graph) already has a subgraph with na\ +me "a" # Test getting subgraphs by name gap> g := GraphvizDigraph();; From 4dbf0cd8c31f3fb55ca0542d6df750c2936ea773 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Tue, 14 May 2024 09:31:44 +0100 Subject: [PATCH 10/38] Remove GraphvizGetSubgraph and rename GraphvizFindGraph -> GraphvizFindSubgraphRecursive --- gap/dot.gd | 6 +++--- gap/dot.gi | 19 +++---------------- gap/gv.gi | 7 ++++++- tst/subgraph.tst | 30 +++++++++++++++--------------- 4 files changed, 27 insertions(+), 35 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index cc38809..d7412b6 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -93,7 +93,6 @@ DeclareOperation("GraphvizNodes", [IsGraphvizGraphOrDigraph]); #! @Returns the subgraphs of the provided graphviz graph. #! @Description gets the subgraphs of a provided graphviz graph. DeclareOperation("GraphvizSubgraphs", [IsGraphvizGraphOrDigraph]); -DeclareOperation("GraphvizGetSubgraph", [IsGraphvizGraphOrDigraph, IsObject]); #! @Arguments graph, name #! @Returns a graph with the provided name. @@ -101,8 +100,9 @@ DeclareOperation("GraphvizGetSubgraph", [IsGraphvizGraphOrDigraph, IsObject]); #! Searches through the tree of subgraphs connected to this subgraph for a graph #! with the provided name. #! It returns the graph if it exists. -#! If no such graph exists then it will return fail. -DeclareOperation("GraphvizFindGraph", [IsGraphvizGraphOrDigraph, IsObject]); +#! If no such graph exists then it will return fail. +DeclareOperation("GraphvizFindSubgraphRecursive", +[IsGraphvizGraphOrDigraph, IsObject]); #! @Arguments graph #! @Returns the edges of the provided graphviz graph. diff --git a/gap/dot.gi b/gap/dot.gi index f83b620..228f2fe 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -133,16 +133,6 @@ x -> x!.Tail); InstallMethod(GraphvizHead, "for a graphviz edge", [IsGraphvizEdge], x -> x!.Head); -# TODO remove the next two? - -InstallMethod(GraphvizGetSubgraph, "for a graphviz (di)graph and string", -[IsGraphvizGraphOrDigraph, IsString], -{x, name} -> GraphvizSubgraphs(x)[name]); - -InstallMethod(GraphvizGetSubgraph, "for a graphviz (di)graph and an object", -[IsGraphvizGraphOrDigraph, IsObject], -{x, o} -> GraphvizSubgraphs(x)[String(o)]); - # Accessing node attributes InstallMethod(\[\], "for a graphviz node and a string", @@ -191,7 +181,6 @@ end); # Accessor for graphs and digraphs -# TODO remove either this or GraphvizNode(gv, name); InstallMethod(\[\], "for a graphviz (di)graph and string", [IsGraphvizGraphOrDigraph, IsString], {graph, node} -> GraphvizNodes(graph)[node]); @@ -200,17 +189,15 @@ InstallMethod(\[\], "for a graphviz (di)graph and object", [IsGraphvizGraphOrDigraph, IsObject], {g, o} -> g[String(o)]); -# TODO is this named appropriately? Should it be FindSubgraph? - -InstallMethod(GraphvizFindGraph, +InstallMethod(GraphvizFindSubgraphRecursive, "for a graphviz (di)graph and a string", [IsGraphvizGraphOrDigraph, IsString], {g, s} -> GV_GraphTreeSearch(g, v -> GraphvizName(v) = s)); -InstallMethod(GraphvizFindGraph, +InstallMethod(GraphvizFindSubgraphRecursive, "for a graphviz (di)graph and a string", [IsGraphvizGraphOrDigraph, IsObject], -{g, o} -> GraphvizFindGraph(g, String(o))); +{g, o} -> GraphvizFindSubgraphRecursive(g, String(o))); ############################################################################# # GraphvizSetName diff --git a/gap/gv.gi b/gap/gv.gi index 4395d86..d06a488 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -212,7 +212,7 @@ end); InstallOtherMethod(\[\], "for a graphviz map and an object", -[GV_IsMap, IsObject], +[GV_IsMap, IsString], function(m, o) if IsBound(m[o]) then return m!.Data.(o); @@ -220,6 +220,11 @@ function(m, o) return fail; end); +InstallOtherMethod(\[\], +"for a graphviz map and an object", +[GV_IsMap, IsObject], +{m, o} -> m[String(o)]); + InstallOtherMethod(\[\]\:\=, "for a graphviz map and two objects", [GV_IsMap, IsObject, IsObject], diff --git a/tst/subgraph.tst b/tst/subgraph.tst index fe7141f..55cf739 100644 --- a/tst/subgraph.tst +++ b/tst/subgraph.tst @@ -260,31 +260,31 @@ me "a" gap> g := GraphvizDigraph();; gap> s1 := GraphvizAddSubgraph(g, "a");; gap> s2 := GraphvizAddSubgraph(g, "b");; -gap> GraphvizGetSubgraph(g, "a"); +gap> GraphvizSubgraphs(g)["a"]; -gap> GraphvizGetSubgraph(g, "b"); +gap> GraphvizSubgraphs(g)["b"]; -gap> GraphvizGetSubgraph(g, "d"); +gap> GraphvizSubgraphs(g)["d"]; fail # Test getting context (subgraph) by name gap> g := GraphvizDigraph();; gap> s1 := GraphvizAddSubgraph(g, "a");; gap> s2 := GraphvizAddContext(g, "c");; -gap> GraphvizGetSubgraph(g, "a"); +gap> GraphvizSubgraphs(g)["a"]; -gap> GraphvizGetSubgraph(g, "c"); +gap> GraphvizSubgraphs(g)["c"]; # Test adding a nested subgraph gap> g := GraphvizGraph();; gap> s1 := GraphvizAddSubgraph(g, "a");; gap> s2 := GraphvizAddSubgraph(s1, "c");; -gap> GraphvizGetSubgraph(g, "a"); +gap> GraphvizSubgraphs(g)["a"]; -gap> GraphvizGetSubgraph(g, "c"); +gap> GraphvizSubgraphs(g)["c"]; fail -gap> GraphvizGetSubgraph(s1, "c"); +gap> GraphvizSubgraphs(s1)["c"]; # Test displaying a nested subgraph @@ -307,13 +307,13 @@ gap> GraphvizAddContext(g, 11); # Test getting subgraphs with non-string names gap> g := GraphvizGraph();; gap> GraphvizAddContext(g, ["a"]);; -gap> GraphvizGetSubgraph(g, ["a"]); +gap> GraphvizSubgraphs(g)[["a"]]; # Test finding subgraph (parent) gap> g := GraphvizGraph("a");; gap> s := GraphvizAddSubgraph(g, "b");; -gap> o := GraphvizFindGraph(s, "a"); +gap> o := GraphvizFindSubgraphRecursive(s, "a"); gap> IsIdenticalObj(o, g); true @@ -321,7 +321,7 @@ true # Test finding subgraph (child) gap> g := GraphvizGraph("a");; gap> s := GraphvizAddSubgraph(g, "b");; -gap> o := GraphvizFindGraph(g, "b"); +gap> o := GraphvizFindSubgraphRecursive(g, "b"); gap> IsIdenticalObj(o, s); true @@ -330,14 +330,14 @@ true gap> g := GraphvizGraph("a");; gap> s := GraphvizAddSubgraph(g, "b");; gap> s2 := GraphvizAddSubgraph(g, "c");; -gap> o := GraphvizFindGraph(s, "c"); +gap> o := GraphvizFindSubgraphRecursive(s, "c"); gap> IsIdenticalObj(o, s2); true # Test finding subgraph (self) gap> g := GraphvizGraph("a");; -gap> o := GraphvizFindGraph(g, "a"); +gap> o := GraphvizFindSubgraphRecursive(g, "a"); gap> IsIdenticalObj(o, g); true @@ -350,7 +350,7 @@ gap> a3 := GraphvizAddSubgraph(a2, "a3");; gap> b1 := GraphvizAddSubgraph(g, "b1");; gap> b2 := GraphvizAddSubgraph(b1, "b2");; gap> b3 := GraphvizAddSubgraph(b2, "b3");; -gap> o := GraphvizFindGraph(a3, "b3"); +gap> o := GraphvizFindSubgraphRecursive(a3, "b3"); gap> IsIdenticalObj(o, b3); true @@ -376,7 +376,7 @@ gap> AsString(g); # Test finding subgraph (non-string name) gap> g := GraphvizGraph("r");; gap> s := GraphvizAddSubgraph(g, 1);; -gap> o := GraphvizFindGraph(g, 1); +gap> o := GraphvizFindSubgraphRecursive(g, 1); gap> IsIdenticalObj(o, s); true From 2eb081b16bcf1d78c988232c8131fc7eafae654c Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Tue, 14 May 2024 09:44:19 +0100 Subject: [PATCH 11/38] More cleanups --- TODO.md | 4 ++-- gap/dot.gi | 14 +++++++++----- tst/dot.tst | 3 +++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/TODO.md b/TODO.md index 8ba8f71..5165e96 100644 --- a/TODO.md +++ b/TODO.md @@ -8,11 +8,11 @@ - make it so when duplicates are added to global graph attrs the old values are automatically replaced - Improve behaviour around ':' syntax - mimic python package -## TODO (ONCE THIS IS EMPTY THEN DONE!) - - Ask about `Pluralize` - think james said to remove for old versions of gap +## TODO - Update docs - Add more unit tests - Thoroughly test the ':' syntax more (might have broke when the quotes were changed) + - PrintObj method is missing for nodes (and probably edges) ## Other - relates to deadnaut github issue https://www.mankier.com/1/nauty-dretodot diff --git a/gap/dot.gi b/gap/dot.gi index 228f2fe..c13c537 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -259,9 +259,6 @@ function(x, name, value) attrs := GraphvizAttrs(x); name := String(name); value := String(value); - if ' ' in name then - name := StringFormatted("\"{}\"", name); - fi; if ' ' in value then # Replace with call to GV_QuoteName or whatever TODO value := StringFormatted("\"{}\"", value); @@ -410,6 +407,7 @@ function(graph, name) subgraphs := GraphvizSubgraphs(graph); # TODO is GraphvizSubgraphs appropriately named? It seems to contain both # contexts and subgraphs, rather than just subgraphs as the name suggests + # See https://github.com/digraphs/graphviz/issues/19 if IsBound(subgraphs[name]) then # TODO why are we talking about subgraphs in the error? ErrorFormatted("the 1st argument (a graphviz (di)graph) already has ", @@ -441,9 +439,15 @@ InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph and a string", [IsGraphvizGraphOrDigraph, IsString], function(g, name) local nodes; - # TODO error if there's no such node? nodes := GraphvizNodes(g); - Unbind(nodes[name]); + if nodes[name] <> fail then + Unbind(nodes[name]); + else + # Don't just silently do nothing + ErrorFormatted("the 2nd argument (node name string) \"{}\"", + " is not a node of the 1st argument (a graphviz (di)graph)", + name); + fi; # remove incident edges GraphvizFilterEdges(g, diff --git a/tst/dot.tst b/tst/dot.tst index 4f0c708..366dc37 100644 --- a/tst/dot.tst +++ b/tst/dot.tst @@ -37,6 +37,9 @@ gap> n := GraphvizAddNode(g, "test");; gap> GraphvizSetAttrs(n, rec(color := "red", label := "lab"));; gap> AsString(g); "//dot\ngraph {\n\ttest [color=red, label=lab]\n}\n" +gap> GraphvizRemoveNode(g, "banana"); +Error, the 2nd argument (node name string) "banana" is not a node of the 1st a\ +rgument (a graphviz (di)graph) # Test stringify with edge (digraphs) gap> g := GraphvizDigraph();; From 61e63b44066481d1f74fe4d3682101e89ab181e9 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Tue, 14 May 2024 09:55:43 +0100 Subject: [PATCH 12/38] Rename GraphvizFilterEnds -> GraphvizRemoveEdges --- gap/dot.gd | 2 +- gap/dot.gi | 19 +++++++++---------- tst/edge.tst | 26 +++++++++++++------------- tst/subgraph.tst | 2 +- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index d7412b6..e862db5 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -174,7 +174,7 @@ DeclareOperation("GraphvizFilterEdges", [IsGraphvizGraphOrDigraph, IsFunction]); #! @Returns the modified graph. #! @Description Filters the graph's edges, removing edges between nodes with #! the specified names. -DeclareOperation("GraphvizFilterEnds", +DeclareOperation("GraphvizRemoveEdges", [IsGraphvizGraphOrDigraph, IsObject, IsObject]); #! @Subsection For modifying object attributes. diff --git a/gap/dot.gi b/gap/dot.gi index c13c537..daaa43d 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -433,8 +433,6 @@ InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph and node", [IsGraphvizGraphOrDigraph, IsGraphvizNode], {g, node} -> GraphvizRemoveNode(g, GraphvizName(node))); -# TODO GraphvizRemoveEdges(gv, n1, n2) - InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph and a string", [IsGraphvizGraphOrDigraph, IsString], function(g, name) @@ -483,9 +481,7 @@ function(g, filter) return g; end); -# TODO remove? - -InstallMethod(GraphvizFilterEnds, "for a graphviz (di)graph and two strings", +InstallMethod(GraphvizRemoveEdges, "for a graphviz (di)graph and two strings", [IsGraphvizGraphOrDigraph, IsString, IsString], function(g, hn, tn) GraphvizFilterEdges(g, @@ -504,17 +500,16 @@ function(g, hn, tn) return g; end); -# TODO remove? - -InstallMethod(GraphvizFilterEnds, "for a graphviz (di)graph and two objects", +InstallMethod(GraphvizRemoveEdges, "for a graphviz (di)graph and two objects", [IsGraphvizGraphOrDigraph, IsObject, IsObject], -{gv, o1, o2} -> GraphvizFilterEnds(gv, String(o1), String(o2))); +{gv, o1, o2} -> GraphvizRemoveEdges(gv, String(o1), String(o2))); InstallMethod(GraphvizRemoveAttr, "for a graphviz object and an object", [IsGraphvizObject, IsObject], function(obj, attr) local attrs; attrs := GraphvizAttrs(obj); + # TODO error if no such attr? Unbind(attrs[String(attr)]); return obj; end); @@ -541,7 +536,11 @@ InstallMethod(GraphvizSetNodeLabels, [IsGraphvizGraphOrDigraph, IsList], function(gv, labels) local nodes, i; - # TODO error if labels and nodes aren't same size + if Size(GraphvizNodes(gv)) <> Size(labels) then + ErrorFormatted("the 2nd argument (list of node labels) ", + "has incorrect length, expected {}, but ", + "found {}", Size(GraphvizNodes(gv)), Size(labels)); + fi; # TODO GV_ErrorIfNotValidLabel nodes := GraphvizNodes(gv); for i in [1 .. Size(nodes)] do diff --git a/tst/edge.tst b/tst/edge.tst index c0117db..ebd5bc3 100644 --- a/tst/edge.tst +++ b/tst/edge.tst @@ -36,19 +36,19 @@ gap> c := GraphvizAddNode(g, "c");; gap> d := GraphvizAddNode(g, "d");; gap> ab := GraphvizAddEdge(g, a, b);; gap> cd := GraphvizAddEdge(g, c, d);; -gap> GraphvizFilterEnds(g, "a", "c"); +gap> GraphvizRemoveEdges(g, "a", "c"); -gap> GraphvizFilterEnds(g, "b", "d"); +gap> GraphvizRemoveEdges(g, "b", "d"); -gap> GraphvizFilterEnds(g, "a", "b"); +gap> GraphvizRemoveEdges(g, "a", "b"); gap> GraphvizEdges(g); [ ] -gap> GraphvizFilterEnds(g, "c", "d"); +gap> GraphvizRemoveEdges(g, "c", "d"); gap> GraphvizEdges(g); [ ] -gap> GraphvizFilterEnds(g, "c", "d"); +gap> GraphvizRemoveEdges(g, "c", "d"); # Test filtering edges by names (graph) @@ -59,19 +59,19 @@ gap> c := GraphvizAddNode(g, "c");; gap> d := GraphvizAddNode(g, "d");; gap> ab := GraphvizAddEdge(g, a, b);; gap> cd := GraphvizAddEdge(g, c, d);; -gap> GraphvizFilterEnds(g, "a", "c"); +gap> GraphvizRemoveEdges(g, "a", "c"); -gap> GraphvizFilterEnds(g, "b", "d"); +gap> GraphvizRemoveEdges(g, "b", "d"); -gap> GraphvizFilterEnds(g, "b", "a"); +gap> GraphvizRemoveEdges(g, "b", "a"); gap> GraphvizEdges(g); [ ] -gap> GraphvizFilterEnds(g, "d", "c"); +gap> GraphvizRemoveEdges(g, "d", "c"); gap> GraphvizEdges(g); [ ] -gap> GraphvizFilterEnds(g, "c", "d"); +gap> GraphvizRemoveEdges(g, "c", "d"); # Test adding edge between nodes which are not in the graph, but there exists nodes in the graph which share their names. @@ -110,13 +110,13 @@ gap> GraphvizAddEdge(g, 1, "a"); gap> GraphvizAddEdge(g, 1, 1); -gap> GraphvizFilterEnds(g, "a", 1);; +gap> GraphvizRemoveEdges(g, "a", 1);; gap> GraphvizEdges(g); [ , ] -gap> GraphvizFilterEnds(g, 1, "a");; +gap> GraphvizRemoveEdges(g, 1, "a");; gap> GraphvizEdges(g); [ ] -gap> GraphvizFilterEnds(g, 1, 1);; +gap> GraphvizRemoveEdges(g, 1, 1);; gap> GraphvizEdges(g); [ ] diff --git a/tst/subgraph.tst b/tst/subgraph.tst index 55cf739..5b2fec9 100644 --- a/tst/subgraph.tst +++ b/tst/subgraph.tst @@ -117,7 +117,7 @@ gap> GraphvizAddEdge(parent, "x", "y");; gap> GraphvizAddEdge(main, "x", "y");; gap> GraphvizAddEdge(sibling, "x", "y");; gap> GraphvizAddEdge(child, "x", "y");; -gap> GraphvizFilterEnds(main, "x", "y");; +gap> GraphvizRemoveEdges(main, "x", "y");; gap> GraphvizEdges(g); [ ] gap> GraphvizEdges(parent); From 7f4951699d0953569f24b9c8d42a866f5d543fc4 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Tue, 14 May 2024 09:58:19 +0100 Subject: [PATCH 13/38] Rename AsString -> String This was my mistake when we discussed this before, I thought AsString was a thing in GAP but it turns out it isn't. --- gap/dot.gd | 2 +- gap/dot.gi | 3 +-- gap/gv.gd | 2 +- gap/splash.gi | 2 +- tst/dot.tst | 16 ++++++++-------- tst/examples/angles.tst | 4 ++-- tst/examples/btree.tst | 2 +- tst/examples/cluster.tst | 2 +- tst/examples/cluster_edge.tst | 2 +- tst/examples/colors.tst | 2 +- tst/examples/er.tst | 2 +- tst/examples/fsm.tst | 2 +- tst/examples/g_c_n.tst | 4 ++-- tst/examples/hello.tst | 2 +- tst/examples/process.tst | 2 +- tst/examples/rank_same.tst | 2 +- tst/examples/structs.tst | 2 +- tst/examples/traffic_lights.tst | 2 +- tst/examples/unix.tst | 2 +- tst/graph.tst | 2 +- tst/node.tst | 4 ++-- tst/subgraph.tst | 18 +++++++++--------- 22 files changed, 40 insertions(+), 41 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index e862db5..e911100 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -198,7 +198,7 @@ DeclareOperation("GraphvizRemoveAttr", [IsGraphvizObject, IsObject]); #! @Section Outputting #! @Arguments graph #! @Returns the dot representation of the graphviz object. -DeclareOperation("AsString", [IsGraphvizGraphOrDigraph]); +# TODO document "String" # TODO PrintObj diff --git a/gap/dot.gi b/gap/dot.gi index daaa43d..6dda979 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -527,8 +527,7 @@ end); # Stringify ############################################################################# -# TODO AsString -> String -InstallMethod(AsString, "for a graphviz (di)graph", +InstallMethod(String, "for a graphviz (di)graph", [IsGraphvizGraphOrDigraph], graph -> GV_StringifyGraph(graph, false)); InstallMethod(GraphvizSetNodeLabels, diff --git a/gap/gv.gd b/gap/gv.gd index 3658ce0..2e68cb7 100644 --- a/gap/gv.gd +++ b/gap/gv.gd @@ -38,7 +38,7 @@ DeclareOperation("GV_Context", [IsGraphvizGraphOrDigraph, IsString]); DeclareOperation("GV_Map", []); DeclareOperation("GV_MapNames", [GV_IsMap]); -# TODO required? Replace with AsString or just String? +# TODO required? Replace with String or just String? DeclareOperation("GV_EnsureString", [IsObject]); DeclareOperation("GV_HasNode", [IsGraphvizGraphOrDigraph, IsObject]); diff --git a/gap/splash.gi b/gap/splash.gi index b959344..32d8b05 100644 --- a/gap/splash.gi +++ b/gap/splash.gi @@ -16,7 +16,7 @@ if not IsBound(Splash) then ErrorFormatted("the 1st argument must be a string or ", "graphviz graph, found {}", TNAM_OBJ(arg[1])); elif IsGraphvizGraphOrDigraph(arg[1]) then - arg[1] := AsString(arg[1]); + arg[1] := String(arg[1]); fi; str := arg[1]; diff --git a/tst/dot.tst b/tst/dot.tst index 366dc37..43d3a83 100644 --- a/tst/dot.tst +++ b/tst/dot.tst @@ -35,7 +35,7 @@ gap> GraphvizAttrs(g); gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "test");; gap> GraphvizSetAttrs(n, rec(color := "red", label := "lab"));; -gap> AsString(g); +gap> String(g); "//dot\ngraph {\n\ttest [color=red, label=lab]\n}\n" gap> GraphvizRemoveNode(g, "banana"); Error, the 2nd argument (node name string) "banana" is not a node of the 1st a\ @@ -49,7 +49,7 @@ gap> GraphvizSetAttrs(a, rec(color := "blue"));; gap> GraphvizSetAttrs(b, rec(color := "red"));; gap> e := GraphvizAddEdge(g, a, b);; gap> GraphvizSetAttrs(e, rec(color := "green"));; -gap> AsString(g); +gap> String(g); "//dot\ndigraph {\n\ta [color=blue]\n\tb [color=red]\n\ta -> b [color=green]\ \n}\n" @@ -61,13 +61,13 @@ gap> GraphvizSetAttrs(a, rec(color := "blue"));; gap> GraphvizSetAttrs(b, rec(color := "red"));; gap> e := GraphvizAddEdge(g, a, b);; gap> GraphvizSetAttrs(e, rec(color := "green"));; -gap> AsString(g); +gap> String(g); "//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); +gap> String(g); "//dot\ngraph {\n}\n" # Test unknown attributes (node) @@ -87,24 +87,24 @@ gap> GraphvizSetAttr(g, "test", "false"); gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "node");; gap> GraphvizSetAttr(n, "label", ">>hello");; -gap> AsString(g); +gap> String(g); "//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); +gap> String(g); "//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); +gap> String(g); "//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); +gap> String(g); "//dot\ngraph {\n\ta\n\tb\n\ta -- b [label=\"before>>hello\"]\n}\n" # diff --git a/tst/examples/angles.tst b/tst/examples/angles.tst index fc39502..cab0d92 100644 --- a/tst/examples/angles.tst +++ b/tst/examples/angles.tst @@ -68,7 +68,7 @@ gap> GraphvizAddEdge(g, "n5", "n14"); #@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") -gap> Print(AsString(g)); +gap> Print(String(g)); //dot digraph G { bgcolor=blue @@ -103,7 +103,7 @@ ientangle=360,label="n9:n360", fontcolor=black] label="Radial Angle Variations\ n5 -> n14 } #@else -gap> Print(AsString(g)); +gap> Print(String(g)); //dot digraph G { bgcolor=blue diff --git a/tst/examples/btree.tst b/tst/examples/btree.tst index 555996e..1e22687 100644 --- a/tst/examples/btree.tst +++ b/tst/examples/btree.tst @@ -55,7 +55,7 @@ gap> GraphvizAddEdge(s, "node4:f2", "node6:f1"); gap> GraphvizAddEdge(s, "node4:f0", "node5:f1"); -gap> AsString(s) = +gap> String(s) = > "//dot\ndigraph g {\n\tnode [shape=record, height=.1] \n\tnode0 [label=\" \ > | G|\"]\n\tnode1 [label=\" | E|\"]\n\tnode2 [label=\" \ > | B|\"]\n\tnode3 [label=\" | F|\"]\n\tnode4 [label=\" \ diff --git a/tst/examples/cluster.tst b/tst/examples/cluster.tst index 2786feb..4f4ac8c 100644 --- a/tst/examples/cluster.tst +++ b/tst/examples/cluster.tst @@ -74,7 +74,7 @@ gap> GraphvizSetAttr(graph["end"], "shape", "Msquare"); # -gap> AsString(graph); +gap> String(graph); "//dot\ndigraph G {\nsubgraph cluster_0 {\n\tcolor=\"lightgrey\" style=\"fille\ d\" node [color=\"white\", style=\"filled\"] label=\"process #1\" \n\ta0\n\ta1\ \n\ta0 -> a1\n\ta2\n\ta1 -> a2\n\ta3\n\ta2 -> a3\n}\nsubgraph cluster_1 {\n\tc\ diff --git a/tst/examples/cluster_edge.tst b/tst/examples/cluster_edge.tst index 3a017fe..0af6cb6 100644 --- a/tst/examples/cluster_edge.tst +++ b/tst/examples/cluster_edge.tst @@ -53,7 +53,7 @@ gap> GraphvizSetAttr(e, "ltail", "cluster0"); gap> GraphvizAddEdge(g, "d", "h"); -gap> AsString(g); +gap> String(g); "//dot\ndigraph G {\n\tcompound=true \nsubgraph cluster0 {\n\ta\n\tb\n\ta -> b\ \n\tc\n\ta -> c\n\td\n\tb -> d\n\tc -> d\n}\nsubgraph cluster1 {\n\te\n\tg\n\t\ e -> g\n\tf\n\te -> f\n}\n\tb -> f [lhead=cluster1]\n\td -> e\n\tc -> g [lhead\ diff --git a/tst/examples/colors.tst b/tst/examples/colors.tst index d1f4d8c..695c008 100644 --- a/tst/examples/colors.tst +++ b/tst/examples/colors.tst @@ -54,7 +54,7 @@ gap> GraphvizSetAttr(node, "fillcolor", "deeppink"); # -gap> AsString(g); +gap> String(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 diff --git a/tst/examples/er.tst b/tst/examples/er.tst index a1dcbf3..41228f0 100644 --- a/tst/examples/er.tst +++ b/tst/examples/er.tst @@ -104,7 +104,7 @@ gap> GraphvizSetAttr(e, "fontsize=\"20\""); # -gap> AsString(e); +gap> String(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 diff --git a/tst/examples/fsm.tst b/tst/examples/fsm.tst index ad70da3..177b453 100644 --- a/tst/examples/fsm.tst +++ b/tst/examples/fsm.tst @@ -73,7 +73,7 @@ gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_8", "LR_5"), "label", "\"S(a)\"" # -gap> AsString(f); +gap> String(f); "//dot\ndigraph finite_state_machine {\n\trankdir=LR size=\"8,5\" \n// termina\ ls context \n\tnode [shape=doublecircle] \n\tLR_0\n\tLR_3\n\tLR_4\n\tLR_8\n\tr\ ankdir=LR size=\"8,5\" \n\n// nodes context \n\tnode [shape=circle] \n\tLR_2\n\ diff --git a/tst/examples/g_c_n.tst b/tst/examples/g_c_n.tst index f38f5b7..beea2f2 100644 --- a/tst/examples/g_c_n.tst +++ b/tst/examples/g_c_n.tst @@ -36,7 +36,7 @@ gap> GraphvizAddNode(cluster1, "anode"); #@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") -gap> Print(AsString(g)); +gap> Print(String(g)); //dot graph G { bgcolor="purple:pink" label="agraph" fontcolor="white" @@ -48,7 +48,7 @@ ntangle=270 } } #@else -gap> Print(AsString(g)); +gap> Print(String(g)); //dot graph G { bgcolor="purple:pink" label="agraph" fontcolor="white" diff --git a/tst/examples/hello.tst b/tst/examples/hello.tst index d9af8ae..8d4cc54 100644 --- a/tst/examples/hello.tst +++ b/tst/examples/hello.tst @@ -20,7 +20,7 @@ gap> graph := GraphvizDigraph("G"); gap> GraphvizAddEdge(graph, "hello", "world"); -gap> AsString(graph); +gap> String(graph); "//dot\ndigraph G {\n\thello\n\tworld\n\thello -> world\n}\n" # diff --git a/tst/examples/process.tst b/tst/examples/process.tst index 9b922b8..44b2f11 100644 --- a/tst/examples/process.tst +++ b/tst/examples/process.tst @@ -47,7 +47,7 @@ gap> GraphvizAddEdge(graph, "runswap", "runmem"); gap> GraphvizAddEdge(graph, "new", "runmem"); -gap> AsString(graph); +gap> String(graph); "//dot\ngraph G {\n\tengine=\"sfdp\" \n\trun\n\tintr\n\trun -- intr\n\trunbl\n\ \tintr -- runbl\n\trunbl -- run\n\tkernel\n\trun -- kernel\n\tzombie\n\tkernel\ -- zombie\n\tsleep\n\tkernel -- sleep\n\trunmem\n\tkernel -- runmem\n\tswap\n\ diff --git a/tst/examples/rank_same.tst b/tst/examples/rank_same.tst index 685dee2..df7355d 100644 --- a/tst/examples/rank_same.tst +++ b/tst/examples/rank_same.tst @@ -58,7 +58,7 @@ gap> GraphvizAddEdge(g, "X", "Y"); # -gap> AsString(g); +gap> String(g); "//dot\ndigraph {\nsubgraph no_name_1 {\n\trank=same \n\tA\n\tX\n}\n\tC\nsubg\ raph no_name_3 {\n\trank=same \n\tB\n\tD\n\tY\n}\n\tA -> B\n\tA -> C\n\tC -> D\ \n\tX -> Y\n}\n" diff --git a/tst/examples/structs.tst b/tst/examples/structs.tst index 2068f9f..f10bd74 100644 --- a/tst/examples/structs.tst +++ b/tst/examples/structs.tst @@ -63,7 +63,7 @@ gap> GraphvizAddEdge(s, "struct1:f2", "struct3:here"); # -gap> AsString(s); +gap> String(s); "//dot\ndigraph structs {\n\tnode [shape=\"plaintext\"] \n\tstruct1 [label=<\n\nleft\nmiddleright\n\n>]\n\tstru\ diff --git a/tst/examples/traffic_lights.tst b/tst/examples/traffic_lights.tst index 295ac0f..5654ab7 100644 --- a/tst/examples/traffic_lights.tst +++ b/tst/examples/traffic_lights.tst @@ -79,7 +79,7 @@ gap> GraphvizSetAttr(t, "fontsize=12"); # -gap> AsString(t); +gap> String(t); "//dot\ndigraph TrafficLights {\n\tengine=neato overlap=\"false\" label=\"Petr\ iNet Model TrafficLights\nExtracted from ConceptBase and laid out by Graphviz\ \"\n fontsize=12 \nsubgraph ctx1 {\n\tnode [shape=\"box\"] \n\tgy2\n\tyr2\n\tr\ diff --git a/tst/examples/unix.tst b/tst/examples/unix.tst index 5207345..e63d3f2 100644 --- a/tst/examples/unix.tst +++ b/tst/examples/unix.tst @@ -124,7 +124,7 @@ gap> GraphvizAddEdge(u, "System V.2", "System V.3"); # -gap> AsString(u) = +gap> String(u) = > "//dot\ndigraph unix {\n\tnode [color=\"lightblue2\", style=\"filled\", size=\ > \"6,6\"] \n\t\"5th Edition\"\n\t\"6th Edition\"\n\t\"5th Edition\" -> \"6th Ed\ > ition\"\n\t\"PWB 1.0\"\n\t\"5th Edition\" -> \"PWB 1.0\"\n\tLSX\n\t\"6th Editi\ diff --git a/tst/graph.tst b/tst/graph.tst index dcdd261..d485ee1 100644 --- a/tst/graph.tst +++ b/tst/graph.tst @@ -176,7 +176,7 @@ gap> GraphvizAttrs(g); gap> g := GraphvizGraph();; gap> GraphvizSetAttr(g, "color", "red");; gap> GraphvizSetAttr(g, "color", "blue");; -gap> AsString(g); +gap> String(g); "//dot\ngraph {\n\tcolor=red color=blue \n}\n" # # Test removing attributes from a graph TODO uncomment or delete diff --git a/tst/node.tst b/tst/node.tst index 9a8a506..0555e43 100644 --- a/tst/node.tst +++ b/tst/node.tst @@ -54,14 +54,14 @@ rec( shape := "circle" ) # Test name containing ':' gap> g := GraphvizGraph();; gap> GraphvizAddNode(g, "test:colon");; -gap> AsString(g); +gap> String(g); "//dot\ngraph {\n\ttest:colon\n}\n" # Test non-string name containing ':' gap> g := GraphvizGraph();; gap> GraphvizAddNode(g, 111); -gap> AsString(g); +gap> String(g); "//dot\ngraph {\n\t111\n}\n" # Test removing a node with a non-string name diff --git a/tst/subgraph.tst b/tst/subgraph.tst index 5b2fec9..162ba6f 100644 --- a/tst/subgraph.tst +++ b/tst/subgraph.tst @@ -134,7 +134,7 @@ gap> GraphvizAddEdge(g, "x", "y");; gap> GraphvizSetAttr(s, "color", "red");; gap> GraphvizSetAttr(s, "node [color=red]");; gap> GraphvizSetAttr(s, "edge [color=red]");; -gap> AsString(g); +gap> String(g); "//dot\ndigraph {\nsubgraph a {\n\tcolor=red node [color=red] edge [color=red\ ] \n}\n\tx\n\ty\n\tx -> y\n}\n" @@ -145,7 +145,7 @@ gap> GraphvizAddEdge(g, "x", "y");; gap> GraphvizSetAttr(s, "color", "red");; gap> GraphvizSetAttr(s, "node [color=red]");; gap> GraphvizSetAttr(s, "edge [color=red]");; -gap> AsString(g); +gap> String(g); "//dot\ngraph {\nsubgraph a {\n\tcolor=red node [color=red] edge [color=red] \ \n}\n\tx\n\ty\n\tx -- y\n}\n" @@ -156,7 +156,7 @@ gap> GraphvizAddEdge(g, "x", "y");; gap> GraphvizSetAttr(s, "color", "red");; gap> GraphvizSetAttr(s, "node [color=red]");; gap> GraphvizSetAttr(s, "edge [color=red]");; -gap> AsString(g); +gap> String(g); "//dot\ngraph {\n// a context \n\tcolor=red node [color=red] edge [color=red]\ \n\n\tx\n\ty\n\tx -- y\n}\n" @@ -167,14 +167,14 @@ gap> GraphvizAddEdge(g, "x", "y");; gap> GraphvizSetAttr(s, "color", "red");; gap> GraphvizSetAttr(s, "node [color=red]");; gap> GraphvizSetAttr(s, "edge [color=red]");; -gap> AsString(g); +gap> String(g); "//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); +gap> String(g); "//dot\ndigraph {\nsubgraph no_name_1 {\n}\n}\n" # finding a node in a sibling graph @@ -244,7 +244,7 @@ gap> GraphvizSetAttr(g, "node[color=blue]");; gap> GraphvizSetAttr(g, "edge[color=blue]");; gap> GraphvizSetAttr(ctx, "node[color=red]");; gap> GraphvizAddNode(ctx, "a");; -gap> AsString(g); +gap> String(g); "//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" @@ -291,7 +291,7 @@ gap> GraphvizSubgraphs(s1)["c"]; gap> g := GraphvizGraph();; gap> s1 := GraphvizAddSubgraph(g, "a");; gap> s2 := GraphvizAddSubgraph(s1, "c");; -gap> AsString(g); +gap> String(g); "//dot\ngraph {\nsubgraph a {\nsubgraph c {\n}\n}\n}\n" # Test subgraphs with non-string names @@ -360,7 +360,7 @@ gap> g := GraphvizGraph("g");; gap> parent := GraphvizAddContext(g, "parent");; gap> ctx := GraphvizAddContext(parent, "ctx");; gap> GraphvizAddEdge(ctx, "a", "b");; -gap> AsString(g); +gap> String(g); "//dot\ngraph g {\n// parent context \n// ctx context \n\ta\n\tb\n\ta -- b\n\n\ \n}\n" @@ -369,7 +369,7 @@ gap> g := GraphvizDigraph("g");; gap> parent := GraphvizAddContext(g, "parent");; gap> ctx := GraphvizAddContext(parent, "ctx");; gap> GraphvizAddEdge(ctx, "a", "b");; -gap> AsString(g); +gap> String(g); "//dot\ndigraph g {\n// parent context \n// ctx context \n\ta\n\tb\n\ta -> b\n\ \n\n}\n" From 9118809c1505db1d4bed1f026a8288ce5bab557e Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Tue, 14 May 2024 16:41:37 +0100 Subject: [PATCH 14/38] Add splash.gd --- gap/splash.gd | 15 ++++ gap/splash.gi | 219 +++++++++++++++++++++++++++----------------------- init.g | 1 + 3 files changed, 133 insertions(+), 102 deletions(-) diff --git a/gap/splash.gd b/gap/splash.gd index e69de29..919a68a 100644 --- a/gap/splash.gd +++ b/gap/splash.gd @@ -0,0 +1,15 @@ +############################################################################# +## +## splash.gd +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## + +# This function is transplanted from the Digraphs package to here. The original +# function was written by A. Egri-Nagy and Manuel Delgado, with some minor +# modifications by J. Mitchell. + +DeclareGlobalFunction("Splash"); diff --git a/gap/splash.gi b/gap/splash.gi index 32d8b05..e61e9ba 100644 --- a/gap/splash.gi +++ b/gap/splash.gi @@ -1,118 +1,133 @@ -# TODO file header -# TODO rename file to remove "i" suffix +############################################################################# +## +## splash.gi +## Copyright (C) 2024 Matthew Pancer +## +## Licensing information can be found in the README file of this package. +## +############################################################################# +## -if not IsBound(Splash) then - BindGlobal("VizViewers", - ["xpdf", "xdg-open", "open", "evince", "okular", "gv"]); +# The contents of this file are transplanted from the Digraphs package to here. +# The original function was written by A. Egri-Nagy and Manuel Delgado, with +# some minor modifications by J. Mitchell. - BindGlobal("Splash", - function(arg...) - local str, opt, path, dir, tdir, file, viewer, type, inn, filetype, out, - engine; +BindGlobal("VizViewers", + ["xpdf", "xdg-open", "open", "evince", "okular", "gv"]); - if IsEmpty(arg) then - ErrorNoReturn("the must be at least 1 argument, found none"); - elif not IsString(arg[1]) and not IsGraphvizGraphOrDigraph(arg[1]) then - ErrorFormatted("the 1st argument must be a string or ", - "graphviz graph, found {}", TNAM_OBJ(arg[1])); - elif IsGraphvizGraphOrDigraph(arg[1]) then - arg[1] := String(arg[1]); - fi; - str := arg[1]; +InstallGlobalFunction(Splash, +function(arg...) + local file, str, opt, path, dir, tdir, viewer, type, inn, filetype, out, + engine, i; - opt := rec(); - if IsBound(arg[2]) and IsRecord(arg[2]) then - opt := arg[2]; - elif IsBound(arg[2]) then - ErrorNoReturn("the 2nd argument must be a record,"); - fi; + if IsEmpty(arg) then + ErrorNoReturn("the must be at least 1 argument, found none"); + elif not IsString(arg[1]) and not IsGraphvizGraphOrDigraph(arg[1]) then + ErrorFormatted("the 1st argument must be a string or ", + "graphviz graph, found {}", TNAM_OBJ(arg[1])); + elif IsGraphvizGraphOrDigraph(arg[1]) then + file := GraphvizName(arg[1]); + for i in [1 .. Length(file)] do + if not IsAlphaChar(file[i]) and not IsDigitChar(file[i]) then + file[i] := '_'; + fi; + od; + arg[1] := String(arg[1]); + else + file := "vizpicture"; + fi; + str := arg[1]; - path := UserHomeExpand("~/"); - if IsBound(opt.path) then - path := opt.path; - fi; + opt := rec(); + if IsBound(arg[2]) and IsRecord(arg[2]) then + opt := arg[2]; + elif IsBound(arg[2]) then + ErrorNoReturn("the 2nd argument must be a record,"); + fi; - if IsBound(opt.directory) then - if not opt.directory in DirectoryContents(path) then - Exec(Concatenation("mkdir ", path, opt.directory)); - fi; - dir := Concatenation(path, opt.directory, "/"); - elif IsBound(opt.path) then - if not "tmp.viz" in DirectoryContents(path) then - tdir := Directory(Concatenation(path, "/", "tmp.viz")); - dir := Filename(tdir, ""); - fi; - else - tdir := DirectoryTemporary(); - dir := Filename(tdir, ""); - fi; + path := UserHomeExpand("~/"); + if IsBound(opt.path) then + path := opt.path; + fi; - # TODO use the graphs name - file := "vizpicture"; - if IsBound(opt.filename) then - file := opt.filename; + if IsBound(opt.directory) then + if not opt.directory in DirectoryContents(path) then + Exec(Concatenation("mkdir ", path, opt.directory)); fi; - - if IsBound(opt.viewer) then - viewer := opt.viewer; - if not IsString(viewer) then - ErrorNoReturn("the option `viewer` must be a string, not an ", - TNAM_OBJ(viewer)); - elif Filename(DirectoriesSystemPrograms(), viewer) = fail then - ErrorNoReturn("the viewer \"", viewer, "\" specified in the option ", - "`viewer` is not available"); - fi; - else - viewer := First(VizViewers, x -> - Filename(DirectoriesSystemPrograms(), x) <> fail); - if viewer = fail then - ErrorNoReturn("none of the default viewers ", VizViewers, - " is available, please specify an available viewer", - " in the options record component `viewer`,"); - fi; + dir := Concatenation(path, opt.directory, "/"); + elif IsBound(opt.path) then + if not "tmp.viz" in DirectoryContents(path) then + tdir := Directory(Concatenation(path, "/", "tmp.viz")); + dir := Filename(tdir, ""); fi; + else + tdir := DirectoryTemporary(); + dir := Filename(tdir, ""); + fi; + + if IsBound(opt.filename) then + file := opt.filename; + fi; - 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\","); + if IsBound(opt.viewer) then + viewer := opt.viewer; + if not IsString(viewer) then + ErrorNoReturn("the option `viewer` must be a string, not an ", + TNAM_OBJ(viewer)); + elif Filename(DirectoriesSystemPrograms(), viewer) = fail then + ErrorNoReturn("the viewer \"", viewer, "\" specified in the option ", + "`viewer` is not available"); fi; - if type = "latex" then - inn := Concatenation(dir, file, ".tex"); - else - inn := Concatenation(dir, file, ".dot"); + else + viewer := First(VizViewers, x -> + Filename(DirectoriesSystemPrograms(), x) <> fail); + if viewer = fail then + ErrorNoReturn("none of the default viewers ", VizViewers, + " is available, please specify an available viewer", + " in the options record component `viewer`,"); fi; + fi; - filetype := "pdf"; - if IsBound(opt.filetype) and IsString(opt.filetype) and type <> "latex" then - filetype := opt.filetype; - fi; - out := Concatenation(dir, file, ".", filetype); + 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; - engine := "dot"; - if IsBound(opt.engine) then - engine := opt.engine; - if not engine in ["dot", "neato", "twopi", "circo", - "fdp", "sfdp", "patchwork"] then - ErrorNoReturn("the component \"engine\" of the 2nd argument ", - " must be one of: \"dot\", \"neato\", ", - "\"twopi\", \"circo\", \"fdp\", \"sfdp\", ", - "or \"patchwork\""); - fi; - fi; + filetype := "pdf"; + if IsBound(opt.filetype) and IsString(opt.filetype) and type <> "latex" then + filetype := opt.filetype; + fi; + out := Concatenation(dir, file, ".", filetype); - FileString(inn, str); - 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)); + engine := "dot"; + if IsBound(opt.engine) then + engine := opt.engine; + if not engine in ["dot", "neato", "twopi", "circo", + "fdp", "sfdp", "patchwork"] then + ErrorNoReturn("the component \"engine\" of the 2nd argument ", + " must be one of: \"dot\", \"neato\", ", + "\"twopi\", \"circo\", \"fdp\", \"sfdp\", ", + "or \"patchwork\""); fi; - Exec(Concatenation(viewer, " ", out, " 2>/dev/null 1>/dev/null &")); - end); -fi; + fi; + + FileString(inn, str); + 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); diff --git a/init.g b/init.g index b6ccf00..42a7379 100644 --- a/init.g +++ b/init.g @@ -11,3 +11,4 @@ ReadPackage("graphviz", "gap/error.gd"); ReadPackage("graphviz", "gap/dot.gd"); ReadPackage("graphviz", "gap/gv.gd"); +ReadPackage("graphviz", "gap/splash.gd"); From 2e7c27faa46a4731b602d5a23da4a91084a45ee8 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Tue, 14 May 2024 16:50:50 +0100 Subject: [PATCH 15/38] Add PrintObj method for graphs and digraphs --- gap/dot.gd | 2 -- gap/dot.gi | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index e911100..51fe311 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -200,8 +200,6 @@ DeclareOperation("GraphvizRemoveAttr", [IsGraphvizObject, IsObject]); #! @Returns the dot representation of the graphviz object. # TODO document "String" -# TODO PrintObj - #! @Arguments obj #! @Returns the graphviz representation of the object. #! @Description diff --git a/gap/dot.gi b/gap/dot.gi index 6dda979..42cbc33 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -530,6 +530,12 @@ end); InstallMethod(String, "for a graphviz (di)graph", [IsGraphvizGraphOrDigraph], graph -> GV_StringifyGraph(graph, false)); +InstallMethod(PrintObj, "for a graphviz (di)graph", +[IsGraphvizGraphOrDigraph], +function(gv) + Print(String(gv)); +end); + InstallMethod(GraphvizSetNodeLabels, "for a graphviz (di)graph and list of colors", [IsGraphvizGraphOrDigraph, IsList], From bd99589b1d2f35e408a16d867e47635e315b5ec3 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Tue, 14 May 2024 16:51:09 +0100 Subject: [PATCH 16/38] Add comment about valid identifiers --- gap/dot.gd | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/gap/dot.gd b/gap/dot.gd index 51fe311..087a4b5 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -86,7 +86,14 @@ DeclareOperation("GraphvizAttrs", [IsGraphvizObject]); #! @Arguments graph #! @Returns the nodes of the provided graphviz graph. #! @Description Gets the nodes of the provided graphviz graph. -#! Node names can only be [a-zA-Z0-9_£] TODO check exact docs. +# From https://graphviz.org/doc/info/lang.html +# An ID is one of the following: +# Any string of alphabetic ([a-zA-Z\200-\377]) characters, underscores ('_') or +# digits([0-9]), not beginning with a digit; +# a numeral [-]?(.[0-9]⁺ | [0-9]⁺(.[0-9]*)? ); +# any double-quoted string ("...") possibly containing escaped quotes (\")¹; +# an HTML string (<...>). +# TODO specify DeclareOperation("GraphvizNodes", [IsGraphvizGraphOrDigraph]); #! @Arguments graph From 9bef7d5187355c089bd043234dbc80f858bb46be Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Tue, 14 May 2024 16:57:46 +0100 Subject: [PATCH 17/38] Add comment to GraphvizSetAttr --- gap/dot.gi | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/gap/dot.gi b/gap/dot.gi index 42cbc33..149cc34 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -228,7 +228,10 @@ function(x, attrs) return x; end); -# TODO combine this and the next method +# TODO not sure why these two methods are required? I.e. why is setting +# attributes for graphs and digraphs different? Be good to have a comment +# explaining why. + InstallMethod(GraphvizSetAttr, "for a graphviz object, object, and object", [IsGraphvizObject, IsObject, IsObject], function(x, name, value) @@ -243,17 +246,16 @@ function(x, name, value) return x; end); -InstallMethod(GraphvizSetAttr, "for a graphviz (di)graph, object and object", +InstallMethod(GraphvizSetAttr, "for a graphviz (di)graph, object, and object", [IsGraphvizGraphOrDigraph, IsObject, IsObject], function(x, name, value) - local attrs, string, msg; + local attrs, string; if not name in GV_KNOWN_ATTRS then - msg := Concatenation( - StringFormatted("unknown attribute \"{}\", the", name), - " graphviz object may no longer be valid, it can", - " be removed using GraphvizRemoveAttr"); - Info(InfoWarning, 1, msg); + Info(InfoWarning, 1, + StringFormatted("unknown attribute \"{}\", the", name), + " graphviz object may no longer be valid, it can", + " be removed using GraphvizRemoveAttr"); fi; attrs := GraphvizAttrs(x); From 9ba8bc984634bae071fde6bf82d266f3004e1b54 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Tue, 14 May 2024 17:04:24 +0100 Subject: [PATCH 18/38] IsGraphvizContext does not imply graph or digraph --- gap/dot.gd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/dot.gd b/gap/dot.gd index 087a4b5..1da2945 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -40,7 +40,7 @@ DeclareCategory("IsGraphvizObject", IsObject); DeclareCategory("IsGraphvizGraphOrDigraph", IsGraphvizObject); DeclareCategory("IsGraphvizGraph", IsGraphvizGraphOrDigraph); DeclareCategory("IsGraphvizDigraph", IsGraphvizGraphOrDigraph); -DeclareCategory("IsGraphvizContext", IsGraphvizGraphOrDigraph); +DeclareCategory("IsGraphvizContext", IsGraphvizObject); DeclareCategory("IsGraphvizNode", IsGraphvizObject); DeclareCategory("IsGraphvizEdge", IsGraphvizObject); #! @EndGroup From 6a4c89256be6f23bde29d5486720781680fad185 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Tue, 14 May 2024 17:26:02 +0100 Subject: [PATCH 19/38] Further tweak the categories --- gap/dot.gd | 51 ++++++++++++++++--------------- gap/dot.gi | 83 +++++++++++++++++++++++++-------------------------- gap/gv.gd | 42 +++++++++++++------------- gap/gv.gi | 42 +++++++++++++------------- gap/splash.gi | 4 +-- 5 files changed, 111 insertions(+), 111 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index 1da2945..af234cf 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -37,12 +37,15 @@ #! which is a subcategory of is IsGraphvizGraph. DeclareCategory("IsGraphvizObject", IsObject); -DeclareCategory("IsGraphvizGraphOrDigraph", IsGraphvizObject); -DeclareCategory("IsGraphvizGraph", IsGraphvizGraphOrDigraph); -DeclareCategory("IsGraphvizDigraph", IsGraphvizGraphOrDigraph); -DeclareCategory("IsGraphvizContext", IsGraphvizObject); -DeclareCategory("IsGraphvizNode", IsGraphvizObject); -DeclareCategory("IsGraphvizEdge", IsGraphvizObject); + +DeclareCategory("IsGraphvizObjectWithSubobjects", IsGraphvizObject); +DeclareCategory("IsGraphvizGraph", IsGraphvizObjectWithSubobjects); +DeclareCategory("IsGraphvizDigraph", IsGraphvizObjectWithSubobjects); +DeclareCategory("IsGraphvizContext", IsGraphvizObjectWithSubobjects); + +DeclareCategory("IsGraphvizNodeOrEdge", IsGraphvizObject); +DeclareCategory("IsGraphvizNode", IsGraphvizNodeOrEdge); +DeclareCategory("IsGraphvizEdge", IsGraphvizNodeOrEdge); #! @EndGroup #! @Section Constructors @@ -94,12 +97,12 @@ DeclareOperation("GraphvizAttrs", [IsGraphvizObject]); # any double-quoted string ("...") possibly containing escaped quotes (\")¹; # an HTML string (<...>). # TODO specify -DeclareOperation("GraphvizNodes", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GraphvizNodes", [IsGraphvizObjectWithSubobjects]); #! @Arguments graph #! @Returns the subgraphs of the provided graphviz graph. #! @Description gets the subgraphs of a provided graphviz graph. -DeclareOperation("GraphvizSubgraphs", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GraphvizSubgraphs", [IsGraphvizObjectWithSubobjects]); #! @Arguments graph, name #! @Returns a graph with the provided name. @@ -109,14 +112,14 @@ DeclareOperation("GraphvizSubgraphs", [IsGraphvizGraphOrDigraph]); #! It returns the graph if it exists. #! If no such graph exists then it will return fail. DeclareOperation("GraphvizFindSubgraphRecursive", -[IsGraphvizGraphOrDigraph, IsObject]); +[IsGraphvizObjectWithSubobjects, IsObject]); #! @Arguments graph #! @Returns the edges of the provided graphviz graph. #! @Description Gets the edges of the provided graphviz graph. -DeclareOperation("GraphvizEdges", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GraphvizEdges", [IsGraphvizObjectWithSubobjects]); DeclareOperation("GraphvizEdges", -[IsGraphvizGraphOrDigraph, IsObject, IsObject]); +[IsGraphvizObjectWithSubobjects, IsObject, IsObject]); #! @Subsection For only edges. @@ -138,13 +141,13 @@ DeclareOperation("GraphvizTail", [IsGraphvizEdge]); #! @Arguments graph, name #! @Returns the modified graph. #! @Description Sets the name of a graphviz graph or digraph. -DeclareOperation("GraphvizSetName", [IsGraphvizGraphOrDigraph, IsObject]); +DeclareOperation("GraphvizSetName", [IsGraphvizObjectWithSubobjects, IsObject]); #! @Arguments graph, node #! @Returns the modified graph. #! @Description Adds a node to the graph. #! If a node with the same name is already present the operation fails. -DeclareOperation("GraphvizAddNode", [IsGraphvizGraphOrDigraph, IsObject]); +DeclareOperation("GraphvizAddNode", [IsGraphvizObjectWithSubobjects, IsObject]); #! @Arguments graph, edge #! @Returns the modified graph. @@ -153,36 +156,36 @@ DeclareOperation("GraphvizAddNode", [IsGraphvizGraphOrDigraph, IsObject]); #! added to the graph. If different nodes with the same name are in the graph #! then the operation fails. DeclareOperation("GraphvizAddEdge", -[IsGraphvizGraphOrDigraph, IsObject, IsObject]); +[IsGraphvizObjectWithSubobjects, IsObject, IsObject]); #! @Arguments graph, filter, name #! @Returns the new subgraph. #! @Description Adds a subgraph to a graph. -DeclareOperation("GraphvizAddSubgraph", [IsGraphvizGraphOrDigraph, IsObject]); -DeclareOperation("GraphvizAddSubgraph", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GraphvizAddSubgraph", [IsGraphvizObjectWithSubobjects, IsObject]); +DeclareOperation("GraphvizAddSubgraph", [IsGraphvizObjectWithSubobjects]); #! @Arguments graph, filter, name #! @Returns the new context. #! @Description Adds a context to a graph. -DeclareOperation("GraphvizAddContext", [IsGraphvizGraphOrDigraph, IsObject]); -DeclareOperation("GraphvizAddContext", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GraphvizAddContext", [IsGraphvizObjectWithSubobjects, IsObject]); +DeclareOperation("GraphvizAddContext", [IsGraphvizObjectWithSubobjects]); #! @Arguments graph, node #! @Returns the modified graph. #! @Description Removes the node from the graph. -DeclareOperation("GraphvizRemoveNode", [IsGraphvizGraphOrDigraph, IsObject]); +DeclareOperation("GraphvizRemoveNode", [IsGraphvizObjectWithSubobjects, IsObject]); #! @Arguments graph, predicate #! @Returns the modified graph. #! @Description Filters the graph's edges using the provided predicate. -DeclareOperation("GraphvizFilterEdges", [IsGraphvizGraphOrDigraph, IsFunction]); +DeclareOperation("GraphvizFilterEdges", [IsGraphvizObjectWithSubobjects, IsFunction]); #! @Arguments graph, head_name, tail_name #! @Returns the modified graph. #! @Description Filters the graph's edges, removing edges between nodes with #! the specified names. DeclareOperation("GraphvizRemoveEdges", -[IsGraphvizGraphOrDigraph, IsObject, IsObject]); +[IsGraphvizObjectWithSubobjects, IsObject, IsObject]); #! @Subsection For modifying object attributes. @@ -214,8 +217,8 @@ DeclareOperation("GraphvizRemoveAttr", [IsGraphvizObject, IsObject]); #! Should output the graphviz package representation of the object. DeclareOperation("Graphviz", [IsObject]); -DeclareOperation("GraphvizSetNodeColors", [IsGraphvizGraphOrDigraph, IsList]); -DeclareOperation("GraphvizSetNodeLabels", [IsGraphvizGraphOrDigraph, IsList]); +DeclareOperation("GraphvizSetNodeColors", [IsGraphvizObjectWithSubobjects, IsList]); +DeclareOperation("GraphvizSetNodeLabels", [IsGraphvizObjectWithSubobjects, IsList]); DeclareGlobalFunction("ErrorIfNotValidColor"); @@ -230,4 +233,4 @@ DeclareOperation("\[\]", [IsGraphvizEdge, IsObject]); DeclareOperation("\[\]\:\=", [IsGraphvizEdge, IsObject, IsObject]); # TODO doc -DeclareOperation("\[\]", [IsGraphvizGraphOrDigraph, IsObject]); +DeclareOperation("\[\]", [IsGraphvizObjectWithSubobjects, IsObject]); diff --git a/gap/dot.gi b/gap/dot.gi index 149cc34..b691a59 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -61,7 +61,7 @@ function(e) GraphvizName(tail)); end); -InstallMethod(ViewString, "for a graphviz (di)graph", [IsGraphvizGraphOrDigraph], +InstallMethod(ViewString, "for a graphviz (di)graph", [IsGraphvizObjectWithSubobjects], function(g) local result, edges, nodes, kind; @@ -101,14 +101,14 @@ InstallMethod(GraphvizAttrs, "for a graphviz object", [IsGraphvizObject], x -> x!.Attrs); InstallMethod(GraphvizNodes, "for a graphviz (di)graph", -[IsGraphvizGraphOrDigraph], x -> x!.Nodes); +[IsGraphvizObjectWithSubobjects], x -> x!.Nodes); InstallMethod(GraphvizEdges, "for a graphviz (di)graph", -[IsGraphvizGraphOrDigraph], x -> x!.Edges); +[IsGraphvizObjectWithSubobjects], x -> x!.Edges); InstallMethod(GraphvizEdges, "for a graphviz (di)graph, object, and object", -[IsGraphvizGraphOrDigraph, IsObject, IsObject], +[IsGraphvizObjectWithSubobjects, IsObject, IsObject], function(gv, head, tail) head := GraphvizNodes(gv)[head]; if head = fail then @@ -125,7 +125,7 @@ function(gv, head, tail) end); InstallMethod(GraphvizSubgraphs, "for a graphviz (di)graph", -[IsGraphvizGraphOrDigraph], x -> x!.Subgraphs); +[IsGraphvizObjectWithSubobjects], x -> x!.Subgraphs); InstallMethod(GraphvizTail, "for a graphviz edge", [IsGraphvizEdge], x -> x!.Tail); @@ -182,21 +182,21 @@ end); # Accessor for graphs and digraphs InstallMethod(\[\], "for a graphviz (di)graph and string", -[IsGraphvizGraphOrDigraph, IsString], +[IsGraphvizObjectWithSubobjects, IsString], {graph, node} -> GraphvizNodes(graph)[node]); InstallMethod(\[\], "for a graphviz (di)graph and object", -[IsGraphvizGraphOrDigraph, IsObject], +[IsGraphvizObjectWithSubobjects, IsObject], {g, o} -> g[String(o)]); InstallMethod(GraphvizFindSubgraphRecursive, "for a graphviz (di)graph and a string", -[IsGraphvizGraphOrDigraph, IsString], +[IsGraphvizObjectWithSubobjects, IsString], {g, s} -> GV_GraphTreeSearch(g, v -> GraphvizName(v) = s)); InstallMethod(GraphvizFindSubgraphRecursive, "for a graphviz (di)graph and a string", -[IsGraphvizGraphOrDigraph, IsObject], +[IsGraphvizObjectWithSubobjects, IsObject], {g, o} -> GraphvizFindSubgraphRecursive(g, String(o))); ############################################################################# @@ -204,14 +204,14 @@ InstallMethod(GraphvizFindSubgraphRecursive, ############################################################################# InstallMethod(GraphvizSetName, "for a graphviz (di)graph and string", -[IsGraphvizGraphOrDigraph, IsString], +[IsGraphvizObjectWithSubobjects, IsString], function(x, name) x!.Name := name; return x; end); InstallMethod(GraphvizSetName, "for a graphviz (di)graph and string", -[IsGraphvizGraphOrDigraph, IsObject], +[IsGraphvizObjectWithSubobjects, IsObject], {g, o} -> GraphvizSetName(g, String(o))); ############################################################################# @@ -228,12 +228,8 @@ function(x, attrs) return x; end); -# TODO not sure why these two methods are required? I.e. why is setting -# attributes for graphs and digraphs different? Be good to have a comment -# explaining why. - -InstallMethod(GraphvizSetAttr, "for a graphviz object, object, and object", -[IsGraphvizObject, IsObject, IsObject], +InstallMethod(GraphvizSetAttr, "for a graphviz node or edge, object, and object", +[IsGraphvizNodeOrEdge, IsObject, IsObject], function(x, name, value) if not name in GV_KNOWN_ATTRS then @@ -246,8 +242,9 @@ function(x, name, value) return x; end); -InstallMethod(GraphvizSetAttr, "for a graphviz (di)graph, object, and object", -[IsGraphvizGraphOrDigraph, IsObject, IsObject], +InstallMethod(GraphvizSetAttr, +"for a graphviz object with subobjects, object, and object", +[IsGraphvizObjectWithSubobjects, IsObject, IsObject], function(x, name, value) local attrs, string; @@ -272,7 +269,7 @@ function(x, name, value) end); InstallMethod(GraphvizSetAttr, "for a graphviz (di)graph and object", -[IsGraphvizGraphOrDigraph, IsObject], +[IsGraphvizObjectWithSubobjects, IsObject], function(x, value) local attrs; attrs := GraphvizAttrs(x); @@ -286,7 +283,7 @@ end); ############################################################################# InstallMethod(GraphvizAddNode, "for a graphviz (di)graph and string", -[IsGraphvizGraphOrDigraph, IsString], +[IsGraphvizObjectWithSubobjects, IsString], function(x, name) local node; node := GV_Node(x, name); @@ -295,7 +292,7 @@ function(x, name) end); InstallMethod(GraphvizAddNode, "for a graphviz (di)graph and string", -[IsGraphvizGraphOrDigraph, IsGraphvizNode], +[IsGraphvizObjectWithSubobjects, IsGraphvizNode], function(gv, name) # gaplint: disable=analyse-lvars ErrorNoReturn("it is not currently possible to add Graphviz node ", "objects directly to Graphviz graphs or digraphs, use ", @@ -304,7 +301,7 @@ end); InstallMethod(GraphvizAddNode, "for a graphviz (di)graph and string", -[IsGraphvizGraphOrDigraph, IsObject], +[IsGraphvizObjectWithSubobjects, IsObject], {x, name} -> GraphvizAddNode(x, String(name))); ############################################################################# @@ -313,7 +310,7 @@ InstallMethod(GraphvizAddNode, InstallMethod(GraphvizAddEdge, "for a graphviz (di)graph and two graphviz nodes", -[IsGraphvizGraphOrDigraph, IsGraphvizNode, IsGraphvizNode], +[IsGraphvizObjectWithSubobjects, IsGraphvizNode, IsGraphvizNode], function(x, head, tail) local edge, head_name, tail_name; @@ -335,7 +332,7 @@ end); InstallMethod(GraphvizAddEdge, "for a graphviz (di)graph and two strings", -[IsGraphvizGraphOrDigraph, IsString, IsString], +[IsGraphvizObjectWithSubobjects, IsString, IsString], function(x, head, tail) local head_node, tail_node; @@ -354,7 +351,7 @@ end); InstallMethod(GraphvizAddEdge, "for a graphviz (di)graph and two objects", -[IsGraphvizGraphOrDigraph, IsObject, IsObject], +[IsGraphvizObjectWithSubobjects, IsObject, IsObject], {gv, o1, o2} -> GraphvizAddEdge(gv, String(o1), String(o2))); ############################################################################# @@ -362,7 +359,7 @@ InstallMethod(GraphvizAddEdge, ############################################################################# InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph and string", -[IsGraphvizGraphOrDigraph, IsString], +[IsGraphvizObjectWithSubobjects, IsString], function(gv, name) local subgraphs, subgraph; @@ -391,18 +388,18 @@ function(gv, name) end); InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph and an object", -[IsGraphvizGraphOrDigraph, IsObject], +[IsGraphvizObjectWithSubobjects, IsObject], {g, o} -> GraphvizAddSubgraph(g, String(o))); InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph", -[IsGraphvizGraphOrDigraph], +[IsGraphvizObjectWithSubobjects], graph -> GraphvizAddSubgraph(graph, StringFormatted("no_name_{}", GV_GetCounter(graph)))); InstallMethod(GraphvizAddContext, "for a graphviz (di)graph and a string", -[IsGraphvizGraphOrDigraph, IsString], +[IsGraphvizObjectWithSubobjects, IsString], function(graph, name) local subgraphs, ctx; @@ -423,20 +420,20 @@ end); InstallMethod(GraphvizAddContext, "for a graphviz (di)graph", -[IsGraphvizGraphOrDigraph], +[IsGraphvizObjectWithSubobjects], g -> GraphvizAddContext(g, StringFormatted("no_name_{}", GV_GetCounter(g)))); InstallMethod(GraphvizAddContext, "for a graphviz (di)graph and an object", -[IsGraphvizGraphOrDigraph, IsObject], +[IsGraphvizObjectWithSubobjects, IsObject], {g, o} -> GraphvizAddContext(g, String(o))); InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph and node", -[IsGraphvizGraphOrDigraph, IsGraphvizNode], +[IsGraphvizObjectWithSubobjects, IsGraphvizNode], {g, node} -> GraphvizRemoveNode(g, GraphvizName(node))); InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph and a string", -[IsGraphvizGraphOrDigraph, IsString], +[IsGraphvizObjectWithSubobjects, IsString], function(g, name) local nodes; nodes := GraphvizNodes(g); @@ -462,11 +459,11 @@ function(g, name) end); InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph and a string", -[IsGraphvizGraphOrDigraph, IsObject], +[IsGraphvizObjectWithSubobjects, IsObject], {g, o} -> GraphvizRemoveNode(g, String(o))); InstallMethod(GraphvizFilterEdges, "for a graphviz (di)graph and edge filter", -[IsGraphvizGraphOrDigraph, IsFunction], +[IsGraphvizObjectWithSubobjects, IsFunction], function(g, filter) local edge, idx, edges; @@ -484,7 +481,7 @@ function(g, filter) end); InstallMethod(GraphvizRemoveEdges, "for a graphviz (di)graph and two strings", -[IsGraphvizGraphOrDigraph, IsString, IsString], +[IsGraphvizObjectWithSubobjects, IsString, IsString], function(g, hn, tn) GraphvizFilterEdges(g, function(e) @@ -503,7 +500,7 @@ function(g, hn, tn) end); InstallMethod(GraphvizRemoveEdges, "for a graphviz (di)graph and two objects", -[IsGraphvizGraphOrDigraph, IsObject, IsObject], +[IsGraphvizObjectWithSubobjects, IsObject, IsObject], {gv, o1, o2} -> GraphvizRemoveEdges(gv, String(o1), String(o2))); InstallMethod(GraphvizRemoveAttr, "for a graphviz object and an object", @@ -517,7 +514,7 @@ function(obj, attr) end); InstallMethod(GraphvizRemoveAttr, "for a graphviz (di)graph and an object", -[IsGraphvizGraphOrDigraph, IsObject], +[IsGraphvizObjectWithSubobjects, IsObject], function(obj, attr) local attrs; attrs := GraphvizAttrs(obj); @@ -530,17 +527,17 @@ end); ############################################################################# InstallMethod(String, "for a graphviz (di)graph", -[IsGraphvizGraphOrDigraph], graph -> GV_StringifyGraph(graph, false)); +[IsGraphvizObjectWithSubobjects], graph -> GV_StringifyGraph(graph, false)); InstallMethod(PrintObj, "for a graphviz (di)graph", -[IsGraphvizGraphOrDigraph], +[IsGraphvizObjectWithSubobjects], function(gv) Print(String(gv)); end); InstallMethod(GraphvizSetNodeLabels, "for a graphviz (di)graph and list of colors", -[IsGraphvizGraphOrDigraph, IsList], +[IsGraphvizObjectWithSubobjects, IsList], function(gv, labels) local nodes, i; if Size(GraphvizNodes(gv)) <> Size(labels) then @@ -558,7 +555,7 @@ end); InstallMethod(GraphvizSetNodeColors, "for a graphviz (di)graph and list of colors", -[IsGraphvizGraphOrDigraph, IsList], +[IsGraphvizObjectWithSubobjects, IsList], function(gv, colors) local nodes, i; diff --git a/gap/gv.gd b/gap/gv.gd index 2e68cb7..c98f38b 100644 --- a/gap/gv.gd +++ b/gap/gv.gd @@ -11,46 +11,46 @@ ## This file contains declarations of the internal/private functions for the ## graphviz package. -DeclareOperation("GV_GetCounter", [IsGraphvizGraphOrDigraph]); -DeclareOperation("GV_IncCounter", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GV_GetCounter", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GV_IncCounter", [IsGraphvizObjectWithSubobjects]); DeclareCategory("GV_IsMap", IsObject); DeclareAttribute("Size", GV_IsMap); -DeclareOperation("GV_StringifyGraphHead", [IsGraphvizGraphOrDigraph]); -DeclareOperation("GV_StringifyDigraphHead", [IsGraphvizGraphOrDigraph]); -DeclareOperation("GV_StringifySubgraphHead", [IsGraphvizGraphOrDigraph]); -DeclareOperation("GV_StringifyContextHead", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GV_StringifyGraphHead", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GV_StringifyDigraphHead", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GV_StringifySubgraphHead", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GV_StringifyContextHead", [IsGraphvizObjectWithSubobjects]); DeclareOperation("GV_StringifyNode", [IsGraphvizNode]); -DeclareOperation("GV_StringifyGraphAttrs", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GV_StringifyGraphAttrs", [IsGraphvizObjectWithSubobjects]); DeclareOperation("GV_StringifyNodeEdgeAttrs", [GV_IsMap]); -DeclareOperation("GV_StringifyGraph", [IsGraphvizGraphOrDigraph, IsBool]); +DeclareOperation("GV_StringifyGraph", [IsGraphvizObjectWithSubobjects, IsBool]); -DeclareOperation("GV_FindNode", [IsGraphvizGraphOrDigraph, IsObject]); +DeclareOperation("GV_FindNode", [IsGraphvizObjectWithSubobjects, IsObject]); DeclareOperation("GV_Pluralize", [IsInt, IsString]); -DeclareOperation("GV_Node", [IsGraphvizGraphOrDigraph, IsString]); +DeclareOperation("GV_Node", [IsGraphvizObjectWithSubobjects, IsString]); DeclareOperation("GV_Edge", -[IsGraphvizGraphOrDigraph, IsGraphvizNode, IsGraphvizNode]); -DeclareOperation("GV_Graph", [IsGraphvizGraphOrDigraph, IsString]); +[IsGraphvizObjectWithSubobjects, IsGraphvizNode, IsGraphvizNode]); +DeclareOperation("GV_Graph", [IsGraphvizObjectWithSubobjects, IsString]); DeclareOperation("GV_Digraph", [IsGraphvizDigraph, IsString]); -DeclareOperation("GV_Context", [IsGraphvizGraphOrDigraph, IsString]); +DeclareOperation("GV_Context", [IsGraphvizObjectWithSubobjects, IsString]); DeclareOperation("GV_Map", []); DeclareOperation("GV_MapNames", [GV_IsMap]); # TODO required? Replace with String or just String? DeclareOperation("GV_EnsureString", [IsObject]); -DeclareOperation("GV_HasNode", [IsGraphvizGraphOrDigraph, IsObject]); +DeclareOperation("GV_HasNode", [IsGraphvizObjectWithSubobjects, IsObject]); -DeclareOperation("GV_GetParent", [IsGraphvizGraphOrDigraph]); -DeclareOperation("GV_GraphTreeSearch", [IsGraphvizGraphOrDigraph, IsFunction]); -DeclareOperation("GV_FindGraphWithNode", [IsGraphvizGraphOrDigraph, IsString]); -DeclareOperation("GV_GetRoot", [IsGraphvizGraphOrDigraph]); -DeclareOperation("GV_AddNode", [IsGraphvizGraphOrDigraph, IsGraphvizNode]); -DeclareOperation("GV_AddEdge", [IsGraphvizGraphOrDigraph, IsGraphvizEdge]); +DeclareOperation("GV_GetParent", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GV_GraphTreeSearch", [IsGraphvizObjectWithSubobjects, IsFunction]); +DeclareOperation("GV_FindGraphWithNode", [IsGraphvizObjectWithSubobjects, IsString]); +DeclareOperation("GV_GetRoot", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GV_AddNode", [IsGraphvizObjectWithSubobjects, IsGraphvizNode]); +DeclareOperation("GV_AddEdge", [IsGraphvizObjectWithSubobjects, IsGraphvizEdge]); DeclareOperation("GV_GetIdx", [IsGraphvizObject]); -DeclareOperation("GV_ConstructHistory", [IsGraphvizGraphOrDigraph]); +DeclareOperation("GV_ConstructHistory", [IsGraphvizObjectWithSubobjects]); DeclareGlobalFunction("GV_IsValidColor"); DeclareGlobalFunction("GV_ErrorIfNotNodeColoring"); diff --git a/gap/gv.gi b/gap/gv.gi index d06a488..c2056aa 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -125,7 +125,7 @@ InstallMethod(GV_Map, "for no args", [], {} -> Objectify(GV_MapType, rec(Data := rec()))); InstallMethod(GV_Node, "for a string", -[IsGraphvizGraphOrDigraph, IsString], +[IsGraphvizObjectWithSubobjects, IsString], function(graph, name) local out; if Length(name) = 0 then @@ -141,7 +141,7 @@ function(graph, name) end); InstallMethod(GV_Edge, "for two graphviz nodes", -[IsGraphvizGraphOrDigraph, IsGraphvizNode, IsGraphvizNode], +[IsGraphvizObjectWithSubobjects, IsGraphvizNode, IsGraphvizNode], function(graph, head, tail) local out; out := Objectify(GV_EdgeType, @@ -173,7 +173,7 @@ end); InstallMethod(GV_Graph, "for a graphviz graph and a string", -[IsGraphvizGraphOrDigraph, IsString], +[IsGraphvizObjectWithSubobjects, IsString], function(parent, name) local out; @@ -187,7 +187,7 @@ end); InstallMethod(GV_Context, "for a string and a positive integer", -[IsGraphvizGraphOrDigraph, IsString], +[IsGraphvizObjectWithSubobjects, IsString], function(parent, name) local out; @@ -257,12 +257,12 @@ InstallMethod(Size, "for a graphviz map", InstallMethod(GV_IncCounter, "for a graphviz graph", -[IsGraphvizGraphOrDigraph], +[IsGraphvizObjectWithSubobjects], function(x) x!.Counter := x!.Counter + 1; end); -InstallMethod(GV_GetCounter, "for a graphviz graph", [IsGraphvizGraphOrDigraph], +InstallMethod(GV_GetCounter, "for a graphviz graph", [IsGraphvizObjectWithSubobjects], x -> x!.Counter); # Converting strings @@ -275,16 +275,16 @@ InstallMethod(GV_EnsureString, "for a string", [IsString], IdFunc); InstallMethod(GV_HasNode, "for a graphviz graph", -[IsGraphvizGraphOrDigraph, IsString], +[IsGraphvizObjectWithSubobjects, IsString], {g, name} -> name in GV_MapNames(GraphvizNodes(g))); InstallMethod(GV_GetParent, "for a graphviz graph", -[IsGraphvizGraphOrDigraph], graph -> graph!.Parent); +[IsGraphvizObjectWithSubobjects], graph -> graph!.Parent); InstallMethod(GV_GraphTreeSearch, "for a graphviz graph and a predicate", -[IsGraphvizGraphOrDigraph, IsFunction], +[IsGraphvizObjectWithSubobjects, IsFunction], function(graph, pred) local seen, to_visit, g, key, subgraph, parent; seen := [graph]; @@ -309,7 +309,7 @@ function(graph, pred) # add parent if not visited parent := GV_GetParent(g); - if not IsGraphvizGraphOrDigraph(parent) then + if not IsGraphvizObjectWithSubobjects(parent) then continue; fi; if not ForAny(seen, s -> IsIdenticalObj(s, parent)) then @@ -323,12 +323,12 @@ end); InstallMethod(GV_FindGraphWithNode, "for a graphviz graph and a node", -[IsGraphvizGraphOrDigraph, IsString], +[IsGraphvizObjectWithSubobjects, IsString], {g, n} -> GV_GraphTreeSearch(g, v -> v[n] <> fail)); InstallMethod(GV_GetRoot, "for a graphviz graph", -[IsGraphvizGraphOrDigraph], +[IsGraphvizObjectWithSubobjects], function(graph) while GV_GetParent(graph) <> fail do graph := GV_GetParent(graph); @@ -338,7 +338,7 @@ end); InstallMethod(GV_FindNode, "for a graphviz graph and a string", -[IsGraphvizGraphOrDigraph, IsString], +[IsGraphvizObjectWithSubobjects, IsString], function(g, n) local graph; graph := GV_FindGraphWithNode(g, n); @@ -350,7 +350,7 @@ end); InstallMethod(GV_AddNode, "for a graphviz graph and node", -[IsGraphvizGraphOrDigraph, IsGraphvizNode], +[IsGraphvizObjectWithSubobjects, IsGraphvizNode], function(x, node) local found, error, name, nodes; name := GraphvizName(node); @@ -369,7 +369,7 @@ end); InstallMethod(GV_AddEdge, "for a graphviz graph and edge", -[IsGraphvizGraphOrDigraph, IsGraphvizEdge], +[IsGraphvizObjectWithSubobjects, IsGraphvizEdge], function(x, edge) local head, head_name, tail_name, tail, hg, error, tg; @@ -412,7 +412,7 @@ end); ############################################################################### # @ Return DOT graph head line. -InstallMethod(GV_StringifyGraphHead, "for a string", [IsGraphvizGraphOrDigraph], +InstallMethod(GV_StringifyGraphHead, "for a string", [IsGraphvizObjectWithSubobjects], graph -> StringFormatted("graph {} {{\n", GraphvizName(graph))); # @ Return DOT digraph head line. @@ -421,7 +421,7 @@ graph -> StringFormatted("digraph {} {{\n", GraphvizName(graph))); # @ Return DOT subgraph head line. InstallMethod(GV_StringifySubgraphHead, "for a string", -[IsGraphvizGraphOrDigraph], +[IsGraphvizObjectWithSubobjects], graph -> StringFormatted("subgraph {} {{\n", GraphvizName(graph))); # @ Return DOT subgraph head line. @@ -480,7 +480,7 @@ end); InstallMethod(GV_StringifyGraphAttrs, "for a graphviz graph", -[IsGraphvizGraphOrDigraph], +[IsGraphvizObjectWithSubobjects], function(graph) local result, attrs, kv; attrs := GraphvizAttrs(graph); @@ -565,7 +565,7 @@ x -> x!.Idx); InstallMethod(GV_ConstructHistory, "for a graphviz graph", -[IsGraphvizGraphOrDigraph], +[IsGraphvizObjectWithSubobjects], function(graph) local nodes, edges, subs, node_hist, edge_hist, subs_hist, hist; @@ -586,7 +586,7 @@ end); InstallMethod(GV_StringifyGraph, "for a graphviz graph and a string", -[IsGraphvizGraphOrDigraph, IsBool], +[IsGraphvizObjectWithSubobjects, IsBool], function(graph, is_subgraph) local result, obj; result := ""; @@ -617,7 +617,7 @@ function(graph, is_subgraph) # Add child graphviz objects for obj in GV_ConstructHistory(graph) do - if IsGraphvizGraphOrDigraph(obj) then + if IsGraphvizObjectWithSubobjects(obj) then Append(result, GV_StringifyGraph(obj, true)); elif IsGraphvizNode(obj) then Append(result, GV_StringifyNode(obj)); diff --git a/gap/splash.gi b/gap/splash.gi index e61e9ba..57bbf19 100644 --- a/gap/splash.gi +++ b/gap/splash.gi @@ -22,10 +22,10 @@ function(arg...) if IsEmpty(arg) then ErrorNoReturn("the must be at least 1 argument, found none"); - elif not IsString(arg[1]) and not IsGraphvizGraphOrDigraph(arg[1]) then + elif not IsString(arg[1]) and not IsGraphvizObjectWithSubobjects(arg[1]) then ErrorFormatted("the 1st argument must be a string or ", "graphviz graph, found {}", TNAM_OBJ(arg[1])); - elif IsGraphvizGraphOrDigraph(arg[1]) then + elif IsGraphvizObjectWithSubobjects(arg[1]) then file := GraphvizName(arg[1]); for i in [1 .. Length(file)] do if not IsAlphaChar(file[i]) and not IsDigitChar(file[i]) then From 03f5e1e70839aec548be3efeac8abe998526fbba Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Tue, 14 May 2024 17:32:27 +0100 Subject: [PATCH 20/38] Fix GraphvizAddSubgraph --- gap/dot.gi | 24 +++++++++++------------- gap/gv.gd | 1 + gap/gv.gi | 12 ++++++++++++ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/gap/dot.gi b/gap/dot.gi index b691a59..5c4e674 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -361,7 +361,7 @@ InstallMethod(GraphvizAddEdge, InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph and string", [IsGraphvizObjectWithSubobjects, IsString], function(gv, name) - local subgraphs, subgraph; + local subgraphs, root, subgraph; subgraphs := GraphvizSubgraphs(gv); if IsBound(subgraphs[name]) then @@ -369,18 +369,16 @@ function(gv, name) " a subgraph with name \"{}\"", name); fi; - # TODO why are the graph and context cases conflated here? - # Shouldn't this be something like - # if IsGraphvizContext(gv) then - # root := GraphvizRoot(gv); - # else - # root := gv; - # fi; - # Then use root instead of gv below? - if IsGraphvizDigraph(gv) then - subgraph := GV_Digraph(gv, name); - elif IsGraphvizGraph(gv) or IsGraphvizContext(gv) then - subgraph := GV_Graph(gv, name); + if IsGraphvizContext(gv) then + root := GV_EnclosingNonContext(gv); + else + root := gv; + fi; + + if IsGraphvizDigraph(root) then + subgraph := GV_Digraph(root, name); + elif IsGraphvizGraph(root) then + subgraph := GV_Graph(root, name); fi; subgraphs[name] := subgraph; diff --git a/gap/gv.gd b/gap/gv.gd index c98f38b..3d88335 100644 --- a/gap/gv.gd +++ b/gap/gv.gd @@ -47,6 +47,7 @@ DeclareOperation("GV_GetParent", [IsGraphvizObjectWithSubobjects]); DeclareOperation("GV_GraphTreeSearch", [IsGraphvizObjectWithSubobjects, IsFunction]); DeclareOperation("GV_FindGraphWithNode", [IsGraphvizObjectWithSubobjects, IsString]); DeclareOperation("GV_GetRoot", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GV_EnclosingNonContext", [IsGraphvizObjectWithSubobjects]); DeclareOperation("GV_AddNode", [IsGraphvizObjectWithSubobjects, IsGraphvizNode]); DeclareOperation("GV_AddEdge", [IsGraphvizObjectWithSubobjects, IsGraphvizEdge]); DeclareOperation("GV_GetIdx", [IsGraphvizObject]); diff --git a/gap/gv.gi b/gap/gv.gi index c2056aa..e203428 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -336,6 +336,18 @@ function(graph) return graph; end); +InstallMethod(GV_EnclosingNonContext, +"for a graphviz object with subobjects", +[IsGraphvizContext], +function(graph) + local parent; + + repeat + parent := GV_GetParent(graph); + until parent = fail or not IsGraphvizContext(parent); + return parent; +end); + InstallMethod(GV_FindNode, "for a graphviz graph and a string", [IsGraphvizObjectWithSubobjects, IsString], From 20abb1645511d7fdc9db403ba62eb46df016ec0d Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Tue, 14 May 2024 17:44:45 +0100 Subject: [PATCH 21/38] Fix tests --- gap/dot.gi | 34 ++++++++++++++++++---------------- gap/gv.gi | 6 ++++-- tst/graph.tst | 18 +++++++++--------- tst/subgraph.tst | 11 ++++++----- 4 files changed, 37 insertions(+), 32 deletions(-) diff --git a/gap/dot.gi b/gap/dot.gi index 5c4e674..b56d4ca 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -48,10 +48,10 @@ InstallMethod(GraphvizDigraph, "for no args", [], {} -> GraphvizDigraph("")); # ViewString ############################################################################# -InstallMethod(ViewString, "for a graphviz node", [IsGraphvizNode], +InstallMethod(PrintString, "for a graphviz node", [IsGraphvizNode], n -> StringFormatted("", GraphvizName(n))); -InstallMethod(ViewString, "for a graphviz edge", [IsGraphvizEdge], +InstallMethod(PrintString, "for a graphviz edge", [IsGraphvizEdge], function(e) local head, tail; head := GraphvizHead(e); @@ -61,7 +61,8 @@ function(e) GraphvizName(tail)); end); -InstallMethod(ViewString, "for a graphviz (di)graph", [IsGraphvizObjectWithSubobjects], +InstallMethod(PrintString, "for a graphviz object with subobjects", +[IsGraphvizObjectWithSubobjects], function(g) local result, edges, nodes, kind; @@ -406,9 +407,8 @@ function(graph, name) # contexts and subgraphs, rather than just subgraphs as the name suggests # See https://github.com/digraphs/graphviz/issues/19 if IsBound(subgraphs[name]) then - # TODO why are we talking about subgraphs in the error? ErrorFormatted("the 1st argument (a graphviz (di)graph) already has ", - " a subgraph with name \"{}\"", name); + " a context or subgraph with name \"{}\"", name); fi; ctx := GV_Context(graph, name); @@ -527,11 +527,14 @@ end); InstallMethod(String, "for a graphviz (di)graph", [IsGraphvizObjectWithSubobjects], graph -> GV_StringifyGraph(graph, false)); -InstallMethod(PrintObj, "for a graphviz (di)graph", -[IsGraphvizObjectWithSubobjects], -function(gv) - Print(String(gv)); -end); +# Can't do the following because it conflicts with the PrintString above, we +# leave this here as a reminder. + +# InstallMethod(PrintObj, "for a graphviz object with subobjects", +# [IsGraphvizObjectWithSubobjects], +# function(gv) +# Print(String(gv)); +# end); InstallMethod(GraphvizSetNodeLabels, "for a graphviz (di)graph and list of colors", @@ -574,11 +577,10 @@ function(c) 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)); + 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); diff --git a/gap/gv.gi b/gap/gv.gi index e203428..f9b2a64 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -247,8 +247,10 @@ InstallOtherMethod(IsBound\[\], InstallMethod(GV_MapNames, "for a graphviz map", [GV_IsMap], m -> RecNames(m!.Data)); -InstallMethod(ViewString, "for a graphviz map", [GV_IsMap], -m -> String(m!.Data)); +InstallMethod(ViewObj, "for a graphviz map", [GV_IsMap], +function(m) + ViewObj(m!.Data); +end); InstallMethod(Size, "for a graphviz map", [GV_IsMap], m -> Length(GV_MapNames(m))); diff --git a/tst/graph.tst b/tst/graph.tst index d485ee1..f0a9124 100644 --- a/tst/graph.tst +++ b/tst/graph.tst @@ -33,24 +33,24 @@ gap> n := GraphvizAddNode(g, "n"); gap> g; gap> GraphvizNodes(g); -rec( n := ) +rec( n := ) gap> GraphvizAddNode(g, "x"); gap> g; gap> GraphvizNodes(g); -rec( n := , x := ) +rec( n := , x := ) # Test add node (name) gap> g := GraphvizGraph();; gap> GraphvizAddNode(g, "n"); gap> GraphvizNodes(g); -rec( n := ) +rec( n := ) gap> GraphvizAddNode(g, "x"); gap> GraphvizNodes(g); -rec( n := , x := ) +rec( n := , x := ) # Test has nodes gap> g := GraphvizGraph();; @@ -99,7 +99,7 @@ gap> GraphvizAddEdge(g, "a", "b");; gap> GraphvizAddEdge(g, "a", "c"); gap> GraphvizNodes(g); -rec( a := , b := , c := ) +rec( a := , b := , c := ) gap> GraphvizAddEdge(g, "c", "a"); gap> GraphvizAddEdge(g, "b", "d"); @@ -126,13 +126,13 @@ gap> GraphvizAddEdge(g, c, d);; gap> GraphvizRemoveNode(g, a); gap> GraphvizNodes(g); -rec( b := , c := , d := ) +rec( b := , c := , d := ) gap> GraphvizEdges(g); [ ] gap> GraphvizRemoveNode(g, b); gap> GraphvizNodes(g); -rec( c := , d := ) +rec( c := , d := ) # Test removing node gap> g := GraphvizGraph();; @@ -141,13 +141,13 @@ gap> GraphvizAddEdge(g, "c", "d");; gap> GraphvizRemoveNode(g, "a"); gap> GraphvizNodes(g); -rec( b := , c := , d := ) +rec( b := , c := , d := ) gap> GraphvizEdges(g); [ ] gap> GraphvizRemoveNode(g, "b"); gap> GraphvizNodes(g); -rec( c := , d := ) +rec( c := , d := ) # Test renaming graph gap> g := GraphvizGraph();; diff --git a/tst/subgraph.tst b/tst/subgraph.tst index 162ba6f..fb1c907 100644 --- a/tst/subgraph.tst +++ b/tst/subgraph.tst @@ -60,7 +60,8 @@ gap> g := GraphvizGraph();; gap> GraphvizAddSubgraph(g, "a");; gap> GraphvizAddContext(g, "b");; gap> GraphvizSubgraphs(g); -rec( a := , b := ) +rec( a := , + b := ) # Test adding a node to a subgraph (does or does not add to parent???) # TODO need to nail down expected behaviour! @@ -70,7 +71,7 @@ gap> GraphvizAddNode(s, "n");; gap> GraphvizNodes(g); rec( ) gap> GraphvizNodes(s); -rec( n := ) +rec( n := ) # Test adding a node to a subgraph which is already in parent fails (by name) gap> g := GraphvizGraph("r");; @@ -229,11 +230,11 @@ gap> GraphvizRemoveNode(g, "d");; gap> GraphvizNodes(g); rec( ) gap> GraphvizNodes(parent); -rec( a := ) +rec( a := ) gap> GraphvizNodes(sibling); -rec( b := ) +rec( b := ) gap> GraphvizNodes(child); -rec( c := ) +rec( c := ) # Test context attribute resetting gap> g := GraphvizDigraph();; From 0edd2e6b95fbae4df2e854f9f813c585938b7c3c Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Tue, 14 May 2024 19:21:13 +0100 Subject: [PATCH 22/38] Fix lint + codespell --- .codespellrc | 2 +- gap/dot.gd | 20 +++++++++++++------- gap/gv.gd | 6 ++++-- gap/gv.gi | 6 ++++-- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/.codespellrc b/.codespellrc index 92e8c49..fdb0e06 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,3 +1,3 @@ [codespell] skip = ./.git,./doc/*.log,./doc/*.html,./doc/*.txt,./doc/*.six,./doc/*.js,./doc/*.bbl,./doc/*.tex,./doc/*.bib,./doc/_* -ignore-words-list=fille +ignore-words-list=fille,manuel diff --git a/gap/dot.gd b/gap/dot.gd index af234cf..7e0f67b 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -96,7 +96,7 @@ DeclareOperation("GraphvizAttrs", [IsGraphvizObject]); # a numeral [-]?(.[0-9]⁺ | [0-9]⁺(.[0-9]*)? ); # any double-quoted string ("...") possibly containing escaped quotes (\")¹; # an HTML string (<...>). -# TODO specify +# TODO specify DeclareOperation("GraphvizNodes", [IsGraphvizObjectWithSubobjects]); #! @Arguments graph @@ -161,24 +161,28 @@ DeclareOperation("GraphvizAddEdge", #! @Arguments graph, filter, name #! @Returns the new subgraph. #! @Description Adds a subgraph to a graph. -DeclareOperation("GraphvizAddSubgraph", [IsGraphvizObjectWithSubobjects, IsObject]); +DeclareOperation("GraphvizAddSubgraph", +[IsGraphvizObjectWithSubobjects, IsObject]); DeclareOperation("GraphvizAddSubgraph", [IsGraphvizObjectWithSubobjects]); #! @Arguments graph, filter, name #! @Returns the new context. #! @Description Adds a context to a graph. -DeclareOperation("GraphvizAddContext", [IsGraphvizObjectWithSubobjects, IsObject]); +DeclareOperation("GraphvizAddContext", +[IsGraphvizObjectWithSubobjects, IsObject]); DeclareOperation("GraphvizAddContext", [IsGraphvizObjectWithSubobjects]); #! @Arguments graph, node #! @Returns the modified graph. #! @Description Removes the node from the graph. -DeclareOperation("GraphvizRemoveNode", [IsGraphvizObjectWithSubobjects, IsObject]); +DeclareOperation("GraphvizRemoveNode", +[IsGraphvizObjectWithSubobjects, IsObject]); #! @Arguments graph, predicate #! @Returns the modified graph. #! @Description Filters the graph's edges using the provided predicate. -DeclareOperation("GraphvizFilterEdges", [IsGraphvizObjectWithSubobjects, IsFunction]); +DeclareOperation("GraphvizFilterEdges", +[IsGraphvizObjectWithSubobjects, IsFunction]); #! @Arguments graph, head_name, tail_name #! @Returns the modified graph. @@ -217,8 +221,10 @@ DeclareOperation("GraphvizRemoveAttr", [IsGraphvizObject, IsObject]); #! Should output the graphviz package representation of the object. DeclareOperation("Graphviz", [IsObject]); -DeclareOperation("GraphvizSetNodeColors", [IsGraphvizObjectWithSubobjects, IsList]); -DeclareOperation("GraphvizSetNodeLabels", [IsGraphvizObjectWithSubobjects, IsList]); +DeclareOperation("GraphvizSetNodeColors", +[IsGraphvizObjectWithSubobjects, IsList]); +DeclareOperation("GraphvizSetNodeLabels", +[IsGraphvizObjectWithSubobjects, IsList]); DeclareGlobalFunction("ErrorIfNotValidColor"); diff --git a/gap/gv.gd b/gap/gv.gd index 3d88335..d75118f 100644 --- a/gap/gv.gd +++ b/gap/gv.gd @@ -44,8 +44,10 @@ DeclareOperation("GV_EnsureString", [IsObject]); DeclareOperation("GV_HasNode", [IsGraphvizObjectWithSubobjects, IsObject]); DeclareOperation("GV_GetParent", [IsGraphvizObjectWithSubobjects]); -DeclareOperation("GV_GraphTreeSearch", [IsGraphvizObjectWithSubobjects, IsFunction]); -DeclareOperation("GV_FindGraphWithNode", [IsGraphvizObjectWithSubobjects, IsString]); +DeclareOperation("GV_GraphTreeSearch", +[IsGraphvizObjectWithSubobjects, IsFunction]); +DeclareOperation("GV_FindGraphWithNode", +[IsGraphvizObjectWithSubobjects, IsString]); DeclareOperation("GV_GetRoot", [IsGraphvizObjectWithSubobjects]); DeclareOperation("GV_EnclosingNonContext", [IsGraphvizObjectWithSubobjects]); DeclareOperation("GV_AddNode", [IsGraphvizObjectWithSubobjects, IsGraphvizNode]); diff --git a/gap/gv.gi b/gap/gv.gi index f9b2a64..9f38e5a 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -264,7 +264,8 @@ function(x) x!.Counter := x!.Counter + 1; end); -InstallMethod(GV_GetCounter, "for a graphviz graph", [IsGraphvizObjectWithSubobjects], +InstallMethod(GV_GetCounter, "for a graphviz graph", +[IsGraphvizObjectWithSubobjects], x -> x!.Counter); # Converting strings @@ -426,7 +427,8 @@ end); ############################################################################### # @ Return DOT graph head line. -InstallMethod(GV_StringifyGraphHead, "for a string", [IsGraphvizObjectWithSubobjects], +InstallMethod(GV_StringifyGraphHead, "for a string", +[IsGraphvizObjectWithSubobjects], graph -> StringFormatted("graph {} {{\n", GraphvizName(graph))); # @ Return DOT digraph head line. From f25ff249a095ba61b326024e9350f34c245a9252 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 08:37:35 +0100 Subject: [PATCH 23/38] Fixup code coverage script --- etc/code-coverage-test-gap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/code-coverage-test-gap.py b/etc/code-coverage-test-gap.py index e50ea5a..c9b0432 100755 --- a/etc/code-coverage-test-gap.py +++ b/etc/code-coverage-test-gap.py @@ -103,5 +103,5 @@ def rewrite_fname(fname: str) -> str: else: filename = _DIR + "/index.html" print(f"{_INFO_PREFIX}\nSUCCESS!\033[0m") -print(f"{_INFO_PREFIX} See {filename}") +print(f"{_INFO_PREFIX}See {filename}") sys.exit(0) From 62578776c749b78d55656c1172cbdd302e7ef3fd Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 09:09:44 +0100 Subject: [PATCH 24/38] Update desc. strings --- gap/dot.gd | 44 +++++++-------- gap/dot.gi | 148 ++++++++++++++++++++++++++------------------------ gap/gv.gd | 46 ++++++++-------- gap/gv.gi | 42 +++++++------- gap/splash.gi | 4 +- 5 files changed, 147 insertions(+), 137 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index 7e0f67b..508d6da 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -38,10 +38,10 @@ DeclareCategory("IsGraphvizObject", IsObject); -DeclareCategory("IsGraphvizObjectWithSubobjects", IsGraphvizObject); -DeclareCategory("IsGraphvizGraph", IsGraphvizObjectWithSubobjects); -DeclareCategory("IsGraphvizDigraph", IsGraphvizObjectWithSubobjects); -DeclareCategory("IsGraphvizContext", IsGraphvizObjectWithSubobjects); +DeclareCategory("IsGraphvizGraphDigraphOrContext", IsGraphvizObject); +DeclareCategory("IsGraphvizGraph", IsGraphvizGraphDigraphOrContext); +DeclareCategory("IsGraphvizDigraph", IsGraphvizGraphDigraphOrContext); +DeclareCategory("IsGraphvizContext", IsGraphvizGraphDigraphOrContext); DeclareCategory("IsGraphvizNodeOrEdge", IsGraphvizObject); DeclareCategory("IsGraphvizNode", IsGraphvizNodeOrEdge); @@ -97,12 +97,12 @@ DeclareOperation("GraphvizAttrs", [IsGraphvizObject]); # any double-quoted string ("...") possibly containing escaped quotes (\")¹; # an HTML string (<...>). # TODO specify -DeclareOperation("GraphvizNodes", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GraphvizNodes", [IsGraphvizGraphDigraphOrContext]); #! @Arguments graph #! @Returns the subgraphs of the provided graphviz graph. #! @Description gets the subgraphs of a provided graphviz graph. -DeclareOperation("GraphvizSubgraphs", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GraphvizSubgraphs", [IsGraphvizGraphDigraphOrContext]); #! @Arguments graph, name #! @Returns a graph with the provided name. @@ -112,14 +112,14 @@ DeclareOperation("GraphvizSubgraphs", [IsGraphvizObjectWithSubobjects]); #! It returns the graph if it exists. #! If no such graph exists then it will return fail. DeclareOperation("GraphvizFindSubgraphRecursive", -[IsGraphvizObjectWithSubobjects, IsObject]); +[IsGraphvizGraphDigraphOrContext, IsObject]); #! @Arguments graph #! @Returns the edges of the provided graphviz graph. #! @Description Gets the edges of the provided graphviz graph. -DeclareOperation("GraphvizEdges", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GraphvizEdges", [IsGraphvizGraphDigraphOrContext]); DeclareOperation("GraphvizEdges", -[IsGraphvizObjectWithSubobjects, IsObject, IsObject]); +[IsGraphvizGraphDigraphOrContext, IsObject, IsObject]); #! @Subsection For only edges. @@ -141,13 +141,13 @@ DeclareOperation("GraphvizTail", [IsGraphvizEdge]); #! @Arguments graph, name #! @Returns the modified graph. #! @Description Sets the name of a graphviz graph or digraph. -DeclareOperation("GraphvizSetName", [IsGraphvizObjectWithSubobjects, IsObject]); +DeclareOperation("GraphvizSetName", [IsGraphvizGraphDigraphOrContext, IsObject]); #! @Arguments graph, node #! @Returns the modified graph. #! @Description Adds a node to the graph. #! If a node with the same name is already present the operation fails. -DeclareOperation("GraphvizAddNode", [IsGraphvizObjectWithSubobjects, IsObject]); +DeclareOperation("GraphvizAddNode", [IsGraphvizGraphDigraphOrContext, IsObject]); #! @Arguments graph, edge #! @Returns the modified graph. @@ -156,40 +156,40 @@ DeclareOperation("GraphvizAddNode", [IsGraphvizObjectWithSubobjects, IsObject]); #! added to the graph. If different nodes with the same name are in the graph #! then the operation fails. DeclareOperation("GraphvizAddEdge", -[IsGraphvizObjectWithSubobjects, IsObject, IsObject]); +[IsGraphvizGraphDigraphOrContext, IsObject, IsObject]); #! @Arguments graph, filter, name #! @Returns the new subgraph. #! @Description Adds a subgraph to a graph. DeclareOperation("GraphvizAddSubgraph", -[IsGraphvizObjectWithSubobjects, IsObject]); -DeclareOperation("GraphvizAddSubgraph", [IsGraphvizObjectWithSubobjects]); +[IsGraphvizGraphDigraphOrContext, IsObject]); +DeclareOperation("GraphvizAddSubgraph", [IsGraphvizGraphDigraphOrContext]); #! @Arguments graph, filter, name #! @Returns the new context. #! @Description Adds a context to a graph. DeclareOperation("GraphvizAddContext", -[IsGraphvizObjectWithSubobjects, IsObject]); -DeclareOperation("GraphvizAddContext", [IsGraphvizObjectWithSubobjects]); +[IsGraphvizGraphDigraphOrContext, IsObject]); +DeclareOperation("GraphvizAddContext", [IsGraphvizGraphDigraphOrContext]); #! @Arguments graph, node #! @Returns the modified graph. #! @Description Removes the node from the graph. DeclareOperation("GraphvizRemoveNode", -[IsGraphvizObjectWithSubobjects, IsObject]); +[IsGraphvizGraphDigraphOrContext, IsObject]); #! @Arguments graph, predicate #! @Returns the modified graph. #! @Description Filters the graph's edges using the provided predicate. DeclareOperation("GraphvizFilterEdges", -[IsGraphvizObjectWithSubobjects, IsFunction]); +[IsGraphvizGraphDigraphOrContext, IsFunction]); #! @Arguments graph, head_name, tail_name #! @Returns the modified graph. #! @Description Filters the graph's edges, removing edges between nodes with #! the specified names. DeclareOperation("GraphvizRemoveEdges", -[IsGraphvizObjectWithSubobjects, IsObject, IsObject]); +[IsGraphvizGraphDigraphOrContext, IsObject, IsObject]); #! @Subsection For modifying object attributes. @@ -222,9 +222,9 @@ DeclareOperation("GraphvizRemoveAttr", [IsGraphvizObject, IsObject]); DeclareOperation("Graphviz", [IsObject]); DeclareOperation("GraphvizSetNodeColors", -[IsGraphvizObjectWithSubobjects, IsList]); +[IsGraphvizGraphDigraphOrContext, IsList]); DeclareOperation("GraphvizSetNodeLabels", -[IsGraphvizObjectWithSubobjects, IsList]); +[IsGraphvizGraphDigraphOrContext, IsList]); DeclareGlobalFunction("ErrorIfNotValidColor"); @@ -239,4 +239,4 @@ DeclareOperation("\[\]", [IsGraphvizEdge, IsObject]); DeclareOperation("\[\]\:\=", [IsGraphvizEdge, IsObject, IsObject]); # TODO doc -DeclareOperation("\[\]", [IsGraphvizObjectWithSubobjects, IsObject]); +DeclareOperation("\[\]", [IsGraphvizGraphDigraphOrContext, IsObject]); diff --git a/gap/dot.gi b/gap/dot.gi index b56d4ca..b2b9b85 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -61,8 +61,8 @@ function(e) GraphvizName(tail)); end); -InstallMethod(PrintString, "for a graphviz object with subobjects", -[IsGraphvizObjectWithSubobjects], +InstallMethod(PrintString, "for a graphviz (di)graph or context", +[IsGraphvizGraphDigraphOrContext], function(g) local result, edges, nodes, kind; @@ -101,15 +101,15 @@ x -> x!.Name); InstallMethod(GraphvizAttrs, "for a graphviz object", [IsGraphvizObject], x -> x!.Attrs); -InstallMethod(GraphvizNodes, "for a graphviz (di)graph", -[IsGraphvizObjectWithSubobjects], x -> x!.Nodes); +InstallMethod(GraphvizNodes, "for a graphviz (di)graph or context", +[IsGraphvizGraphDigraphOrContext], x -> x!.Nodes); -InstallMethod(GraphvizEdges, "for a graphviz (di)graph", -[IsGraphvizObjectWithSubobjects], x -> x!.Edges); +InstallMethod(GraphvizEdges, "for a graphviz (di)graph or context", +[IsGraphvizGraphDigraphOrContext], x -> x!.Edges); InstallMethod(GraphvizEdges, -"for a graphviz (di)graph, object, and object", -[IsGraphvizObjectWithSubobjects, IsObject, IsObject], +"for a graphviz (di)graph or context, object, and object", +[IsGraphvizGraphDigraphOrContext, IsObject, IsObject], function(gv, head, tail) head := GraphvizNodes(gv)[head]; if head = fail then @@ -125,8 +125,8 @@ function(gv, head, tail) x -> GraphvizHead(x) = head and GraphvizTail(x) = tail); end); -InstallMethod(GraphvizSubgraphs, "for a graphviz (di)graph", -[IsGraphvizObjectWithSubobjects], x -> x!.Subgraphs); +InstallMethod(GraphvizSubgraphs, "for a graphviz (di)graph or context", +[IsGraphvizGraphDigraphOrContext], x -> x!.Subgraphs); InstallMethod(GraphvizTail, "for a graphviz edge", [IsGraphvizEdge], x -> x!.Tail); @@ -182,37 +182,37 @@ end); # Accessor for graphs and digraphs -InstallMethod(\[\], "for a graphviz (di)graph and string", -[IsGraphvizObjectWithSubobjects, IsString], +InstallMethod(\[\], "for a graphviz (di)graph or context and string", +[IsGraphvizGraphDigraphOrContext, IsString], {graph, node} -> GraphvizNodes(graph)[node]); -InstallMethod(\[\], "for a graphviz (di)graph and object", -[IsGraphvizObjectWithSubobjects, IsObject], +InstallMethod(\[\], "for a graphviz (di)graph or context and object", +[IsGraphvizGraphDigraphOrContext, IsObject], {g, o} -> g[String(o)]); InstallMethod(GraphvizFindSubgraphRecursive, -"for a graphviz (di)graph and a string", -[IsGraphvizObjectWithSubobjects, IsString], +"for a graphviz (di)graph or context and a string", +[IsGraphvizGraphDigraphOrContext, IsString], {g, s} -> GV_GraphTreeSearch(g, v -> GraphvizName(v) = s)); InstallMethod(GraphvizFindSubgraphRecursive, -"for a graphviz (di)graph and a string", -[IsGraphvizObjectWithSubobjects, IsObject], +"for a graphviz (di)graph or context and a string", +[IsGraphvizGraphDigraphOrContext, IsObject], {g, o} -> GraphvizFindSubgraphRecursive(g, String(o))); ############################################################################# # GraphvizSetName ############################################################################# -InstallMethod(GraphvizSetName, "for a graphviz (di)graph and string", -[IsGraphvizObjectWithSubobjects, IsString], +InstallMethod(GraphvizSetName, "for a graphviz (di)graph or context and string", +[IsGraphvizGraphDigraphOrContext, IsString], function(x, name) x!.Name := name; return x; end); -InstallMethod(GraphvizSetName, "for a graphviz (di)graph and string", -[IsGraphvizObjectWithSubobjects, IsObject], +InstallMethod(GraphvizSetName, "for a graphviz (di)graph or context and string", +[IsGraphvizGraphDigraphOrContext, IsObject], {g, o} -> GraphvizSetName(g, String(o))); ############################################################################# @@ -245,7 +245,7 @@ end); InstallMethod(GraphvizSetAttr, "for a graphviz object with subobjects, object, and object", -[IsGraphvizObjectWithSubobjects, IsObject, IsObject], +[IsGraphvizGraphDigraphOrContext, IsObject, IsObject], function(x, name, value) local attrs, string; @@ -269,8 +269,8 @@ function(x, name, value) return x; end); -InstallMethod(GraphvizSetAttr, "for a graphviz (di)graph and object", -[IsGraphvizObjectWithSubobjects, IsObject], +InstallMethod(GraphvizSetAttr, "for a graphviz (di)graph or context and object", +[IsGraphvizGraphDigraphOrContext, IsObject], function(x, value) local attrs; attrs := GraphvizAttrs(x); @@ -283,8 +283,8 @@ end); # GraphvizAddNode ############################################################################# -InstallMethod(GraphvizAddNode, "for a graphviz (di)graph and string", -[IsGraphvizObjectWithSubobjects, IsString], +InstallMethod(GraphvizAddNode, "for a graphviz (di)graph or context and string", +[IsGraphvizGraphDigraphOrContext, IsString], function(x, name) local node; node := GV_Node(x, name); @@ -292,8 +292,8 @@ function(x, name) return node; end); -InstallMethod(GraphvizAddNode, "for a graphviz (di)graph and string", -[IsGraphvizObjectWithSubobjects, IsGraphvizNode], +InstallMethod(GraphvizAddNode, "for a graphviz (di)graph or context and string", +[IsGraphvizGraphDigraphOrContext, IsGraphvizNode], function(gv, name) # gaplint: disable=analyse-lvars ErrorNoReturn("it is not currently possible to add Graphviz node ", "objects directly to Graphviz graphs or digraphs, use ", @@ -301,8 +301,8 @@ function(gv, name) # gaplint: disable=analyse-lvars end); InstallMethod(GraphvizAddNode, -"for a graphviz (di)graph and string", -[IsGraphvizObjectWithSubobjects, IsObject], +"for a graphviz (di)graph or context and string", +[IsGraphvizGraphDigraphOrContext, IsObject], {x, name} -> GraphvizAddNode(x, String(name))); ############################################################################# @@ -310,8 +310,8 @@ InstallMethod(GraphvizAddNode, ############################################################################# InstallMethod(GraphvizAddEdge, -"for a graphviz (di)graph and two graphviz nodes", -[IsGraphvizObjectWithSubobjects, IsGraphvizNode, IsGraphvizNode], +"for a graphviz (di)graph or context and two graphviz nodes", +[IsGraphvizGraphDigraphOrContext, IsGraphvizNode, IsGraphvizNode], function(x, head, tail) local edge, head_name, tail_name; @@ -332,8 +332,8 @@ function(x, head, tail) end); InstallMethod(GraphvizAddEdge, -"for a graphviz (di)graph and two strings", -[IsGraphvizObjectWithSubobjects, IsString, IsString], +"for a graphviz (di)graph or context and two strings", +[IsGraphvizGraphDigraphOrContext, IsString, IsString], function(x, head, tail) local head_node, tail_node; @@ -351,16 +351,17 @@ function(x, head, tail) end); InstallMethod(GraphvizAddEdge, -"for a graphviz (di)graph and two objects", -[IsGraphvizObjectWithSubobjects, IsObject, IsObject], +"for a graphviz (di)graph or context and two objects", +[IsGraphvizGraphDigraphOrContext, IsObject, IsObject], {gv, o1, o2} -> GraphvizAddEdge(gv, String(o1), String(o2))); ############################################################################# # GraphvizAddSubgraph ############################################################################# -InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph and string", -[IsGraphvizObjectWithSubobjects, IsString], +InstallMethod(GraphvizAddSubgraph, +"for a graphviz (di)graph or context and string", +[IsGraphvizGraphDigraphOrContext, IsString], function(gv, name) local subgraphs, root, subgraph; @@ -386,19 +387,20 @@ function(gv, name) return subgraph; end); -InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph and an object", -[IsGraphvizObjectWithSubobjects, IsObject], +InstallMethod(GraphvizAddSubgraph, +"for a graphviz (di)graph or context and an object", +[IsGraphvizGraphDigraphOrContext, IsObject], {g, o} -> GraphvizAddSubgraph(g, String(o))); -InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph", -[IsGraphvizObjectWithSubobjects], +InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph or context", +[IsGraphvizGraphDigraphOrContext], graph -> GraphvizAddSubgraph(graph, StringFormatted("no_name_{}", GV_GetCounter(graph)))); InstallMethod(GraphvizAddContext, -"for a graphviz (di)graph and a string", -[IsGraphvizObjectWithSubobjects, IsString], +"for a graphviz (di)graph or context and a string", +[IsGraphvizGraphDigraphOrContext, IsString], function(graph, name) local subgraphs, ctx; @@ -417,21 +419,22 @@ function(graph, name) end); InstallMethod(GraphvizAddContext, -"for a graphviz (di)graph", -[IsGraphvizObjectWithSubobjects], +"for a graphviz (di)graph or context", +[IsGraphvizGraphDigraphOrContext], g -> GraphvizAddContext(g, StringFormatted("no_name_{}", GV_GetCounter(g)))); InstallMethod(GraphvizAddContext, -"for a graphviz (di)graph and an object", -[IsGraphvizObjectWithSubobjects, IsObject], +"for a graphviz (di)graph or context and an object", +[IsGraphvizGraphDigraphOrContext, IsObject], {g, o} -> GraphvizAddContext(g, String(o))); -InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph and node", -[IsGraphvizObjectWithSubobjects, IsGraphvizNode], +InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph or context and node", +[IsGraphvizGraphDigraphOrContext, IsGraphvizNode], {g, node} -> GraphvizRemoveNode(g, GraphvizName(node))); -InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph and a string", -[IsGraphvizObjectWithSubobjects, IsString], +InstallMethod(GraphvizRemoveNode, +"for a graphviz (di)graph or context and a string", +[IsGraphvizGraphDigraphOrContext, IsString], function(g, name) local nodes; nodes := GraphvizNodes(g); @@ -456,12 +459,14 @@ function(g, name) return g; end); -InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph and a string", -[IsGraphvizObjectWithSubobjects, IsObject], +InstallMethod(GraphvizRemoveNode, +"for a graphviz (di)graph or context and a string", +[IsGraphvizGraphDigraphOrContext, IsObject], {g, o} -> GraphvizRemoveNode(g, String(o))); -InstallMethod(GraphvizFilterEdges, "for a graphviz (di)graph and edge filter", -[IsGraphvizObjectWithSubobjects, IsFunction], +InstallMethod(GraphvizFilterEdges, +"for a graphviz (di)graph or context and edge filter", +[IsGraphvizGraphDigraphOrContext, IsFunction], function(g, filter) local edge, idx, edges; @@ -478,8 +483,9 @@ function(g, filter) return g; end); -InstallMethod(GraphvizRemoveEdges, "for a graphviz (di)graph and two strings", -[IsGraphvizObjectWithSubobjects, IsString, IsString], +InstallMethod(GraphvizRemoveEdges, +"for a graphviz (di)graph or context, string, and string", +[IsGraphvizGraphDigraphOrContext, IsString, IsString], function(g, hn, tn) GraphvizFilterEdges(g, function(e) @@ -497,8 +503,9 @@ function(g, hn, tn) return g; end); -InstallMethod(GraphvizRemoveEdges, "for a graphviz (di)graph and two objects", -[IsGraphvizObjectWithSubobjects, IsObject, IsObject], +InstallMethod(GraphvizRemoveEdges, +"for a graphviz (di)graph or context, object, and object", +[IsGraphvizGraphDigraphOrContext, IsObject, IsObject], {gv, o1, o2} -> GraphvizRemoveEdges(gv, String(o1), String(o2))); InstallMethod(GraphvizRemoveAttr, "for a graphviz object and an object", @@ -511,8 +518,9 @@ function(obj, attr) return obj; end); -InstallMethod(GraphvizRemoveAttr, "for a graphviz (di)graph and an object", -[IsGraphvizObjectWithSubobjects, IsObject], +InstallMethod(GraphvizRemoveAttr, +"for a graphviz (di)graph or context and an object", +[IsGraphvizGraphDigraphOrContext, IsObject], function(obj, attr) local attrs; attrs := GraphvizAttrs(obj); @@ -524,21 +532,21 @@ end); # Stringify ############################################################################# -InstallMethod(String, "for a graphviz (di)graph", -[IsGraphvizObjectWithSubobjects], graph -> GV_StringifyGraph(graph, false)); +InstallMethod(String, "for a graphviz (di)graph or context", +[IsGraphvizGraphDigraphOrContext], graph -> GV_StringifyGraph(graph, false)); # Can't do the following because it conflicts with the PrintString above, we # leave this here as a reminder. # InstallMethod(PrintObj, "for a graphviz object with subobjects", -# [IsGraphvizObjectWithSubobjects], +# [IsGraphvizGraphDigraphOrContext], # function(gv) # Print(String(gv)); # end); InstallMethod(GraphvizSetNodeLabels, -"for a graphviz (di)graph and list of colors", -[IsGraphvizObjectWithSubobjects, IsList], +"for a graphviz (di)graph or context and list of colors", +[IsGraphvizGraphDigraphOrContext, IsList], function(gv, labels) local nodes, i; if Size(GraphvizNodes(gv)) <> Size(labels) then @@ -555,8 +563,8 @@ function(gv, labels) end); InstallMethod(GraphvizSetNodeColors, -"for a graphviz (di)graph and list of colors", -[IsGraphvizObjectWithSubobjects, IsList], +"for a graphviz (di)graph or context and list of colors", +[IsGraphvizGraphDigraphOrContext, IsList], function(gv, colors) local nodes, i; diff --git a/gap/gv.gd b/gap/gv.gd index d75118f..6d453f5 100644 --- a/gap/gv.gd +++ b/gap/gv.gd @@ -11,49 +11,51 @@ ## This file contains declarations of the internal/private functions for the ## graphviz package. -DeclareOperation("GV_GetCounter", [IsGraphvizObjectWithSubobjects]); -DeclareOperation("GV_IncCounter", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GV_GetCounter", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GV_IncCounter", [IsGraphvizGraphDigraphOrContext]); DeclareCategory("GV_IsMap", IsObject); DeclareAttribute("Size", GV_IsMap); -DeclareOperation("GV_StringifyGraphHead", [IsGraphvizObjectWithSubobjects]); -DeclareOperation("GV_StringifyDigraphHead", [IsGraphvizObjectWithSubobjects]); -DeclareOperation("GV_StringifySubgraphHead", [IsGraphvizObjectWithSubobjects]); -DeclareOperation("GV_StringifyContextHead", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GV_StringifyGraphHead", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GV_StringifyDigraphHead", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GV_StringifySubgraphHead", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GV_StringifyContextHead", [IsGraphvizGraphDigraphOrContext]); DeclareOperation("GV_StringifyNode", [IsGraphvizNode]); -DeclareOperation("GV_StringifyGraphAttrs", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GV_StringifyGraphAttrs", [IsGraphvizGraphDigraphOrContext]); DeclareOperation("GV_StringifyNodeEdgeAttrs", [GV_IsMap]); -DeclareOperation("GV_StringifyGraph", [IsGraphvizObjectWithSubobjects, IsBool]); +DeclareOperation("GV_StringifyGraph", [IsGraphvizGraphDigraphOrContext, IsBool]); -DeclareOperation("GV_FindNode", [IsGraphvizObjectWithSubobjects, IsObject]); +DeclareOperation("GV_FindNode", [IsGraphvizGraphDigraphOrContext, IsObject]); DeclareOperation("GV_Pluralize", [IsInt, IsString]); -DeclareOperation("GV_Node", [IsGraphvizObjectWithSubobjects, IsString]); +DeclareOperation("GV_Node", [IsGraphvizGraphDigraphOrContext, IsString]); DeclareOperation("GV_Edge", -[IsGraphvizObjectWithSubobjects, IsGraphvizNode, IsGraphvizNode]); -DeclareOperation("GV_Graph", [IsGraphvizObjectWithSubobjects, IsString]); +[IsGraphvizGraphDigraphOrContext, IsGraphvizNode, IsGraphvizNode]); +DeclareOperation("GV_Graph", [IsGraphvizGraphDigraphOrContext, IsString]); DeclareOperation("GV_Digraph", [IsGraphvizDigraph, IsString]); -DeclareOperation("GV_Context", [IsGraphvizObjectWithSubobjects, IsString]); +DeclareOperation("GV_Context", [IsGraphvizGraphDigraphOrContext, IsString]); DeclareOperation("GV_Map", []); DeclareOperation("GV_MapNames", [GV_IsMap]); # TODO required? Replace with String or just String? DeclareOperation("GV_EnsureString", [IsObject]); -DeclareOperation("GV_HasNode", [IsGraphvizObjectWithSubobjects, IsObject]); +DeclareOperation("GV_HasNode", [IsGraphvizGraphDigraphOrContext, IsObject]); -DeclareOperation("GV_GetParent", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GV_GetParent", [IsGraphvizGraphDigraphOrContext]); DeclareOperation("GV_GraphTreeSearch", -[IsGraphvizObjectWithSubobjects, IsFunction]); +[IsGraphvizGraphDigraphOrContext, IsFunction]); DeclareOperation("GV_FindGraphWithNode", -[IsGraphvizObjectWithSubobjects, IsString]); -DeclareOperation("GV_GetRoot", [IsGraphvizObjectWithSubobjects]); -DeclareOperation("GV_EnclosingNonContext", [IsGraphvizObjectWithSubobjects]); -DeclareOperation("GV_AddNode", [IsGraphvizObjectWithSubobjects, IsGraphvizNode]); -DeclareOperation("GV_AddEdge", [IsGraphvizObjectWithSubobjects, IsGraphvizEdge]); +[IsGraphvizGraphDigraphOrContext, IsString]); +DeclareOperation("GV_GetRoot", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GV_EnclosingNonContext", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GV_AddNode", +[IsGraphvizGraphDigraphOrContext, IsGraphvizNode]); +DeclareOperation("GV_AddEdge", +[IsGraphvizGraphDigraphOrContext, IsGraphvizEdge]); DeclareOperation("GV_GetIdx", [IsGraphvizObject]); -DeclareOperation("GV_ConstructHistory", [IsGraphvizObjectWithSubobjects]); +DeclareOperation("GV_ConstructHistory", [IsGraphvizGraphDigraphOrContext]); DeclareGlobalFunction("GV_IsValidColor"); DeclareGlobalFunction("GV_ErrorIfNotNodeColoring"); diff --git a/gap/gv.gi b/gap/gv.gi index 9f38e5a..d4eeb03 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -125,7 +125,7 @@ InstallMethod(GV_Map, "for no args", [], {} -> Objectify(GV_MapType, rec(Data := rec()))); InstallMethod(GV_Node, "for a string", -[IsGraphvizObjectWithSubobjects, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], function(graph, name) local out; if Length(name) = 0 then @@ -141,7 +141,7 @@ function(graph, name) end); InstallMethod(GV_Edge, "for two graphviz nodes", -[IsGraphvizObjectWithSubobjects, IsGraphvizNode, IsGraphvizNode], +[IsGraphvizGraphDigraphOrContext, IsGraphvizNode, IsGraphvizNode], function(graph, head, tail) local out; out := Objectify(GV_EdgeType, @@ -173,7 +173,7 @@ end); InstallMethod(GV_Graph, "for a graphviz graph and a string", -[IsGraphvizObjectWithSubobjects, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], function(parent, name) local out; @@ -187,7 +187,7 @@ end); InstallMethod(GV_Context, "for a string and a positive integer", -[IsGraphvizObjectWithSubobjects, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], function(parent, name) local out; @@ -259,13 +259,13 @@ InstallMethod(Size, "for a graphviz map", InstallMethod(GV_IncCounter, "for a graphviz graph", -[IsGraphvizObjectWithSubobjects], +[IsGraphvizGraphDigraphOrContext], function(x) x!.Counter := x!.Counter + 1; end); InstallMethod(GV_GetCounter, "for a graphviz graph", -[IsGraphvizObjectWithSubobjects], +[IsGraphvizGraphDigraphOrContext], x -> x!.Counter); # Converting strings @@ -278,16 +278,16 @@ InstallMethod(GV_EnsureString, "for a string", [IsString], IdFunc); InstallMethod(GV_HasNode, "for a graphviz graph", -[IsGraphvizObjectWithSubobjects, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], {g, name} -> name in GV_MapNames(GraphvizNodes(g))); InstallMethod(GV_GetParent, "for a graphviz graph", -[IsGraphvizObjectWithSubobjects], graph -> graph!.Parent); +[IsGraphvizGraphDigraphOrContext], graph -> graph!.Parent); InstallMethod(GV_GraphTreeSearch, "for a graphviz graph and a predicate", -[IsGraphvizObjectWithSubobjects, IsFunction], +[IsGraphvizGraphDigraphOrContext, IsFunction], function(graph, pred) local seen, to_visit, g, key, subgraph, parent; seen := [graph]; @@ -312,7 +312,7 @@ function(graph, pred) # add parent if not visited parent := GV_GetParent(g); - if not IsGraphvizObjectWithSubobjects(parent) then + if not IsGraphvizGraphDigraphOrContext(parent) then continue; fi; if not ForAny(seen, s -> IsIdenticalObj(s, parent)) then @@ -326,12 +326,12 @@ end); InstallMethod(GV_FindGraphWithNode, "for a graphviz graph and a node", -[IsGraphvizObjectWithSubobjects, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], {g, n} -> GV_GraphTreeSearch(g, v -> v[n] <> fail)); InstallMethod(GV_GetRoot, "for a graphviz graph", -[IsGraphvizObjectWithSubobjects], +[IsGraphvizGraphDigraphOrContext], function(graph) while GV_GetParent(graph) <> fail do graph := GV_GetParent(graph); @@ -353,7 +353,7 @@ end); InstallMethod(GV_FindNode, "for a graphviz graph and a string", -[IsGraphvizObjectWithSubobjects, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], function(g, n) local graph; graph := GV_FindGraphWithNode(g, n); @@ -365,7 +365,7 @@ end); InstallMethod(GV_AddNode, "for a graphviz graph and node", -[IsGraphvizObjectWithSubobjects, IsGraphvizNode], +[IsGraphvizGraphDigraphOrContext, IsGraphvizNode], function(x, node) local found, error, name, nodes; name := GraphvizName(node); @@ -384,7 +384,7 @@ end); InstallMethod(GV_AddEdge, "for a graphviz graph and edge", -[IsGraphvizObjectWithSubobjects, IsGraphvizEdge], +[IsGraphvizGraphDigraphOrContext, IsGraphvizEdge], function(x, edge) local head, head_name, tail_name, tail, hg, error, tg; @@ -428,7 +428,7 @@ end); # @ Return DOT graph head line. InstallMethod(GV_StringifyGraphHead, "for a string", -[IsGraphvizObjectWithSubobjects], +[IsGraphvizGraphDigraphOrContext], graph -> StringFormatted("graph {} {{\n", GraphvizName(graph))); # @ Return DOT digraph head line. @@ -437,7 +437,7 @@ graph -> StringFormatted("digraph {} {{\n", GraphvizName(graph))); # @ Return DOT subgraph head line. InstallMethod(GV_StringifySubgraphHead, "for a string", -[IsGraphvizObjectWithSubobjects], +[IsGraphvizGraphDigraphOrContext], graph -> StringFormatted("subgraph {} {{\n", GraphvizName(graph))); # @ Return DOT subgraph head line. @@ -496,7 +496,7 @@ end); InstallMethod(GV_StringifyGraphAttrs, "for a graphviz graph", -[IsGraphvizObjectWithSubobjects], +[IsGraphvizGraphDigraphOrContext], function(graph) local result, attrs, kv; attrs := GraphvizAttrs(graph); @@ -581,7 +581,7 @@ x -> x!.Idx); InstallMethod(GV_ConstructHistory, "for a graphviz graph", -[IsGraphvizObjectWithSubobjects], +[IsGraphvizGraphDigraphOrContext], function(graph) local nodes, edges, subs, node_hist, edge_hist, subs_hist, hist; @@ -602,7 +602,7 @@ end); InstallMethod(GV_StringifyGraph, "for a graphviz graph and a string", -[IsGraphvizObjectWithSubobjects, IsBool], +[IsGraphvizGraphDigraphOrContext, IsBool], function(graph, is_subgraph) local result, obj; result := ""; @@ -633,7 +633,7 @@ function(graph, is_subgraph) # Add child graphviz objects for obj in GV_ConstructHistory(graph) do - if IsGraphvizObjectWithSubobjects(obj) then + if IsGraphvizGraphDigraphOrContext(obj) then Append(result, GV_StringifyGraph(obj, true)); elif IsGraphvizNode(obj) then Append(result, GV_StringifyNode(obj)); diff --git a/gap/splash.gi b/gap/splash.gi index 57bbf19..9d3c67e 100644 --- a/gap/splash.gi +++ b/gap/splash.gi @@ -22,10 +22,10 @@ function(arg...) if IsEmpty(arg) then ErrorNoReturn("the must be at least 1 argument, found none"); - elif not IsString(arg[1]) and not IsGraphvizObjectWithSubobjects(arg[1]) then + elif not IsString(arg[1]) and not IsGraphvizGraphDigraphOrContext(arg[1]) then ErrorFormatted("the 1st argument must be a string or ", "graphviz graph, found {}", TNAM_OBJ(arg[1])); - elif IsGraphvizObjectWithSubobjects(arg[1]) then + elif IsGraphvizGraphDigraphOrContext(arg[1]) then file := GraphvizName(arg[1]); for i in [1 .. Length(file)] do if not IsAlphaChar(file[i]) and not IsDigitChar(file[i]) then From 19e0450b990eab60575ef88ba836cb58d341d44e Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 10:55:29 +0100 Subject: [PATCH 25/38] More test for code coverage --- etc/tst-local-vars.yml | 8 +++ gap/dot.gi | 36 ++++++++------ gap/gv.gi | 8 --- tst/dot.tst | 109 ++++++++++++++++++++++++++++++++++++++++- tst/edge.tst | 7 ++- tst/graph.tst | 29 +++++++++++ tst/node.tst | 12 ++++- tst/subgraph.tst | 33 +++++++++++-- 8 files changed, 212 insertions(+), 30 deletions(-) create mode 100644 etc/tst-local-vars.yml diff --git a/etc/tst-local-vars.yml b/etc/tst-local-vars.yml new file mode 100644 index 0000000..844de31 --- /dev/null +++ b/etc/tst-local-vars.yml @@ -0,0 +1,8 @@ +name: tst-local-vars + +channels: + - conda-forge + +dependencies: + - pyyaml + - bs4 diff --git a/gap/dot.gi b/gap/dot.gi index b2b9b85..0b2e2a8 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -111,18 +111,22 @@ InstallMethod(GraphvizEdges, "for a graphviz (di)graph or context, object, and object", [IsGraphvizGraphDigraphOrContext, IsObject, IsObject], function(gv, head, tail) - head := GraphvizNodes(gv)[head]; - if head = fail then - ErrorNoReturn("the 2nd argument (head of an edge) is not a node ", - "of the 1st argument (a graphviz graph or digraph)"); + local nhead, ntail; + + nhead := GraphvizNodes(gv)[head]; + if nhead = fail then + ErrorFormatted("the 2nd argument \"{}\" (head of an edge) is not a ", + "node of the 1st argument (a graphviz graph or digraph)", + head); fi; - tail := GraphvizNodes(gv)[tail]; - if tail = fail then - ErrorNoReturn("the 2nd argument (head of an edge) is not a node ", - "of the 1st argument (a graphviz graph or digraph)"); + ntail := GraphvizNodes(gv)[tail]; + if ntail = fail then + ErrorFormatted("the 3rd argument \"{}\" (tail of an edge) is not a ", + "node of the 1st argument (a graphviz graph or digraph)", + tail); fi; return Filtered(GraphvizEdges(gv), - x -> GraphvizHead(x) = head and GraphvizTail(x) = tail); + x -> GraphvizHead(x) = nhead and GraphvizTail(x) = ntail); end); InstallMethod(GraphvizSubgraphs, "for a graphviz (di)graph or context", @@ -367,8 +371,8 @@ function(gv, name) subgraphs := GraphvizSubgraphs(gv); if IsBound(subgraphs[name]) then - ErrorFormatted("the 1st argument (a graphviz (di)graph) already has ", - " a subgraph with name \"{}\"", name); + ErrorFormatted("the 1st argument (a graphviz (di)graph/context) ", + "already has a subgraph with name \"{}\"", name); fi; if IsGraphvizContext(gv) then @@ -409,8 +413,9 @@ function(graph, name) # contexts and subgraphs, rather than just subgraphs as the name suggests # See https://github.com/digraphs/graphviz/issues/19 if IsBound(subgraphs[name]) then - ErrorFormatted("the 1st argument (a graphviz (di)graph) already has ", - " a context or subgraph with name \"{}\"", name); + ErrorFormatted("the 1st argument (a graphviz (di)graph/context) ", + "already has a context or subgraph with name \"{}\"", + name); fi; ctx := GV_Context(graph, name); @@ -443,7 +448,8 @@ function(g, name) else # Don't just silently do nothing ErrorFormatted("the 2nd argument (node name string) \"{}\"", - " is not a node of the 1st argument (a graphviz (di)graph)", + " is not a node of the 1st argument (a graphviz", + " (di)graph/context)", name); fi; @@ -518,6 +524,8 @@ function(obj, attr) return obj; end); +# TODO this doesn't currently work as intended, see: +# https://github.com/digraphs/graphviz/issues/23 InstallMethod(GraphvizRemoveAttr, "for a graphviz (di)graph or context and an object", [IsGraphvizGraphDigraphOrContext, IsObject], diff --git a/gap/gv.gi b/gap/gv.gi index d4eeb03..2a697c0 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -395,14 +395,6 @@ function(x, edge) hg := GV_FindGraphWithNode(x, head_name); tg := GV_FindGraphWithNode(x, tail_name); - # if not already existing, add the nodes to the graph - if hg = fail then - GV_AddNode(x, head); - fi; - if tg = fail then - GV_AddNode(x, tail); - fi; - # make sure the nodes exist / are the same as existing ones if hg <> fail and not IsIdenticalObj(head, hg[head_name]) then # TODO improve diff --git a/tst/dot.tst b/tst/dot.tst index 43d3a83..7d8c398 100644 --- a/tst/dot.tst +++ b/tst/dot.tst @@ -8,7 +8,7 @@ ############################################################################# ## -#@local a, b, color, e, g, label, n, shape +#@local a, b, color, e, g, gv, label, n, shape gap> START_TEST("graphviz package: dot.tst"); gap> LoadPackage("graphviz", false);; @@ -39,7 +39,7 @@ gap> String(g); "//dot\ngraph {\n\ttest [color=red, label=lab]\n}\n" gap> GraphvizRemoveNode(g, "banana"); Error, the 2nd argument (node name string) "banana" is not a node of the 1st a\ -rgument (a graphviz (di)graph) +rgument (a graphviz (di)graph/context) # Test stringify with edge (digraphs) gap> g := GraphvizDigraph();; @@ -107,5 +107,110 @@ gap> GraphvizSetAttr(e, "label", "before>>hello");; gap> String(g); "//dot\ngraph {\n\ta\n\tb\n\ta -- b [label=\"before>>hello\"]\n}\n" +# Test GraphvizSetNodeLabels +gap> gv := GraphvizGraph("xxx"); + +gap> GraphvizAddNode(gv, 1); + +gap> GraphvizAddNode(gv, 2); + +gap> GraphvizAddNode(gv, 3); + +gap> GraphvizSetNodeLabels(gv, ["i", "ii", "iii"]); + +gap> Print(String(gv)); +//dot +graph xxx { + 1 [label=i] + 2 [label=ii] + 3 [label=iii] +} +gap> GraphvizSetNodeLabels(gv, ["a", "b", "c"]); + +gap> Print(String(gv)); +//dot +graph xxx { + 1 [label=i] + 2 [label=ii] + 3 [label=iii] +} +gap> GraphvizSetNodeLabels(gv, ["i", "ii"]); +Error, the 2nd argument (list of node labels) has incorrect length, expected 3\ +, but found 2 +gap> GraphvizSetNodeLabels(gv, ["i", "ii", "iii", "iv"]); +Error, the 2nd argument (list of node labels) has incorrect length, expected 3\ +, but found 4 + +# Test GraphvizSetNodeColors +gap> gv := GraphvizGraph("xxx"); + +gap> GraphvizAddNode(gv, 1); + +gap> GraphvizAddNode(gv, 2); + +gap> GraphvizAddNode(gv, 3); + +gap> GraphvizSetNodeColors(gv, ["i", "ii", "iii"]); +Error, invalid color "i" (list (string)), valid colors are RGB values or names\ + from the GraphViz 2.44.1 X11 Color Scheme http://graphviz.org/doc/info/colors\ +.html +gap> GraphvizSetNodeColors(gv, ["red", "green", "blue"]); + +gap> Print(String(gv)); +//dot +graph xxx { + 1 [color=red, style=filled] + 2 [color=green, style=filled] + 3 [color=blue, style=filled] +} +gap> GraphvizSetNodeColors(gv, ["red", "#00FF00", "blue"]); + +gap> Print(String(gv)); +//dot +graph xxx { + 1 [color=red, style=filled] + 2 [color=green, style=filled] + 3 [color=blue, style=filled] +} +gap> GraphvizSetNodeColors(gv, ["#FF0000", "#00FF00", "#0000FF"]); + +gap> Print(String(gv)); +//dot +graph xxx { + 1 [color=red, style=filled] + 2 [color=green, style=filled] + 3 [color=blue, style=filled] +} +gap> GraphvizSetNodeColors(gv, ["#FF0000", "#00FF00", "#0000FG"]); +Error, invalid color "#0000FG" (list (string)), valid colors are RGB values or\ + names from the GraphViz 2.44.1 X11 Color Scheme http://graphviz.org/doc/info/\ +colors.html +gap> GraphvizAddEdge(gv, "a", "b"); + +gap> GraphvizNodes(gv); +rec( 1 := , 2 := , 3 := , + a := , b := ) + +# Test attribute names with spaces (TODO are there any valid such??) +gap> gv := GraphvizGraph("xxx"); + +gap> n := GraphvizAddNode(gv, 1); + +gap> n := GraphvizSetAttr(n, "probably not ok", 1); +#I unknown attribute "probably not ok", the graphviz object may no longer be valid, it can be removed using GraphvizRemoveAttr + +gap> Print(String(gv)); +//dot +graph xxx { + 1 ["probably not ok"=1] +} +gap> GraphvizSetAttr(n, "label", "<<>>"); + +gap> Print(String(gv)); +//dot +graph xxx { + 1 ["probably not ok"=1] +} + # gap> STOP_TEST("graphviz package: dot.tst", 0); diff --git a/tst/edge.tst b/tst/edge.tst index ebd5bc3..ae47f3c 100644 --- a/tst/edge.tst +++ b/tst/edge.tst @@ -74,7 +74,8 @@ gap> GraphvizEdges(g); gap> GraphvizRemoveEdges(g, "c", "d"); -# Test adding edge between nodes which are not in the graph, but there exists nodes in the graph which share their names. +# Test adding edge between nodes which are not in the graph, but there exists +# nodes in the graph which share their names. gap> g := GraphvizGraph();; gap> g1 := GraphvizGraph();; gap> a1 := GraphvizAddNode(g, "a");; @@ -86,6 +87,8 @@ gap> e2 := GraphvizAddEdge(g, a2, c);; Error, Different node in graph with name a gap> GraphvizEdges(g); [ ] +gap> e2 := GraphvizAddEdge(g, c, a2);; +Error, Different node in graph with name a. # Test adding an edge reuses a node automatically gap> g := GraphvizGraph();; @@ -132,6 +135,8 @@ rec( color := "red", label := "1" ) gap> n["color"] := "blue";; gap> GraphvizAttrs(n); rec( color := "blue", label := "1" ) +gap> n[1]; +fail # Test getting attributes using the [] syntax gap> g := GraphvizGraph();; diff --git a/tst/graph.tst b/tst/graph.tst index f0a9124..933146d 100644 --- a/tst/graph.tst +++ b/tst/graph.tst @@ -92,6 +92,20 @@ gap> g; gap> GraphvizEdges(g); [ , ] +gap> GraphvizEdges(g, "a", "c"); +[ ] +gap> GraphvizEdges(g, "a", "b"); +[ ] +gap> GraphvizAddEdge(g, "a", "b"); + +gap> GraphvizEdges(g, "a", "b"); +[ , ] +gap> GraphvizEdges(g, "x", "b"); +Error, the 2nd argument "x" (head of an edge) is not a node of the 1st argumen\ +t (a graphviz graph or digraph) +gap> GraphvizEdges(g, "a", "y"); +Error, the 3rd argument "y" (tail of an edge) is not a node of the 1st argumen\ +t (a graphviz graph or digraph) # Test adding edge with different nodes with the same name gap> g := GraphvizGraph();; @@ -153,6 +167,8 @@ rec( c := , d := ) gap> g := GraphvizGraph();; gap> GraphvizSetName(g, "test"); +gap> GraphvizSetName(g, 1); + # Test global attributes graph gap> g := GraphvizGraph();; @@ -212,6 +228,19 @@ gap> g := GraphvizGraph();; gap> GraphvizSetAttr(g, "label", "test");; gap> GraphvizAttrs(g); [ "label=test" ] +gap> GraphvizSetAttr(g, 1, 2); +#I unknown attribute "1", the graphviz object may no longer be valid, it can be removed using GraphvizRemoveAttr + +gap> GraphvizAttrs(g); +[ "label=test", "1=2" ] +gap> GraphvizRemoveAttr(g, "1=2"); + +gap> GraphvizAttrs(g); +[ "label=test", "1=2" ] +gap> GraphvizRemoveAttr(g, "1"); + +gap> GraphvizAttrs(g); +[ "label=test", "1=2" ] # Test set color (graph) gap> g := GraphvizGraph();; diff --git a/tst/node.tst b/tst/node.tst index 0555e43..8d6ebab 100644 --- a/tst/node.tst +++ b/tst/node.tst @@ -59,10 +59,20 @@ gap> String(g); # Test non-string name containing ':' gap> g := GraphvizGraph();; -gap> GraphvizAddNode(g, 111); +gap> n := GraphvizAddNode(g, 111); gap> String(g); "//dot\ngraph {\n\t111\n}\n" +gap> n[1]; +fail +gap> n[1] := 2; +2 +gap> n[1]; +"2" +gap> GraphvizRemoveAttr(n, 1); + +gap> n[1]; +fail # Test removing a node with a non-string name gap> g := GraphvizGraph();; diff --git a/tst/subgraph.tst b/tst/subgraph.tst index fb1c907..005e216 100644 --- a/tst/subgraph.tst +++ b/tst/subgraph.tst @@ -8,8 +8,8 @@ ############################################################################# ## -#@local a, a1, a2, a3, b, b1, b2, b3, c, child, ctx, g, main, n, o, parent, s -#@local s1, s11, s2, sibling +#@local a, a1, a2, a3, b, b1, b2, b3, c, child, ctx, g, gv, legend, main, n, o +#@local parent, s, s1, s11, s2, sibling gap> START_TEST("graphviz package: subgraph.tst"); gap> LoadPackage("graphviz", false);; @@ -34,6 +34,9 @@ gap> GraphvizAddSubgraph(g); gap> g := GraphvizGraph();; gap> GraphvizAddContext(g); +gap> GraphvizAddContext(g, "no_name_1"); +Error, the 1st argument (a graphviz (di)graph/context) already has a context o\ +r subgraph with name "no_name_1" # Test no-name constructor graphs' names increment gap> g := GraphvizGraph();; @@ -254,8 +257,8 @@ edge [label=testing123] node[color=blue] edge[color=blue] \n\n}\n" gap> g := GraphvizDigraph();; gap> s1 := GraphvizAddSubgraph(g, "a");; gap> s2 := GraphvizAddSubgraph(g, "a"); -Error, the 1st argument (a graphviz (di)graph) already has a subgraph with na\ -me "a" +Error, the 1st argument (a graphviz (di)graph/context) already has a subgraph \ +with name "a" # Test getting subgraphs by name gap> g := GraphvizDigraph();; @@ -382,5 +385,27 @@ gap> o := GraphvizFindSubgraphRecursive(g, 1); gap> IsIdenticalObj(o, s); true +# Test a context containing a subgraph +gap> gv := GraphvizGraph("context+subgraph");; +gap> GraphvizSetAttr(gv, "node [shape=\"box\"]"); + +gap> legend := GraphvizAddContext(gv, "legend"); + +gap> GraphvizSetAttr(legend, "node [shape=plaintext]"); + +gap> GraphvizAddSubgraph(legend, "legend"); + + +# Test a context containing a subdigraph +gap> gv := GraphvizDigraph("context+subgraph");; +gap> GraphvizSetAttr(gv, "node [shape=\"box\"]"); + +gap> legend := GraphvizAddContext(gv, "legend"); + +gap> GraphvizSetAttr(legend, "node [shape=plaintext]"); + +gap> GraphvizAddSubgraph(legend, "legend"); + + # gap> STOP_TEST("graphviz package: subgraph.tst", 0); From 737a67fcb24d12ea54ba09d8dfa8f70689e59a8c Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 10:57:31 +0100 Subject: [PATCH 26/38] Revert "Rename AsString -> String" This reverts commit 7f4951699d0953569f24b9c8d42a866f5d543fc4. --- gap/dot.gd | 2 +- gap/dot.gi | 6 ++++- gap/gv.gd | 2 +- tst/dot.tst | 48 ++++++++++++++++----------------- tst/examples/angles.tst | 4 +-- tst/examples/btree.tst | 2 +- tst/examples/cluster.tst | 2 +- tst/examples/cluster_edge.tst | 2 +- tst/examples/colors.tst | 2 +- tst/examples/er.tst | 2 +- tst/examples/fsm.tst | 2 +- tst/examples/g_c_n.tst | 4 +-- tst/examples/hello.tst | 2 +- tst/examples/process.tst | 2 +- tst/examples/rank_same.tst | 2 +- tst/examples/structs.tst | 2 +- tst/examples/traffic_lights.tst | 2 +- tst/examples/unix.tst | 2 +- tst/graph.tst | 2 +- tst/node.tst | 4 +-- tst/subgraph.tst | 18 ++++++------- 21 files changed, 59 insertions(+), 55 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index 508d6da..9ef407e 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -212,7 +212,7 @@ DeclareOperation("GraphvizRemoveAttr", [IsGraphvizObject, IsObject]); #! @Section Outputting #! @Arguments graph #! @Returns the dot representation of the graphviz object. -# TODO document "String" +DeclareOperation("AsString", [IsGraphvizGraphDigraphOrContext]); #! @Arguments obj #! @Returns the graphviz representation of the object. diff --git a/gap/dot.gi b/gap/dot.gi index 0b2e2a8..db37732 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -540,7 +540,11 @@ end); # Stringify ############################################################################# -InstallMethod(String, "for a graphviz (di)graph or context", +# It might be more natural for the next method to be one for String rather than +# AsString, but unfortunately String is an attribute, which means it is +# immutable, and hence cannot be changed after it is first set. + +InstallMethod(AsString, "for a graphviz (di)graph", [IsGraphvizGraphDigraphOrContext], graph -> GV_StringifyGraph(graph, false)); # Can't do the following because it conflicts with the PrintString above, we diff --git a/gap/gv.gd b/gap/gv.gd index 6d453f5..3c977b1 100644 --- a/gap/gv.gd +++ b/gap/gv.gd @@ -38,7 +38,7 @@ DeclareOperation("GV_Context", [IsGraphvizGraphDigraphOrContext, IsString]); DeclareOperation("GV_Map", []); DeclareOperation("GV_MapNames", [GV_IsMap]); -# TODO required? Replace with String or just String? +# TODO required? Replace with AsString or just String? DeclareOperation("GV_EnsureString", [IsObject]); DeclareOperation("GV_HasNode", [IsGraphvizGraphDigraphOrContext, IsObject]); diff --git a/tst/dot.tst b/tst/dot.tst index 7d8c398..c4448d6 100644 --- a/tst/dot.tst +++ b/tst/dot.tst @@ -35,7 +35,7 @@ gap> GraphvizAttrs(g); gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "test");; gap> GraphvizSetAttrs(n, rec(color := "red", label := "lab"));; -gap> String(g); +gap> AsString(g); "//dot\ngraph {\n\ttest [color=red, label=lab]\n}\n" gap> GraphvizRemoveNode(g, "banana"); Error, the 2nd argument (node name string) "banana" is not a node of the 1st a\ @@ -49,7 +49,7 @@ gap> GraphvizSetAttrs(a, rec(color := "blue"));; gap> GraphvizSetAttrs(b, rec(color := "red"));; gap> e := GraphvizAddEdge(g, a, b);; gap> GraphvizSetAttrs(e, rec(color := "green"));; -gap> String(g); +gap> AsString(g); "//dot\ndigraph {\n\ta [color=blue]\n\tb [color=red]\n\ta -> b [color=green]\ \n}\n" @@ -61,13 +61,13 @@ gap> GraphvizSetAttrs(a, rec(color := "blue"));; gap> GraphvizSetAttrs(b, rec(color := "red"));; gap> e := GraphvizAddEdge(g, a, b);; gap> GraphvizSetAttrs(e, rec(color := "green"));; -gap> String(g); +gap> AsString(g); "//dot\ngraph {\n\ta [color=blue]\n\tb [color=red]\n\ta -- b [color=green]\n}\ \n" # Test stringify empty gap> g := GraphvizGraph();; -gap> String(g); +gap> AsString(g); "//dot\ngraph {\n}\n" # Test unknown attributes (node) @@ -87,24 +87,24 @@ gap> GraphvizSetAttr(g, "test", "false"); gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "node");; gap> GraphvizSetAttr(n, "label", ">>hello");; -gap> String(g); +gap> AsString(g); "//dot\ngraph {\n\tnode [label=\">>hello\"]\n}\n" gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "node");; gap> GraphvizSetAttr(n, "label", "before>>hello");; -gap> String(g); +gap> AsString(g); "//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> String(g); +gap> AsString(g); "//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> String(g); +gap> AsString(g); "//dot\ngraph {\n\ta\n\tb\n\ta -- b [label=\"before>>hello\"]\n}\n" # Test GraphvizSetNodeLabels @@ -118,7 +118,7 @@ gap> GraphvizAddNode(gv, 3); gap> GraphvizSetNodeLabels(gv, ["i", "ii", "iii"]); -gap> Print(String(gv)); +gap> Print(AsString(gv)); //dot graph xxx { 1 [label=i] @@ -127,12 +127,12 @@ graph xxx { } gap> GraphvizSetNodeLabels(gv, ["a", "b", "c"]); -gap> Print(String(gv)); +gap> Print(AsString(gv)); //dot graph xxx { - 1 [label=i] - 2 [label=ii] - 3 [label=iii] + 1 [label=a] + 2 [label=b] + 3 [label=c] } gap> GraphvizSetNodeLabels(gv, ["i", "ii"]); Error, the 2nd argument (list of node labels) has incorrect length, expected 3\ @@ -156,7 +156,7 @@ Error, invalid color "i" (list (string)), valid colors are RGB values or names\ .html gap> GraphvizSetNodeColors(gv, ["red", "green", "blue"]); -gap> Print(String(gv)); +gap> Print(AsString(gv)); //dot graph xxx { 1 [color=red, style=filled] @@ -165,21 +165,21 @@ graph xxx { } gap> GraphvizSetNodeColors(gv, ["red", "#00FF00", "blue"]); -gap> Print(String(gv)); +gap> Print(AsString(gv)); //dot graph xxx { 1 [color=red, style=filled] - 2 [color=green, style=filled] + 2 [color="#00FF00", style=filled] 3 [color=blue, style=filled] } gap> GraphvizSetNodeColors(gv, ["#FF0000", "#00FF00", "#0000FF"]); -gap> Print(String(gv)); +gap> Print(AsString(gv)); //dot graph xxx { - 1 [color=red, style=filled] - 2 [color=green, style=filled] - 3 [color=blue, style=filled] + 1 [color="#FF0000", style=filled] + 2 [color="#00FF00", style=filled] + 3 [color="#0000FF", style=filled] } gap> GraphvizSetNodeColors(gv, ["#FF0000", "#00FF00", "#0000FG"]); Error, invalid color "#0000FG" (list (string)), valid colors are RGB values or\ @@ -188,7 +188,7 @@ colors.html gap> GraphvizAddEdge(gv, "a", "b"); gap> GraphvizNodes(gv); -rec( 1 := , 2 := , 3 := , +rec( 1 := , 2 := , 3 := , a := , b := ) # Test attribute names with spaces (TODO are there any valid such??) @@ -199,17 +199,17 @@ gap> n := GraphvizAddNode(gv, 1); gap> n := GraphvizSetAttr(n, "probably not ok", 1); #I unknown attribute "probably not ok", the graphviz object may no longer be valid, it can be removed using GraphvizRemoveAttr -gap> Print(String(gv)); +gap> Print(AsString(gv)); //dot graph xxx { 1 ["probably not ok"=1] } gap> GraphvizSetAttr(n, "label", "<<>>"); -gap> Print(String(gv)); +gap> Print(AsString(gv)); //dot graph xxx { - 1 ["probably not ok"=1] + 1 [label=<<>>, "probably not ok"=1] } # diff --git a/tst/examples/angles.tst b/tst/examples/angles.tst index cab0d92..fc39502 100644 --- a/tst/examples/angles.tst +++ b/tst/examples/angles.tst @@ -68,7 +68,7 @@ gap> GraphvizAddEdge(g, "n5", "n14"); #@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") -gap> Print(String(g)); +gap> Print(AsString(g)); //dot digraph G { bgcolor=blue @@ -103,7 +103,7 @@ ientangle=360,label="n9:n360", fontcolor=black] label="Radial Angle Variations\ n5 -> n14 } #@else -gap> Print(String(g)); +gap> Print(AsString(g)); //dot digraph G { bgcolor=blue diff --git a/tst/examples/btree.tst b/tst/examples/btree.tst index 1e22687..555996e 100644 --- a/tst/examples/btree.tst +++ b/tst/examples/btree.tst @@ -55,7 +55,7 @@ gap> GraphvizAddEdge(s, "node4:f2", "node6:f1"); gap> GraphvizAddEdge(s, "node4:f0", "node5:f1"); -gap> String(s) = +gap> AsString(s) = > "//dot\ndigraph g {\n\tnode [shape=record, height=.1] \n\tnode0 [label=\" \ > | G|\"]\n\tnode1 [label=\" | E|\"]\n\tnode2 [label=\" \ > | B|\"]\n\tnode3 [label=\" | F|\"]\n\tnode4 [label=\" \ diff --git a/tst/examples/cluster.tst b/tst/examples/cluster.tst index 4f4ac8c..2786feb 100644 --- a/tst/examples/cluster.tst +++ b/tst/examples/cluster.tst @@ -74,7 +74,7 @@ gap> GraphvizSetAttr(graph["end"], "shape", "Msquare"); # -gap> String(graph); +gap> AsString(graph); "//dot\ndigraph G {\nsubgraph cluster_0 {\n\tcolor=\"lightgrey\" style=\"fille\ d\" node [color=\"white\", style=\"filled\"] label=\"process #1\" \n\ta0\n\ta1\ \n\ta0 -> a1\n\ta2\n\ta1 -> a2\n\ta3\n\ta2 -> a3\n}\nsubgraph cluster_1 {\n\tc\ diff --git a/tst/examples/cluster_edge.tst b/tst/examples/cluster_edge.tst index 0af6cb6..3a017fe 100644 --- a/tst/examples/cluster_edge.tst +++ b/tst/examples/cluster_edge.tst @@ -53,7 +53,7 @@ gap> GraphvizSetAttr(e, "ltail", "cluster0"); gap> GraphvizAddEdge(g, "d", "h"); -gap> String(g); +gap> AsString(g); "//dot\ndigraph G {\n\tcompound=true \nsubgraph cluster0 {\n\ta\n\tb\n\ta -> b\ \n\tc\n\ta -> c\n\td\n\tb -> d\n\tc -> d\n}\nsubgraph cluster1 {\n\te\n\tg\n\t\ e -> g\n\tf\n\te -> f\n}\n\tb -> f [lhead=cluster1]\n\td -> e\n\tc -> g [lhead\ diff --git a/tst/examples/colors.tst b/tst/examples/colors.tst index 695c008..d1f4d8c 100644 --- a/tst/examples/colors.tst +++ b/tst/examples/colors.tst @@ -54,7 +54,7 @@ gap> GraphvizSetAttr(node, "fillcolor", "deeppink"); # -gap> String(g); +gap> 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 diff --git a/tst/examples/er.tst b/tst/examples/er.tst index 41228f0..a1dcbf3 100644 --- a/tst/examples/er.tst +++ b/tst/examples/er.tst @@ -104,7 +104,7 @@ gap> GraphvizSetAttr(e, "fontsize=\"20\""); # -gap> String(e); +gap> 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 diff --git a/tst/examples/fsm.tst b/tst/examples/fsm.tst index 177b453..ad70da3 100644 --- a/tst/examples/fsm.tst +++ b/tst/examples/fsm.tst @@ -73,7 +73,7 @@ gap> GraphvizSetAttr(GraphvizAddEdge(nodes, "LR_8", "LR_5"), "label", "\"S(a)\"" # -gap> String(f); +gap> AsString(f); "//dot\ndigraph finite_state_machine {\n\trankdir=LR size=\"8,5\" \n// termina\ ls context \n\tnode [shape=doublecircle] \n\tLR_0\n\tLR_3\n\tLR_4\n\tLR_8\n\tr\ ankdir=LR size=\"8,5\" \n\n// nodes context \n\tnode [shape=circle] \n\tLR_2\n\ diff --git a/tst/examples/g_c_n.tst b/tst/examples/g_c_n.tst index beea2f2..f38f5b7 100644 --- a/tst/examples/g_c_n.tst +++ b/tst/examples/g_c_n.tst @@ -36,7 +36,7 @@ gap> GraphvizAddNode(cluster1, "anode"); #@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") -gap> Print(String(g)); +gap> Print(AsString(g)); //dot graph G { bgcolor="purple:pink" label="agraph" fontcolor="white" @@ -48,7 +48,7 @@ ntangle=270 } } #@else -gap> Print(String(g)); +gap> Print(AsString(g)); //dot graph G { bgcolor="purple:pink" label="agraph" fontcolor="white" diff --git a/tst/examples/hello.tst b/tst/examples/hello.tst index 8d4cc54..d9af8ae 100644 --- a/tst/examples/hello.tst +++ b/tst/examples/hello.tst @@ -20,7 +20,7 @@ gap> graph := GraphvizDigraph("G"); gap> GraphvizAddEdge(graph, "hello", "world"); -gap> String(graph); +gap> AsString(graph); "//dot\ndigraph G {\n\thello\n\tworld\n\thello -> world\n}\n" # diff --git a/tst/examples/process.tst b/tst/examples/process.tst index 44b2f11..9b922b8 100644 --- a/tst/examples/process.tst +++ b/tst/examples/process.tst @@ -47,7 +47,7 @@ gap> GraphvizAddEdge(graph, "runswap", "runmem"); gap> GraphvizAddEdge(graph, "new", "runmem"); -gap> String(graph); +gap> AsString(graph); "//dot\ngraph G {\n\tengine=\"sfdp\" \n\trun\n\tintr\n\trun -- intr\n\trunbl\n\ \tintr -- runbl\n\trunbl -- run\n\tkernel\n\trun -- kernel\n\tzombie\n\tkernel\ -- zombie\n\tsleep\n\tkernel -- sleep\n\trunmem\n\tkernel -- runmem\n\tswap\n\ diff --git a/tst/examples/rank_same.tst b/tst/examples/rank_same.tst index df7355d..685dee2 100644 --- a/tst/examples/rank_same.tst +++ b/tst/examples/rank_same.tst @@ -58,7 +58,7 @@ gap> GraphvizAddEdge(g, "X", "Y"); # -gap> String(g); +gap> AsString(g); "//dot\ndigraph {\nsubgraph no_name_1 {\n\trank=same \n\tA\n\tX\n}\n\tC\nsubg\ raph no_name_3 {\n\trank=same \n\tB\n\tD\n\tY\n}\n\tA -> B\n\tA -> C\n\tC -> D\ \n\tX -> Y\n}\n" diff --git a/tst/examples/structs.tst b/tst/examples/structs.tst index f10bd74..2068f9f 100644 --- a/tst/examples/structs.tst +++ b/tst/examples/structs.tst @@ -63,7 +63,7 @@ gap> GraphvizAddEdge(s, "struct1:f2", "struct3:here"); # -gap> String(s); +gap> AsString(s); "//dot\ndigraph structs {\n\tnode [shape=\"plaintext\"] \n\tstruct1 [label=<\n\nleft\nmiddleright\n\n>]\n\tstru\ diff --git a/tst/examples/traffic_lights.tst b/tst/examples/traffic_lights.tst index 5654ab7..295ac0f 100644 --- a/tst/examples/traffic_lights.tst +++ b/tst/examples/traffic_lights.tst @@ -79,7 +79,7 @@ gap> GraphvizSetAttr(t, "fontsize=12"); # -gap> String(t); +gap> AsString(t); "//dot\ndigraph TrafficLights {\n\tengine=neato overlap=\"false\" label=\"Petr\ iNet Model TrafficLights\nExtracted from ConceptBase and laid out by Graphviz\ \"\n fontsize=12 \nsubgraph ctx1 {\n\tnode [shape=\"box\"] \n\tgy2\n\tyr2\n\tr\ diff --git a/tst/examples/unix.tst b/tst/examples/unix.tst index e63d3f2..5207345 100644 --- a/tst/examples/unix.tst +++ b/tst/examples/unix.tst @@ -124,7 +124,7 @@ gap> GraphvizAddEdge(u, "System V.2", "System V.3"); # -gap> String(u) = +gap> AsString(u) = > "//dot\ndigraph unix {\n\tnode [color=\"lightblue2\", style=\"filled\", size=\ > \"6,6\"] \n\t\"5th Edition\"\n\t\"6th Edition\"\n\t\"5th Edition\" -> \"6th Ed\ > ition\"\n\t\"PWB 1.0\"\n\t\"5th Edition\" -> \"PWB 1.0\"\n\tLSX\n\t\"6th Editi\ diff --git a/tst/graph.tst b/tst/graph.tst index 933146d..5c90819 100644 --- a/tst/graph.tst +++ b/tst/graph.tst @@ -192,7 +192,7 @@ gap> GraphvizAttrs(g); gap> g := GraphvizGraph();; gap> GraphvizSetAttr(g, "color", "red");; gap> GraphvizSetAttr(g, "color", "blue");; -gap> String(g); +gap> AsString(g); "//dot\ngraph {\n\tcolor=red color=blue \n}\n" # # Test removing attributes from a graph TODO uncomment or delete diff --git a/tst/node.tst b/tst/node.tst index 8d6ebab..c83d575 100644 --- a/tst/node.tst +++ b/tst/node.tst @@ -54,14 +54,14 @@ rec( shape := "circle" ) # Test name containing ':' gap> g := GraphvizGraph();; gap> GraphvizAddNode(g, "test:colon");; -gap> String(g); +gap> AsString(g); "//dot\ngraph {\n\ttest:colon\n}\n" # Test non-string name containing ':' gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, 111); -gap> String(g); +gap> AsString(g); "//dot\ngraph {\n\t111\n}\n" gap> n[1]; fail diff --git a/tst/subgraph.tst b/tst/subgraph.tst index 005e216..45adb25 100644 --- a/tst/subgraph.tst +++ b/tst/subgraph.tst @@ -138,7 +138,7 @@ gap> GraphvizAddEdge(g, "x", "y");; gap> GraphvizSetAttr(s, "color", "red");; gap> GraphvizSetAttr(s, "node [color=red]");; gap> GraphvizSetAttr(s, "edge [color=red]");; -gap> String(g); +gap> AsString(g); "//dot\ndigraph {\nsubgraph a {\n\tcolor=red node [color=red] edge [color=red\ ] \n}\n\tx\n\ty\n\tx -> y\n}\n" @@ -149,7 +149,7 @@ gap> GraphvizAddEdge(g, "x", "y");; gap> GraphvizSetAttr(s, "color", "red");; gap> GraphvizSetAttr(s, "node [color=red]");; gap> GraphvizSetAttr(s, "edge [color=red]");; -gap> String(g); +gap> AsString(g); "//dot\ngraph {\nsubgraph a {\n\tcolor=red node [color=red] edge [color=red] \ \n}\n\tx\n\ty\n\tx -- y\n}\n" @@ -160,7 +160,7 @@ gap> GraphvizAddEdge(g, "x", "y");; gap> GraphvizSetAttr(s, "color", "red");; gap> GraphvizSetAttr(s, "node [color=red]");; gap> GraphvizSetAttr(s, "edge [color=red]");; -gap> String(g); +gap> AsString(g); "//dot\ngraph {\n// a context \n\tcolor=red node [color=red] edge [color=red]\ \n\n\tx\n\ty\n\tx -- y\n}\n" @@ -171,14 +171,14 @@ gap> GraphvizAddEdge(g, "x", "y");; gap> GraphvizSetAttr(s, "color", "red");; gap> GraphvizSetAttr(s, "node [color=red]");; gap> GraphvizSetAttr(s, "edge [color=red]");; -gap> String(g); +gap> AsString(g); "//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> String(g); +gap> AsString(g); "//dot\ndigraph {\nsubgraph no_name_1 {\n}\n}\n" # finding a node in a sibling graph @@ -248,7 +248,7 @@ gap> GraphvizSetAttr(g, "node[color=blue]");; gap> GraphvizSetAttr(g, "edge[color=blue]");; gap> GraphvizSetAttr(ctx, "node[color=red]");; gap> GraphvizAddNode(ctx, "a");; -gap> String(g); +gap> AsString(g); "//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" @@ -295,7 +295,7 @@ gap> GraphvizSubgraphs(s1)["c"]; gap> g := GraphvizGraph();; gap> s1 := GraphvizAddSubgraph(g, "a");; gap> s2 := GraphvizAddSubgraph(s1, "c");; -gap> String(g); +gap> AsString(g); "//dot\ngraph {\nsubgraph a {\nsubgraph c {\n}\n}\n}\n" # Test subgraphs with non-string names @@ -364,7 +364,7 @@ gap> g := GraphvizGraph("g");; gap> parent := GraphvizAddContext(g, "parent");; gap> ctx := GraphvizAddContext(parent, "ctx");; gap> GraphvizAddEdge(ctx, "a", "b");; -gap> String(g); +gap> AsString(g); "//dot\ngraph g {\n// parent context \n// ctx context \n\ta\n\tb\n\ta -- b\n\n\ \n}\n" @@ -373,7 +373,7 @@ gap> g := GraphvizDigraph("g");; gap> parent := GraphvizAddContext(g, "parent");; gap> ctx := GraphvizAddContext(parent, "ctx");; gap> GraphvizAddEdge(ctx, "a", "b");; -gap> String(g); +gap> AsString(g); "//dot\ndigraph g {\n// parent context \n// ctx context \n\ta\n\tb\n\ta -> b\n\ \n\n}\n" From 7c412f3107310798b757d6fa3fad1adce4a4bdde Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 11:11:27 +0100 Subject: [PATCH 27/38] More test for code coverage and remove some unreachable code --- gap/gv.gi | 26 +++++++++++++------------- tst/dot.tst | 3 +++ tst/subgraph.tst | 11 +++++++++++ 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/gap/gv.gi b/gap/gv.gi index 2a697c0..27650e9 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -525,9 +525,13 @@ function(attrs) if "label" = key and StartsWith(tmp, "<<") and EndsWith(tmp, ">>") then val := StringFormatted("{}", val); else - if ' ' in key then - key := StringFormatted("\"{}\"", key); - fi; + # TODO it doesn't seem to be possible to enter the if-statement + # below, even with examples where the key contains spaces (probably + # the quotes are added somewhere else). Either uncomment or delete + # this code. + # if ' ' in key then + # key := StringFormatted("\"{}\"", key); + # fi; if ' ' in val or '>' in val or '^' in val or '#' in val then # TODO avoid code duplication here, and below val := StringFormatted("\"{}\"", val); @@ -603,10 +607,8 @@ function(graph, is_subgraph) if is_subgraph then if IsGraphvizContext(graph) then Append(result, GV_StringifyContextHead(graph)); - elif IsGraphvizGraph(graph) or IsGraphvizDigraph(graph) then - Append(result, GV_StringifySubgraphHead(graph)); else - ErrorNoReturn("Invalid subgraph type."); + Append(result, GV_StringifySubgraphHead(graph)); fi; elif IsGraphvizDigraph(graph) then Append(result, "//dot\n"); @@ -614,11 +616,11 @@ function(graph, is_subgraph) elif IsGraphvizGraph(graph) then Append(result, "//dot\n"); Append(result, GV_StringifyGraphHead(graph)); - elif IsGraphvizContext(graph) then - Append(result, "//dot\n"); - Append(result, GV_StringifyContextHead(graph)); - else - ErrorNoReturn("Invalid graph type."); + # TODO doesn't seem to be possible to reach the case below either, uncomment + # or delete + # else + # Append(result, "//dot\n"); + # Append(result, GV_StringifyContextHead(graph)); fi; Append(result, GV_StringifyGraphAttrs(graph)); @@ -635,8 +637,6 @@ function(graph, is_subgraph) else Append(result, GV_StringifyEdge(obj, "--")); fi; - else - ErrorNoReturn("Invalid graphviz object type."); fi; od; diff --git a/tst/dot.tst b/tst/dot.tst index c4448d6..781777b 100644 --- a/tst/dot.tst +++ b/tst/dot.tst @@ -185,6 +185,9 @@ gap> GraphvizSetNodeColors(gv, ["#FF0000", "#00FF00", "#0000FG"]); Error, invalid color "#0000FG" (list (string)), valid colors are RGB values or\ names from the GraphViz 2.44.1 X11 Color Scheme http://graphviz.org/doc/info/\ colors.html +gap> GraphvizSetNodeColors(gv, ["#FF0000", "#00FF00"]); +Error, the number of node colors must be the same as the number of nodes, expe\ +cted 3 but found 2 gap> GraphvizAddEdge(gv, "a", "b"); gap> GraphvizNodes(gv); diff --git a/tst/subgraph.tst b/tst/subgraph.tst index 45adb25..3610bbc 100644 --- a/tst/subgraph.tst +++ b/tst/subgraph.tst @@ -395,6 +395,17 @@ gap> GraphvizSetAttr(legend, "node [shape=plaintext]"); gap> GraphvizAddSubgraph(legend, "legend"); +gap> Print(AsString(gv)); +//dot +graph context+subgraph { + node [shape="box"] +// legend context + node [shape=plaintext] +subgraph legend { +} + node [shape="box"] + +} # Test a context containing a subdigraph gap> gv := GraphvizDigraph("context+subgraph");; From 6d90950e001f71a35f0bcd50613c8d14bb27a7f7 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 11:25:41 +0100 Subject: [PATCH 28/38] Correct STOP_TEST strings in tst/examples --- tst/examples/cluster.tst | 2 +- tst/examples/cluster_edge.tst | 2 +- tst/examples/colors.tst | 2 +- tst/examples/er.tst | 2 +- tst/examples/fsm.tst | 2 +- tst/examples/g_c_n.tst | 2 +- tst/examples/hello.tst | 2 +- tst/examples/process.tst | 2 +- tst/examples/rank_same.tst | 2 +- tst/examples/structs.tst | 2 +- tst/examples/traffic_lights.tst | 2 +- tst/examples/unix.tst | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tst/examples/cluster.tst b/tst/examples/cluster.tst index 2786feb..fc03e78 100644 --- a/tst/examples/cluster.tst +++ b/tst/examples/cluster.tst @@ -84,4 +84,4 @@ t -> a0\n\tstart -> b0\n\ta1 -> b3\n\tb2 -> a3\n\ta3 -> a0\n\tend [shape=Msqua\ re]\n\ta3 -> end\n\tb3 -> end\n}\n" # -gap> STOP_TEST("graphviz package: cluster.tst"); +gap> STOP_TEST("graphviz package: examples/cluster.tst"); diff --git a/tst/examples/cluster_edge.tst b/tst/examples/cluster_edge.tst index 3a017fe..a3f9461 100644 --- a/tst/examples/cluster_edge.tst +++ b/tst/examples/cluster_edge.tst @@ -60,4 +60,4 @@ e -> g\n\tf\n\te -> f\n}\n\tb -> f [lhead=cluster1]\n\td -> e\n\tc -> g [lhead\ =cluster1, ltail=cluster0]\n\tc -> e [ltail=cluster0]\n\th\n\td -> h\n}\n" # -gap> STOP_TEST("graphviz package: cluster_edge.tst"); +gap> STOP_TEST("graphviz package: examples/cluster_edge.tst"); diff --git a/tst/examples/colors.tst b/tst/examples/colors.tst index d1f4d8c..71eb3f7 100644 --- a/tst/examples/colors.tst +++ b/tst/examples/colors.tst @@ -65,4 +65,4 @@ gap> AsString(g); deeppink\" [fillcolor=deeppink, style=filled]\n}\n" # -gap> STOP_TEST("graphviz package: colors.tst"); +gap> STOP_TEST("graphviz package: examples/colors.tst"); diff --git a/tst/examples/er.tst b/tst/examples/er.tst index a1dcbf3..94ffc72 100644 --- a/tst/examples/er.tst +++ b/tst/examples/er.tst @@ -131,4 +131,4 @@ t\n\t\"S-C\" -- student [label=m, len=1.00]\n\tcourse -- \"S-C\" [label=n, len\ =1.00]\n}\n" # -gap> STOP_TEST("graphviz package: er.tst"); +gap> STOP_TEST("graphviz package: examples/er.tst"); diff --git a/tst/examples/fsm.tst b/tst/examples/fsm.tst index ad70da3..6e8f291 100644 --- a/tst/examples/fsm.tst +++ b/tst/examples/fsm.tst @@ -86,4 +86,4 @@ LR_5\n\tLR_2 -> LR_5 [label=\"SS(a)\"]\n\tLR_2 -> LR_4 [label=\"S(A)\"]\n\tLR_\ \tLR_8 -> LR_5 [label=\"S(a)\"]\n\trankdir=LR size=\"8,5\" \n\n}\n" # -gap> STOP_TEST("graphviz package: fsm.tst"); +gap> STOP_TEST("graphviz package: examples/fsm.tst"); diff --git a/tst/examples/g_c_n.tst b/tst/examples/g_c_n.tst index f38f5b7..58261ae 100644 --- a/tst/examples/g_c_n.tst +++ b/tst/examples/g_c_n.tst @@ -63,4 +63,4 @@ tangle=270 #@fi # -gap> STOP_TEST("graphviz package: g_c_n.tst"); +gap> STOP_TEST("graphviz package: examples/g_c_n.tst"); diff --git a/tst/examples/hello.tst b/tst/examples/hello.tst index d9af8ae..9c4ae17 100644 --- a/tst/examples/hello.tst +++ b/tst/examples/hello.tst @@ -24,4 +24,4 @@ gap> AsString(graph); "//dot\ndigraph G {\n\thello\n\tworld\n\thello -> world\n}\n" # -gap> STOP_TEST("graphviz package: hello.tst"); +gap> STOP_TEST("graphviz package: examples/hello.tst"); diff --git a/tst/examples/process.tst b/tst/examples/process.tst index 9b922b8..75e9c20 100644 --- a/tst/examples/process.tst +++ b/tst/examples/process.tst @@ -55,4 +55,4 @@ gap> AsString(graph); wap -- runmem\n\tnew -- runmem\n}\n" # -gap> STOP_TEST("graphviz package: process.tst"); +gap> STOP_TEST("graphviz package: examples/process.tst"); diff --git a/tst/examples/rank_same.tst b/tst/examples/rank_same.tst index 685dee2..5417cd5 100644 --- a/tst/examples/rank_same.tst +++ b/tst/examples/rank_same.tst @@ -64,4 +64,4 @@ raph no_name_3 {\n\trank=same \n\tB\n\tD\n\tY\n}\n\tA -> B\n\tA -> C\n\tC -> D\ \n\tX -> Y\n}\n" # -gap> STOP_TEST("graphviz package: rank_same.tst"); +gap> STOP_TEST("graphviz package: examples/rank_same.tst"); diff --git a/tst/examples/structs.tst b/tst/examples/structs.tst index 2068f9f..2e4d14c 100644 --- a/tst/examples/structs.tst +++ b/tst/examples/structs.tst @@ -77,4 +77,4 @@ re\">d\ne\n\n\nf\n\n struct3:here\n}\n" # -gap> STOP_TEST("graphviz package: structs.tst"); +gap> STOP_TEST("graphviz package: examples/structs.tst"); diff --git a/tst/examples/traffic_lights.tst b/tst/examples/traffic_lights.tst index 295ac0f..a2b64c4 100644 --- a/tst/examples/traffic_lights.tst +++ b/tst/examples/traffic_lights.tst @@ -91,4 +91,4 @@ ze=true, width=0.9] \n\tgreen2\n\tyellow2\n\tred2\n\tsafe2\n\tgreen1\n\tyellow\ g1\n\tgreen1 -> gy1\n\tyellow1 -> yr1\n\tred1 -> rg1\n}\n" # -gap> STOP_TEST("graphviz package: traffic_lights.tst"); +gap> STOP_TEST("graphviz package: examples/traffic_lights.tst"); diff --git a/tst/examples/unix.tst b/tst/examples/unix.tst index 5207345..13ea228 100644 --- a/tst/examples/unix.tst +++ b/tst/examples/unix.tst @@ -283,4 +283,4 @@ gap> AsString(u) = true # -gap> STOP_TEST("graphviz package: unix.tst"); +gap> STOP_TEST("graphviz package: examples/unix.tst"); From 8569f758b6f7f76755b6e4b336ea35d5624c0a92 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 11:31:47 +0100 Subject: [PATCH 29/38] Remove GV_EnsureString --- gap/dot.gi | 2 +- gap/gv.gd | 3 --- gap/gv.gi | 6 ------ 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/gap/dot.gi b/gap/dot.gi index db37732..3203a1b 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -181,7 +181,7 @@ end); InstallMethod(\[\]\:\=, "for a graphviz edge and an object", [IsGraphvizEdge, IsObject, IsObject], function(edge, key, val) - edge[GV_EnsureString(key)] := GV_EnsureString(val); + edge[String(key)] := String(val); end); # Accessor for graphs and digraphs diff --git a/gap/gv.gd b/gap/gv.gd index 3c977b1..65659fb 100644 --- a/gap/gv.gd +++ b/gap/gv.gd @@ -38,9 +38,6 @@ DeclareOperation("GV_Context", [IsGraphvizGraphDigraphOrContext, IsString]); DeclareOperation("GV_Map", []); DeclareOperation("GV_MapNames", [GV_IsMap]); -# TODO required? Replace with AsString or just String? -DeclareOperation("GV_EnsureString", [IsObject]); - DeclareOperation("GV_HasNode", [IsGraphvizGraphDigraphOrContext, IsObject]); DeclareOperation("GV_GetParent", [IsGraphvizGraphDigraphOrContext]); diff --git a/gap/gv.gi b/gap/gv.gi index 27650e9..c895a2c 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -268,12 +268,6 @@ InstallMethod(GV_GetCounter, "for a graphviz graph", [IsGraphvizGraphDigraphOrContext], x -> x!.Counter); -# Converting strings - -InstallMethod(GV_EnsureString, "for an object", [IsObject], String); - -InstallMethod(GV_EnsureString, "for a string", [IsString], IdFunc); - # Nodes InstallMethod(GV_HasNode, From e840460cf7cf2f09f870963d441248779d230bfc Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 11:44:22 +0100 Subject: [PATCH 30/38] Fix tests for GAP 4.11 --- tst/dot.tst | 14 ++++++++++++++ tst/graph.tst | 11 +++++++++++ tst/subgraph.tst | 14 ++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/tst/dot.tst b/tst/dot.tst index 781777b..9bffc61 100644 --- a/tst/dot.tst +++ b/tst/dot.tst @@ -150,10 +150,17 @@ gap> GraphvizAddNode(gv, 2); gap> GraphvizAddNode(gv, 3); +#@if CompareVersionNumbers(GAPInfo.Version, "4.12") gap> GraphvizSetNodeColors(gv, ["i", "ii", "iii"]); Error, invalid color "i" (list (string)), valid colors are RGB values or names\ from the GraphViz 2.44.1 X11 Color Scheme http://graphviz.org/doc/info/colors\ .html +#@else +gap> GraphvizSetNodeColors(gv, ["i", "ii", "iii"]); +Error, invalid color "i" (list (string)), valid colors are RGB values or names\ + from the GraphViz 2.44.1 X11 Color Sch\ +eme http://graphviz.org/doc/info/colors.html +#@fi gap> GraphvizSetNodeColors(gv, ["red", "green", "blue"]); gap> Print(AsString(gv)); @@ -181,10 +188,17 @@ graph xxx { 2 [color="#00FF00", style=filled] 3 [color="#0000FF", style=filled] } +#@if CompareVersionNumbers(GAPInfo.Version, "4.12") gap> GraphvizSetNodeColors(gv, ["#FF0000", "#00FF00", "#0000FG"]); Error, invalid color "#0000FG" (list (string)), valid colors are RGB values or\ names from the GraphViz 2.44.1 X11 Color Scheme http://graphviz.org/doc/info/\ colors.html +#@else +gap> GraphvizSetNodeColors(gv, ["#FF0000", "#00FF00", "#0000FG"]); +Error, invalid color "#0000FG" (list (string)), valid colors are RGB values or\ + names from the GraphViz 2.44.1 X11 Color Sch\ +eme http://graphviz.org/doc/info/colors.html +#@fi gap> GraphvizSetNodeColors(gv, ["#FF0000", "#00FF00"]); Error, the number of node colors must be the same as the number of nodes, expe\ cted 3 but found 2 diff --git a/tst/graph.tst b/tst/graph.tst index 5c90819..7fd2b95 100644 --- a/tst/graph.tst +++ b/tst/graph.tst @@ -100,12 +100,23 @@ gap> GraphvizAddEdge(g, "a", "b"); gap> GraphvizEdges(g, "a", "b"); [ , ] +#@if CompareVersionNumbers(GAPInfo.Version, "4.12") gap> GraphvizEdges(g, "x", "b"); Error, the 2nd argument "x" (head of an edge) is not a node of the 1st argumen\ t (a graphviz graph or digraph) gap> GraphvizEdges(g, "a", "y"); Error, the 3rd argument "y" (tail of an edge) is not a node of the 1st argumen\ t (a graphviz graph or digraph) +#@else +gap> GraphvizEdges(g, "x", "b"); +Error, the 2nd argument "x" (head of an edge) is not a node of the 1st argumen\ +t (a graphviz graph or dig\ +raph) +gap> GraphvizEdges(g, "a", "y"); +Error, the 3rd argument "y" (tail of an edge) is not a node of the 1st argumen\ +t (a graphviz graph or dig\ +raph) +#@fi # Test adding edge with different nodes with the same name gap> g := GraphvizGraph();; diff --git a/tst/subgraph.tst b/tst/subgraph.tst index 3610bbc..462abab 100644 --- a/tst/subgraph.tst +++ b/tst/subgraph.tst @@ -34,9 +34,16 @@ gap> GraphvizAddSubgraph(g); gap> g := GraphvizGraph();; gap> GraphvizAddContext(g); +#@if CompareVersionNumbers(GAPInfo.Version, "4.12") gap> GraphvizAddContext(g, "no_name_1"); Error, the 1st argument (a graphviz (di)graph/context) already has a context o\ r subgraph with name "no_name_1" +#@else +gap> GraphvizAddContext(g, "no_name_1"); +Error, the 1st argument (a graphviz (di)graph/context) already has a context o\ +r subgr\ +aph with name "no_name_1" +#@fi # Test no-name constructor graphs' names increment gap> g := GraphvizGraph();; @@ -256,9 +263,16 @@ edge [label=testing123] node[color=blue] edge[color=blue] \n\n}\n" # Test adding subgraphs with the same name gap> g := GraphvizDigraph();; gap> s1 := GraphvizAddSubgraph(g, "a");; +#@if CompareVersionNumbers(GAPInfo.Version, "4.12") gap> s2 := GraphvizAddSubgraph(g, "a"); Error, the 1st argument (a graphviz (di)graph/context) already has a subgraph \ with name "a" +#@else +gap> s2 := GraphvizAddSubgraph(g, "a"); +Error, the 1st argument (a graphviz (di)graph/context) already has a subgraph \ +with na\ +me "a" +#@fi # Test getting subgraphs by name gap> g := GraphvizDigraph();; From b78eea94084ce541218753b8f744a79070464577 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 11:48:39 +0100 Subject: [PATCH 31/38] Remove InstallOtherMethod from gv.gi --- gap/gv.gd | 4 ++++ gap/gv.gi | 12 ++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/gap/gv.gd b/gap/gv.gd index 65659fb..3193736 100644 --- a/gap/gv.gd +++ b/gap/gv.gd @@ -15,6 +15,10 @@ DeclareOperation("GV_GetCounter", [IsGraphvizGraphDigraphOrContext]); DeclareOperation("GV_IncCounter", [IsGraphvizGraphDigraphOrContext]); DeclareCategory("GV_IsMap", IsObject); DeclareAttribute("Size", GV_IsMap); +DeclareOperation("\[\]", [GV_IsMap, IsObject]); +DeclareOperation("\[\]:=", [GV_IsMap, IsObject, IsObject]); +DeclareOperation("Unbind\[\]", [GV_IsMap, IsObject]); +DeclareOperation("IsBound\[\]", [GV_IsMap, IsObject]); DeclareOperation("GV_StringifyGraphHead", [IsGraphvizGraphDigraphOrContext]); DeclareOperation("GV_StringifyDigraphHead", [IsGraphvizGraphDigraphOrContext]); diff --git a/gap/gv.gi b/gap/gv.gi index c895a2c..63e77ac 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -210,8 +210,8 @@ end); # Graphviz Map Functions ############################################################ -InstallOtherMethod(\[\], -"for a graphviz map and an object", +InstallMethod(\[\], +"for a graphviz map and a string", [GV_IsMap, IsString], function(m, o) if IsBound(m[o]) then @@ -220,26 +220,26 @@ function(m, o) return fail; end); -InstallOtherMethod(\[\], +InstallMethod(\[\], "for a graphviz map and an object", [GV_IsMap, IsObject], {m, o} -> m[String(o)]); -InstallOtherMethod(\[\]\:\=, +InstallMethod(\[\]\:\=, "for a graphviz map and two objects", [GV_IsMap, IsObject, IsObject], function(m, key, val) m!.Data.(key) := val; end); -InstallOtherMethod(Unbind\[\], +InstallMethod(Unbind\[\], "for a graphviz map and an object", [GV_IsMap, IsObject], function(m, key) Unbind(m!.Data.(key)); end); -InstallOtherMethod(IsBound\[\], +InstallMethod(IsBound\[\], "for a graphviz map and an object", [GV_IsMap, IsObject], {m, key} -> IsBound(m!.Data.(key))); From 0cee7841d65cbf1f242c9adc8ee1a924bff84bac Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 11:49:00 +0100 Subject: [PATCH 32/38] Conditionally install GV_Pluralize --- gap/gv.gi | 161 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 84 insertions(+), 77 deletions(-) diff --git a/gap/gv.gi b/gap/gv.gi index 63e77ac..a328982 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -8,86 +8,93 @@ ############################################################################# ## -# code from the GAP standard library -InstallMethod(GV_Pluralize, -"for an integer and a string", -[IsInt, IsString], -function(args...) - local nargs, i, count, include_num, str, len, out; - - nargs := Length(args); - if nargs >= 1 and IsInt(args[1]) and args[1] >= 0 then - i := 2; - count := args[1]; - include_num := true; - else - i := 1; - include_num := false; # if not given, assume pluralization is wanted. - fi; +# Code from the GAP standard library, repeated here so that the package works +# with GAP 4.11 since Pluralize was introduced to the GAP library in 4.12 +if CompareVersionNumbers(GAPInfo.Version, "4.12") then + InstallMethod(GV_Pluralize, + "for an integer and a string", + [IsInt, IsString], Pluralize); +else + InstallMethod(GV_Pluralize, + "for an integer and a string", + [IsInt, IsString], + function(args...) + local nargs, i, count, include_num, str, len, out; + + nargs := Length(args); + if nargs >= 1 and IsInt(args[1]) and args[1] >= 0 then + i := 2; + count := args[1]; + include_num := true; + else + i := 1; + include_num := false; # if not given, assume pluralization is wanted. + fi; - if not (nargs in [i, i + 1] and - IsString(args[i]) and - (nargs = i or IsString(args[i + 1]))) then - ErrorNoReturn("Usage: GV_Pluralize([, ][, ])"); - fi; + if not (nargs in [i, i + 1] and + IsString(args[i]) and + (nargs = i or IsString(args[i + 1]))) then + ErrorNoReturn("Usage: GV_Pluralize([, ][, ])"); + fi; - str := args[i]; - len := Length(str); - - if len = 0 then - ErrorNoReturn("the argument must be a non-empty string"); - elif include_num and count = 1 then # no pluralization needed - return Concatenation("\>1\< ", str); - elif nargs = i + 1 then # pluralization given - out := args[i + 1]; - elif len <= 2 then - out := Concatenation(str, "s"); - - # Guess and return the plural form of . - # Inspired by the "Ruby on Rails" inflection rules. - - # Uncountable nouns - elif str in ["equipment", "information"] then - out := str; - - # Irregular plurals - elif str = "axis" then - out := "axes"; - elif str = "child" then - out := "children"; - elif str = "person" then - out := "people"; - - # Peculiar endings - elif EndsWith(str, "ix") or EndsWith(str, "ex") then - out := Concatenation(str{[1 .. len - 2]}, "ices"); - elif EndsWith(str, "x") then - out := Concatenation(str, "es"); - elif EndsWith(str, "tum") or EndsWith(str, "ium") then - out := Concatenation(str{[1 .. len - 2]}, "a"); - elif EndsWith(str, "sis") then - out := Concatenation(str{[1 .. len - 3]}, "ses"); - elif EndsWith(str, "fe") and not EndsWith(str, "ffe") then - out := Concatenation(str{[1 .. len - 2]}, "ves"); - elif EndsWith(str, "lf") or EndsWith(str, "rf") or EndsWith(str, "loaf") then - out := Concatenation(str{[1 .. len - 1]}, "ves"); - elif EndsWith(str, "y") and not str[len - 1] in "aeiouy" then - out := Concatenation(str{[1 .. len - 1]}, "ies"); - elif str{[len - 1, len]} in ["ch", "ss", "sh"] then - out := Concatenation(str, "es"); - elif EndsWith(str, "s") then - out := str; - - # Default to appending 's' - else - out := Concatenation(str, "s"); - fi; + str := args[i]; + len := Length(str); + + if len = 0 then + ErrorNoReturn("the argument must be a non-empty string"); + elif include_num and count = 1 then # no pluralization needed + return Concatenation("\>1\< ", str); + elif nargs = i + 1 then # pluralization given + out := args[i + 1]; + elif len <= 2 then + out := Concatenation(str, "s"); + + # Guess and return the plural form of . + # Inspired by the "Ruby on Rails" inflection rules. + + # Uncountable nouns + elif str in ["equipment", "information"] then + out := str; + + # Irregular plurals + elif str = "axis" then + out := "axes"; + elif str = "child" then + out := "children"; + elif str = "person" then + out := "people"; + + # Peculiar endings + elif EndsWith(str, "ix") or EndsWith(str, "ex") then + out := Concatenation(str{[1 .. len - 2]}, "ices"); + elif EndsWith(str, "x") then + out := Concatenation(str, "es"); + elif EndsWith(str, "tum") or EndsWith(str, "ium") then + out := Concatenation(str{[1 .. len - 2]}, "a"); + elif EndsWith(str, "sis") then + out := Concatenation(str{[1 .. len - 3]}, "ses"); + elif EndsWith(str, "fe") and not EndsWith(str, "ffe") then + out := Concatenation(str{[1 .. len - 2]}, "ves"); + elif EndsWith(str, "lf") or EndsWith(str, "rf") or EndsWith(str, "loaf") then + out := Concatenation(str{[1 .. len - 1]}, "ves"); + elif EndsWith(str, "y") and not str[len - 1] in "aeiouy" then + out := Concatenation(str{[1 .. len - 1]}, "ies"); + elif str{[len - 1, len]} in ["ch", "ss", "sh"] then + out := Concatenation(str, "es"); + elif EndsWith(str, "s") then + out := str; + + # Default to appending 's' + else + out := Concatenation(str, "s"); + fi; - if include_num then - return Concatenation("\>", String(args[1]), "\< ", out); - fi; - return out; -end); + if include_num then + return Concatenation("\>", String(args[1]), "\< ", out); + fi; + return out; + end); +fi; ############################################################################### # Family + type From 994e1df8789b7a2249390cf669e1940836b06e50 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 12:04:35 +0100 Subject: [PATCH 33/38] More \= method for nodes to dot.gi Also add \= for edges --- gap/dot.gi | 8 ++++++++ gap/gv.gi | 4 ---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/gap/dot.gi b/gap/dot.gi index 3203a1b..05805ca 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -138,6 +138,11 @@ x -> x!.Tail); InstallMethod(GraphvizHead, "for a graphviz edge", [IsGraphvizEdge], x -> x!.Head); +# Operators for nodes + +InstallMethod(\=, "for graphviz nodes", +[IsGraphvizNode, IsGraphvizNode], IsIdenticalObj); + # Accessing node attributes InstallMethod(\[\], "for a graphviz node and a string", @@ -184,6 +189,9 @@ function(edge, key, val) edge[String(key)] := String(val); end); +InstallMethod(\=, "for graphviz edges", +[IsGraphvizEdge, IsGraphvizEdge], IsIdenticalObj); + # Accessor for graphs and digraphs InstallMethod(\[\], "for a graphviz (di)graph or context and string", diff --git a/gap/gv.gi b/gap/gv.gi index a328982..593a9e1 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -120,10 +120,6 @@ BindGlobal("GV_ContextType", NewType(GV_ObjectFamily, IsComponentObjectRep and IsAttributeStoringRep)); -InstallMethod(\=, "for IsGraphvizNode and IsGraphvizNode", -[IsGraphvizNode, IsGraphvizNode], -{n1, n2} -> GraphvizName(n1) = GraphvizName(n2)); - ############################################################################### # Constructors etc ############################################################################### From 07bf02fbcd7dff26456c9eb14d112de20374d0e4 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 12:05:36 +0100 Subject: [PATCH 34/38] Better error messages in gv.gi --- gap/gv.gi | 38 +++++++++++++++++++++++--------------- tst/edge.tst | 8 ++++++-- tst/subgraph.tst | 9 ++++++--- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/gap/gv.gi b/gap/gv.gi index 593a9e1..3c56d6a 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -364,15 +364,20 @@ InstallMethod(GV_AddNode, "for a graphviz graph and node", [IsGraphvizGraphDigraphOrContext, IsGraphvizNode], function(x, node) - local found, error, name, nodes; + local name, nodes, found; + name := GraphvizName(node); nodes := GraphvizNodes(x); # dont add if already node with the same name found := GV_FindGraphWithNode(x, name); if found <> fail then - error := "Already node with name {} in graph {}."; - ErrorNoReturn(StringFormatted(error, name, GraphvizName(found))); + ErrorFormatted("the 2nd argument (node) has name \"{}\"", + " but there is already a node with this name in ", + "the 1st argument (a graphviz (di)graph / context)", + " named \"{}\"", + name, + GraphvizName(x)); fi; nodes[name] := node; @@ -383,7 +388,7 @@ InstallMethod(GV_AddEdge, "for a graphviz graph and edge", [IsGraphvizGraphDigraphOrContext, IsGraphvizEdge], function(x, edge) - local head, head_name, tail_name, tail, hg, error, tg; + local head, tail, head_name, tail_name, hg, tg; head := GraphvizHead(edge); tail := GraphvizTail(edge); @@ -393,18 +398,21 @@ function(x, edge) tg := GV_FindGraphWithNode(x, tail_name); # make sure the nodes exist / are the same as existing ones - if hg <> fail and not IsIdenticalObj(head, hg[head_name]) then - # TODO improve - ErrorFormatted("Different node in graph {} with name {}", - GraphvizName(hg), - head_name); + if hg <> fail and head <> hg[head_name] then + ErrorFormatted("The 2nd argument (edge) has head node named \"{}\"", + " but there is already a node with this name in ", + "the 1st argument (a graphviz (di)graph / context)", + " named \"{}\"", + head_name, + GraphvizName(x)); fi; - if tg <> fail and not IsIdenticalObj(tail, tg[tail_name]) then - # TODO improve - error := "Different node in graph {} with name {}."; - ErrorNoReturn(StringFormatted(error, - GraphvizName(tg), - tail_name)); + if tg <> fail and tail <> tg[tail_name] then + ErrorFormatted("The 2nd argument (edge) has tail node named \"{}\"", + " but there is already a node with this name in ", + "the 1st argument (a graphviz (di)graph / context)", + " named \"{}\"", + head_name, + GraphvizName(x)); fi; Add(x!.Edges, edge); diff --git a/tst/edge.tst b/tst/edge.tst index ae47f3c..05f9f8e 100644 --- a/tst/edge.tst +++ b/tst/edge.tst @@ -84,11 +84,15 @@ 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, The 2nd argument (edge) has head node named "a" but there is already a \ +node with this name in the 1st argument (a graphviz (di)graph / context) named\ + "" gap> GraphvizEdges(g); [ ] gap> e2 := GraphvizAddEdge(g, c, a2);; -Error, Different node in graph with name a. +Error, The 2nd argument (edge) has tail node named "c" but there is already a \ +node with this name in the 1st argument (a graphviz (di)graph / context) named\ + "" # Test adding an edge reuses a node automatically gap> g := GraphvizGraph();; diff --git a/tst/subgraph.tst b/tst/subgraph.tst index 462abab..bf94d16 100644 --- a/tst/subgraph.tst +++ b/tst/subgraph.tst @@ -88,14 +88,16 @@ gap> g := GraphvizGraph("r");; gap> s := GraphvizAddSubgraph(g, "a");; gap> GraphvizAddNode(g, "n");; gap> GraphvizAddNode(s, "n"); -Error, Already node with name n in graph r. +Error, the 2nd argument (node) has name "n" but there is already a node with t\ +his name in the 1st argument (a graphviz (di)graph / context) named "a" # Test adding a node to a graph which is already in child fails (by name) gap> g := GraphvizGraph();; gap> s := GraphvizAddSubgraph(g, "a");; gap> GraphvizAddNode(s, "n");; gap> GraphvizAddNode(g, "n"); -Error, Already node with name n in graph a. +Error, the 2nd argument (node) has name "n" but there is already a node with t\ +his name in the 1st argument (a graphviz (di)graph / context) named "" # Test adding a node to a graph which is already in sibling fails (by name) gap> g := GraphvizGraph();; @@ -103,7 +105,8 @@ gap> s1 := GraphvizAddSubgraph(g, "a");; gap> s2 := GraphvizAddSubgraph(g, "b");; gap> GraphvizAddNode(s1, "n");; gap> GraphvizAddNode(s2, "n"); -Error, Already node with name n in graph a. +Error, the 2nd argument (node) has name "n" but there is already a node with t\ +his name in the 1st argument (a graphviz (di)graph / context) named "b" # Test adding edges to subgraphs gap> g := GraphvizGraph();; From de8b6ca791d3540790d449fc16f53bdd1cf71844 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 12:14:30 +0100 Subject: [PATCH 35/38] Tweak ViewString and rewrite tests --- gap/dot.gi | 6 ++- tst/dot.tst | 41 ++++++++------- tst/edge.tst | 4 +- tst/examples/angles.tst | 24 ++++----- tst/examples/btree.tst | 22 ++++---- tst/examples/cluster.tst | 24 ++++----- tst/examples/cluster_edge.tst | 8 +-- tst/examples/colors.tst | 24 ++++----- tst/examples/er.tst | 44 ++++++++-------- tst/examples/fsm.tst | 22 ++++---- tst/examples/g_c_n.tst | 12 ++--- tst/examples/hello.tst | 2 +- tst/examples/process.tst | 4 +- tst/examples/rank_same.tst | 20 +++---- tst/examples/structs.tst | 10 ++-- tst/examples/traffic_lights.tst | 18 +++---- tst/examples/unix.tst | 4 +- tst/graph.tst | 49 +++++++++--------- tst/node.tst | 10 ++-- tst/subgraph.tst | 92 ++++++++++++++++----------------- 20 files changed, 223 insertions(+), 217 deletions(-) diff --git a/gap/dot.gi b/gap/dot.gi index 05805ca..ab34369 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -49,13 +49,14 @@ InstallMethod(GraphvizDigraph, "for no args", [], {} -> GraphvizDigraph("")); ############################################################################# InstallMethod(PrintString, "for a graphviz node", [IsGraphvizNode], -n -> StringFormatted("", GraphvizName(n))); +n -> StringFormatted("", GraphvizName(n))); InstallMethod(PrintString, "for a graphviz edge", [IsGraphvizEdge], function(e) local head, tail; head := GraphvizHead(e); tail := GraphvizTail(e); + return StringFormatted("", GraphvizName(head), GraphvizName(tail)); @@ -82,11 +83,12 @@ function(g) Append(result, StringFormatted(" "" then - Append(result, StringFormatted("{} ", GraphvizName(g))); + Append(result, StringFormatted("\"{}\" ", GraphvizName(g))); fi; Append(result, StringFormatted("with {} ", GV_Pluralize(nodes, "node"))); Append(result, StringFormatted("and {}>", GV_Pluralize(edges, "edge"))); + # TODO add more info like that about number of subgraphs + contexts return result; end); diff --git a/tst/dot.tst b/tst/dot.tst index 9bffc61..f9c39e1 100644 --- a/tst/dot.tst +++ b/tst/dot.tst @@ -75,7 +75,7 @@ gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "n");; gap> GraphvizSetAttr(n, "test", "false"); #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();; @@ -109,15 +109,15 @@ gap> AsString(g); # Test GraphvizSetNodeLabels gap> gv := GraphvizGraph("xxx"); - + gap> GraphvizAddNode(gv, 1); - + gap> GraphvizAddNode(gv, 2); - + gap> GraphvizAddNode(gv, 3); - + gap> GraphvizSetNodeLabels(gv, ["i", "ii", "iii"]); - + gap> Print(AsString(gv)); //dot graph xxx { @@ -126,7 +126,7 @@ graph xxx { 3 [label=iii] } gap> GraphvizSetNodeLabels(gv, ["a", "b", "c"]); - + gap> Print(AsString(gv)); //dot graph xxx { @@ -143,13 +143,13 @@ Error, the 2nd argument (list of node labels) has incorrect length, expected 3\ # Test GraphvizSetNodeColors gap> gv := GraphvizGraph("xxx"); - + gap> GraphvizAddNode(gv, 1); - + gap> GraphvizAddNode(gv, 2); - + gap> GraphvizAddNode(gv, 3); - + #@if CompareVersionNumbers(GAPInfo.Version, "4.12") gap> GraphvizSetNodeColors(gv, ["i", "ii", "iii"]); Error, invalid color "i" (list (string)), valid colors are RGB values or names\ @@ -162,7 +162,7 @@ Error, invalid color "i" (list (string)), valid colors are RGB values or names\ eme http://graphviz.org/doc/info/colors.html #@fi gap> GraphvizSetNodeColors(gv, ["red", "green", "blue"]); - + gap> Print(AsString(gv)); //dot graph xxx { @@ -171,7 +171,7 @@ graph xxx { 3 [color=blue, style=filled] } gap> GraphvizSetNodeColors(gv, ["red", "#00FF00", "blue"]); - + gap> Print(AsString(gv)); //dot graph xxx { @@ -180,7 +180,7 @@ graph xxx { 3 [color=blue, style=filled] } gap> GraphvizSetNodeColors(gv, ["#FF0000", "#00FF00", "#0000FF"]); - + gap> Print(AsString(gv)); //dot graph xxx { @@ -205,24 +205,25 @@ cted 3 but found 2 gap> GraphvizAddEdge(gv, "a", "b"); gap> GraphvizNodes(gv); -rec( 1 := , 2 := , 3 := , - a := , b := ) +rec( 1 := , 2 := , + 3 := , a := , + b := ) # Test attribute names with spaces (TODO are there any valid such??) gap> gv := GraphvizGraph("xxx"); - + gap> n := GraphvizAddNode(gv, 1); - + gap> n := GraphvizSetAttr(n, "probably not ok", 1); #I unknown attribute "probably not ok", the graphviz object may no longer be valid, it can be removed using GraphvizRemoveAttr - + gap> Print(AsString(gv)); //dot graph xxx { 1 ["probably not ok"=1] } gap> GraphvizSetAttr(n, "label", "<<>>"); - + gap> Print(AsString(gv)); //dot graph xxx { diff --git a/tst/edge.tst b/tst/edge.tst index 05f9f8e..19afffc 100644 --- a/tst/edge.tst +++ b/tst/edge.tst @@ -24,9 +24,9 @@ gap> g := GraphvizGraph();; gap> e := GraphvizAddEdge(g, "a", "b"); gap> GraphvizHead(e); - + gap> GraphvizTail(e); - + # Test filtering edges by names (digraph) gap> g := GraphvizDigraph();; diff --git a/tst/examples/angles.tst b/tst/examples/angles.tst index fc39502..ee25a19 100644 --- a/tst/examples/angles.tst +++ b/tst/examples/angles.tst @@ -16,19 +16,19 @@ 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 ] ] @@ -41,17 +41,17 @@ gap> for pair in pairs do 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 ] ] @@ -63,7 +63,7 @@ gap> for pair in pairs do > od; gap> GraphvizSetAttr(cluster2, "label", > "Radial Angle Variations (white to black gradient)"); - + gap> GraphvizAddEdge(g, "n5", "n14"); diff --git a/tst/examples/btree.tst b/tst/examples/btree.tst index 555996e..d693e1b 100644 --- a/tst/examples/btree.tst +++ b/tst/examples/btree.tst @@ -18,27 +18,27 @@ 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"); diff --git a/tst/examples/cluster.tst b/tst/examples/cluster.tst index fc03e78..32023fa 100644 --- a/tst/examples/cluster.tst +++ b/tst/examples/cluster.tst @@ -15,17 +15,17 @@ 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"); @@ -33,15 +33,15 @@ 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"); @@ -49,7 +49,7 @@ gap> GraphvizAddEdge(cluster1, "b1", "b2"); gap> GraphvizAddEdge(cluster1, "b2", "b3"); gap> GraphvizSetAttr(cluster1, "label=\"process #2\""); - + # gap> GraphvizAddEdge(graph, "start", "a0"); @@ -69,9 +69,9 @@ gap> GraphvizAddEdge(graph, "b3", "end"); # gap> GraphvizSetAttr(graph["start"], "shape", "Mdiamond"); - + gap> GraphvizSetAttr(graph["end"], "shape", "Msquare"); - + # gap> AsString(graph); diff --git a/tst/examples/cluster_edge.tst b/tst/examples/cluster_edge.tst index a3f9461..4b4a9f2 100644 --- a/tst/examples/cluster_edge.tst +++ b/tst/examples/cluster_edge.tst @@ -18,11 +18,11 @@ 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"); @@ -32,7 +32,7 @@ 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"); diff --git a/tst/examples/colors.tst b/tst/examples/colors.tst index 71eb3f7..1c044da 100644 --- a/tst/examples/colors.tst +++ b/tst/examples/colors.tst @@ -23,35 +23,35 @@ 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> AsString(g); diff --git a/tst/examples/er.tst b/tst/examples/er.tst index 94ffc72..d48d7c0 100644 --- a/tst/examples/er.tst +++ b/tst/examples/er.tst @@ -18,52 +18,52 @@ 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"); @@ -99,9 +99,9 @@ gap> GraphvizSetAttrs(GraphvizAddEdge(e, "course", "S-C"), # gap> GraphvizSetAttr(e, "label=\"Entity Relation Diagram\ndrawn by NEATO\""); - + gap> GraphvizSetAttr(e, "fontsize=\"20\""); - + # gap> AsString(e); diff --git a/tst/examples/fsm.tst b/tst/examples/fsm.tst index 6e8f291..9310d3c 100644 --- a/tst/examples/fsm.tst +++ b/tst/examples/fsm.tst @@ -18,31 +18,31 @@ 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)\""); diff --git a/tst/examples/g_c_n.tst b/tst/examples/g_c_n.tst index 58261ae..560cb09 100644 --- a/tst/examples/g_c_n.tst +++ b/tst/examples/g_c_n.tst @@ -18,22 +18,22 @@ 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"); - + #@if CompareVersionNumbers(GAPInfo.Version, "4.12.0") gap> Print(AsString(g)); diff --git a/tst/examples/hello.tst b/tst/examples/hello.tst index 9c4ae17..a7f8f38 100644 --- a/tst/examples/hello.tst +++ b/tst/examples/hello.tst @@ -17,7 +17,7 @@ true # gap> graph := GraphvizDigraph("G"); - + gap> GraphvizAddEdge(graph, "hello", "world"); gap> AsString(graph); diff --git a/tst/examples/process.tst b/tst/examples/process.tst index 75e9c20..4a57db2 100644 --- a/tst/examples/process.tst +++ b/tst/examples/process.tst @@ -18,9 +18,9 @@ true # gap> graph := GraphvizGraph("G"); - + gap> GraphvizSetAttr(graph, "engine=\"sfdp\""); - + # gap> GraphvizAddEdge(graph, "run", "intr"); diff --git a/tst/examples/rank_same.tst b/tst/examples/rank_same.tst index 5417cd5..1e9a7f4 100644 --- a/tst/examples/rank_same.tst +++ b/tst/examples/rank_same.tst @@ -23,29 +23,29 @@ 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"); diff --git a/tst/examples/structs.tst b/tst/examples/structs.tst index 2e4d14c..8de2523 100644 --- a/tst/examples/structs.tst +++ b/tst/examples/structs.tst @@ -16,9 +16,9 @@ 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", @@ -28,7 +28,7 @@ gap> GraphvizSetAttr(GraphvizAddNode(s, "struct1"), "label", > middleright > > >"""); - + gap> GraphvizSetAttr(GraphvizAddNode(s, "struct2"), "label", > """< > @@ -36,7 +36,7 @@ gap> GraphvizSetAttr(GraphvizAddNode(s, "struct2"), "label", > > >
two
>"""); - + gap> GraphvizSetAttr(GraphvizAddNode(s, "struct3"), "label", > """< > @@ -54,7 +54,7 @@ gap> GraphvizSetAttr(GraphvizAddNode(s, "struct3"), "label", > > >
f
>"""); - + # gap> GraphvizAddEdge(s, "struct1:f1", "struct2:f0"); diff --git a/tst/examples/traffic_lights.tst b/tst/examples/traffic_lights.tst index a2b64c4..3b6259c 100644 --- a/tst/examples/traffic_lights.tst +++ b/tst/examples/traffic_lights.tst @@ -16,15 +16,15 @@ 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)); @@ -33,9 +33,9 @@ gap> for i in [2, 1] do # 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)); @@ -69,14 +69,14 @@ gap> for pair in [[2, 1], [1, 2]] do # 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> AsString(t); diff --git a/tst/examples/unix.tst b/tst/examples/unix.tst index 13ea228..833ce3d 100644 --- a/tst/examples/unix.tst +++ b/tst/examples/unix.tst @@ -18,10 +18,10 @@ true # gap> u := GraphvizDigraph("unix"); - + gap> GraphvizSetAttr( > u, "node [color=\"lightblue2\", style=\"filled\", size=\"6,6\"]"); - + # gap> GraphvizAddEdge(u, "5th Edition", "6th Edition"); diff --git a/tst/graph.tst b/tst/graph.tst index 7fd2b95..1bc010e 100644 --- a/tst/graph.tst +++ b/tst/graph.tst @@ -18,44 +18,44 @@ gap> GraphvizGraph(); # Test graph constructor gap> GraphvizGraph("test-name"); - + # Test digraph printing gap> x := GraphvizDigraph("test-name"); - + gap> x := GraphvizDigraph(); # Test adding nodes gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "n"); - + gap> g; gap> GraphvizNodes(g); -rec( n := ) +rec( n := ) gap> GraphvizAddNode(g, "x"); - + gap> g; gap> GraphvizNodes(g); -rec( n := , x := ) +rec( n := , x := ) # Test add node (name) gap> g := GraphvizGraph();; gap> GraphvizAddNode(g, "n"); - + gap> GraphvizNodes(g); -rec( n := ) +rec( n := ) gap> GraphvizAddNode(g, "x"); - + gap> GraphvizNodes(g); -rec( n := , x := ) +rec( n := , x := ) # Test has nodes gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, "n"); - + gap> GV_HasNode(g, "n"); true gap> GV_HasNode(g, "x"); @@ -124,7 +124,8 @@ gap> GraphvizAddEdge(g, "a", "b");; gap> GraphvizAddEdge(g, "a", "c"); gap> GraphvizNodes(g); -rec( a := , b := , c := ) +rec( a := , b := , + c := ) gap> GraphvizAddEdge(g, "c", "a"); gap> GraphvizAddEdge(g, "b", "d"); @@ -151,13 +152,14 @@ gap> GraphvizAddEdge(g, c, d);; gap> GraphvizRemoveNode(g, a); gap> GraphvizNodes(g); -rec( b := , c := , d := ) +rec( b := , c := , + d := ) gap> GraphvizEdges(g); [ ] gap> GraphvizRemoveNode(g, b); gap> GraphvizNodes(g); -rec( c := , d := ) +rec( c := , d := ) # Test removing node gap> g := GraphvizGraph();; @@ -166,25 +168,26 @@ gap> GraphvizAddEdge(g, "c", "d");; gap> GraphvizRemoveNode(g, "a"); gap> GraphvizNodes(g); -rec( b := , c := , d := ) +rec( b := , c := , + d := ) gap> GraphvizEdges(g); [ ] gap> GraphvizRemoveNode(g, "b"); gap> GraphvizNodes(g); -rec( c := , d := ) +rec( c := , d := ) # Test renaming graph gap> g := GraphvizGraph();; gap> GraphvizSetName(g, "test"); - + gap> GraphvizSetName(g, 1); - + # Test global attributes graph gap> g := GraphvizGraph();; gap> GraphvizSetName(g, "test"); - + # Test global attributes graph gap> g := GraphvizGraph();; @@ -223,18 +226,18 @@ gap> g := GraphvizGraph();; gap> n1 := GraphvizAddNode(g, "test");; gap> n2 := GraphvizAddNode(g, "abc");; gap> g["test"]; - + gap> g["abc"]; - + # Test getting a node with a non-string name using bracket notation gap> g := GraphvizGraph();; gap> n1 := GraphvizAddNode(g, 1);; gap> n2 := GraphvizAddNode(g, ["a"]);; gap> g[1]; - + gap> g[["a"]]; - + gap> g := GraphvizGraph();; gap> GraphvizSetAttr(g, "label", "test");; gap> GraphvizAttrs(g); diff --git a/tst/node.tst b/tst/node.tst index c83d575..cbf9313 100644 --- a/tst/node.tst +++ b/tst/node.tst @@ -14,7 +14,7 @@ gap> LoadPackage("graphviz", false);; # Test node constructor gap> GraphvizAddNode(GraphvizGraph(), "test-node"); - + # Test renaming nodes fails gap> n := GraphvizAddNode(GraphvizGraph(), "a");; @@ -24,7 +24,7 @@ Error, no 1st choice method found for `GraphvizName' on 2 arguments # Test making a node with an all whitespace name gap> n := GraphvizAddNode(GraphvizGraph(), " "); - + # Test making a node with empty name fails gap> n := GraphvizAddNode(GraphvizGraph(), ""); @@ -32,7 +32,7 @@ Error, the 2nd argument (string/node name) cannot be empty # Test whitespace in node names gap> n := GraphvizAddNode(GraphvizGraph(), "a a "); - + # Test modifying attributes gap> n := GraphvizAddNode(GraphvizGraph(), "t");; @@ -60,7 +60,7 @@ gap> AsString(g); # Test non-string name containing ':' gap> g := GraphvizGraph();; gap> n := GraphvizAddNode(g, 111); - + gap> AsString(g); "//dot\ngraph {\n\t111\n}\n" gap> n[1]; @@ -70,7 +70,7 @@ gap> n[1] := 2; gap> n[1]; "2" gap> GraphvizRemoveAttr(n, 1); - + gap> n[1]; fail diff --git a/tst/subgraph.tst b/tst/subgraph.tst index bf94d16..9545fde 100644 --- a/tst/subgraph.tst +++ b/tst/subgraph.tst @@ -16,24 +16,24 @@ gap> LoadPackage("graphviz", false);; # Test creating subgraphs (named) gap> g := GraphvizGraph();; gap> GraphvizAddSubgraph(g, "test-graph"); - + gap> g := GraphvizDigraph();; gap> GraphvizAddSubgraph(g, "test-digraph"); - + gap> g := GraphvizGraph();; gap> GraphvizAddContext(g, "test-context"); - + # Test no-name constructors gap> g := GraphvizGraph();; gap> GraphvizAddSubgraph(g); - + gap> g := GraphvizDigraph();; gap> GraphvizAddSubgraph(g); - + gap> g := GraphvizGraph();; gap> GraphvizAddContext(g); - + #@if CompareVersionNumbers(GAPInfo.Version, "4.12") gap> GraphvizAddContext(g, "no_name_1"); Error, the 1st argument (a graphviz (di)graph/context) already has a context o\ @@ -48,30 +48,30 @@ aph with name "no_name_1" # Test no-name constructor graphs' names increment gap> g := GraphvizGraph();; gap> GraphvizAddSubgraph(g); - + gap> GraphvizAddSubgraph(g); - + gap> GraphvizAddSubgraph(g); - + gap> GraphvizAddContext(g); - + # Test no-name constructor graphs' names increment (contexts) gap> g := GraphvizGraph();; gap> GraphvizAddContext(g); - + gap> GraphvizAddContext(g); - + gap> GraphvizAddContext(g); - + # Test getting subgraphs gap> g := GraphvizGraph();; gap> GraphvizAddSubgraph(g, "a");; gap> GraphvizAddContext(g, "b");; gap> GraphvizSubgraphs(g); -rec( a := , - b := ) +rec( a := , + b := ) # Test adding a node to a subgraph (does or does not add to parent???) # TODO need to nail down expected behaviour! @@ -81,7 +81,7 @@ gap> GraphvizAddNode(s, "n");; gap> GraphvizNodes(g); rec( ) gap> GraphvizNodes(s); -rec( n := ) +rec( n := ) # Test adding a node to a subgraph which is already in parent fails (by name) gap> g := GraphvizGraph("r");; @@ -197,7 +197,7 @@ gap> s1 := GraphvizAddSubgraph(g);; gap> GraphvizAddNode(s1, "a");; gap> s2 := GraphvizAddSubgraph(g);; gap> GV_FindNode(s2, "a"); - + gap> GV_FindNode(s2, "b"); fail @@ -206,7 +206,7 @@ gap> g := GraphvizDigraph();; gap> s1 := GraphvizAddSubgraph(g);; gap> GraphvizAddNode(s1, "a");; gap> GV_FindNode(g, "a"); - + gap> GV_FindNode(g, "b"); fail @@ -215,7 +215,7 @@ gap> g := GraphvizDigraph();; gap> s1 := GraphvizAddSubgraph(g);; gap> GraphvizAddNode(g, "a");; gap> GV_FindNode(s1, "a"); - + gap> GV_FindNode(s1, "b"); fail @@ -226,7 +226,7 @@ gap> s2 := GraphvizAddSubgraph(g);; gap> s11 := GraphvizAddSubgraph(s1);; gap> GraphvizAddNode(s2, "a");; gap> GV_FindNode(s11, "a"); - + gap> GV_FindNode(s11, "b"); fail @@ -243,11 +243,11 @@ gap> GraphvizRemoveNode(g, "d");; gap> GraphvizNodes(g); rec( ) gap> GraphvizNodes(parent); -rec( a := ) +rec( a := ) gap> GraphvizNodes(sibling); -rec( b := ) +rec( b := ) gap> GraphvizNodes(child); -rec( c := ) +rec( c := ) # Test context attribute resetting gap> g := GraphvizDigraph();; @@ -282,9 +282,9 @@ gap> g := GraphvizDigraph();; gap> s1 := GraphvizAddSubgraph(g, "a");; gap> s2 := GraphvizAddSubgraph(g, "b");; gap> GraphvizSubgraphs(g)["a"]; - + gap> GraphvizSubgraphs(g)["b"]; - + gap> GraphvizSubgraphs(g)["d"]; fail @@ -293,20 +293,20 @@ gap> g := GraphvizDigraph();; gap> s1 := GraphvizAddSubgraph(g, "a");; gap> s2 := GraphvizAddContext(g, "c");; gap> GraphvizSubgraphs(g)["a"]; - + gap> GraphvizSubgraphs(g)["c"]; - + # Test adding a nested subgraph gap> g := GraphvizGraph();; gap> s1 := GraphvizAddSubgraph(g, "a");; gap> s2 := GraphvizAddSubgraph(s1, "c");; gap> GraphvizSubgraphs(g)["a"]; - + gap> GraphvizSubgraphs(g)["c"]; fail gap> GraphvizSubgraphs(s1)["c"]; - + # Test displaying a nested subgraph gap> g := GraphvizGraph();; @@ -318,24 +318,24 @@ gap> AsString(g); # Test subgraphs with non-string names gap> g := GraphvizGraph();; gap> GraphvizAddSubgraph(g, 11); - + # Test contexts with non-string names gap> g := GraphvizGraph();; gap> GraphvizAddContext(g, 11); - + # Test getting subgraphs with non-string names gap> g := GraphvizGraph();; gap> GraphvizAddContext(g, ["a"]);; gap> GraphvizSubgraphs(g)[["a"]]; - + # Test finding subgraph (parent) gap> g := GraphvizGraph("a");; gap> s := GraphvizAddSubgraph(g, "b");; gap> o := GraphvizFindSubgraphRecursive(s, "a"); - + gap> IsIdenticalObj(o, g); true @@ -343,7 +343,7 @@ true gap> g := GraphvizGraph("a");; gap> s := GraphvizAddSubgraph(g, "b");; gap> o := GraphvizFindSubgraphRecursive(g, "b"); - + gap> IsIdenticalObj(o, s); true @@ -352,14 +352,14 @@ gap> g := GraphvizGraph("a");; gap> s := GraphvizAddSubgraph(g, "b");; gap> s2 := GraphvizAddSubgraph(g, "c");; gap> o := GraphvizFindSubgraphRecursive(s, "c"); - + gap> IsIdenticalObj(o, s2); true # Test finding subgraph (self) gap> g := GraphvizGraph("a");; gap> o := GraphvizFindSubgraphRecursive(g, "a"); - + gap> IsIdenticalObj(o, g); true @@ -372,7 +372,7 @@ gap> b1 := GraphvizAddSubgraph(g, "b1");; gap> b2 := GraphvizAddSubgraph(b1, "b2");; gap> b3 := GraphvizAddSubgraph(b2, "b3");; gap> o := GraphvizFindSubgraphRecursive(a3, "b3"); - + gap> IsIdenticalObj(o, b3); true @@ -398,20 +398,20 @@ gap> AsString(g); gap> g := GraphvizGraph("r");; gap> s := GraphvizAddSubgraph(g, 1);; gap> o := GraphvizFindSubgraphRecursive(g, 1); - + gap> IsIdenticalObj(o, s); true # Test a context containing a subgraph gap> gv := GraphvizGraph("context+subgraph");; gap> GraphvizSetAttr(gv, "node [shape=\"box\"]"); - + gap> legend := GraphvizAddContext(gv, "legend"); - + gap> GraphvizSetAttr(legend, "node [shape=plaintext]"); - + gap> GraphvizAddSubgraph(legend, "legend"); - + gap> Print(AsString(gv)); //dot graph context+subgraph { @@ -427,13 +427,13 @@ subgraph legend { # Test a context containing a subdigraph gap> gv := GraphvizDigraph("context+subgraph");; gap> GraphvizSetAttr(gv, "node [shape=\"box\"]"); - + gap> legend := GraphvizAddContext(gv, "legend"); - + gap> GraphvizSetAttr(legend, "node [shape=plaintext]"); - + gap> GraphvizAddSubgraph(legend, "legend"); - + # gap> STOP_TEST("graphviz package: subgraph.tst", 0); From 57f2736f3cd2df0c61f2ccff80ff4bd73d3e1aba Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 12:19:05 +0100 Subject: [PATCH 36/38] Add comment --- gap/gv.gd | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gap/gv.gd b/gap/gv.gd index 3193736..ddaef86 100644 --- a/gap/gv.gd +++ b/gap/gv.gd @@ -61,14 +61,17 @@ DeclareOperation("GV_ConstructHistory", [IsGraphvizGraphDigraphOrContext]); DeclareGlobalFunction("GV_IsValidColor"); DeclareGlobalFunction("GV_ErrorIfNotNodeColoring"); +# TODO move to dot? and make public? BindGlobal("GV_ObjectFamily", NewFamily("GV_ObjectFamily", IsGraphvizObject)); +# TODO move to dot? and make public? BindGlobal("GV_DigraphType", NewType(GV_ObjectFamily, IsGraphvizDigraph and IsComponentObjectRep and IsAttributeStoringRep)); +# TODO move to dot? and make public? BindGlobal("GV_GraphType", NewType(GV_ObjectFamily, IsGraphvizGraph and IsComponentObjectRep and From 910639c82867d4d31d9d19ca441764e193d3f77a Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 12:21:45 +0100 Subject: [PATCH 37/38] Fix tests for GAP 4.11 again --- tst/edge.tst | 4 ++++ tst/subgraph.tst | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/tst/edge.tst b/tst/edge.tst index 19afffc..6381a04 100644 --- a/tst/edge.tst +++ b/tst/edge.tst @@ -83,16 +83,20 @@ gap> d := GraphvizAddNode(g, "d");; gap> a2 := GraphvizAddNode(g1, "a");; gap> c := GraphvizAddNode(g1, "c");; gap> e1 := GraphvizAddEdge(g, d, a1);; +#@if CompareVersionNumbers(GAPInfo.Version, "4.12") gap> e2 := GraphvizAddEdge(g, a2, c);; Error, The 2nd argument (edge) has head node named "a" but there is already a \ node with this name in the 1st argument (a graphviz (di)graph / context) named\ "" +#@fi gap> GraphvizEdges(g); [ ] +#@if CompareVersionNumbers(GAPInfo.Version, "4.12") gap> e2 := GraphvizAddEdge(g, c, a2);; Error, The 2nd argument (edge) has tail node named "c" but there is already a \ node with this name in the 1st argument (a graphviz (di)graph / context) named\ "" +#@fi # Test adding an edge reuses a node automatically gap> g := GraphvizGraph();; diff --git a/tst/subgraph.tst b/tst/subgraph.tst index 9545fde..de7eede 100644 --- a/tst/subgraph.tst +++ b/tst/subgraph.tst @@ -87,26 +87,32 @@ rec( n := ) gap> g := GraphvizGraph("r");; gap> s := GraphvizAddSubgraph(g, "a");; gap> GraphvizAddNode(g, "n");; +#@if CompareVersionNumbers(GAPInfo.Version, "4.12") gap> GraphvizAddNode(s, "n"); Error, the 2nd argument (node) has name "n" but there is already a node with t\ his name in the 1st argument (a graphviz (di)graph / context) named "a" +#@fi # Test adding a node to a graph which is already in child fails (by name) gap> g := GraphvizGraph();; gap> s := GraphvizAddSubgraph(g, "a");; gap> GraphvizAddNode(s, "n");; +#@if CompareVersionNumbers(GAPInfo.Version, "4.12") gap> GraphvizAddNode(g, "n"); Error, the 2nd argument (node) has name "n" but there is already a node with t\ his name in the 1st argument (a graphviz (di)graph / context) named "" +#@fi # Test adding a node to a graph which is already in sibling fails (by name) gap> g := GraphvizGraph();; gap> s1 := GraphvizAddSubgraph(g, "a");; gap> s2 := GraphvizAddSubgraph(g, "b");; gap> GraphvizAddNode(s1, "n");; +#@if CompareVersionNumbers(GAPInfo.Version, "4.12") gap> GraphvizAddNode(s2, "n"); Error, the 2nd argument (node) has name "n" but there is already a node with t\ his name in the 1st argument (a graphviz (di)graph / context) named "b" +#@fi # Test adding edges to subgraphs gap> g := GraphvizGraph();; From 2785ab5cd16eb8fab0986c1162a830b22e5450c6 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 15 May 2024 13:04:33 +0100 Subject: [PATCH 38/38] Fix codespell --- .codespellrc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.codespellrc b/.codespellrc index fdb0e06..ff818f3 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,3 +1,3 @@ [codespell] -skip = ./.git,./doc/*.log,./doc/*.html,./doc/*.txt,./doc/*.six,./doc/*.js,./doc/*.bbl,./doc/*.tex,./doc/*.bib,./doc/_* -ignore-words-list=fille,manuel +skip = ./.git,./doc/*.log,./doc/*.html,./doc/*.txt,./doc/*.six,./doc/*.js,./doc/*.bbl,./doc/*.tex,./doc/*.bib,./doc/_*,./tst/* +ignore-words-list=manuel