Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
90a9a89
Added SwapDigraphs and DigraphsRemoveAllEdges functions
rm387 Oct 1, 2025
3027792
Fixed gaplint errors
rm387 Oct 1, 2025
300ebc5
Changes made to SwapDigraphs and DigraphRemoveAllEdges
rm387 Oct 6, 2025
72e68c4
Changes made to DigraphRemoveAllEdges
rm387 Oct 8, 2025
e697fa4
More changes made to DigraphRemoveAllEdges
rm387 Oct 8, 2025
15a5150
DigraphEdgeConnectivity and additional functions (Dominating Set func…
rm387 Nov 19, 2025
05f99d5
Added explanations for each Algorithm and edited gapdocs + tests for …
rm387 Nov 21, 2025
57c908e
Minor gaplint/test changes made
rm387 Nov 26, 2025
60505dc
Added DigraphEdgeConnectivityDS tests to weights.tst
rm387 Nov 29, 2025
e1bbe0c
Added tests for DigraphDominatingSet()
rm387 Nov 29, 2025
4205ed0
Fixes made to Spanning Tree Algorithm + tests added to weights.tst
rm387 Dec 1, 2025
531fc71
Tests added to testinstall.tst for DigraphEdgeConnectivityDS()
rm387 Dec 3, 2025
75ac98a
Removing Spanning Tree Algorithm
rm387 Dec 3, 2025
c3645ab
Documentation changes + some DigraphsDominatingSet implementation cha…
rm387 Dec 10, 2025
bcf23b8
Removing DigraphsOutNeighbourhood
rm387 Dec 10, 2025
dfec296
Changing DigraphEdgeConnectivity and associated tests to work only fo…
rm387 Jan 28, 2026
37a044e
Move EdgeConnectivity to attr
reiniscirpons May 28, 2026
acc9c0d
Small formatting fixes etc
reiniscirpons May 28, 2026
35128b6
Improve wording a little
reiniscirpons May 28, 2026
a167c36
Factor out dominating set and add it as attr
reiniscirpons Aug 26, 2026
94f52e1
Finish adding tests for dominating set
reiniscirpons Sep 9, 2026
47be251
Add more tests for EdgeConnectivity, fix mutability bug
reiniscirpons Sep 23, 2026
06e5fdf
Add docs
reiniscirpons Sep 23, 2026
38b4803
Fix minor issue with testinstall
reiniscirpons Sep 23, 2026
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
75 changes: 75 additions & 0 deletions doc/attr.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2702,6 +2702,47 @@ gap> Length(M);
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="AttrDigraphGreedyOutDominatingSet">
<ManSection>
<Attr Name="DigraphGreedyOutDominatingSet" Arg="digraph"/>
<Attr Name="DigraphGreedyInDominatingSet" Arg="digraph"/>
<Returns>A list of positive integers</Returns>
<Description>
<C>DigraphGreedyOutDominatingSet</C> returns the unique <E>greedy
out-dominating set</E> of <A>digraph</A> with respect to the ordering
<M>1 &lt; 2 &lt; ... &lt; n</M> where <M>n</M> is the number of vertices in
<A>digraph</A>. An <E>out-dominating set</E> is a subset <M>S</M> of
vertices of <A>digraph</A> such that every vertex of <A>digraph</A> is
either in <M>S</M> or an out-neighbour of a vertex in <M>S</M>. Such a
set is <E>greedy</E>, if it is obtained by starting with an empty set
<M>S</M> and repeatedly adding to <M>S</M> the least vertex that is not
in <M>S</M> and not and out-neighbour of <M>S</M>.

See also <Ref Oper="IsDigraphOutDominatingSet"/> for a further

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
See also <Ref Oper="IsDigraphOutDominatingSet"/> for a further
See also <Ref Oper="IsDigraphOutDominatingSet"/> for further

information on dominating sets, and <Ref
Oper="DigraphGreedyOutDominatingSet"/> for a version of this function
that finds a greedy out-dominating set with respect to an arbitrary
ordering on vertices.

Similarly, <C>DigraphGreedyInDominatingSet</C> returns the unique <E>greedy
in-dominating set</E> of <A>digraph</A> with respect to the ordering
<M>1 &lt; 2 &lt; ... &lt; n</M> where <M>n</M> is the number of vertices in
<A>digraph</A>. This is equivalently the greedy out-dominating set of
the <Ref Attr="DigraphDual"/> of <A>digraph</A>.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
the <Ref Attr="DigraphDual"/> of <A>digraph</A>.
the <Ref Attr="DigraphReverse"/> of <A>digraph</A>.

The dual is the graph where every non-edge becomes an edge and vice versa, do you mean the reverse?


See also <Ref Oper="IsDigraphInDominatingSet"/> and <Ref
Oper="DigraphGreedyInDominatingSet"/>.
<Example><![CDATA[
gap> D := Digraph([[2, 4], [3], [1, 5], [3], [4]]);;
gap> A := DigraphGreedyOutDominatingSet(D);
[ 1, 3 ]
gap> A := DigraphGreedyInDominatingSet(D);
[ 1, 2, 4 ]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="DigraphVertexConnectivity">
<ManSection>
<Attr Name="DigraphVertexConnectivity" Arg="digraph"/>
Expand Down Expand Up @@ -2777,6 +2818,40 @@ gap> DigraphVertexConnectivity(CompleteDigraph(5));
</ManSection>
<#/GAPDoc>

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

The edge connectivity of a symmetric digraph is the size <M>k</M> of the
smallest set of edges whose removal would make the digraph disconnected
(in the sense of <Ref Prop="IsConnectedDigraph"/>).<P/>

The implementation makes use of the
<C>DigraphMaximumFlow(<A>digraph</A>)</C> function, assuming each edge has
weight 1, then using the max-flow min-cut theorem to determine the size of
the minimum cut. See also <Ref Attr="DigraphMaximumFlow"/>.<P/>

The edge connectivity of any symmetric bridgeless digraph is at least 2.
See also <Ref Prop="IsBridgelessDigraph"/>.
<Example><![CDATA[
gap> d := Digraph([[4], [4], [4], [1, 2, 3]]);;
gap> DigraphEdgeConnectivity(d);
1
gap> D := RandomDigraph(1);;
gap> DigraphEdgeConnectivity(D);
0
gap> d := Digraph([[2, 3], [1, 4], [1, 4], [2, 3]]);;
gap> DigraphEdgeConnectivity(d);
2
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="NonUpperSemimodularPair">
<ManSection>
<Attr Name="NonUpperSemimodularPair" Arg="D"/>
Expand Down
86 changes: 86 additions & 0 deletions doc/oper.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1954,6 +1954,92 @@ rec( idom := [ 2, fail, 2, 2, 2 ], preorder := [ 2, 1, 3, 4, 5 ] )
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="IsDigraphOutDominatingSet">
<ManSection>
<Oper Name="IsDigraphOutDominatingSet" Arg="digraph, list"/>
<Oper Name="IsDigraphInDominatingSet" Arg="digraph, list"/>
<Returns><K>true</K> or <K>false</K>.</Returns>
<Description>
If <A>digraph</A> is a digraph and <A>list</A> is a strictly sorted list of
vertices of <A>digraph</A>, then <C>IsDigraphOutDominatingSet</C>
returns <K>true</K> if <A>list</A> is an out-dominating set of <A>digraph</A>.
Similarly, the operation <C>IsDigraphInDominatingSet</C> returns <K>true</K>
if <A>list</A> is an in-dominating set of <A>digraph</A>.
Otherwise, each of these operations return <K>false</K>.
<P/>

An <E>out-dominating set</E> of <A>digraph</A> is a subset <M>S</M> of
vertices of <A>digraph</A> such that every vertex of <A>digraph</A> is
either in <M>S</M> or an out-neighbour of a vertex in <M>S</M>.
An <E>in-dominating set</E> of <A>digraph</A> is a subset <M>S</M> of
vertices of <A>digraph</A> such that every vertex of <A>digraph</A> is
either in <M>S</M> or an in-neighbour of a vertex in <M>S</M>.

<Example><![CDATA[
gap> D := Digraph([[2, 4], [3], [1, 5], [3], [4]]);;
gap> IsDigraphOutDominatingSet(D, [1, 3]);
true
gap> IsDigraphOutDominatingSet(D, [1, 3, 5]);
true
gap> IsDigraphOutDominatingSet(D, [3, 5]);
false
gap> IsDigraphOutDominatingSet(D, [3, 1, 5, 2, 4]);
false
gap> IsDigraphInDominatingSet(D, [3, 4]);
true
gap> IsDigraphInDominatingSet(D, [1, 3, 5]);
true
gap> IsDigraphInDominatingSet(D, [3, 5]);
false
gap> IsDigraphInDominatingSet(D, [3, 1, 5, 2, 4]);
false
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="OperDigraphGreedyOutDominatingSet">
<ManSection>
<Oper Name="DigraphGreedyOutDominatingSet" Arg="digraph, order"/>
<Oper Name="DigraphGreedyInDominatingSet" Arg="digraph, order"/>
<Returns>A list of positive integers</Returns>
<Description>
<C>DigraphGreedyOutDominatingSet</C> returns the unique <E>greedy
out-dominating set</E> of <A>digraph</A> with respect to the ordering
that the list <A>order</A> induced on the vertices in
<A>digraph</A>. An <E>out-dominating set</E> is a subset <M>S</M> of
vertices of <A>digraph</A> such that every vertex of <A>digraph</A> is
either in <M>S</M> or an out-neighbour of a vertex in <M>S</M>. Such a
set is <E>greedy</E>, if it is obtained by starting with an empty set
<M>S</M> and repeatedly adding to <M>S</M> the least (with respect to the
ordering <A>order</A>) vertex that is not in <M>S</M> and not and
out-neighbour of <M>S</M>.

See also <Ref Oper="IsDigraphOutDominatingSet"/> for a further

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
See also <Ref Oper="IsDigraphOutDominatingSet"/> for a further
See also <Ref Oper="IsDigraphOutDominatingSet"/> for further

information on dominating sets, and <Ref
Attr="DigraphGreedyOutDominatingSet"/> for the attribute version of this
function that finds a greedy out-dominating set with respect to the
ordering <M>1 &lt; 2 &lt; ... &lt; n </M> on the vertices of <A>digraph</A>.

Similarly, <C>DigraphGreedyInDominatingSet</C> returns the unique <E>greedy
in-dominating set</E> of <A>digraph</A> with respect to the ordering
that the list <A>order</A> induces on the vertices in
<A>digraph</A>. This is equivalently the greedy out-dominating set of
the <Ref Attr="DigraphDual"/> of <A>digraph</A>.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
the <Ref Attr="DigraphDual"/> of <A>digraph</A>.
the <Ref Attr="DigraphReverse"/> of <A>digraph</A>.

Same comment as above.


See also <Ref Oper="IsDigraphInDominatingSet"/> and <Ref
Attr="DigraphGreedyInDominatingSet"/>.
<Example><![CDATA[
gap> D := Digraph([[2, 4], [3], [1, 5], [3], [4]]);;
gap> DigraphGreedyOutDominatingSet(D, [2, 1, 3, 4, 5]);
[ 1, 2, 5 ]
gap> DigraphGreedyInDominatingSet(D, [5, 1, 3, 4, 2]);
[ 1, 2, 4, 5 ]
]]></Example>
</Description>
</ManSection>
<#/GAPDoc>

<#GAPDoc Label="PartialOrderDigraphMeetOfVertices">
<ManSection>
<Oper Name="PartialOrderDigraphMeetOfVertices"
Expand Down
1 change: 1 addition & 0 deletions doc/weights.xml
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ gap> DigraphMinimumCutSet(g, 1, 3);
</ManSection>
<#/GAPDoc>


Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change

No change required in this file.

<#GAPDoc Label="RandomUniqueEdgeWeightedDigraph">
<ManSection>
<Oper Name="RandomUniqueEdgeWeightedDigraph" Arg="[filt, ]n[, p]"/>
Expand Down
4 changes: 4 additions & 0 deletions doc/z-chap4.xml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@
<#Include Label="DigraphAbsorptionExpectedSteps">
<#Include Label="Dominators">
<#Include Label="DominatorTree">
<#Include Label="IsDigraphOutDominatingSet">
<#Include Label="AttrDigraphGreedyOutDominatingSet">
<#Include Label="OperDigraphGreedyOutDominatingSet">
<#Include Label="IteratorOfPaths">
<#Include Label="DigraphAllSimpleCircuits">
<#Include Label="DigraphLongestSimpleCircuit">
Expand All @@ -89,6 +92,7 @@
<#Include Label="NrSpanningTrees">
<#Include Label="DigraphDijkstra">
<#Include Label="DigraphVertexConnectivity">
<#Include Label="DigraphEdgeConnectivity">
<#Include Label="DigraphCycleBasis">
<#Include Label="DigraphIsKing">
<#Include Label="DigraphKings">
Expand Down
4 changes: 4 additions & 0 deletions gap/attr.gd
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ DeclareAttribute("DigraphCore", IsDigraph);
DeclareAttribute("CharacteristicPolynomial", IsDigraph);
DeclareAttribute("NrSpanningTrees", IsDigraph);
DeclareAttribute("DigraphVertexConnectivity", IsDigraph);
DeclareAttribute("DigraphEdgeConnectivity", IsDigraph);

# AsGraph must be mutable for grape to function properly
DeclareAttribute("AsGraph", IsDigraph, "mutable");
Expand Down Expand Up @@ -135,6 +136,9 @@ DeclareAttribute("DigraphMaximumMatching", IsDigraph);
DeclareAttribute("Bridges", IsDigraph);
DeclareAttributeThatReturnsDigraph("StrongOrientation", IsDigraph);

DeclareAttribute("DigraphGreedyOutDominatingSet", IsDigraph);
DeclareAttribute("DigraphGreedyInDominatingSet", IsDigraph);

DeclareAttribute("NonUpperSemimodularPair", IsDigraph);
DeclareAttribute("NonLowerSemimodularPair", IsDigraph);

Expand Down
143 changes: 143 additions & 0 deletions gap/attr.gi
Original file line number Diff line number Diff line change
Expand Up @@ -3504,6 +3504,149 @@ function(D)
return kappa_min;
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

# This function computes the greedy dominating set for the subdigraph
# of a digraph induced by a set of vertices. The neighbour_fun function
# determines if in or out-edges are used. Pass OutNeighboursOfVertex
# for out-edges and InNeighboursOfVertex for in-edges.
#
# In other words, we find a subset S of the vertices in the parameter
# vertices such that every vertex in vertices is in S or adjacent
# to a vertex in S.
#
# This is done in a greedy manner by including every vertex in

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is probably not important, but can you possibly reflow this comment, the line breaks look weird to me.

# vertices in order, if it is not already adjacent to some
# vertex in the current dominating set. The vertices are
# processed in the same order as they occur in the
# parameter vertices.
#
# Implements Algorithm 7 in :
# https://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf
BindGlobal("DIGRAPHS_GreedyDominatingSet",
function(digraph, vertices, neighbour_fun)
local S, seen, neighbour, vertex;

Assert(1,
neighbour_fun = OutNeighboursOfVertex or
neighbour_fun = InNeighboursOfVertex);

seen := BlistList(DigraphVertices(digraph), []);
S := [];
for vertex in vertices do
if not seen[vertex] then
seen[vertex] := true;
Add(S, vertex);
for neighbour in neighbour_fun(digraph, vertex) do
seen[neighbour] := true;
od;
fi;
od;

return S;
end);

InstallMethod(DigraphGreedyOutDominatingSet, "for a digraph", [IsDigraph],
digraph ->
DIGRAPHS_GreedyDominatingSet(
digraph,
DigraphVertices(digraph),
OutNeighboursOfVertex));

InstallMethod(DigraphGreedyInDominatingSet, "for a digraph", [IsDigraph],
digraph ->
DIGRAPHS_GreedyDominatingSet(
digraph,
DigraphVertices(digraph),
InNeighboursOfVertex));
# Algorithms 4-7 are used below:

# Digraph EdgeConnectivity calculated with Dominating Sets (Algorithm 6-7)
InstallMethod(DigraphEdgeConnectivity, "for a symmetric 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;

# check for symmetric digraph
if not IsSymmetricDigraph(digraph) then
ErrorNoReturn("the argument <digraph> must be a symmetric digraph,");
fi;

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

EdgeD := UnitEdgeWeightedDigraph(DigraphImmutableCopyIfMutable(digraph));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Move this line down to just before if Length(D) > 1 then no point in doing this here, again a minor point.


min := -1;

# Algorithm 7: Creating a dominating set of the digraph
D := DIGRAPHS_GreedyDominatingSet(
digraph,
Shuffle([1 .. DigraphNrVertices(digraph)]),
OutNeighboursOfVertex);

# 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)),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Minimum is associative, no? So this could just be Minimum(min, Minimum(OutDegrees(EdgeD)), Minimum(InDegrees(EdgeD)), right?

Minimum(InDegrees(EdgeD))));
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
6 changes: 6 additions & 0 deletions gap/oper.gd
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ DeclareOperation("IsDigraphPath",
[IsDigraph, IsHomogeneousList, IsHomogeneousList]);
DeclareOperation("IsDigraphPath", [IsDigraph, IsList]);

DeclareOperation("IsDigraphOutDominatingSet", [IsDigraph, IsList]);
DeclareSynonym("IsDigraphDominatingSet", IsDigraphOutDominatingSet);
DeclareOperation("IsDigraphInDominatingSet", [IsDigraph, IsList]);

# 9. Connectivity . . .
DeclareOperation("DigraphIsKing", [IsDigraph, IsPosInt, IsPosInt]);
DeclareOperation("DigraphKings", [IsDigraph, IsPosInt]);
Expand Down Expand Up @@ -154,6 +158,8 @@ DeclareOperation("IsOrderIdeal", [IsDigraph, IsList]);
DeclareOperation("IsOrderFilter", [IsDigraph, IsList]);
DeclareOperation("Dominators", [IsDigraph, IsPosInt]);
DeclareOperation("DominatorTree", [IsDigraph, IsPosInt]);
DeclareOperation("DigraphGreedyOutDominatingSet", [IsDigraph, IsList]);
DeclareOperation("DigraphGreedyInDominatingSet", [IsDigraph, IsList]);
DeclareOperation("DigraphCycleBasis", [IsDigraph]);

DeclareOperation("DigraphColourRefinement", [IsDigraph]);
Expand Down
Loading
Loading