Skip to content

Commit

Permalink
Add Min/MaximalCommonSubdigraph
Browse files Browse the repository at this point in the history
  • Loading branch information
james-d-mitchell committed Feb 28, 2021
1 parent e097454 commit 28946b8
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 0 deletions.
63 changes: 63 additions & 0 deletions doc/grahom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -798,3 +798,66 @@ false
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="MaximalCommonSubdigraph">
<ManSection>
<Oper Name="MaximalCommonSubdigraph" Arg="D1, D2"/>
<Returns>A list containing a digraph and two transformations.</Returns>
<Description>
If <A>D1</A> and <A>D2</A> are digraphs without multiple edges, then
<C>MaximalCommonSubdigraph</C> returns a maximal common subgraph <C>M</C> of
<A>D1</A> and <A>D2</A> with the maximum number of vertices. So <C>M</C> is a
digraph which embeds into both <A>D1</A> and <A>D2</A> and has the largest
number of vertices amoung such digraphs.

It returns a list <C>[M, t1, t2]</C> where <C>M</C> is the maximal common
subdigraph and <C>t1, t2</C> are transformations embedding <C>M</C> into
<A>D1</A> and <A>D2</A> respectively.

<Example><![CDATA[
gap> MaximalCommonSubdigraph(PetersenGraph(), CompleteDigraph(10));
[ <immutable digraph with 2 vertices, 2 edges>,
IdentityTransformation, IdentityTransformation ]
gap> MaximalCommonSubdigraph(PetersenGraph(),
> DigraphSymmetricClosure(CycleDigraph(5)));
[ <immutable digraph with 5 vertices, 10 edges>,
IdentityTransformation, IdentityTransformation ]
gap> MaximalCommonSubdigraph(NullDigraph(0), CompleteDigraph(10));
[ <immutable empty digraph with 0 vertices>, IdentityTransformation,
IdentityTransformation ]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="MinimalCommonSuperdigraph">
<ManSection>
<Oper Name="MinimalCommonSuperdigraph" Arg="D1, D2"/>
<Returns>A list containing a digraph and two transformations.</Returns>
<Description>
If <A>D1</A> and <A>D2</A> are digraphs without multiple edges, then
<C>MinimalCommonSuperdigraph</C> returns a minimal common superdigraph
<C>M</C> of <A>D1</A> and <A>D2</A> with the minimum number of vertices.
So <C>M</C> is a digraph into which both <A>D1</A> and <A>D2</A> embed and
has the smallest number of vertices amoung such digraphs.

It returns a list <C>[M, t1, t2]</C> where <C>M</C> is the minimal common
superdigraph and <C>t1, t2</C> are transformations embedding <A>D1</A> and
<A>D2</A> respectively into <C>M</C>.
<Example><![CDATA[
gap> MinimalCommonSuperdigraph(PetersenGraph(), CompleteDigraph(10));
[ <immutable digraph with 18 vertices, 118 edges>,
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)));
[ <immutable digraph with 10 vertices, 30 edges>,
IdentityTransformation, IdentityTransformation ]
gap> MinimalCommonSuperdigraph(NullDigraph(0), CompleteDigraph(10));
[ <immutable digraph with 10 vertices, 90 edges>,
IdentityTransformation, IdentityTransformation ]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>
2 changes: 2 additions & 0 deletions doc/z-chap6.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
</Section>

<Section><Heading>Homomorphisms of digraphs</Heading>
Expand Down
3 changes: 3 additions & 0 deletions gap/grahom.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
77 changes: 77 additions & 0 deletions gap/grahom.gi
Original file line number Diff line number Diff line change
Expand Up @@ -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);
40 changes: 40 additions & 0 deletions tst/standard/grahom.tst
Original file line number Diff line number Diff line change
Expand Up @@ -2453,6 +2453,46 @@ false
gap> IsDigraphEmbedding(ran, src, (), [2, 1], [1, 1, 2]);
false

# MaximalCommSubdigraph and MinimalCommonSuperDigraph
gap> MaximalCommonSubdigraph(NullDigraph(0), CompleteDigraph(10));
[ <immutable empty digraph with 0 vertices>, IdentityTransformation,
IdentityTransformation ]
gap> MinimalCommonSuperdigraph(NullDigraph(0), CompleteDigraph(10));
[ <immutable digraph with 10 vertices, 90 edges>, IdentityTransformation,
IdentityTransformation ]
gap> MaximalCommonSubdigraph(PetersenGraph(), CompleteDigraph(10));
[ <immutable digraph with 2 vertices, 2 edges>, IdentityTransformation,
IdentityTransformation ]
gap> MinimalCommonSuperdigraph(PetersenGraph(), CompleteDigraph(10));
[ <immutable digraph with 18 vertices, 118 edges>, 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));
[ <immutable empty digraph with 1 vertex>, IdentityTransformation,
IdentityTransformation ]
gap> MinimalCommonSuperdigraph(NullDigraph(10), CompleteDigraph(10));
[ <immutable digraph with 19 vertices, 90 edges>, 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));
[ <immutable digraph with 100 vertices, 9900 edges>, IdentityTransformation,
IdentityTransformation ]
gap> MinimalCommonSuperdigraph(CompleteDigraph(100), CompleteDigraph(100));
[ <immutable digraph with 100 vertices, 9900 edges>, IdentityTransformation,
IdentityTransformation ]
gap> MaximalCommonSubdigraph(PetersenGraph(),
> DigraphSymmetricClosure(CycleDigraph(5)));
[ <immutable digraph with 5 vertices, 10 edges>, IdentityTransformation,
IdentityTransformation ]
gap> MinimalCommonSuperdigraph(PetersenGraph(),
> DigraphSymmetricClosure(CycleDigraph(5)));
[ <immutable digraph with 10 vertices, 30 edges>, 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);
Expand Down

0 comments on commit 28946b8

Please sign in to comment.