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