diff --git a/doc/attr.xml b/doc/attr.xml
index c0342e175..7c1daf610 100644
--- a/doc/attr.xml
+++ b/doc/attr.xml
@@ -2371,3 +2371,39 @@ gap> Length(M);
<#/GAPDoc>
+
+<#GAPDoc Label="VertexConnectivity">
+
+
+ An non-negative integer.
+
+ For a digraph digraph with set of vertices V, the attribute
+ VertexConnectivity(digraph) returns the least cardinality
+ |S| of a subset S of V such that the induced subdigraph
+ of digraph on V \ S is disconnected, or has at most one
+ vertex.
+
+ The algorithm makes n - d - 1 + d * (d - 1) / 2 calls to a max-flow
+ algorithm which itself has complexity O((n ^ 2) * e), where n
+ is the number of vertices of digraph, and e, d are the number
+ of edges and the minimum degree (respectively) of the underlying undirected
+ graph of digraph.
+
+ J := JohnsonDigraph(9, 2);
+
+gap> VertexConnectivity(J);
+14
+gap> D := Digraph([[2, 4, 5], [1, 4], [4, 7], [1, 2, 3, 5, 6, 7],
+> [1, 4], [4, 7], [3, 4, 6]]);
+
+gap> VertexConnectivity(D);
+1
+gap> T := Digraph([]);
+
+gap> VertexConnectivity(T);
+0
+]]>
+
+
+<#/GAPDoc>
diff --git a/doc/z-chap4.xml b/doc/z-chap4.xml
index 8d948d754..746e481f0 100644
--- a/doc/z-chap4.xml
+++ b/doc/z-chap4.xml
@@ -72,6 +72,7 @@
<#Include Label="HamiltonianPath">
<#Include Label="NrSpanningTrees">
<#Include Label="DigraphDijkstra">
+ <#Include Label="VertexConnectivity">
Cayley graphs of groups
diff --git a/gap/attr.gd b/gap/attr.gd
index 7f57ba5d2..6e8c420cc 100644
--- a/gap/attr.gd
+++ b/gap/attr.gd
@@ -65,6 +65,7 @@ DeclareAttribute("DigraphCore", IsDigraph);
DeclareAttribute("CharacteristicPolynomial", IsDigraph);
DeclareAttribute("NrSpanningTrees", IsDigraph);
+DeclareAttribute("VertexConnectivity", IsDigraph);
# AsGraph must be mutable for grape to function properly
DeclareAttribute("AsGraph", IsDigraph, "mutable");
diff --git a/gap/attr.gi b/gap/attr.gi
index 3b56892da..e2a874ff5 100644
--- a/gap/attr.gi
+++ b/gap/attr.gi
@@ -2388,3 +2388,146 @@ function(D)
M := List(DigraphLoops(D), x -> [x, x]);
return Union(M, DIGRAPHS_MateToMatching(D, mateD));
end);
+
+InstallMethod(VertexConnectivity, "for a digraph", [IsDigraph],
+function(digraph)
+ local kappas, newnetw, edmondskarp, mat, degs, mindegv, mindeg, Nv, outn, k,
+ i, j, x, y;
+
+ if DigraphNrVertices(digraph) <= 1 or not IsConnectedDigraph(digraph) then
+ return 0;
+ fi;
+
+ if IsMultiDigraph(digraph) then
+ digraph := DigraphRemoveAllMultipleEdges(digraph);
+ fi;
+
+ kappas := [DigraphNrVertices(digraph) - 1];
+
+ # The function newnetw is an implementation of Algorithm Nine from
+ # Abdol-Hossein Esfahanian's ``Connectivity Algorithms'' which can be found at
+ # https://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf
+ newnetw := function(digraph, source, sink)
+ local n, mat, outn, x, y;
+ n := DigraphNrVertices(digraph);
+ mat := List([1 .. 2 * n], x -> BlistList([1 .. 2 * n], []));
+ outn := OutNeighbours(digraph);
+ for x in [1 .. DigraphNrVertices(digraph)] do
+ if x <> source and x <> sink then
+ mat[x + n][x] := true;
+ fi;
+ for y in outn[x] do
+ if x = source or x = sink then
+ mat[x][y + n] := true;
+ mat[y][x] := true;
+ elif y = source or y = sink then
+ mat[y][x + n] := true;
+ mat[x][y] := true;
+ else
+ mat[y][x + n] := true;
+ mat[x][y + n] := true;
+ fi;
+ od;
+ od;
+ return List(mat, x -> ListBlist([1 .. 2 * n], x));
+ end;
+
+ # The following function is an implementation of the Edmonds-Karp algorithm
+ # with some minor adjustments that take into account the fact that the
+ # capacity of all edges is 1.
+ edmondskarp := function(netw, source, sink)
+ local flow, capacity, queue, m, predecessor, edgeindex, stop, current, n, v;
+
+ flow := 0;
+ capacity := List(netw, x -> BlistList(x, x));
+ # nredges := Sum(List(netw, Length));
+
+ while true do
+ queue := [source];
+ m := 1;
+ predecessor := List(netw, x -> 0);
+ edgeindex := List(netw, x -> 0);
+ stop := false;
+ while m <= Size(queue) and not stop do
+ current := queue[m];
+ n := 0;
+ for v in netw[current] do
+ n := n + 1;
+ if predecessor[v] = 0 and v <> source and capacity[current][n] then
+ predecessor[v] := current;
+ edgeindex[v] := n;
+ Add(queue, v);
+ fi;
+ if v = sink then
+ stop := true;
+ break;
+ fi;
+ od;
+ m := m + 1;
+ od;
+
+ if predecessor[sink] <> 0 then
+ v := predecessor[sink];
+ n := edgeindex[sink];
+ while v <> 0 do
+ capacity[v][n] := false;
+ n := edgeindex[v];
+ v := predecessor[v];
+ od;
+ flow := flow + 1;
+ else
+ return flow;
+ fi;
+ od;
+ end;
+
+ # Referring once again to Abdol-Hossein Esfahanian's paper (see newnetw, above)
+ # the following lines implement Algorithm Eleven of that paper.
+ mat := BooleanAdjacencyMatrix(digraph);
+ degs := ListWithIdenticalEntries(DigraphNrVertices(digraph), 0);
+ for i in DigraphVertices(digraph) do
+ for j in [i + 1 .. DigraphNrVertices(digraph)] do
+ if mat[i][j] or mat[j][i] then
+ degs[i] := degs[i] + 1;
+ degs[j] := degs[j] + 1;
+ fi;
+ od;
+ od;
+
+ mindegv := 0;
+ mindeg := DigraphNrVertices(digraph) + 1;
+ for i in DigraphVertices(digraph) do
+ if degs[i] < mindeg then
+ mindeg := degs[i];
+ mindegv := i;
+ fi;
+ od;
+
+ Nv := OutNeighboursOfVertex(digraph, mindegv);
+ outn := OutNeighbours(digraph);
+
+ for x in DigraphVertices(digraph) do
+ if x <> mindegv and not mat[x][mindegv] and not mat[mindegv][x] then
+ k := edmondskarp(newnetw(digraph, mindegv, x), mindegv, x);
+ if k = 0 then
+ return 0;
+ else
+ AddSet(kappas, k);
+ fi;
+ fi;
+ od;
+
+ for x in [1 .. Size(Nv) - 1] do
+ for y in [x + 1 .. Size(Nv)] do
+ if not mat[Nv[x]][Nv[y]] and not mat[Nv[y]][Nv[x]] then
+ k := edmondskarp(newnetw(digraph, Nv[x], Nv[y]), Nv[x], Nv[y]);
+ if k = 0 then
+ return 0;
+ else
+ AddSet(kappas, k);
+ fi;
+ fi;
+ od;
+ od;
+ return kappas[1];
+end);
diff --git a/gap/examples.gi b/gap/examples.gi
index 402ef6456..d30c1cb0e 100644
--- a/gap/examples.gi
+++ b/gap/examples.gi
@@ -288,6 +288,11 @@ function(filt, n, k)
D := MakeImmutable(JohnsonDigraphCons(IsMutableDigraph, n, k));
SetIsMultiDigraph(D, false);
SetIsSymmetricDigraph(D, true);
+ if k > n then
+ SetVertexConnectivity(D, 0);
+ else
+ SetVertexConnectivity(D, (n - k) * k);
+ fi;
return D;
end);
diff --git a/tst/standard/attr.tst b/tst/standard/attr.tst
index 735e63c8e..e15069977 100644
--- a/tst/standard/attr.tst
+++ b/tst/standard/attr.tst
@@ -2567,6 +2567,38 @@ true
gap> DigraphNrLoops(D) = 0;
true
+# VertexConnectivity
+gap> D := CompleteDigraph(10);
+
+gap> VertexConnectivity(D);
+9
+gap> D := JohnsonDigraph(9, 2);
+
+gap> VertexConnectivity(D);
+14
+gap> D := Digraph([]);
+
+gap> VertexConnectivity(D);
+0
+gap> D := Digraph([[]]);
+
+gap> VertexConnectivity(D);
+0
+gap> D := Digraph([[2, 4, 5], [1, 4], [4, 7], [1, 2, 3, 5, 6, 7],
+> [1, 4], [4, 7], [3, 4, 6]]);
+
+gap> VertexConnectivity(D);
+1
+gap> D := Digraph([[2, 4, 5], [1, 3, 4], [4, 7], [1, 2, 3, 5, 6, 7],
+> [1, 4], [4, 7], [3, 4, 6]]);
+
+gap> VertexConnectivity(D);
+2
+gap> D := Digraph([[2, 3], [3, 5], [1, 2, 4], [2, 3], [3]]);
+
+gap> VertexConnectivity(D);
+2
+
# DIGRAPHS_UnbindVariables
gap> Unbind(adj);
gap> Unbind(adj1);