diff --git a/doc/oper.xml b/doc/oper.xml
index 0930e8f3c..4f7cbd8ae 100644
--- a/doc/oper.xml
+++ b/doc/oper.xml
@@ -1954,6 +1954,27 @@ rec( idom := [ 2, fail, 2, 2, 2 ], preorder := [ 2, 1, 3, 4, 5 ] )
<#/GAPDoc>
+<#GAPDoc Label="DigraphDominatingSet">
+
+
+ A List
+
+ This function returns a dominating set of digraph,
+ which is a subset of vertices whose neighbourhood consists of all vertices in digraph.
+
+
+ The neighbourhood of a set of vertices, V, refers to the set of vertices that are adjacent to a vertex in V,
+ not including any vertices that exist in V. The domating set returned will be one of potentially multiple possible dominating sets for the digraph.
+ DigraphDominatingSet(D);
+[ 4, 1 ]
+gap> DigraphDominatingSet(D);
+[ 1 ]]]>
+
+
+<#/GAPDoc>
+
<#GAPDoc Label="PartialOrderDigraphMeetOfVertices">
Sum(flow[1]);
<#/GAPDoc>
+<#GAPDoc Label="DigraphEdgeConnectivity">
+
+
+ An integer
+
+ This function returns the edge connectivity of digraph. Edge Connectivity refers to the size of a minimum cut of the graph,
+ which, for digraphs, refers to set of edges needed to be removed to ensure the graph is no longer Strongly Connected. That is, there exists two
+ vertices, A and B, for which a path from A to B does not exist.
+
+ It makes use of the DigraphMaximumFlow(digraph) function, by constructing an edge-weighted Digraph
+ with edge weights of 1, then using the Max-flow min-cut theorem to determine the size of the minimum cut.
+ See also .
+ D := Digraph([[2, 3, 4], [1, 3, 4], [1, 2], [2, 3]]);;
+gap> DigraphEdgeConnectivity(D);
+2
+gap> D := Digraph([[], [1, 2], [2]]);;
+gap> DigraphEdgeConnectivity(D);
+0
+gap> D := Digraph([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]);;
+gap> DigraphEdgeConnectivity(D);
+4]]>
+
+
+<#/GAPDoc>
+
<#GAPDoc Label="RandomUniqueEdgeWeightedDigraph">
diff --git a/doc/z-chap4.xml b/doc/z-chap4.xml
index 059e10eea..b2f0c32b7 100644
--- a/doc/z-chap4.xml
+++ b/doc/z-chap4.xml
@@ -76,6 +76,7 @@
<#Include Label="DigraphAbsorptionExpectedSteps">
<#Include Label="Dominators">
<#Include Label="DominatorTree">
+ <#Include Label="DigraphDominatingSet">
<#Include Label="IteratorOfPaths">
<#Include Label="DigraphAllSimpleCircuits">
<#Include Label="DigraphLongestSimpleCircuit">
diff --git a/doc/z-chap5.xml b/doc/z-chap5.xml
index 759876e11..a1be116c9 100644
--- a/doc/z-chap5.xml
+++ b/doc/z-chap5.xml
@@ -33,6 +33,7 @@
<#Include Label="EdgeWeightedDigraphShortestPath">
<#Include Label="DigraphMaximumFlow">
<#Include Label="RandomUniqueEdgeWeightedDigraph">
+ <#Include Label="DigraphEdgeConnectivity">
Orders
diff --git a/gap/oper.gd b/gap/oper.gd
index f6a37e0f8..031efe812 100644
--- a/gap/oper.gd
+++ b/gap/oper.gd
@@ -154,6 +154,7 @@ DeclareOperation("IsOrderIdeal", [IsDigraph, IsList]);
DeclareOperation("IsOrderFilter", [IsDigraph, IsList]);
DeclareOperation("Dominators", [IsDigraph, IsPosInt]);
DeclareOperation("DominatorTree", [IsDigraph, IsPosInt]);
+DeclareOperation("DigraphDominatingSet", [IsDigraph]);
DeclareOperation("DigraphCycleBasis", [IsDigraph]);
# 10. Operations for vertices . . .
diff --git a/gap/oper.gi b/gap/oper.gi
index 3876db50e..452976985 100644
--- a/gap/oper.gi
+++ b/gap/oper.gi
@@ -2522,6 +2522,34 @@ function(D, root)
return result;
end);
+# For calculating a dominating set for a digraph
+# Algorithm 7 in :
+# https://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf
+InstallMethod(DigraphDominatingSet, "for a digraph",
+[IsDigraph],
+function(digraph)
+ local D, seen, Vertices, neighbour, v;
+
+ Vertices := [1 .. DigraphNrVertices(digraph)];
+
+ # Shuffling not technically necessary - may be better not to?
+ Shuffle(Vertices);
+
+ seen := BlistList([1 .. DigraphNrVertices(digraph)], []);
+ D := [];
+ for v in Vertices do
+ if seen[v] = false then
+ seen[v] := true;
+ Append(D, [v]);
+ for neighbour in OutNeighbours(digraph)[v] do
+ seen[neighbour] := true;
+ od;
+ fi;
+ od;
+
+ return D;
+end);
+
# Computes the fundamental cycle basis of a symmetric digraph
# First, notice that the cycle space is composed of orthogonal subspaces
# corresponding to the cycle spaces of the connected components.
diff --git a/gap/weights.gd b/gap/weights.gd
index 7d11bf5f7..c266616a2 100644
--- a/gap/weights.gd
+++ b/gap/weights.gd
@@ -39,6 +39,9 @@ DeclareGlobalFunction("DIGRAPHS_Edge_Weighted_Dijkstra");
DeclareOperation("DigraphMaximumFlow",
[IsDigraph and HasEdgeWeights, IsPosInt, IsPosInt]);
+# Digraph Edge Connectivity
+DeclareOperation("DigraphEdgeConnectivity", [IsDigraph]);
+
# 6. Random edge weighted digraphs
DeclareOperation("RandomUniqueEdgeWeightedDigraph", [IsPosInt]);
DeclareOperation("RandomUniqueEdgeWeightedDigraph", [IsPosInt, IsFloat]);
diff --git a/gap/weights.gi b/gap/weights.gi
index 5b246b002..2595d87e6 100644
--- a/gap/weights.gi
+++ b/gap/weights.gi
@@ -772,6 +772,92 @@ function(D, start, destination)
return flows;
end);
+#############################################################################
+# Digraph Edge Connectivity
+#############################################################################
+
+# Algorithms constructed off the algorithms detailed in:
+# https://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf
+# Each Algorithm uses a different method to decrease the time complexity,
+# of calculating Edge Connectivity, though all make use of DigraphMaximumFlow()
+# due to the Max-Flow, Min-Cut Theorem
+
+# Algorithm 1: Calculating the Maximum Flow of every possible source and sink
+# Algorithm 2: Calculating the Maximum Flow to all sinks of an arbitrary source
+# Algorithm 3: Finding Maximum Flow within the non-leaves of a Spanning Tree
+# Algorithm 4: Constructing a spanning tree with a high number of leaves
+# Algorithm 5: Using the spanning tree^ to find Maximum Flow within non-leaves
+# Algorithm 6: Finding Maximum Flow within a dominating set of the digraph
+# Algorithm 7: Constructing a dominating set for use in Algorithm 6
+
+# Algorithms 4-7 are used below:
+
+# Digraph EdgeConnectivity calculated with Dominating Sets (Algorithm 6-7)
+InstallMethod(DigraphEdgeConnectivity, "for a digraph",
+[IsDigraph],
+function(digraph)
+ # Form an identical but edge weighted digraph with all edge weights as 1:
+ local weights, i, u, v, w, neighbourhood, EdgeD,
+ maxFlow, min, sum, a, b, V, added, st, non_leaf, max,
+ notAddedNeighbours, notadded, NextVertex, NeighboursV,
+ neighbour, Edges, D, VerticesLeft, VerticesED;
+
+ if DigraphNrVertices(digraph) = 1 or
+ DigraphNrStronglyConnectedComponents(digraph) > 1 then
+ return 0;
+ fi;
+
+ weights := List([1 .. DigraphNrVertices(digraph)],
+ x -> List([1 .. Length(OutNeighbours(digraph)[x])],
+ y -> 1));
+ EdgeD := EdgeWeightedDigraph(digraph, weights);
+
+ min := -1;
+
+ # Algorithm 7: Creating a dominating set of the digraph
+ D := DigraphDominatingSet(digraph);
+
+ # Algorithm 6: Using the dominating set created to determine the Maximum Flow
+
+ if Length(D) > 1 then
+
+ v := D[1];
+ for i in [2 .. Length(D)] do
+ w := D[i];
+ a := DigraphMaximumFlow(EdgeD, v, w)[v];
+ b := DigraphMaximumFlow(EdgeD, w, v)[w];
+
+ sum := Minimum(Sum(a), Sum(b));
+ if (sum < min or min = -1) then
+ min := sum;
+ fi;
+ od;
+
+ else
+ # If the dominating set of EdgeD is of Length 1,
+ # the above algorithm will not work
+ # Revert to iterating through all vertices of the original digraph
+
+ u := 1;
+
+ for v in [2 .. DigraphNrVertices(EdgeD)] do
+ a := DigraphMaximumFlow(EdgeD, u, v)[u];
+ b := DigraphMaximumFlow(EdgeD, v, u)[v];
+
+ sum := Minimum(Sum(a), Sum(b));
+ if (sum < min or min = -1) then
+ min := sum;
+ fi;
+
+ od;
+ fi;
+
+ return Minimum(min,
+ Minimum(Minimum(OutDegrees(EdgeD)),
+ Minimum(InDegrees(EdgeD))));
+
+end);
+
#############################################################################
# 6. Random edge weighted digraphs
#############################################################################
diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst
index 1c813fe21..6d45717c6 100644
--- a/tst/standard/oper.tst
+++ b/tst/standard/oper.tst
@@ -134,6 +134,18 @@ gap> M := DigraphMutableCopy(D);;
gap> M ^ p = OnDigraphs(M, p);
true
+# DigraphRemoveAllEdges: for a digraph
+gap> gr2 := Digraph(IsMutableDigraph, [[2, 3], [3], [4], []]);
+
+gap> DigraphRemoveAllEdges(gr2);
+
+gap> gr3 := Digraph(IsMutableDigraph, [[], [], [], []]);
+
+gap> DigraphRemoveAllEdges(gr3);
+
+gap> OutNeighbours(gr3);
+[ [ ], [ ], [ ], [ ] ]
+
# OnDigraphs: for a digraph and a perm
gap> gr := Digraph([[2], [1], [3]]);
@@ -3324,6 +3336,40 @@ gap> DigraphEdges(D);
gap> DigraphVertexLabels(D);
[ 1, 2, 3, 6, [ 4, 5 ] ]
+# DigraphDominatingSet
+gap> d := Digraph([[2, 3], [2, 3], [1, 2, 3]]);;
+gap> p := DigraphDominatingSet(d);;
+gap> neighbours := [];;
+gap> for v in p do
+> Append(neighbours, OutNeighbours(d)[v]);
+> od;
+gap> DigraphVertices(d) = Union(neighbours, p);
+true
+gap> d := Digraph([[2, 4], [3], [1, 5], [3], [4]]);;
+gap> p := DigraphDominatingSet(d);;
+gap> neighbours := [];;
+gap> for v in p do
+> Append(neighbours, OutNeighbours(d)[v]);
+> od;
+gap> DigraphVertices(d) = Union(neighbours, p);
+true
+gap> D := Digraph([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]);;
+gap> p := DigraphDominatingSet(d);;
+gap> neighbours := [];;
+gap> for v in p do
+> Append(neighbours, OutNeighbours(d)[v]);
+> od;
+gap> DigraphVertices(d) = Union(neighbours, p);
+true
+gap> D := RandomDigraph(1);;
+gap> p := DigraphDominatingSet(d);;
+gap> neighbours := [];;
+gap> for v in p do
+> Append(neighbours, OutNeighbours(d)[v]);
+> od;
+gap> DigraphVertices(d) = Union(neighbours, p);
+true
+
#
gap> DIGRAPHS_StopTest();
gap> STOP_TEST("Digraphs package: standard/oper.tst", 0);
diff --git a/tst/standard/weights.tst b/tst/standard/weights.tst
index 59a632140..23d28a0a3 100644
--- a/tst/standard/weights.tst
+++ b/tst/standard/weights.tst
@@ -368,6 +368,23 @@ gap> gr := EdgeWeightedDigraph([[2], [3, 6], [4], [1, 6], [1, 3], []],
gap> DigraphMaximumFlow(gr, 5, 6);
[ [ 10 ], [ 3, 7 ], [ 7 ], [ 0, 7 ], [ 10, 4 ], [ ] ]
+# EdgeConnectivity
+gap> d := Digraph([[2, 3], [2, 3], [1, 2, 3]]);;
+gap> DigraphEdgeConnectivity(d);
+1
+gap> D := RandomDigraph(1);;
+gap> DigraphEdgeConnectivity(D);
+0
+gap> d := Digraph([[2, 4], [3], [1, 5], [3], [4]]);;
+gap> DigraphEdgeConnectivity(d);
+1
+gap> D := Digraph([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]);;
+gap> DigraphEdgeConnectivity(D);
+4
+gap> D := DigraphFromGraph6String("I~~~~~~~w");;
+gap> DigraphEdgeConnectivity(D);
+9
+
#############################################################################
# 6. Random edge-weighted digraphs
#############################################################################
diff --git a/tst/testinstall.tst b/tst/testinstall.tst
index 291b09b7a..02224e66c 100644
--- a/tst/testinstall.tst
+++ b/tst/testinstall.tst
@@ -550,6 +550,20 @@ gap> OutNeighbours(D);
gap> OutNeighbours(C);
[ [ 2, 3, 4 ], [ 1, 3, 4, 5 ], [ 1, 2 ], [ 5 ], [ 4 ] ]
+# DigraphEdgeConnectivity
+gap> D := Digraph([[2, 3, 4], [1, 3, 4], [1, 2], [2, 3]]);;
+gap> DigraphEdgeConnectivity(D);
+2
+gap> D := Digraph([[], [1, 2], [2]]);;
+gap> DigraphEdgeConnectivity(D);
+0
+gap> C := Digraph([[3, 4], [1, 3, 4], [2], [3]]);;
+gap> DigraphEdgeConnectivity(C);
+1
+gap> D := Digraph([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]);;
+gap> DigraphEdgeConnectivity(D);
+4
+
#
gap> DIGRAPHS_StopTest();
gap> STOP_TEST("Digraphs package: testinstall.tst", 0);