Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AmalgamDigraphs #532

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
80 changes: 80 additions & 0 deletions doc/oper.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2227,3 +2227,83 @@ true
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="AmalgamDigraphs">
<ManSection>
<Oper Name="AmalgamDigraphs" Arg="D1, D2,
subdigraphVertices1, subdigraphVertices2"/>
<Returns>An immutable digraph and a record.</Returns>
<Description>

<C>AmalgamDigraphs</C> takes as input two digraphs <A>D1</A> and <A>D2</A>
and two lists of vertices <A>subdigraphVertices1</A> and
<A>subdigraphVertices2</A>, which correspond to two identical subdigraphs
of <A>D1</A> and <A>D2</A>. It returns a new digraph, the <E>amalgam
digraph</E> <C>AD</C>, which consists of <A>D1</A> and <A>D2</A> joined
together by their common subdigraph in such a way that the edge connectivity
between the vertices of <C>AD</C> matches the edge connectivity of
<A>D1</A> and <A>D2</A>.<P/>

It returns a <E>tuple</E> of size two, with the first element being
<C>AD</C> and the second element being <C>map</C>, which is a record which
maps each vertex's number in <A>D2</A> to the corresponding vertex's number
in <C>AD</C>. The mapping of the vertices of <A>D1</A> can be seen as the
<E>identity mapping</E>.

<Example><![CDATA[
gap> T := Digraph([[2, 3], [1, 3], [1, 2]]);;
gap> A := AmalgamDigraphs(T, T, [1, 2], [1, 2]);
[ <immutable digraph with 4 vertices, 10 edges>,
rec( 1 := 1, 2 := 2, 3 := 4 ) ]
gap> A := AmalgamDigraphs(A[1], T, [1, 2], [1, 2]);
[ <immutable digraph with 5 vertices, 14 edges>,
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]);
[ <immutable digraph with 11 vertices, 34 edges>,
rec( 1 := 1, 2 := 11, 3 := 2, 4 := 5, 5 := 7, 6 := 10 ) ]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="AmalgamDigraphsIsomorphic">
finnbuck marked this conversation as resolved.
Show resolved Hide resolved
<ManSection>
<Oper Name="AmalgamDigraphsIsomorphic" Arg="D1, D2,
subdigraphVertices1, subdigraphVertices2"/>
<Returns>An immutable digraph and a record.</Returns>
<Description>

<C>AmalgamDigraphsIsomorphic</C> is meant to function very similarly to
<C>AmalgamDigraphs</C>. The difference is that in <C>AmalgamDigraphs</C>
<A>subdigraphVertices1</A> and <A>subdigraphVertices2</A> need not
necessarily describe identical subdigraphs of <A>D1</A> and <A>D2</A>,
but need only describe subdigraphs that are isomorphic to one another.
<C>AmalgamDigraphsIsomorphic</C> rearranges the entries of
<A>subdigraphVertices2</A> to obtain <C>newSubdigraphVertices2</C>
in such a way that the induced subdigraph in <A>D2</A> with the
vertices <C>newSubdigraphVertices2</C> is identical to the induced
subdigraph in <A>D1</A> with the vertices <C>subdigraphVertices1</C>.
<C>AmalgamDigraphsIsomorphic</C> then calls <C>AmalgamDigraphs</C>
with <C>newSubdigraphVertices2</C> in the place of
<A>subdigraphVertices2</A>.

<Example><![CDATA[
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]);
[ <immutable digraph with 11 vertices, 34 edges>,
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]);
[ <immutable digraph with 11 vertices, 34 edges>,
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.
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>
2 changes: 2 additions & 0 deletions doc/z-chap2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@
<#Include Label="DistanceDigraph">
<#Include Label="DigraphClosure">
<#Include Label="DigraphMycielskian">
<#Include Label="AmalgamDigraphs">
<#Include Label="AmalgamDigraphsIsomorphic">
</Section>

<Section><Heading>Random digraphs</Heading>
Expand Down
3 changes: 3 additions & 0 deletions gap/oper.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
85 changes: 85 additions & 0 deletions gap/oper.gi
Original file line number Diff line number Diff line change
Expand Up @@ -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",
finnbuck marked this conversation as resolved.
Show resolved Hide resolved
[IsDigraph, IsDigraph, IsList, IsList],
function(D1, D2, subdigraphVertices1, subdigraphVertices2)
local D, map, vertex, vertexList, size, iterator, edgeList, subLength;

if not InducedSubdigraph(D1, subdigraphVertices1) =
finnbuck marked this conversation as resolved.
Show resolved Hide resolved
InducedSubdigraph(D2, subdigraphVertices2) then
ErrorNoReturn(
finnbuck marked this conversation as resolved.
Show resolved Hide resolved
"the two subdigraphs must be equal.");
finnbuck marked this conversation as resolved.
Show resolved Hide resolved
fi;

# Create a mutable copy so that the function also works on
# immutable input digraphs.
D := DigraphMutableCopy(D1);
finnbuck marked this conversation as resolved.
Show resolved Hide resolved
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();
finnbuck marked this conversation as resolved.
Show resolved Hide resolved

for vertex in [1 .. subLength] do
finnbuck marked this conversation as resolved.
Show resolved Hide resolved
map.(subdigraphVertices2[vertex]) := subdigraphVertices1[vertex];
od;

vertexList := Difference(DigraphVertices(D2), subdigraphVertices2);
finnbuck marked this conversation as resolved.
Show resolved Hide resolved
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
finnbuck marked this conversation as resolved.
Show resolved Hide resolved
# 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));
finnbuck marked this conversation as resolved.
Show resolved Hide resolved
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
###############################################################################
Expand Down
35 changes: 35 additions & 0 deletions tst/standard/oper.tst
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
[ <immutable digraph with 7 vertices, 15 edges>,
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]);
[ <immutable digraph with 11 vertices, 32 edges>,
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]);
[ <immutable digraph with 15 vertices, 50 edges>,
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]);
[ <immutable digraph with 13 vertices, 42 edges>,
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);
Expand Down