diff --git a/doc/grahom.xml b/doc/grahom.xml index ac1520148..7f7e2922d 100644 --- a/doc/grahom.xml +++ b/doc/grahom.xml @@ -321,8 +321,8 @@ gap> MonomorphismsDigraphsRepresentatives(gr1, CompleteDigraph(3)); the vertices and the edges of digraph1, and are therefore possibly strictly contained in the induced subdigraph on the same vertex set. SubdigraphsMonomorphisms(CompleteBipartiteDigraph(2, 2), -> CompleteDigraph(4)); +gap> Set(SubdigraphsMonomorphisms(CompleteBipartiteDigraph(2, 2), +> CompleteDigraph(4))); [ Transformation( [ 1, 3, 2 ] ), Transformation( [ 2, 3, 1 ] ), Transformation( [ 3, 4, 2, 1 ] ) ] gap> SubdigraphsMonomorphismsRepresentatives( diff --git a/gap/attr.gd b/gap/attr.gd index 47faa5e31..ab8ffcbf8 100644 --- a/gap/attr.gd +++ b/gap/attr.gd @@ -87,8 +87,8 @@ DeclareAttributeThatReturnsDigraph("DigraphDual", IsDigraph); DeclareAttributeThatReturnsDigraph("ReducedDigraph", IsDigraph); DeclareAttributeThatReturnsDigraph("DigraphRemoveAllMultipleEdges", IsDigraph); -# TODO replace all DeclareOperations below to DeclareAttributeThatReturnsDigraph, -# and remove the *Attr versions. +# TODO replace all DeclareOperations below to +# DeclareAttributeThatReturnsDigraph, and remove the *Attr versions. DeclareOperation("DigraphAddAllLoops", [IsDigraph]); DeclareAttribute("DigraphAddAllLoopsAttr", IsDigraph); diff --git a/gap/attr.gi b/gap/attr.gi index aed31b012..c3e5bff2e 100644 --- a/gap/attr.gi +++ b/gap/attr.gi @@ -372,7 +372,8 @@ function(D) fi; od; # Iterate over the maximal independent sets of V[S] - subset_mis := DIGRAPHS_MaximalIndependentSetsSubtractedSet(mis, S, infinity); + subset_mis := + DIGRAPHS_MaximalIndependentSetsSubtractedSet(mis, S, infinity); # Flip the list, as we now need the actual set. FlipBlist(S); for I in subset_mis do @@ -1673,9 +1674,9 @@ function(D, rotationSystem) if Difference(Union(rotationSystem), DigraphVertices(D)) <> [] then - Error("the 2nd argument (dense list ) is not a rotation", - " system for the 1st argument (digraph ), expected the union", - " to be ", DigraphVertices(D), " but found ", + Error("the 2nd argument (dense list ) is not ", + "a rotation system for the 1st argument (digraph ), ", + "expected the union to be ", DigraphVertices(D), " but found ", Union(rotationSystem)); fi; @@ -2953,7 +2954,8 @@ function(D) # Ensure that InducedSubdigraph is given a digraph with vertex labels equal # to DigraphVertices(D). SetDigraphVertexLabels(G, DigraphVertices(G)); - G := InducedSubdigraph(G, Difference(DigraphVertices(G), DigraphLoops(G))); + G := InducedSubdigraph(G, Difference(DigraphVertices(G), + DigraphLoops(G))); lab := DigraphVertexLabels(G); G := DigraphSymmetricClosure(G); mateG := DIGRAPHS_MaximalMatching(G); diff --git a/gap/cliques.gi b/gap/cliques.gi index 12a86617a..df7b3acd0 100644 --- a/gap/cliques.gi +++ b/gap/cliques.gi @@ -57,7 +57,8 @@ function(D, set) return not ForAny(try, x -> IsEmpty(Intersection(set, nbs[x]))); end); -InstallMethod(IsClique, "for a digraph by out-neighbours and a homogeneous list", +InstallMethod(IsClique, +"for a digraph by out-neighbours and a homogeneous list", [IsDigraphByOutNeighboursRep, IsHomogeneousList], function(D, clique) local nbs, v; @@ -432,7 +433,15 @@ function(arg...) return DigraphCliquesAttr(D); fi; - out := CliquesFinder(D, fail, [], limit, include, exclude, false, size, false); + out := CliquesFinder(D, + fail, + [], + limit, + include, + exclude, + false, + size, + false); # Store the result if appropriate (not special case due to params) if IsEmpty(include) and IsEmpty(exclude) and limit = infinity and size = fail and IsImmutableDigraph(D) then @@ -550,7 +559,7 @@ function(arg...) orbits := HashMap(); for c in cliques do if not c in orbits then - DIGRAPHS_AddOrbitToHashMap(G, c, orbits); + DIGRAPHS_AddOrbitToHashMap(G, c, OnSets, orbits); fi; od; out := Keys(orbits); @@ -709,7 +718,8 @@ function(digraph, hook, user_param, limit, include, exclude, max, size, reps) new_found := 0; if not clique in found_orbits then - orbit := DIGRAPHS_AddOrbitToHashMap(group, clique, found_orbits); + orbit := + DIGRAPHS_AddOrbitToHashMap(group, clique, OnSets, found_orbits); n := Length(orbit); if invariant_include and invariant_exclude then @@ -895,7 +905,7 @@ function(D, hook, param, lim, inc, exc, max, size, reps, inc_var, exc_var) num := num + 1; return; elif not c in found_orbits then - orb := DIGRAPHS_AddOrbitToHashMap(grp, c, found_orbits); + orb := DIGRAPHS_AddOrbitToHashMap(grp, c, OnSets, found_orbits); n := Length(orb); if invariant then # we're not just looking for orbit reps, but inc and diff --git a/gap/digraph.gi b/gap/digraph.gi index 21ab2bae8..8cd890a3e 100644 --- a/gap/digraph.gi +++ b/gap/digraph.gi @@ -859,8 +859,11 @@ function(_, edges, n) for edge in edges do pos := pos + 1; if not IsList(edge) then - ErrorNoReturn("the 1st argument (list of edges) must be a list of lists, ", - "but found ", TNAM_OBJ(edge), " in position ", pos); + ErrorNoReturn("the 1st argument (list of edges) must be a list of ", + "lists, but found ", + TNAM_OBJ(edge), + " in position ", + pos); elif Length(edge) <> 2 then ErrorNoReturn("the 1st argument (list of edges) must be a list of lists ", "of length 2, found ", edge, " (length ", Length(edge), diff --git a/gap/display.gi b/gap/display.gi index b578f8d60..44db21e7f 100644 --- a/gap/display.gi +++ b/gap/display.gi @@ -144,11 +144,13 @@ InstallMethod(DotDigraph, "for a digraph by out-neighbours", [IsDigraphByOutNeighboursRep], D -> DIGRAPHS_DotDigraph(D, [], [])); -InstallMethod(DotColoredDigraph, "for a digraph by out-neighbours and two lists", +InstallMethod(DotColoredDigraph, +"for a digraph by out-neighbours and two lists", [IsDigraphByOutNeighboursRep, IsList, IsList], function(D, vert, edge) local vert_func, edge_func; - if DIGRAPHS_ValidVertColors(D, vert) and DIGRAPHS_ValidEdgeColors(D, edge) then + if DIGRAPHS_ValidVertColors(D, vert) + and DIGRAPHS_ValidEdgeColors(D, edge) then vert_func := i -> StringFormatted("[color={}, style=filled]", vert[i]); edge_func := {i, j} -> StringFormatted("[color={}]", edge[i][j]); return DIGRAPHS_DotDigraph(D, [vert_func], [edge_func]); @@ -226,7 +228,8 @@ InstallMethod(DotSymmetricColoredDigraph, [IsDigraphByOutNeighboursRep, IsList, IsList], function(D, vert, edge) local vert_func, edge_func; - if DIGRAPHS_ValidVertColors(D, vert) and DIGRAPHS_ValidEdgeColors(D, edge) then + if DIGRAPHS_ValidVertColors(D, vert) + and DIGRAPHS_ValidEdgeColors(D, edge) then vert_func := i -> StringFormatted("[color={}, style=filled]", vert[i]); edge_func := {i, j} -> StringFormatted("[color={}]", edge[i][j]); return DIGRAPHS_DotSymmetricDigraph(D, [vert_func], [edge_func]); diff --git a/gap/examples.gi b/gap/examples.gi index 7070e3790..b542fa6fe 100644 --- a/gap/examples.gi +++ b/gap/examples.gi @@ -1422,7 +1422,7 @@ InstallMethod(KneserGraphCons, "for IsMutableDigraph and two integers", function(_, n, k) local D, vertices, i, j; if n < k then - ErrorNoReturn("argument must be greater than or equal to argument ,"); + ErrorNoReturn("argument must be greater than or equal to argument "); fi; vertices := Combinations([1 .. n], k); D := EmptyDigraph(IsMutableDigraph, Length(vertices)); @@ -1467,7 +1467,8 @@ InstallMethod(KneserGraph, "for two integers", [IsPosInt, IsPosInt], InstallMethod(KneserGraph, "for a function and two integers", [IsFunction, IsPosInt, IsPosInt], KneserGraphCons); -InstallMethod(LindgrenSousselierGraphCons, "for IsMutableDigraph and an integer", +InstallMethod(LindgrenSousselierGraphCons, +"for IsMutableDigraph and an integer", [IsMutableDigraph, IsPosInt], function(_, n) local D, central, i, threei; diff --git a/gap/grahom.gi b/gap/grahom.gi index 07e8b7c31..c3e433f45 100644 --- a/gap/grahom.gi +++ b/gap/grahom.gi @@ -333,75 +333,59 @@ end); InstallMethod(SubdigraphsMonomorphismsRepresentatives, "for a digraph and a digraph", [IsDigraph, IsDigraph], function(H, G) - local GV, HN, map, reps, result, set, rep; - - GV := DigraphVertices(G); - HN := DigraphNrVertices(H); + local AG, map, result, K, rep; + AG := AutomorphismGroup(G); map := HashMap(); - reps := []; + result := []; - for set in Combinations(GV, HN) do - if not set in map then - Add(reps, set); - DIGRAPHS_AddOrbitToHashMap(AutomorphismGroup(G), set, map); + for rep in MonomorphismsDigraphsRepresentatives(H, G) do + K := OnSetsTuples(DigraphEdges(H), rep); + if not K in map then + Add(result, rep); + DIGRAPHS_AddOrbitToHashMap(AG, K, OnSetsTuples, map); fi; od; - result := []; - for rep in reps do - map := - HomomorphismDigraphsFinder(H, # domain - G, # range - fail, # hook - [], # user_param - 1, # max_results - HN, # hint (i.e. rank) - true, # injective - rep, # image - [], # partial_map - fail, # colors1 - fail, # colors2 - DigraphWelshPowellOrder(H), - Group(())); - if Length(map) <> 0 then - Add(result, map[1]); - fi; - od; return result; end); InstallMethod(SubdigraphsMonomorphisms, "for a digraph and a digraph", [IsDigraph, IsDigraph], function(H, G) - local ApplyHomomorphismNC, reps, AG, result, sub, o, x, rep, i; - - ApplyHomomorphismNC := function(D1, D2, t) - local old, new, v, im; - old := OutNeighbours(D1); - new := List([1 .. DigraphNrVertices(D2)], x -> []); - for v in DigraphVertices(D1) do - im := v ^ t; - if not IsBound(new[im]) then - new[im] := []; - fi; - Append(new[im], OnTuples(old[v], t)); + local AddOrbitToHashMap, AG, map, K, rep; + + AddOrbitToHashMap := function(G, set, act, hashmap, rep) + local gens, o, im, pt, g; + + gens := GeneratorsOfGroup(G); + o := [set]; + Assert(1, not set in hashmap); + hashmap[set] := rep; + for pt in o do + for g in gens do + im := act(pt, g); + if not im in hashmap then + hashmap[im] := hashmap[pt] * g; + # Assert(0, OnSetsTuples(set, hashmap[im]) = im); + Add(o, im); + fi; + od; od; - return DigraphNC(new); + return o; end; - reps := SubdigraphsMonomorphismsRepresentatives(H, G); AG := AutomorphismGroup(G); - result := []; - for rep in reps do - sub := ApplyHomomorphismNC(H, G, rep); - o := Enumerate(Orb(AG, sub, OnDigraphs, rec(schreier := true))); - for i in [1 .. Length(o)] do - x := EvaluateWord(GeneratorsOfGroup(AG), TraceSchreierTreeForward(o, i)); - Add(result, rep * x); - od; + map := HashMap(); + + for rep in MonomorphismsDigraphsRepresentatives(H, G) do + K := OnSetsTuples(DigraphEdges(H), rep); + if not K in map then + AddOrbitToHashMap(AG, K, OnSetsTuples, map, rep); + fi; od; - return result; + + return Values(map); end); ################################################################################ diff --git a/gap/io.gi b/gap/io.gi index 383f393b4..24a986994 100644 --- a/gap/io.gi +++ b/gap/io.gi @@ -695,7 +695,8 @@ DigraphFromGraph6StringCons); InstallMethod(DigraphFromGraph6String, "for a string", [IsString], s -> DigraphFromGraph6String(IsImmutableDigraph, s)); -InstallMethod(DigraphFromDigraph6StringCons, "for IsMutableDigraph and a string", +InstallMethod(DigraphFromDigraph6StringCons, +"for IsMutableDigraph and a string", [IsMutableDigraph, IsString], function(filt, s) local legacy, list, n, start, i, range, source, pos, len, j, bpos, tabpos; diff --git a/gap/isomorph.gd b/gap/isomorph.gd index 0eb05a13c..0792204a7 100644 --- a/gap/isomorph.gd +++ b/gap/isomorph.gd @@ -57,10 +57,14 @@ DeclareGlobalFunction("DIGRAPHS_ValidateEdgeColouring"); DeclareGlobalFunction("DIGRAPHS_CollapseMultiColouredEdges"); DeclareGlobalFunction("DIGRAPHS_CollapseMultipleEdges"); -DeclareOperation("IsDigraphAutomorphism", [IsDigraph, IsPerm]); -DeclareOperation("IsDigraphAutomorphism", [IsDigraph, IsPerm, IsList]); -DeclareOperation("IsDigraphAutomorphism", [IsDigraph, IsTransformation]); -DeclareOperation("IsDigraphAutomorphism", [IsDigraph, IsTransformation, IsList]); +DeclareOperation("IsDigraphAutomorphism", + [IsDigraph, IsPerm]); +DeclareOperation("IsDigraphAutomorphism", + [IsDigraph, IsPerm, IsList]); +DeclareOperation("IsDigraphAutomorphism", + [IsDigraph, IsTransformation]); +DeclareOperation("IsDigraphAutomorphism", + [IsDigraph, IsTransformation, IsList]); DeclareOperation("IsDigraphIsomorphism", [IsDigraph, IsDigraph, IsPerm]); DeclareOperation("IsDigraphIsomorphism", diff --git a/gap/orbits.gi b/gap/orbits.gi index e1c6cbf08..257ae53f9 100644 --- a/gap/orbits.gi +++ b/gap/orbits.gi @@ -69,7 +69,7 @@ function(G, domain) end); InstallGlobalFunction(DIGRAPHS_AddOrbitToHashMap, -function(G, set, hashmap) +function(G, set, act, hashmap) local gens, o, im, pt, g; gens := GeneratorsOfGroup(G); @@ -78,7 +78,7 @@ function(G, set, hashmap) hashmap[set] := true; for pt in o do for g in gens do - im := OnSets(pt, g); + im := act(pt, g); if not im in hashmap then hashmap[im] := true; Add(o, im); @@ -118,7 +118,8 @@ end); InstallImmediateMethod(DigraphGroup, IsDigraph and HasAutomorphismGroup, 0, DIGRAPHS_DigraphGroup); -InstallMethod(DigraphGroup, "for a digraph", [IsDigraph], DIGRAPHS_DigraphGroup); +InstallMethod(DigraphGroup, "for a digraph", [IsDigraph], +DIGRAPHS_DigraphGroup); InstallMethod(DigraphOrbits, "for a digraph", [IsDigraph], diff --git a/gap/weights.gd b/gap/weights.gd index 071463c21..e2e4d530d 100644 --- a/gap/weights.gd +++ b/gap/weights.gd @@ -12,7 +12,8 @@ DeclareAttribute("EdgeWeights", IsDigraph); DeclareGlobalFunction("EdgeWeightedDigraph"); DeclareProperty("IsNegativeEdgeWeightedDigraph", IsDigraph and HasEdgeWeights); -DeclareAttribute("EdgeWeightedDigraphTotalWeight", IsDigraph and HasEdgeWeights); +DeclareAttribute("EdgeWeightedDigraphTotalWeight", +IsDigraph and HasEdgeWeights); # 2. Edge Weight Copies DeclareOperation("EdgeWeightsMutableCopy", [IsDigraph and HasEdgeWeights]); diff --git a/gap/weights.gi b/gap/weights.gi index 859b0d3bb..3cb37429e 100644 --- a/gap/weights.gi +++ b/gap/weights.gi @@ -230,7 +230,8 @@ end); InstallMethod(EdgeWeightedDigraphShortestPaths, "for a digraph with edge weights and known shortest paths and a pos int", -[IsDigraph and HasEdgeWeights and HasEdgeWeightedDigraphShortestPaths, IsPosInt], +[IsDigraph and HasEdgeWeights and HasEdgeWeightedDigraphShortestPaths, + IsPosInt], function(digraph, source) local all_paths; if not source in DigraphVertices(digraph) then diff --git a/tst/standard/examples.tst b/tst/standard/examples.tst index 56d1359d5..24f780db9 100644 --- a/tst/standard/examples.tst +++ b/tst/standard/examples.tst @@ -629,7 +629,7 @@ gap> KneserGraph(6, 3); gap> KneserGraph(3, 4); -Error, argument must be greater than or equal to argument , +Error, argument must be greater than or equal to argument gap> KneserGraph(3, -1); Error, no method found! For debugging hints type ?Recovery from NoMethodFound Error, no 1st choice method found for `KneserGraph' on 2 arguments diff --git a/tst/standard/grahom.tst b/tst/standard/grahom.tst index 7b5b56b5c..68c637947 100644 --- a/tst/standard/grahom.tst +++ b/tst/standard/grahom.tst @@ -2762,13 +2762,13 @@ gap> IsLatticeEpimorphism(D, D, (2, 3)); true # SubdigraphsMonomorphisms -gap> SubdigraphsMonomorphisms(CompleteBipartiteDigraph(2, 2), -> CompleteDigraph(4)); +gap> Set(SubdigraphsMonomorphisms(CompleteBipartiteDigraph(2, 2), +> CompleteDigraph(4))); [ Transformation( [ 1, 3, 2 ] ), Transformation( [ 2, 3, 1 ] ), Transformation( [ 3, 4, 2, 1 ] ) ] gap> D := DigraphFromGraph6String("D^{"); -gap> SubdigraphsMonomorphisms(CompleteDigraph(4), D); +gap> Set(SubdigraphsMonomorphisms(CompleteDigraph(4), D)); [ Transformation( [ 1, 3, 4, 5, 5 ] ), Transformation( [ 2, 3, 4, 5, 5 ] ) ] gap> Length(SubdigraphsMonomorphisms(CompleteDigraph(4), CompleteDigraph(12))); 495 @@ -2776,10 +2776,12 @@ gap> D := DigraphFromGraph6String("K^vMMF@oM?{@"); gap> Length(SubdigraphsMonomorphisms(CompleteMultipartiteDigraph([2, 5]), D)); 252 -gap> D := DigraphFromGraph6String("O^vMMF@oM?w@o@o?w?N?@"); - -gap> Length(SubdigraphsMonomorphisms(CompleteMultipartiteDigraph([2, 7]), D)); -3432 + +# The next test is a bit slow +# gap> D := DigraphFromGraph6String("O^vMMF@oM?w@o@o?w?N?@"); +# +# gap> Length(SubdigraphsMonomorphisms(CompleteMultipartiteDigraph([2, 7]), D)); +# 3432 # gap> H := DigraphFromGraph6String("F~CWw"); diff --git a/tst/testinstall.tst b/tst/testinstall.tst index e7d891de3..183caf656 100644 --- a/tst/testinstall.tst +++ b/tst/testinstall.tst @@ -462,6 +462,12 @@ gap> C := DigraphContractEdge(D, 2, 1); gap> DigraphEdges(C); [ [ 2, 1 ] ] +# Issue #704 SubdigraphsMonomorphisms bug +gap> d := Digraph([[2, 3, 4, 5], [1, 3, 4], [1, 2, 4, 5], [1, 2, 3, 5], +> [1, 3, 4]]);; +gap> Length(SubdigraphsMonomorphisms(CompleteMultipartiteDigraph([2, 3]), d)); +4 + # DIGRAPHS_UnbindVariables gap> Unbind(C); gap> Unbind(D);