From 4a4ee13c9e555b3ca6f1a240e4d733af98e37f36 Mon Sep 17 00:00:00 2001 From: reiniscirpons Date: Fri, 2 Oct 2026 14:30:49 +0200 Subject: [PATCH 1/5] Merge the types --- TODO.md | 34 ++++++++++- gap/dot.gd | 44 +++++++------- gap/dot.gi | 156 ++++++++++++++++++++++++-------------------------- gap/gv.gd | 46 +++++++-------- gap/gv.gi | 103 +++++++++++++++------------------ gap/splash.gi | 4 +- 6 files changed, 199 insertions(+), 188 deletions(-) diff --git a/TODO.md b/TODO.md index 5165e96..fe172f8 100644 --- a/TODO.md +++ b/TODO.md @@ -1,4 +1,36 @@ - - save & load (potentially with 6-strings) +# Status log + +## 2026-10-02 + +During GAPDays 2026 the graphviz working group made the following contributions + +- There have been various improvements to the package infrastructure, + improvements to CI, Makefile, PackageInfo +- The docs have been improved, there are now more examples, the readme now + renders all its pictures correctly +- The splash function has been improved, we fixed an error relating to + output directory creation, better error messages +- Started improving the internals and aligning it more closely with user + expectations + +Need to do: + +- Make the behavior of function match user expectations more + - e.g. GraphvizNodes returning all nodes belonging to subgraphs too + - Setting attrs applying to the correct contexts +- Overhaul the internals to simplify functionality + (there are parts of code that assume the hierarchy is not a tree when it is) +- Add better attribute handling +- Add missing core functionality + - Vertex and edge coloring + - Better html support +- Add html handling, use this to improve quotation +- Big documentation pass +- Big test pass + +# Old todos + +- save & load (potentially with 6-strings) - condense code in displaying defaults using the new graphviz pkg model - ex. all the symmetric vs not symmetric methods can be made a single method which chooses automatically relatively easily. - Allow photos to be used as nodes & composition of graphviz output photos (later) diff --git a/gap/dot.gd b/gap/dot.gd index bfefcd1..b5ef985 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -240,6 +240,8 @@ DeclareOperation("GraphvizGraph", [IsObject]); DeclareOperation("GraphvizGraph", []); #! @EndGroup +# TODO: deprecate + #! @BeginGroup #! @GroupTitle Creating a new &GAPGraphviz; digraphs #! @Arguments name @@ -339,7 +341,7 @@ DeclareOperation("GraphvizAttrs", [IsGraphvizObject]); #! gap> GraphvizNodes(context); #! rec( a := ) #! @EndExampleSession -DeclareOperation("GraphvizNodes", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GraphvizNodes", [IsGraphvizGraph]); #! @Arguments gv, val #! @Returns a &GraphvizForGAP; node object or fail. @@ -372,14 +374,14 @@ DeclareOperation("GraphvizNode", [IsGraphvizGraphDigraphOrContext, IsObject]); #! &GAPGraphviz; graph, digraph, or context graph. #! @BeginExampleSession #! @EndExampleSession -DeclareOperation("GraphvizNumberOfNodes", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GraphvizNumberOfNodes", [IsGraphvizGraph]); #! @Arguments graph #! @Returns a print record of &GAPGraphviz; graphs #! @Description gets the subgraphs of a provided graphviz graph. #! @BeginExampleSession #! @EndExampleSession -DeclareOperation("GraphvizSubgraphs", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GraphvizSubgraphs", [IsGraphvizGraph]); #! @Arguments graph #! @Returns a print record of &GAPGraphviz; contexts @@ -387,7 +389,7 @@ DeclareOperation("GraphvizSubgraphs", [IsGraphvizGraphDigraphOrContext]); #! or context. #! @BeginExampleSession #! @EndExampleSession -DeclareOperation("GraphvizContexts", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GraphvizContexts", [IsGraphvizGraph]); #! @Arguments graph, name #! @Returns a &GAPGraphviz; graph @@ -399,7 +401,7 @@ DeclareOperation("GraphvizContexts", [IsGraphvizGraphDigraphOrContext]); #! @BeginExampleSession #! @EndExampleSession DeclareOperation("GraphvizFindSubgraphRecursive", -[IsGraphvizGraphDigraphOrContext, IsObject]); +[IsGraphvizGraph, IsObject]); #! @BeginGroup #! @GroupTitle Getting Graphviz Edges @@ -416,10 +418,10 @@ DeclareOperation("GraphvizFindSubgraphRecursive", #! gap> GraphvizEdges(gv, "a", "b"); #! [ ] #! @EndExampleSession -DeclareOperation("GraphvizEdges", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GraphvizEdges", [IsGraphvizGraph]); #! @Arguments graph, head, tail DeclareOperation("GraphvizEdges", -[IsGraphvizGraphDigraphOrContext, IsObject, IsObject]); +[IsGraphvizGraph, IsObject, IsObject]); #! @EndGroup #! @Arguments edge @@ -461,7 +463,7 @@ DeclareOperation("GraphvizTail", [IsGraphvizEdge]); #! #! @EndExampleSession DeclareOperation("GraphvizSetName", - [IsGraphvizGraphDigraphOrContext, IsObject]); + [IsGraphvizGraph, IsObject]); #! @Arguments graph, node #! @Returns a &GAPGraphviz; node object @@ -478,7 +480,7 @@ DeclareOperation("GraphvizSetName", #! #! @EndExampleSession DeclareOperation("GraphvizAddNode", - [IsGraphvizGraphDigraphOrContext, IsObject]); + [IsGraphvizGraph, IsObject]); #! @Arguments graph, head, tail #! @Returns a &GAPGraphviz; edge object @@ -501,7 +503,7 @@ DeclareOperation("GraphvizAddNode", #! #! @EndExampleSession DeclareOperation("GraphvizAddEdge", -[IsGraphvizGraphDigraphOrContext, IsObject, IsObject]); +[IsGraphvizGraph, IsObject, IsObject]); #! @BeginGroup #! @GroupTitle Adding Subgraphs @@ -514,9 +516,9 @@ DeclareOperation("GraphvizAddEdge", #! @BeginExampleSession #! @EndExampleSession DeclareOperation("GraphvizAddSubgraph", -[IsGraphvizGraphDigraphOrContext, IsObject]); +[IsGraphvizGraph, IsObject]); #! @Arguments graph -DeclareOperation("GraphvizAddSubgraph", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GraphvizAddSubgraph", [IsGraphvizGraph]); #! @EndGroup #! @BeginGroup @@ -538,13 +540,13 @@ DeclareOperation("GraphvizAddSubgraph", [IsGraphvizGraphDigraphOrContext]); #! @BeginExampleSession #! @EndExampleSession DeclareOperation("GraphvizAddContext", -[IsGraphvizGraphDigraphOrContext, IsObject]); +[IsGraphvizGraph, IsObject]); #! @Arguments graph -DeclareOperation("GraphvizAddContext", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GraphvizAddContext", [IsGraphvizGraph]); #! @EndGroup DeclareOperation("GraphvizAddComment", -[IsGraphvizGraphDigraphOrContext, IsString]); +[IsGraphvizGraph, IsString]); #! @Arguments graph, node #! @Returns a &GAPGraphviz; graph @@ -563,7 +565,7 @@ DeclareOperation("GraphvizAddComment", #! #! @EndExampleSession DeclareOperation("GraphvizRemoveNode", -[IsGraphvizGraphDigraphOrContext, IsObject]); +[IsGraphvizGraph, IsObject]); #! @Arguments graph, predicate #! @Returns a &GAPGraphviz; graph @@ -571,7 +573,7 @@ DeclareOperation("GraphvizRemoveNode", #! @BeginExampleSession #! @EndExampleSession DeclareOperation("GraphvizFilterEdges", -[IsGraphvizGraphDigraphOrContext, IsFunction]); +[IsGraphvizGraph, IsFunction]); #! @Arguments graph, head_id, tail_id #! @Returns a &GAPGraphviz; graph @@ -587,7 +589,7 @@ DeclareOperation("GraphvizFilterEdges", #! #! @EndExampleSession DeclareOperation("GraphvizRemoveEdges", -[IsGraphvizGraphDigraphOrContext, IsObject, IsObject]); +[IsGraphvizGraph, IsObject, IsObject]); #! @Subsection Modifying object attributes #! Operations for modifying attributes. @@ -645,7 +647,7 @@ DeclareOperation("GraphvizRemoveAttr", [IsGraphvizObject, IsObject]); #! @Description The &DOT; source for the graph argument. #! @BeginExampleSession #! @EndExampleSession -DeclareOperation("AsString", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("AsString", [IsGraphvizGraph]); #! @Arguments obj #! @Returns a &GAPGraphviz; object @@ -666,7 +668,7 @@ DeclareOperation("Graphviz", [IsObject]); #! @BeginExampleSession #! @EndExampleSession DeclareOperation("GraphvizSetNodeColors", -[IsGraphvizGraphDigraphOrContext, IsList]); +[IsGraphvizGraph, IsList]); #! @Arguments graph, labels #! @Returns a &GAPGraphviz; object @@ -679,7 +681,7 @@ DeclareOperation("GraphvizSetNodeColors", #! @BeginExampleSession #! @EndExampleSession DeclareOperation("GraphvizSetNodeLabels", -[IsGraphvizGraphDigraphOrContext, IsList]); +[IsGraphvizGraph, IsList]); #! @Arguments color #! @Returns true or false diff --git a/gap/dot.gi b/gap/dot.gi index a440b5d..a11d429 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -13,21 +13,20 @@ ############################################################################# InstallMethod(GraphvizGraph, "for a string", [IsString], -function(name) - return Objectify(GV_GraphType, - rec( - Name := name, - Subgraphs := rec(), - Contexts := rec(), - Nodes := rec(), - Edges := [], - Attrs := rec(graph := rec(), - edge := rec(), - node := rec()), - Parent := fail, - Idx := 1, - Counter := 1)); -end); +name -> GV_Graph(name, false)); + # return Objectify(GV_GraphType, + # rec( + # Name := name, + # Subgraphs := rec(), + # Contexts := rec(), + # Nodes := rec(), + # Edges := [], + # Attrs := rec(graph := rec(), + # edge := rec(), + # node := rec()), + # Parent := fail, + # Idx := 1, + # Counter := 1)); InstallMethod(GraphvizGraph, "for an object", [IsObject], obj -> GraphvizGraph(String(obj))); @@ -35,27 +34,13 @@ obj -> GraphvizGraph(String(obj))); InstallMethod(GraphvizGraph, "for no args", [], {} -> GraphvizGraph("")); InstallMethod(GraphvizDigraph, "for a string", [IsString], -function(name) - return Objectify(GV_DigraphType, - rec( - Name := name, - Subgraphs := rec(), - Contexts := rec(), - Nodes := rec(), - Edges := [], - Attrs := rec(graph := rec(), - edge := rec(), - node := rec()), - Parent := fail, - Idx := 1, - Counter := 1)); -end); - -InstallMethod(GraphvizDigraph, "for no args", [], {} -> GraphvizDigraph("")); +name -> GV_Graph(name, true)); InstallMethod(GraphvizDigraph, "for an object", [IsObject], obj -> GraphvizDigraph(String(obj))); +InstallMethod(GraphvizDigraph, "for no args", [], {} -> GraphvizDigraph("")); + ############################################################################# # ViewString ############################################################################# @@ -67,7 +52,7 @@ InstallMethod(PrintString, "for a graphviz edge", [IsGraphvizEdge], e -> StringFormatted("", GraphvizName(e))); InstallMethod(PrintString, "for a graphviz (di)graph or context", -[IsGraphvizGraphDigraphOrContext], +[IsGraphvizGraph], function(g) local result, edges, nodes, kind; @@ -81,10 +66,10 @@ function(g) return false; end); - if IsGraphvizDigraph(g) then - kind := "digraph"; - elif IsGraphvizContext(g) then + if g!.IsContext then kind := "context"; + elif g!.Directed then + kind := "digraph"; else kind := "graph"; fi; @@ -113,7 +98,7 @@ InstallMethod(GraphvizAttrs, "for a graphviz object", [IsGraphvizObject], x -> x!.Attrs); InstallMethod(GraphvizNodes, "for a graphviz (di)graph or context", -[IsGraphvizGraphDigraphOrContext], x -> x!.Nodes); +[IsGraphvizGraph], x -> x!.Nodes); InstallMethod(GraphvizNode, "for a graphviz (di)graph or context and object", [IsGraphvizGraphDigraphOrContext, IsObject], @@ -129,14 +114,14 @@ end); # FIXME the below only counts nodes in the root graph, not in its children InstallMethod(GraphvizNumberOfNodes, "for a graphviz (di)graph or context", -[IsGraphvizGraphDigraphOrContext], x -> Length(RecNames(GraphvizNodes(x)))); +[IsGraphvizGraph], x -> Length(RecNames(GraphvizNodes(x)))); InstallMethod(GraphvizEdges, "for a graphviz (di)graph or context", -[IsGraphvizGraphDigraphOrContext], x -> x!.Edges); +[IsGraphvizGraph], x -> x!.Edges); InstallMethod(GraphvizEdges, "for a graphviz (di)graph or context, object, and object", -[IsGraphvizGraphDigraphOrContext, IsObject, IsObject], +[IsGraphvizGraph, IsObject, IsObject], function(gv, head, tail) local nodes; @@ -160,10 +145,10 @@ function(gv, head, tail) end); InstallMethod(GraphvizSubgraphs, "for a graphviz (di)graph or context", -[IsGraphvizGraphDigraphOrContext], x -> x!.Subgraphs); +[IsGraphvizGraph], x -> x!.Subgraphs); InstallMethod(GraphvizContexts, "for a graphviz (di)graph or context", -[IsGraphvizGraphDigraphOrContext], x -> x!.Contexts); +[IsGraphvizGraph], x -> x!.Contexts); InstallMethod(GraphvizTail, "for a graphviz edge", [IsGraphvizEdge], x -> x!.Tail); @@ -183,13 +168,13 @@ InstallMethod(\=, "for graphviz edges", InstallMethod(GraphvizFindSubgraphRecursive, "for a graphviz (di)graph or context and a string", -[IsGraphvizGraphDigraphOrContext, IsString], +[IsGraphvizGraph, IsString], {g, s} -> GV_GraphTreeSearch(g, v -> GraphvizName(v) = s and - not IsGraphvizContext(v))); + not v!.IsContext)); InstallMethod(GraphvizFindSubgraphRecursive, "for a graphviz (di)graph or context and a string", -[IsGraphvizGraphDigraphOrContext, IsObject], +[IsGraphvizGraph, IsObject], {g, o} -> GraphvizFindSubgraphRecursive(g, String(o))); ############################################################################# @@ -197,14 +182,14 @@ InstallMethod(GraphvizFindSubgraphRecursive, ############################################################################# InstallMethod(GraphvizSetName, "for a graphviz (di)graph or context and string", -[IsGraphvizGraphDigraphOrContext, IsString], +[IsGraphvizGraph, IsString], function(x, name) x!.Name := name; return x; end); InstallMethod(GraphvizSetName, "for a graphviz (di)graph or context and string", -[IsGraphvizGraphDigraphOrContext, IsObject], +[IsGraphvizGraph, IsObject], {g, o} -> GraphvizSetName(g, String(o))); ############################################################################# @@ -345,7 +330,7 @@ function(gv, val) end); InstallMethod(GraphvizAddNode, "for a graphviz (di)graph or context and string", -[IsGraphvizGraphDigraphOrContext, IsGraphvizNode], +[IsGraphvizGraph, IsGraphvizNode], function(gv, name) # gaplint: disable=unused-func-args ErrorNoReturn("it is not currently possible to add Graphviz node ", "objects directly to Graphviz graphs or digraphs, use ", @@ -358,7 +343,7 @@ end); InstallMethod(GraphvizAddEdge, "for a graphviz (di)graph or context and two graphviz nodes", -[IsGraphvizGraphDigraphOrContext, IsGraphvizNode, IsGraphvizNode], +[IsGraphvizGraph, IsGraphvizNode, IsGraphvizNode], function(x, head, tail) local edge, root_x, root_head, root_tail; @@ -391,7 +376,7 @@ end); InstallMethod(GraphvizAddEdge, "for a graphviz (di)graph or context and two strings", -[IsGraphvizGraphDigraphOrContext, IsString, IsString], +[IsGraphvizGraph, IsString, IsString], function(x, head, tail) local head_node, tail_node; @@ -416,7 +401,7 @@ end); InstallMethod(GraphvizAddEdge, "for a graphviz (di)graph or context and two objects", -[IsGraphvizGraphDigraphOrContext, IsObject, IsObject], +[IsGraphvizGraph, IsObject, IsObject], function(gv, head, tail) local head_name, tail_name; if IsGraphvizNode(head) then @@ -438,9 +423,9 @@ end); InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph or context and string", -[IsGraphvizGraphDigraphOrContext, IsString], +[IsGraphvizGraph, IsString], function(gv, name) - local subgraphs, root, subgraph; + local subgraphs, subgraph; subgraphs := GraphvizSubgraphs(gv); if IsBound(subgraphs.(name)) then @@ -448,36 +433,26 @@ function(gv, name) "already has a subgraph with name \"{}\"", name); fi; - 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; - + subgraph := GV_Subgraph(gv, name); + # TODO(reiniscirpons): Why not just do this in the internal func? subgraphs.(name) := subgraph; return subgraph; end); InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph or context and an object", -[IsGraphvizGraphDigraphOrContext, IsObject], +[IsGraphvizGraph, IsObject], {g, o} -> GraphvizAddSubgraph(g, String(o))); InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph or context", -[IsGraphvizGraphDigraphOrContext], +[IsGraphvizGraph], graph -> GraphvizAddSubgraph(graph, StringFormatted("no_name_{}", GV_GetCounter(graph)))); InstallMethod(GraphvizAddContext, "for a graphviz (di)graph or context and a string", -[IsGraphvizGraphDigraphOrContext, IsString], +[IsGraphvizGraph, IsString], function(graph, name) local contexts, ctx; @@ -495,22 +470,24 @@ end); InstallMethod(GraphvizAddContext, "for a graphviz (di)graph or context", -[IsGraphvizGraphDigraphOrContext], +[IsGraphvizGraph], g -> GraphvizAddContext(g, StringFormatted("no_name_{}", GV_GetCounter(g)))); InstallMethod(GraphvizAddContext, "for a graphviz (di)graph or context and an object", -[IsGraphvizGraphDigraphOrContext, IsObject], +[IsGraphvizGraph, IsObject], {g, o} -> GraphvizAddContext(g, String(o))); +# Removal + InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph or context and node", -[IsGraphvizGraphDigraphOrContext, IsGraphvizNode], +[IsGraphvizGraph, IsGraphvizNode], {g, node} -> GraphvizRemoveNode(g, GraphvizName(node))); InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph or context and a string", -[IsGraphvizGraphDigraphOrContext, IsString], +[IsGraphvizGraph, IsString], function(g, name) local nodes; nodes := GraphvizNodes(g); @@ -537,12 +514,12 @@ end); InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph or context and a string", -[IsGraphvizGraphDigraphOrContext, IsObject], +[IsGraphvizGraph, IsObject], {g, o} -> GraphvizRemoveNode(g, String(o))); InstallMethod(GraphvizFilterEdges, "for a graphviz (di)graph or context and edge filter", -[IsGraphvizGraphDigraphOrContext, IsFunction], +[IsGraphvizGraph, IsFunction], function(g, filter) local edge, idx, edges; @@ -561,7 +538,7 @@ end); InstallMethod(GraphvizRemoveEdges, "for a graphviz (di)graph or context, string, and string", -[IsGraphvizGraphDigraphOrContext, IsString, IsString], +[IsGraphvizGraph, IsString, IsString], function(g, hn, tn) local lh, lt, len; @@ -582,7 +559,7 @@ function(g, hn, tn) local head, tail, tmp; head := GraphvizHead(e); tail := GraphvizTail(e); - if IsGraphvizDigraph(g) then + if g!.Directed then return tn <> GraphvizName(tail) or hn <> GraphvizName(head); else tmp := tn <> GraphvizName(tail) or hn <> GraphvizName(head); @@ -599,9 +576,26 @@ end); InstallMethod(GraphvizRemoveEdges, "for a graphviz (di)graph or context, object, and object", -[IsGraphvizGraphDigraphOrContext, IsObject, IsObject], +[IsGraphvizGraph, IsObject, IsObject], {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); + attr := String(attr); + + if not IsBound(attrs.(attr)) then + ErrorFormatted("the 2nd argument (attribute name) \"{}\" ", + "is not set on the provided object.", + attr); + fi; + + Unbind(attrs.(attr)); + return obj; +end); + ############################################################################# # Stringify ############################################################################# @@ -611,20 +605,20 @@ InstallMethod(GraphvizRemoveEdges, # immutable, and hence cannot be changed after it is first set. InstallMethod(AsString, "for a graphviz (di)graph", -[IsGraphvizGraphDigraphOrContext], graph -> GV_StringifyGraph(graph, false)); +[IsGraphvizGraph], 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", -# [IsGraphvizGraphDigraphOrContext], +# [IsGraphvizGraph], # function(gv) # Print(String(gv)); # end); InstallMethod(GraphvizSetNodeLabels, "for a graphviz (di)graph or context and list of colors", -[IsGraphvizGraphDigraphOrContext, IsList], +[IsGraphvizGraph, IsList], function(gv, labels) local nodes, i; if GraphvizNumberOfNodes(gv) <> Size(labels) then @@ -646,7 +640,7 @@ end); InstallMethod(GraphvizSetNodeColors, "for a graphviz (di)graph or context and list of colors", -[IsGraphvizGraphDigraphOrContext, IsList], +[IsGraphvizGraph, IsList], function(gv, colors) local nodes, i; diff --git a/gap/gv.gd b/gap/gv.gd index d60ade8..b46ffc7 100644 --- a/gap/gv.gd +++ b/gap/gv.gd @@ -11,43 +11,43 @@ ## This file contains declarations of the internal/private functions for the ## graphviz package. -DeclareOperation("GV_GetCounter", [IsGraphvizGraphDigraphOrContext]); -DeclareOperation("GV_IncCounter", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GV_GetCounter", [IsGraphvizGraph]); +DeclareOperation("GV_IncCounter", [IsGraphvizGraph]); -DeclareOperation("GV_StringifyGraphHead", [IsGraphvizGraphDigraphOrContext]); -DeclareOperation("GV_StringifyDigraphHead", [IsGraphvizGraphDigraphOrContext]); -DeclareOperation("GV_StringifySubgraphHead", [IsGraphvizGraphDigraphOrContext]); -DeclareOperation("GV_StringifyContextHead", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GV_StringifyGraphHead", [IsGraphvizGraph]); +DeclareOperation("GV_StringifyDigraphHead", [IsGraphvizGraph]); +DeclareOperation("GV_StringifySubgraphHead", [IsGraphvizGraph]); +DeclareOperation("GV_StringifyContextHead", [IsGraphvizGraph]); DeclareOperation("GV_StringifyNode", [IsGraphvizNode]); -DeclareOperation("GV_StringifyGraphAttrs", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GV_StringifyGraphAttrs", [IsGraphvizGraph]); DeclareOperation("GV_StringifyNodeEdgeAttrs", [IsRecord]); DeclareOperation("GV_StringifyGraph", - [IsGraphvizGraphDigraphOrContext, IsBool]); + [IsGraphvizGraph, IsBool]); -DeclareOperation("GV_Node", [IsGraphvizGraphDigraphOrContext, IsString]); +DeclareOperation("GV_Node", [IsGraphvizGraph, IsString]); DeclareOperation("GV_Edge", -[IsGraphvizGraphDigraphOrContext, IsGraphvizNode, IsGraphvizNode]); -DeclareOperation("GV_Graph", [IsGraphvizGraphDigraphOrContext, IsString]); -DeclareOperation("GV_Digraph", [IsGraphvizDigraph, IsString]); -DeclareOperation("GV_Context", [IsGraphvizGraphDigraphOrContext, IsString]); +[IsGraphvizGraph, IsGraphvizNode, IsGraphvizNode]); +DeclareOperation("GV_Graph", [IsString, IsBool]); +DeclareOperation("GV_Subgraph", [IsGraphvizGraph, IsString]); +DeclareOperation("GV_Context", [IsGraphvizGraph, IsString]); -DeclareOperation("GV_HasNode", [IsGraphvizGraphDigraphOrContext, IsObject]); +DeclareOperation("GV_HasNode", [IsGraphvizGraph, IsObject]); DeclareOperation("GV_GetParent", [IsGraphvizObject]); DeclareOperation("GV_GraphTreeSearch", -[IsGraphvizGraphDigraphOrContext, IsFunction]); +[IsGraphvizGraph, IsFunction]); DeclareOperation("GV_GraphSearchChildren", -[IsGraphvizGraphDigraphOrContext, IsFunction]); +[IsGraphvizGraph, IsFunction]); DeclareOperation("GV_FindGraphWithNode", -[IsGraphvizGraphDigraphOrContext, IsString]); +[IsGraphvizGraph, IsString]); DeclareOperation("GV_GetRoot", [IsGraphvizObject]); DeclareOperation("GV_EnclosingNonContext", [IsGraphvizObject]); DeclareOperation("GV_AddNode", -[IsGraphvizGraphDigraphOrContext, IsGraphvizNode]); +[IsGraphvizGraph, IsGraphvizNode]); DeclareOperation("GV_AddEdge", -[IsGraphvizGraphDigraphOrContext, IsGraphvizEdge]); +[IsGraphvizGraph, IsGraphvizEdge]); DeclareOperation("GV_GetIdx", [IsGraphvizObject]); -DeclareOperation("GV_ConstructHistory", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GV_ConstructHistory", [IsGraphvizGraph]); DeclareGlobalFunction("GV_IsValidColor"); DeclareGlobalFunction("GV_ErrorIfNotNodeColoring"); @@ -57,12 +57,6 @@ DeclareGlobalFunction("GV_ErrorIfNotValidLabel"); 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 diff --git a/gap/gv.gi b/gap/gv.gi index 10b7126..198c6f9 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -24,17 +24,12 @@ BindGlobal("GV_EdgeType", NewType(GV_ObjectFamily, IsComponentObjectRep and IsAttributeStoringRep)); -BindGlobal("GV_ContextType", NewType(GV_ObjectFamily, - IsGraphvizContext and - IsComponentObjectRep and - IsAttributeStoringRep)); - ############################################################################### # Constructors etc ############################################################################### InstallMethod(GV_Node, "for a string", -[IsGraphvizGraphDigraphOrContext, IsString], +[IsGraphvizGraph, IsString], function(graph, name) local out; Assert(0, not IsEmpty(name)); @@ -49,7 +44,7 @@ function(graph, name) end); InstallMethod(GV_Edge, "for two graphviz nodes", -[IsGraphvizGraphDigraphOrContext, IsGraphvizNode, IsGraphvizNode], +[IsGraphvizGraph, IsGraphvizNode, IsGraphvizNode], function(graph, head, tail) local out; @@ -69,27 +64,33 @@ end); # Graph constructors -InstallMethod(GV_Digraph, -"for a graphviz digraph and a string", -[IsGraphvizDigraph, IsString], -function(parent, name) - local out; - - out := GraphvizDigraph(name); - out!.Parent := parent; - out!.Idx := GV_GetCounter(parent); - - GV_IncCounter(parent); - return out; +InstallMethod(GV_Graph, +"for a string and a bool", +[IsString, IsBool], +function(name, directed) + return Objectify( + GV_GraphType, + rec( + Name := name, + Directed := directed, + IsContext := false, + Subgraphs := rec(), + Contexts := rec(), + Nodes := rec(), + Edges := [], + Attrs := [], + Parent := fail, + Idx := 1, + Counter := 1)); end); -InstallMethod(GV_Graph, +InstallMethod(GV_Subgraph, "for a graphviz graph and a string", -[IsGraphvizGraphDigraphOrContext, IsString], +[IsGraphvizGraph, IsString], function(parent, name) local out; - out := GraphvizGraph(name); + out := GV_Graph(name, parent!.Directed); out!.Parent := parent; out!.Idx := GV_GetCounter(parent); @@ -99,25 +100,13 @@ end); InstallMethod(GV_Context, "for a string and a positive integer", -[IsGraphvizGraphDigraphOrContext, IsString], +[IsGraphvizGraph, IsString], function(parent, name) local out; - out := Objectify(GV_ContextType, - rec( - Name := name, - Subgraphs := rec(), - Contexts := rec(), - Nodes := rec(), - Edges := [], - Attrs := rec(graph := rec(), - edge := rec(), - node := rec()), - Parent := parent, - Idx := GV_GetCounter(parent), - Counter := 1)); + out := GV_Subgraph(parent, name); + out!.IsContext := true; - GV_IncCounter(parent); return out; end); @@ -125,20 +114,20 @@ end); InstallMethod(GV_IncCounter, "for a graphviz graph", -[IsGraphvizGraphDigraphOrContext], +[IsGraphvizGraph], function(x) x!.Counter := x!.Counter + 1; end); InstallMethod(GV_GetCounter, "for a graphviz graph", -[IsGraphvizGraphDigraphOrContext], +[IsGraphvizGraph], x -> x!.Counter); # Nodes InstallMethod(GV_HasNode, "for a graphviz graph", -[IsGraphvizGraphDigraphOrContext, IsString], +[IsGraphvizGraph, IsString], {g, name} -> name in RecNames(GraphvizNodes(g))); InstallMethod(GV_GetParent, @@ -147,7 +136,7 @@ InstallMethod(GV_GetParent, InstallMethod(GV_GraphTreeSearch, "for a graphviz graph and a predicate", -[IsGraphvizGraphDigraphOrContext, IsFunction], +[IsGraphvizGraph, IsFunction], function(graph, pred) local seen, to_visit, g, key, subgraph, context, parent; seen := [graph]; @@ -181,7 +170,7 @@ function(graph, pred) # add parent if not visited parent := GV_GetParent(g); - if not IsGraphvizGraphDigraphOrContext(parent) then + if not IsGraphvizGraph(parent) then continue; fi; if not ForAny(seen, s -> IsIdenticalObj(s, parent)) then @@ -196,7 +185,7 @@ end); # tree search only on the children of the graph InstallMethod(GV_GraphSearchChildren, "for a graphviz graph and a predicate", -[IsGraphvizGraphDigraphOrContext, IsFunction], +[IsGraphvizGraph, IsFunction], function(graph, pred) local _, curr, queue, count, nexts, key; @@ -230,7 +219,7 @@ end); InstallMethod(GV_FindGraphWithNode, "for a graphviz graph and a node", -[IsGraphvizGraphDigraphOrContext, IsString], +[IsGraphvizGraph, IsString], {g, n} -> GV_GraphTreeSearch(g, v -> IsBound(GraphvizNodes(v).(n)))); InstallMethod(GV_GetRoot, @@ -251,13 +240,13 @@ function(graph) repeat parent := GV_GetParent(graph); - until parent = fail or not IsGraphvizContext(parent); + until parent = fail or not parent!.IsContext; return parent; end); InstallMethod(GV_AddNode, "for a graphviz graph and node", -[IsGraphvizGraphDigraphOrContext, IsGraphvizNode], +[IsGraphvizGraph, IsGraphvizNode], function(x, node) local name, nodes; name := GraphvizName(node); @@ -268,7 +257,7 @@ end); InstallMethod(GV_AddEdge, "for a graphviz graph and edge", -[IsGraphvizGraphDigraphOrContext, IsGraphvizEdge], +[IsGraphvizGraph, IsGraphvizEdge], function(x, edge) Add(x!.Edges, edge); return x; @@ -280,20 +269,20 @@ end); # @ Return DOT graph head line. InstallMethod(GV_StringifyGraphHead, "for a string", -[IsGraphvizGraphDigraphOrContext], +[IsGraphvizGraph], graph -> StringFormatted("graph {} {{\n", GraphvizName(graph))); # @ Return DOT digraph head line. -InstallMethod(GV_StringifyDigraphHead, "for a string", [IsGraphvizDigraph], +InstallMethod(GV_StringifyDigraphHead, "for a string", [IsGraphvizGraph], graph -> StringFormatted("digraph {} {{\n", GraphvizName(graph))); # @ Return DOT subgraph head line. InstallMethod(GV_StringifySubgraphHead, "for a string", -[IsGraphvizGraphDigraphOrContext], +[IsGraphvizGraph], graph -> StringFormatted("subgraph {} {{\n", GraphvizName(graph))); # @ Return DOT subgraph head line. -InstallMethod(GV_StringifyContextHead, "for a string", [IsGraphvizContext], +InstallMethod(GV_StringifyContextHead, "for a string", [IsGraphvizGraph], graph -> StringFormatted("// {} context \n{{\n", GraphvizName(graph))); BindGlobal("GV_StringifyNodeName", @@ -386,7 +375,7 @@ x -> x!.Idx); InstallMethod(GV_ConstructHistory, "for a graphviz graph", -[IsGraphvizGraphDigraphOrContext], +[IsGraphvizGraph], function(graph) local ctxs, nodes, edges, subs, ctxs_hist, node_hist, edge_hist, subs_hist, hist; @@ -410,7 +399,7 @@ end); InstallMethod(GV_StringifyGraph, "for a graphviz graph and a string", -[IsGraphvizGraphDigraphOrContext, IsBool], +[IsGraphvizGraph, IsBool], function(graph, is_subgraph) local result, record, type, obj; @@ -418,12 +407,12 @@ function(graph, is_subgraph) # get the correct head to use if is_subgraph then - if IsGraphvizContext(graph) then + if graph!.IsContext then Append(result, GV_StringifyContextHead(graph)); else Append(result, GV_StringifySubgraphHead(graph)); fi; - elif IsGraphvizDigraph(graph) then + elif graph!.Directed then Append(result, "//dot\n"); Append(result, GV_StringifyDigraphHead(graph)); elif IsGraphvizGraph(graph) then @@ -443,12 +432,12 @@ function(graph, is_subgraph) # Add child graphviz objects for obj in GV_ConstructHistory(graph) do - if IsGraphvizGraphDigraphOrContext(obj) then + if IsGraphvizGraph(obj) then Append(result, GV_StringifyGraph(obj, true)); elif IsGraphvizNode(obj) then Append(result, GV_StringifyNode(obj)); elif IsGraphvizEdge(obj) then - if IsGraphvizDigraph(GV_GetRoot(graph)) then + if (GV_GetRoot(graph))!.Directed then Append(result, GV_StringifyEdge(obj, "->")); else Append(result, GV_StringifyEdge(obj, "--")); diff --git a/gap/splash.gi b/gap/splash.gi index 0dee649..5dee50c 100644 --- a/gap/splash.gi +++ b/gap/splash.gi @@ -42,10 +42,10 @@ function(arg...) if IsEmpty(arg) then ErrorNoReturn("the must be at least 1 argument, found none"); - elif not IsString(arg[1]) and not IsGraphvizGraphDigraphOrContext(arg[1]) then + elif not IsString(arg[1]) and not IsGraphvizGraph(arg[1]) then ErrorFormatted("the 1st argument must be a string or ", "graphviz graph, found {}", TNAM_OBJ(arg[1])); - elif IsGraphvizGraphDigraphOrContext(arg[1]) then + elif IsGraphvizGraph(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 3ca57952059032d87bc1f8ee79dd7faf131911b4 Mon Sep 17 00:00:00 2001 From: reiniscirpons Date: Fri, 2 Oct 2026 15:56:14 +0200 Subject: [PATCH 2/5] Maybe fix docs? --- gap/dot.gd | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index b5ef985..04e5a84 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -109,14 +109,16 @@ #! digraph finite_state_machine { #! rankdir=LR size="8,5" #! // terminals context +#! { #! node [shape=doublecircle] #! LR_0 #! LR_3 #! LR_4 #! LR_8 #! rankdir=LR size="8,5" -#! +#! } #! // nodes context +#! { #! node [shape=circle] #! LR_2 #! LR_0 -> LR_2 [label="SS(B)"] @@ -138,6 +140,7 @@ #! LR_8 -> LR_6 [label="S(b)"] #! LR_8 -> LR_5 [label="S(a)"] #! rankdir=LR size="8,5" +#! } #! #! } #! gap> Splash(f); @@ -220,7 +223,7 @@ DeclareCategory("IsGraphvizEdge", IsGraphvizNodeOrEdge); #! See also: #! * #! * +#! Label="for IsGraphvizGraph", IsObject"/> #! * #! #! @BeginExampleSession @@ -262,7 +265,7 @@ DeclareOperation("GraphvizGraph", []); #! See also: #! * #! * +#! Label="for IsGraphvizGraph, IsObject"/> #! * #! #! @BeginExampleSession @@ -733,6 +736,6 @@ DeclareGlobalFunction("ErrorIfNotValidColor"); #! viewer it uses. At level 2, it reports each program it runs with its #! arguments. At level 3, it reports where it found each program, and #! +#! Label="for IsGraphvizGraph, IsObject, IsObject"/> #! reports the nodes it adds. DeclareInfoClass("InfoGraphviz"); From 798c6fcc4f908a10f2522c09425ef34c12ac51fc Mon Sep 17 00:00:00 2001 From: reiniscirpons Date: Fri, 2 Oct 2026 21:38:25 +0200 Subject: [PATCH 3/5] Fix docs! --- gap/dot.gd | 2 +- gap/splash.gd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index 04e5a84..f49a2a5 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -223,7 +223,7 @@ DeclareCategory("IsGraphvizEdge", IsGraphvizNodeOrEdge); #! See also: #! * #! * +#! Label="for IsGraphvizGraph, IsObject"/> #! * #! #! @BeginExampleSession diff --git a/gap/splash.gd b/gap/splash.gd index debd390..c9eec0a 100644 --- a/gap/splash.gd +++ b/gap/splash.gd @@ -23,7 +23,7 @@ #! #! #! a &GAPGraphviz; graph or digraph, which is converted into a string -#! using ; +#! using ; #! #! #! a string containing a valid dot or &LaTeX; document. From 39f1a58e8155b49554772d7551059aa1de2e52a1 Mon Sep 17 00:00:00 2001 From: James Mitchell Date: Sat, 3 Oct 2026 16:14:33 +0100 Subject: [PATCH 4/5] Use GAP filter system properly --- gap/dot.gd | 2 ++ gap/dot.gi | 10 +++++----- gap/gv.gi | 34 ++++++++++++++++++---------------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index f49a2a5..13b0928 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -201,6 +201,8 @@ DeclareCategory("IsGraphvizEdge", IsGraphvizNodeOrEdge); #! attributes. #! @EndGroup +DeclareCategory("IsGraphvizDigraph", IsGraphvizGraph); +DeclareCategory("IsGraphvizContext", IsGraphvizGraph); #! @Section Constructors #! @BeginGroup diff --git a/gap/dot.gi b/gap/dot.gi index a11d429..435a2ff 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -66,9 +66,9 @@ function(g) return false; end); - if g!.IsContext then + if IsGraphvizContext(g) then kind := "context"; - elif g!.Directed then + elif IsGraphvizDigraph(g) then kind := "digraph"; else kind := "graph"; @@ -101,7 +101,7 @@ InstallMethod(GraphvizNodes, "for a graphviz (di)graph or context", [IsGraphvizGraph], x -> x!.Nodes); InstallMethod(GraphvizNode, "for a graphviz (di)graph or context and object", -[IsGraphvizGraphDigraphOrContext, IsObject], +[IsGraphvizGraph, IsObject], function(gv, val) local graph; val := String(val); @@ -170,7 +170,7 @@ InstallMethod(GraphvizFindSubgraphRecursive, "for a graphviz (di)graph or context and a string", [IsGraphvizGraph, IsString], {g, s} -> GV_GraphTreeSearch(g, v -> GraphvizName(v) = s and - not v!.IsContext)); + not IsGraphvizContext(v))); InstallMethod(GraphvizFindSubgraphRecursive, "for a graphviz (di)graph or context and a string", @@ -559,7 +559,7 @@ function(g, hn, tn) local head, tail, tmp; head := GraphvizHead(e); tail := GraphvizTail(e); - if g!.Directed then + if IsGraphvizDigraph(g) then return tn <> GraphvizName(tail) or hn <> GraphvizName(head); else tmp := tn <> GraphvizName(tail) or hn <> GraphvizName(head); diff --git a/gap/gv.gi b/gap/gv.gi index 198c6f9..ed3d08a 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -64,24 +64,28 @@ end); # Graph constructors -InstallMethod(GV_Graph, -"for a string and a bool", -[IsString, IsBool], +InstallMethod(GV_Graph, "for a string and a bool", [IsString, IsBool], function(name, directed) - return Objectify( + local result; + + result := Objectify( GV_GraphType, rec( + # Note that the following aren't attributes because we require them to be + # mutable. Name := name, - Directed := directed, - IsContext := false, Subgraphs := rec(), - Contexts := rec(), + Contexts := rec(), Nodes := rec(), Edges := [], Attrs := [], Parent := fail, Idx := 1, Counter := 1)); + if directed then + SetFilterObj(result, IsGraphvizDigraph); + fi; + return result; end); InstallMethod(GV_Subgraph, @@ -90,7 +94,7 @@ InstallMethod(GV_Subgraph, function(parent, name) local out; - out := GV_Graph(name, parent!.Directed); + out := GV_Graph(name, IsGraphvizDigraph(parent)); out!.Parent := parent; out!.Idx := GV_GetCounter(parent); @@ -99,14 +103,12 @@ function(parent, name) end); InstallMethod(GV_Context, -"for a string and a positive integer", +"for a string and a string", [IsGraphvizGraph, IsString], function(parent, name) local out; - out := GV_Subgraph(parent, name); - out!.IsContext := true; - + SetFilterObj(out, IsGraphvizContext); return out; end); @@ -240,7 +242,7 @@ function(graph) repeat parent := GV_GetParent(graph); - until parent = fail or not parent!.IsContext; + until parent = fail or not IsGraphvizContext(parent); return parent; end); @@ -407,12 +409,12 @@ function(graph, is_subgraph) # get the correct head to use if is_subgraph then - if graph!.IsContext then + if IsGraphvizContext(graph) then Append(result, GV_StringifyContextHead(graph)); else Append(result, GV_StringifySubgraphHead(graph)); fi; - elif graph!.Directed then + elif IsGraphvizDigraph(graph) then Append(result, "//dot\n"); Append(result, GV_StringifyDigraphHead(graph)); elif IsGraphvizGraph(graph) then @@ -437,7 +439,7 @@ function(graph, is_subgraph) elif IsGraphvizNode(obj) then Append(result, GV_StringifyNode(obj)); elif IsGraphvizEdge(obj) then - if (GV_GetRoot(graph))!.Directed then + if (IsGraphvizDigraph(GV_GetRoot(graph))) then Append(result, GV_StringifyEdge(obj, "->")); else Append(result, GV_StringifyEdge(obj, "--")); From fcdf8ecc017c8f9da9f7e5ba4997b86af22db1cf Mon Sep 17 00:00:00 2001 From: James Mitchell Date: Fri, 9 Oct 2026 09:45:52 +0100 Subject: [PATCH 5/5] Cleanup after rebase --- gap/dot.gd | 50 +++++++++++++------------- gap/dot.gi | 98 ++++++++++++++++++--------------------------------- gap/gv.gd | 52 ++++++++++++--------------- gap/gv.gi | 85 +++++++++++++++++++++++++------------------- gap/splash.gd | 2 +- gap/splash.gi | 4 +-- 6 files changed, 131 insertions(+), 160 deletions(-) diff --git a/gap/dot.gd b/gap/dot.gd index 13b0928..0296444 100644 --- a/gap/dot.gd +++ b/gap/dot.gd @@ -201,8 +201,6 @@ DeclareCategory("IsGraphvizEdge", IsGraphvizNodeOrEdge); #! attributes. #! @EndGroup -DeclareCategory("IsGraphvizDigraph", IsGraphvizGraph); -DeclareCategory("IsGraphvizContext", IsGraphvizGraph); #! @Section Constructors #! @BeginGroup @@ -225,7 +223,7 @@ DeclareCategory("IsGraphvizContext", IsGraphvizGraph); #! See also: #! * #! * +#! Label="for IsGraphvizGraphDigraphOrContext, IsObject"/> #! * #! #! @BeginExampleSession @@ -267,7 +265,7 @@ DeclareOperation("GraphvizGraph", []); #! See also: #! * #! * +#! Label="for IsGraphvizGraphDigraphOrContext, IsObject"/> #! * #! #! @BeginExampleSession @@ -346,7 +344,7 @@ DeclareOperation("GraphvizAttrs", [IsGraphvizObject]); #! gap> GraphvizNodes(context); #! rec( a := ) #! @EndExampleSession -DeclareOperation("GraphvizNodes", [IsGraphvizGraph]); +DeclareOperation("GraphvizNodes", [IsGraphvizGraphDigraphOrContext]); #! @Arguments gv, val #! @Returns a &GraphvizForGAP; node object or fail. @@ -379,14 +377,14 @@ DeclareOperation("GraphvizNode", [IsGraphvizGraphDigraphOrContext, IsObject]); #! &GAPGraphviz; graph, digraph, or context graph. #! @BeginExampleSession #! @EndExampleSession -DeclareOperation("GraphvizNumberOfNodes", [IsGraphvizGraph]); +DeclareOperation("GraphvizNumberOfNodes", [IsGraphvizGraphDigraphOrContext]); #! @Arguments graph #! @Returns a print record of &GAPGraphviz; graphs #! @Description gets the subgraphs of a provided graphviz graph. #! @BeginExampleSession #! @EndExampleSession -DeclareOperation("GraphvizSubgraphs", [IsGraphvizGraph]); +DeclareOperation("GraphvizSubgraphs", [IsGraphvizGraphDigraphOrContext]); #! @Arguments graph #! @Returns a print record of &GAPGraphviz; contexts @@ -394,7 +392,7 @@ DeclareOperation("GraphvizSubgraphs", [IsGraphvizGraph]); #! or context. #! @BeginExampleSession #! @EndExampleSession -DeclareOperation("GraphvizContexts", [IsGraphvizGraph]); +DeclareOperation("GraphvizContexts", [IsGraphvizGraphDigraphOrContext]); #! @Arguments graph, name #! @Returns a &GAPGraphviz; graph @@ -406,7 +404,7 @@ DeclareOperation("GraphvizContexts", [IsGraphvizGraph]); #! @BeginExampleSession #! @EndExampleSession DeclareOperation("GraphvizFindSubgraphRecursive", -[IsGraphvizGraph, IsObject]); +[IsGraphvizGraphDigraphOrContext, IsObject]); #! @BeginGroup #! @GroupTitle Getting Graphviz Edges @@ -423,10 +421,10 @@ DeclareOperation("GraphvizFindSubgraphRecursive", #! gap> GraphvizEdges(gv, "a", "b"); #! [ ] #! @EndExampleSession -DeclareOperation("GraphvizEdges", [IsGraphvizGraph]); +DeclareOperation("GraphvizEdges", [IsGraphvizGraphDigraphOrContext]); #! @Arguments graph, head, tail DeclareOperation("GraphvizEdges", -[IsGraphvizGraph, IsObject, IsObject]); +[IsGraphvizGraphDigraphOrContext, IsObject, IsObject]); #! @EndGroup #! @Arguments edge @@ -468,7 +466,7 @@ DeclareOperation("GraphvizTail", [IsGraphvizEdge]); #! #! @EndExampleSession DeclareOperation("GraphvizSetName", - [IsGraphvizGraph, IsObject]); + [IsGraphvizGraphDigraphOrContext, IsObject]); #! @Arguments graph, node #! @Returns a &GAPGraphviz; node object @@ -485,7 +483,7 @@ DeclareOperation("GraphvizSetName", #! #! @EndExampleSession DeclareOperation("GraphvizAddNode", - [IsGraphvizGraph, IsObject]); + [IsGraphvizGraphDigraphOrContext, IsObject]); #! @Arguments graph, head, tail #! @Returns a &GAPGraphviz; edge object @@ -508,7 +506,7 @@ DeclareOperation("GraphvizAddNode", #! #! @EndExampleSession DeclareOperation("GraphvizAddEdge", -[IsGraphvizGraph, IsObject, IsObject]); +[IsGraphvizGraphDigraphOrContext, IsObject, IsObject]); #! @BeginGroup #! @GroupTitle Adding Subgraphs @@ -521,9 +519,9 @@ DeclareOperation("GraphvizAddEdge", #! @BeginExampleSession #! @EndExampleSession DeclareOperation("GraphvizAddSubgraph", -[IsGraphvizGraph, IsObject]); +[IsGraphvizGraphDigraphOrContext, IsObject]); #! @Arguments graph -DeclareOperation("GraphvizAddSubgraph", [IsGraphvizGraph]); +DeclareOperation("GraphvizAddSubgraph", [IsGraphvizGraphDigraphOrContext]); #! @EndGroup #! @BeginGroup @@ -545,13 +543,13 @@ DeclareOperation("GraphvizAddSubgraph", [IsGraphvizGraph]); #! @BeginExampleSession #! @EndExampleSession DeclareOperation("GraphvizAddContext", -[IsGraphvizGraph, IsObject]); +[IsGraphvizGraphDigraphOrContext, IsObject]); #! @Arguments graph -DeclareOperation("GraphvizAddContext", [IsGraphvizGraph]); +DeclareOperation("GraphvizAddContext", [IsGraphvizGraphDigraphOrContext]); #! @EndGroup DeclareOperation("GraphvizAddComment", -[IsGraphvizGraph, IsString]); +[IsGraphvizGraphDigraphOrContext, IsString]); #! @Arguments graph, node #! @Returns a &GAPGraphviz; graph @@ -570,7 +568,7 @@ DeclareOperation("GraphvizAddComment", #! #! @EndExampleSession DeclareOperation("GraphvizRemoveNode", -[IsGraphvizGraph, IsObject]); +[IsGraphvizGraphDigraphOrContext, IsObject]); #! @Arguments graph, predicate #! @Returns a &GAPGraphviz; graph @@ -578,7 +576,7 @@ DeclareOperation("GraphvizRemoveNode", #! @BeginExampleSession #! @EndExampleSession DeclareOperation("GraphvizFilterEdges", -[IsGraphvizGraph, IsFunction]); +[IsGraphvizGraphDigraphOrContext, IsFunction]); #! @Arguments graph, head_id, tail_id #! @Returns a &GAPGraphviz; graph @@ -594,7 +592,7 @@ DeclareOperation("GraphvizFilterEdges", #! #! @EndExampleSession DeclareOperation("GraphvizRemoveEdges", -[IsGraphvizGraph, IsObject, IsObject]); +[IsGraphvizGraphDigraphOrContext, IsObject, IsObject]); #! @Subsection Modifying object attributes #! Operations for modifying attributes. @@ -652,7 +650,7 @@ DeclareOperation("GraphvizRemoveAttr", [IsGraphvizObject, IsObject]); #! @Description The &DOT; source for the graph argument. #! @BeginExampleSession #! @EndExampleSession -DeclareOperation("AsString", [IsGraphvizGraph]); +DeclareOperation("AsString", [IsGraphvizGraphDigraphOrContext]); #! @Arguments obj #! @Returns a &GAPGraphviz; object @@ -673,7 +671,7 @@ DeclareOperation("Graphviz", [IsObject]); #! @BeginExampleSession #! @EndExampleSession DeclareOperation("GraphvizSetNodeColors", -[IsGraphvizGraph, IsList]); +[IsGraphvizGraphDigraphOrContext, IsList]); #! @Arguments graph, labels #! @Returns a &GAPGraphviz; object @@ -686,7 +684,7 @@ DeclareOperation("GraphvizSetNodeColors", #! @BeginExampleSession #! @EndExampleSession DeclareOperation("GraphvizSetNodeLabels", -[IsGraphvizGraph, IsList]); +[IsGraphvizGraphDigraphOrContext, IsList]); #! @Arguments color #! @Returns true or false @@ -738,6 +736,6 @@ DeclareGlobalFunction("ErrorIfNotValidColor"); #! viewer it uses. At level 2, it reports each program it runs with its #! arguments. At level 3, it reports where it found each program, and #! +#! Label="for IsGraphvizGraphDigraphOrContext, IsObject, IsObject"/> #! reports the nodes it adds. DeclareInfoClass("InfoGraphviz"); diff --git a/gap/dot.gi b/gap/dot.gi index 435a2ff..d5305bd 100644 --- a/gap/dot.gi +++ b/gap/dot.gi @@ -13,20 +13,7 @@ ############################################################################# InstallMethod(GraphvizGraph, "for a string", [IsString], -name -> GV_Graph(name, false)); - # return Objectify(GV_GraphType, - # rec( - # Name := name, - # Subgraphs := rec(), - # Contexts := rec(), - # Nodes := rec(), - # Edges := [], - # Attrs := rec(graph := rec(), - # edge := rec(), - # node := rec()), - # Parent := fail, - # Idx := 1, - # Counter := 1)); +name -> GV_GraphOrDigraph(name, IsGraphvizGraph)); InstallMethod(GraphvizGraph, "for an object", [IsObject], obj -> GraphvizGraph(String(obj))); @@ -34,7 +21,7 @@ obj -> GraphvizGraph(String(obj))); InstallMethod(GraphvizGraph, "for no args", [], {} -> GraphvizGraph("")); InstallMethod(GraphvizDigraph, "for a string", [IsString], -name -> GV_Graph(name, true)); +name -> GV_GraphOrDigraph(name, IsGraphvizDigraph)); InstallMethod(GraphvizDigraph, "for an object", [IsObject], obj -> GraphvizDigraph(String(obj))); @@ -52,7 +39,7 @@ InstallMethod(PrintString, "for a graphviz edge", [IsGraphvizEdge], e -> StringFormatted("", GraphvizName(e))); InstallMethod(PrintString, "for a graphviz (di)graph or context", -[IsGraphvizGraph], +[IsGraphvizGraphDigraphOrContext], function(g) local result, edges, nodes, kind; @@ -98,10 +85,10 @@ InstallMethod(GraphvizAttrs, "for a graphviz object", [IsGraphvizObject], x -> x!.Attrs); InstallMethod(GraphvizNodes, "for a graphviz (di)graph or context", -[IsGraphvizGraph], x -> x!.Nodes); +[IsGraphvizGraphDigraphOrContext], x -> x!.Nodes); InstallMethod(GraphvizNode, "for a graphviz (di)graph or context and object", -[IsGraphvizGraph, IsObject], +[IsGraphvizGraphDigraphOrContext, IsObject], function(gv, val) local graph; val := String(val); @@ -114,14 +101,14 @@ end); # FIXME the below only counts nodes in the root graph, not in its children InstallMethod(GraphvizNumberOfNodes, "for a graphviz (di)graph or context", -[IsGraphvizGraph], x -> Length(RecNames(GraphvizNodes(x)))); +[IsGraphvizGraphDigraphOrContext], x -> Length(RecNames(GraphvizNodes(x)))); InstallMethod(GraphvizEdges, "for a graphviz (di)graph or context", -[IsGraphvizGraph], x -> x!.Edges); +[IsGraphvizGraphDigraphOrContext], x -> x!.Edges); InstallMethod(GraphvizEdges, "for a graphviz (di)graph or context, object, and object", -[IsGraphvizGraph, IsObject, IsObject], +[IsGraphvizGraphDigraphOrContext, IsObject, IsObject], function(gv, head, tail) local nodes; @@ -145,10 +132,10 @@ function(gv, head, tail) end); InstallMethod(GraphvizSubgraphs, "for a graphviz (di)graph or context", -[IsGraphvizGraph], x -> x!.Subgraphs); +[IsGraphvizGraphDigraphOrContext], x -> x!.Subgraphs); InstallMethod(GraphvizContexts, "for a graphviz (di)graph or context", -[IsGraphvizGraph], x -> x!.Contexts); +[IsGraphvizGraphDigraphOrContext], x -> x!.Contexts); InstallMethod(GraphvizTail, "for a graphviz edge", [IsGraphvizEdge], x -> x!.Tail); @@ -168,13 +155,13 @@ InstallMethod(\=, "for graphviz edges", InstallMethod(GraphvizFindSubgraphRecursive, "for a graphviz (di)graph or context and a string", -[IsGraphvizGraph, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], {g, s} -> GV_GraphTreeSearch(g, v -> GraphvizName(v) = s and not IsGraphvizContext(v))); InstallMethod(GraphvizFindSubgraphRecursive, "for a graphviz (di)graph or context and a string", -[IsGraphvizGraph, IsObject], +[IsGraphvizGraphDigraphOrContext, IsObject], {g, o} -> GraphvizFindSubgraphRecursive(g, String(o))); ############################################################################# @@ -182,14 +169,14 @@ InstallMethod(GraphvizFindSubgraphRecursive, ############################################################################# InstallMethod(GraphvizSetName, "for a graphviz (di)graph or context and string", -[IsGraphvizGraph, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], function(x, name) x!.Name := name; return x; end); InstallMethod(GraphvizSetName, "for a graphviz (di)graph or context and string", -[IsGraphvizGraph, IsObject], +[IsGraphvizGraphDigraphOrContext, IsObject], {g, o} -> GraphvizSetName(g, String(o))); ############################################################################# @@ -330,7 +317,7 @@ function(gv, val) end); InstallMethod(GraphvizAddNode, "for a graphviz (di)graph or context and string", -[IsGraphvizGraph, IsGraphvizNode], +[IsGraphvizGraphDigraphOrContext, IsGraphvizNode], function(gv, name) # gaplint: disable=unused-func-args ErrorNoReturn("it is not currently possible to add Graphviz node ", "objects directly to Graphviz graphs or digraphs, use ", @@ -343,7 +330,7 @@ end); InstallMethod(GraphvizAddEdge, "for a graphviz (di)graph or context and two graphviz nodes", -[IsGraphvizGraph, IsGraphvizNode, IsGraphvizNode], +[IsGraphvizGraphDigraphOrContext, IsGraphvizNode, IsGraphvizNode], function(x, head, tail) local edge, root_x, root_head, root_tail; @@ -376,7 +363,7 @@ end); InstallMethod(GraphvizAddEdge, "for a graphviz (di)graph or context and two strings", -[IsGraphvizGraph, IsString, IsString], +[IsGraphvizGraphDigraphOrContext, IsString, IsString], function(x, head, tail) local head_node, tail_node; @@ -401,7 +388,7 @@ end); InstallMethod(GraphvizAddEdge, "for a graphviz (di)graph or context and two objects", -[IsGraphvizGraph, IsObject, IsObject], +[IsGraphvizGraphDigraphOrContext, IsObject, IsObject], function(gv, head, tail) local head_name, tail_name; if IsGraphvizNode(head) then @@ -423,7 +410,7 @@ end); InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph or context and string", -[IsGraphvizGraph, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], function(gv, name) local subgraphs, subgraph; @@ -441,18 +428,18 @@ end); InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph or context and an object", -[IsGraphvizGraph, IsObject], +[IsGraphvizGraphDigraphOrContext, IsObject], {g, o} -> GraphvizAddSubgraph(g, String(o))); InstallMethod(GraphvizAddSubgraph, "for a graphviz (di)graph or context", -[IsGraphvizGraph], +[IsGraphvizGraphDigraphOrContext], graph -> GraphvizAddSubgraph(graph, StringFormatted("no_name_{}", GV_GetCounter(graph)))); InstallMethod(GraphvizAddContext, "for a graphviz (di)graph or context and a string", -[IsGraphvizGraph, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], function(graph, name) local contexts, ctx; @@ -470,24 +457,24 @@ end); InstallMethod(GraphvizAddContext, "for a graphviz (di)graph or context", -[IsGraphvizGraph], +[IsGraphvizGraphDigraphOrContext], g -> GraphvizAddContext(g, StringFormatted("no_name_{}", GV_GetCounter(g)))); InstallMethod(GraphvizAddContext, "for a graphviz (di)graph or context and an object", -[IsGraphvizGraph, IsObject], +[IsGraphvizGraphDigraphOrContext, IsObject], {g, o} -> GraphvizAddContext(g, String(o))); # Removal InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph or context and node", -[IsGraphvizGraph, IsGraphvizNode], +[IsGraphvizGraphDigraphOrContext, IsGraphvizNode], {g, node} -> GraphvizRemoveNode(g, GraphvizName(node))); InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph or context and a string", -[IsGraphvizGraph, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], function(g, name) local nodes; nodes := GraphvizNodes(g); @@ -514,12 +501,12 @@ end); InstallMethod(GraphvizRemoveNode, "for a graphviz (di)graph or context and a string", -[IsGraphvizGraph, IsObject], +[IsGraphvizGraphDigraphOrContext, IsObject], {g, o} -> GraphvizRemoveNode(g, String(o))); InstallMethod(GraphvizFilterEdges, "for a graphviz (di)graph or context and edge filter", -[IsGraphvizGraph, IsFunction], +[IsGraphvizGraphDigraphOrContext, IsFunction], function(g, filter) local edge, idx, edges; @@ -538,7 +525,7 @@ end); InstallMethod(GraphvizRemoveEdges, "for a graphviz (di)graph or context, string, and string", -[IsGraphvizGraph, IsString, IsString], +[IsGraphvizGraphDigraphOrContext, IsString, IsString], function(g, hn, tn) local lh, lt, len; @@ -576,26 +563,9 @@ end); InstallMethod(GraphvizRemoveEdges, "for a graphviz (di)graph or context, object, and object", -[IsGraphvizGraph, IsObject, IsObject], +[IsGraphvizGraphDigraphOrContext, IsObject, IsObject], {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); - attr := String(attr); - - if not IsBound(attrs.(attr)) then - ErrorFormatted("the 2nd argument (attribute name) \"{}\" ", - "is not set on the provided object.", - attr); - fi; - - Unbind(attrs.(attr)); - return obj; -end); - ############################################################################# # Stringify ############################################################################# @@ -605,20 +575,20 @@ end); # immutable, and hence cannot be changed after it is first set. InstallMethod(AsString, "for a graphviz (di)graph", -[IsGraphvizGraph], graph -> GV_StringifyGraph(graph, false)); +[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", -# [IsGraphvizGraph], +# [IsGraphvizGraphDigraphOrContext], # function(gv) # Print(String(gv)); # end); InstallMethod(GraphvizSetNodeLabels, "for a graphviz (di)graph or context and list of colors", -[IsGraphvizGraph, IsList], +[IsGraphvizGraphDigraphOrContext, IsList], function(gv, labels) local nodes, i; if GraphvizNumberOfNodes(gv) <> Size(labels) then @@ -640,7 +610,7 @@ end); InstallMethod(GraphvizSetNodeColors, "for a graphviz (di)graph or context and list of colors", -[IsGraphvizGraph, IsList], +[IsGraphvizGraphDigraphOrContext, IsList], function(gv, colors) local nodes, i; diff --git a/gap/gv.gd b/gap/gv.gd index b46ffc7..8a12abd 100644 --- a/gap/gv.gd +++ b/gap/gv.gd @@ -11,58 +11,50 @@ ## This file contains declarations of the internal/private functions for the ## graphviz package. -DeclareOperation("GV_GetCounter", [IsGraphvizGraph]); -DeclareOperation("GV_IncCounter", [IsGraphvizGraph]); +DeclareOperation("GV_GetCounter", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GV_IncCounter", [IsGraphvizGraphDigraphOrContext]); -DeclareOperation("GV_StringifyGraphHead", [IsGraphvizGraph]); -DeclareOperation("GV_StringifyDigraphHead", [IsGraphvizGraph]); -DeclareOperation("GV_StringifySubgraphHead", [IsGraphvizGraph]); -DeclareOperation("GV_StringifyContextHead", [IsGraphvizGraph]); +DeclareOperation("GV_StringifyGraphHead", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GV_StringifyDigraphHead", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GV_StringifySubgraphHead", [IsGraphvizGraphDigraphOrContext]); +DeclareOperation("GV_StringifyContextHead", [IsGraphvizGraphDigraphOrContext]); DeclareOperation("GV_StringifyNode", [IsGraphvizNode]); -DeclareOperation("GV_StringifyGraphAttrs", [IsGraphvizGraph]); +DeclareOperation("GV_StringifyGraphAttrs", [IsGraphvizGraphDigraphOrContext]); DeclareOperation("GV_StringifyNodeEdgeAttrs", [IsRecord]); DeclareOperation("GV_StringifyGraph", - [IsGraphvizGraph, IsBool]); + [IsGraphvizGraphDigraphOrContext, IsBool]); -DeclareOperation("GV_Node", [IsGraphvizGraph, IsString]); +DeclareOperation("GV_Node", [IsGraphvizGraphDigraphOrContext, IsString]); DeclareOperation("GV_Edge", -[IsGraphvizGraph, IsGraphvizNode, IsGraphvizNode]); -DeclareOperation("GV_Graph", [IsString, IsBool]); -DeclareOperation("GV_Subgraph", [IsGraphvizGraph, IsString]); -DeclareOperation("GV_Context", [IsGraphvizGraph, IsString]); +[IsGraphvizGraphDigraphOrContext, IsGraphvizNode, IsGraphvizNode]); +DeclareOperation("GV_GraphOrDigraph", [IsString, IsFunction]); +DeclareAttribute("GV_Filter", IsGraphvizGraph); +DeclareAttribute("GV_Filter", IsGraphvizDigraph); +DeclareOperation("GV_Subgraph", [IsGraphvizGraphDigraphOrContext, IsString]); +DeclareOperation("GV_Context", [IsGraphvizGraphDigraphOrContext, IsString]); -DeclareOperation("GV_HasNode", [IsGraphvizGraph, IsObject]); +DeclareOperation("GV_HasNode", [IsGraphvizGraphDigraphOrContext, IsObject]); DeclareOperation("GV_GetParent", [IsGraphvizObject]); DeclareOperation("GV_GraphTreeSearch", -[IsGraphvizGraph, IsFunction]); +[IsGraphvizGraphDigraphOrContext, IsFunction]); DeclareOperation("GV_GraphSearchChildren", -[IsGraphvizGraph, IsFunction]); +[IsGraphvizGraphDigraphOrContext, IsFunction]); DeclareOperation("GV_FindGraphWithNode", -[IsGraphvizGraph, IsString]); +[IsGraphvizGraphDigraphOrContext, IsString]); DeclareOperation("GV_GetRoot", [IsGraphvizObject]); DeclareOperation("GV_EnclosingNonContext", [IsGraphvizObject]); DeclareOperation("GV_AddNode", -[IsGraphvizGraph, IsGraphvizNode]); +[IsGraphvizGraphDigraphOrContext, IsGraphvizNode]); DeclareOperation("GV_AddEdge", -[IsGraphvizGraph, IsGraphvizEdge]); +[IsGraphvizGraphDigraphOrContext, IsGraphvizEdge]); DeclareOperation("GV_GetIdx", [IsGraphvizObject]); -DeclareOperation("GV_ConstructHistory", [IsGraphvizGraph]); +DeclareOperation("GV_ConstructHistory", [IsGraphvizGraphDigraphOrContext]); DeclareGlobalFunction("GV_IsValidColor"); DeclareGlobalFunction("GV_ErrorIfNotNodeColoring"); DeclareGlobalFunction("GV_ErrorIfNotValidLabel"); -# TODO move to dot? and make public? -BindGlobal("GV_ObjectFamily", - NewFamily("GV_ObjectFamily", IsGraphvizObject)); - -# TODO move to dot? and make public? -BindGlobal("GV_GraphType", NewType(GV_ObjectFamily, - IsGraphvizGraph and - IsComponentObjectRep and - IsAttributeStoringRep)); - BindGlobal("GV_ValidColorNames", ["aliceblue", "antiquewhite", "antiquewhite1", "antiquewhite2", "antiquewhite3", "antiquewhite4", "aquamarine", "aquamarine1", "aquamarine2", diff --git a/gap/gv.gi b/gap/gv.gi index ed3d08a..258b38c 100644 --- a/gap/gv.gi +++ b/gap/gv.gi @@ -14,22 +14,31 @@ # Family + type ############################################################################### +BindGlobal("GV_ObjectFamily", + NewFamily("GV_ObjectFamily", IsGraphvizObject)); + BindGlobal("GV_NodeType", NewType(GV_ObjectFamily, - IsGraphvizNode and - IsComponentObjectRep and - IsAttributeStoringRep)); + IsGraphvizNode and + IsComponentObjectRep and + IsAttributeStoringRep)); BindGlobal("GV_EdgeType", NewType(GV_ObjectFamily, - IsGraphvizEdge and - IsComponentObjectRep and - IsAttributeStoringRep)); + IsGraphvizEdge and + IsComponentObjectRep and + IsAttributeStoringRep)); + +BindGlobal("GV_GraphDigraphOrContextType", + NewType(GV_ObjectFamily, + IsGraphvizGraphDigraphOrContext and + IsComponentObjectRep and + IsAttributeStoringRep)); ############################################################################### # Constructors etc ############################################################################### InstallMethod(GV_Node, "for a string", -[IsGraphvizGraph, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], function(graph, name) local out; Assert(0, not IsEmpty(name)); @@ -44,7 +53,7 @@ function(graph, name) end); InstallMethod(GV_Edge, "for two graphviz nodes", -[IsGraphvizGraph, IsGraphvizNode, IsGraphvizNode], +[IsGraphvizGraphDigraphOrContext, IsGraphvizNode, IsGraphvizNode], function(graph, head, tail) local out; @@ -64,37 +73,40 @@ end); # Graph constructors -InstallMethod(GV_Graph, "for a string and a bool", [IsString, IsBool], -function(name, directed) +InstallMethod(GV_GraphOrDigraph, +"for a string and a filter", [IsString, IsFunction], +function(name, filt) local result; + Assert(0, filt = IsGraphvizGraph or filt = IsGraphvizDigraph); result := Objectify( - GV_GraphType, + GV_GraphDigraphOrContextType, rec( - # Note that the following aren't attributes because we require them to be - # mutable. + # Note that the following aren't attributes because we require them to be + # mutable. Name := name, Subgraphs := rec(), Contexts := rec(), Nodes := rec(), Edges := [], - Attrs := [], + Attrs := rec(graph := rec(), + edge := rec(), + node := rec()), Parent := fail, Idx := 1, Counter := 1)); - if directed then - SetFilterObj(result, IsGraphvizDigraph); - fi; + SetFilterObj(result, filt); + SetGV_Filter(result, filt); return result; end); InstallMethod(GV_Subgraph, "for a graphviz graph and a string", -[IsGraphvizGraph, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], function(parent, name) local out; - out := GV_Graph(name, IsGraphvizDigraph(parent)); + out := GV_GraphOrDigraph(name, GV_Filter(parent)); out!.Parent := parent; out!.Idx := GV_GetCounter(parent); @@ -104,7 +116,7 @@ end); InstallMethod(GV_Context, "for a string and a string", -[IsGraphvizGraph, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], function(parent, name) local out; out := GV_Subgraph(parent, name); @@ -116,20 +128,20 @@ end); InstallMethod(GV_IncCounter, "for a graphviz graph", -[IsGraphvizGraph], +[IsGraphvizGraphDigraphOrContext], function(x) x!.Counter := x!.Counter + 1; end); InstallMethod(GV_GetCounter, "for a graphviz graph", -[IsGraphvizGraph], +[IsGraphvizGraphDigraphOrContext], x -> x!.Counter); # Nodes InstallMethod(GV_HasNode, "for a graphviz graph", -[IsGraphvizGraph, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], {g, name} -> name in RecNames(GraphvizNodes(g))); InstallMethod(GV_GetParent, @@ -138,7 +150,7 @@ InstallMethod(GV_GetParent, InstallMethod(GV_GraphTreeSearch, "for a graphviz graph and a predicate", -[IsGraphvizGraph, IsFunction], +[IsGraphvizGraphDigraphOrContext, IsFunction], function(graph, pred) local seen, to_visit, g, key, subgraph, context, parent; seen := [graph]; @@ -172,7 +184,7 @@ function(graph, pred) # add parent if not visited parent := GV_GetParent(g); - if not IsGraphvizGraph(parent) then + if not IsGraphvizGraphDigraphOrContext(parent) then continue; fi; if not ForAny(seen, s -> IsIdenticalObj(s, parent)) then @@ -187,7 +199,7 @@ end); # tree search only on the children of the graph InstallMethod(GV_GraphSearchChildren, "for a graphviz graph and a predicate", -[IsGraphvizGraph, IsFunction], +[IsGraphvizGraphDigraphOrContext, IsFunction], function(graph, pred) local _, curr, queue, count, nexts, key; @@ -221,7 +233,7 @@ end); InstallMethod(GV_FindGraphWithNode, "for a graphviz graph and a node", -[IsGraphvizGraph, IsString], +[IsGraphvizGraphDigraphOrContext, IsString], {g, n} -> GV_GraphTreeSearch(g, v -> IsBound(GraphvizNodes(v).(n)))); InstallMethod(GV_GetRoot, @@ -248,7 +260,7 @@ end); InstallMethod(GV_AddNode, "for a graphviz graph and node", -[IsGraphvizGraph, IsGraphvizNode], +[IsGraphvizGraphDigraphOrContext, IsGraphvizNode], function(x, node) local name, nodes; name := GraphvizName(node); @@ -259,7 +271,7 @@ end); InstallMethod(GV_AddEdge, "for a graphviz graph and edge", -[IsGraphvizGraph, IsGraphvizEdge], +[IsGraphvizGraphDigraphOrContext, IsGraphvizEdge], function(x, edge) Add(x!.Edges, edge); return x; @@ -270,21 +282,20 @@ end); ############################################################################### # @ Return DOT graph head line. -InstallMethod(GV_StringifyGraphHead, "for a string", -[IsGraphvizGraph], +InstallMethod(GV_StringifyGraphHead, "for a string", [IsGraphvizGraph], graph -> StringFormatted("graph {} {{\n", GraphvizName(graph))); # @ Return DOT digraph head line. -InstallMethod(GV_StringifyDigraphHead, "for a string", [IsGraphvizGraph], +InstallMethod(GV_StringifyDigraphHead, "for a string", [IsGraphvizDigraph], graph -> StringFormatted("digraph {} {{\n", GraphvizName(graph))); # @ Return DOT subgraph head line. InstallMethod(GV_StringifySubgraphHead, "for a string", -[IsGraphvizGraph], +[IsGraphvizGraphDigraphOrContext], graph -> StringFormatted("subgraph {} {{\n", GraphvizName(graph))); # @ Return DOT subgraph head line. -InstallMethod(GV_StringifyContextHead, "for a string", [IsGraphvizGraph], +InstallMethod(GV_StringifyContextHead, "for a string", [IsGraphvizContext], graph -> StringFormatted("// {} context \n{{\n", GraphvizName(graph))); BindGlobal("GV_StringifyNodeName", @@ -377,7 +388,7 @@ x -> x!.Idx); InstallMethod(GV_ConstructHistory, "for a graphviz graph", -[IsGraphvizGraph], +[IsGraphvizGraphDigraphOrContext], function(graph) local ctxs, nodes, edges, subs, ctxs_hist, node_hist, edge_hist, subs_hist, hist; @@ -401,7 +412,7 @@ end); InstallMethod(GV_StringifyGraph, "for a graphviz graph and a string", -[IsGraphvizGraph, IsBool], +[IsGraphvizGraphDigraphOrContext, IsBool], function(graph, is_subgraph) local result, record, type, obj; @@ -434,7 +445,7 @@ function(graph, is_subgraph) # Add child graphviz objects for obj in GV_ConstructHistory(graph) do - if IsGraphvizGraph(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.gd b/gap/splash.gd index c9eec0a..debd390 100644 --- a/gap/splash.gd +++ b/gap/splash.gd @@ -23,7 +23,7 @@ #! #! #! a &GAPGraphviz; graph or digraph, which is converted into a string -#! using ; +#! using ; #! #! #! a string containing a valid dot or &LaTeX; document. diff --git a/gap/splash.gi b/gap/splash.gi index 5dee50c..0dee649 100644 --- a/gap/splash.gi +++ b/gap/splash.gi @@ -42,10 +42,10 @@ function(arg...) if IsEmpty(arg) then ErrorNoReturn("the must be at least 1 argument, found none"); - elif not IsString(arg[1]) and not IsGraphvizGraph(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 IsGraphvizGraph(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