Skip to content

Commit 6262016

Browse files
committed
runLengthEncode rewrite
1 parent 68351e7 commit 6262016

4 files changed

Lines changed: 86 additions & 35 deletions

File tree

M2/Macaulay2/m2/indeterminates.m2

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -63,40 +63,59 @@ succ(Symbol,Symbol) := (x,y) -> (
6363
isUserSymbol(s,x) and isUserSymbol(t,y) and succS#?s and succS#s === t)
6464
succ(Subscript,Subscript) := (x,y) -> x#0 === y#0 and succ(x#1,y#1)
6565
succ(Thing,Thing) := x -> false
66+
67+
-- Blocks contain an encoded item, its number of original entries, and the
68+
-- original items if it is a provisional two-entry range.
69+
runLengthEncodeDuplicates = blocks -> (
70+
i := 0;
71+
while i < #blocks list (
72+
j := i + 1;
73+
weight := blocks#i#1;
74+
while j < #blocks and blocks#j#0 === blocks#i#0 do (
75+
weight += blocks#j#1;
76+
j += 1);
77+
count := j - i;
78+
block := if count === 1 then blocks#i else
79+
(hold count : expression blocks#i#0, weight, null);
80+
i = j;
81+
block))
82+
83+
runLengthRangeStart = x -> if instance(x, BinaryOperation) then x#1 else expression x
84+
runLengthRangeEnd = x -> if instance(x, BinaryOperation) then x#2 else expression x
85+
86+
runLengthEncodeSuccessors = blocks -> (
87+
i := 0;
88+
while i < #blocks list (
89+
j := i + 1;
90+
weight := blocks#i#1;
91+
while j < #blocks and succ(blocks#(j-1)#0, blocks#j#0) do (
92+
weight += blocks#j#1;
93+
j += 1);
94+
block := if j - i > 1 then (
95+
runLengthRangeStart(blocks#i#0) .. runLengthRangeEnd(blocks#(j-1)#0),
96+
weight,
97+
if weight === 2 then apply(i..j-1, k -> hold blocks#k#0))
98+
else blocks#i;
99+
i = j;
100+
block))
101+
102+
runLengthEncodeOutput = blocks -> splice apply(blocks,
103+
block -> if block#2 === null then hold block#0 else block#2)
104+
105+
runLengthEncode1 = x -> (
106+
blocks := apply(x, item -> (item, 1, null));
107+
done := false;
108+
while not done do (
109+
next := runLengthEncodeSuccessors runLengthEncodeDuplicates blocks;
110+
done = #next === #blocks;
111+
blocks = next);
112+
new class x from runLengthEncodeOutput blocks)
113+
66114
runLengthEncode = method(Dispatch => Thing)
67-
runLengthEncode VisibleList := x -> (
68-
local xx;
69-
while (xx=runLengthEncode0 x; #x =!= #xx) do x=xx;
70-
xx
71-
)
72-
runLengthEncode0 = x -> (
73-
if #x === 0 then return x;
74-
dupout := true;
75-
while first(dupout,dupout = false) do x = new class x from (
76-
i0 := null;
77-
lastout := oi := symbol oi;
78-
m := 0;
79-
dupin := null;
80-
for i in append(x,symbol x) list
81-
(o -> (if lastout === o then dupout = true else lastout = o; o))(
82-
if i === oi and dupin =!= false then (dupin = true; m = m+1; continue)
83-
else if succ(oi,i) and dupin =!= true then (
84-
if dupin === null then i0 = oi;
85-
dupin = false;
86-
oi = i;
87-
m = m+1;
88-
continue)
89-
else first(
90-
if oi === symbol oi then (oi = i; m = 1 ; continue) else
91-
if m === 1 then hold oi else if dupin === true then hold m : expression oi else (if instance(i0,BinaryOperation) then i0#1 else expression i0) .. (if instance(oi,BinaryOperation) then oi#2 else expression oi),
92-
(dupin = null; oi = i; m = 1))));
93-
x)
94-
95-
rle = method(Dispatch => Thing)
96-
rle VisibleList := x -> apply(runLengthEncode x, rle)
97-
rle Holder := x -> rle x#0
98-
rle Option := x -> x#0 => rle x#1
99-
rle Thing := identity
115+
runLengthEncode VisibleList := x -> apply(runLengthEncode1 x, runLengthEncode)
116+
runLengthEncode Holder := x -> hold unsequence runLengthEncode x#0
117+
runLengthEncode Option := x -> x#0 => runLengthEncode x#1
118+
runLengthEncode Thing := identity
100119

101120
-- Local Variables:
102121
-- compile-command: "make -C $M2BUILDDIR/Macaulay2/m2 "

M2/Macaulay2/m2/monoids.m2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ monoidParts = M -> (
318318
D := runLengthEncode if opts.DegreeRank === 1 then flatten opts.Degrees else opts.Degrees / (deg -> VerticalList deg);
319319
L := nonnull splice ( G, if not isDefault(opts, Degrees) then Degrees => D,
320320
apply(( DegreeGroup, Heft, Join, MonomialOrder, WeylAlgebra, SkewCommutative, Inverses, Local, Global ),
321-
key -> if opts#?key and not isDefault(opts, key) then key => rle opts#key)))
321+
key -> if opts#?key and not isDefault(opts, key) then key => runLengthEncode opts#key)))
322322

323323
expressionMonoid = M -> (
324324
T := if (options M).Local === true then List else Array;

M2/Macaulay2/packages/Varieties/tests-varieties.m2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ TEST /// -- twisted cubic curve
3232

3333
TEST ///
3434
X = Spec ZZ/101[x,y]/(y^2-x^3)
35-
assert(toString ring X == "(ZZ/101)[x..y]/(-x^3+y^2)")
35+
assert(toString ring X == "(ZZ/101)[x, y]/(-x^3+y^2)")
3636
///
3737

3838
TEST ///
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
-- runLengthEncode prefers repeated entries and avoids two-entry ranges.
2+
assert(toString runLengthEncode {1,2} == "{1, 2}")
3+
assert(toString runLengthEncode {1,2,3} == "{1..3}")
4+
assert(toString runLengthEncode {7,2,5,6} == "{7, 2, 5, 6}")
5+
assert(toString runLengthEncode {1,2,2,2,3,3,3} == "{1, 3:2, 3:3}")
6+
assert(toString runLengthEncode {1,1,2,2,3,3} == "{2:1, 2:2, 2:3}")
7+
assert(toString runLengthEncode {1,2,3,1,2,3} == "{2:1..3}")
8+
9+
assert(toString runLengthEncode {a,b} == "{a, b}")
10+
assert(toString runLengthEncode {a,b,c} == "{a..c}")
11+
12+
R22 = QQ[m_(1,1)..m_(2,2)]
13+
assert(toString runLengthEncode(expression \ gens R22) == "{m_(1,1)..m_(2,2)}")
14+
15+
-- Recursive encoding subsumes the former private rle helper.
16+
assert(toString runLengthEncode {{1,2,3},{4,4,4}} == "{{1..3}, {3:4}}")
17+
assert(toString runLengthEncode (1,(2,2),(3,3)) == "(1,2:2,2:3)")
18+
assert(instance(first runLengthEncode {{1,2,3}}, Holder))
19+
assert(toString runLengthEncode {Degrees => {1,1,1}, Heft => {1,2}} ==
20+
"{Degrees => {3:1}, Heft => {1, 2}}")
21+
assert(class(runLengthEncode (1,2,3)) === Sequence)
22+
assert(class(runLengthEncode [1,2,3]) === Array)
23+
assert(class(runLengthEncode {1,2,3}) === List)
24+
25+
-- Singleton holders are needed for the documented value round trip.
26+
x = {1,2,3,a,b,c,a,b,c,4,4,4,"asdf"}
27+
y = runLengthEncode x
28+
assert(x === deepSplice(value \ y))
29+
30+
-- Local Variables:
31+
-- compile-command: "make -C $M2BUILDDIR/Macaulay2/tests/normal runLengthEncode.out"
32+
-- End:

0 commit comments

Comments
 (0)