diff --git a/.VERSION b/.VERSION index b50dd27dd..850e74240 100644 --- a/.VERSION +++ b/.VERSION @@ -1 +1 @@ -1.13.1 +1.14.0 diff --git a/.github/workflows/manual.yml b/.github/workflows/manual.yml index 19c793bcd..3aea572fc 100644 --- a/.github/workflows/manual.yml +++ b/.github/workflows/manual.yml @@ -40,7 +40,7 @@ jobs: gap-version: latest - uses: gap-actions/build-pkg-docs@v2 - name: Upload compiled manuals . . . - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v5 with: name: Digraphs manual retention-days: 7 diff --git a/.gitignore b/.gitignore index 93793b009..04765d017 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,13 @@ -*.DS_Store -*.Plo -*.Tpo +_*.xml +.ipynb_checkpoints +.null-ls* *.a *.aux *.bbl *.blg *.brf *.digraphs +*.DS_Store *.dylib *.g6 *.gcda @@ -24,6 +25,7 @@ *.o *.out *.pdf +*.Plo *.pnr *.pyc *.six @@ -35,13 +37,11 @@ *.tex *.toc *.top +*.Tpo *.tui *.txt -.ipynb_checkpoints /doc/*.css /doc/*.js -Makefile -_*.xml aclocal.m4 autom4te.* bin/ @@ -58,8 +58,10 @@ doc/title.xml gen/ gh-pages/ main.xml +Makefile manual.lab missing +result src/pkgconfig.h.in tags tst/out/ diff --git a/.mailmap b/.mailmap index a08656c37..971d20658 100644 --- a/.mailmap +++ b/.mailmap @@ -1,9 +1,11 @@ Marina Anagnostopoulou-Merkouri marinaanagno <66735004+marinaanagno@users.noreply.github.com> +Cora Aked coraaked Finn Buck Finnegan Buck <61651823+finnbuck@users.noreply.github.com> Stuart Burrell Stuart Burrell Reinis Cirpons reiniscirpons <43414125+reiniscirpons@users.noreply.github.com> Reinis Cirpons Reinis Cirpons <43414125+reiniscirpons@users.noreply.github.com> Reinis Cirpons reiniscirpons +Devansh Chopra Devansh Chopra <92119416+devansh2605@users.noreply.github.com> Tom Conti-Leslie Tom Conti-Leslie <54725378+tomcontileslie@users.noreply.github.com> Tom Conti-Leslie Tom Conti-Leslie Jan De Beule @@ -35,11 +37,13 @@ James Mitchell James Mitchell James Mitchell James D. James Mitchell James Mitchell Seyyed Ali Mohammadiyeh +Rheya Monerasinghe RheyaM <87742505+RheyaM@users.noreply.github.com> Matthew Pancer M Pancer <115101659+mpan322@users.noreply.github.com> Daniel Pointon <30954660+DanielPointon@users.noreply.github.com> Markus Pfeiffer Markus Pfeiffer Markus Pfeiffer Markus Pfeiffer Markus Pfeiffer Markus Pfeiffer +Amelia Phillips ap4108735 Lea Racine LRacine <35891709+LRacine@users.noreply.github.com> Lea Racine Lea Racine <35891709+LRacine@users.noreply.github.com> Lea Racine Lea Racine diff --git a/CHANGELOG.md b/CHANGELOG.md index 944f2f187..f71dc6940 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,30 @@ Wilf A. Wilson, Michael Young et al. Licensing information can be found in the `LICENSE` file. +## Version 1.14.0 (released 22/01/2026) + +## What's Changed + +- Fix some little things in the manual, etc by @wilfwilson in https://github.com/digraphs/Digraphs/pull/855 +- Re-standardise on function arguments named `D`, as opposed to `digraph` by @wilfwilson in https://github.com/digraphs/Digraphs/pull/868 +- Remove support for GAP 4.10 by @wilfwilson in https://github.com/digraphs/Digraphs/pull/866 +- Abstract RandomDigraphCons redirect methods by @mtorpey in https://github.com/digraphs/Digraphs/pull/871 +- Add `SwapDigraphs` and `DigraphsRemoveAllEdges` functions by @RheyaM in https://github.com/digraphs/Digraphs/pull/864 +- CI: stop the codecov step from failing the job on Windows, since it is buggy by @wilfwilson in https://github.com/digraphs/Digraphs/pull/875 +- ViewString for edge weights by @ap4108735 in https://github.com/digraphs/Digraphs/pull/873 +- Fix dotdigraph doc #759 by @coraaked in https://github.com/digraphs/Digraphs/pull/880 +- Implemented ^ operator for digraphs to delegate to OnDigraphs (issue #580) by @devansh2605 in https://github.com/digraphs/Digraphs/pull/876 +- Added `DigraphMinimumCutSet` by @frankiegillis in https://github.com/digraphs/Digraphs/pull/879 + +## New Contributors + +- @RheyaM made their first contribution in https://github.com/digraphs/Digraphs/pull/864 +- @ap4108735 made their first contribution in https://github.com/digraphs/Digraphs/pull/873 +- @coraaked made their first contribution in https://github.com/digraphs/Digraphs/pull/880 +- @devansh2605 made their first contribution in https://github.com/digraphs/Digraphs/pull/876 + +**Full Changelog**: https://github.com/digraphs/Digraphs/compare/v1.13.1...v1.14.0 + ## Version 1.13.1 (released 27/09/2025) This is a minor release of the Digraphs package, containing one bugfix: diff --git a/PackageInfo.g b/PackageInfo.g index 013414fa0..8de5c2a52 100644 --- a/PackageInfo.g +++ b/PackageInfo.g @@ -38,8 +38,8 @@ fi; SetPackageInfo(rec( PackageName := "Digraphs", Subtitle := "Graphs, digraphs, and multidigraphs in GAP", -Version := "1.13.1", -Date := "27/09/2025", # dd/mm/yyyy format +Version := "1.14.0", +Date := "22/01/2026", # dd/mm/yyyy format License := "GPL-3.0-or-later", ArchiveFormats := ".tar.gz", @@ -119,10 +119,15 @@ Persons := [ IsAuthor := true, IsMaintainer := false, Email := "mam49@st-andrews.ac.uk", - GithubUsername := "marinaanagno", - PostalAddress := _STANDREWSMATHS, - Place := "St Andrews", - Institution := "University of St Andrews"), + GithubUsername := "marinaanagno"), + + rec( + LastName := "Aked", + FirstNames := "Cora", + IsAuthor := true, + IsMaintainer := false, + Email := "ca219@st-andrews.ac.uk", + GithubUsername := "coraaked"), rec( LastName := "Buck", @@ -130,10 +135,7 @@ Persons := [ IsAuthor := true, IsMaintainer := false, Email := "finneganlbuck@gmail.com", - GithubUsername := "finnbuck", - PostalAddress := _STANDREWSMATHS, - Place := "St Andrews", - Institution := "University of St Andrews"), + GithubUsername := "finnbuck"), rec( LastName := "Burrell", @@ -151,6 +153,14 @@ Persons := [ IsMaintainer := false, GithubUsername := "GrahamCampbell"), + rec( + LastName := "Chopra", + FirstNames := "Devansh", + IsAuthor := true, + IsMaintainer := false, + Email := "dc268@st-andrews.ac.uk", + GithubUsername := "devansh2605"), + rec( LastName := "Chowdhury", FirstNames := "Raiyan", @@ -164,10 +174,7 @@ Persons := [ IsAuthor := true, IsMaintainer := false, Email := "rc234@st-andrews.ac.uk", - GithubUsername := "reiniscirpons", - PostalAddress := _STANDREWSMATHS, - Place := "St Andrews", - Institution := "University of St Andrews"), + GithubUsername := "reiniscirpons"), rec( LastName := "Clayton", @@ -175,10 +182,7 @@ Persons := [ IsAuthor := true, IsMaintainer := false, Email := "ac323@st-andrews.ac.uk", - GithubUsername := "AshleyClayton", - PostalAddress := _STANDREWSMATHS, - Place := "St Andrews", - Institution := "University of St Andrews"), + GithubUsername := "AshleyClayton"), rec( LastName := "Conti-Leslie", @@ -221,6 +225,14 @@ Persons := [ GithubUsername := "jengelh", WWWHome := "https://inai.de"), + rec( + LastName := "Flores Brito", + FirstNames := "Fernando", + IsAuthor := true, + IsMaintainer := false, + Email := "ffloresbrito@gmail.com", + GithubUsername := "ffloresbrito"), + rec( LastName := "Fernando", FirstNames := "Isuru", @@ -357,6 +369,14 @@ Persons := [ Email := "MaxBaseCode@Gmail.Com", GithubUsername := "BaseMax"), + rec( + LastName := "Monerasinghe", + FirstNames := "Rheya", + IsAuthor := true, + IsMaintainer := false, + Email := "rm387@st-andrews.ac.uk", + GithubUsername := "RheyaM"), + rec( LastName := "Orlitzky", FirstNames := "Michael", @@ -383,6 +403,14 @@ Persons := [ GithubUsername := "markuspf", WWWHome := "https://markusp.morphism.de/"), + rec( + LastName := "Phillips", + FirstNames := "Amelia", + IsAuthor := true, + IsMaintainer := false, + Email := "ap410@st-andrews.ac.uk", + GithubUsername := "ap4108735"), + rec( LastName := "Pointon", FirstNames := "Daniel", @@ -405,10 +433,7 @@ Persons := [ IsAuthor := true, IsMaintainer := false, Email := "lr217@st-andrews.ac.uk", - GithubUsername := "LRacine", - PostalAddress := _STANDREWSCS, - Place := "St Andrews", - Institution := "University of St Andrews"), + GithubUsername := "LRacine"), rec( LastName := "Russell", @@ -440,10 +465,7 @@ Persons := [ IsAuthor := true, IsMaintainer := false, Email := "kks4@st-andrews.ac.uk", - GithubUsername := "KamranKSharma", - PostalAddress := _STANDREWSCS, - Place := "St Andrews", - Institution := "University of St Andrews"), + GithubUsername := "KamranKSharma"), rec( LastName := "Smith", @@ -471,10 +493,7 @@ Persons := [ IsMaintainer := false, Email := "mt200@st-andrews.ac.uk", GithubUsername := "mariatsalakou", - WWWHome := "https://mariatsalakou.github.io/", - PostalAddress := _STANDREWSMATHS, - Place := "St Andrews", - Institution := "University of St Andrews"), + WWWHome := "https://mariatsalakou.github.io/"), rec( LastName := "Vishvanath", diff --git a/VERSIONS b/VERSIONS index 409fa25dc..8cbec17bb 100644 --- a/VERSIONS +++ b/VERSIONS @@ -1,13 +1,14 @@ ############################################################################# ## #W VERSIONS -#Y Copyright (C) 2015-25 James D. Mitchell +#Y Copyright (C) 2015-26 James D. Mitchell ## ## Licensing information can be found in the README.md file of this package. ## ############################################################################# ## +release 1.14.0 - 22/01/2026 release 1.13.1 - 27/09/2025 release 1.13.0 - 26/09/2025 release 1.12.2 - 20/09/2025 diff --git a/doc/oper.xml b/doc/oper.xml index 16ded8109..0930e8f3c 100644 --- a/doc/oper.xml +++ b/doc/oper.xml @@ -248,6 +248,8 @@ true with OnDigraphs(digraph, AsPermutation(trans)).

+ Note: OnDigraphs for a digraph and a permutation or transformation can also be used via the \^ operator.

+ The of digraph will not be retained in the returned digraph.

@@ -278,6 +280,48 @@ true <#/GAPDoc> +<#GAPDoc Label="\^OperatorOnDigraphs"> + + + A digraph. + + The ^ operator acts on digraphs with either a permutation or a transformation. + For a digraph digraph and a permutation perm, + digraph ^ perm gives the same result as + OnDigraphs(digraph, perm) — a digraph whose vertices have been relabelled according to the permutation.

+ + Similarly, if the second argument is a transformation trans, + then digraph ^ trans calls OnDigraphs(digraph, trans). + This allows a simple way to apply vertex relabelling or transformations directly using the ^ symbol.

+ + D := CycleDigraph(5); + +gap> p := (1, 5)(2, 4);; +gap> D ^ p = DigraphReverse(D); +true +gap> OnDigraphs(D, p) = D ^ p; +true +gap> idp := ();; +gap> D ^ idp = D; +true +gap> q := (1, 2, 3, 4, 5);; +gap> (D ^ q) ^ (q ^ -1) = D; +true +gap> t := Transformation([2, 3, 4, 5, 1]);; +gap> D ^ t = OnDigraphs(D, t); +true +gap> idt := Transformation([1, 2, 3, 4, 5]);; +gap> D ^ idt = D; +true +gap> M := DigraphMutableCopy(D);; +gap> M ^ p = OnDigraphs(M, p); +true +]]> + + +<#/GAPDoc> + <#GAPDoc Label="OnMultiDigraphs"> diff --git a/doc/weights.xml b/doc/weights.xml index 22c6b71e9..7d918606d 100644 --- a/doc/weights.xml +++ b/doc/weights.xml @@ -272,6 +272,64 @@ gap> Sum(flow[1]); <#/GAPDoc> +<#GAPDoc Label="DigraphMinimumCut"> + + + A list of lists of integers. + + If digraph is an edge-weighted digraph with distinct vertices s + and t, this function returns a list of two lists representing the + components of the minimum s-t cut of digraph.

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

+ + This attribute is computed by using and the + max-cut min-flow theorem.

+ + See . + g := EdgeWeightedDigraph([[2, 2], [3], []], [[3, 2], [1], []]); + +gap> DigraphMinimumCut(g, 1, 3); +[ [ 1, 2 ], [3] ] +]]> + + +<#/GAPDoc> + +<#GAPDoc Label="DigraphMinimumCutSet"> + + + A list of lists integers. + + If digraph is an edge-weighted digraph with distinct vertices s + and t, this function returns a list of lists of integers representing the + minimum s-t cut of digraph.

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

+ + This attribute is computed by using .

+ + See . + g := EdgeWeightedDigraph([[2, 2], [3], []], [[3, 2], [1], []]); + +gap> DigraphMinimumCutSet(g, 1, 3); +[ [ 2, 3 ] ] +]]> + + +<#/GAPDoc> + <#GAPDoc Label="RandomUniqueEdgeWeightedDigraph"> diff --git a/doc/z-chap5.xml b/doc/z-chap5.xml index 759876e11..21576bc93 100644 --- a/doc/z-chap5.xml +++ b/doc/z-chap5.xml @@ -32,6 +32,8 @@ <#Include Label="EdgeWeightedDigraphShortestPaths"> <#Include Label="EdgeWeightedDigraphShortestPath"> <#Include Label="DigraphMaximumFlow"> + <#Include Label="DigraphMinimumCut"> + <#Include Label="DigraphMinimumCutSet"> <#Include Label="RandomUniqueEdgeWeightedDigraph"> diff --git a/doc/z-chap6.xml b/doc/z-chap6.xml index 5612a37f8..d6d73b01f 100644 --- a/doc/z-chap6.xml +++ b/doc/z-chap6.xml @@ -10,6 +10,7 @@ from} $E_a$ \emph{to} $E_b$. In this case we say that $E_a$ and $E_b$ are

Acting on digraphs <#Include Label="OnDigraphs"> + <#Include Label="\^OperatorOnDigraphs"> <#Include Label="OnMultiDigraphs"> <#Include Label="OnTuplesDigraphs">
diff --git a/flake.lock b/flake.lock new file mode 100644 index 000000000..7889e5a84 --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1772963539, + "narHash": "sha256-9jVDGZnvCckTGdYT53d/EfznygLskyLQXYwJLKMPsZs=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "9dcb002ca1690658be4a04645215baea8b95f31d", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 000000000..ebd20d6db --- /dev/null +++ b/flake.nix @@ -0,0 +1,119 @@ +{ + description = "The GAP package Digraphs"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + }; + + outputs = { self, nixpkgs }: + let + supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; + forAllSystems = nixpkgs.lib.genAttrs supportedSystems; + in + { + packages = forAllSystems (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + gap = pkgs.gap; + gaproot = "${gap}/lib/gap"; + in + { + default = self.packages.${system}.digraphs; + + digraphs = pkgs.stdenv.mkDerivation { + pname = "gap-digraphs"; + version = "1.14.0"; + + src = ./.; + + nativeBuildInputs = with pkgs; [ + autoconf + automake + gcc + gnumake + ]; + + buildInputs = [ + gap + ]; + + configurePhase = '' + runHook preConfigure + + # Generate the configure script + mkdir -p gen + aclocal -Wall --force + autoconf -Wall -f + autoheader -Wall -f + + # Run configure, pointing at the GAP root + ./configure --with-gaproot=${gaproot} + + runHook postConfigure + ''; + + buildPhase = '' + runHook preBuild + make + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p "$out/digraphs" + + # Copy GAP source files + cp -r gap "$out/digraphs/" + cp -r lib "$out/digraphs/" 2>/dev/null || true + cp -r doc "$out/digraphs/" 2>/dev/null || true + cp -r data "$out/digraphs/" 2>/dev/null || true + cp -r tst "$out/digraphs/" 2>/dev/null || true + + # Copy the compiled shared object + cp -r bin "$out/digraphs/" + + # Copy package metadata files + cp PackageInfo.g "$out/digraphs/" + cp init.g "$out/digraphs/" + cp read.g "$out/digraphs/" + cp -r makedoc.g "$out/digraphs/" 2>/dev/null || true + cp LICENSE "$out/digraphs/" 2>/dev/null || true + cp CHANGELOG.md "$out/digraphs/" 2>/dev/null || true + cp README.md "$out/digraphs/" 2>/dev/null || true + + runHook postInstall + ''; + + meta = with pkgs.lib; { + description = "GAP methods for graphs, digraphs, and multidigraphs"; + homepage = "https://digraphs.github.io/Digraphs"; + license = licenses.gpl3Plus; + platforms = platforms.unix; + }; + }; + } + ); + + devShells = forAllSystems (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + gap = pkgs.gap; + in + { + default = pkgs.mkShell { + inputsFrom = [ self.packages.${system}.digraphs ]; + + packages = with pkgs; [ + gap-full + ]; + + shellHook = '' + export GAPROOT="${gap}/lib/gap" + echo "\$GAPROOT=$GAPROOT" + ''; + }; + } + ); + }; +} diff --git a/gap/oper.gd b/gap/oper.gd index 5c0e9ed0b..f6a37e0f8 100644 --- a/gap/oper.gd +++ b/gap/oper.gd @@ -62,6 +62,8 @@ DeclareOperation("DIGRAPHS_GraphProduct", [IsDigraph, IsDigraph, IsFunction]); DeclareOperation("SwapDigraphs", [IsMutableDigraph, IsMutableDigraph]); # 4. Actions . . . +DeclareOperation("^", [IsDigraph, IsPerm]); +DeclareOperation("^", [IsDigraph, IsTransformation]); DeclareOperation("OnDigraphs", [IsDigraph, IsPerm]); DeclareOperation("OnDigraphs", [IsDigraph, IsTransformation]); DeclareOperation("OnDigraphsNC", [IsDigraph, IsPerm]); diff --git a/gap/oper.gi b/gap/oper.gi index 85b327d40..3876db50e 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -1138,6 +1138,16 @@ InstallMethod(DomainForAction, "for a digraph, list or collection and function", [IsDigraph, IsListOrCollection, IsFunction], ReturnTrue); +# Operator action: D^p and D^t +# Allow D ^ p (digraph and permutation) to call OnDigraphs(D, p) +# and D ^ t (digraph and transformation) to call OnDigraphs(D, t) + +InstallMethod(\^, "digraph acted on by a permutation", + [IsDigraph, IsPerm], OnDigraphs); + +InstallMethod(\^, "digraph acted on by a transformation", + [IsDigraph, IsTransformation], OnDigraphs); + ############################################################################# # 5. Substructures and quotients ############################################################################# diff --git a/gap/weights.gd b/gap/weights.gd index 7d11bf5f7..25991e48b 100644 --- a/gap/weights.gd +++ b/gap/weights.gd @@ -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]); diff --git a/gap/weights.gi b/gap/weights.gi index 5b246b002..b55cf13e0 100644 --- a/gap/weights.gi +++ b/gap/weights.gi @@ -638,7 +638,7 @@ function(D, source) end); ############################################################################# -# 5. Maximum Flow +# 5. Maximum Flow and Minimum Cut ############################################################################# InstallMethod(DigraphMaximumFlow, "for an edge weighted digraph", @@ -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(" must be a vertex of ,"); + elif t < 1 or t > Length(vertices) then + ErrorNoReturn(" must be a vertex of ,"); + elif s = t then + ErrorNoReturn(" and 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(" must be a vertex of ,"); + elif t < 1 or t > DigraphNrVertices(D) then + ErrorNoReturn(" must be a vertex of ,"); + elif s = t then + ErrorNoReturn(" and 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 ############################################################################# diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index f4637c9a1..1c813fe21 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -16,6 +16,7 @@ #@local i1, i2, id, idom, in1, in2, in3, iter, j1, j2, m, m1, m2, mat, n, nbs #@local out, out1, out2, out3, p1, p2, path, preorder, qr, r, res, rtclosure, t #@local tclosure, u1, u2, x +#@local p, q, idp, idt, M gap> START_TEST("Digraphs package: standard/oper.tst"); gap> LoadPackage("digraphs", false);; @@ -109,6 +110,30 @@ gap> gr := DigraphRemoveEdge(gr, [2, 1]); gap> DigraphEdges(gr); [ [ 1, 2 ] ] +# Tests for digraph operator "^" (implements D ^ p and D ^ t using OnDigraphs) +gap> D := CycleDigraph(5); + +gap> p := (1, 5)(2, 4);; +gap> D ^ p = DigraphReverse(D); +true +gap> OnDigraphs(D, p) = D ^ p; +true +gap> idp := ();; +gap> D ^ idp = D; +true +gap> q := (1, 2, 3, 4, 5);; +gap> (D ^ q) ^ (q ^ -1) = D; +true +gap> t := Transformation([2, 3, 4, 5, 1]);; +gap> D ^ t = OnDigraphs(D, t); +true +gap> idt := Transformation([1, 2, 3, 4, 5]);; +gap> D ^ idt = D; +true +gap> M := DigraphMutableCopy(D);; +gap> M ^ p = OnDigraphs(M, p); +true + # OnDigraphs: for a digraph and a perm gap> gr := Digraph([[2], [1], [3]]); diff --git a/tst/standard/weights.tst b/tst/standard/weights.tst index 59a632140..739a12a70 100644 --- a/tst/standard/weights.tst +++ b/tst/standard/weights.tst @@ -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 @@ -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([], []); + +gap> DigraphMinimumCut(d, 1, 1); +Error, must be a vertex of , + +# Minimum cut: single vertex (also empty digraphs) +gap> d := EdgeWeightedDigraph([[]], [[]]); + +gap> DigraphMinimumCut(d, 1, 1); +Error, and must be distinct + +# Minimum cut: source = dest +gap> d := EdgeWeightedDigraph([[2], []], [[5], []]); + +gap> DigraphMinimumCut(d, 1, 1); +Error, and must be distinct + +# Minimum cut: has loop +gap> d := EdgeWeightedDigraph([[1, 2], []], [[5, 10], []]); + +gap> DigraphMinimumCut(d, 1, 2); +[ [ 1 ], [ 2 ] ] + +# Minimum cut: invalid source +gap> d := EdgeWeightedDigraph([[1, 2], []], [[5, 10], []]); + +gap> DigraphMinimumCut(d, 5, 2); +Error, must be a vertex of , + +# Minimum cut: invalid sink +gap> d := EdgeWeightedDigraph([[1, 2], []], [[5, 10], []]); + +gap> DigraphMinimumCut(d, 1, 5); +Error, must be a vertex of , + +# Minimum cut: sink not reachable +gap> d := EdgeWeightedDigraph([[1], []], [[5], []]); + +gap> DigraphMinimumCut(d, 1, 2); +[ [ 1 ], [ 2 ] ] + +# Minimum cut: source has in neighbours +gap> d := EdgeWeightedDigraph([[2], [3], []], [[5], [10], []]); + +gap> DigraphMinimumCut(d, 2, 3); +[ [ 2 ], [ 1, 3 ] ] + +# Minimum cut: sink has out-neighbours +gap> d := EdgeWeightedDigraph([[2], [3], [2]], [[5], [10], [7]]); + +gap> DigraphMinimumCut(d, 2, 3); +[ [ 2 ], [ 1, 3 ] ] + +# Minimum cut: cycle +gap> d := EdgeWeightedDigraph([[2], [3], [1]], [[5], [10], [7]]); + +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([], []); + +gap> DigraphMinimumCutSet(d, 1, 1); +Error, must be a vertex of , + +# Minimum cut set: source has in neighbours +gap> d := EdgeWeightedDigraph([[2], [3], []], [[5], [10], []]); + +gap> DigraphMinimumCutSet(d, 2, 3); +[ [ 2, 3 ] ] + +# Minimum cut set: cycle +gap> d := EdgeWeightedDigraph([[2], [3], [1]], [[5], [10], [7]]); + +gap> DigraphMinimumCutSet(d, 1, 3); +[ [ 1, 2 ] ] + +# Minimum cut set: invalid sink +gap> d := EdgeWeightedDigraph([[1, 2], []], [[5, 10], []]); + +gap> DigraphMinimumCutSet(d, 1, 5); +Error, must be a vertex of , + +# Minimum cut set: source = dest +gap> d := EdgeWeightedDigraph([[2], []], [[5], []]); + +gap> DigraphMinimumCutSet(d, 1, 1); +Error, and must be distinct + ############################################################################# # 6. Random edge-weighted digraphs #############################################################################