Skip to content

Commit

Permalink
attr: add VertexConnectivity
Browse files Browse the repository at this point in the history
  • Loading branch information
ffloresbrito authored and wilfwilson committed Oct 27, 2021
1 parent 5b07fb1 commit 059d12b
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 0 deletions.
36 changes: 36 additions & 0 deletions doc/attr.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2399,3 +2399,39 @@ gap> Length(M);
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="VertexConnectivity">
<ManSection>
<Attr Name="VertexConnectivity" Arg="digraph"/>
<Returns>An non-negative integer.</Returns>
<Description>
For a digraph <A>digraph</A> with set of vertices <C>V</C>, the attribute
<C>VertexConnectivity(<A>digraph</A>)</C> returns the least cardinality
<C>|S|</C> of a subset <C>S</C> of <C>V</C> such that the induced subdigraph
of <A>digraph</A> on <C>V \ S</C> is disconnected, or has at most one
vertex. <P/>

The algorithm makes <C>n - d - 1 + d * (d - 1) / 2</C> calls to a max-flow
algorithm which itself has complexity <C>O((n ^ 2) * e)</C>, where <C>n</C>
is the number of vertices of <A>digraph</A>, and <C>e, d</C> are the number
of edges and the minimum degree (respectively) of the underlying undirected
graph of <A>digraph</A>.

<Example><![CDATA[
gap> J := JohnsonDigraph(9, 2);
<immutable symmetric digraph with 36 vertices, 504 edges>
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]]);
<immutable digraph with 7 vertices, 20 edges>
gap> VertexConnectivity(D);
1
gap> T := Digraph([]);
<immutable empty digraph with 0 vertices>
gap> VertexConnectivity(T);
0
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>
1 change: 1 addition & 0 deletions doc/z-chap4.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
<#Include Label="HamiltonianPath">
<#Include Label="NrSpanningTrees">
<#Include Label="DigraphDijkstra">
<#Include Label="VertexConnectivity">
</Section>

<Section><Heading>Cayley graphs of groups</Heading>
Expand Down
1 change: 1 addition & 0 deletions gap/attr.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
143 changes: 143 additions & 0 deletions gap/attr.gi
Original file line number Diff line number Diff line change
Expand Up @@ -2613,3 +2613,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);
5 changes: 5 additions & 0 deletions gap/examples.gi
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,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);

Expand Down
32 changes: 32 additions & 0 deletions tst/standard/attr.tst
Original file line number Diff line number Diff line change
Expand Up @@ -2774,6 +2774,38 @@ gap> D := DigraphRemoveEdge(D, 1, 3);
gap> D := DigraphRemoveEdge(D, 1, 3);
<immutable digraph with 6 vertices, 11 edges>

# VertexConnectivity
gap> D := CompleteDigraph(10);
<immutable complete digraph with 10 vertices>
gap> VertexConnectivity(D);
9
gap> D := JohnsonDigraph(9, 2);
<immutable symmetric digraph with 36 vertices, 504 edges>
gap> VertexConnectivity(D);
14
gap> D := Digraph([]);
<immutable empty digraph with 0 vertices>
gap> VertexConnectivity(D);
0
gap> D := Digraph([[]]);
<immutable empty digraph with 1 vertex>
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]]);
<immutable digraph with 7 vertices, 20 edges>
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]]);
<immutable digraph with 7 vertices, 21 edges>
gap> VertexConnectivity(D);
2
gap> D := Digraph([[2, 3], [3, 5], [1, 2, 4], [2, 3], [3]]);
<immutable digraph with 5 vertices, 10 edges>
gap> VertexConnectivity(D);
2

# DIGRAPHS_UnbindVariables
gap> Unbind(adj);
gap> Unbind(adj1);
Expand Down

0 comments on commit 059d12b

Please sign in to comment.