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