From 0c7642c60cb8c3de8836aefbdb0dba85f277f427 Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Wed, 29 Oct 2025 14:58:08 +0000 Subject: [PATCH 01/18] Implemented ^ operator for digraphs to delegate to OnDigraphs (issue #580) --- gap/oper.gi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/gap/oper.gi b/gap/oper.gi index 85b327d40..49f4be0ca 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 ############################################################################# From 1af31603ed8077b5fef72471284899f5894e7204 Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Wed, 29 Oct 2025 15:50:37 +0000 Subject: [PATCH 02/18] Added a helper function and updated the existing methods to preserve edge weights when removing vertices, edges or copying digraphs (issue #683) --- gap/digraph.gd | 2 ++ gap/digraph.gi | 30 ++++++++++++++++++++++++++++++ gap/oper.gi | 29 ++++++++++++++++++++++++++--- 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/gap/digraph.gd b/gap/digraph.gd index 46cb83d79..c46ac210d 100644 --- a/gap/digraph.gd +++ b/gap/digraph.gd @@ -152,3 +152,5 @@ DeclareOperation("RandomLattice", [IsFunction, IsPosInt]); # in the not-too-distant future! DeclareOperation("RandomMultiDigraph", [IsPosInt]); DeclareOperation("RandomMultiDigraph", [IsPosInt, IsPosInt]); + +DeclareGlobalFunction("CopyEdgeWeightsForSubdigraph"); \ No newline at end of file diff --git a/gap/digraph.gi b/gap/digraph.gi index 893d363bc..69aca3f0a 100644 --- a/gap/digraph.gi +++ b/gap/digraph.gi @@ -172,6 +172,11 @@ function(D) if HaveEdgeLabelsBeenAssigned(D) then SetDigraphEdgeLabelsNC(copy, StructuralCopy(DigraphEdgeLabelsNC(D))); fi; + + if HasEdgeWeights(D) then + SetEdgeWeights(copy, StructuralCopy(EdgeWeights(D))); + fi; + return copy; end); @@ -1837,3 +1842,28 @@ n -> RandomLatticeCons(IsImmutableDigraph, n)); InstallMethod(RandomLattice, "for a func and a pos int", [IsFunction, IsPosInt], RandomLatticeCons); + +InstallGlobalFunction(CopyEdgeWeightsForSubdigraph, +function(oldDigraph, newDigraph, removedVertices) + local oldWeights, newWeights, i, j, weight, shiftVertices; + + if not HasEdgeWeights(oldDigraph) then + return; + fi; + + oldWeights := EdgeWeights(oldDigraph); + newWeights := []; + for i in [1 .. DigraphNrVertices(newDigraph)] do + newWeights[i] := []; + + for j in OutNeighbours(newDigraph, i) do + shiftVertices := function(x) + return x + Length(Filtered(removedVertices, v -> v <= x)); + end; + weight := oldWeights[shiftVertices(i)][shiftVertices(j)]; + Add(newWeights[i], weight); + od; + od; + + SetEdgeWeights(newDigraph, newWeights); +end); diff --git a/gap/oper.gi b/gap/oper.gi index 49f4be0ca..67e188768 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -107,7 +107,8 @@ InstallMethod(DigraphRemoveVertex, "for a mutable digraph by out-neighbours and positive integer", [IsMutableDigraph and IsDigraphByOutNeighboursRep, IsPosInt], function(D, u) - local pos, w, v; + local pos, w, v, oldD; + oldD := StructuralCopy(D); if u > DigraphNrVertices(D) then return D; fi; @@ -131,6 +132,11 @@ function(D, u) fi; od; od; + + if HasEdgeWeights(D) then + CopyEdgeWeightsForSubdigraph(oldD, D, [u]); + fi; + return D; end); @@ -138,10 +144,18 @@ InstallMethod(DigraphRemoveVertex, "for an immutable digraph and positive integer", [IsImmutableDigraph, IsPosInt], function(D, u) + local newD; if u > DigraphNrVertices(D) then return D; fi; - return MakeImmutable(DigraphRemoveVertex(DigraphMutableCopy(D), u)); + + newD := DigraphRemoveVertex(DigraphMutableCopy(D), u); + if HasEdgeWeights(D) then + CopyEdgeWeightsForSubdigraph(D, newD, [u]); + fi; + MakeImmutable(newD); + + return newD; end); InstallMethod(DigraphRemoveVertices, "for a mutable digraph and a list", @@ -227,7 +241,7 @@ InstallMethod(DigraphRemoveEdge, "for a mutable digraph by out-neighbours and two positive integers", [IsMutableDigraph and IsDigraphByOutNeighboursRep, IsPosInt, IsPosInt], function(D, src, ran) - local pos; + local pos, weights; if IsMultiDigraph(D) then ErrorNoReturn("the 1st argument must be a digraph with no multiple ", "edges,"); @@ -243,6 +257,15 @@ function(D, src, ran) Remove(D!.OutNeighbours[src], pos); RemoveDigraphEdgeLabel(D, src, pos); fi; + + if HasEdgeWeights(D) then + weights := StructuralCopy(EdgeWeights(D)); + if IsBound(weights[src]) and IsBound(weights[src][ran]) then + weights[src][ran] := fail; + fi; + SetEdgeWeights(D, weights); + fi; + return D; end); From b39a548590a492b7027c08d1b7b952d7c5eafddf Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Wed, 29 Oct 2025 15:56:56 +0000 Subject: [PATCH 03/18] Removed code for issue 580 committed by mistake in this branch --- gap/oper.gi | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/gap/oper.gi b/gap/oper.gi index 67e188768..990b44861 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -1161,16 +1161,6 @@ 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 ############################################################################# From 469f7a4d1f8c2365839d769fe647634b8ca06ae3 Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Tue, 11 Nov 2025 14:07:31 +0000 Subject: [PATCH 04/18] Converted shiftVertices to lambda expression and corrected lint formatting --- gap/digraph.gi | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/gap/digraph.gi b/gap/digraph.gi index 69aca3f0a..1d52bd9fd 100644 --- a/gap/digraph.gi +++ b/gap/digraph.gi @@ -1843,7 +1843,7 @@ n -> RandomLatticeCons(IsImmutableDigraph, n)); InstallMethod(RandomLattice, "for a func and a pos int", [IsFunction, IsPosInt], RandomLatticeCons); -InstallGlobalFunction(CopyEdgeWeightsForSubdigraph, +InstallGlobalFunction(CopyEdgeWeightsForSubdigraph, function(oldDigraph, newDigraph, removedVertices) local oldWeights, newWeights, i, j, weight, shiftVertices; @@ -1853,13 +1853,11 @@ function(oldDigraph, newDigraph, removedVertices) oldWeights := EdgeWeights(oldDigraph); newWeights := []; + shiftVertices := x -> x + Length(Filtered(removedVertices, v -> v <= x)); + for i in [1 .. DigraphNrVertices(newDigraph)] do newWeights[i] := []; - for j in OutNeighbours(newDigraph, i) do - shiftVertices := function(x) - return x + Length(Filtered(removedVertices, v -> v <= x)); - end; weight := oldWeights[shiftVertices(i)][shiftVertices(j)]; Add(newWeights[i], weight); od; From f0046405e7ed889af76ff037b90ee23a0121ba8b Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Mon, 24 Nov 2025 13:51:03 +0000 Subject: [PATCH 05/18] Fixed weight preservation in DigraphMutableCopy, DigraphRemoveEdge, DigraphRemoveVertex and related immutable operations. Also added testing. --- gap/digraph.gd | 2 +- gap/digraph.gi | 57 +++++++++++++++++++---------- gap/oper.gi | 78 +++++++++++++++++++++------------------- tst/standard/digraph.tst | 59 +++++++++++++++++++++++++++++- tst/standard/oper.tst | 42 +++++++++++++++++++++- 5 files changed, 180 insertions(+), 58 deletions(-) diff --git a/gap/digraph.gd b/gap/digraph.gd index c46ac210d..758606213 100644 --- a/gap/digraph.gd +++ b/gap/digraph.gd @@ -153,4 +153,4 @@ DeclareOperation("RandomLattice", [IsFunction, IsPosInt]); DeclareOperation("RandomMultiDigraph", [IsPosInt]); DeclareOperation("RandomMultiDigraph", [IsPosInt, IsPosInt]); -DeclareGlobalFunction("CopyEdgeWeightsForSubdigraph"); \ No newline at end of file +DeclareOperation("RemoveDigraphEdgeWeight", [IsDigraph, IsPosInt, IsPosInt]); \ No newline at end of file diff --git a/gap/digraph.gi b/gap/digraph.gi index 1d52bd9fd..f44ae752f 100644 --- a/gap/digraph.gi +++ b/gap/digraph.gi @@ -167,14 +167,18 @@ InstallMethod(DigraphMutableCopy, "for a digraph by out-neighbours", [IsDigraphByOutNeighboursRep], function(D) local copy; + copy := ConvertToMutableDigraphNC(OutNeighboursMutableCopy(D)); SetDigraphVertexLabels(copy, StructuralCopy(DigraphVertexLabels(D))); + if HaveEdgeLabelsBeenAssigned(D) then SetDigraphEdgeLabelsNC(copy, StructuralCopy(DigraphEdgeLabelsNC(D))); fi; - if HasEdgeWeights(D) then - SetEdgeWeights(copy, StructuralCopy(EdgeWeights(D))); + if IsImmutableDigraph(D) and HasEdgeWeights(D) then + copy!.edgeweights := EdgeWeightsMutableCopy(D); + elif IsMutableDigraph(D) and IsBound(D!.edgeweights) then + copy!.edgeweights := StructuralCopy(D!.edgeweights); fi; return copy; @@ -184,11 +188,20 @@ InstallMethod(DigraphImmutableCopy, "for a digraph by out-neighbours", [IsDigraphByOutNeighboursRep], function(D) local copy; + copy := ConvertToImmutableDigraphNC(OutNeighboursMutableCopy(D)); SetDigraphVertexLabels(copy, StructuralCopy(DigraphVertexLabels(D))); + if HaveEdgeLabelsBeenAssigned(D) then SetDigraphEdgeLabelsNC(copy, StructuralCopy(DigraphEdgeLabelsNC(D))); fi; + + if IsImmutableDigraph(D) and HasEdgeWeights(D) then + SetEdgeWeights(copy, StructuralCopy(EdgeWeights(D))); + elif IsMutableDigraph(D) and IsBound(D!.edgeweights) then + SetEdgeWeights(copy, StructuralCopy(D!.edgeweights)); + fi; + return copy; end); @@ -1843,25 +1856,31 @@ n -> RandomLatticeCons(IsImmutableDigraph, n)); InstallMethod(RandomLattice, "for a func and a pos int", [IsFunction, IsPosInt], RandomLatticeCons); -InstallGlobalFunction(CopyEdgeWeightsForSubdigraph, -function(oldDigraph, newDigraph, removedVertices) - local oldWeights, newWeights, i, j, weight, shiftVertices; - - if not HasEdgeWeights(oldDigraph) then - return; +InstallMethod(RemoveDigraphEdgeWeight, "for a mutable digraph, pos int, pos int", +[IsMutableDigraph and IsDigraphByOutNeighboursRep, IsPosInt, IsPosInt], +function(D, v, pos) + if IsBound(D!.edgeweights) and v <= Length(D!.edgeweights) and pos <= Length(D!.edgeweights[v]) then + Remove(D!.edgeweights[v], pos); fi; +end); - oldWeights := EdgeWeights(oldDigraph); - newWeights := []; - shiftVertices := x -> x + Length(Filtered(removedVertices, v -> v <= x)); +InstallMethod(RemoveDigraphEdgeWeight, "for an immutable digraph, pos int, pos int", +[IsImmutableDigraph, IsPosInt, IsPosInt], +function(D, v, pos) + local newD, w; + newD := DigraphMutableCopy(D); - for i in [1 .. DigraphNrVertices(newDigraph)] do - newWeights[i] := []; - for j in OutNeighbours(newDigraph, i) do - weight := oldWeights[shiftVertices(i)][shiftVertices(j)]; - Add(newWeights[i], weight); - od; - od; + if IsBound(newD!.edgeweights) then + if v <= Length(newD!.edgeweights) + and pos <= Length(newD!.edgeweights[v]) then + Remove(newD!.edgeweights[v], pos); + fi; + fi; + + MakeImmutable(newD); + if IsBound(newD!.edgeweights) then + SetEdgeWeights(newD, StructuralCopy(newD!.edgeweights)); + fi; - SetEdgeWeights(newDigraph, newWeights); + return newD; end); diff --git a/gap/oper.gi b/gap/oper.gi index 990b44861..34a1a640f 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -103,58 +103,60 @@ function(D, m, labels) return DigraphAddVertices(D, labels); end); -InstallMethod(DigraphRemoveVertex, -"for a mutable digraph by out-neighbours and positive integer", +InstallMethod(DigraphRemoveVertex, "for a mutable digraph by out-neighbours and positive integer", [IsMutableDigraph and IsDigraphByOutNeighboursRep, IsPosInt], function(D, u) - local pos, w, v, oldD; - oldD := StructuralCopy(D); + local pos, w, v; + if u > DigraphNrVertices(D) then return D; fi; + RemoveDigraphVertexLabel(D, u); if IsBound(D!.edgelabels) then Remove(D!.edgelabels, u); fi; + Remove(D!.OutNeighbours, u); + if IsBound(D!.edgeweights) then + Remove(D!.edgeweights, u); + fi; + for v in DigraphVertices(D) do pos := 1; while pos <= Length(D!.OutNeighbours[v]) do w := D!.OutNeighbours[v][pos]; + if w = u then Remove(D!.OutNeighbours[v], pos); RemoveDigraphEdgeLabel(D, v, pos); + RemoveDigraphEdgeWeight(D, v, pos); + elif w > u then - D!.OutNeighbours[v][pos] := w - 1; - pos := pos + 1; + D!.OutNeighbours[v][pos] := w - 1; + pos := pos + 1; + else - pos := pos + 1; + pos := pos + 1; fi; od; od; - - if HasEdgeWeights(D) then - CopyEdgeWeightsForSubdigraph(oldD, D, [u]); - fi; - return D; end); -InstallMethod(DigraphRemoveVertex, -"for an immutable digraph and positive integer", +InstallMethod(DigraphRemoveVertex, "for an immutable digraph and positive integer", [IsImmutableDigraph, IsPosInt], function(D, u) local newD; - if u > DigraphNrVertices(D) then - return D; - fi; - newD := DigraphRemoveVertex(DigraphMutableCopy(D), u); - if HasEdgeWeights(D) then - CopyEdgeWeightsForSubdigraph(D, newD, [u]); - fi; + newD := DigraphMutableCopy(D); + DigraphRemoveVertex(newD, u); MakeImmutable(newD); + if IsBound(newD!.edgeweights) then + SetEdgeWeights(newD, StructuralCopy(newD!.edgeweights)); + fi; + return newD; end); @@ -237,11 +239,10 @@ InstallMethod(DigraphAddEdges, "for an immutable digraph and a list", [IsImmutableDigraph, IsList], {D, edges} -> MakeImmutable(DigraphAddEdges(DigraphMutableCopy(D), edges))); -InstallMethod(DigraphRemoveEdge, -"for a mutable digraph by out-neighbours and two positive integers", +InstallMethod(DigraphRemoveEdge, "for a mutable digraph by out-neighbours and two positive integers", [IsMutableDigraph and IsDigraphByOutNeighboursRep, IsPosInt, IsPosInt], function(D, src, ran) - local pos, weights; + local pos; if IsMultiDigraph(D) then ErrorNoReturn("the 1st argument must be a digraph with no multiple ", "edges,"); @@ -252,28 +253,33 @@ function(D, src, ran) ErrorNoReturn("the 3rd argument must be a vertex of the ", "digraph that is the 1st argument,"); fi; + pos := Position(D!.OutNeighbours[src], ran); + if pos <> fail then Remove(D!.OutNeighbours[src], pos); RemoveDigraphEdgeLabel(D, src, pos); - fi; - - if HasEdgeWeights(D) then - weights := StructuralCopy(EdgeWeights(D)); - if IsBound(weights[src]) and IsBound(weights[src][ran]) then - weights[src][ran] := fail; - fi; - SetEdgeWeights(D, weights); + RemoveDigraphEdgeWeight(D, src, pos); fi; return D; end); -InstallMethod(DigraphRemoveEdge, -"for a immutable digraph and two positive integers", +InstallMethod(DigraphRemoveEdge, "for a immutable digraph and two positive integers", [IsImmutableDigraph, IsPosInt, IsPosInt], -{D, src, ran} --> MakeImmutable(DigraphRemoveEdge(DigraphMutableCopy(D), src, ran))); +function(D, src, ran) + local newD; + + newD := DigraphMutableCopy(D); + DigraphRemoveEdge(newD, src, ran); + MakeImmutable(newD); + + if IsBound(newD!.edgeweights) then + SetEdgeWeights(newD, StructuralCopy(newD!.edgeweights)); + fi; + + return newD; +end); InstallMethod(DigraphRemoveEdge, "for a mutable digraph and a list", [IsMutableDigraph, IsList], diff --git a/tst/standard/digraph.tst b/tst/standard/digraph.tst index 25f8dcc53..311c80a32 100644 --- a/tst/standard/digraph.tst +++ b/tst/standard/digraph.tst @@ -13,7 +13,7 @@ #@local adjacencies, b, bin, c, c1, c2, d, di, digraph, divides, elms, eq #@local eq_distr, eq_new, error, f, failed, failed_names, failed_values, foo, g #@local gr, gr1, gr2, gr3, gr4, gr5, graph, graph1, graph2, grnc, group, h -#@local hom13, hom21, hom23, hom31, hom41, hom42, hom52, hom53, i, im, inn +#@local hom13, hom21, hom23, hom31, hom41, hom42, hom52, hom53, i, im, im2, inn #@local isGraph, iso, iso_distr, iso_new, j, k, list, m, main, mat, n, name #@local name2, names, new, order, p, prop, properties, r, r1, r2, record, rel1 #@local rel2, rel3, representatives, s, schreierVector, sgn, temp, test, v, x @@ -565,6 +565,63 @@ gap> OutNeighbours(D); gap> AsDigraph(AsPartialPerm((2, 5, 3)), 2); fail +# Tests for DigraphMutableCopy, DigraphImmutableCopy, RemoveDigraphEdgeWeight (mutable & immutable). +gap> d := EdgeWeightedDigraph([[2,3],[3],[],[]], [[5,10],[15],[],[]]); + +gap> HasEdgeWeights(d); +true +gap> EdgeWeights(d); +[ [ 5, 10 ], [ 15 ], [ ], [ ] ] +gap> m := DigraphMutableCopy(d); + +gap> IsMutableDigraph(m); +true +gap> OutNeighbours(m) = OutNeighbours(d); +true +gap> DigraphVertexLabels(m) = DigraphVertexLabels(d); +true +gap> HasEdgeWeights(m); +false +gap> IsBound(m!.edgeweights); +true +gap> m!.edgeweights = [[5,10],[15],[],[]]; +true +gap> m!.edgeweights[1][1] := 999; +999 +gap> EdgeWeights(d)[1][1]; +5 +gap> im := DigraphImmutableCopy(d); + +gap> IsImmutableDigraph(im); +true +gap> OutNeighbours(im) = OutNeighbours(d); +true +gap> HasEdgeWeights(im); +true +gap> EdgeWeights(im); +[ [ 5, 10 ], [ 15 ], [ ], [ ] ] +gap> EdgeWeights(im)[1][1] := 777; +Error, List Assignment: must be a mutable list +gap> EdgeWeights(d); +[ [ 5, 10 ], [ 15 ], [ ], [ ] ] +gap> m := DigraphMutableCopy(d); + +gap> RemoveDigraphEdgeWeight(m, 1, 2); +gap> m!.edgeweights; +[ [ 5 ], [ 15 ], [ ], [ ] ] +gap> EdgeWeights(d); +[ [ 5, 10 ], [ 15 ], [ ], [ ] ] +gap> im2 := DigraphImmutableCopy(d); + +gap> im2 := RemoveDigraphEdgeWeight(im2, 1, 2); + +gap> EdgeWeights(im2); +[ [ 5 ], [ 15 ], [ ], [ ] ] +gap> HasEdgeWeights(im2); +true +gap> EdgeWeights(d); +[ [ 5, 10 ], [ 15 ], [ ], [ ] ] + # RandomDigraph gap> IsImmutableDigraph(RandomDigraph(100, 0.2)); true diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index f4637c9a1..743b7e8e5 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -13,7 +13,7 @@ #@local G, G1, L, TestPartialOrderDigraph #@local TestPartialOrderDigraph2, TestUnion, a, adj, b, comps, copy, d, e #@local edges, edges2, func, g, gr, gr1, gr2, gr3, gr4, gri, grrt, grt, h, i -#@local i1, i2, id, idom, in1, in2, in3, iter, j1, j2, m, m1, m2, mat, n, nbs +#@local i1, i2, id, idom, in1, in2, in3, iter, j1, j2, m, m1, m2, m3, m4, im3, im4, mat, n, nbs #@local out, out1, out2, out3, p1, p2, path, preorder, qr, r, res, rtclosure, t #@local tclosure, u1, u2, x gap> START_TEST("Digraphs package: standard/oper.tst"); @@ -3299,6 +3299,46 @@ gap> DigraphEdges(D); gap> DigraphVertexLabels(D); [ 1, 2, 3, 6, [ 4, 5 ] ] +# Tests for DigraphRemoveVertex, DigraphRemoveVertex (immutable), DigraphRemoveEdge, DigraphRemoveEdge (immutable). +gap> d := EdgeWeightedDigraph([[2,3],[3],[],[]], [[5,10],[15],[],[]]); + +gap> m2 := DigraphMutableCopy(d); + +gap> DigraphRemoveEdge(m2, 1, 3); + +gap> OutNeighbours(m2); +[ [ 2 ], [ 3 ], [ ], [ ] ] +gap> m2!.edgeweights; +[ [ 5 ], [ 15 ], [ ], [ ] ] +gap> im3 := DigraphRemoveEdge(d, 1, 3); + +gap> IsImmutableDigraph(im3); +true +gap> OutNeighbours(im3); +[ [ 2 ], [ 3 ], [ ], [ ] ] +gap> EdgeWeights(im3); +[ [ 5 ], [ 15 ], [ ], [ ] ] +gap> m4 := DigraphMutableCopy(d); + +gap> DigraphRemoveVertex(m4, 1); + +gap> OutNeighbours(m4); +[ [ 2 ], [ ], [ ] ] +gap> m4!.edgeweights; +[ [ 15 ], [ ], [ ] ] +gap> im4 := DigraphRemoveVertex(d, 1); + +gap> IsImmutableDigraph(im4); +true +gap> OutNeighbours(im4); +[ [ 2 ], [ ], [ ] ] +gap> EdgeWeights(im4); +[ [ 15 ], [ ], [ ] ] +gap> OutNeighbours(d); +[ [ 2, 3 ], [ 3 ], [ ], [ ] ] +gap> EdgeWeights(d); +[ [ 5, 10 ], [ 15 ], [ ], [ ] ] + # gap> DIGRAPHS_StopTest(); gap> STOP_TEST("Digraphs package: standard/oper.tst", 0); From 3aa73d9dfbcdfb6a8413488f3c8468dad54d1762 Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Wed, 26 Nov 2025 12:53:04 +0000 Subject: [PATCH 06/18] Resolved comment on pr --- gap/digraph.gi | 4 ++-- gap/oper.gi | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gap/digraph.gi b/gap/digraph.gi index f44ae752f..7108e68b6 100644 --- a/gap/digraph.gi +++ b/gap/digraph.gi @@ -1870,7 +1870,7 @@ function(D, v, pos) local newD, w; newD := DigraphMutableCopy(D); - if IsBound(newD!.edgeweights) then + if HasEdgeWeights(D) then if v <= Length(newD!.edgeweights) and pos <= Length(newD!.edgeweights[v]) then Remove(newD!.edgeweights[v], pos); @@ -1878,7 +1878,7 @@ function(D, v, pos) fi; MakeImmutable(newD); - if IsBound(newD!.edgeweights) then + if HasEdgeWeights(D) then SetEdgeWeights(newD, StructuralCopy(newD!.edgeweights)); fi; diff --git a/gap/oper.gi b/gap/oper.gi index 34a1a640f..556b89359 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -153,7 +153,7 @@ function(D, u) DigraphRemoveVertex(newD, u); MakeImmutable(newD); - if IsBound(newD!.edgeweights) then + if HasEdgeWeights(D) then SetEdgeWeights(newD, StructuralCopy(newD!.edgeweights)); fi; @@ -274,7 +274,7 @@ function(D, src, ran) DigraphRemoveEdge(newD, src, ran); MakeImmutable(newD); - if IsBound(newD!.edgeweights) then + if HasEdgeWeights(D) then SetEdgeWeights(newD, StructuralCopy(newD!.edgeweights)); fi; From 5705fd39d9a39b9ce0990bfef7e954e58f627095 Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Tue, 2 Dec 2025 10:19:54 +0000 Subject: [PATCH 07/18] Revereted mutable fucntions and updated immutable functions to store the weights correctly. Split the DigraphImmutableCopy into a helper DigraphImmutableCopyNoWeights to copy the weights correctly. --- gap/digraph.gd | 2 +- gap/digraph.gi | 76 +++++++++++++--------------------------- gap/oper.gi | 75 ++++++++++++++++++++++----------------- tst/standard/digraph.tst | 31 ++-------------- tst/standard/oper.tst | 38 +++++++------------- 5 files changed, 82 insertions(+), 140 deletions(-) diff --git a/gap/digraph.gd b/gap/digraph.gd index 758606213..79cd91825 100644 --- a/gap/digraph.gd +++ b/gap/digraph.gd @@ -153,4 +153,4 @@ DeclareOperation("RandomLattice", [IsFunction, IsPosInt]); DeclareOperation("RandomMultiDigraph", [IsPosInt]); DeclareOperation("RandomMultiDigraph", [IsPosInt, IsPosInt]); -DeclareOperation("RemoveDigraphEdgeWeight", [IsDigraph, IsPosInt, IsPosInt]); \ No newline at end of file +DeclareOperation("DigraphImmutableCopyNoWeights", [IsDigraph]); \ No newline at end of file diff --git a/gap/digraph.gi b/gap/digraph.gi index 7108e68b6..a4ac47c1f 100644 --- a/gap/digraph.gi +++ b/gap/digraph.gi @@ -167,42 +167,43 @@ InstallMethod(DigraphMutableCopy, "for a digraph by out-neighbours", [IsDigraphByOutNeighboursRep], function(D) local copy; - copy := ConvertToMutableDigraphNC(OutNeighboursMutableCopy(D)); SetDigraphVertexLabels(copy, StructuralCopy(DigraphVertexLabels(D))); - if HaveEdgeLabelsBeenAssigned(D) then SetDigraphEdgeLabelsNC(copy, StructuralCopy(DigraphEdgeLabelsNC(D))); fi; - - if IsImmutableDigraph(D) and HasEdgeWeights(D) then - copy!.edgeweights := EdgeWeightsMutableCopy(D); - elif IsMutableDigraph(D) and IsBound(D!.edgeweights) then - copy!.edgeweights := StructuralCopy(D!.edgeweights); - fi; - return copy; end); -InstallMethod(DigraphImmutableCopy, "for a digraph by out-neighbours", +InstallMethod(DigraphImmutableCopy, +"for a digraph by out-neighbours", [IsDigraphByOutNeighboursRep], function(D) - local copy; + local copy, weights; + copy := DigraphImmutableCopyNoWeights(D); + + if HasEdgeWeights(D) then + weights := EdgeWeightsMutableCopy(D); + SetEdgeWeights(copy, weights); + fi; - copy := ConvertToImmutableDigraphNC(OutNeighboursMutableCopy(D)); - SetDigraphVertexLabels(copy, StructuralCopy(DigraphVertexLabels(D))); + return copy; +end); - if HaveEdgeLabelsBeenAssigned(D) then - SetDigraphEdgeLabelsNC(copy, StructuralCopy(DigraphEdgeLabelsNC(D))); - fi; +InstallMethod(DigraphImmutableCopyNoWeights, +"for a digraph by out-neighbours", +[IsDigraphByOutNeighboursRep], +function(D) + local copy; - if IsImmutableDigraph(D) and HasEdgeWeights(D) then - SetEdgeWeights(copy, StructuralCopy(EdgeWeights(D))); - elif IsMutableDigraph(D) and IsBound(D!.edgeweights) then - SetEdgeWeights(copy, StructuralCopy(D!.edgeweights)); - fi; + copy := ConvertToImmutableDigraphNC(OutNeighboursMutableCopy(D)); + SetDigraphVertexLabels(copy, StructuralCopy(DigraphVertexLabels(D))); - return copy; + if HaveEdgeLabelsBeenAssigned(D) then + SetDigraphEdgeLabelsNC(copy, StructuralCopy(DigraphEdgeLabelsNC(D))); + fi; + + return copy; end); InstallMethod(DigraphCopySameMutability, "for a mutable digraph", @@ -1854,33 +1855,4 @@ InstallMethod(RandomLattice, "for a pos int", [IsPosInt], n -> RandomLatticeCons(IsImmutableDigraph, n)); InstallMethod(RandomLattice, "for a func and a pos int", [IsFunction, IsPosInt], -RandomLatticeCons); - -InstallMethod(RemoveDigraphEdgeWeight, "for a mutable digraph, pos int, pos int", -[IsMutableDigraph and IsDigraphByOutNeighboursRep, IsPosInt, IsPosInt], -function(D, v, pos) - if IsBound(D!.edgeweights) and v <= Length(D!.edgeweights) and pos <= Length(D!.edgeweights[v]) then - Remove(D!.edgeweights[v], pos); - fi; -end); - -InstallMethod(RemoveDigraphEdgeWeight, "for an immutable digraph, pos int, pos int", -[IsImmutableDigraph, IsPosInt, IsPosInt], -function(D, v, pos) - local newD, w; - newD := DigraphMutableCopy(D); - - if HasEdgeWeights(D) then - if v <= Length(newD!.edgeweights) - and pos <= Length(newD!.edgeweights[v]) then - Remove(newD!.edgeweights[v], pos); - fi; - fi; - - MakeImmutable(newD); - if HasEdgeWeights(D) then - SetEdgeWeights(newD, StructuralCopy(newD!.edgeweights)); - fi; - - return newD; -end); +RandomLatticeCons); \ No newline at end of file diff --git a/gap/oper.gi b/gap/oper.gi index 556b89359..f2002aaa4 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -103,61 +103,63 @@ function(D, m, labels) return DigraphAddVertices(D, labels); end); -InstallMethod(DigraphRemoveVertex, "for a mutable digraph by out-neighbours and positive integer", +InstallMethod(DigraphRemoveVertex, +"for a mutable digraph by out-neighbours and positive integer", [IsMutableDigraph and IsDigraphByOutNeighboursRep, IsPosInt], function(D, u) local pos, w, v; - if u > DigraphNrVertices(D) then return D; fi; - RemoveDigraphVertexLabel(D, u); if IsBound(D!.edgelabels) then Remove(D!.edgelabels, u); fi; - Remove(D!.OutNeighbours, u); - if IsBound(D!.edgeweights) then - Remove(D!.edgeweights, u); - fi; - for v in DigraphVertices(D) do pos := 1; while pos <= Length(D!.OutNeighbours[v]) do w := D!.OutNeighbours[v][pos]; - if w = u then Remove(D!.OutNeighbours[v], pos); RemoveDigraphEdgeLabel(D, v, pos); - RemoveDigraphEdgeWeight(D, v, pos); - elif w > u then - D!.OutNeighbours[v][pos] := w - 1; - pos := pos + 1; - + D!.OutNeighbours[v][pos] := w - 1; + pos := pos + 1; else - pos := pos + 1; + pos := pos + 1; fi; od; od; return D; end); -InstallMethod(DigraphRemoveVertex, "for an immutable digraph and positive integer", +InstallMethod(DigraphRemoveVertex, +"for an immutable digraph and positive integer", [IsImmutableDigraph, IsPosInt], function(D, u) - local newD; + local newD, weights; - newD := DigraphMutableCopy(D); - DigraphRemoveVertex(newD, u); - MakeImmutable(newD); + if u > DigraphNrVertices(D) then + return D; + fi; - if HasEdgeWeights(D) then - SetEdgeWeights(newD, StructuralCopy(newD!.edgeweights)); - fi; + newD := DigraphImmutableCopyNoWeights(D); + newD := DigraphMutableCopy(newD); + DigraphRemoveVertex(newD, u); + MakeImmutable(newD); + + if HasEdgeWeights(D) then + weights := EdgeWeightsMutableCopy(D); + + if u <= Length(weights) then + Remove(weights, u); + fi; + + SetEdgeWeights(newD, weights); + fi; - return newD; + return newD; end); InstallMethod(DigraphRemoveVertices, "for a mutable digraph and a list", @@ -239,7 +241,8 @@ InstallMethod(DigraphAddEdges, "for an immutable digraph and a list", [IsImmutableDigraph, IsList], {D, edges} -> MakeImmutable(DigraphAddEdges(DigraphMutableCopy(D), edges))); -InstallMethod(DigraphRemoveEdge, "for a mutable digraph by out-neighbours and two positive integers", +InstallMethod(DigraphRemoveEdge, +"for a mutable digraph by out-neighbours and two positive integers", [IsMutableDigraph and IsDigraphByOutNeighboursRep, IsPosInt, IsPosInt], function(D, src, ran) local pos; @@ -253,29 +256,35 @@ function(D, src, ran) ErrorNoReturn("the 3rd argument must be a vertex of the ", "digraph that is the 1st argument,"); fi; - pos := Position(D!.OutNeighbours[src], ran); - if pos <> fail then Remove(D!.OutNeighbours[src], pos); RemoveDigraphEdgeLabel(D, src, pos); - RemoveDigraphEdgeWeight(D, src, pos); fi; - return D; end); -InstallMethod(DigraphRemoveEdge, "for a immutable digraph and two positive integers", +InstallMethod(DigraphRemoveEdge, +"for an immutable digraph and two positive integers", [IsImmutableDigraph, IsPosInt, IsPosInt], function(D, src, ran) - local newD; + local newD, weights, pos, outs; - newD := DigraphMutableCopy(D); + newD := DigraphImmutableCopyNoWeights(D); + newD := DigraphMutableCopy(newD); DigraphRemoveEdge(newD, src, ran); MakeImmutable(newD); if HasEdgeWeights(D) then - SetEdgeWeights(newD, StructuralCopy(newD!.edgeweights)); + weights := EdgeWeightsMutableCopy(D); + outs := OutNeighbours(D)[src]; + pos := Position(outs, ran); + + if pos <> fail and pos <= Length(weights[src]) then + Remove(weights[src], pos); + fi; + + SetEdgeWeights(newD, weights); fi; return newD; diff --git a/tst/standard/digraph.tst b/tst/standard/digraph.tst index 311c80a32..9fcc1a9d4 100644 --- a/tst/standard/digraph.tst +++ b/tst/standard/digraph.tst @@ -565,31 +565,13 @@ gap> OutNeighbours(D); gap> AsDigraph(AsPartialPerm((2, 5, 3)), 2); fail -# Tests for DigraphMutableCopy, DigraphImmutableCopy, RemoveDigraphEdgeWeight (mutable & immutable). +# Tests for DigraphImmutableCopy gap> d := EdgeWeightedDigraph([[2,3],[3],[],[]], [[5,10],[15],[],[]]); gap> HasEdgeWeights(d); true gap> EdgeWeights(d); [ [ 5, 10 ], [ 15 ], [ ], [ ] ] -gap> m := DigraphMutableCopy(d); - -gap> IsMutableDigraph(m); -true -gap> OutNeighbours(m) = OutNeighbours(d); -true -gap> DigraphVertexLabels(m) = DigraphVertexLabels(d); -true -gap> HasEdgeWeights(m); -false -gap> IsBound(m!.edgeweights); -true -gap> m!.edgeweights = [[5,10],[15],[],[]]; -true -gap> m!.edgeweights[1][1] := 999; -999 -gap> EdgeWeights(d)[1][1]; -5 gap> im := DigraphImmutableCopy(d); gap> IsImmutableDigraph(im); @@ -604,17 +586,10 @@ gap> EdgeWeights(im)[1][1] := 777; Error, List Assignment: must be a mutable list gap> EdgeWeights(d); [ [ 5, 10 ], [ 15 ], [ ], [ ] ] -gap> m := DigraphMutableCopy(d); - -gap> RemoveDigraphEdgeWeight(m, 1, 2); -gap> m!.edgeweights; -[ [ 5 ], [ 15 ], [ ], [ ] ] -gap> EdgeWeights(d); -[ [ 5, 10 ], [ 15 ], [ ], [ ] ] gap> im2 := DigraphImmutableCopy(d); -gap> im2 := RemoveDigraphEdgeWeight(im2, 1, 2); - +gap> im2 := DigraphRemoveEdge(im2, 1, 3); + gap> EdgeWeights(im2); [ [ 5 ], [ 15 ], [ ], [ ] ] gap> HasEdgeWeights(im2); diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index 743b7e8e5..bc139eb9e 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -15,7 +15,7 @@ #@local edges, edges2, func, g, gr, gr1, gr2, gr3, gr4, gri, grrt, grt, h, i #@local i1, i2, id, idom, in1, in2, in3, iter, j1, j2, m, m1, m2, m3, m4, im3, im4, mat, n, nbs #@local out, out1, out2, out3, p1, p2, path, preorder, qr, r, res, rtclosure, t -#@local tclosure, u1, u2, x +#@local tclosure, u1, u2, x, imE, imV gap> START_TEST("Digraphs package: standard/oper.tst"); gap> LoadPackage("digraphs", false);; @@ -3299,40 +3299,26 @@ gap> DigraphEdges(D); gap> DigraphVertexLabels(D); [ 1, 2, 3, 6, [ 4, 5 ] ] -# Tests for DigraphRemoveVertex, DigraphRemoveVertex (immutable), DigraphRemoveEdge, DigraphRemoveEdge (immutable). +# Tests for DigraphRemoveVertex (immutable) and DigraphRemoveEdge (immutable). gap> d := EdgeWeightedDigraph([[2,3],[3],[],[]], [[5,10],[15],[],[]]); -gap> m2 := DigraphMutableCopy(d); - -gap> DigraphRemoveEdge(m2, 1, 3); - -gap> OutNeighbours(m2); -[ [ 2 ], [ 3 ], [ ], [ ] ] -gap> m2!.edgeweights; -[ [ 5 ], [ 15 ], [ ], [ ] ] -gap> im3 := DigraphRemoveEdge(d, 1, 3); +gap> imE := DigraphRemoveEdge(d, 1, 3); -gap> IsImmutableDigraph(im3); +gap> IsImmutableDigraph(imE); true -gap> OutNeighbours(im3); +gap> OutNeighbours(imE); [ [ 2 ], [ 3 ], [ ], [ ] ] -gap> EdgeWeights(im3); +gap> EdgeWeights(imE); [ [ 5 ], [ 15 ], [ ], [ ] ] -gap> m4 := DigraphMutableCopy(d); - -gap> DigraphRemoveVertex(m4, 1); - -gap> OutNeighbours(m4); -[ [ 2 ], [ ], [ ] ] -gap> m4!.edgeweights; -[ [ 15 ], [ ], [ ] ] -gap> im4 := DigraphRemoveVertex(d, 1); +gap> EdgeWeights(d); +[ [ 5, 10 ], [ 15 ], [ ], [ ] ] +gap> imV := DigraphRemoveVertex(d, 1); -gap> IsImmutableDigraph(im4); +gap> IsImmutableDigraph(imV); true -gap> OutNeighbours(im4); +gap> OutNeighbours(imV); [ [ 2 ], [ ], [ ] ] -gap> EdgeWeights(im4); +gap> EdgeWeights(imV); [ [ 15 ], [ ], [ ] ] gap> OutNeighbours(d); [ [ 2, 3 ], [ 3 ], [ ], [ ] ] From dfaf92dfa75b181d0d2d280727eed9c5138bca44 Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Tue, 2 Dec 2025 10:26:18 +0000 Subject: [PATCH 08/18] Cleaning up code --- gap/digraph.gi | 30 ++++++++++----------- gap/oper.gi | 62 +++++++++++++++++++++---------------------- tst/standard/oper.tst | 2 +- 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/gap/digraph.gi b/gap/digraph.gi index a4ac47c1f..30bf01bb6 100644 --- a/gap/digraph.gi +++ b/gap/digraph.gi @@ -179,31 +179,31 @@ InstallMethod(DigraphImmutableCopy, "for a digraph by out-neighbours", [IsDigraphByOutNeighboursRep], function(D) - local copy, weights; - copy := DigraphImmutableCopyNoWeights(D); - - if HasEdgeWeights(D) then - weights := EdgeWeightsMutableCopy(D); - SetEdgeWeights(copy, weights); - fi; + local copy, weights; + copy := DigraphImmutableCopyNoWeights(D); + + if HasEdgeWeights(D) then + weights := EdgeWeightsMutableCopy(D); + SetEdgeWeights(copy, weights); + fi; - return copy; + return copy; end); InstallMethod(DigraphImmutableCopyNoWeights, "for a digraph by out-neighbours", [IsDigraphByOutNeighboursRep], function(D) - local copy; + local copy; - copy := ConvertToImmutableDigraphNC(OutNeighboursMutableCopy(D)); - SetDigraphVertexLabels(copy, StructuralCopy(DigraphVertexLabels(D))); + copy := ConvertToImmutableDigraphNC(OutNeighboursMutableCopy(D)); + SetDigraphVertexLabels(copy, StructuralCopy(DigraphVertexLabels(D))); - if HaveEdgeLabelsBeenAssigned(D) then - SetDigraphEdgeLabelsNC(copy, StructuralCopy(DigraphEdgeLabelsNC(D))); - fi; + if HaveEdgeLabelsBeenAssigned(D) then + SetDigraphEdgeLabelsNC(copy, StructuralCopy(DigraphEdgeLabelsNC(D))); + fi; - return copy; + return copy; end); InstallMethod(DigraphCopySameMutability, "for a mutable digraph", diff --git a/gap/oper.gi b/gap/oper.gi index f2002aaa4..22d1aea89 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -138,28 +138,28 @@ InstallMethod(DigraphRemoveVertex, "for an immutable digraph and positive integer", [IsImmutableDigraph, IsPosInt], function(D, u) - local newD, weights; + local newD, weights; - if u > DigraphNrVertices(D) then - return D; - fi; + if u > DigraphNrVertices(D) then + return D; + fi; - newD := DigraphImmutableCopyNoWeights(D); - newD := DigraphMutableCopy(newD); - DigraphRemoveVertex(newD, u); - MakeImmutable(newD); + newD := DigraphImmutableCopyNoWeights(D); + newD := DigraphMutableCopy(newD); + DigraphRemoveVertex(newD, u); + MakeImmutable(newD); - if HasEdgeWeights(D) then - weights := EdgeWeightsMutableCopy(D); + if HasEdgeWeights(D) then + weights := EdgeWeightsMutableCopy(D); - if u <= Length(weights) then - Remove(weights, u); - fi; + if u <= Length(weights) then + Remove(weights, u); + fi; - SetEdgeWeights(newD, weights); - fi; + SetEdgeWeights(newD, weights); + fi; - return newD; + return newD; end); InstallMethod(DigraphRemoveVertices, "for a mutable digraph and a list", @@ -268,26 +268,26 @@ InstallMethod(DigraphRemoveEdge, "for an immutable digraph and two positive integers", [IsImmutableDigraph, IsPosInt, IsPosInt], function(D, src, ran) - local newD, weights, pos, outs; + local newD, weights, pos, outs; - newD := DigraphImmutableCopyNoWeights(D); - newD := DigraphMutableCopy(newD); - DigraphRemoveEdge(newD, src, ran); - MakeImmutable(newD); + newD := DigraphImmutableCopyNoWeights(D); + newD := DigraphMutableCopy(newD); + DigraphRemoveEdge(newD, src, ran); + MakeImmutable(newD); - if HasEdgeWeights(D) then - weights := EdgeWeightsMutableCopy(D); - outs := OutNeighbours(D)[src]; - pos := Position(outs, ran); + if HasEdgeWeights(D) then + weights := EdgeWeightsMutableCopy(D); + outs := OutNeighbours(D)[src]; + pos := Position(outs, ran); - if pos <> fail and pos <= Length(weights[src]) then - Remove(weights[src], pos); - fi; + if pos <> fail and pos <= Length(weights[src]) then + Remove(weights[src], pos); + fi; - SetEdgeWeights(newD, weights); - fi; + SetEdgeWeights(newD, weights); + fi; - return newD; + return newD; end); InstallMethod(DigraphRemoveEdge, "for a mutable digraph and a list", diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index bc139eb9e..761d2943b 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -13,7 +13,7 @@ #@local G, G1, L, TestPartialOrderDigraph #@local TestPartialOrderDigraph2, TestUnion, a, adj, b, comps, copy, d, e #@local edges, edges2, func, g, gr, gr1, gr2, gr3, gr4, gri, grrt, grt, h, i -#@local i1, i2, id, idom, in1, in2, in3, iter, j1, j2, m, m1, m2, m3, m4, im3, im4, mat, n, nbs +#@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, imE, imV gap> START_TEST("Digraphs package: standard/oper.tst"); From ecb2300311052719d2538c3193e96b46b27f8c69 Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Tue, 2 Dec 2025 11:51:35 +0000 Subject: [PATCH 09/18] Fixed lint formatting --- gap/digraph.gi | 2 +- tst/standard/digraph.tst | 2 +- tst/standard/oper.tst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gap/digraph.gi b/gap/digraph.gi index 04bf63bc8..4e068ac19 100644 --- a/gap/digraph.gi +++ b/gap/digraph.gi @@ -181,7 +181,7 @@ InstallMethod(DigraphImmutableCopy, function(D) local copy, weights; copy := DigraphImmutableCopyNoWeights(D); - + if HasEdgeWeights(D) then weights := EdgeWeightsMutableCopy(D); SetEdgeWeights(copy, weights); diff --git a/tst/standard/digraph.tst b/tst/standard/digraph.tst index 9fcc1a9d4..f97a956c4 100644 --- a/tst/standard/digraph.tst +++ b/tst/standard/digraph.tst @@ -566,7 +566,7 @@ gap> AsDigraph(AsPartialPerm((2, 5, 3)), 2); fail # Tests for DigraphImmutableCopy -gap> d := EdgeWeightedDigraph([[2,3],[3],[],[]], [[5,10],[15],[],[]]); +gap> d := EdgeWeightedDigraph([ [ 2, 3 ], [ 3 ], [ ], [ ] ], [ [ 5, 10 ], [ 15 ], [ ], [ ] ]); gap> HasEdgeWeights(d); true diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index 8a6e8c007..8c1e25541 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -3325,7 +3325,7 @@ gap> DigraphVertexLabels(D); [ 1, 2, 3, 6, [ 4, 5 ] ] # Tests for DigraphRemoveVertex (immutable) and DigraphRemoveEdge (immutable). -gap> d := EdgeWeightedDigraph([[2,3],[3],[],[]], [[5,10],[15],[],[]]); +gap> d := EdgeWeightedDigraph([ [ 2, 3 ], [ 3 ], [ ], [ ] ], [ [ 5, 10 ], [ 15 ], [ ], [ ] ]); gap> imE := DigraphRemoveEdge(d, 1, 3); From 8c656391a54e3282df44e2d6f973470b9189f5d6 Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Tue, 2 Dec 2025 11:56:03 +0000 Subject: [PATCH 10/18] Lint formatting --- tst/standard/digraph.tst | 2 +- tst/standard/oper.tst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tst/standard/digraph.tst b/tst/standard/digraph.tst index f97a956c4..9d0aaeede 100644 --- a/tst/standard/digraph.tst +++ b/tst/standard/digraph.tst @@ -566,7 +566,7 @@ gap> AsDigraph(AsPartialPerm((2, 5, 3)), 2); fail # Tests for DigraphImmutableCopy -gap> d := EdgeWeightedDigraph([ [ 2, 3 ], [ 3 ], [ ], [ ] ], [ [ 5, 10 ], [ 15 ], [ ], [ ] ]); +gap> d := EdgeWeightedDigraph([[2, 3], [3], [], []], [[5, 10], [15], [], []]); gap> HasEdgeWeights(d); true diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index 8c1e25541..9ea9ecd16 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -3325,7 +3325,7 @@ gap> DigraphVertexLabels(D); [ 1, 2, 3, 6, [ 4, 5 ] ] # Tests for DigraphRemoveVertex (immutable) and DigraphRemoveEdge (immutable). -gap> d := EdgeWeightedDigraph([ [ 2, 3 ], [ 3 ], [ ], [ ] ], [ [ 5, 10 ], [ 15 ], [ ], [ ] ]); +gap> d := EdgeWeightedDigraph([[2, 3], [3], [], []], [[5, 10], [15], [], []]); gap> imE := DigraphRemoveEdge(d, 1, 3); From 3f9fe0c4aa4621e0dfa68662ea790b531f0ac53b Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Wed, 3 Dec 2025 08:42:46 +0000 Subject: [PATCH 11/18] Added documentation --- doc/digraph.xml | 31 ++++++++++++++++++++++++++++++- doc/oper.xml | 10 ++++++---- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/doc/digraph.xml b/doc/digraph.xml index 05e578e11..d2d62670c 100644 --- a/doc/digraph.xml +++ b/doc/digraph.xml @@ -506,7 +506,7 @@ gap> D := AsDigraph(b); Each of these operations returns a new copy of digraph, of the appropriate mutability, retaining none of the attributes or - properties of digraph.

+ properties of digraph, with the exception that edge weights are preserved.

DigraphCopy is a synonym for DigraphCopySameMutability. <#/GAPDoc> +<#GAPDoc Label="DigraphImmutableCopyNoWeights"> + + + An immutable digraph. + + This operation returns an immutable copy of digraph that is + identical to , except that any edge + weights that digraph may have are not copied to the returned + digraph.

+ + This can be useful when modifying the structure of a digraph with + or , + where the weights need to be updated to match the new structure, + rather than simply copied.

+ + D := EdgeWeightedDigraph([[2, 3], [3], []], [[2, 5], [3], []]); + +gap> HasEdgeWeights(D); +true +gap> D2 := DigraphImmutableCopyNoWeights(D); + +gap> HasEdgeWeights(D2); +false +]]> + + +<#/GAPDoc> + <#GAPDoc Label="AsBinaryRelation"> diff --git a/doc/oper.xml b/doc/oper.xml index 0930e8f3c..74a1659c2 100644 --- a/doc/oper.xml +++ b/doc/oper.xml @@ -520,6 +520,9 @@ true digraph are [1..n-1], but the original labels can be accessed via .

+ If digraph has edge weights, then the returned digraph will also have edge weights with the weights updated + to reflect the removal of the vertex and its associated edges.

+ If digraph belongs to , then the vertex is removed directly from digraph. If digraph belongs to , an immutable copy of digraph @@ -702,6 +705,9 @@ true constructed from digraph by removing the edge specified by edge or [src, ran].

+ If digraph has edge weights then the returned digraph will also have edge weights with the weight for the + removed edge no longer present.

+ If digraph belongs to , then the edge is removed directly from digraph. If digraph belongs to - Note that if digraph belongs to , - then a new copy of digraph will be returned even if edge or - [src, ran] does not define an edge of digraph.

- D := CycleDigraph(250000); From 2bec6121dddde5171169e8223bd634f56a4a225d Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Wed, 3 Dec 2025 09:05:29 +0000 Subject: [PATCH 12/18] Added documentation --- doc/oper.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/oper.xml b/doc/oper.xml index 74a1659c2..5d5ec1fdb 100644 --- a/doc/oper.xml +++ b/doc/oper.xml @@ -715,6 +715,10 @@ true the edge is returned.

+ Note that if digraph belongs to , + then a new copy of digraph will be returned even if edge or + [src, ran] does not define an edge of digraph.

+ D := CycleDigraph(250000); From 1ec52733faaa72078daf29aa00efd535a8845924 Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Wed, 3 Dec 2025 09:11:29 +0000 Subject: [PATCH 13/18] Fixed formatting --- gap/digraph.gi | 6 +++--- gap/oper.gi | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/gap/digraph.gi b/gap/digraph.gi index 4e068ac19..82db0d26d 100644 --- a/gap/digraph.gi +++ b/gap/digraph.gi @@ -183,8 +183,8 @@ function(D) copy := DigraphImmutableCopyNoWeights(D); if HasEdgeWeights(D) then - weights := EdgeWeightsMutableCopy(D); - SetEdgeWeights(copy, weights); + weights := EdgeWeightsMutableCopy(D); + SetEdgeWeights(copy, weights); fi; return copy; @@ -200,7 +200,7 @@ function(D) SetDigraphVertexLabels(copy, StructuralCopy(DigraphVertexLabels(D))); if HaveEdgeLabelsBeenAssigned(D) then - SetDigraphEdgeLabelsNC(copy, StructuralCopy(DigraphEdgeLabelsNC(D))); + SetDigraphEdgeLabelsNC(copy, StructuralCopy(DigraphEdgeLabelsNC(D))); fi; return copy; diff --git a/gap/oper.gi b/gap/oper.gi index 4518b2ea2..9197c56a7 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -141,7 +141,7 @@ function(D, u) local newD, weights; if u > DigraphNrVertices(D) then - return D; + return D; fi; newD := DigraphImmutableCopyNoWeights(D); @@ -150,13 +150,13 @@ function(D, u) MakeImmutable(newD); if HasEdgeWeights(D) then - weights := EdgeWeightsMutableCopy(D); + weights := EdgeWeightsMutableCopy(D); - if u <= Length(weights) then - Remove(weights, u); - fi; + if u <= Length(weights) then + Remove(weights, u); + fi; - SetEdgeWeights(newD, weights); + SetEdgeWeights(newD, weights); fi; return newD; @@ -276,15 +276,15 @@ function(D, src, ran) MakeImmutable(newD); if HasEdgeWeights(D) then - weights := EdgeWeightsMutableCopy(D); - outs := OutNeighbours(D)[src]; - pos := Position(outs, ran); + weights := EdgeWeightsMutableCopy(D); + outs := OutNeighbours(D)[src]; + pos := Position(outs, ran); - if pos <> fail and pos <= Length(weights[src]) then - Remove(weights[src], pos); - fi; + if pos <> fail and pos <= Length(weights[src]) then + Remove(weights[src], pos); + fi; - SetEdgeWeights(newD, weights); + SetEdgeWeights(newD, weights); fi; return newD; From d58bc279522a6e9958fcf9396e00019a6d53a688 Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Wed, 3 Dec 2025 16:07:47 +0000 Subject: [PATCH 14/18] Added DigraphImmutableCopyNoWeights in chap5.xml --- doc/z-chap5.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/z-chap5.xml b/doc/z-chap5.xml index 759876e11..b5f634890 100644 --- a/doc/z-chap5.xml +++ b/doc/z-chap5.xml @@ -33,6 +33,7 @@ <#Include Label="EdgeWeightedDigraphShortestPath"> <#Include Label="DigraphMaximumFlow"> <#Include Label="RandomUniqueEdgeWeightedDigraph"> + <#Include Label="DigraphImmutableCopyNoWeights">

Orders From b6712a8ebbd2bf4e665957ff78e6d7ed0fa64f24 Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Wed, 3 Dec 2025 16:20:21 +0000 Subject: [PATCH 15/18] Added edge-weighted to the failing tests --- doc/digraph.xml | 2 +- tst/standard/digraph.tst | 8 ++++---- tst/standard/oper.tst | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/digraph.xml b/doc/digraph.xml index d2d62670c..5d91e9787 100644 --- a/doc/digraph.xml +++ b/doc/digraph.xml @@ -602,7 +602,7 @@ true]]> D := EdgeWeightedDigraph([[2, 3], [3], []], [[2, 5], [3], []]); - + gap> HasEdgeWeights(D); true gap> D2 := DigraphImmutableCopyNoWeights(D); diff --git a/tst/standard/digraph.tst b/tst/standard/digraph.tst index 9d0aaeede..1673d5a8d 100644 --- a/tst/standard/digraph.tst +++ b/tst/standard/digraph.tst @@ -567,13 +567,13 @@ fail # Tests for DigraphImmutableCopy gap> d := EdgeWeightedDigraph([[2, 3], [3], [], []], [[5, 10], [15], [], []]); - + gap> HasEdgeWeights(d); true gap> EdgeWeights(d); [ [ 5, 10 ], [ 15 ], [ ], [ ] ] gap> im := DigraphImmutableCopy(d); - + gap> IsImmutableDigraph(im); true gap> OutNeighbours(im) = OutNeighbours(d); @@ -587,9 +587,9 @@ Error, List Assignment: must be a mutable list gap> EdgeWeights(d); [ [ 5, 10 ], [ 15 ], [ ], [ ] ] gap> im2 := DigraphImmutableCopy(d); - + gap> im2 := DigraphRemoveEdge(im2, 1, 3); - + gap> EdgeWeights(im2); [ [ 5 ], [ 15 ], [ ], [ ] ] gap> HasEdgeWeights(im2); diff --git a/tst/standard/oper.tst b/tst/standard/oper.tst index 9ea9ecd16..35dd7175c 100644 --- a/tst/standard/oper.tst +++ b/tst/standard/oper.tst @@ -3326,9 +3326,9 @@ gap> DigraphVertexLabels(D); # Tests for DigraphRemoveVertex (immutable) and DigraphRemoveEdge (immutable). gap> d := EdgeWeightedDigraph([[2, 3], [3], [], []], [[5, 10], [15], [], []]); - + gap> imE := DigraphRemoveEdge(d, 1, 3); - + gap> IsImmutableDigraph(imE); true gap> OutNeighbours(imE); @@ -3338,7 +3338,7 @@ gap> EdgeWeights(imE); gap> EdgeWeights(d); [ [ 5, 10 ], [ 15 ], [ ], [ ] ] gap> imV := DigraphRemoveVertex(d, 1); - + gap> IsImmutableDigraph(imV); true gap> OutNeighbours(imV); From 1d1f57c72365bb9c329ac938839cf83ea9530d28 Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Thu, 11 Dec 2025 19:26:42 +0000 Subject: [PATCH 16/18] Fixed documentation for DigraphRemoveEdge(s) --- doc/oper.xml | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/doc/oper.xml b/doc/oper.xml index 5d5ec1fdb..7579f6527 100644 --- a/doc/oper.xml +++ b/doc/oper.xml @@ -715,22 +715,22 @@ true the edge is returned.

- Note that if digraph belongs to , - then a new copy of digraph will be returned even if edge or - [src, ran] does not define an edge of digraph.

+ An error is raised if edge or [src, ran] does not define an + edge of digraph.

D := CycleDigraph(250000); gap> D := DigraphRemoveEdge(D, [250000, 1]); -gap> new := DigraphRemoveEdge(D, [25000, 2]);; +gap> new := DigraphRemoveEdge(D, [1, 2]); + gap> new = D; -true +false gap> IsIdenticalObj(new, D); false gap> D := DigraphMutableCopy(D);; -gap> new := DigraphRemoveEdge(D, 2500, 2);; +gap> new := DigraphRemoveEdge(D, 2, 3);; gap> IsIdenticalObj(new, D); true]]> @@ -762,10 +762,8 @@ true]]> Filt="IsImmutableDigraph"/>, the edge is removed from an immutable copy of digraph and this new digraph is returned.

- Note that if edges is empty, then this operation - will always return digraph rather than a copy. Also, if any element - of edges is invalid (i.e. does not define an edge of digraph) - then that element will simply be ignored. + An error is raised if any element of edges is invalid (i.e does not + define an edge of digraph). D := CycleDigraph(250000); @@ -774,8 +772,8 @@ gap> D := DigraphRemoveEdges(D, [[250000, 1]]); gap> D := DigraphMutableCopy(D); -gap> new := DigraphRemoveEdges(D, [[1, 2], [2, 3], [3, 100]]); - +gap> new := DigraphRemoveEdges(D, [[1, 2], [2, 3], [3, 4]]); + gap> new = D; true ]]> From dee0c4567bedea25d6f0003b4a265219d40d7c9c Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Thu, 11 Dec 2025 19:41:50 +0000 Subject: [PATCH 17/18] Fix DigraphRemoveEdge reference label in digraph.xml documentation --- doc/oper.xml | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/doc/oper.xml b/doc/oper.xml index 7579f6527..5d5ec1fdb 100644 --- a/doc/oper.xml +++ b/doc/oper.xml @@ -715,22 +715,22 @@ true the edge is returned.

- An error is raised if edge or [src, ran] does not define an - edge of digraph.

+ Note that if digraph belongs to , + then a new copy of digraph will be returned even if edge or + [src, ran] does not define an edge of digraph.

D := CycleDigraph(250000); gap> D := DigraphRemoveEdge(D, [250000, 1]); -gap> new := DigraphRemoveEdge(D, [1, 2]); - +gap> new := DigraphRemoveEdge(D, [25000, 2]);; gap> new = D; -false +true gap> IsIdenticalObj(new, D); false gap> D := DigraphMutableCopy(D);; -gap> new := DigraphRemoveEdge(D, 2, 3);; +gap> new := DigraphRemoveEdge(D, 2500, 2);; gap> IsIdenticalObj(new, D); true]]> @@ -762,8 +762,10 @@ true]]> Filt="IsImmutableDigraph"/>, the edge is removed from an immutable copy of digraph and this new digraph is returned.

- An error is raised if any element of edges is invalid (i.e does not - define an edge of digraph). + Note that if edges is empty, then this operation + will always return digraph rather than a copy. Also, if any element + of edges is invalid (i.e. does not define an edge of digraph) + then that element will simply be ignored. D := CycleDigraph(250000); @@ -772,8 +774,8 @@ gap> D := DigraphRemoveEdges(D, [[250000, 1]]); gap> D := DigraphMutableCopy(D); -gap> new := DigraphRemoveEdges(D, [[1, 2], [2, 3], [3, 4]]); - +gap> new := DigraphRemoveEdges(D, [[1, 2], [2, 3], [3, 100]]); + gap> new = D; true ]]> From 719fcaeeee9f9e7ec618417a7f4a2bf4efe09ae7 Mon Sep 17 00:00:00 2001 From: Devansh Chopra Date: Thu, 11 Dec 2025 19:47:06 +0000 Subject: [PATCH 18/18] Fixed DigraphRemoveEdge reference label --- doc/digraph.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/digraph.xml b/doc/digraph.xml index 5d91e9787..aae0d3a17 100644 --- a/doc/digraph.xml +++ b/doc/digraph.xml @@ -596,7 +596,7 @@ true]]> digraph.

This can be useful when modifying the structure of a digraph with - or , + or , where the weights need to be updated to match the new structure, rather than simply copied.