Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions doc/oper.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2381,6 +2381,64 @@ true
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="AmalgamDigraphs">
<ManSection>
<Oper Name="AmalgamDigraphs" Arg="D1, D2,
S[, map1[, map2]]"/>
<Returns>An immutable digraph and a transformation.</Returns>
<Description>

<C>AmalgamDigraphs</C> takes as input two digraphs <A>D1</A> and <A>D2</A>
and a digraph <A>S</A> for which there is an embedding into both
<A>D1</A> and <A>D2</A>. Additional optional arguments <A>map1</A> and
<A>map2</A> are transformation objects which can force specific
embeddings of <A>S</A> into <A>D1</A> and <A>D2</A> respectively. If
<A>map1</A> and <A>map2</A> are not given then arbitrary embeddings
will be found using <C>DigraphEmbedding</C>. If no embeddings can be found
the function will throw an error.<P/>

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

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

<C>AmalgamDigraphs</C> returns a <E>tuple</E> of size two, with the first
element being the digraph <M>A_D</M> and the second element being a
transformation object which describes the embedding of <A>D2</A> into
<M>A_D</M>.

<Example><![CDATA[
gap> D := CycleGraph(3);;
gap> S := PathGraph(2);;
gap> AmalgamDigraphs(D, D, S);
[ <immutable digraph with 4 vertices, 10 edges>,
Transformation( [ 1, 2, 4, 4 ] ) ]
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);
[ <immutable digraph with 7 vertices, 20 edges>,
Transformation( [ 6, 2, 4, 3, 7, 6, 7 ] ) ]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphCycleBasis">
<ManSection>
<Oper Name="DigraphCycleBasis" Arg="digraph"/>
Expand Down
1 change: 1 addition & 0 deletions doc/z-chap2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
<#Include Label="DistanceDigraph">
<#Include Label="DigraphClosure">
<#Include Label="DigraphMycielskian">
<#Include Label="AmalgamDigraphs">
</Section>

<Section><Heading>Random digraphs</Heading>
Expand Down
10 changes: 10 additions & 0 deletions gap/oper.gd
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ DeclareOperation("StrongProduct", [IsDigraph, IsDigraph]);
DeclareOperation("ConormalProduct", [IsDigraph, IsDigraph]);
DeclareOperation("HomomorphicProduct", [IsDigraph, IsDigraph]);
DeclareOperation("LexicographicProduct", [IsDigraph, IsDigraph]);
DeclareOperation("AmalgamDigraphs",
[IsDigraph, IsDigraph, IsDigraph,
IsTransformation, IsTransformation]);
DeclareOperation("AmalgamDigraphs",
[IsDigraph, IsDigraph, IsDigraph, IsTransformation]);
DeclareOperation("AmalgamDigraphs",
[IsDigraph, IsDigraph, IsDigraph]);

DeclareSynonym("DigraphModularProduct", ModularProduct);
DeclareSynonym("DigraphStrongProduct", StrongProduct);
Expand All @@ -58,6 +65,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]);
Expand Down
164 changes: 164 additions & 0 deletions gap/oper.gi
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,170 @@ function(D1, D2, edge_function)
return Digraph(edges);
end);

InstallMethod(AmalgamDigraphs,
"for a digraph, a digraph, a digraph, a transformation, and a transformation",
[IsDigraph, IsDigraph, IsDigraph, IsTransformation, IsTransformation],
function(D1, D2, S, map1, map2)
local D, n, imageList1, imageList2, map, edge, T;

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;
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.

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 [MakeImmutable(D), T];
end);

InstallMethod(AmalgamDigraphs,
"for a digraph, a digraph, a digraph, and a transformation",
[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, and a digraph",
[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 3rd argument (a digraph) must not satisfy IsMultiDigraph");
fi;

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;

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(NOCHECKS_AmalgamDigraphs,
"for a digraph, a digraph, a digraph, a transformation, and a transformation",
[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];

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 [MakeImmutable(D), T];
end);

###############################################################################
# 4. Actions
###############################################################################
Expand Down
118 changes: 117 additions & 1 deletion tst/standard/oper.tst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#############################################################################
##

#@local C, D, D1, D2, D3, D3_edges, DD
#@local C, D, D1, D2, D3, D3_edges, DD, S, T, map1, map2
#@local G, G1, L, TestPartialOrderDigraph
#@local TestPartialOrderDigraph2, TestUnion, a, adj, b, comps, copy, d, e
#@local edges, edges2, func, g, gr, gr1, gr2, gr3, gr4, gri, grrt, grt, h, i
Expand Down Expand Up @@ -2869,6 +2869,122 @@ gap> D := CycleDigraph(5);;
gap> IsOrderIdeal(D, [1]);
Error, the 1st argument (a digraph) must be a partial order digraph

# 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> S := InducedSubdigraph(D1, [2, 3, 4, 5]);;
gap> T := DigraphEmbedding(S, D2);;
gap> AmalgamDigraphs(D2, D1, S, T);
[ <immutable digraph with 7 vertices, 15 edges>,
Transformation( [ 7, 4, 3, 5, 2, 6, 7 ] ) ]
gap> 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> S := InducedSubdigraph(D1, [2, 3, 6, 7]);;
gap> T := DigraphEmbedding(S, D1);;
gap> 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> AmalgamDigraphs(D1, D2, S, map1, map2);
[ <immutable digraph with 6 vertices, 13 edges>,
Transformation( [ 6, 2, 4, 3, 5, 6 ] ) ]
gap> D1 := DigraphImmutableCopy(D1);
<immutable digraph with 5 vertices, 9 edges>
gap> AmalgamDigraphs(D1, D2, S, map1, map2);
[ <immutable digraph with 6 vertices, 13 edges>,
Transformation( [ 6, 2, 4, 3, 5, 6 ] ) ]
gap> D1 := DigraphMutableCopy(D1);
<mutable digraph with 5 vertices, 9 edges>
gap> AmalgamDigraphs(D1, D2, S, map1, map2);
[ <immutable digraph with 6 vertices, 13 edges>,
Transformation( [ 6, 2, 4, 3, 5, 6 ] ) ]
gap> D1;
<immutable digraph with 6 vertices, 13 edges>
gap> D1 := Digraph([[2, 5], [1, 3], [4], [2, 5], [1, 4]]);;
gap> D2 := DigraphMutableCopy(D2);
<mutable digraph with 4 vertices, 7 edges>
gap> AmalgamDigraphs(D1, D2, S, map1, map2);
[ <immutable digraph with 6 vertices, 13 edges>,
Transformation( [ 6, 2, 4, 3, 5, 6 ] ) ]
gap> D2;
<mutable digraph with 4 vertices, 7 edges>
gap> D1 := DigraphImmutableCopy(D1);
<immutable digraph with 5 vertices, 9 edges>
gap> AmalgamDigraphs(D1, D2, S, map1, map2);
[ <immutable digraph with 6 vertices, 13 edges>,
Transformation( [ 6, 2, 4, 3, 5, 6 ] ) ]
gap> D1 := PetersenGraph();;
gap> D2 := Digraph([[], [1, 3, 4], [1, 2, 5], [2, 6], [3, 6], [4, 5]]);;
gap> S := CycleGraph(5);;
gap> AmalgamDigraphs(D1, D2, S, IdentityTransformation);
[ <immutable digraph with 11 vertices, 32 edges>,
Transformation( [ 11, 1, 2, 5, 3, 4, 7, 8, 9, 10, 11 ] ) ]
gap> AmalgamDigraphs(D1, D2, S);
[ <immutable digraph with 11 vertices, 32 edges>,
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> AmalgamDigraphs(D1, D2, S, map1, map2);
[ <immutable digraph with 6 vertices, 7 edges>,
Transformation( [ 2, 1, 4, 5, 6, 6 ] ) ]
gap> AmalgamDigraphs(D1, D2, S, map1);
[ <immutable digraph with 6 vertices, 7 edges>,
Transformation( [ 1, 4, 2, 5, 6, 6 ] ) ]
gap> AmalgamDigraphs(D1, D2, S);
[ <immutable digraph with 6 vertices, 7 edges>,
Transformation( [ 1, 3, 2, 5, 6, 6 ] ) ]
gap> 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> 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> AmalgamDigraphs(D1, D2, D1);
Error, no embeddings could be found from the 3rd argument (a digraph) to the 2\
nd argument (a digraph)
gap> 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> 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

# IsOrderFilter
gap> D := DigraphByEdges([[1, 1], [1, 2], [1, 3], [2, 3], [3, 3], [2, 2], [2, 4], [4, 4], [1, 4]]);
<immutable digraph with 4 vertices, 9 edges>
Expand Down
Loading