Skip to content

Commit 059d12b

Browse files
ffloresbritowilfwilson
authored andcommitted
attr: add VertexConnectivity
1 parent 5b07fb1 commit 059d12b

File tree

6 files changed

+218
-0
lines changed

6 files changed

+218
-0
lines changed

doc/attr.xml

+36
Original file line numberDiff line numberDiff line change
@@ -2399,3 +2399,39 @@ gap> Length(M);
23992399
</Description>
24002400
</ManSection>
24012401
<#/GAPDoc>
2402+
2403+
<#GAPDoc Label="VertexConnectivity">
2404+
<ManSection>
2405+
<Attr Name="VertexConnectivity" Arg="digraph"/>
2406+
<Returns>An non-negative integer.</Returns>
2407+
<Description>
2408+
For a digraph <A>digraph</A> with set of vertices <C>V</C>, the attribute
2409+
<C>VertexConnectivity(<A>digraph</A>)</C> returns the least cardinality
2410+
<C>|S|</C> of a subset <C>S</C> of <C>V</C> such that the induced subdigraph
2411+
of <A>digraph</A> on <C>V \ S</C> is disconnected, or has at most one
2412+
vertex. <P/>
2413+
2414+
The algorithm makes <C>n - d - 1 + d * (d - 1) / 2</C> calls to a max-flow
2415+
algorithm which itself has complexity <C>O((n ^ 2) * e)</C>, where <C>n</C>
2416+
is the number of vertices of <A>digraph</A>, and <C>e, d</C> are the number
2417+
of edges and the minimum degree (respectively) of the underlying undirected
2418+
graph of <A>digraph</A>.
2419+
2420+
<Example><![CDATA[
2421+
gap> J := JohnsonDigraph(9, 2);
2422+
<immutable symmetric digraph with 36 vertices, 504 edges>
2423+
gap> VertexConnectivity(J);
2424+
14
2425+
gap> D := Digraph([[2, 4, 5], [1, 4], [4, 7], [1, 2, 3, 5, 6, 7],
2426+
> [1, 4], [4, 7], [3, 4, 6]]);
2427+
<immutable digraph with 7 vertices, 20 edges>
2428+
gap> VertexConnectivity(D);
2429+
1
2430+
gap> T := Digraph([]);
2431+
<immutable empty digraph with 0 vertices>
2432+
gap> VertexConnectivity(T);
2433+
0
2434+
]]></Example>
2435+
</Description>
2436+
</ManSection>
2437+
<#/GAPDoc>

doc/z-chap4.xml

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
<#Include Label="HamiltonianPath">
7676
<#Include Label="NrSpanningTrees">
7777
<#Include Label="DigraphDijkstra">
78+
<#Include Label="VertexConnectivity">
7879
</Section>
7980

8081
<Section><Heading>Cayley graphs of groups</Heading>

gap/attr.gd

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ DeclareAttribute("DigraphCore", IsDigraph);
6565

6666
DeclareAttribute("CharacteristicPolynomial", IsDigraph);
6767
DeclareAttribute("NrSpanningTrees", IsDigraph);
68+
DeclareAttribute("VertexConnectivity", IsDigraph);
6869

6970
# AsGraph must be mutable for grape to function properly
7071
DeclareAttribute("AsGraph", IsDigraph, "mutable");

gap/attr.gi

+143
Original file line numberDiff line numberDiff line change
@@ -2613,3 +2613,146 @@ function(D)
26132613
M := List(DigraphLoops(D), x -> [x, x]);
26142614
return Union(M, DIGRAPHS_MateToMatching(D, mateD));
26152615
end);
2616+
2617+
InstallMethod(VertexConnectivity, "for a digraph", [IsDigraph],
2618+
function(digraph)
2619+
local kappas, newnetw, edmondskarp, mat, degs, mindegv, mindeg, Nv, outn, k,
2620+
i, j, x, y;
2621+
2622+
if DigraphNrVertices(digraph) <= 1 or not IsConnectedDigraph(digraph) then
2623+
return 0;
2624+
fi;
2625+
2626+
if IsMultiDigraph(digraph) then
2627+
digraph := DigraphRemoveAllMultipleEdges(digraph);
2628+
fi;
2629+
2630+
kappas := [DigraphNrVertices(digraph) - 1];
2631+
2632+
# The function newnetw is an implementation of Algorithm Nine from
2633+
# Abdol-Hossein Esfahanian's ``Connectivity Algorithms'' which can be found at
2634+
# https://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf
2635+
newnetw := function(digraph, source, sink)
2636+
local n, mat, outn, x, y;
2637+
n := DigraphNrVertices(digraph);
2638+
mat := List([1 .. 2 * n], x -> BlistList([1 .. 2 * n], []));
2639+
outn := OutNeighbours(digraph);
2640+
for x in [1 .. DigraphNrVertices(digraph)] do
2641+
if x <> source and x <> sink then
2642+
mat[x + n][x] := true;
2643+
fi;
2644+
for y in outn[x] do
2645+
if x = source or x = sink then
2646+
mat[x][y + n] := true;
2647+
mat[y][x] := true;
2648+
elif y = source or y = sink then
2649+
mat[y][x + n] := true;
2650+
mat[x][y] := true;
2651+
else
2652+
mat[y][x + n] := true;
2653+
mat[x][y + n] := true;
2654+
fi;
2655+
od;
2656+
od;
2657+
return List(mat, x -> ListBlist([1 .. 2 * n], x));
2658+
end;
2659+
2660+
# The following function is an implementation of the Edmonds-Karp algorithm
2661+
# with some minor adjustments that take into account the fact that the
2662+
# capacity of all edges is 1.
2663+
edmondskarp := function(netw, source, sink)
2664+
local flow, capacity, queue, m, predecessor, edgeindex, stop, current, n, v;
2665+
2666+
flow := 0;
2667+
capacity := List(netw, x -> BlistList(x, x));
2668+
# nredges := Sum(List(netw, Length));
2669+
2670+
while true do
2671+
queue := [source];
2672+
m := 1;
2673+
predecessor := List(netw, x -> 0);
2674+
edgeindex := List(netw, x -> 0);
2675+
stop := false;
2676+
while m <= Size(queue) and not stop do
2677+
current := queue[m];
2678+
n := 0;
2679+
for v in netw[current] do
2680+
n := n + 1;
2681+
if predecessor[v] = 0 and v <> source and capacity[current][n] then
2682+
predecessor[v] := current;
2683+
edgeindex[v] := n;
2684+
Add(queue, v);
2685+
fi;
2686+
if v = sink then
2687+
stop := true;
2688+
break;
2689+
fi;
2690+
od;
2691+
m := m + 1;
2692+
od;
2693+
2694+
if predecessor[sink] <> 0 then
2695+
v := predecessor[sink];
2696+
n := edgeindex[sink];
2697+
while v <> 0 do
2698+
capacity[v][n] := false;
2699+
n := edgeindex[v];
2700+
v := predecessor[v];
2701+
od;
2702+
flow := flow + 1;
2703+
else
2704+
return flow;
2705+
fi;
2706+
od;
2707+
end;
2708+
2709+
# Referring once again to Abdol-Hossein Esfahanian's paper (see newnetw, above)
2710+
# the following lines implement Algorithm Eleven of that paper.
2711+
mat := BooleanAdjacencyMatrix(digraph);
2712+
degs := ListWithIdenticalEntries(DigraphNrVertices(digraph), 0);
2713+
for i in DigraphVertices(digraph) do
2714+
for j in [i + 1 .. DigraphNrVertices(digraph)] do
2715+
if mat[i][j] or mat[j][i] then
2716+
degs[i] := degs[i] + 1;
2717+
degs[j] := degs[j] + 1;
2718+
fi;
2719+
od;
2720+
od;
2721+
2722+
mindegv := 0;
2723+
mindeg := DigraphNrVertices(digraph) + 1;
2724+
for i in DigraphVertices(digraph) do
2725+
if degs[i] < mindeg then
2726+
mindeg := degs[i];
2727+
mindegv := i;
2728+
fi;
2729+
od;
2730+
2731+
Nv := OutNeighboursOfVertex(digraph, mindegv);
2732+
outn := OutNeighbours(digraph);
2733+
2734+
for x in DigraphVertices(digraph) do
2735+
if x <> mindegv and not mat[x][mindegv] and not mat[mindegv][x] then
2736+
k := edmondskarp(newnetw(digraph, mindegv, x), mindegv, x);
2737+
if k = 0 then
2738+
return 0;
2739+
else
2740+
AddSet(kappas, k);
2741+
fi;
2742+
fi;
2743+
od;
2744+
2745+
for x in [1 .. Size(Nv) - 1] do
2746+
for y in [x + 1 .. Size(Nv)] do
2747+
if not mat[Nv[x]][Nv[y]] and not mat[Nv[y]][Nv[x]] then
2748+
k := edmondskarp(newnetw(digraph, Nv[x], Nv[y]), Nv[x], Nv[y]);
2749+
if k = 0 then
2750+
return 0;
2751+
else
2752+
AddSet(kappas, k);
2753+
fi;
2754+
fi;
2755+
od;
2756+
od;
2757+
return kappas[1];
2758+
end);

gap/examples.gi

+5
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,11 @@ function(filt, n, k)
286286
D := MakeImmutable(JohnsonDigraphCons(IsMutableDigraph, n, k));
287287
SetIsMultiDigraph(D, false);
288288
SetIsSymmetricDigraph(D, true);
289+
if k > n then
290+
SetVertexConnectivity(D, 0);
291+
else
292+
SetVertexConnectivity(D, (n - k) * k);
293+
fi;
289294
return D;
290295
end);
291296

tst/standard/attr.tst

+32
Original file line numberDiff line numberDiff line change
@@ -2774,6 +2774,38 @@ gap> D := DigraphRemoveEdge(D, 1, 3);
27742774
gap> D := DigraphRemoveEdge(D, 1, 3);
27752775
<immutable digraph with 6 vertices, 11 edges>
27762776

2777+
# VertexConnectivity
2778+
gap> D := CompleteDigraph(10);
2779+
<immutable complete digraph with 10 vertices>
2780+
gap> VertexConnectivity(D);
2781+
9
2782+
gap> D := JohnsonDigraph(9, 2);
2783+
<immutable symmetric digraph with 36 vertices, 504 edges>
2784+
gap> VertexConnectivity(D);
2785+
14
2786+
gap> D := Digraph([]);
2787+
<immutable empty digraph with 0 vertices>
2788+
gap> VertexConnectivity(D);
2789+
0
2790+
gap> D := Digraph([[]]);
2791+
<immutable empty digraph with 1 vertex>
2792+
gap> VertexConnectivity(D);
2793+
0
2794+
gap> D := Digraph([[2, 4, 5], [1, 4], [4, 7], [1, 2, 3, 5, 6, 7],
2795+
> [1, 4], [4, 7], [3, 4, 6]]);
2796+
<immutable digraph with 7 vertices, 20 edges>
2797+
gap> VertexConnectivity(D);
2798+
1
2799+
gap> D := Digraph([[2, 4, 5], [1, 3, 4], [4, 7], [1, 2, 3, 5, 6, 7],
2800+
> [1, 4], [4, 7], [3, 4, 6]]);
2801+
<immutable digraph with 7 vertices, 21 edges>
2802+
gap> VertexConnectivity(D);
2803+
2
2804+
gap> D := Digraph([[2, 3], [3, 5], [1, 2, 4], [2, 3], [3]]);
2805+
<immutable digraph with 5 vertices, 10 edges>
2806+
gap> VertexConnectivity(D);
2807+
2
2808+
27772809
# DIGRAPHS_UnbindVariables
27782810
gap> Unbind(adj);
27792811
gap> Unbind(adj1);

0 commit comments

Comments
 (0)