diff --git a/.codecov.yml b/.codecov.yml
index 5413b763e..8de3de468 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -2,14 +2,22 @@ coverage:
precision: 2 # Report coverage to 2 decimal places
round: down # Round down
range: "90...100" # Anything below 90% is coloured red (considered bad)
- status: # Various customisations that it seems should be off
- project: off
- patch: off
- changes: off
-comment:
- layout: "header, diff, changes, tree"
- behavior: default
+ status: # GitHub status checks to add to a PR
+ project: # Check all of Digraphs
+ default:
+ informational: true # Don't fail the check if overall coverage decreases
+ patch: # Check only the PR's diff
+ default:
+ target: 100
+ threshold: 0
+ informational: false # Do fail the check if the diff is not 100% covered
+ changes: # Information about changes in coverage outside the diff
+ default:
+ informational: true # Don't fail the check
+
+# Comment to post on PRs
+comment: false
ignore:
- "extern/"
diff --git a/.github/workflows/ci.yml b/.github/workflows/gap.yml
similarity index 61%
rename from .github/workflows/ci.yml
rename to .github/workflows/gap.yml
index 2c9878608..8e88d7e7f 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/gap.yml
@@ -1,32 +1,12 @@
-name: "CI"
-
-# Trigger the workflow on push or pull request
-on:
- pull_request:
- push:
- branches-ignore:
- - rc-v[0-9]+.[0-9]+.[0-9]+
+name: "Digraphs tests"
+on: [push, pull_request]
jobs:
- lint:
- name: "lint"
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- name: "Check out the repository"
- - uses: actions/setup-python@v1
- name: "Set up Python"
- - uses: BSFishy/pip-action@v1
- name: "Install gaplint and cpplint with pip"
- with:
- packages: |
- gaplint
- cpplint
- - name: "Run gaplint + cpplint"
- run: bash etc/lint.sh
test:
name: "GAP ${{ matrix.gap-branch }}"
runs-on: ubuntu-latest
+ # Don't run this twice for PRs from branches in the same repository
+ if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) }}
strategy:
fail-fast: false
matrix:
@@ -43,6 +23,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: gap-actions/setup-gap-for-packages@v1
+ name: "Install GAP and clone/compile necessary packages"
with:
GAP_PKGS_TO_CLONE: "${{ matrix.pkgs-to-clone }}"
GAP_PKGS_TO_BUILD: "io orb profiling grape NautyTracesInterface datastructures"
@@ -52,3 +33,4 @@ jobs:
&& curl --retry 5 -L -O "https://digraphs.github.io/Digraphs/${DIGRAPHS_LIB}.tar.gz"
&& tar xf "${DIGRAPHS_LIB}.tar.gz"
- uses: gap-actions/run-test-for-packages@v1
+ name: "Run tst/testall.g"
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
new file mode 100644
index 000000000..2eb0731ae
--- /dev/null
+++ b/.github/workflows/lint.yml
@@ -0,0 +1,25 @@
+name: "linting"
+on: [push, pull_request]
+
+jobs:
+ lint:
+ name: "${{ matrix.linter }}"
+ runs-on: ubuntu-latest
+ # Don't run this twice for PRs from branches in the same repository
+ if: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) }}
+ strategy:
+ fail-fast: false
+ matrix:
+ linter:
+ - gaplint
+ - cpplint
+ steps:
+ - name: "Check out the repository"
+ uses: actions/checkout@v2
+ - name: "Set up Python"
+ uses: actions/setup-python@v1
+ - name: "Install ${{ matrix.linter }} with pip"
+ run: pip install ${{ matrix.linter }}
+ - name: "Run ${{ matrix.linter }} on the Digraphs package"
+ run: bash etc/${{ matrix.linter }}.sh
+
diff --git a/Makefile.am b/Makefile.am
index e39a0f45e..2927390d7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -124,7 +124,8 @@ doc/manual.six: doc/*.xml PackageInfo.g
($(GAPROOT)/bin/gap.sh -A makedoc.g)
lint:
- etc/lint.sh
+ etc/gaplint.sh
+ etc/cpplint.sh
format:
clang-format -i src/*.[hc]
diff --git a/PackageInfo.g b/PackageInfo.g
index 5599e04d7..42d8b0825 100644
--- a/PackageInfo.g
+++ b/PackageInfo.g
@@ -42,6 +42,16 @@ SourceRepository := rec(
Persons := [
rec(
+ LastName := "Anagnostopoulou-Merkouri",
+ FirstNames := "Marina",
+ IsAuthor := false,
+ IsMaintainer := false,
+ Email := "mam49@st-andrews.ac.uk",
+ PostalAddress := _STANDREWSMATHS,
+ Place := "St Andrews",
+ Institution := "University of St Andrews"),
+
+ rec(
LastName := "De Beule",
FirstNames := "Jan",
IsAuthor := true,
@@ -89,6 +99,16 @@ Persons := [
Place := "St Andrews",
Institution := "University of St Andrews"),
+rec(
+ LastName := "Harper",
+ FirstNames := "Samantha",
+ IsAuthor := false,
+ IsMaintainer := false,
+ Email := "seh25@st-andrews.ac.uk",
+ PostalAddress := _STANDREWSMATHS,
+ Place := "St Andrews",
+ Institution := "University of St Andrews"),
+
rec(
LastName := "Horn",
FirstNames := "Max",
diff --git a/README.md b/README.md
index 5e5454664..4a605633a 100644
--- a/README.md
+++ b/README.md
@@ -85,12 +85,27 @@ If you installed GAP on several architectures, then you must execute the
configure/make step for each of the architectures. You can either do this
immediately after configuring and compiling GAP itself on this architecture, or
alternatively set the environment variable `CONFIGNAME` to the name of the
-configuration you used when compiling GAPbefore running `./configure`. Note
+configuration you used when compiling GAP before running `./configure`. Note
however that your compiler choice and flags (environment variables `CC` and
`CFLAGS`) need to be chosen to match the setup of the original GAP compilation.
For example, you have to specify 32-bit or 64-bit mode correctly!
-Digraphs vendors `bliss` and `planarity` libraries in the `extern` directory.
+### Configuration options
+
+In addition to the usual autoconf generated configuration flags, the following
+flags are provided.
+
+Option | Meaning
+----------------------------- | ------------------------------------------------
+--enable-code-coverage | enable code coverage support
+--enable-compile-warnings | enable compiler warnings
+--enable-debug | enable debug mode
+--with-external-bliss | use external `bliss`
+--with-external-planarity | use external `planarity`
+--with-gaproot | specify root of GAP installation
+--without-intrinsics | do not use compiler intrinsics even if available
+
+Digraphs vendors the `bliss` and `planarity` libraries in the `extern` directory.
If you wish to use your system copy of `bliss` or `planarity`, please use the
configure options `--with-external-bliss` or `--with-external-planarity`, as
appropriate.
diff --git a/doc/attr.xml b/doc/attr.xml
index c0342e175..8b3eaa60d 100644
--- a/doc/attr.xml
+++ b/doc/attr.xml
@@ -83,7 +83,7 @@ gap> DigraphNrVertices(D);
The entries of DigraphEdges(digraph) are in one-to-one
- corresponence with the edges of digraph. Hence
+ correspondence with the edges of digraph. Hence
DigraphEdges(digraph) is duplicate-free if and only if
digraph contains no multiple edges.
@@ -1956,7 +1956,7 @@ gap> D;
and the reverse edge [j,i] is an edge of digraph.
In other words, for every
symmetric pair of edges [i,j] and [j,i] in digraph, where
- i and j are distinct, it discards the the edge
+ i and j are distinct, it discards the edge
[\max(i,j),\min(i,j)].
diff --git a/doc/cliques.xml b/doc/cliques.xml
index 1e8feaa1b..112a2097b 100644
--- a/doc/cliques.xml
+++ b/doc/cliques.xml
@@ -147,7 +147,7 @@ true]]>
DigraphMaximalClique greedily enlarge the clique include
until it cannot continue. The result is guaranteed to be a maximal
clique. This may or may not return an answer more quickly than using
- . with a limit of 1.
+ with a limit of 1.
Three arguments
-
@@ -348,7 +348,7 @@ gap> DigraphMaximalCliques(D);
independent set include until it cannot continue. The result
is guaranteed to be a maximal independent set. This may or may not
return an answer more quickly than using
. with a limit of 1.
+ Func="DigraphMaximalIndependentSets"/> with a limit of 1.
Three arguments
-
diff --git a/doc/digraph.xml b/doc/digraph.xml
index af137933c..0c881eaf4 100644
--- a/doc/digraph.xml
+++ b/doc/digraph.xml
@@ -205,7 +205,7 @@
for a binary relation
-
if obj is a binary relation on the points [1 .. n] for
- some posititve integer n, then this function returns the digraph
+ some positive integer n, then this function returns the digraph
defined by obj. Specifically, this function returns a digraph
which has n vertices, and which has an edge with source i
and range j if and only if [i,j] is a pair in
diff --git a/doc/digraphs.bib b/doc/digraphs.bib
index e7b8bc7d5..bc67a8e82 100644
--- a/doc/digraphs.bib
+++ b/doc/digraphs.bib
@@ -99,6 +99,19 @@ @inproceedings{JK07
Year = {2007},
}
+@article{LT79,
+ Author = {Thomas Lengauer and Robert E. Tarjan},
+ Doi = {https://doi.org/10.1145/357062.357071},
+ Journal = {ACM Transactions on Programming Languages and Systems},
+ Number = {1},
+ Pages = {121--141},
+ Title = {A Fast Algorithm for Finding Dominators in a Flowgraph},
+ Url = {https://doi.org/10.1145/357062.357071},
+ Volume = {1},
+ Year = {1979},
+ Bdsk-Url-1 = {https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf}
+}
+
@article{MP14,
Author = {Brendan D. McKay and Adolfo Piperno},
Doi = {https://dx.doi.org/10.1016/j.jsc.2013.09.003},
diff --git a/doc/labels.xml b/doc/labels.xml
index b0df05244..9973cba61 100644
--- a/doc/labels.xml
+++ b/doc/labels.xml
@@ -24,8 +24,8 @@
i.
If digraph is a digraph created from a record with a component
- vertices, then the labels of the vertices are set to the value of
- this component.
+ DigraphVertices, then the labels of the vertices are set to
+ the value of this component.
Induced subdigraphs, and some other operations which create new digraphs from
old ones, inherit their labels from their parents.
@@ -71,15 +71,23 @@ gap> DigraphVertexLabel(D, 1);
copy of the labels of the vertices in digraph.
SetDigraphVertexLabels can be used to set the labels of the vertices
in digraph to the list of
- arbitrary ⪆ objects list.
+ arbitrary ⪆ objects list, which must be of the same length
+ as the number of vertices of digraph.
+
+ If the list list is immutable, then the vertex labels are set to a
+ mutable copy of list. Otherwise, the labels are set to exactly
+ list.
The label of a vertex can be changed an arbitrary number of times. If no
label has been set for the vertex i, then the default value is
i.
If digraph is a digraph created from a record with a component
- vertices, then the labels of the vertices are set to the value of
- this component.
+ DigraphVertices, then the labels of the vertices are set to the
+ value of this component. As in the above, if the component is immutable
+ then the digraph's vertex labels are set to a mutable copy of
+ DigraphVertices. Otherwise, they are set to exactly
+ DigraphVertices.
Induced subdigraphs, and other operations which create new digraphs from
old ones, inherit their labels from their parents.
diff --git a/doc/oper.xml b/doc/oper.xml
index 71d318341..06b94460d 100644
--- a/doc/oper.xml
+++ b/doc/oper.xml
@@ -1668,6 +1668,92 @@ gap> DigraphShortestDistance(D, [1, 3], [3, 5]);
<#/GAPDoc>
+<#GAPDoc Label="Dominators">
+
+
+ A list of lists.
+
+ Dominators takes a digraph and a root root and returns
+ the dominators of each vertex with respect to the root. The output is
+ returned as a list of length DigraphNrVertices(Digraph),
+ whose ith entry is a list with the dominators of vertex i of
+ the digraph. If there is no path from the root to a specific vertex,
+ the output will contain a hole in the corresponding position. The
+ dominators of a vertex u are the vertices that are
+ contained in every path from the root to u, not including
+ u itself.
+
+ The method for this operation is an implementation of an algorithm by
+ Thomas Lengauer and Robert Endre Tarjan . The complexity
+ of this algorithm is O(mlog n) where m is the number of edges
+ and n is the number of nodes in the subdigraph induced by the nodes
+ in digraph reachable from root.
+ D := Digraph([[2], [3, 6], [2, 4], [1], [], [3]]);
+
+gap> Dominators(D, 1);
+[ , [ 1 ], [ 2, 1 ], [ 3, 2, 1 ],, [ 2, 1 ] ]
+gap> Dominators(D, 2);
+[ [ 4, 3, 2 ],, [ 2 ], [ 3, 2 ],, [ 2 ] ]
+gap> Dominators(D, 3);
+[ [ 4, 3 ], [ 3 ],, [ 3 ],, [ 2, 3 ] ]
+gap> Dominators(D, 4);
+[ [ 4 ], [ 1, 4 ], [ 2, 1, 4 ],,, [ 2, 1, 4 ] ]
+gap> Dominators(D, 5);
+[ ]
+gap> Dominators(D, 6);
+[ [ 4, 3, 6 ], [ 3, 6 ], [ 6 ], [ 3, 6 ] ]
+]]>
+
+
+<#/GAPDoc>
+
+<#GAPDoc Label="DominatorTree">
+
+
+ A record.
+
+ DominatorTree takes a digraph and a
+ root vertex and returns a record with the following components:
+
+ idom
+ -
+ the immediate dominators of the vertices with respect
+ to the root.
+
+ preorder
+ -
+ the preorder values of the vertices defined by the depth first search
+ executed on the digraph.
+
+
+ The immediate dominator of a vertex u is the unique dominator
+ of u that is dominated by all other dominators of u. The
+ algorithm is an implementation of the fast algorithm written by Thomas
+ Lengauer and Robert Endre Tarjan . The complexity of
+ this algorithm is O(mlog n) where m is the number of edges
+ and n is the number of nodes in the subdigraph induced by the nodes
+ in digraph reachable from root.
+ D := Digraph([[2, 3], [4, 6], [4, 5], [3, 5], [1, 6], [2, 3]]);
+
+gap> DominatorTree(D, 1);
+rec( idom := [ fail, 1, 1, 1, 1, 1 ],
+ preorder := [ 1, 2, 4, 3, 5, 6 ] )
+gap> DominatorTree(D, 5);
+rec( idom := [ 5, 5, 5, 5, fail, 5 ],
+ preorder := [ 5, 1, 2, 4, 3, 6 ] )
+gap> D := CompleteDigraph(5);
+
+gap> DominatorTree(D, 1);
+rec( idom := [ fail, 1, 1, 1, 1 ], preorder := [ 1, 2, 3, 4, 5 ] )
+gap> DominatorTree(D, 2);
+rec( idom := [ 2, fail, 2, 2, 2 ], preorder := [ 2, 1, 3, 4, 5 ] )
+]]>
+
+
+<#/GAPDoc>
+
<#GAPDoc Label="PartialOrderDigraphMeetOfVertices">
If you want to check that the package is working correctly, you
should run some of the tests described in Section
.
+
+ Configuration options
+
+In addition to the usual autoconf generated configuration flags, the following
+flags are provided.
+
+
+ Configuration flags
+
+
+ - Option
- Meaning
+
+
+
+
+ - --enable-code-coverage
- enable code coverage support
+
+
+ - --enable-compile-warnings
- enable compiler warnings
+
+
+ - --enable-debug
- enable debug mode
+
+
+ - --with-external-bliss
- use external &bliss;
+
+
+ - --with-external-planarity
- use external &edge-addition-planarity-suite;
+
+
+ - --with-gaproot
- specify root of GAP installation
+
+
+ - --without-intrinsics
- do not use compiler intrinsics even if available
+
+
+
+
diff --git a/doc/z-chap4.xml b/doc/z-chap4.xml
index 8d948d754..0b36cbca0 100644
--- a/doc/z-chap4.xml
+++ b/doc/z-chap4.xml
@@ -63,6 +63,8 @@
<#Include Label="VerticesReachableFrom">
<#Include Label="DigraphPath">
<#Include Label="DigraphShortestPath">
+ <#Include Label="Dominators">
+ <#Include Label="DominatorTree">
<#Include Label="IteratorOfPaths">
<#Include Label="DigraphAllSimpleCircuits">
<#Include Label="DigraphLongestSimpleCircuit">
diff --git a/etc/cpplint.sh b/etc/cpplint.sh
new file mode 100755
index 000000000..d6c18c66c
--- /dev/null
+++ b/etc/cpplint.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+set -e
+
+cpplint src/*.[ch]
diff --git a/etc/lint.sh b/etc/gaplint.sh
similarity index 90%
rename from etc/lint.sh
rename to etc/gaplint.sh
index 5df85006a..8e4062a29 100755
--- a/etc/lint.sh
+++ b/etc/gaplint.sh
@@ -4,4 +4,3 @@ set -e
gaplint --disable W004 *.g gap/*
gaplint --disable W004 doc/*.xml
gaplint --disable W004 tst/testinstall.tst tst/standard/*.tst tst/extreme/*.tst tst/workspaces/*.tst
-cpplint src/*.[ch]
diff --git a/gap/labels.gi b/gap/labels.gi
index 3671a6f92..d72762059 100644
--- a/gap/labels.gi
+++ b/gap/labels.gi
@@ -61,6 +61,9 @@ function(D, names)
"to the number of vertices of the digraph that is the ",
"1st argument,");
fi;
+ if not IsMutable(names) then
+ names := ShallowCopy(names);
+ fi;
D!.vertexlabels := names;
end);
diff --git a/gap/oper.gd b/gap/oper.gd
index 0139c2a71..f1544fbb1 100644
--- a/gap/oper.gd
+++ b/gap/oper.gd
@@ -120,6 +120,8 @@ DeclareOperation("DigraphShortestDistance", [IsDigraph, IsList]);
DeclareOperation("DigraphShortestPath", [IsDigraph, IsPosInt, IsPosInt]);
DeclareOperation("DigraphShortestPathSpanningTree", [IsDigraph, IsPosInt]);
DeclareOperation("VerticesReachableFrom", [IsDigraph, IsPosInt]);
+DeclareOperation("Dominators", [IsDigraph, IsPosInt]);
+DeclareOperation("DominatorTree", [IsDigraph, IsPosInt]);
# 10. Operations for vertices . . .
DeclareOperation("PartialOrderDigraphJoinOfVertices",
diff --git a/gap/oper.gi b/gap/oper.gi
index 630052dd4..ce9ca1b56 100644
--- a/gap/oper.gi
+++ b/gap/oper.gi
@@ -1829,8 +1829,8 @@ function(D, root)
have_visited_root;
N := DigraphNrVertices(D);
if 0 = root or root > N then
- ErrorNoReturn("the 2nd argument (root)",
- " is not a vertex of the 1st argument (a digraph)");
+ ErrorNoReturn("the 2nd argument (root) is not a vertex of the 1st ",
+ "argument (a digraph)");
fi;
index := ListWithIdenticalEntries(N, 0);
have_visited_root := false;
@@ -1863,6 +1863,146 @@ function(D, root)
return visited;
end);
+InstallMethod(DominatorTree, "for a digraph and a vertex",
+[IsDigraph, IsPosInt],
+function(D, root)
+ local M, node_to_preorder_num, preorder_num_to_node, parent, index, next,
+ current, succ, prev, n, semi, lastlinked, label, bucket, idom,
+ compress, eval, pred, N, w, y, x, i, v;
+ M := DigraphNrVertices(D);
+
+ if 0 = root or root > M then
+ ErrorNoReturn("the 2nd argument (root) is not a vertex of the 1st ",
+ "argument (a digraph)");
+ fi;
+
+ node_to_preorder_num := [];
+ node_to_preorder_num[root] := 1;
+ preorder_num_to_node := [root];
+
+ parent := [];
+ parent[root] := fail;
+
+ index := ListWithIdenticalEntries(M, 1);
+
+ next := 2;
+ current := root;
+ succ := OutNeighbours(D);
+ repeat
+ prev := current;
+ for i in [index[current] .. Length(succ[current])] do
+ n := succ[current][i];
+ if not IsBound(node_to_preorder_num[n]) then
+ Add(preorder_num_to_node, n);
+ parent[n] := current;
+ index[current] := i + 1;
+ node_to_preorder_num[n] := next;
+ next := next + 1;
+ current := n;
+ break;
+ fi;
+ od;
+ if prev = current then
+ current := parent[current];
+ fi;
+ until current = fail;
+ semi := [1 .. M];
+ lastlinked := M + 1;
+ label := [];
+ bucket := List([1 .. M], x -> []);
+ idom := [];
+ idom[root] := root;
+
+ compress := function(v)
+ local u;
+ u := parent[v];
+ if u <> fail and lastlinked <= M and node_to_preorder_num[u] >=
+ node_to_preorder_num[lastlinked] then
+ compress(u);
+ if node_to_preorder_num[semi[label[u]]]
+ < node_to_preorder_num[semi[label[v]]] then
+ label[v] := label[u];
+ fi;
+ parent[v] := parent[u];
+ fi;
+ end;
+
+ eval := function(v)
+ if lastlinked <= M and node_to_preorder_num[v] >=
+ node_to_preorder_num[lastlinked] then
+ compress(v);
+ return label[v];
+ else
+ return v;
+ fi;
+ end;
+
+ pred := InNeighbours(D);
+ N := Length(preorder_num_to_node);
+ for i in [N, N - 1 .. 2] do
+ w := preorder_num_to_node[i];
+ for v in bucket[w] do
+ y := eval(v);
+ if node_to_preorder_num[semi[y]] < node_to_preorder_num[w] then
+ idom[v] := y;
+ else
+ idom[v] := w;
+ fi;
+ od;
+ bucket[w] := [];
+ for v in pred[w] do
+ if IsBound(node_to_preorder_num[v]) then
+ x := eval(v);
+ if node_to_preorder_num[semi[x]] < node_to_preorder_num[semi[w]] then
+ semi[w] := semi[x];
+ fi;
+ fi;
+ od;
+ if parent[w] = semi[w] then
+ idom[w] := parent[w];
+ else
+ Add(bucket[semi[w]], w);
+ fi;
+ lastlinked := w;
+ label[w] := semi[w];
+ od;
+ for v in bucket[root] do
+ idom[v] := root;
+ od;
+ for i in [2 .. N] do
+ w := preorder_num_to_node[i];
+ if idom[w] <> semi[w] then
+ idom[w] := idom[semi[w]];
+ fi;
+ od;
+ idom[root] := fail;
+ return rec(idom := idom, preorder := preorder_num_to_node);
+end);
+
+InstallMethod(Dominators, "for a digraph and a vertex",
+[IsDigraph, IsPosInt],
+function(D, root)
+ local tree, preorder, result, u, v;
+ if not root in DigraphVertices(D) then
+ ErrorNoReturn("the 2nd argument (a pos. int.) is not a vertex of ",
+ "the 1st argument (a digraph)");
+ fi;
+ tree := DominatorTree(D, root);
+ preorder := tree.preorder;
+ tree := tree.idom;
+ result := [];
+ for v in preorder do
+ u := tree[v];
+ if u <> fail then
+ result[v] := [u];
+ if IsBound(result[u]) then
+ Append(result[v], result[u]);
+ fi;
+ fi;
+ od;
+ return result;
+end);
+
#############################################################################
# 10. Operations for vertices
#############################################################################
diff --git a/tst/standard/labels.tst b/tst/standard/labels.tst
index 4a4ee086b..3c88deb92 100644
--- a/tst/standard/labels.tst
+++ b/tst/standard/labels.tst
@@ -79,6 +79,12 @@ gap> DigraphVertexLabels(gr);
[ 1, 3, 4, 5, 6, 7, 8, 9, 10 ]
gap> D := NullDigraph(5);;
gap> RemoveDigraphVertexLabel(D, 6);
+gap> A := Immutable([1, 2]);
+[ 1, 2 ]
+gap> D := CycleDigraph(2);
+
+gap> SetDigraphVertexLabels(D, A);
+gap> SetDigraphVertexLabel(D, 2, "b");
# DigraphEdgeLabels
gap> gr := Digraph([[2, 3], [3], [1, 5], [], [4]]);
diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst
index 2fc952cab..d2afb1a2d 100644
--- a/tst/standard/oper.tst
+++ b/tst/standard/oper.tst
@@ -2088,8 +2088,7 @@ gap> OutNeighbours(C);
[ [ 5, 6, 7 ], [ 7 ], [ 7 ], [ 7 ], [ 1, 6, 7 ], [ 1, 5, 7 ],
[ 3, 2, 1, 6, 5, 4 ] ]
-#DigraphDijkstra
-# When there is one path to target
+# DigraphDijkstra - when there is one path to target
gap> mat := [[0, 1, 1], [0, 0, 1], [0, 0, 0]];
[ [ 0, 1, 1 ], [ 0, 0, 1 ], [ 0, 0, 0 ] ]
gap> gr := DigraphByAdjacencyMatrix(mat);
@@ -2129,7 +2128,7 @@ gap> DigraphDijkstra(gr, 1, 2);
gap> DigraphDijkstra(gr, 1, 3);
[ [ 0, 1, 1, 1 ], [ -1, 1, 1, 1 ] ]
-#ModularProduct
+# ModularProduct
gap> ModularProduct(NullDigraph(0), CompleteDigraph(10));
gap> ModularProduct(PetersenGraph(), CompleteDigraph(10));
@@ -2262,6 +2261,198 @@ Error, the 2nd argument must be a vertex of the digraph
gap> DigraphShortestPathSpanningTree(EmptyDigraph(1), 1);
+# Dominators
+gap> D := Digraph([[2], [3, 4, 6], [5], [5], [2], []]);
+
+gap> D := CompleteDigraph(5);
+
+gap> D := DigraphDisjointUnion(D, D);
+
+gap> D := NullDigraph(10);
+
+gap> D := ChainDigraph(10000);
+
+gap> D := Digraph([[1, 2, 3], [4], [1, 5], [], [2]]);;
+gap> D := CompleteDigraph(5);
+
+gap> Dominators(D, 1);
+[ , [ 1 ], [ 1 ], [ 1 ], [ 1 ] ]
+gap> Dominators(D, 2);
+[ [ 2 ],, [ 2 ], [ 2 ], [ 2 ] ]
+gap> Dominators(D, 5);
+[ [ 5 ], [ 5 ], [ 5 ], [ 5 ] ]
+gap> D := CycleDigraph(10);
+
+gap> Dominators(D, 5);
+[ [ 10, 9, 8, 7, 6, 5 ], [ 1, 10, 9, 8, 7, 6, 5 ],
+ [ 2, 1, 10, 9, 8, 7, 6, 5 ], [ 3, 2, 1, 10, 9, 8, 7, 6, 5 ],, [ 5 ],
+ [ 6, 5 ], [ 7, 6, 5 ], [ 8, 7, 6, 5 ], [ 9, 8, 7, 6, 5 ] ]
+gap> D := Digraph([[3, 4], [1, 4], [2, 5], [3, 5], []]);
+
+gap> Dominators(D, 1);
+[ , [ 3, 1 ], [ 1 ], [ 1 ], [ 1 ] ]
+gap> Dominators(D, 2);
+[ [ 2 ],, [ 2 ], [ 2 ], [ 2 ] ]
+gap> Dominators(D, 3);
+[ [ 2, 3 ], [ 3 ],, [ 2, 3 ], [ 3 ] ]
+gap> Dominators(D, 4);
+[ [ 2, 3, 4 ], [ 3, 4 ], [ 4 ],, [ 4 ] ]
+gap> Dominators(D, 5);
+[ ]
+gap> d := Digraph([[2, 3], [4, 6], [4, 5], [3, 5], [1, 6], [2, 3]]);
+
+gap> Dominators(d, 5);
+[ [ 5 ], [ 5 ], [ 5 ], [ 5 ],, [ 5 ] ]
+gap> Dominators(d, 1);
+[ , [ 1 ], [ 1 ], [ 1 ], [ 1 ], [ 1 ] ]
+gap> Dominators(d, 3);
+[ [ 5, 3 ], [ 5, 3 ],, [ 3 ], [ 3 ], [ 5, 3 ] ]
+gap> Dominators(d, 4);
+[ [ 5, 4 ], [ 5, 4 ], [ 4 ],, [ 4 ], [ 5, 4 ] ]
+gap> Dominators(d, 6);
+[ [ 5, 6 ], [ 6 ], [ 6 ], [ 6 ], [ 6 ] ]
+gap> d := Digraph([[], [3], [4, 5], [2], [4]]);
+
+gap> Dominators(d, 1);
+[ ]
+gap> Dominators(d, 2);
+[ ,, [ 2 ], [ 3, 2 ], [ 3, 2 ] ]
+gap> Dominators(d, 3);
+[ , [ 4, 3 ],, [ 3 ], [ 3 ] ]
+gap> Dominators(d, 4);
+[ , [ 4 ], [ 2, 4 ],, [ 3, 2, 4 ] ]
+gap> Dominators(d, 5);
+[ , [ 4, 5 ], [ 2, 4, 5 ], [ 5 ] ]
+gap> D := Digraph([[2, 3, 5], [1, 6], [4, 6, 7], [7, 8], [4], [], [8], []]);
+
+gap> Dominators(D, 1);
+[ , [ 1 ], [ 1 ], [ 1 ], [ 1 ], [ 1 ], [ 1 ], [ 1 ] ]
+gap> Dominators(D, 2);
+[ [ 2 ],, [ 1, 2 ], [ 1, 2 ], [ 1, 2 ], [ 2 ], [ 1, 2 ], [ 1, 2 ] ]
+gap> Dominators(D, 3);
+[ ,,, [ 3 ],, [ 3 ], [ 3 ], [ 3 ] ]
+gap> Dominators(D, 4);
+[ ,,,,,, [ 4 ], [ 4 ] ]
+gap> Dominators(D, 5);
+[ ,,, [ 5 ],,, [ 4, 5 ], [ 4, 5 ] ]
+gap> Dominators(D, 6);
+[ ]
+gap> Dominators(D, 7);
+[ ,,,,,,, [ 7 ] ]
+gap> Dominators(D, 8);
+[ ]
+gap> d := Digraph([[2], [3, 6], [2, 4], [1], [], [3]]);
+
+gap> Dominators(d, 1);
+[ , [ 1 ], [ 2, 1 ], [ 3, 2, 1 ],, [ 2, 1 ] ]
+gap> Dominators(d, 2);
+[ [ 4, 3, 2 ],, [ 2 ], [ 3, 2 ],, [ 2 ] ]
+gap> Dominators(d, 3);
+[ [ 4, 3 ], [ 3 ],, [ 3 ],, [ 2, 3 ] ]
+gap> Dominators(d, 4);
+[ [ 4 ], [ 1, 4 ], [ 2, 1, 4 ],,, [ 2, 1, 4 ] ]
+gap> Dominators(d, 5);
+[ ]
+gap> Dominators(d, 6);
+[ [ 4, 3, 6 ], [ 3, 6 ], [ 6 ], [ 3, 6 ] ]
+gap> d := Digraph([[1, 2, 3], [4, 5], [1, 3], [3, 5], [4]]);
+
+gap> Dominators(d, 1);
+[ , [ 1 ], [ 1 ], [ 2, 1 ], [ 2, 1 ] ]
+gap> Dominators(d, 2);
+[ [ 3, 4, 2 ],, [ 4, 2 ], [ 2 ], [ 2 ] ]
+gap> Dominators(d, 3);
+[ [ 3 ], [ 1, 3 ],, [ 2, 1, 3 ], [ 2, 1, 3 ] ]
+gap> Dominators(d, 4);
+[ [ 3, 4 ], [ 1, 3, 4 ], [ 4 ],, [ 4 ] ]
+gap> Dominators(d, 5);
+[ [ 3, 4, 5 ], [ 1, 3, 4, 5 ], [ 4, 5 ], [ 5 ] ]
+gap> D := Digraph([[1, 2, 3], [4], [1, 5], [], [2]]);
+
+gap> Dominators(D, 1);
+[ , [ 1 ], [ 1 ], [ 2, 1 ], [ 3, 1 ] ]
+gap> Dominators(D, 2);
+[ ,,, [ 2 ] ]
+gap> Dominators(D, 3);
+[ [ 3 ], [ 3 ],, [ 2, 3 ], [ 3 ] ]
+gap> Dominators(D, 4);
+[ ]
+gap> Dominators(D, 5);
+[ , [ 5 ],, [ 2, 5 ] ]
+gap> D := EmptyDigraph(15);
+
+gap> Dominators(D, 3);
+[ ]
+gap> D := Digraph(IsMutableDigraph, [[1, 2, 3], [4], [1, 5], [], [2]]);
+
+gap> Dominators(D, 5);
+[ , [ 5 ],, [ 2, 5 ] ]
+gap> Dominators(D, 4);
+[ ]
+gap> Dominators(D, 3);
+[ [ 3 ], [ 3 ],, [ 2, 3 ], [ 3 ] ]
+gap> Dominators(D, 2);
+[ ,,, [ 2 ] ]
+gap> Dominators(D, 1);
+[ , [ 1 ], [ 1 ], [ 2, 1 ], [ 3, 1 ] ]
+gap> D := Digraph(IsMutableDigraph, [[2, 3, 5], [1, 6], [4, 6, 7], [7, 8], [4], [], [8], []]);
+
+gap> Dominators(D, 1);
+[ , [ 1 ], [ 1 ], [ 1 ], [ 1 ], [ 1 ], [ 1 ], [ 1 ] ]
+gap> Dominators(D, 2);
+[ [ 2 ],, [ 1, 2 ], [ 1, 2 ], [ 1, 2 ], [ 2 ], [ 1, 2 ], [ 1, 2 ] ]
+gap> Dominators(D, 3);
+[ ,,, [ 3 ],, [ 3 ], [ 3 ], [ 3 ] ]
+gap> Dominators(D, 4);
+[ ,,,,,, [ 4 ], [ 4 ] ]
+gap> Dominators(D, 5);
+[ ,,, [ 5 ],,, [ 4, 5 ], [ 4, 5 ] ]
+gap> Dominators(D, 6);
+[ ]
+gap> Dominators(D, 7);
+[ ,,,,,,, [ 7 ] ]
+gap> Dominators(D, 8);
+[ ]
+
+# DominatorTree
+gap> D := CompleteDigraph(5);
+
+gap> DominatorTree(D, 1);
+rec( idom := [ fail, 1, 1, 1, 1 ], preorder := [ 1, 2, 3, 4, 5 ] )
+gap> DominatorTree(D, 2);
+rec( idom := [ 2, fail, 2, 2, 2 ], preorder := [ 2, 1, 3, 4, 5 ] )
+gap> DominatorTree(D, 3);
+rec( idom := [ 3, 3, fail, 3, 3 ], preorder := [ 3, 1, 2, 4, 5 ] )
+gap> DominatorTree(D, 4);
+rec( idom := [ 4, 4, 4, fail, 4 ], preorder := [ 4, 1, 2, 3, 5 ] )
+gap> DominatorTree(D, 5);
+rec( idom := [ 5, 5, 5, 5, fail ], preorder := [ 5, 1, 2, 3, 4 ] )
+gap> D := CycleDigraph(10);
+
+gap> DominatorTree(D, 1);
+rec( idom := [ fail, 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
+ preorder := [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] )
+gap> DominatorTree(D, 2);
+rec( idom := [ 10, fail, 2, 3, 4, 5, 6, 7, 8, 9 ],
+ preorder := [ 2, 3, 4, 5, 6, 7, 8, 9, 10, 1 ] )
+gap> DominatorTree(D, 5);
+rec( idom := [ 10, 1, 2, 3, fail, 5, 6, 7, 8, 9 ],
+ preorder := [ 5, 6, 7, 8, 9, 10, 1, 2, 3, 4 ] )
+gap> D := Digraph([[2, 3], [4, 6], [4, 5], [3, 5], [1, 6], [2, 3]]);
+
+gap> DominatorTree(D, 1);
+rec( idom := [ fail, 1, 1, 1, 1, 1 ], preorder := [ 1, 2, 4, 3, 5, 6 ] )
+gap> DominatorTree(D, 5);
+rec( idom := [ 5, 5, 5, 5, fail, 5 ], preorder := [ 5, 1, 2, 4, 3, 6 ] )
+gap> DominatorTree(D, 6);
+rec( idom := [ 5, 6, 6, 6, 6, fail ], preorder := [ 6, 2, 4, 3, 5, 1 ] )
+gap> D := EmptyDigraph(15);
+
+gap> DominatorTree(D, 1);
+rec( idom := [ fail ], preorder := [ 1 ] )
+gap> DominatorTree(D, 6);
+rec( idom := [ ,,,,, fail ], preorder := [ 6 ] )
+
#DIGRAPHS_UnbindVariables
gap> Unbind(a);
gap> Unbind(adj);