Skip to content

Commit 781dcb9

Browse files
committed
Addressed issues with previous pull request. Made description of amalgam more rigorous.
1 parent 49e5ef5 commit 781dcb9

File tree

5 files changed

+296
-144
lines changed

5 files changed

+296
-144
lines changed

doc/oper.xml

+49-66
Original file line numberDiff line numberDiff line change
@@ -2231,78 +2231,61 @@ true
22312231
<#GAPDoc Label="AmalgamDigraphs">
22322232
<ManSection>
22332233
<Oper Name="AmalgamDigraphs" Arg="D1, D2,
2234-
subdigraphVertices1, subdigraphVertices2"/>
2235-
<Returns>An immutable digraph and a record.</Returns>
2234+
S[, map1[, map2]]"/>
2235+
<Returns>An immutable digraph and a transformation.</Returns>
22362236
<Description>
22372237

22382238
<C>AmalgamDigraphs</C> takes as input two digraphs <A>D1</A> and <A>D2</A>
2239-
and two lists of vertices <A>subdigraphVertices1</A> and
2240-
<A>subdigraphVertices2</A>, which correspond to two identical subdigraphs
2241-
of <A>D1</A> and <A>D2</A>. It returns a new digraph, the <E>amalgam
2242-
digraph</E> <C>AD</C>, which consists of <A>D1</A> and <A>D2</A> joined
2243-
together by their common subdigraph in such a way that the edge connectivity
2244-
between the vertices of <C>AD</C> matches the edge connectivity of
2245-
<A>D1</A> and <A>D2</A>.<P/>
2246-
2247-
It returns a <E>tuple</E> of size two, with the first element being
2248-
<C>AD</C> and the second element being <C>map</C>, which is a record which
2249-
maps each vertex's number in <A>D2</A> to the corresponding vertex's number
2250-
in <C>AD</C>. The mapping of the vertices of <A>D1</A> can be seen as the
2251-
<E>identity mapping</E>.
2239+
and a digraph <A>S</A> for which there is an embedding into both
2240+
<A>D1</A> and <A>D2</A>. Additional optional arguments <A>map1</A> and
2241+
<A>map2</A> are transformation objects which can force specific
2242+
embeddings of <A>S</A> into <A>D1</A> and <A>D2</A> respectively. If
2243+
<A>map1</A> and <A>map2</A> are not given then arbitrary embeddings
2244+
will be found using <C>DigraphEmbedding</C>. If no embeddings can be found
2245+
the function will throw an error.<P/>
2246+
2247+
If <A>D1</A>, <A>D2</A> and <A>S</A> are not multidigraphs then
2248+
<C>AmalgamDigraphs</C> calculates a new digraph, the <E>amalgam digraph</E>
2249+
<M>D_A</M>. <M>D_A</M> is an amalgam of <A>D1</A> and <A>D2</A> over
2250+
<A>S</A> with respect to embeddings (where the embeddings of <A>S</A> into
2251+
<A>D1</A> and <A>D2</A> can be specified by <A>map1</A> and <A>map2</A>).
2252+
The embedding of <A>D1</A> into <M>D_A</M> is set to always be the
2253+
<C>IdentityTransformation<C/>.<P/>
2254+
2255+
Note that <C>AmalgamDigraphs</C> does not necessarily return the smallest
2256+
possible digraph satisfying these properties. For examble, when
2257+
<A>D1</A> and <A>D2</A> are equal, the embedding from <A>D2</A>
2258+
to <M>D_A</M> will not be the <C>IdentityTransformation<C/> and so
2259+
<M>D_A</M> could have many more vertices than the smallest possible amalgam
2260+
of <A>D1</A> and <A>D2</A> over <A>S</A>. A less formal way to picture
2261+
the exact form of <M>D_A</M> is to think of it as <A>D1</A> and <A>D2</A>
2262+
'joined together' by the common subdigraph <A>S</A>.<P/>
2263+
2264+
<C>AmalgamDigraphs</C> returns a <E>tuple</E> of size two, with the first
2265+
element being the digraph <M>A_D</M> and the second element being a
2266+
transformation object which describes the embedding of <A>D2</A> into
2267+
<M>A_D<M>.
22522268

22532269
<Example><![CDATA[
2254-
gap> T := Digraph([[2, 3], [1, 3], [1, 2]]);;
2255-
gap> A := AmalgamDigraphs(T, T, [1, 2], [1, 2]);
2270+
gap> D := CycleGraph(3);;
2271+
gap> S := PathGraph(2);;
2272+
gap> AmalgamDigraphs(D, D, S);
22562273
[ <immutable digraph with 4 vertices, 10 edges>,
2257-
rec( 1 := 1, 2 := 2, 3 := 4 ) ]
2258-
gap> A := AmalgamDigraphs(A[1], T, [1, 2], [1, 2]);
2259-
[ <immutable digraph with 5 vertices, 14 edges>,
2260-
rec( 1 := 1, 2 := 2, 3 := 5 ) ]
2261-
gap> P := PetersenGraph();;
2262-
gap> G := Digraph([[2, 3, 4], [1, 3], [1, 2, 5],
2263-
> [1, 6], [3, 6], [4, 5]]);;
2264-
gap> A := AmalgamDigraphs(P, G, [1, 2, 7, 10, 5], [1, 3, 5, 6, 4]);
2265-
[ <immutable digraph with 11 vertices, 34 edges>,
2266-
rec( 1 := 1, 2 := 11, 3 := 2, 4 := 5, 5 := 7, 6 := 10 ) ]
2267-
]]></Example>
2268-
</Description>
2269-
</ManSection>
2270-
<#/GAPDoc>
2271-
2272-
<#GAPDoc Label="AmalgamDigraphsIsomorphic">
2273-
<ManSection>
2274-
<Oper Name="AmalgamDigraphsIsomorphic" Arg="D1, D2,
2275-
subdigraphVertices1, subdigraphVertices2"/>
2276-
<Returns>An immutable digraph and a record.</Returns>
2277-
<Description>
2278-
2279-
<C>AmalgamDigraphsIsomorphic</C> is meant to function very similarly to
2280-
<C>AmalgamDigraphs</C>. The difference is that in <C>AmalgamDigraphs</C>
2281-
<A>subdigraphVertices1</A> and <A>subdigraphVertices2</A> need not
2282-
necessarily describe identical subdigraphs of <A>D1</A> and <A>D2</A>,
2283-
but need only describe subdigraphs that are isomorphic to one another.
2284-
<C>AmalgamDigraphsIsomorphic</C> rearranges the entries of
2285-
<A>subdigraphVertices2</A> to obtain <C>newSubdigraphVertices2</C>
2286-
in such a way that the induced subdigraph in <A>D2</A> with the
2287-
vertices <C>newSubdigraphVertices2</C> is identical to the induced
2288-
subdigraph in <A>D1</A> with the vertices <C>subdigraphVertices1</C>.
2289-
<C>AmalgamDigraphsIsomorphic</C> then calls <C>AmalgamDigraphs</C>
2290-
with <C>newSubdigraphVertices2</C> in the place of
2291-
<A>subdigraphVertices2</A>.
2292-
2293-
<Example><![CDATA[
2294-
gap> P := PetersenGraph();;
2295-
gap> G := Digraph([[2, 3, 4], [1, 3],
2296-
> [1, 2, 5], [1, 6], [3, 6], [4, 5]]);;
2297-
gap> A := AmalgamDigraphs(P, G, [1, 2, 7, 10, 5], [1, 3, 5, 6, 4]);
2298-
[ <immutable digraph with 11 vertices, 34 edges>,
2299-
rec( 1 := 1, 2 := 11, 3 := 2, 4 := 5, 5 := 7, 6 := 10 ) ]
2300-
gap> A := AmalgamDigraphsIsomorphic(P, G,
2301-
> [1, 2, 7, 10, 5], [1, 4, 6, 3, 5]);
2302-
[ <immutable digraph with 11 vertices, 34 edges>,
2303-
rec( 1 := 1, 2 := 11, 3 := 5, 4 := 2, 5 := 10, 6 := 7 ) ]
2304-
gap> A := AmalgamDigraphs(P, G, [1, 2, 7, 10, 5], [1, 4, 6, 3, 5]);
2305-
Error, the two subdigraphs must be equal.
2274+
Transformation( [ 1, 2, 4, 4 ] ) ]
2275+
gap> D := PetersonGraph();;
2276+
gap> S := CycleGraph(5);;
2277+
gap> AmalgamDigraphs(D, D, S);
2278+
[ <immutable digraph with 15 vertices, 50 edges>,
2279+
Transformation( [ 1, 2, 3, 4, 5, 11, 12, 13, 14, 15, 11, 12, 13, 14, 15 ] )
2280+
]
2281+
gap> D1 := Digraph([[2, 3], [1, 3, 4], [1, 2, 4], [2, 3, 5], [4]]);;
2282+
gap> D2 := Digraph([[2, 3], [1, 3, 4], [1, 2, 4, 5], [2, 3, 5], [3, 4]]);;
2283+
gap> S := CycleGraph(3);;
2284+
gap> map1 := Transformation([2, 4, 3, 4]);;
2285+
gap> map2 := Transformation([2, 3, 4, 4]);;
2286+
gap> AmalgamDigraphs(D1, D2, S, map1, map2);
2287+
[ <immutable digraph with 7 vertices, 20 edges>,
2288+
Transformation( [ 6, 2, 4, 3, 7, 6, 7 ] ) ]
23062289
]]></Example>
23072290
</Description>
23082291
</ManSection>

doc/z-chap2.xml

-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@
7575
<#Include Label="DigraphClosure">
7676
<#Include Label="DigraphMycielskian">
7777
<#Include Label="AmalgamDigraphs">
78-
<#Include Label="AmalgamDigraphsIsomorphic">
7978
</Section>
8079

8180
<Section><Heading>Random digraphs</Heading>

gap/oper.gd

+10-3
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,13 @@ DeclareOperation("StrongProduct", [IsDigraph, IsDigraph]);
4646
DeclareOperation("ConormalProduct", [IsDigraph, IsDigraph]);
4747
DeclareOperation("HomomorphicProduct", [IsDigraph, IsDigraph]);
4848
DeclareOperation("LexicographicProduct", [IsDigraph, IsDigraph]);
49-
DeclareOperation("AmalgamDigraphs", [IsDigraph, IsDigraph, IsList, IsList]);
50-
DeclareOperation("AmalgamDigraphsIsomorphic",
51-
[IsDigraph, IsDigraph, IsList, IsList]);
49+
DeclareOperation("AmalgamDigraphs",
50+
[IsDigraph, IsDigraph, IsDigraph,
51+
IsTransformation, IsTransformation]);
52+
DeclareOperation("AmalgamDigraphs",
53+
[IsDigraph, IsDigraph, IsDigraph, IsTransformation]);
54+
DeclareOperation("AmalgamDigraphs",
55+
[IsDigraph, IsDigraph, IsDigraph,]);
5256

5357
DeclareSynonym("DigraphModularProduct", ModularProduct);
5458
DeclareSynonym("DigraphStrongProduct", StrongProduct);
@@ -58,6 +62,9 @@ DeclareSynonym("DigraphLexicographicProduct", LexicographicProduct);
5862

5963
DeclareGlobalFunction("DIGRAPHS_CombinationOperProcessArgs");
6064
DeclareOperation("DIGRAPHS_GraphProduct", [IsDigraph, IsDigraph, IsFunction]);
65+
DeclareOperation("NOCHECKS_AmalgamDigraphs",
66+
[IsDigraph, IsDigraph, IsDigraph,
67+
IsTransformation, IsTransformation]);
6168

6269
# 4. Actions . . .
6370
DeclareOperation("OnDigraphs", [IsDigraph, IsPerm]);

gap/oper.gi

+130-47
Original file line numberDiff line numberDiff line change
@@ -765,80 +765,163 @@ function(D1, D2, edge_function)
765765
return Digraph(edges);
766766
end);
767767

768-
InstallMethod(AmalgamDigraphsIsomorphic,
768+
InstallMethod(AmalgamDigraphs,
769769
"for a digraph, a digraph, a list, and a list",
770-
[IsDigraph, IsDigraph, IsList, IsList],
771-
function(D1, D2, subdigraphVertices1, subdigraphVertices2)
772-
local subdigraph1, subdigraph2, newSubdigraphVertices2, transformation, vertex;
770+
[IsDigraph, IsDigraph, IsDigraph, IsTransformation, IsTransformation],
771+
function(D1, D2, S, map1, map2)
772+
local D, n, imageList1, imageList2, map, edge, T;
773773

774-
subdigraph1 := InducedSubdigraph(DigraphImmutableCopyIfMutable(D1),
775-
subdigraphVertices1);
776-
subdigraph2 := InducedSubdigraph(DigraphImmutableCopyIfMutable(D2),
777-
subdigraphVertices2);
774+
if IsMultiDigraph(D1) then
775+
ErrorNoReturn(
776+
"the 1st argument (a digraph) must not satisfy IsMultiDigraph");
777+
elif IsMultiDigraph(D2) then
778+
ErrorNoReturn(
779+
"the 2nd argument (a digraph) must not satisfy IsMultiDigraph");
780+
elif IsMultiDigraph(S) then
781+
ErrorNoReturn(
782+
"the 3rd argument (a digraph) must not satisfy IsMultiDigraph");
783+
fi;
778784

779-
if not IsIsomorphicDigraph(subdigraph1, subdigraph2) then
785+
if not IsDigraphEmbedding(S, D1, map1) then
780786
ErrorNoReturn(
781-
"the subdigraph induced by the 3rd argument (a list) in the 1st ",
782-
"argument (a digraph) is not ismorphic to the subdigraph induced ",
783-
"by the 4th argument (a list) in the 2nd argument (a digraph)");
787+
"the 4th argument (a transformation) is not ",
788+
"a digraph embedding from the 3rd argument (a digraph) into ",
789+
"the 1st argument (a digraph)");
784790
fi;
791+
if not IsDigraphEmbedding(S, D2, map2) then
792+
ErrorNoReturn(
793+
"the 5th argument (a transformation) is not ",
794+
"a digraph embedding from the 3rd argument (a digraph) into ",
795+
"the 2nd argument (a digraph)");
796+
fi;
797+
798+
# Create a mutable copy so that the function also works if
799+
# D1 is immutable. If D1 is a mutable digraph then
800+
# D1 will be changed in place.
801+
D := DigraphMutableCopyIfImmutable(D1);
802+
803+
n := DigraphNrVertices(D2) + DigraphNrVertices(D1) - DigraphNrVertices(S);
804+
805+
# 'map' is an embedding of D2 into the final output graph.
806+
# The embedding of D1 into the final output graph is the identity mapping.
785807

786-
newSubdigraphVertices2 := [];
787-
transformation := DigraphEmbedding(subdigraph2, subdigraph1);
788-
for vertex in subdigraphVertices2 do
789-
newSubdigraphVertices2[
790-
Position(subdigraphVertices2, vertex) ^ transformation] := vertex;
808+
map := [1 .. n];
809+
810+
imageList1 := OnTuples([1 .. DigraphNrVertices(S)], map1);
811+
imageList2 := OnTuples([1 .. DigraphNrVertices(S)], map2);
812+
813+
map{imageList2} := imageList1;
814+
map{Difference(DigraphVertices(D2), imageList2)} :=
815+
[DigraphNrVertices(D1) + 1 .. n];
816+
817+
T := Transformation(map);
818+
819+
DigraphAddVertices(D, DigraphNrVertices(D2) - DigraphNrVertices(S));
820+
821+
for edge in DigraphEdges(D2) do
822+
if not (edge[1] in imageList2
823+
and edge[2] in imageList2) then
824+
DigraphAddEdge(D, [edge[1] ^ T, edge[2] ^ T]);
825+
fi;
791826
od;
792827

793-
return AmalgamDigraphs(D1, D2, subdigraphVertices1, newSubdigraphVertices2);
828+
return [MakeImmutable(D), T];
829+
end);
830+
831+
InstallMethod(AmalgamDigraphs,
832+
"for a digraph, a digraph, a list, and a list",
833+
[IsDigraph, IsDigraph, IsDigraph, IsTransformation],
834+
function(D1, D2, S, map1)
835+
local map2;
836+
837+
if IsMultiDigraph(D1) then
838+
ErrorNoReturn(
839+
"the 1st argument (a digraph) must not satisfy IsMultiDigraph");
840+
elif IsMultiDigraph(D2) then
841+
ErrorNoReturn(
842+
"the 2nd argument (a digraph) must not satisfy IsMultiDigraph");
843+
elif IsMultiDigraph(S) then
844+
ErrorNoReturn(
845+
"the 3rd argument (a digraph) must not satisfy IsMultiDigraph");
846+
fi;
847+
848+
if not IsDigraphEmbedding(S, D1, map1) then
849+
ErrorNoReturn(
850+
"the 4th argument (a transformation) is not ",
851+
"a digraph embedding from the 3rd argument (a digraph) into ",
852+
"the 1st argument (a digraph)");
853+
fi;
854+
855+
map2 := DigraphEmbedding(S, D2);
856+
if map2 = fail then
857+
ErrorNoReturn(
858+
"no embeddings could be found from the 3rd argument ",
859+
"(a digraph) to the 2nd argument (a digraph)");
860+
fi;
861+
862+
return NOCHECKS_AmalgamDigraphs(D1, D2, S, map1, map2);
794863
end);
795864

796865
InstallMethod(AmalgamDigraphs,
797866
"for a digraph, a digraph, a list, and a list",
798-
[IsDigraph, IsDigraph, IsList, IsList],
799-
function(D1, D2, subdigraphVertices1, subdigraphVertices2)
800-
local D, n, map, T, vertex, edge;
801-
802-
if not InducedSubdigraph(DigraphImmutableCopyIfMutable(D1),
803-
subdigraphVertices1) =
804-
InducedSubdigraph(DigraphImmutableCopyIfMutable(D2),
805-
subdigraphVertices2) then
867+
[IsDigraph, IsDigraph, IsDigraph],
868+
function(D1, D2, S)
869+
local map1, map2;
870+
871+
if IsMultiDigraph(D1) then
872+
ErrorNoReturn(
873+
"the 1st argument (a digraph) must not satisfy IsMultiDigraph");
874+
elif IsMultiDigraph(D2) then
875+
ErrorNoReturn(
876+
"the 2nd argument (a digraph) must not satisfy IsMultiDigraph");
877+
elif IsMultiDigraph(S) then
806878
ErrorNoReturn(
807-
"the subdigraph induced by the 3rd argument (a list) in the 1st ",
808-
"argument (a digraph) does not equal the subdigraph induced by the ",
809-
"4th argument (a list) in the 2nd argument (a digraph)");
879+
"the 3rd argument (a digraph) must not satisfy IsMultiDigraph");
810880
fi;
811881

812-
# Create a mutable copy so that the function also works if
813-
# D1 is immutable. If D1 is a mutable digraph then
814-
# D1 will be changed in place.
815-
D := DigraphMutableCopyIfImmutable(D1);
882+
map1 := DigraphEmbedding(S, D1);
883+
if map1 = fail then
884+
ErrorNoReturn(
885+
"no embeddings could be found from the 3rd argument ",
886+
"(a digraph) to the 1st argument (a digraph)");
887+
fi;
816888

817-
n := DigraphNrVertices(D2) + DigraphNrVertices(D1);
818-
n := n - Length(subdigraphVertices1);
889+
map2 := DigraphEmbedding(S, D2);
890+
if map2 = fail then
891+
ErrorNoReturn(
892+
"no embeddings could be found from the 3rd argument ",
893+
"(a digraph) to the 2nd argument (a digraph)");
894+
fi;
819895

820-
# 'map' is a mapping from the vertices of D2 to the vertices of the
821-
# final output graph. The idea is to map the subdigraph vertices of D2
822-
# onto the subdigraph vertices of D1 and then map the rest of the vertices
823-
# of D2 to other (higher) values. The mapping from D1 to the output graph
824-
# can be understood as the identity mapping.
896+
return NOCHECKS_AmalgamDigraphs(D1, D2, S, map1, map2);
897+
end);
898+
899+
InstallMethod(NOCHECKS_AmalgamDigraphs,
900+
"for a digraph, a digraph, a list, and a list",
901+
[IsDigraph, IsDigraph, IsDigraph, IsTransformation, IsTransformation],
902+
function(D1, D2, S, map1, map2)
903+
local D, n, imageList1, imageList2, map, edge, T;
904+
905+
D := DigraphMutableCopyIfImmutable(D1);
906+
907+
n := DigraphNrVertices(D2) + DigraphNrVertices(D1) - DigraphNrVertices(S);
825908

826909
map := [1 .. n];
827910

828-
for vertex in [1 .. Length(subdigraphVertices1)] do
829-
map[subdigraphVertices2[vertex]] := subdigraphVertices1[vertex];
830-
od;
911+
imageList1 := OnTuples([1 .. DigraphNrVertices(S)], map1);
912+
imageList2 := OnTuples([1 .. DigraphNrVertices(S)], map2);
831913

832-
map{Difference(DigraphVertices(D2), subdigraphVertices2)} :=
914+
map{imageList2} := imageList1;
915+
map{Difference(DigraphVertices(D2), imageList2)} :=
833916
[DigraphNrVertices(D1) + 1 .. n];
834917

835918
T := Transformation(map);
836919

837-
DigraphAddVertices(D, DigraphNrVertices(D2) - Length(subdigraphVertices1));
920+
DigraphAddVertices(D, DigraphNrVertices(D2) - DigraphNrVertices(S));
838921

839922
for edge in DigraphEdges(D2) do
840-
if not (edge[1] in subdigraphVertices2
841-
and edge[2] in subdigraphVertices2) then
923+
if not (edge[1] in imageList2
924+
and edge[2] in imageList2) then
842925
DigraphAddEdge(D, [edge[1] ^ T, edge[2] ^ T]);
843926
fi;
844927
od;

0 commit comments

Comments
 (0)