-
Notifications
You must be signed in to change notification settings - Fork 64
Implementation of DigraphInsertEdge and DigraphReduceEdge #899
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -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 | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| The opposite operation is <Ref Oper="DigraphReduceEdge"/>. | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| 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/> | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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"/> | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,6 +38,10 @@ DeclareOperation("DigraphClosure", [IsDigraph, IsPosInt]); | |
| DeclareOperation("DigraphContractEdge", [IsDigraph, IsPosInt, IsPosInt]); | ||
| DeclareOperation("DigraphContractEdge", [IsDigraph, IsDenseList]); | ||
|
|
||
| DeclareOperation("DigraphInsertEdge", [IsDigraph, IsDenseList, IsDenseList]); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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"); | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -603,6 +603,183 @@ function(D, edge) | |||||
| return DigraphContractEdge(D, edge[1], edge[2]); | ||||||
| end); | ||||||
|
|
||||||
| DIGRAPHS_CheckInsertEdgeDigraph := function(D, edge1, edge2) | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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"); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| 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)); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| 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); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| end); | ||||||
|
|
||||||
| DIGRAPHS_CheckReduceEdgeDigraph := function(D, edge) | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same two comments for this function:
|
||||||
| 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, | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| D := DigraphReduceEdge(DigraphMutableCopy(D), edge); | ||||||
|
|
||||||
| return MakeImmutable(D); | ||||||
| end); | ||||||
|
|
||||||
| ############################################################################# | ||||||
| # 3. Ways of combining digraphs | ||||||
| ############################################################################# | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.