From 16c0166baddaf000de0cd2c3e6e522440cd6e502 Mon Sep 17 00:00:00 2001 From: Wilf Wilson Date: Mon, 22 Feb 2021 11:47:53 +0000 Subject: [PATCH 1/8] ci: update GitHub actions integration --- .github/workflows/{ci.yml => gap.yml} | 30 ++++++--------------------- .github/workflows/lint.yml | 25 ++++++++++++++++++++++ Makefile.am | 3 ++- etc/cpplint.sh | 4 ++++ etc/{lint.sh => gaplint.sh} | 1 - 5 files changed, 37 insertions(+), 26 deletions(-) rename .github/workflows/{ci.yml => gap.yml} (61%) create mode 100644 .github/workflows/lint.yml create mode 100755 etc/cpplint.sh rename etc/{lint.sh => gaplint.sh} (90%) 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/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] From 514f5c35b246741d30112790e542f5b54017386d Mon Sep 17 00:00:00 2001 From: Wilf Wilson Date: Wed, 3 Mar 2021 14:30:01 +0000 Subject: [PATCH 2/8] Codecov: replace PR comment by PR status --- .codecov.yml | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/.codecov.yml b/.codecov.yml index 5413b763e..5d240d0e2 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -2,14 +2,20 @@ 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: + default: + informational: true + patch: + default: + informational: true + changes: + default: + informational: true + +# Comment to post on PRs +comment: false ignore: - "extern/" From 2ec91459985120982972125ae9019e158585d913 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Wed, 3 Mar 2021 17:57:08 +0000 Subject: [PATCH 3/8] doc: fix typo in the doc --- doc/attr.xml | 4 ++-- doc/cliques.xml | 4 ++-- doc/digraph.xml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) 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 From a4aa9e1b75715ead29bc822e42272f08d6c2b2d9 Mon Sep 17 00:00:00 2001 From: "James D. Mitchell" Date: Thu, 24 Dec 2020 10:26:53 +0000 Subject: [PATCH 4/8] oper: add dominators algorithm Co-authored-by: Marina Anagnostopoulou-Merkouri Co-authored-by: Samantha Harper --- PackageInfo.g | 20 +++++ doc/digraphs.bib | 13 +++ doc/oper.xml | 86 ++++++++++++++++++ doc/z-chap4.xml | 2 + gap/oper.gd | 2 + gap/oper.gi | 144 +++++++++++++++++++++++++++++- tst/standard/oper.tst | 197 +++++++++++++++++++++++++++++++++++++++++- 7 files changed, 459 insertions(+), 5 deletions(-) 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/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/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"> <#Include Label="DigraphPath"> <#Include Label="DigraphShortestPath"> + <#Include Label="Dominators"> + <#Include Label="DominatorTree"> <#Include Label="IteratorOfPaths"> <#Include Label="DigraphAllSimpleCircuits"> <#Include Label="DigraphLongestSimpleCircuit"> 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/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); From 5d7d166c0cceb5a92b008b0b64ba81b317eb6767 Mon Sep 17 00:00:00 2001 From: Wilf Wilson Date: Wed, 3 Mar 2021 20:21:43 +0000 Subject: [PATCH 5/8] Codecov: fail PR status check if diff not 100% covered --- .codecov.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.codecov.yml b/.codecov.yml index 5d240d0e2..8de3de468 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -4,15 +4,17 @@ coverage: range: "90...100" # Anything below 90% is coloured red (considered bad) status: # GitHub status checks to add to a PR - project: + project: # Check all of Digraphs default: - informational: true - patch: + informational: true # Don't fail the check if overall coverage decreases + patch: # Check only the PR's diff default: - informational: true - changes: + 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 + informational: true # Don't fail the check # Comment to post on PRs comment: false From 390b7689c974c83e8a909c8176af3c9ff32c103c Mon Sep 17 00:00:00 2001 From: Murray Whyte Date: Wed, 3 Mar 2021 14:34:41 +0000 Subject: [PATCH 6/8] Copy immutable lists given to SetDigraphVertexLabels Fixes issue #414 --- doc/labels.xml | 14 +++++++++++--- gap/labels.gi | 3 +++ tst/standard/labels.tst | 6 ++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/doc/labels.xml b/doc/labels.xml index b0df05244..2633103ab 100644 --- a/doc/labels.xml +++ b/doc/labels.xml @@ -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 &GAP; objects list.

+ arbitrary &GAP; 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/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/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]]); From 0d2b875dc2388e07084be26900a9dd932d8f0ee9 Mon Sep 17 00:00:00 2001 From: Murray Whyte Date: Wed, 3 Mar 2021 17:56:43 +0000 Subject: [PATCH 7/8] Fix references to the record component `DigraphVertices` used for Digraph creation --- doc/labels.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/labels.xml b/doc/labels.xml index 2633103ab..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. From a825d4ec99cc9af28e153d290262b980f1bbadd2 Mon Sep 17 00:00:00 2001 From: James Mitchell Date: Wed, 3 Mar 2021 22:07:08 +0000 Subject: [PATCH 8/8] Document config options (PR #420) Resolve Issue #320 --- README.md | 19 +++++++++++++++++-- doc/z-chap1.xml | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) 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/z-chap1.xml b/doc/z-chap1.xml index 3d09ee031..f3d19f8f0 100644 --- a/doc/z-chap1.xml +++ b/doc/z-chap1.xml @@ -94,6 +94,44 @@ make]]> 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. + + + + + + OptionMeaning + + + + + --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 + + +
Configuration flags
+