Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
9d1c20d
Change to GAP stable-4.14 in CI
frankiegillis Feb 5, 2025
1ff11a2
Merge branch 'digraphs:main' into main
frankiegillis Feb 25, 2025
00fe48c
Merge branch 'digraphs:main' into main
frankiegillis Feb 26, 2025
7932db5
Merge branch 'main' of github.com:digraphs/Digraphs into HEAD
frankiegillis Feb 26, 2025
4cc0df5
Add HasPseudoSimilarVertices no docs
frankiegillis Mar 2, 2025
f05eaf3
Fixed syntax
frankiegillis Mar 2, 2025
5c5f5e8
fixed syntax
frankiegillis Mar 2, 2025
81a7065
Add HasPSVs
frankiegillis Mar 26, 2025
d3dac89
Is2EdgeTransitive overhaul using Orbit-Stabiliser Theorem
frankiegillis Mar 26, 2025
51a3664
Added support for digraphs with loops
frankiegillis Mar 26, 2025
c9f28ef
Linting
frankiegillis Mar 26, 2025
35033ec
More linting
frankiegillis Mar 26, 2025
02a088c
Edited Documentation
frankiegillis Mar 26, 2025
e1eb03e
Edited Documentation again
frankiegillis Mar 26, 2025
b088fa8
Merge branch 'main' of github.com:digraphs/Digraphs into Is2EdgeTrans…
frankiegillis Apr 7, 2025
4415aa0
Merge branch 'main' of github.com:digraphs/Digraphs into Is2EdgeTrans…
frankiegillis Apr 21, 2025
bc3d557
Once more rewritten Is2EdgeTransitive, this time to avoid looping thr…
frankiegillis Apr 26, 2025
e62fc7e
lint
frankiegillis Apr 26, 2025
1414081
Added more comments to prop.gi
frankiegillis Apr 26, 2025
733cc5f
Fix trailing whitespace
frankiegillis Apr 26, 2025
5ef192f
Added IsTwoEdgeTransitive as synonym for Is2EdgeTransitive
frankiegillis Sep 24, 2025
2964fab
Merge branch 'main' of github.com:digraphs/Digraphs into Is2EdgeTrans…
frankiegillis Sep 24, 2025
851b036
lint
frankiegillis Sep 24, 2025
d3dfdcd
Removed spurious files and added what happens when the argument of Is…
frankiegillis Sep 25, 2025
73afcc5
fixed typo in doc
frankiegillis Sep 25, 2025
6c6ab19
Added new Is2EdgeTransitive draft without bug
frankiegillis Oct 30, 2025
a136f62
back to original
frankiegillis Oct 30, 2025
dfa8fa9
Added DigraphMinimumCut
frankiegillis Oct 30, 2025
4e4b80e
Some nonsense happening in prop
frankiegillis Oct 30, 2025
81e49ee
renamed DigraphMinimumCut to DigraphMinimumCutSet
frankiegillis Oct 31, 2025
272d230
lint
frankiegillis Nov 1, 2025
7e9bd13
Merge branch 'main' of github.com:digraphs/Digraphs into DigraphMinim…
frankiegillis Nov 5, 2025
5e8e5bf
Improved function and updated doc
frankiegillis Nov 19, 2025
7e20645
minor optimisations
frankiegillis Dec 3, 2025
fb325a0
fixed tests
frankiegillis Dec 3, 2025
733cfa7
fix typo
frankiegillis Dec 3, 2025
278e1fd
fix typo in doc
frankiegillis Dec 3, 2025
3685e8f
Added additional tests
frankiegillis Dec 3, 2025
25a4ee0
Very minor nit in docs.
reiniscirpons Dec 4, 2025
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
58 changes: 58 additions & 0 deletions doc/weights.xml
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,64 @@ gap> Sum(flow[1]);
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphMinimumCut">
<ManSection>
<Attr Name="DigraphMinimumCut" Arg="digraph, s, t"/>
<Returns>A list of lists of integers.</Returns>
<Description>
If <A>digraph</A> is an edge-weighted digraph with distinct vertices <A>s</A>
and <A>t</A>, this function returns a list of two lists representing the
components of the minimum <M>s</M>-<M>t</M> cut of <A>digraph</A>. <P/>

An <E><M>s</M>-<M>t</M> cut</E> is a partition of the vertices <M>\{ S, T \}</M>
such that <A>s</A> is in <M>S</M> and <A>t</A> is in <M>T</M>. The <E>capacity</E>
of an <M>s</M>-<M>t</M> cut is the sum of the weights of every edge whose source
is in <M>S</M> and whose range is in <M>T</M>. The minimum <M>s</M>-<M>t</M> cut is
the <M>s</M>-<M>t</M> cut whose capacity is the smallest possible.<P/>

This attribute is computed by using <Ref Func="DigraphMaximumFlow"/> and the
max-cut min-flow theorem.<P/>

See <Ref Attr="EdgeWeights" Func="EdgeWeightedDigraph"/>.
<Example><![CDATA[
gap> g := EdgeWeightedDigraph([[2, 2], [3], []], [[3, 2], [1], []]);
<immutable edge-weighted multidigraph with 3 vertices, 3 edges>
gap> DigraphMinimumCut(g, 1, 3);
[ [ 1, 2 ], [3] ]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphMinimumCutSet">
<ManSection>
<Attr Name="DigraphMinimumCutSet" Arg="digraph, s, t"/>
<Returns>A list of lists integers.</Returns>
<Description>
If <A>digraph</A> is an edge-weighted digraph with distinct vertices <A>s</A>
and <A>t</A>, this function returns a list of lists of integers representing the
minimum <M>s</M>-<M>t</M> cut of <A>digraph</A>. <P/>

An <E><M>s</M>-<M>t</M> cut</E> is a partition of the vertices <M>\{ S, T \}</M>
such that <A>s</A> is in <M>S</M> and <A>t</A> is in <M>T</M>. The <E>cut set</E>
corresponding to this cut is the set of edges whose source is in <M>S</M> and
whose range is in <M>T</M>. The minimum <M>s</M>-<M>t</M> cut set is
the <M>s</M>-<M>t</M> cut set such that the sum of the weights of the edges in
the cut set is the smallest possible.<P/>

This attribute is computed by using <Ref Func="DigraphMinimumCut"/>.<P/>

See <Ref Attr="EdgeWeights" Func="EdgeWeightedDigraph"/>.
<Example><![CDATA[
gap> g := EdgeWeightedDigraph([[2, 2], [3], []], [[3, 2], [1], []]);
<immutable edge-weighted multidigraph with 3 vertices, 3 edges>
gap> DigraphMinimumCutSet(g, 1, 3);
[ [ 2, 3 ] ]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="RandomUniqueEdgeWeightedDigraph">
<ManSection>
<Oper Name="RandomUniqueEdgeWeightedDigraph" Arg="[filt, ]n[, p]"/>
Expand Down
2 changes: 2 additions & 0 deletions doc/z-chap5.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
<#Include Label="EdgeWeightedDigraphShortestPaths">
<#Include Label="EdgeWeightedDigraphShortestPath">
<#Include Label="DigraphMaximumFlow">
<#Include Label="DigraphMinimumCut">
<#Include Label="DigraphMinimumCutSet">
<#Include Label="RandomUniqueEdgeWeightedDigraph">
</Section>

Expand Down
6 changes: 5 additions & 1 deletion gap/weights.gd
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,13 @@ DeclareGlobalFunction("DIGRAPHS_Edge_Weighted_FloydWarshall");
DeclareGlobalFunction("DIGRAPHS_Edge_Weighted_Bellman_Ford");
DeclareGlobalFunction("DIGRAPHS_Edge_Weighted_Dijkstra");

# 5. Maximum Flow
# 5. Maximum Flow and Minimum Cut
DeclareOperation("DigraphMaximumFlow",
[IsDigraph and HasEdgeWeights, IsPosInt, IsPosInt]);
DeclareOperation("DigraphMinimumCut",
[IsDigraph and HasEdgeWeights, IsPosInt, IsPosInt]);
DeclareOperation("DigraphMinimumCutSet",
[IsDigraph and HasEdgeWeights, IsPosInt, IsPosInt]);

# 6. Random edge weighted digraphs
DeclareOperation("RandomUniqueEdgeWeightedDigraph", [IsPosInt]);
Expand Down
83 changes: 82 additions & 1 deletion gap/weights.gi
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ function(D, source)
end);

#############################################################################
# 5. Maximum Flow
# 5. Maximum Flow and Minimum Cut
#############################################################################

InstallMethod(DigraphMaximumFlow, "for an edge weighted digraph",
Expand Down Expand Up @@ -772,6 +772,87 @@ function(D, start, destination)
return flows;
end);

InstallMethod(DigraphMinimumCut, "for an edge weighted digraph",
[IsDigraph and HasEdgeWeights, IsPosInt, IsPosInt],
function(D, s, t)
local weights, outs, vertices, flow, residuals, u, v, S, T, seen, i;

# Extract important data
weights := EdgeWeights(D);
outs := OutNeighbours(D);
vertices := DigraphVertices(D);

# Check input
if s < 1 or s > Length(vertices) then
ErrorNoReturn("<s> must be a vertex of <D>,");
elif t < 1 or t > Length(vertices) then
ErrorNoReturn("<t> must be a vertex of <D>,");
elif s = t then
ErrorNoReturn("<s> and <t> must be distinct");
fi;

# Find the residual edge capacities under the maximum flow
flow := DigraphMaximumFlow(D, s, t);
residuals := weights - flow;

# Carry out a BFS to find all the vertices in the residual
# network which are reachable from s. This gives the minimum
# cut by the max-flow min-cut theorem.

S := [s];
seen := BlistList(DigraphVertices(D), [s]);
i := 1;
while i <= Length(S) do
u := S[i];
i := i + 1;
for v in [1 .. Length(outs[u])] do
if residuals[u][v] > 0 then
if not seen[outs[u][v]] then
Add(S, outs[u][v]);
seen[outs[u][v]] := true;
fi;
fi;
od;
od;

T := Difference(vertices, S);
return [S, T];
end);

InstallMethod(DigraphMinimumCutSet, "for an edge weighted digraph",
[IsDigraph and HasEdgeWeights, IsPosInt, IsPosInt],
function(D, s, t)
local cut, cutset, u, v, S, T;

# Check input
if s < 1 or s > DigraphNrVertices(D) then
ErrorNoReturn("<s> must be a vertex of <D>,");
elif t < 1 or t > DigraphNrVertices(D) then
ErrorNoReturn("<t> must be a vertex of <D>,");
elif s = t then
ErrorNoReturn("<s> and <t> must be distinct");
fi;

# Get the minimum cut

cut := DigraphMinimumCut(D, s, t);
S := cut[1];
T := cut[2];

# Compute the cut-set corresponding to the minimum cut

cutset := [];
for u in S do
for v in OutNeighbours(D)[u] do
if v in T then
Add(cutset, [u, v]);
fi;
od;
od;

return cutset;
end);

#############################################################################
# 6. Random edge weighted digraphs
#############################################################################
Expand Down
106 changes: 105 additions & 1 deletion tst/standard/weights.tst
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ gap> EdgeWeightedDigraphShortestPath(d, 1, 3);
[ [ 1, 2, 3 ], [ 1, 1 ] ]

#############################################################################
# 5. Maximum Flow
# 5. Maximum Flow and Minimum Cut
#############################################################################

# Maximum flow: empty digraphs
Expand Down Expand Up @@ -368,6 +368,110 @@ gap> gr := EdgeWeightedDigraph([[2], [3, 6], [4], [1, 6], [1, 3], []],
gap> DigraphMaximumFlow(gr, 5, 6);
[ [ 10 ], [ 3, 7 ], [ 7 ], [ 0, 7 ], [ 10, 4 ], [ ] ]

# Minimum cut: empty digraphs
gap> d := EdgeWeightedDigraph([], []);
<immutable empty edge-weighted digraph with 0 vertices>
gap> DigraphMinimumCut(d, 1, 1);
Error, <s> must be a vertex of <D>,

# Minimum cut: single vertex (also empty digraphs)
gap> d := EdgeWeightedDigraph([[]], [[]]);
<immutable empty edge-weighted digraph with 1 vertex>
gap> DigraphMinimumCut(d, 1, 1);
Error, <s> and <t> must be distinct

# Minimum cut: source = dest
gap> d := EdgeWeightedDigraph([[2], []], [[5], []]);
<immutable edge-weighted digraph with 2 vertices, 1 edge>
gap> DigraphMinimumCut(d, 1, 1);
Error, <s> and <t> must be distinct

# Minimum cut: has loop
gap> d := EdgeWeightedDigraph([[1, 2], []], [[5, 10], []]);
<immutable edge-weighted digraph with 2 vertices, 2 edges>
gap> DigraphMinimumCut(d, 1, 2);
[ [ 1 ], [ 2 ] ]

# Minimum cut: invalid source
gap> d := EdgeWeightedDigraph([[1, 2], []], [[5, 10], []]);
<immutable edge-weighted digraph with 2 vertices, 2 edges>
gap> DigraphMinimumCut(d, 5, 2);
Error, <s> must be a vertex of <D>,

# Minimum cut: invalid sink
gap> d := EdgeWeightedDigraph([[1, 2], []], [[5, 10], []]);
<immutable edge-weighted digraph with 2 vertices, 2 edges>
gap> DigraphMinimumCut(d, 1, 5);
Error, <t> must be a vertex of <D>,

# Minimum cut: sink not reachable
gap> d := EdgeWeightedDigraph([[1], []], [[5], []]);
<immutable edge-weighted digraph with 2 vertices, 1 edge>
gap> DigraphMinimumCut(d, 1, 2);
[ [ 1 ], [ 2 ] ]

# Minimum cut: source has in neighbours
gap> d := EdgeWeightedDigraph([[2], [3], []], [[5], [10], []]);
<immutable edge-weighted digraph with 3 vertices, 2 edges>
gap> DigraphMinimumCut(d, 2, 3);
[ [ 2 ], [ 1, 3 ] ]

# Minimum cut: sink has out-neighbours
gap> d := EdgeWeightedDigraph([[2], [3], [2]], [[5], [10], [7]]);
<immutable edge-weighted digraph with 3 vertices, 3 edges>
gap> DigraphMinimumCut(d, 2, 3);
[ [ 2 ], [ 1, 3 ] ]

# Minimum cut: cycle
gap> d := EdgeWeightedDigraph([[2], [3], [1]], [[5], [10], [7]]);
<immutable edge-weighted digraph with 3 vertices, 3 edges>
gap> DigraphMinimumCut(d, 1, 3);
[ [ 1 ], [ 2, 3 ] ]

# Minimum cut: example from Wikipedia
gap> gr := EdgeWeightedDigraph([[3, 4], [], [2, 4], [2]],
> [[10, 5], [], [5, 15], [10]]);;
gap> DigraphMinimumCut(gr, 1, 2);
[ [ 1 ], [ 2, 3, 4 ] ]
gap> DigraphMinimumCut(gr, 3, 2);
[ [ 3, 4 ], [ 1, 2 ] ]

# Minimum cut: example from Wikipedia article on Push-label maximum flow
gap> gr := EdgeWeightedDigraph([[2], [3, 6], [4], [1, 6], [1, 3], []],
> [[12], [3, 7], [10], [5, 10], [15, 4], []]);;
gap> DigraphMinimumCut(gr, 5, 6);
[ [ 5, 1, 2 ], [ 3, 4, 6 ] ]

# Minimum cut set: empty digraphs
gap> d := EdgeWeightedDigraph([], []);
<immutable empty edge-weighted digraph with 0 vertices>
gap> DigraphMinimumCutSet(d, 1, 1);
Error, <s> must be a vertex of <D>,

# Minimum cut set: source has in neighbours
gap> d := EdgeWeightedDigraph([[2], [3], []], [[5], [10], []]);
<immutable edge-weighted digraph with 3 vertices, 2 edges>
gap> DigraphMinimumCutSet(d, 2, 3);
[ [ 2, 3 ] ]

# Minimum cut set: cycle
gap> d := EdgeWeightedDigraph([[2], [3], [1]], [[5], [10], [7]]);
<immutable edge-weighted digraph with 3 vertices, 3 edges>
gap> DigraphMinimumCutSet(d, 1, 3);
[ [ 1, 2 ] ]

# Minimum cut set: invalid sink
gap> d := EdgeWeightedDigraph([[1, 2], []], [[5, 10], []]);
<immutable edge-weighted digraph with 2 vertices, 2 edges>
gap> DigraphMinimumCutSet(d, 1, 5);
Error, <t> must be a vertex of <D>,

# Minimum cut set: source = dest
gap> d := EdgeWeightedDigraph([[2], []], [[5], []]);
<immutable edge-weighted digraph with 2 vertices, 1 edge>
gap> DigraphMinimumCutSet(d, 1, 1);
Error, <s> and <t> must be distinct

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