From d7a703b4e8f27d53002fe7ab2542438ff787ad3a Mon Sep 17 00:00:00 2001 From: Michael Torpey Date: Wed, 23 Jan 2019 17:11:48 +0000 Subject: [PATCH 1/3] io: change to rows-based digraph6 format as in nauty --- gap/io.gi | 43 ++++++++++++++++++++++++++++++++++--------- tst/standard/io.tst | 2 +- tst/testinstall.tst | 9 +++++++++ 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/gap/io.gi b/gap/io.gi index fd18c9bbd..84f3799d6 100644 --- a/gap/io.gi +++ b/gap/io.gi @@ -812,7 +812,12 @@ end); InstallMethod(DigraphFromDigraph6String, "for a string", [IsString], function(s) - local list, i, n, start, range, source, pos, len, j, bpos, tabpos; + local legacy, list, n, start, i, range, source, pos, len, j, bpos, tabpos; + # NOTE: this package originally used a version of digraph6 that reads down + # the columns of an adjacency matrix, and appends a '+' to the start. This + # has been replaced by the Nauty standard, which reads across the rows of the + # matrix, and appends a '&' to the start. For backwards compatibility, this + # now accepts both formats, sending an info warning if the old format is used. s := Chomp(s); # Check non-emptiness @@ -821,8 +826,18 @@ function(s) "the input string should be non-empty,"); fi; - # Check for the special '+' character - if s[1] <> '+' then + # Check for the special '&' character (or the deprecated '+') + if s[1] = '&' then + legacy := false; + elif s[1] = '+' then + legacy := true; + Info(InfoDigraphs, 1, "Digraph6 strings beginning with '+' use an old"); + Info(InfoDigraphs, 1, "specification of the Digraph6 format that is"); + Info(InfoDigraphs, 1, "incompatible with the present standard. They can"); + Info(InfoDigraphs, 1, "still be read by the Digraphs package, but are"); + Info(InfoDigraphs, 1, "unlikely to be recognised by other programs."); + Info(InfoDigraphs, 1, "Please consider re-encoding with the new format."); + else ErrorNoReturn("Digraphs: DigraphFromDigraph6String: usage,\n", "the input string is not in valid digraph6 format,"); fi; @@ -867,8 +882,8 @@ function(s) i := i / 2; else tabpos := pos + 6 - bpos; - source[len] := (tabpos - 1) mod n + 1; - range[len] := (tabpos - source[len]) / n + 1; + range[len] := (tabpos - 1) mod n + 1; + source[len] := (tabpos - range[len]) / n + 1; len := len + 1; i := (i - 1) / 2; fi; @@ -877,6 +892,10 @@ function(s) pos := pos + 6; od; + if legacy then # source and range are reversed + return Digraph(rec(nrvertices := n, range := source, source := range)); + fi; + return Digraph(rec(nrvertices := n, range := range, source := source)); end); @@ -1539,12 +1558,18 @@ InstallMethod(Digraph6String, "for a digraph", [IsDigraph], function(digraph) local list, adj, n, lenlist, tablen, blist, i, j, pos, block; + # NOTE: this package originally used a version of digraph6 that reads down + # the columns of an adjacency matrix, and appends a '+' to the start. This + # has been replaced by the Nauty standard, which reads across the rows of the + # matrix, and appends a '&' to the start. The old '+' format can be read by + # DigraphFromDigraph6String, but can no longer be written by this function. + list := []; adj := OutNeighbours(digraph); n := Length(DigraphVertices(digraph)); - # First write the special character '+' - Add(list, -20); + # First write the special character '&' + Add(list, -25); # Now write the number of vertices lenlist := DIGRAPHS_Graph6Length(n); @@ -1555,12 +1580,12 @@ function(digraph) fi; Append(list, lenlist); - # Find adjacencies (non-directed) + # Find adjacencies tablen := n ^ 2; blist := BlistList([1 .. tablen + 6], []); for i in DigraphVertices(digraph) do for j in adj[i] do - blist[i + n * (j - 1)] := true; + blist[j + n * (i - 1)] := true; od; od; diff --git a/tst/standard/io.tst b/tst/standard/io.tst index 0e2085b58..a53e06701 100644 --- a/tst/standard/io.tst +++ b/tst/standard/io.tst @@ -118,7 +118,7 @@ gap> DigraphFromSparse6String(str); gap> gr := Digraph([[5], [1, 2, 5], [1], [2], [4]]); gap> str := Digraph6String(gr); -"+DWg?[?" +"&DBeA@?" gap> DigraphFromDigraph6String(str); gap> gr := Digraph(231, [1 .. 100], [1 .. 100] * 0 + 200); diff --git a/tst/testinstall.tst b/tst/testinstall.tst index 1b1a44254..83cc784d4 100644 --- a/tst/testinstall.tst +++ b/tst/testinstall.tst @@ -327,6 +327,15 @@ gap> not DIGRAPHS_NautyAvailable or > NautyCanonicalLabelling(NullDigraph(0), []) = (); true +# Issue 158: Digraph6 file format incompatibility (with nauty) +gap> SortedList(DigraphEdges(DigraphFromDigraph6String("&DI?AO?")) - 1); +[ [ 0, 2 ], [ 0, 4 ], [ 3, 1 ], [ 3, 4 ] ] +gap> str := "&O?????C??O?@??C??O?@??C??O?@??C??O?@??C??o??";; +gap> gr := DigraphFromDigraph6String(str); + +gap> str = Digraph6String(gr); +true + # DIGRAPHS_UnbindVariables gap> Unbind(gr2); gap> Unbind(gr); From d56cd067dca9e8b429a3186462517c9a5e4572e2 Mon Sep 17 00:00:00 2001 From: Michael Torpey Date: Wed, 23 Jan 2019 17:12:33 +0000 Subject: [PATCH 2/3] doc: use new digraph6 format in examples --- doc/digraph.xml | 10 +++++----- doc/io.xml | 6 +++--- doc/oper.xml | 2 +- doc/orbits.xml | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/digraph.xml b/doc/digraph.xml index 4c05f9adc..f8f02f5ec 100644 --- a/doc/digraph.xml +++ b/doc/digraph.xml @@ -193,7 +193,7 @@ true old ones, inherit their labels from their parents. gr := DigraphFromDigraph6String("+D[NGc_"); +gap> gr := DigraphFromDigraph6String("&DHUEe_"); gap> DigraphVertexLabels(gr); [ 1 .. 5 ] @@ -234,7 +234,7 @@ gap> DigraphVertexLabels(gr); old ones, inherit their labels from their parents. gr := DigraphFromDigraph6String("+D[NGc_"); +gap> gr := DigraphFromDigraph6String("&DHUEe_"); gap> DigraphVertexLabel(gr, 3); 3 @@ -284,7 +284,7 @@ gap> DigraphVertexLabel(gr, 2); from old ones, inherit their labels from their parents. gr := DigraphFromDigraph6String("+D[NGc_"); +gap> gr := DigraphFromDigraph6String("&DHUEe_"); gap> DigraphEdgeLabels(gr); [ [ 1 ], [ 1, 1, 1 ], [ 1 ], [ 1, 1, 1 ], [ 1, 1, 1 ] ] @@ -322,7 +322,7 @@ gap> OutNeighbours(gr); See also . gr := DigraphFromDigraph6String("+D[NGc_"); +gap> gr := DigraphFromDigraph6String("&DHUEe_"); gap> DigraphEdgeLabel(gr, 3, 1); 1 @@ -350,7 +350,7 @@ gap> gr := Digraph(["a", "b", "c"], ["a", "b", "b"], ["b", "c", "a"]); gap> IsMultiDigraph(gr); false -gap> gr := DigraphFromDigraph6String("+Bug"); +gap> gr := DigraphFromDigraph6String("&Bug"); gap> IsDuplicateFree(DigraphEdges(gr)); true diff --git a/doc/io.xml b/doc/io.xml index e89c2442a..6654da9c8 100644 --- a/doc/io.xml +++ b/doc/io.xml @@ -177,11 +177,11 @@ gap> DigraphFromGraph6String("C]"); gap> DigraphFromGraph6String("H?AAEM{"); -gap> DigraphFromDigraph6String("+?"); +gap> DigraphFromDigraph6String("&?"); -gap> DigraphFromDigraph6String("+CQFG"); +gap> DigraphFromDigraph6String("&CQFG"); -gap> DigraphFromDigraph6String("+IM[SrKLc~lhesbU[F_"); +gap> DigraphFromDigraph6String("&IM[SrKLc~lhesbU[F_"); gap> DigraphFromDiSparse6String(".CaWBGA?b"); diff --git a/doc/oper.xml b/doc/oper.xml index b3fb32593..31ff1ad3a 100644 --- a/doc/oper.xml +++ b/doc/oper.xml @@ -933,7 +933,7 @@ od; between the vertices of a digraph is shown below:

gr := DigraphFromDigraph6String("+ECGOElR"); +gap> gr := DigraphFromDigraph6String("&EAHQeDB"); gap> func := function(mat, i, j, k) > if mat[i][k] <> -1 and mat[k][j] <> -1 then diff --git a/doc/orbits.xml b/doc/orbits.xml index 740042603..b71db75bd 100644 --- a/doc/orbits.xml +++ b/doc/orbits.xml @@ -136,7 +136,7 @@ gap> digraph := CayleyDigraph(AlternatingGroup(4)); gap> DigraphOrbitReps(digraph); [ 1 ] -gap> digraph := DigraphFromDigraph6String("+I?OGg????A?Ci_o_@?"); +gap> digraph := DigraphFromDigraph6String("&IGO??S?`?_@?a?CK?O"); gap> DigraphOrbitReps(digraph); [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] @@ -157,7 +157,7 @@ gap> DigraphOrbitReps(digraph); vertices of digraph. digraph := DigraphFromDigraph6String("+GUIQQWWXHHPg"); +gap> digraph := DigraphFromDigraph6String("&GYHPQgWTIIPW"); gap> DigraphStabilizer(digraph, 8); Group(()) @@ -215,12 +215,12 @@ gap> DigraphGroup(digraph); Group(()) gap> RepresentativeOutNeighbours(digraph); [ [ 2, 1, 3, 4, 5 ], [ 3, 5 ], [ 2 ], [ 1, 2, 3, 5 ], [ 1, 2, 3, 4 ] ] -gap> digraph := DigraphFromDigraph6String("+GUIQQWWXHHPg"); +gap> digraph := DigraphFromDigraph6String("&GYHPQgWTIIPW"); gap> DigraphGroup(digraph); Group([ (1,2)(3,4)(5,6)(7,8), (1,3,2,4)(5,7,6,8), (1,5)(2,6)(3,8) (4,7) ]) -gap> RepresentativeOutNeighbours(digraph); +gap> Set(RepresentativeOutNeighbours(digraph), Set); [ [ 2, 3, 5 ] ]]]> From 60fa8b79d07d78eccbe695177e10dbcbe81935fd Mon Sep 17 00:00:00 2001 From: Michael Torpey Date: Wed, 23 Jan 2019 17:13:03 +0000 Subject: [PATCH 3/3] tests: use new digraph6 format in most instances --- tst/standard/attr.tst | 4 ++-- tst/standard/cliques.tst | 4 ++-- tst/standard/display.tst | 4 ++-- tst/standard/grahom.tst | 4 ++-- tst/standard/io.tst | 4 +++- tst/standard/oper.tst | 31 ++++++++++++++++--------------- 6 files changed, 27 insertions(+), 24 deletions(-) diff --git a/tst/standard/attr.tst b/tst/standard/attr.tst index 04481e2ce..50114c989 100644 --- a/tst/standard/attr.tst +++ b/tst/standard/attr.tst @@ -1293,7 +1293,7 @@ gap> ChromaticNumber(DigraphDisjointUnion(CompleteDigraph(1), > Digraph([[2], [4], [1, 2], [3], [1, 2, 3]]))); 4 gap> gr := DigraphFromDigraph6String(Concatenation( -> "+l??O?C?A_@???CE????GAAG?C??M?????@_?OO??G??@?IC???_C?G?o??C?AO???c_??A?", +> "&l??O?C?A_@???CE????GAAG?C??M?????@_?OO??G??@?IC???_C?G?o??C?AO???c_??A?", > "A?S???OAA???OG???G_A??C?@?cC????_@G???S??C_?C???[??A?A?OA?O?@?A?@A???GGO", > "??`?_O??G?@?A??G?@AH????AA?O@??_??b???Cg??C???_??W?G????d?G?C@A?C???GC?W", > "?????K???__O[??????O?W???O@??_G?@?CG??G?@G?C??@G???_Q?O?O?c???OAO?C??C?G", @@ -1425,7 +1425,7 @@ gap> IsUndirectedSpanningForest(gr, forest); true gap> gr = forest; true -gap> gr := DigraphFromDigraph6String("+I?PIMAQc@A?W?ADPP?"); +gap> gr := DigraphFromDigraph6String("&IG@qqW?HO?BSQGA?CG"); gap> IsStronglyConnectedDigraph(gr); true diff --git a/tst/standard/cliques.tst b/tst/standard/cliques.tst index e4b0cad56..06d98ded9 100644 --- a/tst/standard/cliques.tst +++ b/tst/standard/cliques.tst @@ -219,7 +219,7 @@ gap> DigraphMaximalIndependentSets(gr); gap> gr := CompleteDigraph(2);; gap> DigraphMaximalIndependentSets(gr); [ [ 1 ], [ 2 ] ] -gap> gr := DigraphFromDigraph6String("+FWSK?[SK_?"); +gap> gr := DigraphFromDigraph6String("&FWsK?WSKC?"); gap> DigraphMaximalIndependentSetsReps(gr); [ [ 1, 4 ], [ 1, 5 ], [ 2, 5, 7 ] ] @@ -307,7 +307,7 @@ gap> DigraphMaximalCliques(gr); gap> gr := EmptyDigraph(1);; gap> DigraphMaximalCliques(gr); [ [ 1 ] ] -gap> gr := DigraphFromDigraph6String("+D[]]]?"); +gap> gr := DigraphFromDigraph6String("&DNNNF?"); gap> DigraphMaximalCliquesReps(gr); [ [ 1, 3 ] ] diff --git a/tst/standard/display.tst b/tst/standard/display.tst index c54988e75..c7171304c 100644 --- a/tst/standard/display.tst +++ b/tst/standard/display.tst @@ -179,8 +179,8 @@ node [shape=Mrecord, height=0.5, fixedsize=true]ranksep=1; 7 -> 5 8 -> 1 } -gap> gr := Concatenation("+XqD?OG???FbueZpzRKGC@?}]sr]nYXnNl[saOEGOgA@w|he?A?", -> "?}NyxnFlKvbueZpzrLGcHa??A?]NYx_?_GC??AJpzrnw~jm{]srO???_");; +gap> gr := Concatenation("&X_?_A]|^Vr[nHpmVcy~zy[A????_???G??B]nhtmvcwvJq\\^~", +> "|m??_AEx]Rb[nHo??__vJy[??A??O_aV~^Zb]njo???_???GZdxMLy}n_");; gap> gr := DigraphFromDigraph6String(gr);; gap> Print(DotPreorderDigraph(gr){[1 .. 94]}, "\n"); //dot diff --git a/tst/standard/grahom.tst b/tst/standard/grahom.tst index e5a7fc39e..7f98ad05b 100644 --- a/tst/standard/grahom.tst +++ b/tst/standard/grahom.tst @@ -976,7 +976,7 @@ IdentityTransformation gap> gr1 := ChainDigraph(2);; gap> MonomorphismsDigraphs(gr1, EmptyDigraph(1)); [ ] -gap> gr2 := DigraphFromDigraph6String("+DRZ?L?");; +gap> gr2 := DigraphFromDigraph6String("&DZTAW?");; gap> monos := MonomorphismsDigraphs(gr1, gr2); [ IdentityTransformation, Transformation( [ 1, 3, 3 ] ), Transformation( [ 1, 5, 3, 4, 5 ] ), Transformation( [ 2, 1 ] ), @@ -1001,7 +1001,7 @@ gap> gr1 := CompleteDigraph(2);; gap> gr2 := CompleteDigraph(3);; gap> EpimorphismsDigraphs(gr1, gr2); [ ] -gap> gr1 := DigraphFromDigraph6String("+IG????G??I??O?????");; +gap> gr1 := DigraphFromDigraph6String("&I@??HO???????A????");; gap> DigraphEpimorphism(gr1, gr2); Transformation( [ 1, 1, 2, 1, 1, 3, 1, 2, 1, 1 ] ) gap> epis := EpimorphismsDigraphsRepresentatives(gr1, gr2);; diff --git a/tst/standard/io.tst b/tst/standard/io.tst index a53e06701..2bff0731a 100644 --- a/tst/standard/io.tst +++ b/tst/standard/io.tst @@ -119,6 +119,8 @@ gap> gr := Digraph([[5], [1, 2, 5], [1], [2], [4]]); gap> str := Digraph6String(gr); "&DBeA@?" +gap> gr = DigraphFromDigraph6String("+DWg?[?"); # deprecated format +true gap> DigraphFromDigraph6String(str); gap> gr := Digraph(231, [1 .. 100], [1 .. 100] * 0 + 200); @@ -484,7 +486,7 @@ true gap> DigraphFromGraph6String("~llk"); Error, Digraphs: DigraphFromGraph6String: usage, the input string is not in valid graph6 format, -gap> DigraphFromDigraph6String("+~llk"); +gap> DigraphFromDigraph6String("&~llk"); Error, Digraphs: DigraphFromDigraph6String: usage, the input string is not in valid digraph6 format, gap> DigraphFromSparse6String(":~~l"); diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index e67d50bff..961a88325 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -15,7 +15,7 @@ gap> LoadPackage("digraphs", false);; gap> DIGRAPHS_StartTest(); # DigraphReverse -gap> gr := DigraphFromDigraph6String("+D[NGc_"); +gap> gr := DigraphFromDigraph6String("&DHUEe_"); gap> rgr := DigraphReverse(gr); @@ -50,11 +50,11 @@ gap> gr = DigraphReverse(gr); true # DigraphRemoveLoops -gap> gr := DigraphFromDigraph6String("+EhxPC?@"); +gap> gr := DigraphFromDigraph6String("&EhxPC?@"); gap> DigraphRemoveLoops(gr); -gap> gr := DigraphFromDigraph6String("+EhxPC?@"); +gap> gr := DigraphFromDigraph6String("&EhxPC?@"); gap> HasDigraphHasLoops(gr); false @@ -99,11 +99,12 @@ gap> last = gr; true gap> DigraphRemoveEdges(gr, [[1, 2]]); -gap> gr := DigraphFromDigraph6String("+Dv?f`_"); +gap> gr := DigraphFromDigraph6String("&DtGsw_"); -gap> DigraphEdges(gr); -[ [ 1, 2 ], [ 1, 1 ], [ 1, 4 ], [ 2, 1 ], [ 2, 4 ], [ 3, 4 ], [ 3, 3 ], - [ 4, 1 ], [ 4, 5 ], [ 4, 4 ], [ 5, 1 ], [ 5, 5 ] ] +gap> Set(DigraphEdges(gr)) = Set( +> [[1, 2], [1, 1], [1, 4], [2, 1], [2, 4], [3, 4], +> [3, 3], [4, 1], [4, 5], [4, 4], [5, 1], [5, 5]]); +true gap> gr1 := DigraphRemoveEdges(gr, [[1, 4], [4, 5], [5, 5]]); gap> DigraphEdges(gr1); @@ -793,7 +794,7 @@ gap> DigraphVertexLabels(gr2); [ 1, Sym( [ 1 .. 2 ] ) ] # DigraphRemoveVertex -gap> gr := DigraphFromDigraph6String("+MW?Gp?GWe?gS?[L?A?f|C@KOCa_gk?F?r_"); +gap> gr := DigraphFromDigraph6String("&MU?GAa?SDCFStK`???d?@LWOq[{DECO?U?"); gap> DigraphRemoveVertex(gr, "a"); Error, no method found! For debugging hints type ?Recovery from NoMethodFound @@ -1045,7 +1046,7 @@ gap> func := function(mat, i, j, k) > fi; > end; function( mat, i, j, k ) ... end -gap> gr := DigraphFromDigraph6String("+I???@?A`?G?GCCS@??"); +gap> gr := DigraphFromDigraph6String("&I???@?A`?G?GCCS@??"); gap> tclosure := DigraphFloydWarshall(gr, func, 0, 1);; gap> grt := DigraphByAdjacencyMatrix(tclosure); @@ -1104,7 +1105,7 @@ gap> gr = ChainDigraph(14); true # DigraphEdgeUnion -gap> gr1 := DigraphFromDigraph6String("+I????O?GO_?C??_OGG"); +gap> gr1 := DigraphFromDigraph6String("&I????@A_?AA???@d??"); gap> gr2 := DigraphFromDiSparse6String(".H`OS?aEMC?bneOY`l_?QCJ"); @@ -1594,7 +1595,7 @@ gap> DigraphLayers(gr, 9); [ [ 9 ], [ 10, 11 ] ] gap> DigraphLayers(gr, 10); [ [ 10 ] ] -gap> gr := DigraphFromDigraph6String("+GUIQQWWXHHPg");; +gap> gr := DigraphFromDigraph6String("&GYHPQgWTIIPW");; gap> DigraphGroup(gr); Group([ (1,2)(3,4)(5,6)(7,8), (1,3,2,4)(5,7,6,8), (1,5)(2,6)(3,8)(4,7) ]) gap> DigraphOrbitReps(gr); @@ -1698,7 +1699,7 @@ the second argument must be a vertex of the digraph, gap> DigraphDistanceSet(gr, 10, ["string", 1]); Error, Digraphs: DigraphDistanceSet: usage, the third argument must be a list of non-negative integers, -gap> gr := DigraphFromDigraph6String("+GUIQQWWXHHPg");; +gap> gr := DigraphFromDigraph6String("&GYHPQgWTIIPW");; gap> DigraphDistanceSet(gr, 1, [3, 7]); [ ] gap> DigraphDistanceSet(gr, 1, [1]); @@ -1772,7 +1773,7 @@ gap> IsUndirectedSpanningForest(gr1, gr2); false gap> IsUndirectedSpanningForest(gr1, DigraphFromSparse6String(":I`ESyTl^F")); true -gap> gr := DigraphFromDigraph6String("+I?PIMAQc@A?W?ADPP?"); +gap> gr := DigraphFromDigraph6String("&I?PIMAQc@A?W?ADPP?"); gap> IsUndirectedSpanningForest(gr, DigraphByEdges([[2, 7], [7, 2]], 10)); true @@ -1782,7 +1783,7 @@ gap> IsUndirectedSpanningTree(EmptyDigraph(1), EmptyDigraph(1)); true gap> IsUndirectedSpanningTree(EmptyDigraph(2), EmptyDigraph(2)); false -gap> gr := DigraphFromDigraph6String("+I?PIMAQc@A?W?ADPP?"); +gap> gr := DigraphFromDigraph6String("&I?PIMAQc@A?W?ADPP?"); gap> IsUndirectedSpanningTree(gr, EmptyDigraph(10)); false @@ -1995,7 +1996,7 @@ gap> di := Digraph([[1], [1, 2], [1, 3], [1, 2, 3, 4]]);; gap> S := AsSemigroup(IsPartialPermSemigroup, di);; gap> IsInverseSemigroup(S) and ForAll(Elements(S), IsIdempotent); true -gap> temp := "+P~~}~??o??_?@o??_?@_?W}?O_??o??_?@_FGoA?_?Wo?O_Wt_";; +gap> temp := "&P_?@_?B`?FrCK_GXoXo_B?_A@aCA`GDroG`_?`?@e??c?@w??_";; gap> di := DigraphFromDigraph6String(temp);; gap> S := AsSemigroup(IsPartialPermSemigroup, di);; gap> IsInverseSemigroup(S) and ForAll(Elements(S), IsIdempotent);