diff --git a/doc/attr.xml b/doc/attr.xml
index 3a6769da8..0ef656ede 100644
--- a/doc/attr.xml
+++ b/doc/attr.xml
@@ -2510,6 +2510,42 @@ 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>
+
<#GAPDoc Label="NonUpperSemimodularPair">
diff --git a/doc/z-chap4.xml b/doc/z-chap4.xml
index 0f2ebe1ee..c088fc421 100644
--- a/doc/z-chap4.xml
+++ b/doc/z-chap4.xml
@@ -38,7 +38,7 @@
<#Include Label="DegreeMatrix">
<#Include Label="LaplacianMatrix">
-
+
Orders
<#Include Label="PartialOrderDigraphMeetOfVertices">
<#Include Label="NonUpperSemimodularPair">
@@ -83,6 +83,7 @@
<#Include Label="HamiltonianPath">
<#Include Label="NrSpanningTrees">
<#Include Label="DigraphDijkstra">
+ <#Include Label="VertexConnectivity">
<#Include Label="DigraphCycleBasis">
diff --git a/gap/attr.gd b/gap/attr.gd
index d0c1732ff..4bceff6c3 100644
--- a/gap/attr.gd
+++ b/gap/attr.gd
@@ -70,6 +70,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 c2fde5582..887382700 100644
--- a/gap/attr.gi
+++ b/gap/attr.gi
@@ -2868,6 +2868,149 @@ function(D)
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);
+
# The following function is a transliteration from python to GAP of
# the function find_nonsemimodular_pair
# in sage/src/sage/combinat/posets/hasse_diagram.py
diff --git a/gap/examples.gi b/gap/examples.gi
index a5d0e4be4..f752456cc 100644
--- a/gap/examples.gi
+++ b/gap/examples.gi
@@ -286,6 +286,11 @@ function(_, 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 167efe8be..e7770ab9b 100644
--- a/tst/standard/attr.tst
+++ b/tst/standard/attr.tst
@@ -2794,6 +2794,44 @@ gap> D := DigraphRemoveEdge(D, 1, 3);
gap> D := DigraphRemoveEdge(D, 1, 3);
+# 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
+gap> D := DigraphFromGraph6String("NoCQ@?EAS_C`QA?c_Kg");;
+gap> VertexConnectivity(D);
+3
+gap> D := DigraphFromGraph6String("HoStIv{");;
+gap> VertexConnectivity(D);
+4
+
# Semimodular lattices
gap> D := DigraphFromDigraph6String("&C[o?");