Skip to content
Open
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
34 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
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
28 changes: 28 additions & 0 deletions doc/weights.xml
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,34 @@ 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 returns a list of two lists representing the components of
a minimal s-t cut set of <A>digraph</A>. <P/>

An <E>s-t cut set</E> is a partition of the vertices [S, T] such that s is in S and
t is in T. The <E>capacity</E> of an s-t cut set is the sum of the weights of every
edge whose source is in S and whose range is in T. A minimum s-t cut set is an s-t
cut set whose capacity is minimal.<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 multidigraph with 3 vertices, 3 edges>
gap> DigraphMinimumCutSet(g, 1, 3);
[ [ 2, 1 ], [3]]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="RandomUniqueEdgeWeightedDigraph">
<ManSection>
<Oper Name="RandomUniqueEdgeWeightedDigraph" Arg="[filt, ]n[, p]"/>
Expand Down
4 changes: 3 additions & 1 deletion gap/weights.gd
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ 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("DigraphMinimumCutSet",
[IsDigraph and HasEdgeWeights, IsPosInt, IsPosInt]);

# 6. Random edge weighted digraphs
DeclareOperation("RandomUniqueEdgeWeightedDigraph", [IsPosInt]);
Expand Down
50 changes: 49 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,54 @@ function(D, start, destination)
return flows;
end);

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

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

# Check input
if not s in vertices then
ErrorNoReturn("<s> must be a vertex of <D>,");
elif not t in 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;

# Construct the digraph containing all edges with nonzero
# residual capacity
G := [];
for u in [1 .. Length(outs)] do
o := [];
for v in [1 .. Length(outs[u])] do
if residuals[u][v] > 0 then
Add(o, outs[u][v]);
fi;
od;
Add(G, o);
od;

G := Digraph(G);

# Find all vertices reachable from the source in this digraph
# This gives the minimal cut set by the max-flow min-cut theorem
S := Filtered(vertices, x -> IsReachable(G, s, x));
if not s in S then
Add(S, s);
fi;
T := Difference(vertices, S);
return [S, T];
end);

#############################################################################
# 6. Random edge weighted digraphs
#############################################################################
Expand Down
76 changes: 75 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,80 @@ 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 set: empty digraphs
gap> d := EdgeWeightedDigraph([], []);
<immutable empty digraph with 0 vertices>
gap> DigraphMinimumCutSet(d, 1, 1);
Error, <s> must be a vertex of <D>,

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

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

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

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

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

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

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

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

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

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

# Minimum cut set: 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> DigraphMinimumCutSet(gr, 5, 6);
[ [ 1, 2, 5 ], [ 3, 4, 6 ] ]

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