From 28946b87700309aeb26a80ae244ec3bc797dc61e Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Sun, 28 Feb 2021 15:44:48 +0000 Subject: [PATCH 1/2] Add Min/MaximalCommonSubdigraph --- doc/grahom.xml | 63 +++++++++++++++++++++++++++++++++ doc/z-chap6.xml | 2 ++ gap/grahom.gd | 3 ++ gap/grahom.gi | 77 +++++++++++++++++++++++++++++++++++++++++ tst/standard/grahom.tst | 40 +++++++++++++++++++++ 5 files changed, 185 insertions(+) diff --git a/doc/grahom.xml b/doc/grahom.xml index 752285232..36448590b 100644 --- a/doc/grahom.xml +++ b/doc/grahom.xml @@ -798,3 +798,66 @@ false <#/GAPDoc> + +<#GAPDoc Label="MaximalCommonSubdigraph"> + + + A list containing a digraph and two transformations. + + If D1 and D2 are digraphs without multiple edges, then + MaximalCommonSubdigraph returns a maximal common subgraph M of + D1 and D2 with the maximum number of vertices. So M is a + digraph which embeds into both D1 and D2 and has the largest + number of vertices amoung such digraphs. + + It returns a list [M, t1, t2] where M is the maximal common + subdigraph and t1, t2 are transformations embedding M into + D1 and D2 respectively. + + MaximalCommonSubdigraph(PetersenGraph(), CompleteDigraph(10)); +[ , + IdentityTransformation, IdentityTransformation ] +gap> MaximalCommonSubdigraph(PetersenGraph(), +> DigraphSymmetricClosure(CycleDigraph(5))); +[ , + IdentityTransformation, IdentityTransformation ] +gap> MaximalCommonSubdigraph(NullDigraph(0), CompleteDigraph(10)); +[ , IdentityTransformation, + IdentityTransformation ] +]]> + + +<#/GAPDoc> + +<#GAPDoc Label="MinimalCommonSuperdigraph"> + + + A list containing a digraph and two transformations. + + If D1 and D2 are digraphs without multiple edges, then + MinimalCommonSuperdigraph returns a minimal common superdigraph + M of D1 and D2 with the minimum number of vertices. + So M is a digraph into which both D1 and D2 embed and + has the smallest number of vertices amoung such digraphs. + + It returns a list [M, t1, t2] where M is the minimal common + superdigraph and t1, t2 are transformations embedding D1 and + D2 respectively into M. + MinimalCommonSuperdigraph(PetersenGraph(), CompleteDigraph(10)); +[ , + IdentityTransformation, + Transformation( [ 1, 2, 11, 12, 13, 14, 15, 16, 17, 18, 11, 12, 13, + 14, 15, 16, 17, 18 ] ) ] +gap> MinimalCommonSuperdigraph(PetersenGraph(), +> DigraphSymmetricClosure(CycleDigraph(5))); +[ , + IdentityTransformation, IdentityTransformation ] +gap> MinimalCommonSuperdigraph(NullDigraph(0), CompleteDigraph(10)); +[ , + IdentityTransformation, IdentityTransformation ] +]]> + + +<#/GAPDoc> diff --git a/doc/z-chap6.xml b/doc/z-chap6.xml index c8931052c..c4aaad204 100644 --- a/doc/z-chap6.xml +++ b/doc/z-chap6.xml @@ -42,6 +42,8 @@ from} $E_a$ \emph{to} $E_b$. In this case we say that $E_a$ and $E_b$ are <#Include Label="RepresentativeOutNeighbours"> <#Include Label="IsDigraphAutomorphism"> <#Include Label="IsDigraphColouring"> + <#Include Label="MaximalCommonSubdigraph"> + <#Include Label="MinimalCommonSuperdigraph">
Homomorphisms of digraphs diff --git a/gap/grahom.gd b/gap/grahom.gd index 1817be489..bb64b22be 100644 --- a/gap/grahom.gd +++ b/gap/grahom.gd @@ -92,3 +92,6 @@ DeclareOperation("DigraphsRespectsColouring", [IsDigraph, IsDigraph, IsTransformation, IsList, IsList]); DeclareOperation("DigraphsRespectsColouring", [IsDigraph, IsDigraph, IsPerm, IsList, IsList]); + +DeclareOperation("MaximalCommonSubdigraph", [IsDigraph, IsDigraph]); +DeclareOperation("MinimalCommonSuperdigraph", [IsDigraph, IsDigraph]); diff --git a/gap/grahom.gi b/gap/grahom.gi index 4c701d839..d555639ae 100644 --- a/gap/grahom.gi +++ b/gap/grahom.gi @@ -678,3 +678,80 @@ function(D, t) n := DigraphNrVertices(D); return IsDigraphColouring(D, ImageListOfTransformation(t, n)); end); + +InstallMethod(MaximalCommonSubdigraph, "for a pair of digraphs", +[IsDigraph, IsDigraph], +function(A, B) + local D1, D2, MPG, nonloops, Clqus, M, l, n, m, embedding1, embedding2, iso; + + D1 := DigraphImmutableCopy(A); + D2 := DigraphImmutableCopy(B); + + # If the digraphs are isomorphic then we return the first one as the answer + iso := IsomorphismDigraphs(D1, D2); + if iso <> fail then + return [D1, IdentityTransformation, AsTransformation(iso)]; + fi; + + n := DigraphNrVertices(D1); + m := DigraphNrVertices(D2); + + # The algorithm works as follows: We construct the modular product digraph + # MPG (see https://en.wikipedia.org/wiki/Modular_product_of_graphs for the + # undirected version) a maximal partial isomorphism between D1 and D2 is + # equal to a maximal clique this digraph. We then search for cliques using the + # DigraphMaximalCliquesReps function. + + MPG := ModularProduct(D1, D2); + + nonloops := Filtered([1 .. n * m], x -> not x in OutNeighbours(MPG)[x]); + # We find a big clique + Clqus := DigraphMaximalCliquesReps(MPG, [], nonloops); + M := 1; + for l in [1 .. Size(Clqus)] do + if Size(Clqus[l]) > Size(Clqus[M]) then + M := l; + fi; + od; + + embedding1 := List(Clqus[M], x -> QuoInt(x - 1, m) + 1); + embedding2 := List(Clqus[M], x -> RemInt(x - 1, m) + 1); + return [InducedSubdigraph(D1, embedding1), + Transformation([1 .. Size(embedding1)], embedding1), + Transformation([1 .. Size(embedding2)], embedding2)]; + +end); + +InstallMethod(MinimalCommonSuperdigraph, "for a pair of digraphs", +[IsDigraph, IsDigraph], +function(D1, D2) + local out, L, v, e, embfunc, embedding1, embedding2, newvertices; + L := MaximalCommonSubdigraph(D1, D2); + L[2] := List([1 .. DigraphNrVertices(L[1])], x -> x ^ L[2]); + L[3] := List([1 .. DigraphNrVertices(L[1])], x -> x ^ L[3]); + out := List(OutNeighbours(D1), x -> ShallowCopy(x)); + newvertices := Filtered(DigraphVertices(D2), x -> not x in L[3]); + embedding1 := [1 .. DigraphNrVertices(D1)]; + + embfunc := function(v) + if v in L[3] then + return L[2][Position(L[3], v)]; + fi; + return Position(newvertices, v) + DigraphNrVertices(D1); + end; + embedding2 := List(DigraphVertices(D2), embfunc); + + for v in newvertices do + Add(out, []); + od; + + for e in DigraphEdges(D2) do + if (not e[1] in L[3]) or (not e[2] in L[3]) then + Add(out[embedding2[e[1]]], embedding2[e[2]]); + fi; + od; + + return [Digraph(out), Transformation([1 .. Size(embedding1)], embedding1), + Transformation([1 .. Size(embedding2)], embedding2)]; + +end); diff --git a/tst/standard/grahom.tst b/tst/standard/grahom.tst index 86457e039..589c63ad2 100644 --- a/tst/standard/grahom.tst +++ b/tst/standard/grahom.tst @@ -2453,6 +2453,46 @@ false gap> IsDigraphEmbedding(ran, src, (), [2, 1], [1, 1, 2]); false +# MaximalCommSubdigraph and MinimalCommonSuperDigraph +gap> MaximalCommonSubdigraph(NullDigraph(0), CompleteDigraph(10)); +[ , IdentityTransformation, + IdentityTransformation ] +gap> MinimalCommonSuperdigraph(NullDigraph(0), CompleteDigraph(10)); +[ , IdentityTransformation, + IdentityTransformation ] +gap> MaximalCommonSubdigraph(PetersenGraph(), CompleteDigraph(10)); +[ , IdentityTransformation, + IdentityTransformation ] +gap> MinimalCommonSuperdigraph(PetersenGraph(), CompleteDigraph(10)); +[ , IdentityTransformation, + Transformation( [ 1, 2, 11, 12, 13, 14, 15, 16, 17, 18, 11, 12, 13, 14, 15, + 16, 17, 18 ] ) ] +gap> MaximalCommonSubdigraph(NullDigraph(10), CompleteDigraph(10)); +[ , IdentityTransformation, + IdentityTransformation ] +gap> MinimalCommonSuperdigraph(NullDigraph(10), CompleteDigraph(10)); +[ , IdentityTransformation, + Transformation( [ 1, 11, 12, 13, 14, 15, 16, 17, 18, 19, 11, 12, 13, 14, 15, + 16, 17, 18, 19 ] ) ] +gap> MaximalCommonSubdigraph(CompleteDigraph(100), CompleteDigraph(100)); +[ , IdentityTransformation, + IdentityTransformation ] +gap> MinimalCommonSuperdigraph(CompleteDigraph(100), CompleteDigraph(100)); +[ , IdentityTransformation, + IdentityTransformation ] +gap> MaximalCommonSubdigraph(PetersenGraph(), +> DigraphSymmetricClosure(CycleDigraph(5))); +[ , IdentityTransformation, + IdentityTransformation ] +gap> MinimalCommonSuperdigraph(PetersenGraph(), +> DigraphSymmetricClosure(CycleDigraph(5))); +[ , IdentityTransformation, + IdentityTransformation ] +gap> MaximalCommonSubdigraph(Digraph([[1, 1]]), Digraph([[1]])); +Error, ModularProduct does not support multidigraphs, +gap> MinimalCommonSuperdigraph(Digraph([[1, 1]]), Digraph([[1]])); +Error, ModularProduct does not support multidigraphs, + # DIGRAPHS_UnbindVariables gap> Unbind(edges); gap> Unbind(epis); From 6a4ab850a947988eab70222551b8289e0f98a0fd Mon Sep 17 00:00:00 2001 From: Wilf Wilson Date: Wed, 20 Jan 2021 14:43:13 +0000 Subject: [PATCH 2/2] grape: add vertex & edge labels to Cayley digraphs This was originally Jan de Beule's idea. --- doc/grape.xml | 19 +++++++++++++------ gap/grape.gi | 4 +++- tst/standard/grape.tst | 10 +++++++++- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/doc/grape.xml b/doc/grape.xml index e9d98c5e9..012033761 100644 --- a/doc/grape.xml +++ b/doc/grape.xml @@ -1,7 +1,7 @@ ############################################################################# ## #W grape.xml -#Y Copyright (C) 2014-19 James D. Mitchell +#Y Copyright (C) 2014-21 James D. Mitchell ## ## Licensing information can be found in the README file of this package. ## @@ -51,12 +51,19 @@ true]]> Let G be any group and let gens be a list of elements of G. This operation returns an immutable digraph that corresponds to - the Cayley graph of G with respect - gens. The vertices are the elements of G. There exists an edge - from the vertex u to the vertex v if and only if there exists - a generator g in gens such that x * g = y.

+ the Cayley graph of G with respect to gens.

- + The vertices of the digraph correspond to the elements of G, + in the order given by AsList(G). + There exists an edge from vertex u to vertex v + if and only if there exists a generator g in gens + such that AsList(G)[u] * g = AsList(G)[v].

+ + The labels of the vertices u, v, and the edge [u, v] + are the corresponding elements AsList(G)[u], + AsList(G)[v], and generator g, respectively; + see and . +

If the optional second argument gens is not present, then the generators of G are used by default.

diff --git a/gap/grape.gi b/gap/grape.gi index d550a6546..c39035203 100644 --- a/gap/grape.gi +++ b/gap/grape.gi @@ -1,7 +1,7 @@ ############################################################################# ## ## grape.gi -## Copyright (C) 2019 James D. Mitchell +## Copyright (C) 2019-21 James D. Mitchell ## ## Licensing information can be found in the README file of this package. ## @@ -111,6 +111,8 @@ function(G, gens) SetFilterObj(D, IsCayleyDigraph); SetGroupOfCayleyDigraph(D, G); SetGeneratorsOfCayleyDigraph(D, gens); + SetDigraphEdgeLabels(D, ListWithIdenticalEntries(Size(G), gens)); + SetDigraphVertexLabels(D, AsList(G)); return D; end); diff --git a/tst/standard/grape.tst b/tst/standard/grape.tst index 4cf6d0ec1..1a679e317 100644 --- a/tst/standard/grape.tst +++ b/tst/standard/grape.tst @@ -1,7 +1,7 @@ ############################################################################# ## #W standard/grape.tst -#Y Copyright (C) 2019 James D. Mitchell +#Y Copyright (C) 2019-21 James D. Mitchell ## ## Licensing information can be found in the README file of this package. ## @@ -18,6 +18,14 @@ gap> group := DihedralGroup(8); gap> digraph := CayleyDigraph(group); +gap> DigraphVertexLabels(digraph) = AsList(group); +true +gap> DigraphEdgeLabels(digraph) = +> ListWithIdenticalEntries(Size(group), GeneratorsOfGroup(group)); +true +gap> ForAll(DigraphEdges(digraph), e -> AsList(group)[e[1]] +> * DigraphEdgeLabel(digraph, e[1], e[2]) = AsList(group)[e[2]]); +true gap> group := DihedralGroup(IsPermGroup, 8); Group([ (1,2,3,4), (2,4) ]) gap> digraph := CayleyDigraph(group);