diff options
Diffstat (limited to 'ipl/procs/seqops.icn')
-rw-r--r-- | ipl/procs/seqops.icn | 1618 |
1 files changed, 1618 insertions, 0 deletions
diff --git a/ipl/procs/seqops.icn b/ipl/procs/seqops.icn new file mode 100644 index 0000000..f696111 --- /dev/null +++ b/ipl/procs/seqops.icn @@ -0,0 +1,1618 @@ +############################################################################ +# +# File: seqops.icn +# +# Subject: Procedures to manipulate T-sequences +# +# Author: Ralph E. Griswold +# +# Date: March 4, 2003 +# +############################################################################ +# +# This file is in the public domain. +# +############################################################################ +# +# These procedures perform operations related to T-Sequences and to +# analyze T-Sequences. +# +############################################################################ +# +# Requires: Courage. +# +############################################################################ +# +# copyl(xargs[]) copy list of lists +# eval_tree(n) evaluate expression tree +# expression_tree(n) create expression tree +# fragment(s, i, p, arg) +# get_analysis(s) analyze sequence +# get_scollate(s) analyze for collation +# get_splace(s) analyze for motif along a path +# get_srepeat(s) analyze for repeat +# get_srun(s) analyze for run +# get_sruns(s) analyze for simple runs +# is_scompact(x) test sequence for compactness +# pimage(x) +# remod(s, p) +# sanalout() output analysis +# sanalysis(x) over-all analysis +# sbefriend(x, p) befriend sequence +# sbinop(op, xargs[]) binary operation on terms +# sbound(xargs[]) compute sequence upper bound FIX! +# scollate(xargs[]) sequence collation +# scompress(xargs[]) compact sequence +# sconcat(xargs[]) concatenate sequences +# sconcatp(xargs[]) concatenate sequences, pattern style +# scpal(xargs[]) closed sequence palindrome +# sdecimate(xargs[]) decimate sequence +# sdecollate(order, x) decollate sequence +# sdelta(x) get delta sequence +# sdirection(x) "direction" of delta(x) +# sequiv(x1, x2) test sequence equivalence +# sextend(xargs[]) extend sequence +# sflatten(x) flatten nested sequence +# sground(s, i) ground sequence to i +# shaft_period(x1, x2) shaft period +# simage(x, limit) string image of sequence +# sinit() initialize sequence operations +# sintermix(xargs[]) intermix sequences +# slayer(xargs[]) layer sequences +# slength(x) compute sequence length +# slocate(xargs[]) sequences of first positions of terms +# smap(xargs[]) map terms in sequence +# smin(xargs[]) compute sequence lower bound FIX +# smissing(x) missing terms in sequence BOGUS?? +# smod(xargs[]) modular reduction +# smutate(xargs[]) mutation +# snormal(x) normalize sequence +# sopal(xargs[]) create open sequence palindrome +# sorder(x) positions of first occurrence +# sparity(xargs[]) adjust parity +# speriod(s, i) sequence period +# splace(xargs[]) place motif along a path +# splaceg(xargs[]) generalized motifs along a path +# splacep(xargs[]) place motif along a path +# ssplitdupl(xargs[]) split duplicate adjacent terms +# spositions(x1, x2) shaft positions +# spromote(x) promote term to sequence +# srandom(x) random selection +# sreflecth(xargs[]) reflect sequence horizontally +# sreflectr(xargs[]) +# sreflectv(xargs[]) reflect sequence vertically +# sremdupl(xargs[]) remove duplicate adjacent terms +# srepeat(xargs[]) repeat sequence +# srepl(xargs[]) replicate sequence terms +# srotatev(xargs[]) rotate sequence vertically +# srun(xargs[]) create connected run +# sruns(xargs[]) create simple runs +# sscale(xargs[]) scale terms in sequence +# sscollate(xargs[]) collate entire sequences +# sselect(xargs[]) select terms from sequence +# sshift(x, i) shift terms sequence +# sundulate(x) make undulating sequence +# sunmod(x) modular expansion +# sunop(op, xargs[]) unary operation on terms +# walk_tree(n, tree_list, tree_ptrs, depth) +# walk expression tree +# +############################################################################ +# +# Links: factors, numbers +# +############################################################################ + +link factors +link numbers + +global expressions +global node_gen +global saltparity +global scompact +global sfliph +global sflipv +global sflipr +global sflipl + +record node(name, seqlist) + +$define MaxTerms 300 + +procedure copyl(xargs[]) #: copy list of lists + local new_xargs + + new_xargs := [] + + every put(new_xargs, copy(spromote(!xargs))) + + return new_xargs + +end + +procedure eval_tree(n) + local i + + n := integer(n) + + if type(n) ~== "node" then return n + + every i := 1 to *n.seqlist do + n.seqlist[i] := eval_tree(n.seqlist[i]) + + return n.name ! n.seqlist + +end + +procedure expression_tree(n) + local result + + n := integer(n) + + case type(n) of { + "list" | "integer" : return "[" || simage(n, MaxTerms) || "]" + "string" : return n + } + + result := n.name || "(" + + every result ||:= expression_tree(!n.seqlist) || "," + + return result[1:-1] || ")" + +end + +procedure fragment(s, i, p, arg) + local results, j, k + + if *s <= i then return s + + /p := 1 + + results := list(i) + + every !results := [] + + k := 0 + + every j := 1 to i do + every 1 to *s / i do + put(results[j], s[k +:= 1]) | break break + + every j := 1 to i do + results[j] := p(results[j], arg) + + every j := 1 to i do + results[j] := fragment(results[j], i, p, arg) + + return results + +end + +$define MinLength 5 # minimum length for attempting analysis + +procedure get_analysis(seq) + local expression + + if *seq < MinLength then return simageb(seq) + + expression := ( + get_scollate(seq) | + get_srepeat(seq) | + remod(seq, get_srun) | # before sruns(), which would subsume it + remod(seq, get_sruns) | + get_splace(seq) | # would subsume some runs + simageb(seq) + ) + + return expression + +end + +procedure get_scollate(seq) #: find collation in sequence + local bound, deltas, i, j, poses, positions, oper, seqs + local results, result, k, count, oseq, m, nonperiod, facts, period + + bound := (sbound ! seq) + + speriod(seq) | fail # only handle periodic case + + deltas := table() + positions := table() + + every i := 1 to bound do { + poses := spositions(seq, i) + positions[i] := poses + j := sconstant(sdelta(poses)) | fail # CONTRADICTION + /deltas[j] := [] + put(deltas[j], i) + } + + oseq := list(*seq, 1) # decollation order sequence + + count := 0 + + every k := key(deltas) do { + count +:= 1 + every j := !deltas[k] do + every m := !positions[j] do + oseq[m] := count + } + + if *set(oseq) < 2 then fail # not enough sequences + +# oseq := srun([1, get(facts)]) | fail + + seqs := sdecollate(oseq, seq) | fail + + oper := "scollate(" || (simageb(oseq[1+:speriod(oseq)]) | + get_analysis(oseq)) + + every oper ||:= ", " || get_analysis(!seqs) + + return oper || ")" + +end + +procedure get_splace(seq) #: find motif along a path in sequence + local i, j, motif, seq2, path + + if i := sconstant(seq) then return "srepeat(" || i || "," || *seq || ")" + + every i := divisors(*seq) do { + motif := seq[1+:i] + every j := i + 1 to *seq by i do + if not sequiv(motif, sground(seq[j+:i], seq[1])) then break next + path := [] + every put(path, seq[1 to *seq by i]) + return "splace(" || get_analysis(motif) || ", " || get_analysis(path) || ")" + } + + fail + +end + +procedure get_srepeat(seq) #: find repeat in sequence + local i + + i := speriod(seq) | fail + return "srepeat(" || get_analysis(seq[1+:i]) || ", " || (*seq / i) || ")" + +end + +procedure get_srun(seq) + local i, j, new_seq, dir + + seq := copy(seq) + + i := get(seq) + j := get(seq) + + if j = i - 1 then dir := -1 # down going + else if j = i + 1 then dir := 1 # upgoing + else fail + + new_seq := [i] + + while i := get(seq) do { + if i = j + 1 then { + if dir = -1 then put(new_seq, j) + dir := 1 + } + else if i = j - 1 then { + if dir = 1 then put(new_seq, j) + dir := -1 + } + else { + put(new_seq, j) + push(seq, i) # put back non-continuing value + break + } + j := i + } + + if *seq ~= 0 then fail + + put(new_seq, j) + + return "srun(" || get_analysis(new_seq) || ")" + +end + +procedure get_sruns(seq) + local i, j, seq1, seq2, dir + + seq1 := [] + seq2 := [] + + repeat { + i := get(seq) | { + put(seq2, j) + break # end of road + } + j := get(seq) | fail # isolated end point + if j = i - 1 then dir := -1 # down going + else if j = i + 1 then dir := 1 # up going + else fail + put(seq1, i) # beginning point + while i := get(seq) do { + if i = j + dir then { + j := i + next + } + else { + push(seq, i) # put back next value + put(seq2, j) + break + } + } + } + + return "sruns(" || get_analysis(seq1) || ", " || get_analysis(seq2) || ")" + +end + +procedure is_scompact(x) #: test sequence for compactness + local bound + + x := spromote(x) + + bound := sbound ! x + + if bound = *set(x) then return bound + else fail + +end + +procedure pimage(s) # DOES THIS BELONG HERE? + local result, x + + result := "" + + every x := !s do { + if integer(x) then result ||:= x else + result ||:= pimage(x) + result ||:= "," + } + + return "[" || result[1:-1] || "]" + +end + +procedure remod(seq, p) #: handle modulus + local nseq, bound + + nseq := sunmod(seq) + + if (sbound ! nseq) > (bound := sbound ! seq) then + return "smod(" || p(nseq) || ", " || bound || ")" + else return p(copy(seq)) + +end + +procedure sanalout() + local expression, var + + write("link seqops") + write("procedure main()") + + expressions := sort(expressions, 4) + + while expression := get(expressions) do + write(var := get(expressions), " := ", expression) + + write("every write(!", var, ")") + + write("end") + + expressions := table() + + return + +end + +procedure sanalysis(x) + +# sanalyze(x) + + sanalout() + + return + +end + +procedure sbinop(op, xargs[]) #: binary operation on terms + local lseq, i, x1, x2 + + x1 := spromote(xargs[1]) + x2 := spromote(xargs[2]) + + op := proc(op, 2) | fail + + lseq := [] + + every i := 1 to smin(*x1, *x2) do + put(lseq, op(x1[i], x2[i])) + + return lseq + +end + +procedure sbound(xargs[]) #: compute sequence upper bound FIX! + + return sort(xargs)[-1] + +end + +procedure scollate(xargs[]) #: sequence term collation + local lseq, i, order + + if \node_gen then return node("scollate", xargs) + + order := get(xargs) + + /order := srun(1, *xargs) + + xargs := copyl ! xargs + + lseq := [] + + while i := get(order) do { + put(order, i) + put(lseq, get(xargs[i])) | break + } + + put(lseq, get(xargs[get(order)])) # ????? + + return lseq + +end + +procedure scompress(xargs[]) #: compact sequence + local unique, target, x + + if \node_gen then return node("compress", xargs) + + x := spromote(xargs[1]) + + unique := set(x) + + target := [] + + every put(target, 1 to *unique) + + return smap(x, sort(unique), target) + +end + +procedure sconcat(xargs[]) #: concatenate sequences + local lseq + + if \node_gen then return node("sconcat", xargs) + + lseq := [] + + every lseq |||:= spromote(!xargs) + + return lseq + +end + +procedure sconcatp(xargs[]) #: concatenate sequences as pattern + local lseq, nseq + + if \node_gen then return node("sconcat", xargs) + + lseq := [] + + every nseq := spromote(!xargs) do { + if nseq[1] === lseq[-1] then get(nseq) + lseq |||:= nseq + } + + return lseq + +end + +procedure sconstant(seq) #: test for constant sequence + + if *set(seq) = 1 then return !seq + else fail + +end + +procedure scpal(xargs[]) #: closed sequence palindrome + local lseq, x1, x2, i + + if \node_gen then return node("scpal", xargs) + + x1 := spromote(xargs[1]) + x2 := spromote(xargs[2]) | [1] + + i := 0 + + every i +:= !x2 + + lseq := srepeat(sopal(x1), i) + + put(lseq, lseq[1]) + + return lseq + +end + +procedure sdecimate(xargs[]) #: decimate sequence + local lseq, j, k, x1, x2 + + x1 := spromote(xargs[1]) + x2 := sort(spromote(xargs[2])) + + lseq := [] + + k := 1 + + while j := get(x2) do { + every put(lseq, x1[k to j - 1]) + k := j + 1 + } + + every put(lseq, x1[j + 1 to *x1]) + + return lseq + +end + + +procedure sdecollate(order, x) #: sequence decollation + local lseq, i, j + + x := spromote(x) + + if *x = 0 then fail + + order := copy(order) + + lseq := list(sbound ! order) # list of lists to return + + every !lseq := [] # initially empty + + every j := !x do { + i := get(order) | fail + put(order, i) + put(lseq[i], j) + } + + return lseq + +end + +procedure sdelta(seq) #: sequence delta + local i, lseq, j + + if *seq < 2 then fail + + seq := copy(seq) + + i := get(seq) + + lseq := [] + + while j := get(seq) do { + put(lseq, j - i) + i := j + } + + return lseq + +end + +procedure sdirection(x) #: sequence delta "direction" + local lseq, i + + x := sdelta(spromote(x)) | fail + + lseq := [] + + while i := get(x) do + put(lseq, + if i > 0 then 3 + else if i = 0 then 2 + else 1 + ) + + return lseq + +end + +procedure sdistrib(x) + local lseq, i + + x := copy(spromote(x)) + + lseq := list(sbound ! x, 0) + + while i := get(x) do + lseq[i] +:= 1 + + return lseq + +end + +procedure sequiv(x1, x2) # test for sequence equivalence + local i + + x1 := spromote(x1) + x2 := spromote(x2) + + if *x1 ~= *x2 then fail + + every i := 1 to *x1 do + if x1[i] ~= x2[i] then fail + + return x2 + +end + +procedure sextend(xargs[]) #: extend sequence + local lseq, part, i, x1, x2 + + if \node_gen then return node("sextend", xargs) + + x1 := spromote(xargs[1]) + + lseq := [] + + every i := !spromote(xargs[2]) do { + part := [] + until *part >= i do + part |||:= x1 + lseq |||:= part[1+:i] + } + + return lseq + +end + +procedure sflatten(s) # flatten packet sequence BELONGS HERE? + local lseq, x + + lseq := [] + + every x := !s do + if type(x) == "list" then lseq |||:= sflatten(x) + else put(lseq, x) + + return lseq + +end + +procedure sground(seq, i) #: ground sequence to i + local j + + /i := 1 + + j := smin ! seq + + every !seq -:= (j - i) + + return seq + +end + +procedure shaft_period(x1, x2) #: shaft period + local results + + x1 := spromote(x1) + x2 := spromote(x2) + + return sconstant(sdelta(spositions(x1, x2))) + +end + +procedure simage(x, limit) #: string image of sequence + local str + + x := spromote(x) + + if *x = 0 then return "[]" + + /limit := 2 ^ 16 # good enough + + str:= "" + + every str ||:= (!x \ limit) || ", " + + if *x > limit then str ||:= "... " + + return str[1:-2] + +end + +procedure simageb(seq) #: bracketed sequence image + + if *seq = 1 then return seq[1] + + return "sconcat(" || simage(seq) || ")" + +end + +procedure sinit() #: initialize sequence operations + + saltparity := sparity + scompact := scompress + sfliph := sreflecth + sflipv := sreflectv + sflipr := sreflectr +# sflipl := sreflectl + + return + +end + +procedure sintermix(xargs[]) #: sequence intermixing + local lseq, i, order + + if \node_gen then return node("sintermix", xargs) + + order := get(xargs) + + /order := srun(1, *xargs) + + xargs := copyl ! xargs + + lseq := [] + + while i := get(order) do { + put(order, i) + lseq |||:= xargs[i] + } + + return lseq + +end + +procedure slayer(xargs[]) #: layer sequences + local new_xargs, i, shift + + if \node_gen then return node("slayer", xargs) + + new_xargs := [xargs[1], xargs[2]] | fail + + if not integer(xargs[2][1]) then return scollate ! xargs + + shift := sbound ! xargs[2] + + every i := 3 to *xargs do { + put(new_xargs, sshift(xargs[i], shift)) + shift +:= sbound ! xargs[i] + } + + return scollate ! new_xargs + +end + +procedure slength(x) #: compute sequence length + + return *spromote(x) + +end + +procedure slocate(xargs[]) #: sequences of first positions of terms + local count, i, lseq, x1, x2 + + if \node_gen then return node("slocate", xargs) + + x1 := copy(spromote(xargs[1])) + x2 := set(spromote(xargs[2])) + + lseq := [] + + count := 0 + + while i := get(x1) do { + count +:= 1 + if member(x2, integer(i)) then + return count + } + + fail + +end + +procedure smap(xargs[]) #: map terms in sequence + local i, smaptbl, x1, x2, x3 + static tdefault + + initial tdefault := [] + + x1 := copy(spromote(xargs[1])) + x2 := spromote(xargs[2]) + x3 := spromote(xargs[3]) + + if *x2 ~= *x3 then fail + + smaptbl := table(tdefault) # mapping table + + every i := 1 to *x2 do # build the map + smaptbl[x2[i]] := x3[i] + + every i := 1 to *x1 do # map the values + x1[i] := (tdefault ~=== smaptbl[x1[i]]) + + return x1 + +end + +procedure smin(xargs[]) #: compute sequence lower bound FIX + + return sort(xargs)[1] + +end + +procedure smissing(x) #: missing terms in sequence BOGUS?? + local lseq, i, result + + x := spromote(x) + + lseq := sorder(x) + + result := [] + + every i := 1 to *lseq do + if lseq[i] = 0 then put(result, i) + + return result + +end + +procedure smod(xargs[]) #: modular reduction + local lseq, i, x1, x2 + + if \node_gen then return node("smod", xargs) + + x1 := spromote(xargs[1]) + x2 := spromote(xargs[2]) + + lseq := [] + + every i := !x2 do + every put(lseq, residue(!x1, i, 1)) + + return lseq + +end + +procedure smutate(xargs[]) #: mutation + local lseq, x1, x2 + + if \node_gen then return node("smutate", xargs) + + x1 := spromote(xargs[1]) + x2 := spromote(xargs[2]) + + lseq := [] + + every put(lseq, x1[!x2]) + + return lseq + +end + +procedure snormal(x) #: normalize sequence + local lseq, i, target, count # maps shafts so they are numbered in order + # first appearance + x := spromote(x) + + lseq := [] + + count := 0 + + target := table() + + every i := !x do { + /target[i] := (count +:= 1) + put(lseq, target[i]) + } + + return lseq + +end + +procedure sopal(xargs[]) #: create open sequence palindrome + local x + + if \node_gen then return node("sopal", xargs) + + x := spromote(xargs[1]) + + return x ||| sreflecth(x)[2:-1] + +end + +procedure sorder(x) #: positions of first occurrence + local lseq, i, done # of terms in *compact* sequence + + x := copy(spromote(x)) + + lseq := [] + + done := set() + + while i := integer(get(x)) do { + if member(done, i) then next + else { + put(lseq, i) + insert(done, i) + } + } + + return lseq + +end + +procedure sparity(xargs[]) #: adjust parity + local lseq, i, j, k, x1, x2 + + if \node_gen then return node("sparity", xargs) + + x1 := spromote(xargs[1]) + x2 := spromote(xargs[2]) + + lseq := [] + + every i := 1 to *x1 do { + j := x1[i] + k := x2[i] + if (j % 2) = (k % 2) then put(lseq, j) + else put(lseq, j + 1, j) + } + + return lseq + +end + +procedure speriod(seq, k) #: period of sequence + local i, segment + + if /k then { # assume full repeats + every i := 1 | divisors(*seq) do { # if repeats came out even + segment := seq[1+:i] + if sequiv(sextend(segment, *seq), seq) then return i + } + fail + } + else { # assume partial repeat at edge + every i := 1 to *seq do { + segment := seq[1+:i] + if sequiv(sextend(segment, *seq), seq) then return i + } + fail # should not happen + } + +end + +procedure splace(xargs[]) #: place motif along a path + local lseq, i, x1, x2 + + if \node_gen then return node("splace", xargs) + + x1 := copy(spromote(xargs[1])) + x2:= spromote(xargs[2]) + + lseq := [] + + every i := !x2 do + every put(lseq, !x1 + i - 1) + + return lseq + +end + +procedure splacep(xargs[]) #: place motif along a path + local lseq, i, x1, x2, j + + if \node_gen then return node("splace", xargs) + + x1 := copy(spromote(xargs[1])) + x2:= spromote(xargs[2]) + + lseq := [] + + every i := !x2 do { + j := x1[1] + if j ~= lseq[-1] then put(lseq, j) + every put(lseq, x1[2 to * x1] + i - 1) + } + + return lseq + +end + +procedure splaceg(xargs[]) #: generalized motifs along a path + local lseq, i, path, motif + + if \node_gen then return node("splaceg", xargs) + + path := copy(get(xargs)) + + xargs := copyl ! xargs + + lseq := [] + + while i := get(path) do { + motif := get(xargs) + put(xargs, motif) + every put(lseq, !motif + i - 1) + } + + return lseq + +end + +procedure spositions(x1, x2) #: positions of values in sequence + local lseq, count, i + + x1 := copy(spromote(x1)) + x2 := set(spromote(x2)) + + lseq := [] + + count := 0 + + while i := get(x1) do { + count +:= 1 + if member(x2, integer(i)) then + put(lseq, count) + } + + return lseq + +end + +procedure spromote(x) #: promote term to sequence + + if type(x) ~== "list" then x := [x] + + return x + +end + +procedure srandom(x) #: random selection + + return ?spromote(x) + +end + +procedure sreflecth(xargs[]) #: reflect sequence horizontally + local lseq, x + + if \node_gen then return node("sreflecth", xargs) + + lseq := [] + + every push(lseq, !spromote(xargs[1])) + + return lseq + +end + + +procedure sreflectr(xargs[]) + local lseq, i, bound, x + + if \node_gen then return node("sreflectr", xargs) + + x := spromote(xargs[1]) + + bound := sbound ! x + + lseq := [] + + every i := !x do + push(lseq, bound - i + 1) + + return lseq + +end + +procedure sreflectv(xargs[]) #: reflect sequence vertically + local lseq, m, x + + if \node_gen then return node("sreflectv", xargs) + + x := spromote(xargs[1]) + + if not integer(x[1]) then return x + + m := sbound ! x + + lseq := [] + + every put(lseq, m - !x + 1) + + return lseq + +end + +procedure sremdupl(xargs[]) #: remove duplicate adjacent terms + local lseq, i, x + + if \node_gen then return node("sremdupl", xargs) + + x := copy(spromote(xargs[1])) + + lseq := [get(x)] | return [] + + while i := get(x) do + if lseq[-1] ~= i then + put(lseq, i) + + return lseq + +end + +procedure ssplitdupl(xargs[]) #: split duplicate adjacent terms + local lseq, i, x + + if \node_gen then return node("sremdupl", xargs) + + x := copy(spromote(xargs[1])) + + lseq := [get(x)] | return [] + + while i := get(x) do + if lseq[-1] ~= i then + put(lseq, i) + else + put(lseq, i + 1, i) + + return lseq + +end + +procedure srepeat(xargs[]) #: repeat sequence + local lseq, count, x1, x2 + + if \node_gen then return node("srepeat", xargs) + + x1 := spromote(xargs[1]) + + count := 0 + + every count +:= !spromote(xargs[2]) + + lseq := copy(x1) + + every 2 to count do + lseq |||:= x1 + + return lseq + +end + +procedure srepl(xargs[]) # replicate sequence terms + local lseq, i, j, x1, x2 + + if \node_gen then return node("srepl", xargs) + + x1 := spromote(xargs[1]) + x2 := spromote(xargs[2]) + + lseq := [] + + every i := !x2 do + every j := !x1 do + every 1 to i do + put(lseq, j) + + return lseq + +end + +procedure srotatev(xargs[]) #: rotate sequence vertically + local lseq, m, x + + if \node_gen then return node("srotatev", xargs) + + x := spromote(xargs[1]) + + if not integer(x[1]) then return x + + m := sbound ! x + + lseq := [] + + every put(lseq, residue(!x + 1, m, 1)) + + return lseq + +end + +procedure srun(xargs[]) #: create connected runs + local lseq, i, j, x + + if \node_gen then return node("srun", xargs) + + x := copy(spromote(xargs[1])) + + lseq := [] + + i := get(x) | return lseq + + while j := get(x) do { + lseq |||:= sruns(i, j, 1) + pull(lseq) + i := j + } + + put(lseq, i) + + return lseq + +end + +procedure sruns(xargs[]) # disconnected runs + local lseq, i, j, k, limit, x1, x2, x3 + + if \node_gen then return node("sruns", xargs) + + x1 := copy(spromote(xargs[1])) + x2 := copy(spromote(xargs[2])) + x3 := copy(spromote(xargs[3])) | [1] + + lseq := [] + + repeat { + i := get(x1) | break + j := get(x2) | break + k := get(x3) | break + put(x3, k) # cycle + if integer(j) < integer(i) then k := -k + every put(lseq, i to j by k) + } + + return lseq + +end + +procedure sscale(xargs[]) #: scale terms in sequence + local lseq, j, i, x1, x2 + + if \node_gen then return node("sscale", xargs) + + x1 := spromote(xargs[1]) + + lseq := [] + + every i := !spromote(xargs[2]) do + every j := 1 to *x1 do + put(lseq, (x1[j] - 1) * i + 1) + + return lseq + +end + +procedure sscollate(xargs[]) #: entire sequence collation + local lseq, i, order + + if \node_gen then return node("sscollate", xargs) + + order := get(xargs) + + /order := srun(1, *xargs) + + xargs := copyl ! xargs + + lseq := [] + + while i := get(order) do + lseq |||:= xargs[i] + + return lseq + +end + +procedure sselect(xargs[]) #: select terms from sequence + local lseq, i, x1, x2 + + if \node_gen then return node("sselect", xargs) + + x1 := spromote(xargs[1]) + x2 := copy(spromote(xargs[2])) + + lseq := [] + + while i := get(x2) do + put(lseq, x1[i]) # may fail + + return lseq + +end + +procedure sshift(x, i) #: shift terms sequence + local lseq + + lseq := [] + + every put(lseq, !spromote(x) + i) + + return lseq + +end + +procedure sundulate(x) #: make undulating sequence + local lseq, i, dir + + x := copy(spromote(x)) + + lseq := [get(x)] | fail + + while i := get(x) | return lseq do { + if i > lseq[-1] then { + dir := -1 + break + } + else if i < lseq[-1] then { + dir := 1 + break + } + } + + put(lseq, i) + + while i := get(x) do { + if i < lseq[-1] then { + if dir = -1 then { + put(lseq, i) + dir := 1 + } + else lseq[-1] := i + } + if i > lseq[-1] then { + if dir = 1 then { + put(lseq, i) + dir := -1 + } + else lseq[-1] := i + } + } + + return lseq + +end + +procedure sunmod(x) #: modular expansion + local base, bound, i, lseq, k + + x := copy(spromote(x)) + + if not integer(x[1]) then return x + + base := 0 + + bound := sbound ! x + + lseq := [get(x)] | fail + + while i := get(x) do { + if (i = 1) & (lseq[-1] = base + bound) then + base +:= bound + else if (i = bound) & (lseq[-1] = base + 1) then + base -:= bound + put(lseq, base + i) + } + + while (k := (smin ! lseq)) < 1 do + every !lseq +:= bound + + return lseq + +end + +procedure sunop(op, xargs[]) #: unary operation on terms + local lseq, i, x + + if \node_gen then return node("sunop", xargs) + + x := spromote(xargs[1]) + + op := proc(op, 1) | fail + + lseq := [] + + every i := 1 to *x do + put(lseq, op(x[i])) + + return lseq + +end + +procedure walk_tree(n, tree_list, tree_ptrs, depth) + local indent + + /tree_list := [] + /tree_ptrs := [] + /depth := 0 + + indent := repl(" ", 3 * depth) + + n := integer(n) + + case type(n) of { + "integer" | "list" : { + put(tree_list, indent || "[" || simage(n, MaxTerms) || "]") + put(tree_ptrs, n) + return [tree_list, tree_ptrs] + } + "string" : { + put(tree_list, indent || n) + put(tree_ptrs, n) + return [tree_list, tree_ptrs] + } + } + + put(tree_list, indent || n.name) + put(tree_ptrs, n) + + every walk_tree(!n.seqlist, tree_list, tree_ptrs, depth + 1) + + return [tree_list, tree_ptrs] + +end + +procedure sbefriend(x, way) #: make a sequence friendly + local lseq, i, tail + + /way := connect + + x := copy(spromote(x)) + + put(x, x[1]) # for first-last friendliness + + lseq := [get(x)] | return [] + + while i := get(x) do + lseq |||:= way(lseq[-1], i) + + pull(lseq) # remove added term + + return lseq + +end + +procedure connect(j, i) #: connect friends + local k, result + + result := [] + + k := i - j + + if abs(k) = 1 then put(result, i) + else if k = 0 then + put(result, i + ?[1, -1], i) + else if k > 0 then + every put(result, j + 1 to i) + else + every put(result, j - 1 to i by -1) + + return result + +end + +procedure wander(j, i) #: friendly meander + local result, k, incr + + result := [j] + + repeat { + k := i - result[-1] + if abs(k) = 1 then { + put(result, i) + break + } + incr := [1, -1] + if k < 0 then + every 1 to -k do + put(incr, -1) + else + every put(incr, 1) + put(result, result[-1] + ?incr) + if result[-1] == i then break + } + + if *result > 1 then get(result) + + return result + +end + +procedure sxplot(x) # plot sequence + local plot, i, bound + + x := spromote(x) + + bound := sbound ! x + + plot := list(bound, repl(" ", *x)) + + every i := 1 to *x do + plot[x[i]][ i] := "x" + + while write(pull(plot)) + + return + +end + +procedure sundelta(x) # get undulant from delta sequence + local i + + x := spromote(x) + + every i := 2 to *x by 2 do # change sign of even-numbered terms + x[i] := -x[i] + + return sredelta(x) + +end + +procedure sredelta(x) # reconstruct sequence from delta sequence + local lseq + + x := spromote(x) + + lseq := [1] # nominal base + + while put(lseq, lseq[-1] + get(x)) + + return sground(lseq) # may have gone negative ... + +end + +procedure sreplp(x1, x2) + local lseq, i + + x1 := spromote(x1) + x2 := spromote(x2) + + lseq := [] + + while i := get(x1) do + every 1 to get(x2) do + put(lseq, i) + + return lseq + +end + +procedure sundulant(x, sw) # get undulant + local lseq, i, dir, cdir + + x := spromote(x) + + lseq := [x[1]] | fail + + i := 2 + + repeat { + dir := sign(x[i] - x[i - 1]) | fail + if dir ~= 0 then break + else i +:= 1 + } + + every i := 2 to *x do { + cdir := sign(x[i] - x[i - 1]) + if cdir = 0 then next + if dir ~= cdir then { + put(lseq, x[i - 1]) + dir := cdir + } + } + + if \sw & lseq[1] = lseq[-1] then pull(lseq) # repeating undulant + + if *lseq < 3 then fail # too short + + return lseq + +end |