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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
then then this operation inserts a new edge between <A>edge1</A> and
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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does it mean for an edge to be adjacent to an edge?

have a degree of 3.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
have a degree of 3.
have a degree of 3.<P/>


The opposite operation is <Ref Oper="DigraphReduceEdge"/>.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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


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/>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe say that an error is thrown if IsMultiDigraph is true?


<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]);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this shouldn't have a more specific/descriptive name, when this PR was first opened I thought this meant something rather different. I don't have a suggestion for a better name, open to suggestions?


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

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

DIGRAPHS_CheckInsertEdgeDigraph := function(D, edge1, edge2)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function could be a number of lines shorter if the conditions were combined with elif rather than being separate if conditions.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see why you put this in a separate function, but given that it is only called in one place, I think it'd be better to just put this into the function where it is called.

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");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"be two different edges");
"be distinct 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));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
numVertices := Maximum(DigraphVertices(D));
numVertices := DigraphNrVertices(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);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return MakeImmutable(D);
{D, edge1, edge2} -> MakeImmutable(DigraphInsertEdge(DigraphMutableCopy(D), edge1, edge2)));

end);

DIGRAPHS_CheckReduceEdgeDigraph := function(D, edge)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same two comments for this function:

  1. It doesn't need to exist;
  2. it can be shortened a little by combining multiple if statements with elif

local leftVertexOutNeighbours, rightVertexOutNeighbours,
allVertexOutNeighbours;

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]);
allVertexOutNeighbours := Union(leftVertexOutNeighbours,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd move this down after the checks in 713, to avoid computing this in case an error is already given.

rightVertexOutNeighbours);

# 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(allVertexOutNeighbours) in [5, 6] then
ErrorNoReturn("the 2nd argument <edge> must be an edge where the ",
"incident vertices have a maximum of one common ",
"neighbour");
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)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
function(D, edge)
{D, edge} -> MakeImmutable(DigraphReduceEdge(DigraphMutableCopy(D), edge)));

D := DigraphReduceEdge(DigraphMutableCopy(D), edge);

return MakeImmutable(D);
end);

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