Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

By adjacent edges I mean edges that share a common vertex. The operation subdivides edge1 and edge2 by placing a new vertex on each, and then connects those two new vertices with a newly inserted edge. So the four 'split' edge halves share endpoints with the newly inserted edge. Hope i explained it properly now.
Should i rephrase the documentation here?

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?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I copied this section from the documentation of DigraphContractEdge. I can mention that an error is thrown in that case, should i then adjust it for DigraphContractEdge as well?


<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?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I chose to implement it with a rather generic operation name since you would probably change it anyways. However i also don't really have an idea for a more specific name, hence yes i am open to suggestions


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)
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");
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);

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

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

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
Loading