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
78 changes: 78 additions & 0 deletions doc/oper.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2076,6 +2076,84 @@ gap> DigraphVertexLabels(D);
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphInsertEdge">
<ManSection>
<Oper Name="DigraphInsertEdge" Arg="digraph, edge1, edge2"
Label="for a symmeric digraph and two lists of positive integers"/>
<Returns>A digraph.</Returns>
<Description>
If <A>edge1</A> and <A>edge2</A> are distinct pairs of vertices of <A>digraph</A>,
then then this operation inserts a new edge between <A>edge1</A> and
<A>edge2</A>.
<A>edge1</A> and <A>edge2</A> are split up into two new edges each, which are
all adjacent to the inserted edge. Hence, the vertices of the inserted edge both
have a degree of 3.

The opposite operation is <Ref Oper="DigraphReduceEdge"/>.

A new digraph constructed from <A>digraph</A> is returned,
unless <A>digraph</A> belongs to <Ref Filt="IsMutableDigraph"/>;
in this case changes are made directly to <A>digraph</A>, which is then returned.
The <A>digraph</A> must not belong to <Ref Filt="IsMultiDigraph"/>. <P/>

<Example><![CDATA[
gap> D := DigraphByEdges([[1, 2], [2, 1], [3, 4], [4, 3]]);
<immutable digraph with 4 vertices, 4 edges>
gap> D2 := DigraphInsertEdge(D, [1, 2], [3, 4]);
<immutable digraph with 6 vertices, 10 edges>
gap> DigraphEdges(D2);
[ [ 1, 5 ], [ 2, 5 ], [ 3, 6 ], [ 4, 6 ], [ 5, 1 ], [ 5, 2 ], [ 5, 6 ],
[ 6, 3 ], [ 6, 4 ], [ 6, 5 ] ]
gap> D := DigraphByEdges([[1, 2], [2, 1], [2, 3], [3, 2]]);
<immutable digraph with 3 vertices, 4 edges>
gap> D2 := DigraphInsertEdge(D, [1, 2], [2, 3]);
<immutable digraph with 5 vertices, 10 edges>
gap> DigraphEdges(D2);
[ [ 1, 4 ], [ 2, 4 ], [ 2, 5 ], [ 3, 5 ], [ 4, 1 ], [ 4, 2 ], [ 4, 5 ],
[ 5, 2 ], [ 5, 3 ], [ 5, 4 ] ]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphReduceEdge">
<ManSection>
<Oper Name="DigraphReduceEdge" Arg="digraph, edge"
Label="for a symmeric digraph and a list of positive integers"/>
<Returns>A digraph.</Returns>
<Description>
If <A>edge</A> is an edge of <A>digraph</A> and adjacent to four edges, then this
operation reduces this <A>edge</A>: <A>edge</A> will be removed, and for both
vertices of <A>edge</A> the two adjacent edges are combined to a single edge.
The vertices of <A>edge</A> must both have a degree of 3.

The opposite operation is <Ref Oper="DigraphInsertEdge"/>.

A new digraph constructed from <A>digraph</A> is returned,
unless <A>digraph</A> belongs to <Ref Filt="IsMutableDigraph"/>;
in this case changes are made directly to <A>digraph</A>, which is then returned.
The <A>digraph</A> must not belong to <Ref Filt="IsMultiDigraph"/>. <P/>

<Example><![CDATA[
gap> D := DigraphByEdges([[1, 5], [5, 1], [2, 5], [5, 2], [3, 6],
[6, 3], [4, 6], [6, 4], [5, 6], [6, 5]]);
<immutable digraph with 6 vertices, 10 edges>
gap> D2 := DigraphReduceEdge(D, [5, 6]);
<immutable digraph with 4 vertices, 4 edges>
gap> DigraphEdges(D2);
[ [ 1, 2 ], [ 2, 1 ], [ 3, 4 ], [ 4, 3 ] ]
gap> D := DigraphByEdges([[1, 4], [4, 1], [2, 4], [4, 2], [2, 5],
[5, 2], [3, 5], [5, 3], [4, 5], [5, 4]]);
<immutable digraph with 5 vertices, 10 edges>
gap> D2 := DigraphReduceEdge(D, [4, 5]);
<immutable digraph with 3 vertices, 4 edges>
gap> DigraphEdges(D2);
[ [ 1, 2 ], [ 2, 1 ], [ 2, 3 ], [ 3, 2 ] ]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="IsMatching">
<ManSection>
<Oper Name="IsMatching" Arg="digraph, list"/>
Expand Down
4 changes: 4 additions & 0 deletions gap/oper.gd
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ DeclareOperation("DigraphClosure", [IsDigraph, IsPosInt]);
DeclareOperation("DigraphContractEdge", [IsDigraph, IsPosInt, IsPosInt]);
DeclareOperation("DigraphContractEdge", [IsDigraph, IsDenseList]);

DeclareOperation("DigraphInsertEdge", [IsDigraph, IsDenseList, IsDenseList]);

DeclareOperation("DigraphReduceEdge", [IsDigraph, IsDenseList]);

# 3. Ways of combining digraphs . . .
DeclareGlobalFunction("DigraphDisjointUnion");
DeclareGlobalFunction("DigraphJoin");
Expand Down
181 changes: 181 additions & 0 deletions gap/oper.gi
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,187 @@ function(D, edge)
return DigraphContractEdge(D, edge[1], edge[2]);
end);

DIGRAPHS_CheckInsertEdgeDigraph := function(D, edge1, edge2)
if IsEmptyDigraph(D) then
ErrorNoReturn("the 1st argument <D> must not be an empty digraph");
fi;
if not IsSymmetricDigraph(D) then
ErrorNoReturn("the 1st argument <D> must be a symmetric digraph");
fi;

if Length(edge1) <> 2 then
ErrorNoReturn("the 2nd argument <edge1> must be a list of length 2");
fi;
if not IsDigraphEdge(D, edge1) then
ErrorNoReturn("the 2nd argument <edge1> must be an edge of the digraph <D>");
fi;

if Length(edge2) <> 2 then
ErrorNoReturn("the 3rd argument <edge2> must be a list of length 2");
fi;
if not IsDigraphEdge(D, edge2) then
ErrorNoReturn("the 3rd argument <edge2> must be an edge of the digraph <D>");
fi;

if Length(Union(edge1, edge2)) < 3 then
ErrorNoReturn("the 2nd and 3rd argument <edge1> and <edge2> must be two different edges");
fi;

end;

InstallMethod(DigraphInsertEdge,
"for a symmetric digraph and two dense lists",
[IsMutableDigraph, IsDenseList, IsDenseList],
function(D, edge1, edge2)
local numVertices;

DIGRAPHS_CheckInsertEdgeDigraph(D, edge1, edge2);

numVertices := Maximum(DigraphVertices(D));

D := DigraphRemoveEdge(D, edge1);
D := DigraphRemoveEdge(D, Reversed(edge1));
D := DigraphRemoveEdge(D, edge2);
D := DigraphRemoveEdge(D, Reversed(edge2));

DigraphAddVertex(D, numVertices + 1); # vertex A
DigraphAddVertex(D, numVertices + 2); # vertex B

# Add two connected edges between each former edge
#
# Add edges intersecting former edge1 with vertex A
DigraphAddEdge(D, edge1[1], numVertices + 1);
DigraphAddEdge(D, numVertices + 1, edge1[1]);
#
DigraphAddEdge(D, edge1[2], numVertices + 1);
DigraphAddEdge(D, numVertices + 1, edge1[2]);
#
# Add edges intersecting former edge2 with vertex B
DigraphAddEdge(D, edge2[1], numVertices + 2);
DigraphAddEdge(D, numVertices + 2, edge2[1]);
#
DigraphAddEdge(D, edge2[2], numVertices + 2);
DigraphAddEdge(D, numVertices + 2, edge2[2]);
#
# Add edges connecting vertex A and vertex B
DigraphAddEdge(D, numVertices + 1, numVertices + 2);
DigraphAddEdge(D, numVertices + 2, numVertices + 1);

# TODO: Call SetIsSymmetricDigraph and/or
# SetDigraphSymmetricClosureAttr here?

return D;
end);

InstallMethod(DigraphInsertEdge,
"for a symmetric digraph and two dense lists",
[IsImmutableDigraph, IsDenseList, IsDenseList],
function(D, edge1, edge2)
D := DigraphInsertEdge(DigraphMutableCopy(D), edge1, edge2);

return MakeImmutable(D);
end);

InstallMethod(DigraphInsertEdge,
"for a symmetric digraph and two dense lists",
[IsDigraph, IsDenseList, IsDenseList],
function(D, edge1, edge2)
return DigraphInsertEdge(D, edge1, edge2);
end);

DIGRAPHS_CheckReduceEdgeDigraph := function(D, edge)
local leftVertexOutNeighbours, rightVertexOutNeighbours;

if IsEmptyDigraph(D) then
ErrorNoReturn("the 1st argument <D> must not be an empty digraph");
fi;
if not IsSymmetricDigraph(D) then
ErrorNoReturn("the 1st argument <D> must be a symmetric digraph");
fi;

if Length(edge) <> 2 then
ErrorNoReturn("the 2nd argument <edge> must be a list of length 2");
fi;
if not IsDigraphEdge(D, edge) then
ErrorNoReturn("the 2nd argument <edge> must be an edge of the digraph <D>");
fi;

leftVertexOutNeighbours := OutNeighboursOfVertex(D, edge[1]);
rightVertexOutNeighbours := OutNeighboursOfVertex(D, edge[2]);

# Check if edge vertices have degree three
if Length(leftVertexOutNeighbours) <> 3 or Length(rightVertexOutNeighbours) <> 3 then
ErrorNoReturn("the 2nd argument <edge> must be an edge where the incident vertices have degree three");
fi;
if not Length(Union(leftVertexOutNeighbours, rightVertexOutNeighbours)) in [5, 6] then
ErrorNoReturn("the 2nd argument <edge> must be an edge that is adjacent to four edges");
fi;

end;

InstallMethod(DigraphReduceEdge,
"for a symmetric digraph and a dense list",
[IsMutableDigraph, IsDenseList],
function(D, edge)
local neighbours, neighbour, newEdge;

DIGRAPHS_CheckReduceEdgeDigraph(D, edge);

# Add new edges
#
# left side of edge
newEdge := [];
neighbours := OutNeighboursOfVertex(D, edge[1]);
for neighbour in neighbours do
if neighbour <> edge[2] then
Add(newEdge, neighbour);
fi;
od;
for neighbour in neighbours do
DigraphRemoveEdge(D, [edge[1], neighbour]);
od;
DigraphAddEdge(D, newEdge[1], newEdge[2]);
DigraphAddEdge(D, newEdge[2], newEdge[1]);
#
# right side of intersecting edge
newEdge := [];
neighbours := OutNeighboursOfVertex(D, edge[2]);
for neighbour in neighbours do
if neighbour <> edge[1] then
Add(newEdge, neighbour);
fi;
od;
for neighbour in neighbours do
DigraphRemoveEdge(D, [edge[2], neighbour]);
od;
DigraphAddEdge(D, newEdge[1], newEdge[2]);
DigraphAddEdge(D, newEdge[2], newEdge[1]);

# Remove old vertices
DigraphRemoveVertices(D, edge);

# TODO: Call SetIsSymmetricDigraph and/or
# SetDigraphSymmetricClosureAttr here?

return D;
end);

InstallMethod(DigraphReduceEdge,
"for a symmetric digraph and a dense list",
[IsImmutableDigraph, IsDenseList],
function(D, edge)
D := DigraphReduceEdge(DigraphMutableCopy(D), edge);

return MakeImmutable(D);
end);

InstallMethod(DigraphReduceEdge,
"for a symmetric digraph and a dense list",
[IsDigraph, IsDenseList],
function(D, edge)
return DigraphReduceEdge(D, edge);
end);

#############################################################################
# 3. Ways of combining digraphs
#############################################################################
Expand Down
Loading