Skip to content
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
40 changes: 40 additions & 0 deletions doc/oper.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1954,6 +1954,46 @@ rec( idom := [ 2, fail, 2, 2, 2 ], preorder := [ 2, 1, 3, 4, 5 ] )
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphDominatingSet">
<ManSection>
<Oper Name="DigraphDominatingSet" Arg="digraph"/>
<Returns>A List</Returns>
<Description>
This creates a dominating set of <A>digraph</A>, which is a subset of the vertices in
<A>digraph</A> such that the neighbourhood of this subset of vertices is equal to all
the vertices in <A>digraph</A>. </P>

The domating set returned will be one of potentially multiple possible dominating sets for the digraph.
<Example><![CDATA[
D := Digraph([[2,3,4], [],[],[]]);;
gap> DigraphDominatingSet(D);
[ 4, 1 ]
gap> DigraphDominatingSet(D);
[ 1 ]]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphGetNeighbourhood">
<ManSection>
<Oper Name="DigraphGetNeighbourhood" Arg="digraph, vertices"/>
<Returns>A List</Returns>
<Description>
This returns the set of vertices that are adjacent to a vertex in <A>vertices</A>,
not including any vertices that exist in <A>vertices</A>.
<Example><![CDATA[
gap> D := Digraph([[2, 3, 4], [1], [], []]);;
gap> DigraphGetNeighbourhood(D, [1]);
[ 2, 3, 4 ]
gap> DigraphGetNeighbourhood(D, [1, 2]);
[ 3, 4 ]
gap> D := Digraph([[2, 3, 4], [], [], []]);;
gap> DigraphGetNeighbourhood(D, [2]);
[ ]]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="PartialOrderDigraphMeetOfVertices">
<ManSection>
<Oper Name="PartialOrderDigraphMeetOfVertices"
Expand Down
25 changes: 25 additions & 0 deletions doc/weights.xml
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,31 @@ gap> Sum(flow[1]);
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphEdgeConnectivity">
<ManSection>
<Attr Name="DigraphEdgeConnectivity" Arg="digraph"/>
<Returns>An integer</Returns>
<Description>
This returns a record representing the edge connectivity of <A>digraph</A>.<P/>

It makes use of <C>DigraphMaximumFlow(<A>digraph</A>)</C>, by constructing an edge-weighted Digraph
with edge weights of 1, then using the Max-flow min-cut theorem to determine the size of the minimum cut.
For a digraph, the minimum cut is the set of edges that need to be removed to ensure the digraph is
no longer Strongly Connected. </P>
<Example><![CDATA[
gap> D := Digraph([[2, 3, 4], [1, 3, 4], [1, 2], [2, 3]]);;
gap> DigraphEdgeConnectivity(D);
2
gap> D := Digraph([[], [1, 2], [2]]);;
gap> DigraphEdgeConnectivity(D);
0
gap> D := Digraph([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]);;
gap> DigraphEdgeConnectivity(D);
4]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="RandomUniqueEdgeWeightedDigraph">
<ManSection>
<Oper Name="RandomUniqueEdgeWeightedDigraph" Arg="[filt, ]n[, p]"/>
Expand Down
2 changes: 2 additions & 0 deletions gap/oper.gd
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ DeclareOperation("IsOrderIdeal", [IsDigraph, IsList]);
DeclareOperation("IsOrderFilter", [IsDigraph, IsList]);
DeclareOperation("Dominators", [IsDigraph, IsPosInt]);
DeclareOperation("DominatorTree", [IsDigraph, IsPosInt]);
DeclareOperation("DigraphDominatingSet", [IsDigraph]);
DeclareOperation("DigraphGetNeighbourhood", [IsDigraph, IsList]);
DeclareOperation("DigraphCycleBasis", [IsDigraph]);

# 10. Operations for vertices . . .
Expand Down
39 changes: 39 additions & 0 deletions gap/oper.gi
Original file line number Diff line number Diff line change
Expand Up @@ -2522,6 +2522,45 @@ function(D, root)
return result;
end);

# For calculating a dominating set for a digraph
# Algorithm 7 in :
# https://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf
InstallMethod(DigraphDominatingSet, "for a digraph",
[IsDigraph],
function(digraph)
local D, neighbourhood, VerticesLeft, Vertices;

Vertices := [1 .. DigraphNrVertices(digraph)];
Shuffle(Vertices);

# Shuffling not technically necessary - may be better to just do D := [1]?
D := [Vertices[1]];
neighbourhood := DigraphGetNeighbourhood(digraph, D);
VerticesLeft := Difference(Vertices, Union(neighbourhood, D));

while not IsEmpty(VerticesLeft) do;
Append(D, [VerticesLeft[1]]);
neighbourhood := DigraphGetNeighbourhood(digraph, D);
VerticesLeft := Difference(Vertices, Union(neighbourhood, D));
od;

return D;
end);

# For getting the neighbourhood for a given List of Vertices in a Digraph
InstallMethod(DigraphGetNeighbourhood, "for a digraph and a List of vertices",
[IsDigraph, IsList],
function(digraph, vertices)
local v, neighbourhood;
neighbourhood := [];
for v in vertices do
neighbourhood := Difference(Union(neighbourhood,
OutNeighbours(digraph)[v]), vertices);
od;

return neighbourhood;
end);

# Computes the fundamental cycle basis of a symmetric digraph
# First, notice that the cycle space is composed of orthogonal subspaces
# corresponding to the cycle spaces of the connected components.
Expand Down
4 changes: 4 additions & 0 deletions gap/weights.gd
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ DeclareGlobalFunction("DIGRAPHS_Edge_Weighted_Dijkstra");
DeclareOperation("DigraphMaximumFlow",
[IsDigraph and HasEdgeWeights, IsPosInt, IsPosInt]);

# Digraph Edge Connectivity
DeclareOperation("DigraphEdgeConnectivity", [IsDigraph]);
DeclareOperation("DigraphEdgeConnectivityDS", [IsDigraph]);

# 6. Random edge weighted digraphs
DeclareOperation("RandomUniqueEdgeWeightedDigraph", [IsPosInt]);
DeclareOperation("RandomUniqueEdgeWeightedDigraph", [IsPosInt, IsFloat]);
Expand Down
205 changes: 205 additions & 0 deletions gap/weights.gi
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,211 @@ function(D, start, destination)
return flows;
end);

#############################################################################
# Digraph Edge Connectivity
#############################################################################

# Algorithms constructed off the algorithms detailed in:
# https://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf
# Each Algorithm uses a different method to decrease the time complexity,
# of calculating Edge Connectivity, though all make use of DigraphMaximumFlow()
# due to the Max-Flow, Min-Cut Theorem

# Algorithm 1: Calculating the Maximum Flow of every possible source and sink
# Algorithm 2: Calculating the Maximum Flow to all sinks of an arbitrary source
# Algorithm 3: Finding Maximum Flow within the non-leaves of a Spanning Tree
# Algorithm 4: Constructing a spanning tree with a high number of leaves
# Algorithm 5: Using the spanning tree^ to find Maximum Flow within non-leaves
# Algorithm 6: Finding Maximum Flow within a dominating set of the digraph
# Algorithm 7: Constructing a dominating set for use in Algorithm 6

# Algorithms 4-7 are used below:

# DigraphEdgeConnectivity calculated using Spanning Trees (Algorithm 4 & 5)
InstallMethod(DigraphEdgeConnectivity, "for a digraph",
[IsDigraph],
function(digraph)
local w, weights, EdgeD, VerticesED, min, u, v,
sum, a, b, st, added, NeighboursV, Edges, notadded,
max, NextVertex, notAddedNeighbours, non_leaf;

if DigraphNrVertices(digraph) = 1 then
return 0;
fi;

if DigraphNrStronglyConnectedComponents(digraph) > 1 then
return 0;
fi;

weights := List([1 .. DigraphNrVertices(digraph)],
x -> List([1 .. Length(OutNeighbours(digraph)[x])],
y -> 1));
EdgeD := EdgeWeightedDigraph(digraph, weights);
VerticesED := [1 .. DigraphNrVertices(EdgeD)];

min := -1;

# Algorithm 4: Constructing a Spanning Tree with a large numbers of leaves

st := EmptyDigraph(DigraphNrVertices(EdgeD));
v := 1;
added := [v];
notadded := Difference(VerticesED, added);

while (DigraphNrEdges(st) < DigraphNrVertices(EdgeD) - 1) and
Length(notadded) > 0 do

# Add all edges incident from v
NeighboursV := Difference(OutNeighbors(EdgeD)[v], added);

Edges := List([1 .. Length(NeighboursV)],
x -> [v, NeighboursV[x]]);

# Edges := Difference(Edges, [[v, v]]);

st := DigraphAddEdges(st, Edges);
Append(added, Difference(OutNeighbours(EdgeD)[v], added));

# Select the neighbour to v with the highest number of not-added neighbours:
notadded := Difference(VerticesED, added);
max := 0;
NextVertex := v;

# Preventing infinite iteration if v has no non-added neighbours
if (Length(NeighboursV) = 0) then
# Pick from a vertex that hasn't been added yet
NextVertex := notadded[1];
fi;

for w in NeighboursV do;
notAddedNeighbours := Intersection(notadded, OutNeighbours(EdgeD)[w]);
if (Length(notAddedNeighbours) > max) then
max := Length(notAddedNeighbours);
NextVertex := w;
fi;
od;

v := NextVertex;

od;

# Algorithm 5: Iterating through the non-leaves of the
# Spanning Tree created in Algorithm 4 to find the Edge Connectivity
non_leaf := [];
for b in VerticesED do
if not IsEmpty(OutNeighbours(st)[b]) then
Append(non_leaf, [b]);
fi;
od;

if (Length(non_leaf) > 1) then
u := non_leaf[1];

for v in [2 .. Length(non_leaf)] do
a := DigraphMaximumFlow(EdgeD, u, non_leaf[v])[u];
b := DigraphMaximumFlow(EdgeD, non_leaf[v], u)[non_leaf[v]];

sum := Minimum(Sum(a), Sum(b));
if (sum < min or min = -1) then
min := sum;
fi;
od;

min := Minimum(min, Minimum(Minimum(OutDegrees(EdgeD)),
Minimum(InDegrees(EdgeD))));
else
# In the case of spanning trees with only one non-leaf node,
# the above algorithm does not work
# Revert to iterating through all vertices of the original digraph

u := 1;
for v in [2 .. DigraphNrVertices(EdgeD)] do
a := DigraphMaximumFlow(EdgeD, u, v)[u];
b := DigraphMaximumFlow(EdgeD, v, u)[v];

sum := Minimum(Sum(a), Sum(b));
if (sum < min or min = -1) then
min := sum;
fi;
od;
fi;

if (min = -1) then
return 0;
fi;

return min;
end);

# Digraph EdgeConnectivity calculated with Dominating Sets (Algorithm 6-7)
InstallMethod(DigraphEdgeConnectivityDS, "for a digraph",
[IsDigraph],
function(digraph)
# Form an identical but edge weighted digraph with all edge weights as 1:
local weights, i, u, v, w, neighbourhood, EdgeD,
maxFlow, min, sum, a, b, V, added, st, non_leaf, max,
notAddedNeighbours, notadded, NextVertex, NeighboursV,
neighbour, Edges, D, VerticesLeft, VerticesED;

if DigraphNrVertices(digraph) = 1 then
return 0;
fi;

if DigraphNrStronglyConnectedComponents(digraph) > 1 then
return 0;
fi;

weights := List([1 .. DigraphNrVertices(digraph)],
x -> List([1 .. Length(OutNeighbours(digraph)[x])],
y -> 1));
EdgeD := EdgeWeightedDigraph(digraph, weights);

min := -1;

# Algorithm 7: Creating a dominating set of the digraph
D := DigraphDominatingSet(digraph);

# Algorithm 6: Using the dominating set created to determine the Maximum Flow

if Length(D) > 1 then

v := D[1];
for i in [2 .. Length(D)] do
w := D[i];
a := DigraphMaximumFlow(EdgeD, v, w)[v];
b := DigraphMaximumFlow(EdgeD, w, v)[w];

sum := Minimum(Sum(a), Sum(b));
if (sum < min or min = -1) then
min := sum;
fi;
od;

else
# If the dominating set of EdgeD is of Length 1,
# the above algorithm will not work
# Revert to iterating through all vertices of the original digraph

u := 1;

for v in [2 .. DigraphNrVertices(EdgeD)] do
a := DigraphMaximumFlow(EdgeD, u, v)[u];
b := DigraphMaximumFlow(EdgeD, v, u)[v];

sum := Minimum(Sum(a), Sum(b));
if (sum < min or min = -1) then
min := sum;
fi;

od;
fi;

return Minimum(min,
Minimum(Minimum(OutDegrees(EdgeD)),
Minimum(InDegrees(EdgeD))));

end);

#############################################################################
# 6. Random edge weighted digraphs
#############################################################################
Expand Down
Loading
Loading