diff --git a/doc/attr.xml b/doc/attr.xml index 7eecc5721..011f74628 100644 --- a/doc/attr.xml +++ b/doc/attr.xml @@ -1495,6 +1495,55 @@ gap> DigraphAllChordlessCycles(D); <#/GAPDoc> +<#GAPDoc Label="FacialWalks"> + + + A list of lists of vertices. + + If digraph is an Eulerian digraph and list is a rotation system of digraph, + then FacialWalks returns a list of the facial walks in digraph.

+ + A rotation system defines for each vertex the ordering of the out-neighbours. + For example, the method computes for a + planar digraph D the rotation system of a planar embedding of D. + The facial walks of digraph are closed walks and they are defined by the rotation system list. + They describe the boundaries of the faces of the embedding of digraph given + by the rotation system list. + + The operation FacialWalks ignores + multiple edges and loops.

+ Here are some examples for planar embeddings: + D1 := CycleDigraph(4);; +gap> planar := PlanarEmbedding(D1); +[ [ 2 ], [ 3 ], [ 4 ], [ 1 ] ] +gap> FacialWalks(D1, planar); +[ [ 1, 2, 3, 4 ] ] +gap> nonPlanar := [[2, 4], [1, 3], [2, 4], [1, 3]];; +gap> FacialWalks(D1, nonPlanar); +[ [ 1, 2, 3, 4 ] ] +gap> D2 := CompleteMultipartiteDigraph([2, 2, 2]);; +gap> rotationSystem := PlanarEmbedding(D2); +[ [ 3, 5, 4, 6 ], [ 6, 4, 5, 3 ], [ 6, 2, 5, 1 ], [ 1, 5, 2, 6 ], + [ 1, 3, 2, 4 ], [ 1, 4, 2, 3 ] ] +gap> FacialWalks(D2, rotationSystem); +[ [ 1, 3, 6 ], [ 1, 4, 5 ], [ 1, 5, 3 ], [ 1, 6, 4 ], [ 2, 3, 5 ], + [ 2, 4, 6 ], [ 2, 5, 4 ], [ 2, 6, 3 ] ] +]]> + Here is an example of a non-planar digraph with a corresponding rotation system: + D3 := CompleteMultipartiteDigraph([3, 3]);; +gap> rot := [[6, 5, 4], [6, 5, 4], [6, 5, 4], [1, 2, 3], +> [1, 2, 3], [1, 2, 3]]; +[ [ 6, 5, 4 ], [ 6, 5, 4 ], [ 6, 5, 4 ], [ 1, 2, 3 ], [ 1, 2, 3 ], + [ 1, 2, 3 ] ] +gap> FacialWalks(D3, rot); +[ [ 1, 4, 2, 6, 3, 5 ], [ 1, 5, 2, 4, 3, 6 ], [ 1, 6, 2, 5, 3, 4 ] ] +]]> + + +<#/GAPDoc> + <#GAPDoc Label="HamiltonianPath"> diff --git a/doc/z-chap4.xml b/doc/z-chap4.xml index 4e87e055b..789c3f1f7 100644 --- a/doc/z-chap4.xml +++ b/doc/z-chap4.xml @@ -80,6 +80,7 @@ <#Include Label="DigraphLongestSimpleCircuit"> <#Include Label="DigraphAllUndirectedSimpleCircuits"> <#Include Label="DigraphAllChordlessCycles"> + <#Include Label="FacialWalks"> <#Include Label="DigraphLayers"> <#Include Label="DigraphDegeneracy"> <#Include Label="DigraphDegeneracyOrdering"> diff --git a/gap/attr.gd b/gap/attr.gd index 7814a5f37..47faa5e31 100644 --- a/gap/attr.gd +++ b/gap/attr.gd @@ -62,6 +62,7 @@ DeclareAttribute("DigraphAllSimpleCircuits", IsDigraph); DeclareAttribute("DigraphLongestSimpleCircuit", IsDigraph); DeclareAttribute("DigraphAllUndirectedSimpleCircuits", IsDigraph); DeclareAttribute("DigraphAllChordlessCycles", IsDigraph); +DeclareOperation("FacialWalks", [IsDigraph, IsList]); DeclareAttribute("HamiltonianPath", IsDigraph); DeclareAttribute("DigraphPeriod", IsDigraph); DeclareAttribute("DigraphLoops", IsDigraph); diff --git a/gap/attr.gi b/gap/attr.gi index de37f4618..741b0c508 100644 --- a/gap/attr.gi +++ b/gap/attr.gi @@ -1653,6 +1653,75 @@ function(D) return C; end); +# Compute for a given rotation system the facial walks +InstallMethod(FacialWalks, "for a digraph and a list", +[IsDigraph, IsList], +function(D, rotationSystem) + + local FacialWalk, facialWalks, remEdges, cycle; + + if not IsEulerianDigraph(D) then + Error("The given digraph is not Eulerian."); + fi; + + if not IsDenseList(rotationSystem) or Length(rotationSystem) + <> DigraphNrVertices(D) then + Error("The given rotation system does not fit to the given digraph."); + fi; + + if Difference(DuplicateFreeList(Flat(rotationSystem)), DigraphVertices(D)) + <> [] then + Error("The given rotation system does not fit to the given digraph."); + fi; + + # computes a facial cycles starting with the edge 'startEdge' + FacialWalk := function(rotationSystem, startEdge) + local startVertex, preVertex, actVertex, cycle, nextVertex, pos; + + startVertex := startEdge[1]; + actVertex := startEdge[2]; + preVertex := startVertex; + + cycle := [startVertex, actVertex]; + + nextVertex := 0; # just an initialization + while true do + pos := Position(rotationSystem[actVertex], preVertex); + + if pos < Length(rotationSystem[actVertex]) then + nextVertex := rotationSystem[actVertex][pos + 1]; + else + nextVertex := rotationSystem[actVertex][1]; + fi; + if nextVertex <> startEdge[2] or actVertex <> startVertex then + Add(cycle, nextVertex); + Remove(remEdges, Position(remEdges, [preVertex, actVertex])); + preVertex := actVertex; + actVertex := nextVertex; + else + break; + fi; + od; + Remove(remEdges, Position(remEdges, [preVertex, startVertex])); + # Remove the last vertex, otherwise otherwise + # the start vertex is contained twice + Remove(cycle); + return cycle; + end; + + D := DigraphRemoveLoops(DigraphRemoveAllMultipleEdges( + DigraphMutableCopyIfMutable(D))); + + facialWalks := []; + remEdges := ShallowCopy(DigraphEdges(D)); + + while remEdges <> [] do + cycle := FacialWalk(rotationSystem, remEdges[1]); + Add(facialWalks, cycle); + od; + return facialWalks; +end); + # The following method 'DIGRAPHS_Bipartite' was originally written by Isabella # Scott and then modified by FLS. # It is the backend to IsBipartiteDigraph, Bicomponents, and DigraphColouring diff --git a/tst/standard/attr.tst b/tst/standard/attr.tst index 468abcd59..8e87659b5 100644 --- a/tst/standard/attr.tst +++ b/tst/standard/attr.tst @@ -1071,6 +1071,31 @@ gap> DigraphAllUndirectedSimpleCircuits(g); [ 4, 3, 9, 5, 7, 8, 6, 10 ], [ 4, 3, 9, 10 ], [ 5, 6, 8, 7 ], [ 9, 5, 6, 10 ], [ 9, 5, 7, 8, 6, 10 ] ] +# FacialCycles +gap> g := Digraph([]);; +gap> rotationSy := [];; +gap> FacialWalks(g,rotationSy); +[ ] +gap> g := Digraph([[2],[1,3],[2,4],[3]]);;; +gap> rotationSy := [[2],[1,3],[2,4],[3]];; +gap> FacialWalks(g,rotationSy); +[ [ 1, 2, 3, 4, 3, 2 ] ] +gap> g := CycleDigraph(4);; +gap> planar := PlanarEmbedding(g); +[ [ 2 ], [ 3 ], [ 4 ], [ 1 ] ] +gap> FacialWalks(g, planar); +[ [ 1, 2, 3, 4 ] ] +gap> nonPlanar := [[2, 4], [1, 3], [2, 4], [1, 3]];; +gap> FacialWalks(g, nonPlanar); +[ [ 1, 2, 3, 4 ] ] +gap> g := CompleteMultipartiteDigraph([2, 2, 2]);; +gap> rotationSystem := PlanarEmbedding(g); +[ [ 3, 5, 4, 6 ], [ 6, 4, 5, 3 ], [ 6, 2, 5, 1 ], [ 1, 5, 2, 6 ], + [ 1, 3, 2, 4 ], [ 1, 4, 2, 3 ] ] +gap> FacialWalks(g, rotationSystem); +[ [ 1, 3, 6 ], [ 1, 4, 5 ], [ 1, 5, 3 ], [ 1, 6, 4 ], [ 2, 3, 5 ], + [ 2, 4, 6 ], [ 2, 5, 4 ], [ 2, 6, 3 ] ] + # Issue #676 gap> D := Digraph([[], [3], []]);; gap> SetDigraphVertexLabels(D, ["one", "two", "three"]);