Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add VertexConnectivity #94

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions doc/attr.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2510,6 +2510,42 @@ gap> Length(M);
</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>

<#GAPDoc Label="NonUpperSemimodularPair">
<ManSection>
<Attr Name="NonUpperSemimodularPair" Arg="D"/>
Expand Down
3 changes: 2 additions & 1 deletion doc/z-chap4.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<#Include Label="DegreeMatrix">
<#Include Label="LaplacianMatrix">
</Section>

<Section><Heading>Orders</Heading>
<#Include Label="PartialOrderDigraphMeetOfVertices">
<#Include Label="NonUpperSemimodularPair">
Expand Down Expand Up @@ -83,6 +83,7 @@
<#Include Label="HamiltonianPath">
<#Include Label="NrSpanningTrees">
<#Include Label="DigraphDijkstra">
<#Include Label="VertexConnectivity">
<#Include Label="DigraphCycleBasis">
</Section>

Expand Down
1 change: 1 addition & 0 deletions gap/attr.gd
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
143 changes: 143 additions & 0 deletions gap/attr.gi
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be also possible to compute degs with OutDegrees and InDegrees such that it is maybe shorter and easier to read.


mindegv := 0;
mindeg := DigraphNrVertices(digraph) + 1;
for i in DigraphVertices(digraph) do
if degs[i] < mindeg then
mindeg := degs[i];
mindegv := i;
fi;
od;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think mindegv:=PositionMinimum(degs) and mindeg:=degs[mindegv] should do the same and is an easier computation and easier to read.


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
Expand Down
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(_, 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
38 changes: 38 additions & 0 deletions tst/standard/attr.tst
Original file line number Diff line number Diff line change
Expand Up @@ -2794,6 +2794,44 @@ 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
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?");
<immutable digraph with 4 vertices, 5 edges>
Expand Down
Loading