diff --git a/doc/digraph.xml b/doc/digraph.xml index 05e578e11..5d91e9787 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..5d5ec1fdb 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 <#Include Label="DigraphMaximumFlow"> <#Include Label="RandomUniqueEdgeWeightedDigraph"> + <#Include Label="DigraphImmutableCopyNoWeights">

Orders diff --git a/gap/digraph.gd b/gap/digraph.gd index 46cb83d79..79cd91825 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]); + +DeclareOperation("DigraphImmutableCopyNoWeights", [IsDigraph]); \ No newline at end of file diff --git a/gap/digraph.gi b/gap/digraph.gi index 8f17bc8fd..82db0d26d 100644 --- a/gap/digraph.gi +++ b/gap/digraph.gi @@ -175,15 +175,34 @@ function(D) return copy; end); -InstallMethod(DigraphImmutableCopy, "for a digraph by out-neighbours", +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; + + return copy; +end); + +InstallMethod(DigraphImmutableCopyNoWeights, +"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; + return copy; end); @@ -1839,4 +1858,4 @@ InstallMethod(RandomLattice, "for a pos int", [IsPosInt], n -> RandomLatticeCons(IsImmutableDigraph, n)); InstallMethod(RandomLattice, "for a func and a pos int", [IsFunction, IsPosInt], -RandomLatticeCons); +RandomLatticeCons); \ No newline at end of file diff --git a/gap/oper.gi b/gap/oper.gi index 3876db50e..9197c56a7 100644 --- a/gap/oper.gi +++ b/gap/oper.gi @@ -138,10 +138,28 @@ InstallMethod(DigraphRemoveVertex, "for an immutable digraph and positive integer", [IsImmutableDigraph, IsPosInt], function(D, u) + local newD, weights; + if u > DigraphNrVertices(D) then return D; fi; - return MakeImmutable(DigraphRemoveVertex(DigraphMutableCopy(D), u)); + + 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; end); InstallMethod(DigraphRemoveVertices, "for a mutable digraph and a list", @@ -247,10 +265,30 @@ function(D, src, ran) end); InstallMethod(DigraphRemoveEdge, -"for a immutable digraph and two positive integers", +"for an immutable digraph and two positive integers", [IsImmutableDigraph, IsPosInt, IsPosInt], -{D, src, ran} --> MakeImmutable(DigraphRemoveEdge(DigraphMutableCopy(D), src, ran))); +function(D, src, ran) + local newD, weights, pos, outs; + + 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 pos <> fail and pos <= Length(weights[src]) then + Remove(weights[src], pos); + fi; + + SetEdgeWeights(newD, weights); + 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..1673d5a8d 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,38 @@ gap> OutNeighbours(D); gap> AsDigraph(AsPartialPerm((2, 5, 3)), 2); 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); +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> im2 := DigraphImmutableCopy(d); + +gap> im2 := DigraphRemoveEdge(im2, 1, 3); + +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 1c813fe21..35dd7175c 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, 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 #@local p, q, idp, idt, M gap> START_TEST("Digraphs package: standard/oper.tst"); gap> LoadPackage("digraphs", false);; @@ -3324,6 +3324,32 @@ gap> DigraphEdges(D); 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> imE := DigraphRemoveEdge(d, 1, 3); + +gap> IsImmutableDigraph(imE); +true +gap> OutNeighbours(imE); +[ [ 2 ], [ 3 ], [ ], [ ] ] +gap> EdgeWeights(imE); +[ [ 5 ], [ 15 ], [ ], [ ] ] +gap> EdgeWeights(d); +[ [ 5, 10 ], [ 15 ], [ ], [ ] ] +gap> imV := DigraphRemoveVertex(d, 1); + +gap> IsImmutableDigraph(imV); +true +gap> OutNeighbours(imV); +[ [ 2 ], [ ], [ ] ] +gap> EdgeWeights(imV); +[ [ 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);