From 1f4684403c15a33e76586efdbc9f666dc3f12171 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 16 Mar 2022 17:33:50 +0000 Subject: [PATCH 1/8] Initial version of AmalgamDigraphs and AmalgamDigraphsIsomorphic. --- gap/oper.gd | 3 ++ gap/oper.gi | 85 +++++++++++++++++++++++++++++++++++++++++++ tst/standard/oper.tst | 35 ++++++++++++++++++ 3 files changed, 123 insertions(+) diff --git a/gap/oper.gd b/gap/oper.gd index 45c48ea3c..35caa5c31 100644 --- a/gap/oper.gd +++ b/gap/oper.gd @@ -46,6 +46,9 @@ DeclareOperation("StrongProduct", [IsDigraph, IsDigraph]); DeclareOperation("ConormalProduct", [IsDigraph, IsDigraph]); DeclareOperation("HomomorphicProduct", [IsDigraph, IsDigraph]); DeclareOperation("LexicographicProduct", [IsDigraph, IsDigraph]); +DeclareOperation("AmalgamDigraphs", [IsDigraph, IsDigraph, IsList, IsList]); +DeclareOperation("AmalgamDigraphsIsomorphic", + [IsDigraph, IsDigraph, IsList, IsList]); DeclareSynonym("DigraphModularProduct", ModularProduct); DeclareSynonym("DigraphStrongProduct", StrongProduct); diff --git a/gap/oper.gi b/gap/oper.gi index 2af8d27ac..1b9066a51 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -765,6 +765,91 @@ function(D1, D2, edge_function) return Digraph(edges); end); +InstallMethod(AmalgamDigraphsIsomorphic, +"for a digraph, a digraph, a list, and a list", +[IsDigraph, IsDigraph, IsList, IsList], +function(D1, D2, subdigraphVertices1, subdigraphVertices2) + local subdigraph1, subdigraph2, newSubdigraphVertices2, transformation, vertex; + + subdigraph1 := InducedSubdigraph(D1, subdigraphVertices1); + subdigraph2 := InducedSubdigraph(D2, subdigraphVertices2); + + if not IsIsomorphicDigraph(subdigraph1, subdigraph2) then + ErrorNoReturn( + "the two subdigraphs must be isomorphic."); + fi; + + newSubdigraphVertices2 := []; + transformation := DigraphEmbedding(subdigraph2, subdigraph1); + for vertex in subdigraphVertices2 do + newSubdigraphVertices2[ + Position(subdigraphVertices2, vertex) ^ transformation] := vertex; + od; + + return AmalgamDigraphs(D1, D2, subdigraphVertices1, newSubdigraphVertices2); +end); + +InstallMethod(AmalgamDigraphs, +"for a digraph, a digraph, a list, and a list", +[IsDigraph, IsDigraph, IsList, IsList], +function(D1, D2, subdigraphVertices1, subdigraphVertices2) + local D, map, vertex, vertexList, size, iterator, edgeList, subLength; + + if not InducedSubdigraph(D1, subdigraphVertices1) = + InducedSubdigraph(D2, subdigraphVertices2) then + ErrorNoReturn( + "the two subdigraphs must be equal."); + fi; + + # Create a mutable copy so that the function also works on + # immutable input digraphs. + D := DigraphMutableCopy(D1); + subLength := Length(subdigraphVertices1); + + # 'map' is a mapping from the vertices of D2 to the vertices of the + # final output graph. The idea is to map the subdigraph vertices of D2 + # onto the subdigraph vertices of D1 and then map the rest of the vertices + # of D2 to other (higher) values. The mapping from D1 to the output graph + # can be understood as the identity mapping. + map := rec(); + + for vertex in [1 .. subLength] do + map.(subdigraphVertices2[vertex]) := subdigraphVertices1[vertex]; + od; + + vertexList := Difference(DigraphVertices(D2), subdigraphVertices2); + size := DigraphNrVertices(D1); + iterator := 1; + for vertex in vertexList do + map.(vertex) := iterator + size; + iterator := iterator + 1; + od; + + # The problem with adding edges to the output graph was that the + # edges of of the subdigraph were added twice, creating multiple + # edges between certain pairs of points. A quick and readable fix + # would have been to use DigraphRemoveAllMultipleEdges, but I decided + # to check each of the edges being added to see if they were already + # in the subdigraph. This way the function does not end up adding edges + # only to delete them later. + edgeList := ShallowCopy(DigraphEdges(D2)); + iterator := 1; + while iterator <= Length(edgeList) do + if edgeList[iterator][1] in subdigraphVertices2 and + edgeList[iterator][2] in subdigraphVertices2 then + Remove(edgeList, iterator); + else + edgeList[iterator] := [ + map.(edgeList[iterator][1]), map.(edgeList[iterator][2])]; + iterator := iterator + 1; + fi; + od; + + DigraphAddVertices(D, DigraphNrVertices(D2) - subLength); + DigraphAddEdges(D, edgeList); + return [MakeImmutable(D), map]; +end); + ############################################################################### # 4. Actions ############################################################################### diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index 4c4aedf0a..48baca7f7 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -2757,6 +2757,41 @@ gap> path := DigraphPath(D, 5, 5);; gap> IsDigraphPath(D, path); true +# AmalgamDigraphs +gap> D1 := Digraph([[2, 3], [1, 3], [1, 2], [2], [3, 4]]);; +gap> D2 := Digraph([[2, 6], [1, 3, 5], [4], [3], [4, 6], [1, 5]]);; +gap> U := AmalgamDigraphs(D1, D2, [2, 3, 4, 5], [4, 3, 5, 2]); +[ , + rec( 1 := 6, 2 := 5, 3 := 3, 4 := 2, 5 := 4, 6 := 7 ) ] +gap> D1 := Digraph([ +> [2, 3], [1, 3, 4, 6], [1, 2, 5, 7], [2, 6], [3, 7], [2, 4, 7, 8], +> [3, 5, 6, 8], [6, 7]]);; +gap> D2 := Digraph([ +> [2, 3], [1, 4], [1, 5], [2, 5, 6], [3, 4, 7], [4, 7], [5, 6]]);; +gap> U := AmalgamDigraphs(D1, D2, [2, 3, 6, 7], [4, 5, 6, 7]); +[ , + rec( 1 := 9, 2 := 10, 3 := 11, 4 := 2, 5 := 3, 6 := 6, 7 := 7 ) ] +gap> AmalgamDigraphs(D1, D2, [3, 6, 2, 7], [4, 5, 7, 6]); +Error, the two subdigraphs must be equal. +gap> D1 := PetersenGraph();; +gap> U := AmalgamDigraphs(D1, D1, [3, 4, 6, 8, 9], [3, 4, 6, 8, 9]); +[ , + rec( 1 := 11, 10 := 15, 2 := 12, 3 := 3, 4 := 4, 5 := 13, 6 := 6, 7 := 14, + 8 := 8, 9 := 9 ) ] + +# AmalgamDigraphsIsomorphic +gap> D1 := PetersenGraph();; +gap> D2 := Digraph([ +> [2, 4], [1, 3, 4, 5], [2, 5], [1, 2, 6], [2, 3, 7], [4, 7, 8], +> [5, 6, 8], [6, 7]]);; +gap> U := AmalgamDigraphsIsomorphic(D1, D2, [3, 4, 6, 8, 9], +> [2, 4, 5, 6, 7]); +[ , + rec( 1 := 11, 2 := 3, 3 := 12, 4 := 4, 5 := 8, 6 := 9, 7 := 6, 8 := 13 ) ] +gap> U := AmalgamDigraphsIsomorphic(D1, D2, [3, 4, 10, 8, 9], +> [2, 4, 5, 6, 7]); +Error, the two subdigraphs must be isomorphic. + #DIGRAPHS_UnbindVariables gap> Unbind(a); gap> Unbind(adj); From 5fae321a89149eb1e644b4cd97e37bda1660ed8f Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 30 Mar 2022 15:58:24 +0100 Subject: [PATCH 2/8] Added documentation. --- doc/oper.xml | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ doc/z-chap2.xml | 2 ++ 2 files changed, 82 insertions(+) diff --git a/doc/oper.xml b/doc/oper.xml index 324951db2..9e0db3449 100644 --- a/doc/oper.xml +++ b/doc/oper.xml @@ -2227,3 +2227,83 @@ true <#/GAPDoc> + +<#GAPDoc Label="AmalgamDigraphs"> + + + An immutable digraph and a record. + + + AmalgamDigraphs takes as input two digraphs D1 and D2 + and two lists of vertices subdigraphVertices1 and + subdigraphVertices2, which correspond to two identical subdigraphs + of D1 and D2. It returns a new digraph, the amalgam + digraph AD, which consists of D1 and D2 joined + together by their common subdigraph in such a way that the edge connectivity + between the vertices of AD matches the edge connectivity of + D1 and D2.

+ + It returns a tuple of size two, with the first element being + AD and the second element being map, which is a record which + maps each vertex's number in D2 to the corresponding vertex's number + in AD. The mapping of the vertices of D1 can be seen as the + identity mapping. + + T := Digraph([[2, 3], [1, 3], [1, 2]]);; +gap> A := AmalgamDigraphs(T, T, [1, 2], [1, 2]); +[ , + rec( 1 := 1, 2 := 2, 3 := 4 ) ] +gap> A := AmalgamDigraphs(A[1], T, [1, 2], [1, 2]); +[ , + rec( 1 := 1, 2 := 2, 3 := 5 ) ] +gap> P := PetersenGraph();; +gap> G := Digraph([[2, 3, 4], [1, 3], [1, 2, 5], +> [1, 6], [3, 6], [4, 5]]);; +gap> A := AmalgamDigraphs(P, G, [1, 2, 7, 10, 5], [1, 3, 5, 6, 4]); +[ , + rec( 1 := 1, 2 := 11, 3 := 2, 4 := 5, 5 := 7, 6 := 10 ) ] +]]> + + +<#/GAPDoc> + +<#GAPDoc Label="AmalgamDigraphsIsomorphic"> + + + An immutable digraph and a record. + + + AmalgamDigraphsIsomorphic is meant to function very similarly to + AmalgamDigraphs. The difference is that in AmalgamDigraphs + subdigraphVertices1 and subdigraphVertices2 need not + necessarily describe identical subdigraphs of D1 and D2, + but need only describe subdigraphs that are isomorphic to one another. + AmalgamDigraphsIsomorphic rearranges the entries of + subdigraphVertices2 to obtain newSubdigraphVertices2 + in such a way that the induced subdigraph in D2 with the + vertices newSubdigraphVertices2 is identical to the induced + subdigraph in D1 with the vertices subdigraphVertices1. + AmalgamDigraphsIsomorphic then calls AmalgamDigraphs + with newSubdigraphVertices2 in the place of + subdigraphVertices2. + + P := PetersenGraph();; +gap> G := Digraph([[2, 3, 4], [1, 3], +> [1, 2, 5], [1, 6], [3, 6], [4, 5]]);; +gap> A := AmalgamDigraphs(P, G, [1, 2, 7, 10, 5], [1, 3, 5, 6, 4]); +[ , + rec( 1 := 1, 2 := 11, 3 := 2, 4 := 5, 5 := 7, 6 := 10 ) ] +gap> A := AmalgamDigraphsIsomorphic(P, G, +> [1, 2, 7, 10, 5], [1, 4, 6, 3, 5]); +[ , + rec( 1 := 1, 2 := 11, 3 := 5, 4 := 2, 5 := 10, 6 := 7 ) ] +gap> A := AmalgamDigraphs(P, G, [1, 2, 7, 10, 5], [1, 4, 6, 3, 5]); +Error, the two subdigraphs must be equal. +]]> + + +<#/GAPDoc> diff --git a/doc/z-chap2.xml b/doc/z-chap2.xml index 9de59949e..33a4e3c6e 100644 --- a/doc/z-chap2.xml +++ b/doc/z-chap2.xml @@ -74,6 +74,8 @@ <#Include Label="DistanceDigraph"> <#Include Label="DigraphClosure"> <#Include Label="DigraphMycielskian"> + <#Include Label="AmalgamDigraphs"> + <#Include Label="AmalgamDigraphsIsomorphic">

Random digraphs From 241abcdd56eaaec56e520829ffbff41172921827 Mon Sep 17 00:00:00 2001 From: Finnegan Buck <61651823+finnbuck@users.noreply.github.com> Date: Fri, 1 Apr 2022 10:53:22 +0100 Subject: [PATCH 3/8] Update gap/oper.gi Co-authored-by: James Mitchell --- gap/oper.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/oper.gi b/gap/oper.gi index 1b9066a51..5a5959d17 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -826,7 +826,7 @@ function(D1, D2, subdigraphVertices1, subdigraphVertices2) od; # The problem with adding edges to the output graph was that the - # edges of of the subdigraph were added twice, creating multiple + # edges of the subdigraph were added twice, creating multiple # edges between certain pairs of points. A quick and readable fix # would have been to use DigraphRemoveAllMultipleEdges, but I decided # to check each of the edges being added to see if they were already From 304dd95248991d356ebc891091cf6708831ab24b Mon Sep 17 00:00:00 2001 From: Finnegan Buck <61651823+finnbuck@users.noreply.github.com> Date: Fri, 1 Apr 2022 10:54:39 +0100 Subject: [PATCH 4/8] Update gap/oper.gi Co-authored-by: James Mitchell --- gap/oper.gi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gap/oper.gi b/gap/oper.gi index 5a5959d17..ed1f72f6d 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -797,7 +797,7 @@ function(D1, D2, subdigraphVertices1, subdigraphVertices2) if not InducedSubdigraph(D1, subdigraphVertices1) = InducedSubdigraph(D2, subdigraphVertices2) then - ErrorNoReturn( + ErrorNoReturn("the subdigraph induced by the 3rd argument (a list) in the 1st argument (a digraph) does not equal the subdigraph induced by the 4th argument (a list) in the 2nd argument (a digraph)"); "the two subdigraphs must be equal."); fi; From 3ec1aaea80ca38bf467ffcf9ea00dfe90ecdb779 Mon Sep 17 00:00:00 2001 From: Finn Date: Sat, 2 Apr 2022 11:47:13 +0100 Subject: [PATCH 5/8] Added compatibility with mutable digraphs. --- gap/oper.gi | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/gap/oper.gi b/gap/oper.gi index ed1f72f6d..d368e5595 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -771,12 +771,16 @@ InstallMethod(AmalgamDigraphsIsomorphic, function(D1, D2, subdigraphVertices1, subdigraphVertices2) local subdigraph1, subdigraph2, newSubdigraphVertices2, transformation, vertex; - subdigraph1 := InducedSubdigraph(D1, subdigraphVertices1); - subdigraph2 := InducedSubdigraph(D2, subdigraphVertices2); + subdigraph1 := InducedSubdigraph(DigraphImmutableCopyIfMutable(D1), + subdigraphVertices1); + subdigraph2 := InducedSubdigraph(DigraphImmutableCopyIfMutable(D2), + subdigraphVertices2); if not IsIsomorphicDigraph(subdigraph1, subdigraph2) then ErrorNoReturn( - "the two subdigraphs must be isomorphic."); + "the subdigraph induced by the 3rd argument (a list) in the 1st ", + "argument (a digraph) is not ismorphic to the subdigraph induced ", + "by the 4th argument (a list) in the 2nd argument (a digraph)"); fi; newSubdigraphVertices2 := []; @@ -793,18 +797,21 @@ InstallMethod(AmalgamDigraphs, "for a digraph, a digraph, a list, and a list", [IsDigraph, IsDigraph, IsList, IsList], function(D1, D2, subdigraphVertices1, subdigraphVertices2) - local D, map, vertex, vertexList, size, iterator, edgeList, subLength; + local D, map, vertex, vertexList, size, iterator, edgeList; - if not InducedSubdigraph(D1, subdigraphVertices1) = - InducedSubdigraph(D2, subdigraphVertices2) then - ErrorNoReturn("the subdigraph induced by the 3rd argument (a list) in the 1st argument (a digraph) does not equal the subdigraph induced by the 4th argument (a list) in the 2nd argument (a digraph)"); - "the two subdigraphs must be equal."); + if not InducedSubdigraph(DigraphImmutableCopyIfMutable(D1), + subdigraphVertices1) = + InducedSubdigraph(DigraphImmutableCopyIfMutable(D2), + subdigraphVertices2) then + ErrorNoReturn( + "the subdigraph induced by the 3rd argument (a list) in the 1st ", + "argument (a digraph) does not equal the subdigraph induced by the ", + "4th argument (a list) in the 2nd argument (a digraph)"); fi; # Create a mutable copy so that the function also works on # immutable input digraphs. D := DigraphMutableCopy(D1); - subLength := Length(subdigraphVertices1); # 'map' is a mapping from the vertices of D2 to the vertices of the # final output graph. The idea is to map the subdigraph vertices of D2 @@ -813,10 +820,11 @@ function(D1, D2, subdigraphVertices1, subdigraphVertices2) # can be understood as the identity mapping. map := rec(); - for vertex in [1 .. subLength] do + for vertex in [1 .. Length(subdigraphVertices1)] do map.(subdigraphVertices2[vertex]) := subdigraphVertices1[vertex]; od; + # Delete?? vertexList := Difference(DigraphVertices(D2), subdigraphVertices2); size := DigraphNrVertices(D1); iterator := 1; @@ -845,9 +853,9 @@ function(D1, D2, subdigraphVertices1, subdigraphVertices2) fi; od; - DigraphAddVertices(D, DigraphNrVertices(D2) - subLength); + DigraphAddVertices(D, DigraphNrVertices(D2) - Length(subdigraphVertices1)); DigraphAddEdges(D, edgeList); - return [MakeImmutable(D), map]; + return [Immutable(D), map]; end); ############################################################################### From cff214906f4c566985e039b253dad9b234c6486c Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 5 Apr 2022 11:16:49 +0100 Subject: [PATCH 6/8] Attempt to change over to Transformation. --- gap/oper.gi | 61 +++++++++++++++++++++++++++---------------- tst/standard/oper.tst | 8 ++++-- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/gap/oper.gi b/gap/oper.gi index d368e5595..68f11077a 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -797,7 +797,7 @@ InstallMethod(AmalgamDigraphs, "for a digraph, a digraph, a list, and a list", [IsDigraph, IsDigraph, IsList, IsList], function(D1, D2, subdigraphVertices1, subdigraphVertices2) - local D, map, vertex, vertexList, size, iterator, edgeList; + local D, map, vertex, vertexList, size, iterator, edgeList, edge; if not InducedSubdigraph(DigraphImmutableCopyIfMutable(D1), subdigraphVertices1) = @@ -810,7 +810,8 @@ function(D1, D2, subdigraphVertices1, subdigraphVertices2) fi; # Create a mutable copy so that the function also works on - # immutable input digraphs. + # immutable input digraphs and also does not change mutable + # digraphs in place. D := DigraphMutableCopy(D1); # 'map' is a mapping from the vertices of D2 to the vertices of the @@ -818,21 +819,36 @@ function(D1, D2, subdigraphVertices1, subdigraphVertices2) # onto the subdigraph vertices of D1 and then map the rest of the vertices # of D2 to other (higher) values. The mapping from D1 to the output graph # can be understood as the identity mapping. - map := rec(); + map := [1 .. DigraphNrVertices(D2)]; for vertex in [1 .. Length(subdigraphVertices1)] do - map.(subdigraphVertices2[vertex]) := subdigraphVertices1[vertex]; + map[subdigraphVertices2[vertex]] := subdigraphVertices1[vertex]; od; # Delete?? - vertexList := Difference(DigraphVertices(D2), subdigraphVertices2); - size := DigraphNrVertices(D1); + # vertexList := Difference(DigraphVertices(D2), subdigraphVertices2); + # size := DigraphNrVertices(D1); + # iterator := 1; + # for vertex in vertexList do + # map[vertex] := iterator + size; + # iterator := iterator + 1; + # od; + + iterator := 1; - for vertex in vertexList do - map.(vertex) := iterator + size; - iterator := iterator + 1; + for edge in [1 .. DigraphNrEdges(D2)] do + Add(edgeList, []); + for vertex in [1, 2] do + if DigraphEdges(D2)[edge][vertex] in subdigraphVertices2 then + DigraphEdges(D2)[edge][vertex] := DigraphEdges(D2)[edge][vertex] ^ Transformation(map); + else + DigraphEdges(D2)[edge][vertex] := # But we still need a mapping for the non-subdigraph vertices + fi; + od; od; + + # The problem with adding edges to the output graph was that the # edges of the subdigraph were added twice, creating multiple # edges between certain pairs of points. A quick and readable fix @@ -840,22 +856,23 @@ function(D1, D2, subdigraphVertices1, subdigraphVertices2) # to check each of the edges being added to see if they were already # in the subdigraph. This way the function does not end up adding edges # only to delete them later. - edgeList := ShallowCopy(DigraphEdges(D2)); - iterator := 1; - while iterator <= Length(edgeList) do - if edgeList[iterator][1] in subdigraphVertices2 and - edgeList[iterator][2] in subdigraphVertices2 then - Remove(edgeList, iterator); - else - edgeList[iterator] := [ - map.(edgeList[iterator][1]), map.(edgeList[iterator][2])]; - iterator := iterator + 1; - fi; - od; + + # edgeList := ShallowCopy(DigraphEdges(D2)); + # iterator := 1; + # while iterator <= Length(edgeList) do + # if edgeList[iterator][1] in subdigraphVertices2 and + # edgeList[iterator][2] in subdigraphVertices2 then + # Remove(edgeList, iterator); + # else + # edgeList[iterator] := [ + # map.(edgeList[iterator][1]), map.(edgeList[iterator][2])]; + # iterator := iterator + 1; + # fi; + # od; DigraphAddVertices(D, DigraphNrVertices(D2) - Length(subdigraphVertices1)); DigraphAddEdges(D, edgeList); - return [Immutable(D), map]; + return [Immutable(DigraphRemoveAllMultipleEdges(D)), map]; end); ############################################################################### diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index 48baca7f7..492bd614d 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -2772,7 +2772,9 @@ gap> U := AmalgamDigraphs(D1, D2, [2, 3, 6, 7], [4, 5, 6, 7]); [ , rec( 1 := 9, 2 := 10, 3 := 11, 4 := 2, 5 := 3, 6 := 6, 7 := 7 ) ] gap> AmalgamDigraphs(D1, D2, [3, 6, 2, 7], [4, 5, 7, 6]); -Error, the two subdigraphs must be equal. +Error, the subdigraph induced by the 3rd argument (a list) in the 1st argument\ + (a digraph) does not equal the subdigraph induced by the 4th argument (a list\ +) in the 2nd argument (a digraph) gap> D1 := PetersenGraph();; gap> U := AmalgamDigraphs(D1, D1, [3, 4, 6, 8, 9], [3, 4, 6, 8, 9]); [ , @@ -2790,7 +2792,9 @@ gap> U := AmalgamDigraphsIsomorphic(D1, D2, [3, 4, 6, 8, 9], rec( 1 := 11, 2 := 3, 3 := 12, 4 := 4, 5 := 8, 6 := 9, 7 := 6, 8 := 13 ) ] gap> U := AmalgamDigraphsIsomorphic(D1, D2, [3, 4, 10, 8, 9], > [2, 4, 5, 6, 7]); -Error, the two subdigraphs must be isomorphic. +Error, the subdigraph induced by the 3rd argument (a list) in the 1st argument\ + (a digraph) is not ismorphic to the subdigraph induced by the 4th argument (a\ + list) in the 2nd argument (a digraph) #DIGRAPHS_UnbindVariables gap> Unbind(a); From 49e5ef59c1b9e9481a2e4a6215474ea2b275785a Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 13 Apr 2022 15:26:13 +0100 Subject: [PATCH 7/8] Resolved comments on original function. --- gap/oper.gi | 79 ++++++++++++++----------------------------- tst/standard/oper.tst | 10 +++--- 2 files changed, 30 insertions(+), 59 deletions(-) diff --git a/gap/oper.gi b/gap/oper.gi index 68f11077a..70a28b130 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -797,82 +797,53 @@ InstallMethod(AmalgamDigraphs, "for a digraph, a digraph, a list, and a list", [IsDigraph, IsDigraph, IsList, IsList], function(D1, D2, subdigraphVertices1, subdigraphVertices2) - local D, map, vertex, vertexList, size, iterator, edgeList, edge; + local D, n, map, T, vertex, edge; if not InducedSubdigraph(DigraphImmutableCopyIfMutable(D1), - subdigraphVertices1) = + subdigraphVertices1) = InducedSubdigraph(DigraphImmutableCopyIfMutable(D2), subdigraphVertices2) then ErrorNoReturn( - "the subdigraph induced by the 3rd argument (a list) in the 1st ", - "argument (a digraph) does not equal the subdigraph induced by the ", - "4th argument (a list) in the 2nd argument (a digraph)"); + "the subdigraph induced by the 3rd argument (a list) in the 1st ", + "argument (a digraph) does not equal the subdigraph induced by the ", + "4th argument (a list) in the 2nd argument (a digraph)"); fi; - # Create a mutable copy so that the function also works on - # immutable input digraphs and also does not change mutable - # digraphs in place. - D := DigraphMutableCopy(D1); + # Create a mutable copy so that the function also works if + # D1 is immutable. If D1 is a mutable digraph then + # D1 will be changed in place. + D := DigraphMutableCopyIfImmutable(D1); + + n := DigraphNrVertices(D2) + DigraphNrVertices(D1); + n := n - Length(subdigraphVertices1); # 'map' is a mapping from the vertices of D2 to the vertices of the # final output graph. The idea is to map the subdigraph vertices of D2 # onto the subdigraph vertices of D1 and then map the rest of the vertices # of D2 to other (higher) values. The mapping from D1 to the output graph # can be understood as the identity mapping. - map := [1 .. DigraphNrVertices(D2)]; + + map := [1 .. n]; for vertex in [1 .. Length(subdigraphVertices1)] do map[subdigraphVertices2[vertex]] := subdigraphVertices1[vertex]; od; - # Delete?? - # vertexList := Difference(DigraphVertices(D2), subdigraphVertices2); - # size := DigraphNrVertices(D1); - # iterator := 1; - # for vertex in vertexList do - # map[vertex] := iterator + size; - # iterator := iterator + 1; - # od; - - - iterator := 1; - for edge in [1 .. DigraphNrEdges(D2)] do - Add(edgeList, []); - for vertex in [1, 2] do - if DigraphEdges(D2)[edge][vertex] in subdigraphVertices2 then - DigraphEdges(D2)[edge][vertex] := DigraphEdges(D2)[edge][vertex] ^ Transformation(map); - else - DigraphEdges(D2)[edge][vertex] := # But we still need a mapping for the non-subdigraph vertices - fi; - od; - od; + map{Difference(DigraphVertices(D2), subdigraphVertices2)} := + [DigraphNrVertices(D1) + 1 .. n]; + T := Transformation(map); + DigraphAddVertices(D, DigraphNrVertices(D2) - Length(subdigraphVertices1)); - # The problem with adding edges to the output graph was that the - # edges of the subdigraph were added twice, creating multiple - # edges between certain pairs of points. A quick and readable fix - # would have been to use DigraphRemoveAllMultipleEdges, but I decided - # to check each of the edges being added to see if they were already - # in the subdigraph. This way the function does not end up adding edges - # only to delete them later. - - # edgeList := ShallowCopy(DigraphEdges(D2)); - # iterator := 1; - # while iterator <= Length(edgeList) do - # if edgeList[iterator][1] in subdigraphVertices2 and - # edgeList[iterator][2] in subdigraphVertices2 then - # Remove(edgeList, iterator); - # else - # edgeList[iterator] := [ - # map.(edgeList[iterator][1]), map.(edgeList[iterator][2])]; - # iterator := iterator + 1; - # fi; - # od; + for edge in DigraphEdges(D2) do + if not (edge[1] in subdigraphVertices2 + and edge[2] in subdigraphVertices2) then + DigraphAddEdge(D, [edge[1] ^ T, edge[2] ^ T]); + fi; + od; - DigraphAddVertices(D, DigraphNrVertices(D2) - Length(subdigraphVertices1)); - DigraphAddEdges(D, edgeList); - return [Immutable(DigraphRemoveAllMultipleEdges(D)), map]; + return [MakeImmutable(D), T]; end); ############################################################################### diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index 492bd614d..7dbb300ed 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -2762,7 +2762,7 @@ gap> D1 := Digraph([[2, 3], [1, 3], [1, 2], [2], [3, 4]]);; gap> D2 := Digraph([[2, 6], [1, 3, 5], [4], [3], [4, 6], [1, 5]]);; gap> U := AmalgamDigraphs(D1, D2, [2, 3, 4, 5], [4, 3, 5, 2]); [ , - rec( 1 := 6, 2 := 5, 3 := 3, 4 := 2, 5 := 4, 6 := 7 ) ] + Transformation( [ 6, 5, 3, 2, 4, 7, 7 ] ) ] gap> D1 := Digraph([ > [2, 3], [1, 3, 4, 6], [1, 2, 5, 7], [2, 6], [3, 7], [2, 4, 7, 8], > [3, 5, 6, 8], [6, 7]]);; @@ -2770,7 +2770,7 @@ gap> D2 := Digraph([ > [2, 3], [1, 4], [1, 5], [2, 5, 6], [3, 4, 7], [4, 7], [5, 6]]);; gap> U := AmalgamDigraphs(D1, D2, [2, 3, 6, 7], [4, 5, 6, 7]); [ , - rec( 1 := 9, 2 := 10, 3 := 11, 4 := 2, 5 := 3, 6 := 6, 7 := 7 ) ] + Transformation( [ 9, 10, 11, 2, 3, 6, 7, 8, 9, 10, 11 ] ) ] gap> AmalgamDigraphs(D1, D2, [3, 6, 2, 7], [4, 5, 7, 6]); Error, the subdigraph induced by the 3rd argument (a list) in the 1st argument\ (a digraph) does not equal the subdigraph induced by the 4th argument (a list\ @@ -2778,8 +2778,8 @@ Error, the subdigraph induced by the 3rd argument (a list) in the 1st argument\ gap> D1 := PetersenGraph();; gap> U := AmalgamDigraphs(D1, D1, [3, 4, 6, 8, 9], [3, 4, 6, 8, 9]); [ , - rec( 1 := 11, 10 := 15, 2 := 12, 3 := 3, 4 := 4, 5 := 13, 6 := 6, 7 := 14, - 8 := 8, 9 := 9 ) ] + Transformation( [ 11, 12, 3, 4, 13, 6, 14, 8, 9, 15, 11, 12, 13, 14, 15 ] ) + ] # AmalgamDigraphsIsomorphic gap> D1 := PetersenGraph();; @@ -2789,7 +2789,7 @@ gap> D2 := Digraph([ gap> U := AmalgamDigraphsIsomorphic(D1, D2, [3, 4, 6, 8, 9], > [2, 4, 5, 6, 7]); [ , - rec( 1 := 11, 2 := 3, 3 := 12, 4 := 4, 5 := 8, 6 := 9, 7 := 6, 8 := 13 ) ] + Transformation( [ 11, 3, 12, 4, 8, 9, 6, 13, 9, 10, 11, 12, 13 ] ) ] gap> U := AmalgamDigraphsIsomorphic(D1, D2, [3, 4, 10, 8, 9], > [2, 4, 5, 6, 7]); Error, the subdigraph induced by the 3rd argument (a list) in the 1st argument\ From 781dcb9b639919ab7179304835ca6f6e6fbc66ec Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 11 May 2022 08:02:49 +0100 Subject: [PATCH 8/8] Addressed issues with previous pull request. Made description of amalgam more rigorous. --- doc/oper.xml | 115 ++++++++++++--------------- doc/z-chap2.xml | 1 - gap/oper.gd | 13 +++- gap/oper.gi | 177 +++++++++++++++++++++++++++++++----------- tst/standard/oper.tst | 134 +++++++++++++++++++++++++------- 5 files changed, 296 insertions(+), 144 deletions(-) diff --git a/doc/oper.xml b/doc/oper.xml index 9e0db3449..d8d03e86c 100644 --- a/doc/oper.xml +++ b/doc/oper.xml @@ -2231,78 +2231,61 @@ true <#GAPDoc Label="AmalgamDigraphs"> - An immutable digraph and a record. + S[, map1[, map2]]"/> + An immutable digraph and a transformation. AmalgamDigraphs takes as input two digraphs D1 and D2 - and two lists of vertices subdigraphVertices1 and - subdigraphVertices2, which correspond to two identical subdigraphs - of D1 and D2. It returns a new digraph, the amalgam - digraph AD, which consists of D1 and D2 joined - together by their common subdigraph in such a way that the edge connectivity - between the vertices of AD matches the edge connectivity of - D1 and D2.

- - It returns a tuple of size two, with the first element being - AD and the second element being map, which is a record which - maps each vertex's number in D2 to the corresponding vertex's number - in AD. The mapping of the vertices of D1 can be seen as the - identity mapping. + and a digraph S for which there is an embedding into both + D1 and D2. Additional optional arguments map1 and + map2 are transformation objects which can force specific + embeddings of S into D1 and D2 respectively. If + map1 and map2 are not given then arbitrary embeddings + will be found using DigraphEmbedding. If no embeddings can be found + the function will throw an error.

+ + If D1, D2 and S are not multidigraphs then + AmalgamDigraphs calculates a new digraph, the amalgam digraph + D_A. D_A is an amalgam of D1 and D2 over + S with respect to embeddings (where the embeddings of S into + D1 and D2 can be specified by map1 and map2). + The embedding of D1 into D_A is set to always be the + IdentityTransformation.

+ + Note that AmalgamDigraphs does not necessarily return the smallest + possible digraph satisfying these properties. For examble, when + D1 and D2 are equal, the embedding from D2 + to D_A will not be the IdentityTransformation and so + D_A could have many more vertices than the smallest possible amalgam + of D1 and D2 over S. A less formal way to picture + the exact form of D_A is to think of it as D1 and D2 + 'joined together' by the common subdigraph S.

+ + AmalgamDigraphs returns a tuple of size two, with the first + element being the digraph A_D and the second element being a + transformation object which describes the embedding of D2 into + A_D. T := Digraph([[2, 3], [1, 3], [1, 2]]);; -gap> A := AmalgamDigraphs(T, T, [1, 2], [1, 2]); +gap> D := CycleGraph(3);; +gap> S := PathGraph(2);; +gap> AmalgamDigraphs(D, D, S); [ , - rec( 1 := 1, 2 := 2, 3 := 4 ) ] -gap> A := AmalgamDigraphs(A[1], T, [1, 2], [1, 2]); -[ , - rec( 1 := 1, 2 := 2, 3 := 5 ) ] -gap> P := PetersenGraph();; -gap> G := Digraph([[2, 3, 4], [1, 3], [1, 2, 5], -> [1, 6], [3, 6], [4, 5]]);; -gap> A := AmalgamDigraphs(P, G, [1, 2, 7, 10, 5], [1, 3, 5, 6, 4]); -[ , - rec( 1 := 1, 2 := 11, 3 := 2, 4 := 5, 5 := 7, 6 := 10 ) ] -]]> - - -<#/GAPDoc> - -<#GAPDoc Label="AmalgamDigraphsIsomorphic"> - - - An immutable digraph and a record. - - - AmalgamDigraphsIsomorphic is meant to function very similarly to - AmalgamDigraphs. The difference is that in AmalgamDigraphs - subdigraphVertices1 and subdigraphVertices2 need not - necessarily describe identical subdigraphs of D1 and D2, - but need only describe subdigraphs that are isomorphic to one another. - AmalgamDigraphsIsomorphic rearranges the entries of - subdigraphVertices2 to obtain newSubdigraphVertices2 - in such a way that the induced subdigraph in D2 with the - vertices newSubdigraphVertices2 is identical to the induced - subdigraph in D1 with the vertices subdigraphVertices1. - AmalgamDigraphsIsomorphic then calls AmalgamDigraphs - with newSubdigraphVertices2 in the place of - subdigraphVertices2. - - P := PetersenGraph();; -gap> G := Digraph([[2, 3, 4], [1, 3], -> [1, 2, 5], [1, 6], [3, 6], [4, 5]]);; -gap> A := AmalgamDigraphs(P, G, [1, 2, 7, 10, 5], [1, 3, 5, 6, 4]); -[ , - rec( 1 := 1, 2 := 11, 3 := 2, 4 := 5, 5 := 7, 6 := 10 ) ] -gap> A := AmalgamDigraphsIsomorphic(P, G, -> [1, 2, 7, 10, 5], [1, 4, 6, 3, 5]); -[ , - rec( 1 := 1, 2 := 11, 3 := 5, 4 := 2, 5 := 10, 6 := 7 ) ] -gap> A := AmalgamDigraphs(P, G, [1, 2, 7, 10, 5], [1, 4, 6, 3, 5]); -Error, the two subdigraphs must be equal. + Transformation( [ 1, 2, 4, 4 ] ) ] +gap> D := PetersonGraph();; +gap> S := CycleGraph(5);; +gap> AmalgamDigraphs(D, D, S); +[ , + Transformation( [ 1, 2, 3, 4, 5, 11, 12, 13, 14, 15, 11, 12, 13, 14, 15 ] ) + ] +gap> D1 := Digraph([[2, 3], [1, 3, 4], [1, 2, 4], [2, 3, 5], [4]]);; +gap> D2 := Digraph([[2, 3], [1, 3, 4], [1, 2, 4, 5], [2, 3, 5], [3, 4]]);; +gap> S := CycleGraph(3);; +gap> map1 := Transformation([2, 4, 3, 4]);; +gap> map2 := Transformation([2, 3, 4, 4]);; +gap> AmalgamDigraphs(D1, D2, S, map1, map2); +[ , + Transformation( [ 6, 2, 4, 3, 7, 6, 7 ] ) ] ]]> diff --git a/doc/z-chap2.xml b/doc/z-chap2.xml index 33a4e3c6e..8272edbf7 100644 --- a/doc/z-chap2.xml +++ b/doc/z-chap2.xml @@ -75,7 +75,6 @@ <#Include Label="DigraphClosure"> <#Include Label="DigraphMycielskian"> <#Include Label="AmalgamDigraphs"> - <#Include Label="AmalgamDigraphsIsomorphic">

Random digraphs diff --git a/gap/oper.gd b/gap/oper.gd index 35caa5c31..f4abc08b0 100644 --- a/gap/oper.gd +++ b/gap/oper.gd @@ -46,9 +46,13 @@ DeclareOperation("StrongProduct", [IsDigraph, IsDigraph]); DeclareOperation("ConormalProduct", [IsDigraph, IsDigraph]); DeclareOperation("HomomorphicProduct", [IsDigraph, IsDigraph]); DeclareOperation("LexicographicProduct", [IsDigraph, IsDigraph]); -DeclareOperation("AmalgamDigraphs", [IsDigraph, IsDigraph, IsList, IsList]); -DeclareOperation("AmalgamDigraphsIsomorphic", - [IsDigraph, IsDigraph, IsList, IsList]); +DeclareOperation("AmalgamDigraphs", + [IsDigraph, IsDigraph, IsDigraph, + IsTransformation, IsTransformation]); +DeclareOperation("AmalgamDigraphs", + [IsDigraph, IsDigraph, IsDigraph, IsTransformation]); +DeclareOperation("AmalgamDigraphs", + [IsDigraph, IsDigraph, IsDigraph,]); DeclareSynonym("DigraphModularProduct", ModularProduct); DeclareSynonym("DigraphStrongProduct", StrongProduct); @@ -58,6 +62,9 @@ DeclareSynonym("DigraphLexicographicProduct", LexicographicProduct); DeclareGlobalFunction("DIGRAPHS_CombinationOperProcessArgs"); DeclareOperation("DIGRAPHS_GraphProduct", [IsDigraph, IsDigraph, IsFunction]); +DeclareOperation("NOCHECKS_AmalgamDigraphs", + [IsDigraph, IsDigraph, IsDigraph, + IsTransformation, IsTransformation]); # 4. Actions . . . DeclareOperation("OnDigraphs", [IsDigraph, IsPerm]); diff --git a/gap/oper.gi b/gap/oper.gi index 70a28b130..2ff8f6880 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -765,80 +765,163 @@ function(D1, D2, edge_function) return Digraph(edges); end); -InstallMethod(AmalgamDigraphsIsomorphic, +InstallMethod(AmalgamDigraphs, "for a digraph, a digraph, a list, and a list", -[IsDigraph, IsDigraph, IsList, IsList], -function(D1, D2, subdigraphVertices1, subdigraphVertices2) - local subdigraph1, subdigraph2, newSubdigraphVertices2, transformation, vertex; +[IsDigraph, IsDigraph, IsDigraph, IsTransformation, IsTransformation], +function(D1, D2, S, map1, map2) + local D, n, imageList1, imageList2, map, edge, T; - subdigraph1 := InducedSubdigraph(DigraphImmutableCopyIfMutable(D1), - subdigraphVertices1); - subdigraph2 := InducedSubdigraph(DigraphImmutableCopyIfMutable(D2), - subdigraphVertices2); + if IsMultiDigraph(D1) then + ErrorNoReturn( + "the 1st argument (a digraph) must not satisfy IsMultiDigraph"); + elif IsMultiDigraph(D2) then + ErrorNoReturn( + "the 2nd argument (a digraph) must not satisfy IsMultiDigraph"); + elif IsMultiDigraph(S) then + ErrorNoReturn( + "the 3rd argument (a digraph) must not satisfy IsMultiDigraph"); + fi; - if not IsIsomorphicDigraph(subdigraph1, subdigraph2) then + if not IsDigraphEmbedding(S, D1, map1) then ErrorNoReturn( - "the subdigraph induced by the 3rd argument (a list) in the 1st ", - "argument (a digraph) is not ismorphic to the subdigraph induced ", - "by the 4th argument (a list) in the 2nd argument (a digraph)"); + "the 4th argument (a transformation) is not ", + "a digraph embedding from the 3rd argument (a digraph) into ", + "the 1st argument (a digraph)"); fi; + if not IsDigraphEmbedding(S, D2, map2) then + ErrorNoReturn( + "the 5th argument (a transformation) is not ", + "a digraph embedding from the 3rd argument (a digraph) into ", + "the 2nd argument (a digraph)"); + fi; + + # Create a mutable copy so that the function also works if + # D1 is immutable. If D1 is a mutable digraph then + # D1 will be changed in place. + D := DigraphMutableCopyIfImmutable(D1); + + n := DigraphNrVertices(D2) + DigraphNrVertices(D1) - DigraphNrVertices(S); + + # 'map' is an embedding of D2 into the final output graph. + # The embedding of D1 into the final output graph is the identity mapping. - newSubdigraphVertices2 := []; - transformation := DigraphEmbedding(subdigraph2, subdigraph1); - for vertex in subdigraphVertices2 do - newSubdigraphVertices2[ - Position(subdigraphVertices2, vertex) ^ transformation] := vertex; + map := [1 .. n]; + + imageList1 := OnTuples([1 .. DigraphNrVertices(S)], map1); + imageList2 := OnTuples([1 .. DigraphNrVertices(S)], map2); + + map{imageList2} := imageList1; + map{Difference(DigraphVertices(D2), imageList2)} := + [DigraphNrVertices(D1) + 1 .. n]; + + T := Transformation(map); + + DigraphAddVertices(D, DigraphNrVertices(D2) - DigraphNrVertices(S)); + + for edge in DigraphEdges(D2) do + if not (edge[1] in imageList2 + and edge[2] in imageList2) then + DigraphAddEdge(D, [edge[1] ^ T, edge[2] ^ T]); + fi; od; - return AmalgamDigraphs(D1, D2, subdigraphVertices1, newSubdigraphVertices2); + return [MakeImmutable(D), T]; +end); + +InstallMethod(AmalgamDigraphs, +"for a digraph, a digraph, a list, and a list", +[IsDigraph, IsDigraph, IsDigraph, IsTransformation], +function(D1, D2, S, map1) + local map2; + + if IsMultiDigraph(D1) then + ErrorNoReturn( + "the 1st argument (a digraph) must not satisfy IsMultiDigraph"); + elif IsMultiDigraph(D2) then + ErrorNoReturn( + "the 2nd argument (a digraph) must not satisfy IsMultiDigraph"); + elif IsMultiDigraph(S) then + ErrorNoReturn( + "the 3rd argument (a digraph) must not satisfy IsMultiDigraph"); + fi; + + if not IsDigraphEmbedding(S, D1, map1) then + ErrorNoReturn( + "the 4th argument (a transformation) is not ", + "a digraph embedding from the 3rd argument (a digraph) into ", + "the 1st argument (a digraph)"); + fi; + + map2 := DigraphEmbedding(S, D2); + if map2 = fail then + ErrorNoReturn( + "no embeddings could be found from the 3rd argument ", + "(a digraph) to the 2nd argument (a digraph)"); + fi; + + return NOCHECKS_AmalgamDigraphs(D1, D2, S, map1, map2); end); InstallMethod(AmalgamDigraphs, "for a digraph, a digraph, a list, and a list", -[IsDigraph, IsDigraph, IsList, IsList], -function(D1, D2, subdigraphVertices1, subdigraphVertices2) - local D, n, map, T, vertex, edge; - - if not InducedSubdigraph(DigraphImmutableCopyIfMutable(D1), - subdigraphVertices1) = - InducedSubdigraph(DigraphImmutableCopyIfMutable(D2), - subdigraphVertices2) then +[IsDigraph, IsDigraph, IsDigraph], +function(D1, D2, S) + local map1, map2; + + if IsMultiDigraph(D1) then + ErrorNoReturn( + "the 1st argument (a digraph) must not satisfy IsMultiDigraph"); + elif IsMultiDigraph(D2) then + ErrorNoReturn( + "the 2nd argument (a digraph) must not satisfy IsMultiDigraph"); + elif IsMultiDigraph(S) then ErrorNoReturn( - "the subdigraph induced by the 3rd argument (a list) in the 1st ", - "argument (a digraph) does not equal the subdigraph induced by the ", - "4th argument (a list) in the 2nd argument (a digraph)"); + "the 3rd argument (a digraph) must not satisfy IsMultiDigraph"); fi; - # Create a mutable copy so that the function also works if - # D1 is immutable. If D1 is a mutable digraph then - # D1 will be changed in place. - D := DigraphMutableCopyIfImmutable(D1); + map1 := DigraphEmbedding(S, D1); + if map1 = fail then + ErrorNoReturn( + "no embeddings could be found from the 3rd argument ", + "(a digraph) to the 1st argument (a digraph)"); + fi; - n := DigraphNrVertices(D2) + DigraphNrVertices(D1); - n := n - Length(subdigraphVertices1); + map2 := DigraphEmbedding(S, D2); + if map2 = fail then + ErrorNoReturn( + "no embeddings could be found from the 3rd argument ", + "(a digraph) to the 2nd argument (a digraph)"); + fi; - # 'map' is a mapping from the vertices of D2 to the vertices of the - # final output graph. The idea is to map the subdigraph vertices of D2 - # onto the subdigraph vertices of D1 and then map the rest of the vertices - # of D2 to other (higher) values. The mapping from D1 to the output graph - # can be understood as the identity mapping. + return NOCHECKS_AmalgamDigraphs(D1, D2, S, map1, map2); +end); + +InstallMethod(NOCHECKS_AmalgamDigraphs, +"for a digraph, a digraph, a list, and a list", +[IsDigraph, IsDigraph, IsDigraph, IsTransformation, IsTransformation], +function(D1, D2, S, map1, map2) + local D, n, imageList1, imageList2, map, edge, T; + + D := DigraphMutableCopyIfImmutable(D1); + + n := DigraphNrVertices(D2) + DigraphNrVertices(D1) - DigraphNrVertices(S); map := [1 .. n]; - for vertex in [1 .. Length(subdigraphVertices1)] do - map[subdigraphVertices2[vertex]] := subdigraphVertices1[vertex]; - od; + imageList1 := OnTuples([1 .. DigraphNrVertices(S)], map1); + imageList2 := OnTuples([1 .. DigraphNrVertices(S)], map2); - map{Difference(DigraphVertices(D2), subdigraphVertices2)} := + map{imageList2} := imageList1; + map{Difference(DigraphVertices(D2), imageList2)} := [DigraphNrVertices(D1) + 1 .. n]; T := Transformation(map); - DigraphAddVertices(D, DigraphNrVertices(D2) - Length(subdigraphVertices1)); + DigraphAddVertices(D, DigraphNrVertices(D2) - DigraphNrVertices(S)); for edge in DigraphEdges(D2) do - if not (edge[1] in subdigraphVertices2 - and edge[2] in subdigraphVertices2) then + if not (edge[1] in imageList2 + and edge[2] in imageList2) then DigraphAddEdge(D, [edge[1] ^ T, edge[2] ^ T]); fi; od; diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index 7dbb300ed..06d14646a 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -2760,41 +2760,118 @@ true # AmalgamDigraphs gap> D1 := Digraph([[2, 3], [1, 3], [1, 2], [2], [3, 4]]);; gap> D2 := Digraph([[2, 6], [1, 3, 5], [4], [3], [4, 6], [1, 5]]);; -gap> U := AmalgamDigraphs(D1, D2, [2, 3, 4, 5], [4, 3, 5, 2]); +gap> S := InducedSubdigraph(D1, [2, 3, 4, 5]);; +gap> T := DigraphEmbedding(S, D2);; +gap> U := AmalgamDigraphs(D2, D1, S, T); [ , - Transformation( [ 6, 5, 3, 2, 4, 7, 7 ] ) ] + Transformation( [ 7, 4, 3, 5, 2, 6, 7 ] ) ] +gap> U := AmalgamDigraphs(D1, D2, S, IdentityTransformation, T); +Error, the 4th argument (a transformation) is not a digraph embedding from the\ + 3rd argument (a digraph) into the 1st argument (a digraph) gap> D1 := Digraph([ > [2, 3], [1, 3, 4, 6], [1, 2, 5, 7], [2, 6], [3, 7], [2, 4, 7, 8], > [3, 5, 6, 8], [6, 7]]);; gap> D2 := Digraph([ > [2, 3], [1, 4], [1, 5], [2, 5, 6], [3, 4, 7], [4, 7], [5, 6]]);; -gap> U := AmalgamDigraphs(D1, D2, [2, 3, 6, 7], [4, 5, 6, 7]); -[ , - Transformation( [ 9, 10, 11, 2, 3, 6, 7, 8, 9, 10, 11 ] ) ] -gap> AmalgamDigraphs(D1, D2, [3, 6, 2, 7], [4, 5, 7, 6]); -Error, the subdigraph induced by the 3rd argument (a list) in the 1st argument\ - (a digraph) does not equal the subdigraph induced by the 4th argument (a list\ -) in the 2nd argument (a digraph) +gap> S := InducedSubdigraph(D1, [2, 3, 6, 7]);; +gap> T := DigraphEmbedding(S, D1);; +gap> U := AmalgamDigraphs(D1, D2, S, T, IdentityTransformation); +Error, the 5th argument (a transformation) is not a digraph embedding from the\ + 3rd argument (a digraph) into the 2nd argument (a digraph) +gap> D1 := Digraph([[2, 5], [1, 3], [4], [2, 5], [1, 4]]);; +gap> D2 := Digraph([[2, 3], [1, 4], [1, 2], [3]]);; +gap> S := Digraph([[2], [3], [1]]);; +gap> map1 := DigraphEmbedding(S, D1);; +gap> map2 := DigraphEmbedding(S, D2);; +gap> U := AmalgamDigraphs(D1, D2, S, map1, map2); +[ , + Transformation( [ 6, 2, 4, 3, 5, 6 ] ) ] +gap> D1 := DigraphImmutableCopy(D1); + +gap> U := AmalgamDigraphs(D1, D2, S, map1, map2); +[ , + Transformation( [ 6, 2, 4, 3, 5, 6 ] ) ] +gap> D1 := DigraphMutableCopy(D1); + +gap> U := AmalgamDigraphs(D1, D2, S, map1, map2); +[ , + Transformation( [ 6, 2, 4, 3, 5, 6 ] ) ] +gap> D1; + +gap> D1 := Digraph([[2, 5], [1, 3], [4], [2, 5], [1, 4]]);; +gap> D2 := DigraphMutableCopy(D2); + +gap> U := AmalgamDigraphs(D1, D2, S, map1, map2); +[ , + Transformation( [ 6, 2, 4, 3, 5, 6 ] ) ] +gap> D2; + +gap> D1 := DigraphImmutableCopy(D1); + +gap> U := AmalgamDigraphs(D1, D2, S, map1, map2); +[ , + Transformation( [ 6, 2, 4, 3, 5, 6 ] ) ] gap> D1 := PetersenGraph();; -gap> U := AmalgamDigraphs(D1, D1, [3, 4, 6, 8, 9], [3, 4, 6, 8, 9]); -[ , - Transformation( [ 11, 12, 3, 4, 13, 6, 14, 8, 9, 15, 11, 12, 13, 14, 15 ] ) - ] - -# AmalgamDigraphsIsomorphic +gap> D2 := Digraph([[], [1, 3, 4], [1, 2, 5], [2, 6], [3, 6], [4, 5]]);; +gap> S := CycleGraph(5);; +gap> U := AmalgamDigraphs(D1, D2, S, IdentityTransformation); +[ , + Transformation( [ 11, 1, 2, 5, 3, 4, 7, 8, 9, 10, 11 ] ) ] +gap> U := AmalgamDigraphs(D1, D2, S); +[ , + Transformation( [ 11, 1, 2, 5, 3, 4, 7, 8, 9, 10, 11 ] ) ] +gap> D1 := Digraph([[2], [3, 4], [1], [1]]);; +gap> D2 := Digraph([[3], [1], [2, 4, 5], [], []]);; +gap> S := Digraph([[2], [3], [1]]);; +gap> map1 := Transformation([1, 2, 4, 4]);; +gap> map2 := Transformation([2, 1]);; +gap> U := AmalgamDigraphs(D1, D2, S, map1, map2); +[ , + Transformation( [ 2, 1, 4, 5, 6, 6 ] ) ] +gap> U := AmalgamDigraphs(D1, D2, S, map1); +[ , + Transformation( [ 1, 4, 2, 5, 6, 6 ] ) ] +gap> U := AmalgamDigraphs(D1, D2, S); +[ , + Transformation( [ 1, 3, 2, 5, 6, 6 ] ) ] +gap> U := AmalgamDigraphs(D1, D2, S, Transformation([3, 2, 1])); +Error, the 4th argument (a transformation) is not a digraph embedding from the\ + 3rd argument (a digraph) into the 1st argument (a digraph) +gap> U := AmalgamDigraphs(D1, D2, D1, IdentityTransformation); +Error, no embeddings could be found from the 3rd argument (a digraph) to the 2\ +nd argument (a digraph) +gap> U := AmalgamDigraphs(D1, D2, D1); +Error, no embeddings could be found from the 3rd argument (a digraph) to the 2\ +nd argument (a digraph) +gap> U := AmalgamDigraphs(D1, D2, D2); +Error, no embeddings could be found from the 3rd argument (a digraph) to the 1\ +st argument (a digraph) +gap> D1 := Digraph([[2, 3, 3], [3], []]);; +gap> D2 := Digraph([[2, 3], [3, 4], [4], []]);; +gap> S := Digraph([[2, 3], [3], []]);; +gap> AmalgamDigraphs(D1, D2, S); +Error, the 1st argument (a digraph) must not satisfy IsMultiDigraph +gap> AmalgamDigraphs(D1, D2, S, IdentityTransformation); +Error, the 1st argument (a digraph) must not satisfy IsMultiDigraph +gap> AmalgamDigraphs( +> D1, D2, S, IdentityTransformation, IdentityTransformation); +Error, the 1st argument (a digraph) must not satisfy IsMultiDigraph +gap> AmalgamDigraphs(D2, D1, S); +Error, the 2nd argument (a digraph) must not satisfy IsMultiDigraph +gap> AmalgamDigraphs(D2, D1, S, IdentityTransformation); +Error, the 2nd argument (a digraph) must not satisfy IsMultiDigraph +gap> AmalgamDigraphs( +> D2, D1, S, IdentityTransformation, IdentityTransformation); +Error, the 2nd argument (a digraph) must not satisfy IsMultiDigraph gap> D1 := PetersenGraph();; -gap> D2 := Digraph([ -> [2, 4], [1, 3, 4, 5], [2, 5], [1, 2, 6], [2, 3, 7], [4, 7, 8], -> [5, 6, 8], [6, 7]]);; -gap> U := AmalgamDigraphsIsomorphic(D1, D2, [3, 4, 6, 8, 9], -> [2, 4, 5, 6, 7]); -[ , - Transformation( [ 11, 3, 12, 4, 8, 9, 6, 13, 9, 10, 11, 12, 13 ] ) ] -gap> U := AmalgamDigraphsIsomorphic(D1, D2, [3, 4, 10, 8, 9], -> [2, 4, 5, 6, 7]); -Error, the subdigraph induced by the 3rd argument (a list) in the 1st argument\ - (a digraph) is not ismorphic to the subdigraph induced by the 4th argument (a\ - list) in the 2nd argument (a digraph) +gap> S := Digraph([[2], [3, 3], [1]]);; +gap> AmalgamDigraphs(D1, D1, S); +Error, the 3rd argument (a digraph) must not satisfy IsMultiDigraph +gap> AmalgamDigraphs(D1, D1, S, IdentityTransformation); +Error, the 3rd argument (a digraph) must not satisfy IsMultiDigraph +gap> AmalgamDigraphs( +> D1, D1, S, IdentityTransformation, IdentityTransformation); +Error, the 3rd argument (a digraph) must not satisfy IsMultiDigraph #DIGRAPHS_UnbindVariables gap> Unbind(a); @@ -2858,6 +2935,9 @@ gap> Unbind(temp); gap> Unbind(U); gap> Unbind(u1); gap> Unbind(u2); +gap> Unbind(S); +gap> Unbind(map1); +gap> Unbind(map2); # gap> DIGRAPHS_StopTest();