diff --git a/lib/array.bpl b/lib/array.bpl index 209210c0..6d595095 100644 --- a/lib/array.bpl +++ b/lib/array.bpl @@ -79,7 +79,7 @@ disp ← { α←⍬ ⍝ Boxed sketch of nested array. join←{ ⍝ Join of gap-separated sub-planes. sep←≢ω ÷ 1ₓ⌈≢α ⍝ sub plane separation. split←0ₓ=sep|ι≢ω ⊂₀ ω - ⊂⍤¯1α plane¨ split ⍝ sub-plane join. + ⊂⁻¹α plane¨ split ⍝ sub-plane join. } outer←{ ⍝ Outer decoration. sizes←1 0{↑↓ ⍉⍣α ω}¨seprρ¨ω @@ -320,12 +320,12 @@ match ← { ⍝ Wildcard match. ↑{ [[lh lm] [und rm]]←[α ω] ⍝ left and right hits and masks. [lh∧rm lm] ⍝ right-masked left hits. - }/↓⍉⊃⊂⍤¯1¨[h m] + }/↓⍉⊃⊂⁻¹¨[h m] } ⍝ From http://dfns.dyalog.com/s_match.htm -showmatch ← {marks←[(α match ω)]⌷" ¯" ◇ ,⍠ ιρρω ω {[α◇ω]}⍤1 marks} +showmatch ← {marks←[(α match ω)]⌷" ¯" ◇ ,⍠ ιρρω ω {[α◇ω]}¹ marks} ⍝ From http://dfns.dyalog.com/n_nlines.htm @@ -398,7 +398,7 @@ dscan ← { ⍝ Divide scan ascan ← { ⍝ Associative scan. 2ₓ>0ₓ⊥ρω?ω; ⍝ few items: done. lane←⍶{⌽⍶{[(↑ω)⍶α],ω}/⌽[⊂↑ω],1↓ω} ⍝ one lane: builds the results newest first, then reverses them. - lane⍤1 ω + lane¹ ω } ⍝ From http://dfns.dyalog.com/c_ascana.htm @@ -433,7 +433,7 @@ subs ← { ⍝ Vector substitution. fm⍷ω { ⍝ hits mask ~$t∊α?ω; ⍝ early out if no match ts↓,/{to,fs↓ω}¨(lead,α)⊂fm,ω - }⍤1 ω ⍝ apply to vectors + }¹ ω ⍝ apply to vectors } ⍝ From http://dfns.dyalog.com/c_lcase.htm and http://dfns.dyalog.com/c_ucase.htm diff --git a/lib/dyalog.bpl b/lib/dyalog.bpl index 5e50c564..90547c36 100644 --- a/lib/dyalog.bpl +++ b/lib/dyalog.bpl @@ -37,7 +37,7 @@ lsys←{ ⍝ Lindenmayer L-system expansion. ⍝ From https://dfns.dyalog.com/c_rr.htm rr←{ ⍝ Round-robin tournament. v←ιn←0ₓ⌈≤ω - ≥(ω÷2)↑₋₁m{[α◇ω]}⍤1⌽m←0ₓ,v⌽≥[n n]ρv + ≥(ω÷2)↑₋₁m{[α◇ω]}¹⌽m←0ₓ,v⌽≥[n n]ρv } ⍝ From https://dfns.dyalog.com/c_easter.htm @@ -112,7 +112,7 @@ date←{ ⍝ Timestamp from day number (Meeus). ⍝ From https://dfns.dyalog.com/c_days.htm days←{ ⍝ Days since 1899-12-31 (Meeus). α←17520902ₓ - 1ₓ<≢ρω?α ∇⍤0 1 ω; + 1ₓ<≢ρω?α ∇⁰ ¹ ω; [yy mm dd h m s ms]←7↑ω D←dd + [0 60 60 1000]ₓ⊥[h m s ms] ÷ 86400000ₓ [Y M]←[yy mm]+[¯1 12]ₓ×mm≤2ₓ @@ -465,7 +465,7 @@ refmt←{ ⍝ Indent code and align comments. rlb←{∨\' '≠ω # ω} clean←⌽ rlb ⌽ rlb code [clean coms] - }⍤1 ⊃ω + }¹ ⊃ω dents←{ toks←unqtω {α#⁻α#ω} ω dvec←-⌿0 1⌽+\"{}"=⊗toks @@ -577,7 +577,7 @@ queens←{ ⍝ N-queens solutions up to rotation and reflection. fmt←{ chars←[(⊃ω)=⊗ια]⌷"·⊛" expd←1↓,⊃αρ⊂0 1 - ⊂⍤2 expd#⁻₋₁chars + ⊂² expd#⁻₋₁chars } squares←[ι⌈ω÷2],1↓ωρ⊂ιω ω fmt ⍬ search squares @@ -670,7 +670,7 @@ von←{ ⍝ Capitalise names, preserving prefixes and user-supplied exceptions. q←¯1•c{2ₓ>≡ω?,⊂,ω;ω}α 1↓∊∨/q⍶¨⊂' ',ω } - b←¯1↓∊∨/q⍷¨⊂' ',tx < $t,>/⌽⍤1↕~tx∊" -:;.,!?'""/)(" + b←¯1↓∊∨/q⍷¨⊂' ',tx < $t,>/⌽¹↕~tx∊" -:;.,!?'""/)(" b∨←pre(∆pre ∆fix)tx b>←not(∆not ∆fix)tx ¯1↓(1↣•c)@(⍸b) tx @@ -1181,7 +1181,7 @@ tc←{ ⍝ Trace function application. } reshape←{ ⍝ α-col reshape of ω. - α=0ₓ?max↑⍤1 col ω; ⍝ item too wide: truncated single col. + α=0ₓ?max↑¹ col ω; ⍝ item too wide: truncated single col. nr←⌈ni÷ₐα ⍝ number of rows. matr←[α nr]ρ(α×nr)↑ω,α#' ' ⍝ matrix blank-padded to whole no of cols. pads←⊃nr#↓gap#' ' ⍝ inter-column padding. @@ -1314,7 +1314,7 @@ ratsum←{ [lmrs wids reps]←⍉⊃trans¨[α ω] mpads←-wids-⊂⌈/wids rpads←2#⊂∧¨/reps - padded←pad⍤1 ⍉[lmrs◇mpads◇rpads] + padded←pad¹ ⍉[lmrs◇mpads◇rpads] ⊃¨↓⍉padded } trans←{ diff --git a/lib/numeric.bpl b/lib/numeric.bpl index 50f48e99..34a2b1fd 100644 --- a/lib/numeric.bpl +++ b/lib/numeric.bpl @@ -222,7 +222,7 @@ alt ← { ⍝ Alternant. [r c]←ρω ⍝ matrix ω 0ₓ=r?⍹⌿,ω; 1ₓ≥c?⍶⌿,ω; - M←(ιr)~⍤1⍪ιr ⍝ minors + M←(ιr)~¹⍪ιr ⍝ minors ω.[: 0]⍶.⍹∇¨⊂₁ ₂[M 1↓ιc]⌷ω } @@ -277,7 +277,7 @@ kcell ← { ⍝ Relationship between point and k-cell. α←≢ω #₋₁ [2 1]ρ0 1 ⍝ Default is unit k-cell. b←,⍠(2ₓ=ρρα # 0)α p←(2⌊ρρα ↓ 1 1,ρω)ρω ⍝ Points to evaluate. - d←,⍶⌿ ⍤1 ⍉×-b,.-p + d←,⍶⌿ ¹ ⍉×-b,.-p ⍶/⍬?⌈/d;5ₓ⊥d } @@ -309,7 +309,7 @@ stdev ← {√(+/÷≢ ω²)-(+/÷≢ ω)²} ⍝ Standard deviation. NormRand ← { ⍝ Random numbers with a normal distribution depth←10*9 ⍝ randomness depth - [x y]←⊂⍤¯1 ≥¿depthρ⍨2,ω ÷ depth ⍝ two random variables within ]0;1] + [x y]←⊂⁻¹ ≥¿depthρ⍨2,ω ÷ depth ⍝ two random variables within ]0;1] (¯2×⊛x * 0.5)×1○π2×y ⍝ Box-Muller distribution } @@ -375,7 +375,7 @@ polar ← { ⍝ Polar from/to cartesian coordinates. pol_car←{ ⍝ polar from cartesian (default). radius←{√+⌿ω²} ⍝ radius (pythagorus). angle←{ ⍝ phase angle. - [x y]←⊂⍤¯1 ω ⍝ x and y coordinates. + [x y]←⊂⁻¹ ω ⍝ x and y coordinates. [on off]←$t $f=⊂0=x ⍝ points on/off y axis. atan←3○⁻y÷x+on ⍝ arctan y÷x (avoiding y÷0). qne←off×atan + on×π0.5×2-×y @@ -386,7 +386,7 @@ polar ← { ⍝ Polar from/to cartesian coordinates. radiusω lam angleω ⍝ (2,···) array of polar coordinates. } car_pol←{ ⍝ cartesian from polar. - [r o]←⊂⍤¯1 ω ⍝ radius and phase angle. + [r o]←⊂⁻¹ ω ⍝ radius and phase angle. r×2○o lam r×1○o ⍝ r×cos(ø), r×sin(ø). } lam←{⊃[α ω]} diff --git a/lib/string.bpl b/lib/string.bpl index e6a62dff..d3086250 100644 --- a/lib/string.bpl +++ b/lib/string.bpl @@ -32,7 +32,7 @@ ss ← { ⍝ Approx alternative to xutils' ss. ssmat ← { ⍝ Matrix search/replace. [cmat find repl]←ω ⍝ Char matrix, find & replace vectors. - {ss[ω find repl]}⍤1 cmat + {ss[ω find repl]}¹ cmat } ⍝ From http://dfns.dyalog.com/c_squeeze.htm diff --git a/nbs/arrays.ipynb b/nbs/arrays.ipynb index 934ab705..f682dcd3 100644 --- a/nbs/arrays.ipynb +++ b/nbs/arrays.ipynb @@ -691,7 +691,7 @@ "id": "ccb11a91", "metadata": {}, "source": [ - "When results of different lengths are assembled into one array, the shorter ones are padded with fill. `≥ι ⍤0` gives one row per count:" + "When results of different lengths are assembled into one array, the shorter ones are padded with fill. `≥ι ⁰` gives one row per count:" ] }, { @@ -712,7 +712,7 @@ } ], "source": [ - "≥ι ⍤0 [2 4]" + "≥ι ⁰ [2 4]" ] }, { @@ -1055,7 +1055,7 @@ "id": "733270dc", "metadata": {}, "source": [ - "The results take the array's shape and keys as their frame, as [Rank](glyphs/jot-diaeresis.qmd)'s results do. A keyed array of aggregations gives a keyed result, and through Rank it gives one row of results for each row of its argument:" + "The results take the array's shape and keys as their frame, as [Rank](glyphs/jot-diaeresis.qmd)'s results do. A keyed array of aggregations gives a keyed result, and through Rank it gives one row of results for each row of its argument. The full Rank spelling distinguishes this from `stats¹`, which would raise the array's items to a power:" ] }, { diff --git a/nbs/autodiff.qmd b/nbs/autodiff.qmd index 4b1040d1..dff959cd 100644 --- a/nbs/autodiff.qmd +++ b/nbs/autodiff.qmd @@ -33,11 +33,11 @@ t←1 0 ◇ {f x+ω×t}∂0 ⍝ 3 1 u←1 0 ◇ {+/u×fω}∂ x ⍝ 3 2 ``` -For a function that works item by item, such as the sine `1○`, `f∂⍤0` gives the derivative at each item. Differentiating along one number gives the same values in one pass: +For a function that works item by item, such as the sine `1○`, `f∂⁰` gives the derivative at each item. Differentiating along one number gives the same values in one pass: ```bpl x←0 0.5 1 -1○∂⍤0 x ⍝ 1 0.8775825619 0.5403023059 +1○∂⁰ x ⍝ 1 0.8775825619 0.5403023059 {1○x+ω}∂0 ⍝ 1 0.8775825619 0.5403023059 ``` @@ -125,14 +125,14 @@ Without a program, `∂` builds its duals or its record afresh on every call, th ```bpl x←ι64 ÷ 63 ◇ y←1○3×x -loss←{[x y]←α ◇ [w b v c]←ω ◇ h←7○b(+⍤1)x×⊗w ◇ +/÷≢ ⊼y-c+h+.×v} +loss←{[x y]←α ◇ [w b v c]←ω ◇ h←7○b(+¹)x×⊗w ◇ +/÷≢ ⊼y-c+h+.×v} p←["w":1○ι16 "b":16ρ0 "v":0.1×2○ι16 "c":0] [x y] loss p ⍝ 0.5232276475 p←{ω - 0.1× [x y]loss∂ω}⍣200p [x y] loss p ⍝ 0.07655752909 ``` -`∂` runs from a program. The first call with given argument types and shapes traces the function. The function runs on traced values, which have a type and a shape but no items. Each call on a traced value works out the type and shape of its result, and adds a step to the program. A map in the function, such as Rank in `+/{⊼1○+/w×ω}⍤1 X`, calls its dfn once on all its cells, as it does outside a trace. Each call in the dfn then adds one step for all the cells. The derivative's records and transposes add their steps to the same program. The program holds the whole call: the function's value and its derivative together. JAX traces a Python function into a jaxpr in the same way. +`∂` runs from a program. The first call with given argument types and shapes traces the function. The function runs on traced values, which have a type and a shape but no items. Each call on a traced value works out the type and shape of its result, and adds a step to the program. A map in the function, such as Rank in `+/{⊼1○+/w×ω}¹ X`, calls its dfn once on all its cells, as it does outside a trace. Each call in the dfn then adds one step for all the cells. The derivative's records and transposes add their steps to the same program. The program holds the whole call: the function's value and its derivative together. JAX traces a Python function into a jaxpr in the same way. Later calls with the same argument types and shapes replay the program on their arguments, without running the function. The replay runs the program's steps as ordinary calls. Chains of elementwise steps then run as one stage, a block of items at a time, as they do outside a program. A stage folds its last step's items as it computes them. Its intermediate results exist only one block at a time. Once a stage is large enough, or runs again, BPL compiles it to machine code with Cranelift, if its steps can compile. The browser build has no compiler. It runs every stage on the interpreter's kernels. `•explain` shows whether a call built a program or replayed one: @@ -209,7 +209,7 @@ JAX, Dex and tinygrad are the role models. Futhark, Dex and Julia set the standa | tinygrad | Lazy arrays: a call on a large array gives a pending array, and a read of its items runs the calls it needs, fused. Derivative code that fuses as other code does. Copies, such as a transpose or a slice, whose transposes are copies, not scatters. A program replayed as `TinyJit` replays its kernels. | | Futhark | One table of partial derivatives for both modes, which BPL's table was mapped from. The rules for folds by `×`, `⌈` and `⌊`. Accumulation as the transpose of a gather. | | ForwardDiff | Dual numbers with tags, which keep nested derivatives apart. | -| J | `D.`, which gives a Jacobian, and `d.`, which gives the derivative at each item. `f∂` and `f∂⍤0` do these jobs. | +| J | `D.`, which gives a Jacobian, and `d.`, which gives the derivative at each item. `f∂` and `f∂⁰` do these jobs. | BPL also differs from all of them. `∂` strips its tags from values that escape it, where JAX raises an error when a leaked tracer is used. One operator picks the mode, where JAX offers `jvp`, `vjp`, `jacfwd` and `jacrev`. A Jacobian takes its keys, axis names and records from the rules of outer products. Futhark differentiates its program before running it and recomputes values in reverse mode. BPL differentiates the calls that `f` makes as it runs. It keeps their linear steps instead of recomputing values. diff --git a/nbs/comparison.qmd b/nbs/comparison.qmd index 9b073ece..4a4ced35 100644 --- a/nbs/comparison.qmd +++ b/nbs/comparison.qmd @@ -469,7 +469,7 @@ a +˝∘×⎉1‿∞ b ```bpl a←2 3ρι6ₓ ◇ b←3 2ρι6ₓ -a +⌿×∘⍤1 ∞ b ⍝ [10 13◇28 40]ₓ +a +⌿× ⍤1 ∞ b ⍝ [10 13◇28 40]ₓ ``` ### A vector bound into a composition diff --git a/nbs/composition.qmd b/nbs/composition.qmd index c7dbc49b..1269f58f 100644 --- a/nbs/composition.qmd +++ b/nbs/composition.qmd @@ -28,13 +28,14 @@ v←2 4 9 ◇ +/÷≢v ⍝ 0ₓ ## Operators on trains -Before an operator, `∘` finishes the current run as that operator's left operand. `⊂⊢∘⌸` is `(⊂⊢)⌸`, and `+/÷≢∘⍤1` is `(+/÷≢)⍤1`. The right operand of a dyadic operator follows as usual: +A run that starts with an operator takes the whole preceding run as its left operand. A space can therefore replace parentheses around a short train: `⊂⊢ ⌸` is `(⊂⊢)⌸`, and `+/÷≢ ¹` is `(+/÷≢)¹`. ```bpl -m←2 3ρι6 ◇ +/÷≢∘⍤1m ⍝ 1 4 +m←2 3ρι6 ◇ +/÷≢ ¹m ⍝ 1 4 +0 1 0 ⊂⊢ ⌸ "abc" ⍝ "ac" "b" ``` -The boundary includes the whole run on its left. Keep a left argument or an earlier function outside that run with spaces or parentheses. Named operators work the same way as glyphs. Before a function, `∘` remains [Atop](#atop-and-over). +The preceding run is the whole operand, including any prefix. Keep a left argument or an earlier function outside it with spaces or parentheses. With both arguments, separate the operand, operator and right argument as above; `0 1 0 ⊂⊢ ⌸"abc"` instead evaluates the rightmost run first. Named operators work the same way as glyphs. Keep parentheses where they show nested structure more clearly. ## Identity functions @@ -78,10 +79,10 @@ The two-function train `⌊÷` divides, then rounds down: -↢10⁝3 ⍝ ¯7 ``` -With two function operands, `↣` and `↢` form monadic hooks. `f↣g Y` is `(f Y)g Y` and `f↢g Y` is `Y f(g Y)`. Two-function trains in BPL are atops. `(3<)↣# Y` is `(3¿nρ0 p⊢←q×~restart + restart×place n diff --git a/nbs/gallery/orbits.bpl b/nbs/gallery/orbits.bpl index 5e4ed072..254b4d29 100644 --- a/nbs/gallery/orbits.bpl +++ b/nbs/gallery/orbits.bpl @@ -9,7 +9,7 @@ speed←0.06× 30÷r * 1.5 [warm cool]←[1 0.6 0.2◇0.3 0.5 1] glow←0.9 0 colour←⍉[1-t◇t] +.× [warm◇cool] -style←colour ,⍤1 glow +style←colour ,¹ glow frame←{ z←250ⱼ250+r×○start+ω×speed ["points":(∨z),3,style] diff --git a/nbs/gallery/phyllotaxis.bpl b/nbs/gallery/phyllotaxis.bpl index bb3d37cc..ca0aba8f 100644 --- a/nbs/gallery/phyllotaxis.bpl +++ b/nbs/gallery/phyllotaxis.bpl @@ -8,6 +8,6 @@ z←50ⱼ50 + 1.8× √i × ○i×golden size←0.4+1.1×t hue←300×t seed←{["cx":ω₀;"cy":ω₁;"r":ω₂;"fill":"hsl(",(⍕ω₃),",80%,60%)"] circle ""} -seeds←⊂seed ⍤1 ∨z , ⍉[size◇hue] +seeds←⊂seed ¹ ∨z , ⍉[size◇hue] back←["width":100;"height":100;"fill":"#111"] rect "" ["width":500;"height":500] •svg [back],seeds diff --git a/nbs/gallery/reaction.bpl b/nbs/gallery/reaction.bpl index 3df1caa2..7c27a3ab 100644 --- a/nbs/gallery/reaction.bpl +++ b/nbs/gallery/reaction.bpl @@ -5,7 +5,7 @@ ⍝ 60 more steps of the simulation as you watch, and the animation stops after 400 frames. n←250 ⎕←"centres←",⍎⁻ centres←40+¿[≥¿4 2]ρ170 -seed←∨⌿{8>|ω₀-ιn ∧⊗ 8>|ω₁-ιn}⍤1 centres +seed←∨⌿{8>|ω₀-ιn ∧⊗ 8>|ω₁-ιn}¹ centres lap←{1⌽ω + ¯1⌽ω + 1⊖ω + ¯1⊖ω - 4×ω} [feed kill]←0.0545 0.062 step←{ diff --git a/nbs/glyphs/at.qmd b/nbs/glyphs/at.qmd index 3a101fd0..1d00becb 100644 --- a/nbs/glyphs/at.qmd +++ b/nbs/glyphs/at.qmd @@ -43,8 +43,8 @@ When a function `g` returns items of `Y` that selecting primitives took, `f@g Y` +\@∊ [3 1 0] [2 5] ⍝ [[3 4 4] [6 11]] 9@↑ 1 2 3 ⍝ 9 2 3 -@ 1↓⍣2 [1 2 3 4] ⍝ 1 2 ¯3 ¯4 -ι≢∘@< 30 10 20 ⍝ [2 0 1]ₓ -1+∘@{ω>15 # ω} 10 20 30 ⍝ 10 21 31 +ι≢ @< 30 10 20 ⍝ [2 0 1]ₓ +1+ @{ω>15 # ω} 10 20 30 ⍝ 10 21 31 ``` `g` may select a keyed or unkeyed position more than once. Which replacement that position keeps isn't promised. The updated array retains its keys. A write at a fill position is dropped. diff --git a/nbs/glyphs/backslash.qmd b/nbs/glyphs/backslash.qmd index 722aeabc..fdca5fb4 100644 --- a/nbs/glyphs/backslash.qmd +++ b/nbs/glyphs/backslash.qmd @@ -22,7 +22,7 @@ Each lane starts from the whole seed. Use Rank for separate seeds per cell. ```bpl M←[1 2 3◇4 5 6] -10 20+\⍤0 1 M ⍝ [11 13 16◇24 29 35] +10 20+\⁰ ¹ M ⍝ [11 13 16◇24 29 35] [10]+\1 2 3 ⍝ [[11] [13] [16]] ``` diff --git a/nbs/glyphs/circle-star.qmd b/nbs/glyphs/circle-star.qmd index 9e65cdba..2407f1f7 100644 --- a/nbs/glyphs/circle-star.qmd +++ b/nbs/glyphs/circle-star.qmd @@ -24,7 +24,7 @@ Uses complex logarithms where needed. `⊛0` is `¯∞`. `1⊛1` gives zero when ```bpl 2⊛⁻3 ⍝ 8 -⊛↢8∘⁻3 ⍝ 2 +⊛↢8 ⁻ 3 ⍝ 2 ``` ## Fast combinations diff --git a/nbs/glyphs/comma.qmd b/nbs/glyphs/comma.qmd index 195929cc..164f769e 100644 --- a/nbs/glyphs/comma.qmd +++ b/nbs/glyphs/comma.qmd @@ -16,12 +16,12 @@ Function. Hanzi: `连` (`連`). Ranks: `∞` monadic, `∞ ∞` dyadic 1 2,3 4 ⍝ 1 2 3 4 ``` -There is no laminate. `[x◇y]` has `x` and `y` as its major cells, along a new leading axis. `x,⍤0 y` pairs the items of `x` and `y` along a new last axis. +There is no laminate. `[x◇y]` has `x` and `y` as its major cells, along a new leading axis. `x,⁰y` pairs the items of `x` and `y` along a new last axis. ```bpl x←1 2 ◇ y←3 4 [x◇y] ⍝ [1 2◇3 4] -x,⍤0 y ⍝ [1 3◇2 4] +x,⁰y ⍝ [1 3◇2 4] ``` ## Inverse @@ -31,5 +31,5 @@ x,⍤0 y ⍝ [1 3◇2 4] ```bpl ,⁻1 2 3 ⍝ 1 2 3 1 2,⁻1 2 3 4 ⍝ 3 4 -,↢3 4∘⁻1 2 3 4 ⍝ 1 2 +,↢3 4 ⁻ 1 2 3 4 ⍝ 1 2 ``` diff --git a/nbs/glyphs/diamond-underbar.qmd b/nbs/glyphs/diamond-underbar.qmd index 76aba081..74dd49cd 100644 --- a/nbs/glyphs/diamond-underbar.qmd +++ b/nbs/glyphs/diamond-underbar.qmd @@ -9,8 +9,8 @@ Dyadic operator. Keys: `Alt-Minus Backtick`. Hanzi: `择` (`擇`) A unit selector picks one case, which runs on the whole arguments. ```bpl -cases←[- ⊢] ◇ abs←(0≤)⍚cases ◇ abs¯3 ⍝ 3 -cases←[- ⊢] ◇ abs←(0≤)⍚cases ◇ abs3 ⍝ 3 +cases←[- ⊢] ◇ abs←0≤ ⍚cases ◇ abs¯3 ⍝ 3 +cases←[- ⊢] ◇ abs←0≤ ⍚cases ◇ abs3 ⍝ 3 mul←1⍚[+ ×] ◇ 2 mul 3 ⍝ 6 mul←¯1⍚[+ ×] ◇ 2 mul 3 ⍝ 6 choose←>⍚[- ÷] ◇ 12 choose 3 ⍝ 4 @@ -21,11 +21,11 @@ choose←>⍚[- ÷] ◇ 12 choose 3 ⍝ 4 Any other selector picks a case for each cell of the argument. Unnamed axes of the selector take the argument's leading axes, and a named axis takes the argument's axis with that name. The argument's other axes form its cells. Each case runs once, on the list of all the cells that pick it. It gives one result for each of those cells, paired by key where both lists have keys, or a result with exactly one item, which fills them all, as `@` fills its selection. That item can be a single value or a list of one, such as `[¯2]`. A case that no cell picks doesn't run. Below, `√` never sees a negative number. ```bpl -(0≤)⍚[0 √] ¯4 9 16 ⍝ 0 3 4 +0≤ ⍚[0 √] ¯4 9 16 ⍝ 0 3 4 0 2 1 2⍚[- ⊢ 10×] 1 2 3 4 ⍝ ¯1 20 3 40 -(0≤)⍚[+/ ⊢] ¯1 4 ¯2 ⍝ ¯3 4 ¯3 -(0>)⍚[⊢ 1↓] ¯1 4 ¯2 ⍝ ¯2 4 ¯2 -(0<⊣/)⍚[0 ⊢] [¯1 2◇3 4] ⍝ [0 0◇3 4] +0≤ ⍚[+/ ⊢] ¯1 4 ¯2 ⍝ ¯3 4 ¯3 +0> ⍚[⊢ 1↓] ¯1 4 ¯2 ⍝ ¯2 4 ¯2 +0<⊣/ ⍚[0 ⊢] [¯1 2◇3 4] ⍝ [0 0◇3 4] ``` A left argument lines up with the right argument by position, or by key where both have keys: each case gets the left argument's cells at the positions of its right argument's cells. A key that the left argument lacks reads the fill. A key that only the left argument has is ignored. A unit left argument goes whole to every case. A left argument's axis of length 1 stretches to match, as agreement stretches it. With `⊣` and `⊢` as the cases, the selector picks each item from one argument or the other. @@ -41,13 +41,13 @@ A selector with a named axis picks cells along the argument's axis of that name. ```bpl m←["i":2 "j":3]ρι6ₓ -(4ₓ<+⌿)⍚[⊢ -] m ⍝ ["i":2 "j":3]ρ[0 ¯1 ¯2 3 ¯4 ¯5]ₓ +4ₓ<+⌿ ⍚[⊢ -] m ⍝ ["i":2 "j":3]ρ[0 ¯1 ¯2 3 ¯4 ¯5]ₓ ``` Under dynamic kinds, results keep their kinds, as Each's results do. Under static kinds, they join to one compact type, as a write's items do. Result cells keep the keys and names they agree on and pad differing shapes, as Rank does. A single value fills every item of its cells; when every result fills, the argument gives the cell shape. An argument with no cells gives an empty result: as Each does with prototypes, the case that the selector's fill picks runs on no cells, and the result is empty, with that case's cells. ```bpl -0 1 2⍚[5 (1↓)⍤1 ⊢] [1 2 3◇4 5 6◇7 8 9] ⍝ [5 5 5◇5 6 0◇7 8 9] +0 1 2⍚[5 (1↓)¹ ⊢] [1 2 3◇4 5 6◇7 8 9] ⍝ [5 5 5◇5 6 0◇7 8 9] ``` A selector with keys pairs with the argument by key, as arithmetic does. A cell whose key the selector lacks gets the fill. A key that only the selector has is ignored. @@ -68,7 +68,7 @@ A cell's derivative comes only from the case that the cell picks. Below, the cel Where the selector gives a Boolean for each item of a float argument, and every case is a function that can't fail, such as `⊢`, `-`, `2×` or a constant, `⍚` and `@[p]` can run each case on the whole argument, then keep for each item the result of the case it picks. That gives the same result faster. On a large argument, the selector's comparison, the cases and the pick then run as one [fused](../system/prefs.qmd) group. `•explain` names this `"masked select"`: ```bpl -(•explain "(0>)⍚[⊢ -] ¯1 4 ¯2").fast.rule ⍝ ["masked select"] +(•explain "0> ⍚[⊢ -] ¯1 4 ¯2").fast.rule ⍝ ["masked select"] ``` ## Errors diff --git a/nbs/glyphs/dot.qmd b/nbs/glyphs/dot.qmd index 5fdea058..8c494c30 100644 --- a/nbs/glyphs/dot.qmd +++ b/nbs/glyphs/dot.qmd @@ -15,10 +15,10 @@ Float and complex `+.×` read a large operand that is a transpose, or windows of Where `g` is a dfn, `X f.g Y` calls it once on all the pairings together, in a [batched call](../evaluation.qmd#functions-and-effects). The result is the same as from one call for each pairing. -[Rank](jot-diaeresis.qmd) and [Axis](quad-colon.qmd) can give `f.g` cells of rank 1. Where `g` is pervasive, `g` pairs the cells' items in one call and `f` folds along them. `X+.×⍤1Y` gives the dot product of each pair of rows at the cost of `+/X×Y`. Axis selects an axis that [`•index`](../system/index.qmd) names wherever each argument holds it. The other named axes pair by name. `xu.[b k]+.×⍠k⁝wu.[k o]` is then the matrix product in [index notation](../index-notation.qmd). A large one runs as one product. +[Rank](jot-diaeresis.qmd) and [Axis](quad-colon.qmd) can give `f.g` cells of rank 1. Where `g` is pervasive, `g` pairs the cells' items in one call and `f` folds along them. `X+.×¹Y` gives the dot product of each pair of rows at the cost of `+/X×Y`. Axis selects an axis that [`•index`](../system/index.qmd) names wherever each argument holds it. The other named axes pair by name. `xu.[b k]+.×⍠k⁝wu.[k o]` is then the matrix product in [index notation](../index-notation.qmd). A large one runs as one product. ```bpl -X←[1 2 3◇4 5 6] ◇ X+.×⍤1X ⍝ 14 77 +X←[1 2 3◇4 5 6] ◇ X+.×¹X ⍝ 14 77 xu←[2 3]ρι6ₓ ◇ wu←[3 4]ρι12ₓ ◇ [b o k]←•index 2 4 3 ◇ ∧/,(xu.[b k]+.×⍠k⁝wu.[k o])=xu+.×wu ⍝ $t ``` @@ -64,7 +64,7 @@ After a function, `.name` and `.[I]` read from the function's result, as they re v←10 20 30 40 .[[1 3]] v ⍝ 20 40 1 2 3 4 +.[[0 2]] v ⍝ 11 33 -10×∘@.[[1 3]]v ⍝ 10 200 30 400 +10× @.[[1 3]]v ⍝ 10 200 30 400 T←["a":1 "x":[10 20 30]] ⊢.a¨[T T] ⍝ 1 1 ⊢.x.[[2 0]] T ⍝ 30 10 diff --git a/nbs/glyphs/jot-diaeresis.qmd b/nbs/glyphs/jot-diaeresis.qmd index 831bacf1..e56e42c9 100644 --- a/nbs/glyphs/jot-diaeresis.qmd +++ b/nbs/glyphs/jot-diaeresis.qmd @@ -34,12 +34,12 @@ v←[[1 2] [3 4 5]] -⍤0⁝5 ⍝ ¯5 ``` -With rank `∞`, the cell is the whole argument, and rank `¯∞` is rank 0. For example, `⍤1 ∞` pairs each row on the left with the whole right argument. In the examples below, `+⌿×∘⍤1 ∞` is the matrix-vector product. `∘` gives Rank the whole train `+⌿×` as its left operand. With a matrix on the right, the same function multiplies matrices. +With rank `∞`, the cell is the whole argument, and rank `¯∞` is rank 0. For example, `⍤1 ∞` pairs each row on the left with the whole right argument. In the examples below, `+⌿× ⍤1 ∞` is the matrix-vector product. The space gives Rank the whole train `+⌿×` as its left operand. With a matrix on the right, the same function multiplies matrices. ```bpl m←[1 2 3◇4 5 6] -m +⌿×∘⍤1 ∞ [1 2 3] ⍝ 14 32 -m +⌿×∘⍤1 ∞ [1 10◇2 20◇3 30] ⍝ [14 140◇32 320] +m +⌿× ⍤1 ∞ [1 2 3] ⍝ 14 32 +m +⌿× ⍤1 ∞ [1 10◇2 20◇3 30] ⍝ [14 140◇32 320] ``` A function right operand computes the ranks from the arguments, as BQN's `⎉` does: `f⍤g Y` is `f⍤(g Y) Y`, and `X f⍤g Y` is `X f⍤(X g Y) Y`. [Axis](quad-colon.qmd) and [Stencil](quad-diamond.qmd) take a function right operand in the same way. Here each cell of `Y` with the rank of `X` pairs with `X`: diff --git a/nbs/glyphs/jot.qmd b/nbs/glyphs/jot.qmd index f7423dea..1d8a8975 100644 --- a/nbs/glyphs/jot.qmd +++ b/nbs/glyphs/jot.qmd @@ -9,16 +9,6 @@ Dyadic operator. Keys: `Alt-t`. Hanzi: `承` ``` See [Rank](jot-diaeresis.qmd) for applying a function to cells of a chosen rank. -## Before an operator - -`∘` before an operator finishes the current run as its left operand. `⊂⊢∘⌸` is `(⊂⊢)⌸`; `+/÷≢∘⍤1` applies the mean train at rank 1. Named operators have the same behavior. Spaces or parentheses keep any earlier function or left argument outside the run. - -```bpl -m←2 3ρι6 ◇ +/÷≢∘⍤1m ⍝ 1 4 -``` - -Before a function, `∘` still means Atop. [Composing functions](../composition.qmd#operators-on-trains) describes both uses. - ## Inverse `(f∘g)⁻Y` is `g⁻ f⁻ Y`. `X(f∘g)⁻Y` is `X g⁻ f⁻ Y`. diff --git a/nbs/glyphs/left-shoe-underbar.qmd b/nbs/glyphs/left-shoe-underbar.qmd index 05422d4f..69999cbe 100644 --- a/nbs/glyphs/left-shoe-underbar.qmd +++ b/nbs/glyphs/left-shoe-underbar.qmd @@ -16,10 +16,10 @@ Function. Keys: `Alt-Minus z`. Hanzi: `巢/段`. Ranks: `∞` monadic, `1 ∞` d 1 1 0 2⊆4 2ρι8ₓ ⍝ [[0 1◇2 3] [6 7◇]]ₓ ``` -Marks are nonnegative whole numbers. Unit and singleton marks extend. `N⊆⍠K Y` partitions along axis `K` instead. `N⊆⍤1 Y` partitions each row. Unlike [`⊂`](left-shoe.qmd), positive marks need not start a partition at every position. +Marks are nonnegative whole numbers. Unit and singleton marks extend. `N⊆⍠K Y` partitions along axis `K` instead. `N⊆¹Y` partitions each row. Unlike [`⊂`](left-shoe.qmd), positive marks need not start a partition at every position. ```bpl -1 1 0 1 1⊆⍤1 ["abcde"◇"fghij"] ⍝ ["ab" "de"◇"fg" "ij"] +1 1 0 1 1⊆¹["abcde"◇"fghij"] ⍝ ["ab" "de"◇"fg" "ij"] ``` ## Inverse diff --git a/nbs/glyphs/left-shoe.qmd b/nbs/glyphs/left-shoe.qmd index b1eb5e25..e9fd6f64 100644 --- a/nbs/glyphs/left-shoe.qmd +++ b/nbs/glyphs/left-shoe.qmd @@ -25,11 +25,11 @@ With [axes](quad-colon.qmd), `⊂⍠K Y` encloses cells on axes `K`. 1 0 1⊂3 2ρι6ₓ ⍝ [[0 1◇2 3] [4 5◇]]ₓ ``` -A mark greater than 1 starts extra empty partitions. Unit marks extend. `N⊂⍠K Y` partitions along axis `K` instead. `N⊂⍤1 Y` partitions each row. +A mark greater than 1 starts extra empty partitions. Unit marks extend. `N⊂⍠K Y` partitions along axis `K` instead. `N⊂¹Y` partitions each row. ```bpl 1 0 1⊂₁2 3ρι6ₓ ⍝ [[0 1◇3 4] [[2]◇[5]]]ₓ -1 0 1⊂⍤1 (2 3ρι6ₓ) ⍝ [[0 1] [2]◇[3 4] [5]]ₓ +1 0 1⊂¹(2 3ρι6ₓ) ⍝ [[0 1] [2]◇[3 4] [5]]ₓ ``` See also [`⊆`](left-shoe-underbar.qmd). diff --git a/nbs/glyphs/left-tail-arrow.qmd b/nbs/glyphs/left-tail-arrow.qmd index 6d16e7ad..0801163d 100644 --- a/nbs/glyphs/left-tail-arrow.qmd +++ b/nbs/glyphs/left-tail-arrow.qmd @@ -29,6 +29,6 @@ See [Before](right-tail-arrow.qmd), [Atop / Rank](jot-diaeresis.qmd) and [Over]( With an array operand, `(f↢X)⁻Y` inverts `f` with `X` fixed on the right. With two functions, `X(f↢g)⁻Y` inverts `f` with `X` fixed, then applies `g⁻`. The hook `(×↢*)⁻` gives the Lambert W function. ```bpl --↢3∘⁻7 ⍝ 10 -×↢*∘⁻1 ⍝ 0.567143290409784 +-↢3 ⁻ 7 ⍝ 10 +×↢* ⁻ 1 ⍝ 0.567143290409784 ``` diff --git a/nbs/glyphs/minus.qmd b/nbs/glyphs/minus.qmd index e73d837d..2605bf4b 100644 --- a/nbs/glyphs/minus.qmd +++ b/nbs/glyphs/minus.qmd @@ -29,5 +29,5 @@ Characters shift by code point. Character differences are exact integers. ```bpl 10-⁻3 ⍝ 7 --↢3∘⁻7 ⍝ 10 +-↢3 ⁻ 7 ⍝ 10 ``` diff --git a/nbs/glyphs/obelus.qmd b/nbs/glyphs/obelus.qmd index e9464504..88006624 100644 --- a/nbs/glyphs/obelus.qmd +++ b/nbs/glyphs/obelus.qmd @@ -34,7 +34,7 @@ An integer divided by zero gives the integer limit of its sign: i64's under dyna ```bpl 12÷⁻4 ⍝ 3 -÷↢4∘⁻3 ⍝ 12 +÷↢4 ⁻ 3 ⍝ 12 ``` ## Errors diff --git a/nbs/glyphs/partial.qmd b/nbs/glyphs/partial.qmd index f73366a2..657860c7 100644 --- a/nbs/glyphs/partial.qmd +++ b/nbs/glyphs/partial.qmd @@ -15,7 +15,7 @@ cart←{[r t]←ω ◇ [r×2○t r×1○t]} ◇ -.×cart∂ 2 0.5 ⍝ 2 ```bpl ⊼∂3ₓ ⍝ 6 -p←["a":1 "b":2] ◇ ⊢.a×⊢.b∘∂ p ⍝ ["a":2 "b":1] +p←["a":1 "b":2] ◇ ⊢.a×⊢.b ∂ p ⍝ ["a":2 "b":1] -∂3ₓ₁ ⍝ ¯1ₛ ``` @@ -23,7 +23,7 @@ For the derivative at each item of a function that works item by item, different ```bpl x←0 0.5 1 -1○∂⍤0 x ⍝ 1 0.8775825619 0.5403023059 +1○∂⁰ x ⍝ 1 0.8775825619 0.5403023059 {1○x+ω}∂0 ⍝ 1 0.8775825619 0.5403023059 ``` @@ -41,7 +41,7 @@ f←[1 2 3]ₓ⌻ ◇ f∂2ₓ ⍝ 14 {ω⌻2ₓ}∂ [1 2 3]ₓ ⍝ 1 2 4 ``` -`∂` runs `f` once. With more than one number in `X`, it records the linear steps of the derivative as `f` runs, then reads the Jacobian from that record: once for each result item, or once for each number in `X`, whichever is fewer. A gradient therefore costs a small multiple of one run of `f`, however many numbers `X` holds. `∂` differentiates a [map](../terms.qmd#term-map) inside `f` through the map's [batched call](../evaluation.qmd#functions-and-effects), on whole arrays. So does `∂` inside a map, as in `f∂⍤1`, with one batched call for all the cells. The gradient of a structural copy or a selection, such as a reversal, a transpose or windows, adds each item's gradient back where the item came from in its source. [`•explain`](../system/explain.qmd) reports each such accumulation, apart from one that adds a single ascending run of positions as a block, as the gradients of take and drop do. The record keeps the values those steps need until `∂` finishes. Its memory grows with the work that `f` does. A value that `f` writes to an outer name loses its tangents when `∂` returns. [Automatic differentiation](../autodiff.qmd) explains how `∂` works. +`∂` runs `f` once. With more than one number in `X`, it records the linear steps of the derivative as `f` runs, then reads the Jacobian from that record: once for each result item, or once for each number in `X`, whichever is fewer. A gradient therefore costs a small multiple of one run of `f`, however many numbers `X` holds. `∂` differentiates a [map](../terms.qmd#term-map) inside `f` through the map's [batched call](../evaluation.qmd#functions-and-effects), on whole arrays. So does `∂` inside a map, as in `f∂¹`, with one batched call for all the cells. The gradient of a structural copy or a selection, such as a reversal, a transpose or windows, adds each item's gradient back where the item came from in its source. [`•explain`](../system/explain.qmd) reports each such accumulation, apart from one that adds a single ascending run of positions as a block, as the gradients of take and drop do. The record keeps the values those steps need until `∂` finishes. Its memory grows with the work that `f` does. A value that `f` writes to an outer name loses its tangents when `∂` returns. [Automatic differentiation](../autodiff.qmd) explains how `∂` works. No derivative flows back through a value that [`•detach`](../system/detach.qmd) gives. diff --git a/nbs/glyphs/pi.qmd b/nbs/glyphs/pi.qmd index 4c0a4220..3c542267 100644 --- a/nbs/glyphs/pi.qmd +++ b/nbs/glyphs/pi.qmd @@ -25,5 +25,5 @@ Use [`○`](circle.qmd) to turn an angle into a unit-circle point. ```bpl π⁻π2 ⍝ 2 2π⁻4 ⍝ π0.5 -π↢2∘⁻4 ⍝ 8÷π1 +π↢2 ⁻ 4 ⍝ 8÷π1 ``` diff --git a/nbs/glyphs/quad-diamond.qmd b/nbs/glyphs/quad-diamond.qmd index a5b0836f..8f99d970 100644 --- a/nbs/glyphs/quad-diamond.qmd +++ b/nbs/glyphs/quad-diamond.qmd @@ -6,7 +6,7 @@ Dyadic operator. Keys: `Alt-q Backtick`. Hanzi: `邻` (`鄰`) ```bpl +/⌺3 [1 2 3 4] ⍝ 3 6 9 7 -(+/⌺3 [1 2 3 4])≡+/⍤¯1 [¯3]↕[1 2 3 4] ⍝ $t +(+/⌺3 [1 2 3 4])≡+/⁻¹ [¯3]↕[1 2 3 4] ⍝ $t ``` A two-row specification gives sizes, then movements. An options record, as `↕` takes, can also name an edge mode, which a window's positions past an end read by. The edge mode is fill unless the record names another. Its `fill` gives the item that padding with fill reads. diff --git a/nbs/glyphs/quad-equal.qmd b/nbs/glyphs/quad-equal.qmd index d03f2023..afe7751d 100644 --- a/nbs/glyphs/quad-equal.qmd +++ b/nbs/glyphs/quad-equal.qmd @@ -21,10 +21,10 @@ BPL computes each of these combinations by an algorithm of its own, in any spell | `≢⊢ ⌸Y` or `K (≢⊢)⌸Y` | any keys | counts each group's major cells without building the groups | | `K (f/⊢)⌸Y` or `K (f⌿⊢)⌸Y`, with `f` of `+ ⌈ ⌊`, or `×` of floats | a vector `Y` of floats, integers or Booleans | folds every group in one pass, without a call of the operand for each group | -`∘` also gives Key a whole train as its operand, as in `≢⊢∘⌸Y` or `K +/⊢∘⌸ Y`. +A space gives Key a whole train as its operand, as in `≢⊢ ⌸Y` or `K +/⊢ ⌸ Y`. ```bpl -≢⊢∘⌸"banana" ⍝ [1 3 2]ₓ -1 1 2 +/⊢∘⌸ 10 20 30 ⍝ 30 30 -(•explain "1 1 2 +/⊢∘⌸ 10 20 30").fast.rule ⍝ ["group folds"] +≢⊢ ⌸"banana" ⍝ [1 3 2]ₓ +1 1 2 +/⊢ ⌸ 10 20 30 ⍝ 30 30 +(•explain "1 1 2 +/⊢ ⌸ 10 20 30").fast.rule ⍝ ["group folds"] ``` diff --git a/nbs/glyphs/radical.qmd b/nbs/glyphs/radical.qmd index ebb58d19..daf7962d 100644 --- a/nbs/glyphs/radical.qmd +++ b/nbs/glyphs/radical.qmd @@ -24,7 +24,7 @@ Function. Keys: `Alt-3`. Hanzi: `根`. Ranks: `0` monadic, `0 0` dyadic ```bpl √⁻3 ⍝ 9 3√⁻2 ⍝ 8 -√↢8∘⁻2 ⍝ 3 +√↢8 ⁻ 2 ⍝ 3 ``` ## Errors diff --git a/nbs/glyphs/right-tail-arrow.qmd b/nbs/glyphs/right-tail-arrow.qmd index f8e4c0fe..112022f7 100644 --- a/nbs/glyphs/right-tail-arrow.qmd +++ b/nbs/glyphs/right-tail-arrow.qmd @@ -30,6 +30,6 @@ See [After](left-tail-arrow.qmd), [Atop / Rank](jot-diaeresis.qmd) and [Over](ci With an array operand, `(X↣f)⁻Y` is `X f⁻ Y`. With two functions, `X(f↣g)⁻Y` inverts `g` with `f X` fixed on the left. ```bpl -2↣×∘⁻6 ⍝ 3 +2↣× ⁻ 6 ⍝ 3 3(-↣+)⁻7 ⍝ 10 ``` diff --git a/nbs/glyphs/slash.qmd b/nbs/glyphs/slash.qmd index 1e35abd4..aaa378d9 100644 --- a/nbs/glyphs/slash.qmd +++ b/nbs/glyphs/slash.qmd @@ -27,7 +27,7 @@ A dfn that reduces several lanes, such as each row of a matrix, runs each stage 10-/1 2 3 ⍝ ¯8 10+/2 3ρι6ₓ ⍝ [13 22] ⊂10 +/ 1 2 3 ⍝ ⊂16 -10 20 +/⍤0 1 [2 3]ρι6ₓ ⍝ [13 32] +10 20 +/⁰ ¹ [2 3]ρι6ₓ ⍝ [13 32] ``` Fixed-width integer reductions keep the promoted fixed type. A wider seed selects a wider accumulator without widening the stored input array: diff --git a/nbs/glyphs/star.qmd b/nbs/glyphs/star.qmd index e09ae37f..ab26e1c3 100644 --- a/nbs/glyphs/star.qmd +++ b/nbs/glyphs/star.qmd @@ -33,7 +33,7 @@ See also function [power `⍣`](star-diaeresis.qmd). ```bpl 2*⁻8 ⍝ 3 -*↢2∘⁻9 ⍝ 3 +*↢2 ⁻ 9 ⍝ 3 ``` ## Fast combinations diff --git a/nbs/glyphs/superscript-minus.qmd b/nbs/glyphs/superscript-minus.qmd index da5fcbfe..146dba08 100644 --- a/nbs/glyphs/superscript-minus.qmd +++ b/nbs/glyphs/superscript-minus.qmd @@ -7,7 +7,7 @@ Monadic operator. Keys: `Alt-_`. Hanzi: `反` ```bpl *⁻1 ⍝ 0 2×⁻10 ⍝ 5 -+↢3∘⁻10 ⍝ 7 ++↢3 ⁻ 10 ⍝ 7 ``` BPL infers inverses of the primitives and compositions listed under [Power](star-diaeresis.qmd). `f⁻←g` [attaches an inverse](../assignment.ipynb#inverses-and-derivatives) to a named function. @@ -18,6 +18,6 @@ The minus is bare: no superscript digit follows it. `f⁻¹` means [Rank](jot-di ⌽⁻ ¹[1 2◇3 4] ⍝ [2 1◇4 3] ``` -An inverse applies to the whole derived function on its left. Use `∘` before `⁻` when that function ends in a number: `+↢3∘⁻10`. Parentheses or a space also group the function: `(+↢3)⁻10` or `+↢3 ⁻ 10`. +An inverse applies to the whole derived function on its left. A space groups a function that ends in a number: `+↢3 ⁻ 10`. Parentheses also work: `(+↢3)⁻10`. Errors: `DOMAIN` for an unknown inverse or an array operand. diff --git a/nbs/glyphs/tricolon.qmd b/nbs/glyphs/tricolon.qmd index a1f73f32..f8989962 100644 --- a/nbs/glyphs/tricolon.qmd +++ b/nbs/glyphs/tricolon.qmd @@ -9,4 +9,4 @@ h←- ◇ m←5 ◇ h⁝m ⍝ ¯5 ≥⍣3⁝5 ⍝ 8 ``` -`h⁝m` is `h(m)`, and `≥⍣3⁝5` is `(≥⍣3)5`. A space also groups runs, as [Syntax](../syntax.qmd#runs) describes. `⁝` leaves the grouping unchanged. Before an operator, [`∘`](jot.qmd#before-an-operator) finishes the current run as its left operand. Parentheses still group compound operands and nested trains. [Composing functions](../composition.qmd#separating-an-operand-from-its-argument) gives examples. +`h⁝m` is `h(m)`, and `≥⍣3⁝5` is `(≥⍣3)5`. A space also groups runs, as [Syntax](../syntax.qmd#runs) describes: `⊂⊢ ⌸` gives Key the whole train `⊂⊢` as its operand. `⁝` leaves the grouping unchanged. Parentheses still group compound operands and nested trains. [Composing functions](../composition.qmd#separating-an-operand-from-its-argument) gives examples. diff --git a/nbs/index-notation.qmd b/nbs/index-notation.qmd index cacf895a..bd2b02a6 100644 --- a/nbs/index-notation.qmd +++ b/nbs/index-notation.qmd @@ -23,7 +23,7 @@ Each index has its length from the start. BPL doesn't infer a range from the rea ## A neural network -This network has one hidden layer of tanh units (`7○`) and fits `y` from `x` by mean squared error. `p` holds its parameters. `mlp` is the tacit form, where `b(+⍤1)` adds the bias to each row. In the index form, `mlpi`, `n` names the samples, `i` the inputs and `h` the hidden units. Each line of `mlpi` gives its formula for one sample and one unit. `a` is the tanh of the bias at `h` plus the sum over `i` of `x` at `n i` times `w` at `i h`. Both forms give the same loss and the same gradient: +This network has one hidden layer of tanh units (`7○`) and fits `y` from `x` by mean squared error. `p` holds its parameters. `mlp` is the tacit form, where `b(+¹)` adds the bias to each row. In the index form, `mlpi`, `n` names the samples, `i` the inputs and `h` the hidden units. Each line of `mlpi` gives its formula for one sample and one unit. `a` is the tanh of the bias at `h` plus the sum over `i` of `x` at `n i` times `w` at `i h`. Both forms give the same loss and the same gradient: ```bpl •prefs ["seed":42] @@ -31,7 +31,7 @@ x←¯0.5+¿[64 8]ρ0 ◇ y←1○+/x p←["w":0.5ׯ0.5+¿[8 16]ρ0 "b":16ρ0 "v":0.1ׯ0.5+¿16ρ0 "c":0] mlp←{ [x y]←α ◇ [w b v c]←ω - h←7○b(+⍤1)x+.×w + h←7○b(+¹)x+.×w +/÷≢ ⊼y-c+h+.×v } [x y]mlp p ⍝ 0.3262591588 @@ -61,9 +61,9 @@ heads←{h←0 2 1 3⍉ω ◇ (¯2↓ρh , ×/¯2↑ρh)ρh} attn←{ [wqkv wo]←α [q k v]←1 3 0 2 4⍉ω+.×wqkv - s←mask(+⍤2) q+.×⍤2⍉⍤2⁝k ÷ √(ρq)₋₁ + s←mask(+²) q+.ײ⍉²k ÷ √(ρq)₋₁ e←*s-⌈/s - (heads e÷+/e +.×⍤2 v)+.×wo + (heads e÷+/e +.ײ v)+.×wo } attni←{ [wqkv wo]←α @@ -92,7 +92,7 @@ Line by line, in `attni`: This objective scores how well a mixture of Gaussian components fits a set of points, with a prior on each component's precision. `gp` holds each component's log weight `alpha` and mean `mu`. Its precision factor has the exponentials of `q` on its diagonal and `l` below it. `low` masks `l` to the part below the diagonal. `eye` is the identity matrix. `•detach` makes the log-sum-exp shifts constants to `∂`. -`gmm` is the rank form. `l×⍤2 low` masks each component's matrix, `(*q)×⍤[1 2]eye` puts each component's row of `*q` on a diagonal, `⍉⍤2` transposes each component's factor, and `⌿` folds along the first axis, the components. In the index form, `gmmi`, `n` names the points, `k` the components, and `d` and `e` the dimensions. Both forms give the same objective and the same gradient: +`gmm` is the rank form. `lײ low` masks each component's matrix, `(*q)×¹ ²eye` puts each component's row of `*q` on a diagonal, `⍉²` transposes each component's factor, and `⌿` folds along the first axis, the components. In the index form, `gmmi`, `n` names the points, `k` the components, and `d` and `e` the dimensions. Both forms give the same objective and the same gradient: ```bpl •prefs ["seed":42] @@ -100,13 +100,13 @@ gx←¿[50 4]ρ0 ◇ eye←=⊗⍨ι4 ◇ low←>⊗⍨ι4 gp←["alpha":¿3ρ0 "mu":¿[3 4]ρ0 "q":0.1׿[3 4]ρ0 "l":0.1׿[3 4 4]ρ0] gmm←{ [alpha mu q l]←ω - L←l×⍤2 low - Q←L+(*q)×⍤[1 2]eye - sq←+/⊼(α(-⍤1)⍤[2 1]mu)+.×⍤2⍉⍤2⁝Q + L←lײ low + Q←L+(*q)×¹ ²eye + sq←+/⊼(α(-¹)² ¹mu)+.ײ⍉²Q t←(alpha++/q)-0.5×sq m←⌈⌿•detach t am←⌈/•detach alpha - (+/m+⊛+⌿*t-⍤1m) + (0.5×(+/,⊼*q)++/,⊼L) - (≢α)×am+⊛+/*alpha-am + (+/m+⊛+⌿*t-¹m) + (0.5×(+/,⊼*q)++/,⊼L) - (≢α)×am+⊛+/*alpha-am } gx gmm gp ⍝ ¯0.8795002466 gmmi←{ @@ -125,7 +125,7 @@ g←gx gmm∂ gp ◇ h←gx gmmi∂ gp 1E¯12>⌈/,|g.l-h.l ⍝ $t ``` -Each form reads better in different lines. Rank suits the lines that work on whole components: `⍤2` and `⍤[1 2]` pair each component's matrix and row, and `⌿` folds along the components. Index notation suits `sq`. There `α.[n e]-mu.[k e]` pairs every point with every mean by name, where the rank form needs the nested Rank `α(-⍤1)⍤[2 1]mu`. `+.×⍠e` also names the axis that the product sums along. +Each form reads better in different lines. Rank suits the lines that work on whole components: `²` and `¹ ²` pair each component's matrix and row, and `⌿` folds along the components. Index notation suits `sq`. There `α.[n e]-mu.[k e]` pairs every point with every mean by name, where the rank form needs the nested Rank `α(-¹)² ¹mu`. `+.×⍠e` also names the axis that the product sums along. ## Why it works this way diff --git a/nbs/indexing.ipynb b/nbs/indexing.ipynb index 210d82ac..0f076167 100644 --- a/nbs/indexing.ipynb +++ b/nbs/indexing.ipynb @@ -985,7 +985,7 @@ } ], "source": [ - "10×∘@[1 3]u" + "10× @[1 3]u" ] }, { @@ -1013,7 +1013,7 @@ } ], "source": [ - "10×∘@.[[1 3]] u" + "10× @.[[1 3]] u" ] }, { diff --git a/nbs/llms.txt b/nbs/llms.txt index 77bc4396..63f6d56d 100644 --- a/nbs/llms.txt +++ b/nbs/llms.txt @@ -15,8 +15,8 @@ Entry: Dyalog diff, example, defining page. Index, not reference: read a feature ## Language - [Syntax](syntax.html.md): BQN stranding: mark strands with `[]` (per BQN's 5-year retrospective), except spaced literals (step 1) and subjects side by side (step 3); like BQN, a space is semantic. `⁝` separates tokens and stops literal stranding without ending the run: `h⁝m`≡`h(m)`, `f⍣3⁝0`≡`(f⍣3)0`. 3 steps: 1. spaced literals join, 1 vector: `1 2`, `"ab" "cd"`; even operand+arg: `+/⍠2 3 3 3↕m` has operand `2 3 3 3`, write `+/⍠2 3⁝3 3↕m`. 2. each other run→`(run)`: `a+b × c+d`≡`(a+b)(×)(c+d)`; fn between two runs: space both sides: `a×b + c`≡`(a×b)+c`; `a×b +c`≡`[a×b ; +c]`; `a×b+ c`≡`(a×b+)c`, train `a×(b+c)`; `1+k (⌈/⊢)⌸ a`≡`(1+k)((⌈/⊢)⌸)(a)`. 3. read as APL, right to left; subjects side by side strand: `a b`≡`(a)(b)`≡`[a b]` only if neither touches; `1+a b`≡`(1+a)(b)`→`11 20`, 1 plus both: `1+[a b]`→`11 21`; `n 2ρ0`≡`(n)(2ρ0)`→`[3 [0 0]]`, names never join literal strands: write `[n 2]ρ0`. no needless spaces; join by deleting spaces, not adding parens: `1+k(⌈/⊢)⌸a`. name fn, name arg: `h⁝m` `h[m n]`. name operand, glyph arg: `+/⍠kω`. list: `[+/x ; +/x ÷ ≢x]`. name digits: `x_1`; `x1`≡`x(1)`. -- [Evaluation](evaluation.html.md): run ending in fn: train. `+/÷≢ x` mean; `+/÷≢x`≡`+/÷(≢x)`. `⁝` doesn't group a train: `+/÷≢⁝x` still means the latter. A space before an arg makes the run on its left a train: `10÷√1++/⍠i x` calls dyadic `√`, write `10÷√1++/⍠i⁝x`; `+/,m+⍤2 P` applies the train `+/,m+⍤2` to `P`, write `+/,m(+⍤2)P`. Calls give values: a call's result, a field read from it, a subscript's selection and a scope's result bind as arrays even when they hold a function, so `+/÷(f 0)` is an expression, never a train; name a returned function first: `g←f 0 ◇ +/÷g`; call a selected function with Agenda: `1⍚fs x`, `2 (1⍚fs) 3`. -- [Composition](composition.html.md): read before writing tests or examples. trains: `f⁝g Y`≡`f(g Y)`, `f⁝g⁝h Y`≡`(f Y)g(h Y)`; `∘` atop, `⍥` over, `↣` `↢` bind left, right; `⍨` self, commute; `⊢` `⊣` stand for args in trains; `⁻` inverse; `@` under. worse→better, same results: `0.5×⊢+2÷⊢`→`⊽⁻+÷`; `{ω,1}`→`,↢1`; `×⍨x`→`x²`; `≥⍣3⊢5`→`≥⍣3⁝5`; `+/⍠i⊢m`→`+/⍠i⁝m`. Prefer spaces for top-level groups/subtrains: `+/÷≢ ⊼v`, `mean_square←+/÷≢ ⊼`, `f⁝g⁝h x`. A space groups the whole left run, including any prefix. Nested `()`: try the inner pair first. Prefer `⁝` where a boundary is needed: `f⍣3⁝0`, `(+/÷≢)⍤1⁝2 3ρι6`; with a left arg too, `Q+.×⍠e⁝r`, or group the derived fn, `10 20(+⍤1)m`: whichever reads better. Keep compound operands grouped: `⌊@(10×)x`. Add nothing where tokens already stay distinct: `+/⍤1m`. +- [Evaluation](evaluation.html.md): run ending in fn: train. `+/÷≢ x` mean; `+/÷≢x`≡`+/÷(≢x)`. `⁝` doesn't group a train: `+/÷≢⁝x` still means the latter. A space before an arg makes the run on its left a train: `10÷√1++/⍠i x` calls dyadic `√`, write `10÷√1++/⍠i⁝x`; `+/,m+² P` applies the train `+/,m+²` to `P`, write `+/,m(+²)P`. Calls give values: a call's result, a field read from it, a subscript's selection and a scope's result bind as arrays even when they hold a function, so `+/÷(f 0)` is an expression, never a train; name a returned function first: `g←f 0 ◇ +/÷g`; call a selected function with Agenda: `1⍚fs x`, `2 (1⍚fs) 3`. +- [Composition](composition.html.md): read before writing tests or examples. trains: `f⁝g Y`≡`f(g Y)`, `f⁝g⁝h Y`≡`(f Y)g(h Y)`; `∘` atop, `⍥` over, `↣` `↢` bind left, right; `⍨` self, commute; `⊢` `⊣` stand for args in trains; `⁻` inverse; `@` under. worse→better, same results: `0.5×⊢+2÷⊢`→`⊽⁻+÷`; `{ω,1}`→`,↢1`; `×⍨x`→`x²`; `≥⍣3⊢5`→`≥⍣3⁝5`; `+/⍠i⊢m`→`+/⍠i⁝m`. Prefer spaces for top-level groups/subtrains: `+/÷≢ ⊼v`, `mean_square←+/÷≢ ⊼`, `f⁝g⁝h x`. An operator at a run's start takes the whole previous run as its left operand: `⊂⊢ ⌸`≡`(⊂⊢)⌸`, `+/÷≢ ¹`≡`(+/÷≢)¹`; with both args: `0 1 0 ⊂⊢ ⌸ "abc"`. A space groups the whole left run, including any prefix. Nested `()`: try the inner pair first. Prefer `⁝` where a boundary is needed: `f⍣3⁝0`, `+/÷≢ ⍤1⁝2 3ρι6`; with a left arg too, `Q+.×⍠e⁝r`, or group the derived fn, `10 20(+⍤1)m`: whichever reads better. Keep compound operands grouped: `⌊@(10×)x`. Add nothing where tokens already stay distinct: `+/¹m`. - [Agreement](evaluation.html.md#agreement-and-pervasion): pervasive fns, Each, Rank align leading axes: `[1 2 3◇4 5 6]+10 20`→`[11 12 13◇24 25 26]`. length-1 axes expand. - [Maps](evaluation.html.md#functions-and-effects): Each, Rank, stencils, outer products call a dfn once on all cells where possible: `{ω×ω+1}¨v` costs ≈ `v×v+1`. data-dependent guard, output, nested result, value-dependent shape: a call per cell. dfn fold/scan along matrix rows: a call per column, on all rows. `f.g`: dfn `g` once, on all pairings. - [Arrays](arrays.html.md): numbers, chars, fns: atoms, not scalars (BQN). `⊂` always adds a layer: `⊂3 ≡ 3`→`$f`. array of fns applies to a following subject: `2 [+ ×] 3`→`5 6`. @@ -40,10 +40,10 @@ Entry: Dyalog diff, example, defining page. Index, not reference: read a feature - [Glyphs](glyphs.html.md): every glyph, name. page `glyphs/.html.md`: read before use. - [Removed](glyphs.html.md#language-wide-differences-from-dyalog-apl): `Y[I]` indexing, `f[A]` axes, `∘.f`, windowed reduce, laminate. - [`@`](glyphs/at.html.md) Under: `f@g`: `f` on `g`'s selection, written back (BQN `⌾`, not Dyalog `@`): `⌊@(10×)1.25 2.78`→`1.2 2.7`. positions/`[p]`: left arg aligns with right by position, by key if both keyed: `10 20 30 +@[0 2] 1 2 3`→`11 2 33`. -- [`∘`](glyphs/jot.html.md) atop: `α f∘g ω`≡`f α g ω` (BQN; Dyalog `α f g ω`): `10 -∘| ¯3`→`¯7`. Before an operator, finishes the whole current run as its left operand: `⊂⊢∘⌸`≡`(⊂⊢)⌸`, `+/÷≢∘⍤1`≡`(+/÷≢)⍤1`. Spaces keep earlier functions and left arguments outside that run. +- [`∘`](glyphs/jot.html.md) atop: `α f∘g ω`≡`f α g ω` (BQN; Dyalog `α f g ω`): `10 -∘| ¯3`→`¯7`. - [`⍤`](glyphs/jot-diaeresis.html.md) rank, only: `+/¹m` (`+/⍤1 m`) row sums. fn right operand computes ranks. - [`⍠`](glyphs/quad-colon.html.md) axis: along axes by number or name: `+/⍠0 m`, `+/⍠"month" sales`. options record sets fill: `5↑⍠["fill":¯1] 1 2`→`1 2 ¯1 ¯1 ¯1`. -- [`⌺`](glyphs/quad-diamond.html.md) stencil: Rank over centred windows: `f⌺3 v`≡`f⍤¯1 [¯3]↕v`; `life⌺[3 3] g`≡`life⍤¯2 [¯3 ¯3]↕g`. `f` gets each window alone, no `α` (J `;._3`). fn right operand computes window from args. +- [`⌺`](glyphs/quad-diamond.html.md) stencil: Rank over centred windows: `f⌺3 v`≡`f⁻¹ [¯3]↕v`; `life⌺[3 3] g`≡`life⁻² [¯3 ¯3]↕g`. `f` gets each window alone, no `α` (J `;._3`). fn right operand computes window from args. - [`.`](glyphs/dot.html.md) dot: after array: `.name` field, `.[I]` select. Standalone `.[I]` is a selector fn. `T.¨[I]`, `T.¹ ²[I]`, `T.⍤(1 2)[I]` modify that selector, then apply to `T`; `f.¨[I]` selects from `f`'s result. Named/grouped operator heads need a space: `T. op[I]`, `T. (op)[I]`. Tight `T.op[I]`/`T.(expr)[I]` keep field/scope meanings. First current-level bracket starts selectors; groups/dfns stay whole. Subject first, selectors once. Monadic `f.g`: J determinant: `-.×[1 2◇3 4]`→`¯2`. - [`⍣`](glyphs/star-diaeresis.html.md) power: count list keeps history: `2×⍣(ι5) 1`→`1 2 4 8 16`. `f⍣∞` fixed point. - [`/`](glyphs/slash.html.md) [`⌿`](glyphs/slash-bar.html.md) [`\`](glyphs/backslash.html.md) [`⍀`](glyphs/backslash-bar.html.md): reduce, scan only. left arg: right seed (BQN): `2+/1 2 3`→`8`. `0ₓ₈+/v`: i64 accumulation of fixed bytes, no widened input; `+/vₓ`: ordinary ints. scans run left to right. diff --git a/nbs/overview.ipynb b/nbs/overview.ipynb index 43480998..efa7ec6f 100644 --- a/nbs/overview.ipynb +++ b/nbs/overview.ipynb @@ -705,7 +705,7 @@ "id": "701f3e94", "metadata": {}, "source": [ - "Rank, `⍤`, applies a function to [cells](terms.qmd#term-cell) of a chosen rank. The 1-cells of a matrix are its rows:" + "Rank applies a function to [cells](terms.qmd#term-cell) of a chosen rank. Numeric superscripts are its short spelling: `mean¹` is `mean⍤1`. The 1-cells of a matrix are its rows:" ] }, { @@ -725,7 +725,7 @@ } ], "source": [ - "mean⍤1 m" + "mean¹ m" ] }, { diff --git a/nbs/principles.ipynb b/nbs/principles.ipynb index 9d7ccb16..172c581e 100644 --- a/nbs/principles.ipynb +++ b/nbs/principles.ipynb @@ -1113,7 +1113,7 @@ "id": "77efd97e", "metadata": {}, "source": [ - "`⊂⍤1` partitions each row instead, and `⊂₁` splits a matrix into blocks of columns.\n", + "`⊂¹` partitions each row instead, and `⊂₁` splits a matrix into blocks of columns.\n", "\n", "Encode and Decode put digits on the last axis, as J's `#:` and `#.` do. Encode turns each number of a vector into a row of digits. Decode turns the rows back into numbers:" ] @@ -1175,7 +1175,7 @@ } ], "source": [ - "≡⍤0 [1 [2 3]]" + "≡⁰ [1 [2 3]]" ] }, { @@ -1183,7 +1183,7 @@ "id": "478eb67e", "metadata": {}, "source": [ - "As a result, `⊢⍤0` returns its argument unchanged, even when the argument is nested. A function under `⍤0` sees numbers as literals and selection give them. Each, `¨`, gives the function the items themselves." + "As a result, `⊢⁰` returns its argument unchanged, even when the argument is nested. A function at rank 0 sees numbers as literals and selection give them. Each, `¨`, gives the function the items themselves." ] }, { diff --git a/nbs/python.ipynb b/nbs/python.ipynb index a4b9ef0f..3058c192 100644 --- a/nbs/python.ipynb +++ b/nbs/python.ipynb @@ -1374,7 +1374,7 @@ "id": "aa988119", "metadata": {}, "source": [ - "Comparisons return arrays. `%` uses Python's operand order and `//` is floor division. Array `@` applies BPL's `+.×⍤2`. It multiplies vectors and matrices, broadcasting leading batch axes.\n", + "Comparisons return arrays. `%` uses Python's operand order and `//` is floor division. Array `@` applies BPL's `+.ײ`. It multiplies vectors and matrices, broadcasting leading batch axes.\n", "\n", "Array `&`, `|` and `~` require Boolean or integer inputs and perform bitwise AND, OR and NOT. Their BPL counterparts are `∧ᵇ`, `∨ᵇ` and `~ᵇ` ([Bitwise](glyphs/superscript-b.qmd)). Plain `∧` and `∨` retain LCM and GCD." ] @@ -2019,7 +2019,7 @@ "\n", "Function attributes append functions to a train. `plus.reduce.divide.tally` builds the three-part train `+/÷≢`.\n", "\n", - "An operator attribute applies to the whole function built so far. In `sqrt.plus.reduce`, `.reduce` applies to the two-function train `√+`. The full chain `sqrt.plus.reduce.divide.tally` means `√+∘/÷≢`, equivalently `(√+)/÷≢`: reduce with `√+`, then divide by the count.\n", + "An operator attribute applies to the whole function built so far. In `sqrt.plus.reduce`, `.reduce` applies to the two-function train `√+`. The full chain `sqrt.plus.reduce.divide.tally` means `√+ /÷≢`, equivalently `(√+)/÷≢`: reduce with `√+`, then divide by the count.\n", "\n", "Calling a function with one function argument composes the functions. `sqrt(plus.reduce / tally)` means `√+/÷≢`, the square root of the mean. On `[4., 4.]`, composition gives `2`, while the dot chain gives `√2`." ] @@ -2334,7 +2334,7 @@ "id": "802ab031", "metadata": {}, "source": [ - "`f.power.each(n)` constructs `f⍣n∘¨` (equivalently `(f⍣n)¨`), just like `f.power(n).each`. For multiple missing operands, successive calls fill the innermost construction first: `f.power.each.power(n)(m)` constructs `f⍣n∘¨∘⍣m`. Complete the operands before passing evaluation arguments.\n", + "`f.power.each(n)` constructs `f⍣n ¨` (equivalently `(f⍣n)¨`), just like `f.power(n).each`. For multiple missing operands, successive calls fill the innermost construction first: `f.power.each.power(n)(m)` constructs `f⍣n ¨⍣m`. Complete the operands before passing evaluation arguments.\n", "\n", "Arithmetic between functions makes forks: `f+g` is `(f+g)`. `f @ g` is inner product. `f << g` is the Atop `f∘g`, and `f >> g` is `g∘f`. `f ** n` is Power. `atop(f, g, h)` is `f << g << h`; it accepts two or more functions. Use `fork(f, g, h)` for a fork. `value >> (f >> g)` calls the composed function once. `value >> f >> g` makes separate calls and misses whole-composition optimizations. `|` binds arguments to functions; array `|` remains bitwise OR. Python's precedence applies when building these expressions:" ] @@ -3060,7 +3060,7 @@ "id": "735a5794", "metadata": {}, "source": [ - "`basedpl.syntax.linear` shows BPL source with its structural [grouping](syntax.qmd#runs) made explicit. Operator-stage `∘` keeps its spelling because operator names resolve during evaluation. Strands of literals appear in brackets. Runs beside a run-ending dot keep their spacing. Other runs of several tokens appear in parentheses, as does a literal that touches the name before it, such as the `1` in `x1`. `basedpl.worker.fresh` shows the linear form before each result, as the timing and checking tools in `basedpl.bpltests` do, so unexpected grouping shows up beside the code:" + "`basedpl.syntax.linear` shows BPL source with its structural [grouping](syntax.qmd#runs) made explicit. Strands of literals appear in brackets. Runs beside a run-ending dot keep their spacing. Other runs of several tokens appear in parentheses, as does a literal that touches the name before it, such as the `1` in `x1`. `basedpl.worker.fresh` shows the linear form before each result, as the timing and checking tools in `basedpl.bpltests` do, so unexpected grouping shows up beside the code:" ] }, { diff --git a/nbs/scripts.ipynb b/nbs/scripts.ipynb index 18c3ad5f..e58c010e 100644 --- a/nbs/scripts.ipynb +++ b/nbs/scripts.ipynb @@ -621,7 +621,7 @@ "id": "3ed12e5e", "metadata": {}, "source": [ - "`∘` before an operator finishes the whole function run: `+↢3∘⁻10` also gives `7`. A space before the superscript works too:" + "A space before the superscript applies it to the whole preceding run, so the parentheses can be left out:" ] }, { diff --git a/nbs/study/01_basics.ipynb b/nbs/study/01_basics.ipynb index e9933708..afd3b874 100644 --- a/nbs/study/01_basics.ipynb +++ b/nbs/study/01_basics.ipynb @@ -2618,7 +2618,7 @@ { "data": { "text/plain": [ - "2 5 3 3 3" + "3 5 0 5 5" ] }, "metadata": {}, @@ -2638,7 +2638,7 @@ { "data": { "text/plain": [ - "0.4217883456 0.4926436415" + "0.5836406264 0.07477551829" ] }, "metadata": {}, @@ -2674,7 +2674,7 @@ { "data": { "text/plain": [ - "16 27 1 34 37 29 3 49 5 28 24 2 8" + "13 45 28 18 9 42 39 44 35 23 16 49 32" ] }, "metadata": {}, diff --git a/nbs/study/03_operators.ipynb b/nbs/study/03_operators.ipynb index 0b34de9b..70f6aeee 100644 --- a/nbs/study/03_operators.ipynb +++ b/nbs/study/03_operators.ipynb @@ -2405,7 +2405,7 @@ } ], "source": [ - "+⌿⍤2 cube" + "+⌿² cube" ] }, { @@ -2678,7 +2678,7 @@ "id": "ca6378d6", "metadata": {}, "source": [ - "Inverses apply to bound functions too. `2↣×⁻` undoes doubling. A numeric superscript touching a final number instead applies to that number: `+↢3⁻¹` adds a third. Bare `+↢3⁻` tries to invert the number and raises `DOMAIN`. Put `∘` before `⁻` to invert the whole function run. Parentheses and a space before `⁻` also work." + "Inverses apply to bound functions too. `2↣×⁻` undoes doubling. A numeric superscript touching a final number instead applies to that number: `+↢3⁻¹` adds a third. Bare `+↢3⁻` tries to invert the number and raises `DOMAIN`. Put parentheses around the bound function, or a space before `⁻`, to invert it as a whole." ] }, { @@ -2717,7 +2717,7 @@ ], "source": [ "2↣×⁻10\n", - "+↢3∘⁻10\n", + "(+↢3)⁻10\n", "+↢3 ⁻ 10" ] }, @@ -2755,8 +2755,8 @@ } ], "source": [ - ",↢3 4∘⁻1 2 3 4\n", - "⍪↢3 4∘⁻[1 2◇3 4]" + ",↢3 4 ⁻1 2 3 4\n", + "⍪↢3 4 ⁻[1 2◇3 4]" ] }, { @@ -2990,7 +2990,7 @@ } ], "source": [ - "×↢*∘⁻1" + "×↢* ⁻1" ] }, { @@ -3523,7 +3523,7 @@ } ], "source": [ - "inc⍣3∘⁻10" + "inc⍣3 ⁻10" ] }, { diff --git a/nbs/study/06_rearranging-arrays.ipynb b/nbs/study/06_rearranging-arrays.ipynb index 1ca95592..36dabe47 100644 --- a/nbs/study/06_rearranging-arrays.ipynb +++ b/nbs/study/06_rearranging-arrays.ipynb @@ -1509,7 +1509,7 @@ ], "source": [ "v←10 20 30 40\n", - "10×∘@.[[1 3]] v" + "10× @.[[1 3]] v" ] }, { @@ -1558,7 +1558,7 @@ } ], "source": [ - "≥@[1 3]∘⁻10 20 30 40" + "≥@[1 3] ⁻10 20 30 40" ] }, { @@ -1594,7 +1594,7 @@ } ], "source": [ - "abs←0≤∘⍚[- ⊢]\n", + "abs←0≤ ⍚[- ⊢]\n", "abs¯3" ] }, @@ -1643,7 +1643,7 @@ } ], "source": [ - "0≤∘⍚[0 √] ¯4 9 16" + "0≤ ⍚[0 √] ¯4 9 16" ] }, { diff --git a/nbs/style.qmd b/nbs/style.qmd index fd147bd1..9a64b570 100644 --- a/nbs/style.qmd +++ b/nbs/style.qmd @@ -6,17 +6,17 @@ Use spaces to show the top-level structure of an expression. Keep parentheses wh A function between two runs takes a space on each side, as in `a×b + c`. A space on one side only changes the grouping: `a×b +c` is the strand `[a×b ; +c]`, and `a×b+ c` applies the train `a×b+` to `c`. -`⁝` separates a derived function's operand from its right argument where a boundary is needed: `f⍣3⁝0`, `10÷√1++/⍠i⁝m`, `+/÷≢∘⍤1⁝2 3ρι6`. It stops literal stranding without grouping the expression before it. A vector argument can touch the operand in brackets: `≥⍣2[1 2 3]`. Add nothing where tokens already stay distinct, as in `+/⍤1m` or `+/÷≢∘⍠d⊼n`. +`⁝` separates a derived function's operand from its right argument where a boundary is needed: `f⍣3⁝0`, `10÷√1++/⍠i⁝m`, `+/÷≢ ⍤1⁝2 3ρι6`. It stops literal stranding without grouping the expression before it. A vector argument can touch the operand in brackets: `≥⍣2[1 2 3]`. Add nothing where tokens already stay distinct, as in `+/¹m` or `+/÷≢ ⍠d⊼n`. With a left argument as well, `⁝` works the same way, as in `Q+.×⍠e⁝r`. Parentheses around the derived function also show it between its arguments: `10 20(+⍤1)m`. Use whichever reads better. Keep parentheses where a compound operand or nested train needs grouping, as in `⌊@(10×)x`. -A space groups the whole run before it, including any prefix. `+/÷≢ ⊼y-c+h+.×v` applies the mean train to its complete argument. `mean_square←+/÷≢ ⊼` separates an atop's subtrains. `f⁝g⁝h x` keeps three named functions in one run. `+/÷≢⁝v` doesn't group the mean train. For nested parentheses, try removing the inner pair first: `(+⌿ N*Ms ÷ ≢N)*÷Ms`. Naming a train that a line uses twice can read better: `mean⍤1m`. +A space groups the whole run before it, including any prefix. `+/÷≢ ⊼y-c+h+.×v` applies the mean train to its complete argument. `mean_square←+/÷≢ ⊼` separates an atop's subtrains. `f⁝g⁝h x` keeps three named functions in one run. `+/÷≢⁝v` doesn't group the mean train. For nested parentheses, try removing the inner pair first: `(+⌿ N*Ms ÷ ≢N)*÷Ms`. Naming a train that a line uses twice can read better: `mean¹m`. Lowercase `j` reads most clearly in complex literals, as in `3j4`. Uppercase `J` is an input alias, and only its own tests need it. Archived upstream source keeps its original form. Array notation shows a literal matrix's rows directly, as in `[10 20 30◇40 50 60]`, where a reshape hides them. A reshape still suits an example about reshape. A `◇` between rows reads best with no spaces around it. A `◇` between statements reads best with a space on each side. -Brackets build a list from names or expressions. A bare literal list, such as `1 2 3`, is a shorthand. In brackets, a list of names reads as a list at a glance, as in `[a b]`, even where `a b` would also work. `[n 2]ρ0`, `[x],y`, `[a◇b]` and `f⍤1 m` read more directly than APL's `(n,2)ρ0`, `(⊂x),y`, `⊃[a b]` and `⊃f¨↓m`. Where no item of a bracket list contains a space, spaces separate the items more lightly than `;`: `[i j]` rather than `[i;j]`. +Brackets build a list from names or expressions. A bare literal list, such as `1 2 3`, is a shorthand. In brackets, a list of names reads as a list at a glance, as in `[a b]`, even where `a b` would also work. `[n 2]ρ0`, `[x],y`, `[a◇b]` and `f¹m` read more directly than APL's `(n,2)ρ0`, `(⊂x),y`, `⊃[a b]` and `⊃f¨↓m`. Where no item of a bracket list contains a space, spaces separate the items more lightly than `;`: `[i j]` rather than `[i;j]`. -Before an operator, `∘` finishes the whole current run as its left operand: `≢⊢∘⌸x`, `+/÷≢∘⍤1m`. Keep parentheses where they show nested structure more clearly. A compound right operand keeps its grouping, as in `⌊@(10×)x`. Spacing also makes a run into an operand: after a dyadic operator and a space, the whole next run is the operand, as in `⌊@ 10× x`. When both operands are compound, parentheses around each show the grouping: `(•ucs 9)@(⍸tabs)ω`. An operand can keep its parentheses when a left argument comes before it, as in `tree (α⍢)/ next`. Report any case where none of these forms reads well. +A run beginning with an operator takes the whole preceding run as its left operand. Use a space for a short function operand, as in `≢⊢ ⌸x` or `+/÷≢ ¹m`. With two arguments, separate each part: `K +/⊢ ⌸ Y`. Keep parentheses where they show nested structure more clearly. A compound right operand keeps its grouping, as in `⌊@(10×)x`. After a dyadic operator and a space, the whole next run is the operand, as in `⌊@ 10× x`. When both operands are compound, parentheses around each show the grouping: `(•ucs 9)@(⍸tabs)ω`. An operand can keep its parentheses when a left argument comes before it, as in `tree (α⍢)/ next`. Report any case where none of these forms reads well. A train reads more directly than naming an argument twice: `+/÷≢ v` rather than `+/v ÷ ≢v`. A tacit form usually reads more directly than a dfn. A dfn reads better where the tacit form would be longer or clearly awkward. diff --git a/nbs/syntax.qmd b/nbs/syntax.qmd index 99acbab6..13c6a06e 100644 --- a/nbs/syntax.qmd +++ b/nbs/syntax.qmd @@ -60,7 +60,7 @@ A literal strand can appear on each side. In `+/⍠2 3⁝3 3↕m`, the operand o ## Runs -Outside brackets, spaces divide a statement into [runs](terms.qmd#term-run). A group in brackets, parentheses or braces counts as one token, even when it contains spaces. The operator rules below can join runs or finish an operand within one. Each completed run must give one value: a subject, a function, or a lone operator such as the `/` in `+ / x`. A run that gives anything else is a `SYNTAX` error. +Outside brackets, spaces divide a statement into [runs](terms.qmd#term-run). A group in brackets, parentheses or braces counts as one token, even when it contains spaces. The operator rules below can join runs. Each completed run must give one value: a subject, a function, or a lone operator such as the `/` in `+ / x`. A run that gives anything else is a `SYNTAX` error. BPL reads a statement in three steps: @@ -74,7 +74,7 @@ A call's result binds where a subject would, whatever it returns, and so do a fi A run that ends in a dyadic operator takes the next run as its right operand: `⌊@ 10× x` is `(⌊@)(10×)(x)`, where `10×` is the operand of `@`. A run that starts with an operator takes the previous run as its left operand: `≢⊢ ⌸x` is `(≢⊢)(⌸x)`, where `≢⊢` is the operand of `⌸`. [Evaluation](evaluation.qmd) explains operands. -Before an operator, `∘` finishes the current run as its left operand: `⊂⊢∘⌸` is `(⊂⊢)⌸`. This depends on what the next item holds, like the operator rules that join runs. Before a function, `∘` remains Atop. [Composing functions](composition.qmd#operators-on-trains) gives examples. +A space can thus replace parentheses around a short function operand: `⊂⊢ ⌸` is `(⊂⊢)⌸`. Keep the arguments outside that operand's run: `0 1 0 ⊂⊢ ⌸ "abc"`. [Composing functions](composition.qmd#operators-on-trains) gives examples. ```bpl a←1 ◇ b←2 ◇ c←3 ◇ d←4 ◇ a+b × c+d ⍝ 21 diff --git a/nbs/system/decompose.qmd b/nbs/system/decompose.qmd index ffa65948..f4b5fd90 100644 --- a/nbs/system/decompose.qmd +++ b/nbs/system/decompose.qmd @@ -4,7 +4,7 @@ | `kind` | Fields | Factors | |---|---|---| -| `"svd"` | `u`, `s`, `v` | `m` is `u×⍤1s +.× +⍉v`, with the singular values `s` in descending order | +| `"svd"` | `u`, `s`, `v` | `m` is `u×¹s +.× +⍉v`, with the singular values `s` in descending order | | `"qr"` | `q`, `r` | `m` is `q+.×r`, with orthonormal columns in `q`, and `r` upper triangular | | `"eigen"` | `values`, `vectors` | each column of `vectors` is an eigenvector of `m`, for the eigenvalue at the same position in `values` | | `"cholesky"` | `l` | `m` is `l+.×+⍉l`, with `l` lower triangular | @@ -41,7 +41,7 @@ d←0 0⍉f.u +/⊛|d ⍝ 0.6931471805599453 ``` -`kind •decompose⁻ factors` multiplies a record of factors back into the matrix, as the table shows. For `"eigen"`, the matrix is `vectors×⍤1values +.× ⌹vectors`, and for `"lu"` it's `[⍋p]⌷l+.×u`. Eigenvectors that aren't independent, such as those of the defective matrix `[1 1◇0 1]`, can't determine the matrix. +`kind •decompose⁻ factors` multiplies a record of factors back into the matrix, as the table shows. For `"eigen"`, the matrix is `vectors×¹values +.× ⌹vectors`, and for `"lu"` it's `[⍋p]⌷l+.×u`. Eigenvectors that aren't independent, such as those of the defective matrix `[1 1◇0 1]`, can't determine the matrix. ```bpl f←"cholesky" •decompose [4 2◇2 3] diff --git a/nbs/system/explain.qmd b/nbs/system/explain.qmd index 6a607ae6..2857fc73 100644 --- a/nbs/system/explain.qmd +++ b/nbs/system/explain.qmd @@ -71,7 +71,7 @@ s←2×y+1 ◇ (•explain "5↑s").forced.items ⍝ [5]ₓ r←⌽y ◇ (•explain "r₀←0").forced.function ⍝ ["←"] (•explain "(10↑)∘⍋ y").fast.rule ⍝ ["partial grade"] x←¿1000ρ0 ◇ p←¿1000ρ1000 -(•explain "{+/, 3↕ω (×⍤1) 1 2 1}∂ x").accumulations.items ⍝ ⍬ₓ +(•explain "{+/, 3↕ω (×¹) 1 2 1}∂ x").accumulations.items ⍝ ⍬ₓ (•explain "{+/ω.[p]}∂ x").accumulations ⍝ ["items":[1000]ₓ "size":[1000]ₓ "path":["in place"]] z←1000ρ0ₓ ◇ (•explain "z.[p]+←1ₓ").accumulations.path ⍝ ["on a copy"] (•explain "{2(×⍣ω)1}¨ι5ₓ").fallbacks ⍝ ["reason":["a cell's value"] "items":[5]ₓ] diff --git a/nbs/system/replace.qmd b/nbs/system/replace.qmd index 9462b6b9..753e15a9 100644 --- a/nbs/system/replace.qmd +++ b/nbs/system/replace.qmd @@ -4,7 +4,7 @@ ```bpl "ab12 cd3" •replace ["([a-z]+)([0-9]+)" "$2:$1"] ⍝ "12:ab 3:cd" -•replace↢["[0-9]+" "#"]∘¨"a1" "b22" ⍝ "a#" "b#" +•replace↢["[0-9]+" "#"] ¨"a1" "b22" ⍝ "a#" "b#" ``` Errors: `DOMAIN` for invalid patterns, non-text arguments, and a right argument that isn't a pattern and a template; `SYNTAX` for the wrong valence; `LIMIT` for oversized results. diff --git a/nbs/system/special.qmd b/nbs/system/special.qmd index f10451a5..4853296a 100644 --- a/nbs/system/special.qmd +++ b/nbs/system/special.qmd @@ -28,7 +28,7 @@ Each function works item by item on real numbers and gives floats, as `⊛` does [pg bi]←•special "polygamma" "betainc" 1 pg 1 ⍝ 1.644934067 [2 3] bi 0.5 ⍝ 0.6875 -[2 3◇4 5] (bi⍤1 0) 0.5 0.25 ⍝ 0.6875 0.1138153076 +[2 3◇4 5] bi¹ ⁰ 0.5 0.25 ⍝ 0.6875 0.1138153076 ``` `∂` differentiates each function in its last argument. The slope of `gammaln` is digamma, digamma's is `1 polygamma`, and each polygamma's is the next order's. `beta` also differentiates in a. The order of `polygamma`, the a of `gammainc` and the pair of `betainc` have no slope, and `∂` gives `UNSUPPORTED` for them: diff --git a/nbs/xml.ipynb b/nbs/xml.ipynb index cc894fa3..cccf8bd7 100644 --- a/nbs/xml.ipynb +++ b/nbs/xml.ipynb @@ -901,7 +901,7 @@ } ], "source": [ - "edges←+/+/k×⍤2win\n", + "edges←+/+/kײwin\n", "•image |edges" ] } diff --git a/python/basedpl/syntax.py b/python/basedpl/syntax.py index a3a2229b..4ef0a50d 100644 --- a/python/basedpl/syntax.py +++ b/python/basedpl/syntax.py @@ -47,7 +47,7 @@ def node(kind, start, end, children, error): return node(*_parse(text)) def linear(text): - "Show BPL's structural grouping. Literal strands are in brackets and multi-token runs in parentheses, except beside a run-ending dot. Multi-token bracket items use ` ; `. A literal touching a name, as in `x1`, is parenthesized. Operator-stage `∘` stays explicit: operator names resolve at evaluation." + "Show BPL's structural grouping. Literal strands are in brackets and multi-token runs in parentheses, except beside a run-ending dot. Multi-token bracket items use ` ; `. A literal touching a name, as in `x1`, is parenthesized." dotted = lambda n: n and n.kind == 'Run' and n.children[-1].text == "." def form(n, before=None): if n.kind in ('Comment', 'Error'): return n.text diff --git a/src/eval/binder.rs b/src/eval/binder.rs index 0a415e58..723645e7 100644 --- a/src/eval/binder.rs +++ b/src/eval/binder.rs @@ -7,11 +7,6 @@ use crate::{ }; use std::{borrow::Cow, sync::Arc}; -fn stage_marker(node: &Node) -> bool { - matches!(node.kind, NodeKind::Operator(OperatorKind::Atop)) - || matches!(&node.kind, NodeKind::Embedded(Value::Operator(op)) if matches!(*op.0, OperatorNode::Primitive(OperatorKind::Atop))) -} - impl Session { /// Lower selector sections and data-first operator tails before runs bind their operands. fn sections<'a>(&self, nodes: &'a [Node]) -> Cow<'a, [Node]> { @@ -113,25 +108,9 @@ impl Session { _ => members, } } - /// Finish the current run before an operator: `⊂⊢∘⌸` is `(⊂⊢)⌸`. Names and dot paths use their resolved categories. - fn stages<'a>(&self, nodes: &'a [Node]) -> Cow<'a, [Node]> { - let boundary = |i: usize| stage_marker(&nodes[i]) && nodes.get(i + 1).is_some_and(|next| self.static_category(next).valence().is_some()); - if !(1..nodes.len()).any(&boundary) { return Cow::Borrowed(nodes); } - let (mut out, mut start) = (Vec::with_capacity(nodes.len()), 0); - for (i, node) in nodes.iter().enumerate() { - // Selector lowering can flatten runs; an operator still takes the run before it as its operand. - if i > 0 && !crate::syntax::touching(&nodes[i - 1], node) && self.static_category(node).valence().is_none() { start = out.len(); } - if boundary(i) && out.len() > start { - let inner = out.split_off(start); - out.push(Node { span: crate::syntax::cover(&inner), kind: NodeKind::Group(inner) }); - } else { out.push(node.clone()); if matches!(node.kind, NodeKind::Assign) { start = out.len(); } } - } - Cow::Owned(out) - } - - /// Rewrite dot reads and operator-stage boundaries. + /// Rewrite dot reads. pub(super) fn members_with<'a>(&self, nodes: &'a [Node]) -> Cow<'a, [Node]> { - if !Self::has_members(nodes) { return self.stages(nodes); } + if !Self::has_members(nodes) { return Cow::Borrowed(nodes); } let mut out: Vec = Vec::with_capacity(nodes.len()); // Whether the last node in `out` is the right operand of a `.` after a function. let (mut i, mut on_function) = (0, false); @@ -211,7 +190,7 @@ impl Session { node.kind = NodeKind::Operator(OperatorKind::Super(Superscript::Mark(crate::number::Mark::Rational))); } } - match self.stages(&out) { Cow::Borrowed(_) => Cow::Owned(out), Cow::Owned(staged) => Cow::Owned(staged) } + Cow::Owned(out) } /// Whether a run ends in a dyadic operator, which then takes the next run as its right operand. @@ -227,25 +206,15 @@ impl Session { /// Join each run that starts with an operator to the node before it, as the run's first token: `≢⊢ ⌸x` reads as `(≢⊢)⌸x`. A run before it joins as a group. A joined run that still starts with an operator joins again: `+ / ¨x` reads as `+/¨x`. No join reaches across `←`. fn joined<'a>(&self, nodes: &'a [Node]) -> Cow<'a, [Node]> { let starts = |node: &Node| matches!(&node.kind, NodeKind::Run(inner) if self.starts_with_operator(inner)); - let joins = |before: &Node, node: &Node| { - starts(node) - || matches!(&before.kind, NodeKind::Run(inner) if inner.last().is_some_and(stage_marker)) && self.static_category(node).valence().is_some() - }; - if !nodes.windows(2).any(|w| joins(&w[0], &w[1])) { return Cow::Borrowed(nodes); } + if !nodes.iter().skip(1).any(starts) { return Cow::Borrowed(nodes); } let mut out: Vec = Vec::with_capacity(nodes.len()); for node in nodes { let mut node = node.clone(); - while out.last().is_some_and(|before| !matches!(before.kind, NodeKind::Assign) && joins(before, &node)) { + while out.last().is_some_and(|before| !matches!(before.kind, NodeKind::Assign)) && starts(&node) { let before = out.pop().expect("a node is before this run"); let span = Span { source: before.span.source.clone(), range: before.span.range.start..node.span.range.end }; - let before = match before.kind { - NodeKind::Run(mut run) => { - if run.last().is_some_and(stage_marker) { run.pop(); } - Node { span: crate::syntax::cover(&run), kind: NodeKind::Group(run) } - } - _ => before, - }; - let inner = match node.kind { NodeKind::Run(inner) => inner, _ => vec![node] }; + let before = match before.kind { NodeKind::Run(run) => Node { kind: NodeKind::Group(run), span: before.span }, _ => before }; + let NodeKind::Run(inner) = node.kind else { unreachable!() }; node = Node { kind: NodeKind::Run(std::iter::once(before).chain(inner).collect()), span }; } out.push(node); diff --git a/tests/core.rs b/tests/core.rs index 141dec1c..9d1332da 100644 --- a/tests/core.rs +++ b/tests/core.rs @@ -511,22 +511,18 @@ fn operator_categories_and_singleton_replicate() { } #[test] -fn operator_stage_boundaries() { +fn spaced_operator_operands() { let s = Session::new(); - s.eval("w←1 2 3 ◇ m←2 3ρι6 ◇ op←⌸ ◇ ops←[\"key\":⌸]"); - for (stage, grouped) in [ - ("0 1 0 ⊂⊢∘⌸ \"abc\"", "0 1 0 (⊂⊢)⌸ \"abc\""), ("+/÷≢∘⍤1⁝m", "(+/÷≢)⍤1⁝m"), ("+/÷≢∘¹m", "(+/÷≢)¹m"), - ("+↢3∘⁻10", "(+↢3)⁻10"), ("+/w×∘∂ 4 5 6", "(+/w×)∂ 4 5 6"), ("custom←{⍶ω} ◇ -÷∘custom 2", "(-÷){⍶ω} 2"), - ("0 1 0 ⊂⊢∘op \"abc\"", "0 1 0 (⊂⊢)op \"abc\""), ("0 1 0 ⊂⊢∘ops.key \"abc\"", "0 1 0 (⊂⊢)ops.key \"abc\""), - ("+/÷≢∘⍤1∘¨[m m]", "((+/÷≢)⍤1)¨[m m]"), ("-÷∘∘+ 2", "(-÷)∘+ 2"), ("+/÷≢∘ ⍤1⁝m", "(+/÷≢)⍤1⁝m"), - ("+/÷≢ ∘⍤1⁝m", "(+/÷≢)⍤1⁝m"), ("f←+/÷≢∘⍤1 ◇ f m", "(+/÷≢)⍤1⁝m"), ("√ +/÷≢∘⍤1⁝m", "√ (+/÷≢)⍤1⁝m"), - ("≢ -÷ ∘ ¨ 1 4 9", "3ₓ"), ("≢ +/÷≢ ∘ ⍤ 1 m", "2ₓ"), ("T←[1 2;3 4] ◇ i←[0] ◇ ≢ -÷∘¨T.¨[i]", "2ₓ"), + s.eval("w←1 2 3 ◇ m←2 3ρι6"); + for (spaced, grouped) in [ + ("0 1 0 ⊂⊢ ⌸ \"abc\"", "0 1 0(⊂⊢)⌸\"abc\""), ("+/÷≢ ⍤1m", "(+/÷≢)⍤1m"), ("+↢3 ⁻ 10", "(+↢3)⁻10"), + ("+/w× ∂ 4 5 6", "(+/w×)∂ 4 5 6"), ("T←[1 2;3 4] ◇ i←[0] ◇ ≢ -÷ ¨T.¨[i]", "2ₓ"), ] { let expected = evaluated(&s, grouped).unwrap(); - assert_same(evaluated(&s, stage), &expected); + assert_same(evaluated(&s, spaced), &expected); } equiv_in(&s, "√∘+/1 3 5", "(√+)/1 3 5"); - assert!(s.eval("∘⌸").error.is_some()); + assert!(s.eval("⊂⊢∘⌸").error.is_some()); } #[test] diff --git a/tests/reference/aplcart.bpl b/tests/reference/aplcart.bpl index 9a42d268..f053e4ae 100644 --- a/tests/reference/aplcart.bpl +++ b/tests/reference/aplcart.bpl @@ -961,7 +961,7 @@ X f↣g↢h Y ⍝ ¯18 [15ₚ "" [0 1 2◇3 4 5◇6 7 8]ₓ "" [3 12 21]ₓ] ⍝ aplcart/table.tsv:589 — Running sum of Is consecutive elements of N -[+/∘ 2↣↕ 2 2 3 2 2;"";5 5ρι9ₓ;"";(+/∘(3↣↕)⍤1) 5 5ρι9ₓ] +[+/∘ 2↣↕ 2 2 3 2 2;"";5 5ρι9ₓ;"";(+/∘(3↣↕)¹) 5 5ρι9ₓ] [[4 5 5 4]ₚ "" [0 1 2 3 4◇5 6 7 8 0◇1 2 3 4 5◇6 7 8 0 1◇2 3 4 5 6]ₓ "" [3 6 9◇18 21 15◇6 9 12◇21 15 9◇9 12 15]ₓ] ⍝ aplcart/table.tsv:590 — Row-wise alternating sum: ((N[1]-N[2])+N[3])-N[4]+… @@ -1438,19 +1438,19 @@ Y←[1 2;3 4 5] ◇ {0}¨Y ⍝ 0 0 X←1 2 f←, Y←3 4 -X f⍤0 Y ⍝ [1 3◇2 4] +X f⁰ Y ⍝ [1 3◇2 4] ⍝ aplcart/table.tsv:733 — Apply scalar function f between vector Mv and each column of Nm Mv←1 2 f←+ Nm←2 3ρι6ₓ -Mv f⍤0 1 Nm ⍝ [1 2 3◇5 6 7] +Mv f⁰ ¹ Nm ⍝ [1 2 3◇5 6 7] ⍝ aplcart/table.tsv:734 — Apply f between vector Mv and each row of Nm Mv←1 2 3 f←+ Nm←2 3ρι6ₓ -Mv f⍤1 Nm ⍝ [1 3 5◇4 6 8] +Mv f¹ Nm ⍝ [1 3 5◇4 6 8] ⍝ aplcart/table.tsv:735 — Replacing first major cell of Y with Xs Xs←99ₓ @@ -1530,7 +1530,7 @@ Y←[1 2;3 4] [X]⌷⊃Y ⍝ 2 3 ⍝ aplcart/table.tsv:753 — Continued fraction convergents with terms N; Reduce each prefix to preserve right association -N←2 3 4 ◇ +↢÷/∘¨,\N ⍝ 2 2.333333333333333 2.307692307692307 +N←2 3 4 ◇ +↢÷/ ¨,\N ⍝ 2 2.333333333333333 2.307692307692307 ⍝ aplcart/table.tsv:754 — Turn off all 1s before first 0 (remove leading 1s) B←1 1 0 1 0 1 0 ◇ ∧\↣/₁∘(2↣↕)) N ⍝ 0 0 0 1 0 @@ -2558,7 +2558,7 @@ Y←3 1 3 2 ◇ ↑⌽∘, Y ⍝ 2 ⍝ aplcart/table.tsv:1046 — Select: each element of Iv selects a cell from Y Iv←[[0 1] [1 2]] Y←2 3ρι6ₓ -Iv ⊃↣⌷⍤0 99 Y ⍝ [1 5]ₓ +Iv ⊃↣⌷⁰ ⁹⁹ Y ⍝ [1 5]ₓ ⍝ aplcart/table.tsv:1047 — Indices of dimensions of Y Y←3 1 3 2 ◇ ι∘≢ρ Y ⍝ [0]ₓ @@ -2846,7 +2846,7 @@ B←1 1 0 1 0 1 0 ◇ ~∨/∘, B ⍝ $f ⍝ aplcart/table.tsv:1123 — Join scalar elements of vector Yv with separator Xs Xs←9 Yv←4 5 6 -Xs 1↓↢,,⍤0 Yv ⍝ 4 9 5 9 6 +Xs 1↓↢,,⁰ Yv ⍝ 4 9 5 9 6 ⍝ aplcart/table.tsv:1124 — Shift before: Inserting X at front/left/top of Y, pushing corresponding cells off the back/right/bottom edge X←1 2 @@ -2869,7 +2869,7 @@ Y←3 1 3 2 Is ↑,⍥⊂↓ Y ⍝ [[3 1] [3 2]] ⍝ aplcart/table.tsv:1128 — Increment rank by inserting a new dimension before the trailing one -ρ (⊃,∘⊂⍤1) 2 3 4ρ$a ⍝ [2 3 1 4]ₓ +ρ (⊃,∘⊂¹) 2 3 4ρ$a ⍝ [2 3 1 4]ₓ ⍝ aplcart/table.tsv:1129 — Prototype (converts characters to spaces, numbers to zeros) Y← ["ab";1 2] ◇ ↑0ρ,Y ⍝ " " @@ -2983,7 +2983,7 @@ Nm←[0 0j1◇0j1 0] ◇ ⌹≡⍉∘+ Nm ⍝ $t D←"Abc 19 Σς!" ◇ (¯1↣•c=1↣•c)D ⍝ $f $f $f $t $t $t $t $f $f $t ⍝ aplcart/table.tsv:1162 — Indices of first blanks in rows of array D -D← ["abc "◇"a b"◇" xyz"] ◇ ι↢' '⍤1 D ⍝ [3 1 0]ₓ +D← ["abc "◇"a b"◇" xyz"] ◇ ι↢' ' ¹ D ⍝ [3 1 0]ₓ ⍝ aplcart/table.tsv:1164 — Shuffle major cells; Reviewed deterministic random-operation invariant; independently checked in Dyalog and through the Rust reference worker; Assert shape, range, uniqueness, permutation preservation, rounding bounds or deterministic sorting; no sampled values or seed are compared Y←4 2ρι8ₓ @@ -3034,11 +3034,11 @@ N←2 ¯3 4 N←1 4 16 ◇ ×⌿*↢÷≢ₐ N ⍝ 4 ⍝ aplcart/table.tsv:1176 — Row-wise percentage per row -N←[1 2 3◇4 5 6] ◇ 100×(⊢÷⍤1 0+/) N +N←[1 2 3◇4 5 6] ◇ 100×(⊢÷¹ ⁰+/) N [16.666666666666664 33.33333333333333 50◇26.666666666666668 33.33333333333333 40] ⍝ aplcart/table.tsv:1177 — Column-wise percentage per column -N←[1 2 3◇4 5 6] ◇ 100×(⊢÷⍤1+⌿) N +N←[1 2 3◇4 5 6] ◇ 100×(⊢÷¹+⌿) N [20 28.57142857142857 33.33333333333333◇80 71.42857142857143 66.66666666666666] ⍝ aplcart/table.tsv:1178 — Apply function f (optionally with left argument X) to last cell of Y @@ -3067,7 +3067,7 @@ Js←3 Is ↑>⍥|⌽, Js ⍝ ¯2 ⍝ aplcart/table.tsv:1184 — Increment rank by inserting a new dimension after the leading one -ρ (⊃∘,∘⊂⍤¯1) 2 3 4ρ$a ⍝ [2 1 3 4]ₓ +ρ (⊃∘,∘⊂⁻¹) 2 3 4ρ$a ⍝ [2 1 3 4]ₓ ⍝ aplcart/table.tsv:1185 — Membership (∊) on major cells for any rank X←[1 2◇3 4◇1 2] @@ -3136,10 +3136,10 @@ $t $t $f $f $t Js←4 ◇ ≢∘∪ι↣∨ Js ⍝ 3ₓ ⍝ aplcart/table.tsv:1202 — Sort each row in ascending order -Y←[3 1 2◇2 3 1] ◇ ⊂∘⍋↣⌷⍤1 Y ⍝ [1 2 3◇1 2 3] +Y←[3 1 2◇2 3 1] ◇ ⊂∘⍋↣⌷¹ Y ⍝ [1 2 3◇1 2 3] ⍝ aplcart/table.tsv:1203 — Sort major cells ascending -Y←[3 1 2◇2 3 1] ◇ ⊂∘⍋↣⌷⍤¯1 Y ⍝ [1 2 3◇1 2 3] +Y←[3 1 2◇2 3 1] ◇ ⊂∘⍋↣⌷⁻¹ Y ⍝ [1 2 3◇1 2 3] ⍝ aplcart/table.tsv:1204 — Choosing grading direction (¯1,0,1) dynamically during execution Is←¯1 @@ -3147,7 +3147,7 @@ Y←3 1 3 2 Is ⍋×↢⍋↢⍋ Y ⍝ [2 0 3 1]ₓ ⍝ aplcart/table.tsv:1205 — Sort major cells descending -Y←[3 1 2◇2 3 1] ◇ ⊂∘⍒↣⌷⍤¯1 Y ⍝ [3 2 1◇3 2 1] +Y←[3 1 2◇2 3 1] ◇ ⊂∘⍒↣⌷⁻¹ Y ⍝ [3 2 1◇3 2 1] ⍝ aplcart/table.tsv:1206 — Mask to get subvectors with indices Iv as indicated by Bv Iv←1 3 @@ -3182,7 +3182,7 @@ Xs ,↢⌽↢⍉⍣4 Ym ⍝ aplcart/table.tsv:1213 — Index of first consecutive occurrence of major cells of X in Y X←[3 4◇5 6] Y←[1 2◇3 4◇5 6◇7 8] -X ↑⍤¯1∘⍷ι1ₓ⍨ Y ⍝ 1ₓ +X ↑⁻¹∘⍷ι1ₓ⍨ Y ⍝ 1ₓ ⍝ aplcart/table.tsv:1214 — Conway's Game of Life: next generation given Bv of 140 surviving 3-by-3 subarrays; the Game of Life recipe constructs its table of surviving neighbourhoods states←⊂3 3 ρ¨ ↓(9ρ2)⊤ι512ₓ @@ -3240,7 +3240,7 @@ Ns←0.75 ◇ ,÷∨ ↢1 Ns ⍝ 3 4 D← [" ab"◇" c d"] ◇ ∨\' '↣≠ D ⍝ [$f $f $t $t◇$f $t $t $t] ⍝ aplcart/table.tsv:1234 — Differences of successive elements of N along direction Is -N←[1 3 6◇2 5 9] ◇ -⍨/∘(2↣↕)⍤1 N ⍝ [2 3◇3 4] +N←[1 3 6◇2 5 9] ◇ -⍨/∘(2↣↕)¹ N ⍝ [2 3◇3 4] ⍝ aplcart/table.tsv:1235 — Merge the leading Is axes of Y [a ← 2 3 4ρι24ₓ;ρ a;ρ 1 {,⍠ ια ω} a;ρ 2 {,⍠ ια ω} a;ρ 3 {,⍠ ια ω} a] @@ -3420,11 +3420,11 @@ Iv←1 4 6 Jv←2 3 Iv ↓(1+⊢⊤¯1+⊣) Jv ⍝ [[1 1] [2 1] [2 3]] -⍝ aplcart/table.tsv:1283 — Formatting N with Jv decimals in fields of width Iv; Swap outer arguments so the width/precision specification, not the data matrix, goes through (∊,⍤0/); original recipe errors in Dyalog +⍝ aplcart/table.tsv:1283 — Formatting N with Jv decimals in fields of width Iv; Swap outer arguments so the width/precision specification, not the data matrix, goes through (∊,⁰/); original recipe errors in Dyalog Iv←7 8 Jv←1 2 N←[1.25 2.375◇3.25 4.625] -N⍕⍨↢ ∊,⍤0/ [Iv Jv] +N⍕⍨↢ ∊,⁰/ [Iv Jv] ⍝ => [" 1.3 2.38"◇" 3.3 4.63"] @@ -3551,7 +3551,7 @@ Mv ↑↣≤∧⊢/↣> N ⍝ $f $t $t $f $f ⍝ aplcart/table.tsv:1317 — Widening matrix Ym to be compatible with Xm Xm←2 4ρ0 Ym←2 2ρι4ₓ -Xm↑∘⌽∘ρ↣ ↑⍤1 Ym ⍝ [0 1 0 0◇2 3 0 0]ₓ +Xm↑∘⌽∘ρ↣ ↑¹ Ym ⍝ [0 1 0 0◇2 3 0 0]ₓ ⍝ aplcart/table.tsv:1318 — last index of ((ι): Last indices in X of major cells Y X←1 2 3 2 @@ -3569,7 +3569,7 @@ Js←12 ◇ +/∘∪⊢∨(1↓ι) Js ⍝ 16 ⍝ aplcart/table.tsv:1321 — Sort Y ascending according to column Is Is←1 Y←[10 3◇20 1◇30 2] -Is ⌷⍤1⊂∘⍋↣⌷⊢ Y ⍝ [20 1◇30 2◇10 3] +Is ⌷¹⊂∘⍋↣⌷⊢ Y ⍝ [20 1◇30 2◇10 3] ⍝ aplcart/table.tsv:1322 — More accurately sum a vector of floating point numbers Nv←1 2 3 ◇ +/⍒∘|⊃¨⊂ Nv ⍝ 6 @@ -3577,7 +3577,7 @@ Nv←1 2 3 ◇ +/⍒∘|⊃¨⊂ Nv ⍝ 6 ⍝ aplcart/table.tsv:1323 — Sort Y descending according to column Is Is←1 Y←[10 3◇20 1◇30 2] -Is ⌷⍤1⊂∘⍒↣⌷⊢ Y ⍝ [10 3◇30 2◇20 1] +Is ⌷¹⊂∘⍒↣⌷⊢ Y ⍝ [10 3◇30 2◇20 1] ⍝ aplcart/table.tsv:1324 — Suffixes of a vector Yv←1 2 3 4 ◇ ⌽∘,¨,\∘⌽ Yv ⍝ [[4] [3 4] [2 3 4] [1 2 3 4]] @@ -3699,7 +3699,7 @@ Nv←3 4 5 ◇ ×/⊢÷(+/-2×⊢) Nv ⍝ 1.25 ⍝ aplcart/table.tsv:1361 — Tiling a matrix Ym over a matrix of shape Iv Iv←4 6 Ym←2 3ρι6ₓ -Iv ⊣ρ⊢⌿∘⊣ρ⍤1⊢ Ym +Iv ⊣ρ⊢⌿∘⊣ρ¹⊢ Ym ⍝ => [0 1 2 0 1 2◇3 4 5 3 4 5◇0 1 2 0 1 2◇3 4 5 3 4 5]ₓ @@ -3731,7 +3731,7 @@ N←2 3ρι6ₓ ◇ +/∘,÷1××/∘ρ N ⍝ 2.5 ⍝ aplcart/table.tsv:1367 — Appending X as additional major cell of Y, adjusting dimensions of both as necessary X←1 2 3 4 Y←2 3ρι6ₓ -X ⊃⊂⍤¯1∘⊢,⊂∘⊣ Y +X ⊃⊂⁻¹∘⊢,⊂∘⊣ Y ⍝ => [0 1 2 0◇3 4 5 0◇1 2 3 4] @@ -3820,12 +3820,12 @@ D←"Abc 19 Σς!" ◇ ¯1↣•c↣≠∧1↣•c↣≠ D ⍝ $f $f $f $f $f ⍝ aplcart/table.tsv:1392 — Expansion mask (left argument for ⍀) for fields of length Jv to uniform field of length |Is Is←4 Jv←2 3 1 -Is ,(⊣↑1ρ⍨⊢)⍤0 Jv +Is ,(⊣↑1ρ⍨⊢)⁰ Jv ⍝ => 1 1 0 0 1 1 1 0 1 0 0 0 ⍝ aplcart/table.tsv:1393 — Rightmost neighbouring elements (padding at edge) -Y←2 3ρι6ₓ ◇ 1↓⊢,1↑0↣ρ ⍤1 Y ⍝ [1 2 0◇4 5 0]ₓ +Y←2 3ρι6ₓ ◇ 1↓⊢,1↑0↣ρ ¹ Y ⍝ [1 2 0◇4 5 0]ₓ ⍝ aplcart/table.tsv:1395 — Self-classify: table of unique vs all major cells of Y Y←1 2 1 3 ◇ (∪=⊗⊢)ι⍨ Y ⍝ 3 4ρ[$t $f $t $f $f $t $f $f $f $f $f $t] @@ -3833,52 +3833,52 @@ Y←1 2 1 3 ◇ (∪=⊗⊢)ι⍨ Y ⍝ 3 4ρ[$t $f $t $f $f $t $f $f $f $f $f ⍝ aplcart/table.tsv:1396 — Bit-wise OR for positive integers I←2 3 4 J←4 9 16 -I 2⊥((∨⌿⍤2)2⊥⁻,⍤0) J ⍝ 6 11 20 +I 2⊥((∨⌿²)2⊥⁻,⁰) J ⍝ 6 11 20 ⍝ aplcart/table.tsv:1397 — Bit-wise AND for positive integers I←2 3 4 J←4 9 16 -I 2⊥((∧⌿⍤2)2⊥⁻,⍤0) J ⍝ 0 1 0 +I 2⊥((∧⌿²)2⊥⁻,⁰) J ⍝ 0 1 0 ⍝ aplcart/table.tsv:1398 — Bit-wise converse nonimplication for positive integers I←2 3 4 J←4 9 16 -I 2⊥((<⌿⍤2)2⊥⁻,⍤0) J ⍝ 4 8 16 +I 2⊥((<⌿²)2⊥⁻,⁰) J ⍝ 4 8 16 ⍝ aplcart/table.tsv:1399 — Bit-wise implication for positive integers I←2 3 4 J←4 9 16 -I 2⊥((≤⌿⍤2)2⊥⁻,⍤0) J ⍝ 29 29 27 +I 2⊥((≤⌿²)2⊥⁻,⁰) J ⍝ 29 29 27 ⍝ aplcart/table.tsv:1400 — Bit-wise XNOR for positive integers I←2 3 4 J←4 9 16 -I 2⊥((=⌿⍤2)2⊥⁻,⍤0) J ⍝ 25 21 11 +I 2⊥((=⌿²)2⊥⁻,⁰) J ⍝ 25 21 11 ⍝ aplcart/table.tsv:1401 — Bit-wise converse implication for positive integers I←2 3 4 J←4 9 16 -I 2⊥((≥⌿⍤2)2⊥⁻,⍤0) J ⍝ 27 23 15 +I 2⊥((≥⌿²)2⊥⁻,⁰) J ⍝ 27 23 15 ⍝ aplcart/table.tsv:1402 — Bit-wise nonimplication for positive integers I←2 3 4 J←4 9 16 -I 2⊥((>⌿⍤2)2⊥⁻,⍤0) J ⍝ 2 2 4 +I 2⊥((>⌿²)2⊥⁻,⁰) J ⍝ 2 2 4 ⍝ aplcart/table.tsv:1403 — Bit-wise XOR for positive integers I←2 3 4 J←4 9 16 -I 2⊥((≠⌿⍤2)2⊥⁻,⍤0) J ⍝ 6 10 20 +I 2⊥((≠⌿²)2⊥⁻,⁰) J ⍝ 6 10 20 ⍝ aplcart/table.tsv:1404 — Bit-wise NOR for positive integers I←2 3 4 J←4 9 16 -I 2⊥((⊽⌿⍤2)2⊥⁻,⍤0) J ⍝ 25 20 11 +I 2⊥((⊽⌿²)2⊥⁻,⁰) J ⍝ 25 20 11 ⍝ aplcart/table.tsv:1405 — Bit-wise NAND for positive integers I←2 3 4 J←4 9 16 -I 2⊥((⊼⌿⍤2)2⊥⁻,⍤0) J ⍝ 31 30 31 +I 2⊥((⊼⌿²)2⊥⁻,⁰) J ⍝ 31 30 31 ⍝ aplcart/table.tsv:1406 — Date (⎕TS format) to YYYY-MM-DD Jv←2026 9 18 ◇ ('-'@4 7∘⍕1000⊥3↣↑)Jv ⍝ "2026-09-18" @@ -3941,9 +3941,9 @@ Yv←ι6ₓ Is ⍉⊢ρ⍨≢↣÷⍨,⊣ Yv ⍝ [0 2 4◇1 3 5]ₓ ⍝ aplcart/table.tsv:1424 — Distribute major cells of Y into Is (default Is:≢Y) groups as evenly as possible -UnZip ← |↢(ι≢) ⊂⊢∘⌸ ⊢ +UnZip ← |↢(ι≢) ⊂⊢ ⌸ ⊢ var ← "abcdef" -[1 UnZip var;2 UnZip var;3 UnZip var;4 UnZip var;5 UnZip var;6 UnZip var;7 UnZip var;8 UnZip var;(ι≢ ⊂⊢∘⌸ ⊢) var] +[1 UnZip var;2 UnZip var;3 UnZip var;4 UnZip var;5 UnZip var;6 UnZip var;7 UnZip var;8 UnZip var;(ι≢ ⊂⊢ ⌸ ⊢) var] ⍝ => [["abcdef"] ["ace" "bdf"] ["ad" "be" "cf"] ["ae" "bf" "c" "d"] ["af" "b" "c" "d" "e"] ["a" "b" "c" "d" "e" "f"] ["a" "b" "c" "d" "e" "f"] ["a" "b" "c" "d" "e" "f"] ["a" "b" "c" "d" "e" "f"]] @@ -3978,7 +3978,7 @@ Mv *@0(⊢↢⊛⌹1,↢⍪⊣) Nv "aaa" "bbb" "ccc" "ccc" "ccc" "ddd" "eee" ⍝ aplcart/table.tsv:1434 — Leftmost neighbouring elements (padding at edge) -Y←2 3ρι6ₓ ◇ ¯1↓⊢,⍨(1↑0↣ρ) ⍤1 Y ⍝ [0 0 1◇0 3 4]ₓ +Y←2 3ρι6ₓ ◇ ¯1↓⊢,⍨(1↑0↣ρ) ¹ Y ⍝ [0 0 1◇0 3 4]ₓ ⍝ aplcart/table.tsv:1435 — Choose the number closer to zero (the positive one if tied) Is←¯2 @@ -3986,7 +3986,7 @@ Js←2 Is ⌈(↑>⍥|⌽,)⌊ Js ⍝ 2 ⍝ aplcart/table.tsv:1436 — Indices of last non-blanks in rows -D← ["ab "◇" c "◇"d "] ◇ ↑∘⌽∘⍸⍤1≠↢' ' D ⍝ [1 2 0]ₓ +D← ["ab "◇" c "◇"d "] ◇ ↑∘⌽∘⍸¹≠↢' ' D ⍝ [1 2 0]ₓ ⍝ aplcart/table.tsv:1437 — Juxtapositioning planes of rank 3 array Y Y←2 3 4ρι24ₓ ◇ (×⌿(2 2ρ1,ρ))ρ1 0 2↣⍉ Y @@ -4025,7 +4025,7 @@ M *∘-∘⊣×*÷!∘⊢ N ⍝ aplcart/table.tsv:1450 — Merging Y[1] Y[2] Y[3], … under control of Iv (1:cell from Y[1], 2:cell from Y[2], …) Iv←0 1 0 1 Y←[[10 11 12 13] [20 21 22 23]] -Iv ι∘≢∘⊣⌷⍤0 1⌷⍤0 99 Y ⍝ 10 21 12 23 +Iv ι∘≢∘⊣⌷⁰ ¹⌷⁰ ⁹⁹ Y ⍝ 10 21 12 23 ⍝ aplcart/table.tsv:1451 — Lengths of groups of ones in Bv Bv←$f $t $t $f $t $f $t $t $t $f ◇ [0]~⍨¯1+-/⌽2↕⍸1,(~Bv),1 ⍝ 2 1 3 @@ -4129,13 +4129,13 @@ Yv← 'b' "aa" 'a' "ab" ◇ ⊂⊃¨⍨↢⍒(≢,⊂)¨ Yv ⍝ "ab" "aa" 'b' Jv←2 0 1 ◇ +\∊⍨↢↦+/ 1↣+ Jv ⍝ $f $f $t $t $f $t ⍝ aplcart/table.tsv:1477 — Sort each column in ascending order -Y←2 3 2ρ3 2 1 4 2 1 5 6 4 5 6 4 ◇ ⍉⊂∘⍋↣⌷⍤1∘⍉ ⍤2 Y +Y←2 3 2ρ3 2 1 4 2 1 5 6 4 5 6 4 ◇ ⍉⊂∘⍋↣⌷¹∘⍉ ² Y [[1 1◇2 2◇3 4]◇[4 4◇5 5◇6 6]] ⍝ aplcart/table.tsv:1478 — Kronecker product A ← [1 ¯4 7◇¯2 3 3] B ← [8 ¯9 ¯6 5◇1 ¯3 ¯4 7◇2 8 ¯8 ¯3◇1 2 ¯5 ¯1] -A {,⍤2,⍠ ι2ₓ [0 2 1 3]⍉α×⊗ω} B +A {,²,⍠ ι2ₓ [0 2 1 3]⍉α×⊗ω} B ⍝ => [8 ¯9 ¯6 5 ¯32 36 24 ¯20 56 ¯63 ¯42 35◇1 ¯3 ¯4 7 ¯4 12 16 ¯28 7 ¯21 ¯28 49◇2 8 ¯8 ¯3 ¯8 ¯32 32 12 14 56 ¯56 ¯21◇1 2 ¯5 ¯1 ¯4 ¯8 20 4 7 14 ¯35 ¯7◇¯16 18 12 ¯10 24 ¯27 ¯18 15 24 ¯27 ¯18 15◇¯2 6 8 ¯14 3 ¯9 ¯12 21 3 ¯9 ¯12 21◇¯4 ¯16 16 6 6 24 ¯24 ¯9 6 24 ¯24 ¯9◇¯2 ¯4 10 2 3 6 ¯15 ¯3 3 6 ¯15 ¯3] @@ -4181,7 +4181,7 @@ Is ⊣,⊣-↢(1+ι ∘|××)- Js ⍝ 5 4 3 2 ⍝ aplcart/table.tsv:1488 — Move items X to end of Y X←2 4 Y←1 2 3 4 2 -X ⊂∘⍋∘∊⍨⍥(⊂⍤¯1)⌷⊢ Y ⍝ 1 3 2 4 2 +X ⊂∘⍋∘∊⍨⍥(⊂⁻¹)⌷⊢ Y ⍝ 1 3 2 4 2 ⍝ aplcart/table.tsv:1489 — Expansion vector (left argument for #⁻) to insert Jv[i] elements after i'th element Jv←2 0 1 ◇ ¯1⌽(+\∊⍨↢↦+/) 1↣+ Jv ⍝ $t $f $f $t $t $f @@ -4333,7 +4333,7 @@ Dv← " ab c " ◇ ' '↣ 1↓,#⍨(1(⊢∨⌽)0,≠) Dv ⍝ "ab c" Nv←1 4 ◇ ↑((+⌿÷≢),≢÷1⊥÷)⍣≡ Nv ⍝ 2 ⍝ aplcart/table.tsv:1530 — Add line numbers to table Xm; Format exact counts as ordinary numbers -Ym←2 3ρι6ₓ ◇ 3⌽"] [",0↣⍕ ⍤0∘ι∘≢,0↣⍕ Ym +Ym←2 3ρι6ₓ ◇ 3⌽"] [",0↣⍕ ⁰∘ι∘≢,0↣⍕ Ym ["[0] 0 1 2"◇"[1] 3 4 5"] ⍝ aplcart/table.tsv:1531 — Syllabisation of a Finnish word Dv @@ -4397,7 +4397,7 @@ Nv←1 2 4 ◇ (2*↢÷⍨(+⌿÷≢))(2*⍨(⊢-+⌿÷≢)) Nv ⍝ 1.24721912 Bv←$f $t $t $f $t $t $t $f ◇ 0{ω×1+α}\Bv ⍝ 0 1 2 0 1 2 3 0 ⍝ aplcart/table.tsv:1548 — Shortest path length matrix from weighted adjacency matrix n2, using Floyd-Warshall -Nm←[0 2 9◇2 0 3◇9 3 0] ◇ ι∘≢(⊢⌊⌷⍤1+⊗⌷)/∘,⊂ Nm +Nm←[0 2 9◇2 0 3◇9 3 0] ◇ ι∘≢(⊢⌊⌷¹+⊗⌷)/∘,⊂ Nm [0 2 5◇2 0 3◇5 3 0] ⍝ aplcart/table.tsv:1549 — Component of Mv in direction of Nv @@ -4961,7 +4961,7 @@ B←0 1 1 0 [B]⌷Xv ⍝ "no" "yes" "yes" "no" ⍝ aplcart/table.tsv:1807 — Integer quotient and remainder (new leading length-2 axis) of all combinations of an element from N divided by an element from M -2 3 4 5 6 {⍉(0,⍤0α)⊤ω} 10 ⍝ [5 3 2 2 1◇0 1 2 0 4] +2 3 4 5 6 {⍉(0,⁰α)⊤ω} 10 ⍝ [5 3 2 2 1◇0 1 2 0 4] ⍝ aplcart/table.tsv:1812 — Replacing major cells of Y not satisfying Bv with prototypical cells [1 1 0 1 1 1 0 1 {α#⁻α#ω} "Amazing!";1 1 0 {α#⁻α#ω} [3 1 4;2 7 18;1 6 18]] @@ -5095,12 +5095,12 @@ Nv←4 5 ⍝ aplcart/table.tsv:1860 — Count number of leading major cells that match between two arrays of equal length X←[1 2◇3 4◇5 6] Y←[1 2◇3 4◇7 8] -X +/(∧\≡⍤¯1) Y ⍝ 2ₓ +X +/(∧\≡⁻¹) Y ⍝ 2ₓ ⍝ aplcart/table.tsv:1861 — Count number of leading major cells that differ between two arrays of equal length X←[1 2◇3 4◇5 6] Y←[9 2◇3 4◇5 6] -X +/(∧\≢⍤¯1) Y ⍝ 1ₓ +X +/(∧\≢⁻¹) Y ⍝ 1ₓ ⍝ aplcart/table.tsv:1862 — Reverse order of partitions in Y as indicated by Av (Fast ∊⌽Av⊂Yv) 1 0 0 0 1 1 0 0 {ω⌷⍨⊂⍒+\α} "abcd-XYZ" ⍝ "XYZ-abcd" @@ -5113,7 +5113,7 @@ N←[1 2◇3 4◇5 6] ⍝ aplcart/table.tsv:1864 — Is N Non-decreasing along axis Is? Is←2 N←[1 1 2◇3 4 4] -~0∊, ≤/∘(2↣↕)⍤1 N ⍝ $t +~0∊, ≤/∘(2↣↕)¹ N ⍝ $t ⍝ aplcart/table.tsv:1865 — Is N Non-increasing along axis Is? Is←1 @@ -5212,12 +5212,12 @@ Y←1 2 3 4 5 6 ◇ Y⌷⍨⊂⍋⍒1 0ρ⍨≢Y ⍝ 1 4 2 5 3 6 ⍝ aplcart/table.tsv:1897 — Count number of trailing major cells that match between two arrays of equal length X←[1 2◇3 4◇5 6] Y←[9 2◇3 4◇5 6] -X +/(∧\∘⌽≡⍤¯1) Y ⍝ 2ₓ +X +/(∧\∘⌽≡⁻¹) Y ⍝ 2ₓ ⍝ aplcart/table.tsv:1898 — Count number of trailing major cells that differ between two arrays of equal length X←[1 2◇3 4◇5 6] Y←[1 2◇3 4◇7 8] -X +/(∧\∘⌽≢⍤¯1) Y ⍝ 1ₓ +X +/(∧\∘⌽≢⁻¹) Y ⍝ 1ₓ ⍝ aplcart/table.tsv:1899 — FIFO stock Nv decremented by Ms Ms←5 @@ -5552,7 +5552,7 @@ Jv←2 3 1 ◇ {ω≢∪ω?0;¯1*1⊥∊ω<,\ω}Jv ⍝ 1 ⍝ aplcart/table.tsv:1993 — Convolution Mv←1 2 3 Nv←4 5 6 -Nv+.×⍨(↦≢Mv)⌽⍤0 1⌽Mv ⍝ 31 31 28 +Nv+.×⍨(↦≢Mv)⌽⁰ ¹⌽Mv ⍝ 31 31 28 ⍝ aplcart/table.tsv:1994 — Matrix power: Mm raised to the power Js (even for negative Js) Mm←[1 1◇0 1] @@ -5622,10 +5622,10 @@ Nv+.×(Mv↣*÷!)ι≢Nv ⍝ 6.333333333333333 ⍝ aplcart/table.tsv:2013 — Cross-correlation Mv←1 2 3 Nv←4 5 6 -Nv+.×⍨(↦≢Mv)⌽⍤0 1+⌽Mv ⍝ 31 31 28 +Nv+.×⍨(↦≢Mv)⌽⁰ ¹+⌽Mv ⍝ 31 31 28 ⍝ aplcart/table.tsv:2014 — Auto-correlation; Use ω for the length in this monadic autocorrelation; upstream α gives VALUE ERROR. Concrete vector independently checked in Dyalog -Nv←1 2 3 ◇ {ω+.×⍨(↦≢ω)⌽⍤0 1+⌽ω}Nv ⍝ 13 13 10 +Nv←1 2 3 ◇ {ω+.×⍨(↦≢ω)⌽⁰ ¹+⌽ω}Nv ⍝ 13 13 10 ⍝ aplcart/table.tsv:2016 — Surround any-rank array Y with scalar Xs Xs←9ₓ @@ -5775,7 +5775,7 @@ N←1 1.2 1.23 1.234 ⍝ aplcart/table.tsv:2046 — Conversion of characters to hexadecimal byte representation Dv←"Hello, world! 123" -,(3↑⍤1)[(16 16⊤¯1+"UTF-8"•ucs Dv)]⌷$d,$a +,(3↑¹)[(16 16⊤¯1+"UTF-8"•ucs Dv)]⌷$d,$a ⍝ => "47 64 6B 6B 6E 2B 1F 76 6E 71 6B 63 20 1F 30 31 32 " @@ -5868,70 +5868,70 @@ Is{α>ω?0;↑⌽1(+\×)⍣(ω-α)⍨↦α}Js ⍝ 7 ⍝ — 2's-complement bit-wise OR; positive operands (aplcart/table.tsv:2070) I←3 2 1 J←2 5 2 -I{2⊥(-∨/0>b),∨⌿⍤2(2⊥⁻b←[α◇ω]ᵀ)}J +I{2⊥(-∨/0>b),∨⌿²(2⊥⁻b←[α◇ω]ᵀ)}J ⍝ => 3 7 3 ⍝ — 2's-complement bit-wise AND; positive operands (aplcart/table.tsv:2071) I←3 2 1 J←2 5 2 -I{2⊥(-∧/0>b),∧⌿⍤2(2⊥⁻b←[α◇ω]ᵀ)}J +I{2⊥(-∧/0>b),∧⌿²(2⊥⁻b←[α◇ω]ᵀ)}J ⍝ => 2 0 0 ⍝ — 2's-complement bit-wise converse nonimplication; positive operands (aplcart/table.tsv:2072) I←3 2 1 J←2 5 2 -I{2⊥(-b),<⌿⍤2(2⊥⁻b←[α◇ω]ᵀ)}J +I{2⊥(-b),<⌿²(2⊥⁻b←[α◇ω]ᵀ)}J ⍝ => 0 5 2 ⍝ — 2's-complement bit-wise implication; positive operands (aplcart/table.tsv:2073) I←3 2 1 J←2 5 2 -I{2⊥(-≤/0>b),≤⌿⍤2(2⊥⁻b←[α◇ω]ᵀ)}J +I{2⊥(-≤/0>b),≤⌿²(2⊥⁻b←[α◇ω]ᵀ)}J ⍝ => ¯2 ¯3 ¯2 ⍝ — 2's-complement bit-wise XNOR; positive operands (aplcart/table.tsv:2074) I←3 2 1 J←2 5 2 -I{2⊥(-=/0>b),=⌿⍤2(2⊥⁻b←[α◇ω]ᵀ)}J +I{2⊥(-=/0>b),=⌿²(2⊥⁻b←[α◇ω]ᵀ)}J ⍝ => ¯2 ¯8 ¯4 ⍝ — 2's-complement bit-wise converse implication; positive operands (aplcart/table.tsv:2075) I←3 2 1 J←2 5 2 -I{2⊥(-≥/0>b),≥⌿⍤2(2⊥⁻b←[α◇ω]ᵀ)}J +I{2⊥(-≥/0>b),≥⌿²(2⊥⁻b←[α◇ω]ᵀ)}J ⍝ => ¯1 ¯6 ¯3 ⍝ — 2's-complement bit-wise nonimplication; positive operands (aplcart/table.tsv:2076) I←3 2 1 J←2 5 2 -I{2⊥(->/0>b),>⌿⍤2(2⊥⁻b←[α◇ω]ᵀ)}J +I{2⊥(->/0>b),>⌿²(2⊥⁻b←[α◇ω]ᵀ)}J ⍝ => 1 2 1 ⍝ — 2's-complement bit-wise XOR; positive operands (aplcart/table.tsv:2077) I←3 2 1 J←2 5 2 -I{2⊥(-≠/0>b),≠⌿⍤2(2⊥⁻b←[α◇ω]ᵀ)}J +I{2⊥(-≠/0>b),≠⌿²(2⊥⁻b←[α◇ω]ᵀ)}J ⍝ => 1 7 3 ⍝ — 2's-complement bit-wise NOR; positive operands (aplcart/table.tsv:2078) I←3 2 1 J←2 5 2 -I{2⊥(-⊽/0>b),⊽⌿⍤2(2⊥⁻b←[α◇ω]ᵀ)}J +I{2⊥(-⊽/0>b),⊽⌿²(2⊥⁻b←[α◇ω]ᵀ)}J ⍝ => ¯4 ¯8 ¯4 ⍝ — 2's-complement bit-wise NAND; positive operands (aplcart/table.tsv:2079) I←3 2 1 J←2 5 2 -I{2⊥(-⊼/0>b),⊼⌿⍤2(2⊥⁻b←[α◇ω]ᵀ)}J +I{2⊥(-⊼/0>b),⊼⌿²(2⊥⁻b←[α◇ω]ᵀ)}J ⍝ => ¯3 ¯1 ¯1 @@ -6082,7 +6082,7 @@ Is{r←+\ω=d←↑ω ◇ 0<α?ω#⍨r>α;ω#⍨r≤α+⊃⌽r}Dv "/cd/ef" ⍝ aplcart/table.tsv:2119 — Numeric matrix of all permutations of length Js in lexicographical order -{0=ω?1 0ρ0;,₀ ₁[:;0,1+∇ ω-1]⌷⍒⍤1=⊗⍨ιω} 3 +{0=ω?1 0ρ0;,₀ ₁[:;0,1+∇ ω-1]⌷⍒¹=⊗⍨ιω} 3 6 3ρ[0 1 2 0 2 1 1 0 2 1 2 0 2 0 1 2 1 0]ₓ ⍝ aplcart/table.tsv:2120 — Sorting rows of matrix Y into ascending order (Fast (⊂∘⍋⌷⊢)⍤1) @@ -6596,7 +6596,7 @@ X Y{α =⊗ ⍶+.×ω} N ⍝ $f $f $f Is←6 Iv←1 2 Nm←[1.25 2.375◇3.25 4.625] -(Is{ω⍕⍤1⍨⍶,⍪⍹}Iv)Nm +(Is{ω⍕¹⍨⍶,⍪⍹}Iv)Nm ⍝ => [" 1.3 2.4"◇" 3.25 4.63"] @@ -6629,7 +6629,7 @@ Mv Is{⌽ω⌹α*⊗ι1ₓ+⍶} Nv ⍝ 1 1 1 I←3 5 f←≠ J←6 2 -I f{2⊥⍶⌿⍤2(2⊥⁻⍉[α◇ω])} J ⍝ 5 7 +I f{2⊥⍶⌿²(2⊥⁻⍉[α◇ω])} J ⍝ 5 7 ⍝ aplcart/table.tsv:2274 — Justifying left fields of Yv (lengths Iv) to length Is Iv←2 1 @@ -6697,7 +6697,7 @@ f{⍶⍨⁻ω⍉⍨rρι2ₓ÷⍨r←ρρω}Y ⍝ 1 2 3 Mv←1 2 3 f←+ Nv←4 5 6 -Mv f{ω+.×⍨(↦≢α)⌽⍤0 1⍶⌽α} Nv ⍝ 31 31 28 +Mv f{ω+.×⍨(↦≢α)⌽⁰ ¹⍶⌽α} Nv ⍝ 31 31 28 ⍝ aplcart/table.tsv:2287 — Interpolated value of series Mv=f(Nv) at Ms Mv←1 3 7 @@ -6746,7 +6746,7 @@ X f{α(⍶⊣⊢)⍣⍹ ω}Bs Y ⍝ 3 4 5 f←1+ J←0 1 3 Y←10 -(f{⍶{⍶⍣ω ⍹}ω⍤0 ⍹}J)Y ⍝ 10 11 13 +(f{⍶{⍶⍣ω ⍹}ω ⁰ ⍹}J)Y ⍝ 10 11 13 ⍝ aplcart/table.tsv:2296 — Reduction (/) with f in dimension Is (default: last), rank unchanged Is←0 @@ -6790,7 +6790,7 @@ X←2 f←+ J←0 1 3 Y←10 -X(f{α ⍶{α ⍶⍣ω ⍹}ω⍤0 ⍹}J)Y ⍝ 10 12 16 +X(f{α ⍶{α ⍶⍣ω ⍹}ω ⁰ ⍹}J)Y ⍝ 10 12 16 ⍝ aplcart/table.tsv:2302 — Power: Iterating f on Y while condition g Y is true but at most I times [2 ,↢0 {⍶{⍶⍣(⍹ ω) ω}⍹⍣α ω} (7ₓ>≢) 1 2 3;9 ,↢0 {⍶{⍶⍣(⍹ ω) ω}⍹⍣α ω} (7ₓ>≢) 1 2 3] @@ -6832,7 +6832,7 @@ Is f{a+.×⍶ω↑↣-(a←-/ω÷-α)ׯ0.5-ια} Nv I←3 5 f←≠ J←6 2 -I f{2⊥(-⍶/0>b),⍶⌿⍤2(2⊥⁻b←[α◇ω]ᵀ)} J +I f{2⊥(-⍶/0>b),⍶⌿²(2⊥⁻b←[α◇ω]ᵀ)} J ⍝ => 5 7 @@ -6861,13 +6861,13 @@ f{⍶{ω,⍨⊂α⍶↑ω}/1↓⍬(⊢,↢⊂ρ)¯1⌽ω}Y ⍝ 2 ¯1 3 Mv←2 3 Ns←7 Jv←5 4 -Mv Ns{⍶{⍶|α×⍶|×⍨ω}⌿α*⍤1⊖0⍪⍉2⊥⁻ω} Jv ⍝ 4 4 +Mv Ns{⍶{⍶|α×⍶|×⍨ω}⌿α*¹⊖0⍪⍉2⊥⁻ω} Jv ⍝ 4 4 ⍝ aplcart/table.tsv:2314 — Mesh matrices Xm and Ym along rows under control of Av (0:cell from Xm, 1:cell from Ym, …) Xm←[10 20◇30 40] Av←0 1 0 1 1 Ym←[1 2 3◇4 5 6] -Xm Av{⍶⊃¨⍤1 (⍶~↣(#⁻₋₁)α),¨(⍶#⁻₋₁ω)} Ym +Xm Av{⍶⊃¨¹ (⍶~↣(#⁻₋₁)α),¨(⍶#⁻₋₁ω)} Ym ⍝ => [10 1 20 2 3◇30 4 40 5 6] @@ -6875,7 +6875,7 @@ Xm Av{⍶⊃¨⍤1 (⍶~↣(#⁻₋₁)α),¨(⍶#⁻₋₁ω)} Ym Xm←[10 20◇30 40] Av←0 1 0 1 1 Ym←[1 2◇3 4◇5 6] -Xm Av{⍶⊃¨⍤0 1 (⍶~↣(#⁻)α),¨(⍶#⁻ω)} Ym +Xm Av{⍶⊃¨⁰ ¹ (⍶~↣(#⁻)α),¨(⍶#⁻ω)} Ym ⍝ => [10 20◇1 2◇30 40◇3 4◇5 6] @@ -6883,7 +6883,7 @@ Xm Av{⍶⊃¨⍤0 1 (⍶~↣(#⁻)α),¨(⍶#⁻ω)} Ym M←0.25 I←1 6 7 N←0.5 -M I{+/(⍶⊤⍨4ρ2)×⍤1⊃,[1-α α]×⊗[1-ω ω]} N +M I{+/(⍶⊤⍨4ρ2)×¹⊃,[1-α α]×⊗[1-ω ω]} N ⍝ => 0.125 0.5 0.625 @@ -6985,7 +6985,7 @@ Iv{ω#⁻⍨(↦ω≢↣++/⍶)∊+\1+¯1↓0,⍶#⁻⍨⍹∊⍨ι≢ω}Jv Y ⍝ aplcart/table.tsv:2330 — Stable quicksort using custom comparison function f (negative:left precedes right, zero:keep ordering, positive:right precedes left); Reviewed deterministic random-operation invariant; independently checked in Dyalog and through the Rust reference worker; Assert shape, range, uniqueness, permutation preservation, rounding bounds or deterministic sorting; no sampled values or seed are compared f←{(↑α)-↑ω} Y←[2 30◇1 90◇2 10◇1 70◇2 20] -r←f{1ₓ≥≢ω?ω;c←ω (⍶-⍶⍨)⍤¯1 99 ¿∘≢↣⌷ω ◇ (∇ω#⍨0>c)⍪(ω#⍨0=c)⍪∇ω#⍨0c)⍪(ω#⍨0=c)⍪∇ω#⍨0 [1 2 3 0◇4 5 6 0◇1 2 3 4] @@ -7790,10 +7790,10 @@ Yv←[1 2 3;["ab"◇" c"◇"de"]] Yv←[1 2 3;'a' "bc" 'd'] ◇ ⍉⊃ Yv ⍝ [1 'a'◇2 "bc"◇3 'd'] ⍝ aplcart/tt.tsv:344 — Convert permutation matrices in B to permutation vectors -B←[0 1 0◇0 0 1◇1 0 0] ◇ ι↢1⍤1 B ⍝ [1 2 0]ₓ +B←[0 1 0◇0 0 1◇1 0 0] ◇ ι↢1 ¹ B ⍝ [1 2 0]ₓ ⍝ aplcart/tt.tsv:346 — Convert permutation vectors in I to permutation matrices -I←2 3 1 ◇ 1↑⍨⍤0- I ⍝ [0 1 0◇0 0 1◇1 0 0] +I←2 3 1 ◇ 1↑⍨⁰- I ⍝ [0 1 0◇0 0 1◇1 0 0] ⍝ aplcart/tt.tsv:352 — Convert table to inverted table (character data as matrices) Ym←[1 "ab"◇2 "cd"◇3 "ef"] ◇ ⊃¨⊂₀Ym ⍝ [1 2 3;["ab"◇"cd"◇"ef"]] @@ -8038,16 +8038,16 @@ Y←[1 2◇1 2◇3 4◇3 4◇1 2] ◇ +⍀1⍪(≢/₁∘(2↣↕)) Y [1 1◇1 1◇2 2◇2 2◇3 3] ⍝ aplcart/tt.tsv:764 — Increment rank by inserting a new dimension after the leading one -Y←1+2 3ρι6ₓ ◇ ⊃∘,∘⊂⍤¯1 Y ⍝ 2 1 3ρ1 2 3 4 5 6 +Y←1+2 3ρι6ₓ ◇ ⊃∘,∘⊂⁻¹ Y ⍝ 2 1 3ρ1 2 3 4 5 6 ⍝ aplcart/tt.tsv:766 — Increment rank by inserting a new dimension after the trailing one -Y←1+2 3ρι6ₓ ◇ ,⍤0 Y ⍝ 2 3 1ρ1 2 3 4 5 6 +Y←1+2 3ρι6ₓ ◇ ,⁰ Y ⍝ 2 3 1ρ1 2 3 4 5 6 ⍝ aplcart/tt.tsv:768 — Increment rank by inserting a new dimension before the leading one Y←1+2 3ρι6ₓ ◇ ⊃,∘⊂ Y ⍝ 1 2 3ρ1 2 3 4 5 6 ⍝ aplcart/tt.tsv:770 — Increment rank by inserting a new dimension before the trailing one -Y←1+2 3ρι6ₓ ◇ ⊃,∘⊂⍤1 Y ⍝ 2 1 3ρ1 2 3 4 5 6 +Y←1+2 3ρι6ₓ ◇ ⊃,∘⊂¹ Y ⍝ 2 1 3ρ1 2 3 4 5 6 ⍝ aplcart/tt.tsv:772 — Increment: N+1 N←4 9 16 ◇ 1↣+N ⍝ 5 10 17 @@ -8055,7 +8055,7 @@ N←4 9 16 ◇ 1↣+N ⍝ 5 10 17 ⍝ aplcart/tt.tsv:783 — Index of first consecutive occurrence of major cells of X in Y; Reuse concrete inputs from aplcart/table.tsv:1213; execute this alternate recipe independently X←[3 4◇5 6] Y←[1 2◇3 4◇5 6◇7 8] -X ι↢1∘ ↑⍤¯1∘⍷ Y ⍝ 1ₓ +X ι↢1∘ ↑⁻¹∘⍷ Y ⍝ 1ₓ ⍝ aplcart/tt.tsv:787 — Index of first instance of each major cell; Reuse concrete inputs from aplcart/table.tsv:1136; execute this alternate recipe independently Y←3 1 3 2 ◇ ι⍨∪ι⊢ Y ⍝ [0 1 0 3]ₓ @@ -8288,7 +8288,7 @@ Jv←2026 9 18 ◇ 100↣⊥Jv ⍝ 20260918 ⍝ aplcart/tt.tsv:1066 — Kronecker product Mm←[1 2◇3 4] Nm←1+2 3ρι6ₓ -,⍤2,⍠ ι2ₓ [0 2 1 3]⍉Mm×⊗Nm +,²,⍠ ι2ₓ [0 2 1 3]⍉Mm×⊗Nm ⍝ => [1 2 3 2 4 6◇4 5 6 8 10 12◇3 6 9 4 8 12◇12 15 18 16 20 24] @@ -8641,7 +8641,7 @@ Dv←",ab,c,,def" ◇ ¯1+-/⌽2↕⍸(Dv=↑Dv),1 ⍝ 2 1 0 3 ⍝ aplcart/tt.tsv:1649 — Select: each element of Iv selects a cell from Y; Reuse concrete inputs from aplcart/table.tsv:1046; execute this alternate recipe independently Iv←[0 1;1 2] Y←2 3ρι6ₓ -Iv ⌷⍨↢⊃⍨⍤0 99 Y ⍝ [1 5]ₓ +Iv ⌷⍨↢⊃⍨⁰ ⁹⁹ Y ⍝ [1 5]ₓ ⍝ aplcart/tt.tsv:1658 — Separating packed YYYYMMDD date integer date Js←20260918 ◇ 0 100 100↣⊤Js ⍝ 2026 9 18 @@ -8663,25 +8663,25 @@ Y←3 1 3 2 ◇ ⊂∘⍒⌷⊢ Y ⍝ 3 3 2 1 ⍝ aplcart/tt.tsv:1705 — Sort Y ascending according to column Is; Reuse concrete inputs from aplcart/table.tsv:1321; execute this alternate recipe independently Is←1 Y←[10 3◇20 1◇30 2] -Is ⊢⌷⍨↢⊂↢⍋⌷⍤1 Y ⍝ [20 1◇30 2◇10 3] +Is ⊢⌷⍨↢⊂↢⍋⌷¹ Y ⍝ [20 1◇30 2◇10 3] ⍝ aplcart/tt.tsv:1707 — Sort Y descending according to column Is; Reuse concrete inputs from aplcart/table.tsv:1323; execute this alternate recipe independently Is←1 Y←[10 3◇20 1◇30 2] -Is ⊢⌷⍨↢⊂↢⍒⌷⍤1 Y ⍝ [10 3◇30 2◇20 1] +Is ⊢⌷⍨↢⊂↢⍒⌷¹ Y ⍝ [10 3◇30 2◇20 1] ⍝ aplcart/tt.tsv:1709 — Sort each column in ascending order; Reuse concrete inputs from aplcart/table.tsv:1477; execute this alternate recipe independently -Y←2 3 2ρ3 2 1 4 2 1 5 6 4 5 6 4 ◇ {⍉(⊂∘⍋⌷⊢)⍤1⍉ω}⍤2 Y +Y←2 3 2ρ3 2 1 4 2 1 5 6 4 5 6 4 ◇ {⍉(⊂∘⍋⌷⊢)¹⍉ω}² Y 2 3 2ρ1 1 2 2 3 4 4 4 5 5 6 6 ⍝ aplcart/tt.tsv:1711 — Sort each row in ascending order; Reuse concrete inputs from aplcart/table.tsv:1202; execute this alternate recipe independently -Y←[3 1 2◇2 3 1] ◇ ⊂∘⍋⌷⊢ ⍤1 Y ⍝ [1 2 3◇1 2 3] +Y←[3 1 2◇2 3 1] ◇ ⊂∘⍋⌷⊢ ¹ Y ⍝ [1 2 3◇1 2 3] ⍝ aplcart/tt.tsv:1713 — Sort major cells ascending; Reuse concrete inputs from aplcart/table.tsv:1203; execute this alternate recipe independently -Y←[3 1 2◇2 3 1] ◇ ⊂∘⍋⌷⊢ ⍤¯1 Y ⍝ [1 2 3◇1 2 3] +Y←[3 1 2◇2 3 1] ◇ ⊂∘⍋⌷⊢ ⁻¹ Y ⍝ [1 2 3◇1 2 3] ⍝ aplcart/tt.tsv:1715 — Sort major cells descending; Reuse concrete inputs from aplcart/table.tsv:1205; execute this alternate recipe independently -Y←[3 1 2◇2 3 1] ◇ ⊂∘⍒⌷⊢ ⍤¯1 Y ⍝ [3 2 1◇3 2 1] +Y←[3 1 2◇2 3 1] ◇ ⊂∘⍒⌷⊢ ⁻¹ Y ⍝ [3 2 1◇3 2 1] ⍝ aplcart/tt.tsv:1717 — Sorted frequency table; Reuse concrete inputs from aplcart/table.tsv:1510; execute this alternate recipe independently Y←1 2 1 3 1 2 ◇ {ω⌷⍨⊂⍒⊢/ω}{α,≢ω}⌸ Y ⍝ [1 3◇2 2◇3 1] @@ -8812,7 +8812,7 @@ Nv←1 2 3 ◇ ×/Nv ⍝ 6 ⍝ aplcart/tt.tsv:1931 — Widening matrix Ym to be compatible with Xm; Reuse concrete inputs from aplcart/table.tsv:1317; execute this alternate recipe independently Xm←2 4ρ0 Ym←2 2ρι4ₓ -Xm↑⍤1⍨↢↑↢⌽↢ρ⍨Ym ⍝ [0 1 0 0◇2 3 0 0]ₓ +Xm↑¹⍨↢↑↢⌽↢ρ⍨Ym ⍝ [0 1 0 0◇2 3 0 0]ₓ ⍝ aplcart/tt.tsv:1940 — Zero array of shape, size, and structure of N N←[1 2;3 4 5] ◇ 0↣×N ⍝ [0 0;0 0 0] @@ -9471,70 +9471,70 @@ f←{2⊃date¯1+days(1+0 12⊤12⊥(α-1),ω),1} I←¯3 2 ¯1 0 J←2 ¯5 ¯2 ¯1 w←1+⌈2⊛1+⌈/|I,J -w int 2⊥ ∨⌿⍤2 (wρ2)⊤[I◇J]ᵀ ⍝ ¯1 ¯5 ¯1 ¯1 +w int 2⊥ ∨⌿² (wρ2)⊤[I◇J]ᵀ ⍝ ¯1 ¯5 ¯1 ¯1 ⍝ aplcart/table.tsv:2071 — 2's-complement bit-wise AND; Prepared signed-bitwise algorithm using ordinary fixed-width encoding; Python integer truth-table expectations retained; Use an explicit sufficient two’s-complement width, ordinary Encode, and the existing int signed-decoding helper; This avoids undefined inverse Decode on negatives without changing language semantics or reducing the original mixed-sign inputs [int:]←•load "lib/numeric.bpl" I←¯3 2 ¯1 0 J←2 ¯5 ¯2 ¯1 w←1+⌈2⊛1+⌈/|I,J -w int 2⊥ ∧⌿⍤2 (wρ2)⊤[I◇J]ᵀ ⍝ 0 2 ¯2 0 +w int 2⊥ ∧⌿² (wρ2)⊤[I◇J]ᵀ ⍝ 0 2 ¯2 0 ⍝ aplcart/table.tsv:2072 — 2's-complement bit-wise converse nonimplication; Prepared signed-bitwise algorithm using ordinary fixed-width encoding; Python integer truth-table expectations retained; Use an explicit sufficient two’s-complement width, ordinary Encode, and the existing int signed-decoding helper; This avoids undefined inverse Decode on negatives without changing language semantics or reducing the original mixed-sign inputs [int:]←•load "lib/numeric.bpl" I←¯3 2 ¯1 0 J←2 ¯5 ¯2 ¯1 w←1+⌈2⊛1+⌈/|I,J -w int 2⊥ <⌿⍤2 (wρ2)⊤[I◇J]ᵀ ⍝ 2 ¯7 0 ¯1 +w int 2⊥ <⌿² (wρ2)⊤[I◇J]ᵀ ⍝ 2 ¯7 0 ¯1 ⍝ aplcart/table.tsv:2073 — 2's-complement bit-wise implication; Prepared signed-bitwise algorithm using ordinary fixed-width encoding; Python integer truth-table expectations retained; Use an explicit sufficient two’s-complement width, ordinary Encode, and the existing int signed-decoding helper; This avoids undefined inverse Decode on negatives without changing language semantics or reducing the original mixed-sign inputs [int:]←•load "lib/numeric.bpl" I←¯3 2 ¯1 0 J←2 ¯5 ¯2 ¯1 w←1+⌈2⊛1+⌈/|I,J -w int 2⊥ ≤⌿⍤2 (wρ2)⊤[I◇J]ᵀ ⍝ 2 ¯1 ¯2 ¯1 +w int 2⊥ ≤⌿² (wρ2)⊤[I◇J]ᵀ ⍝ 2 ¯1 ¯2 ¯1 ⍝ aplcart/table.tsv:2074 — 2's-complement bit-wise XNOR; Prepared signed-bitwise algorithm using ordinary fixed-width encoding; Python integer truth-table expectations retained; Use an explicit sufficient two’s-complement width, ordinary Encode, and the existing int signed-decoding helper; This avoids undefined inverse Decode on negatives without changing language semantics or reducing the original mixed-sign inputs [int:]←•load "lib/numeric.bpl" I←¯3 2 ¯1 0 J←2 ¯5 ¯2 ¯1 w←1+⌈2⊛1+⌈/|I,J -w int 2⊥ =⌿⍤2 (wρ2)⊤[I◇J]ᵀ ⍝ 0 6 ¯2 0 +w int 2⊥ =⌿² (wρ2)⊤[I◇J]ᵀ ⍝ 0 6 ¯2 0 ⍝ aplcart/table.tsv:2075 — 2's-complement bit-wise converse implication; Prepared signed-bitwise algorithm using ordinary fixed-width encoding; Python integer truth-table expectations retained; Use an explicit sufficient two’s-complement width, ordinary Encode, and the existing int signed-decoding helper; This avoids undefined inverse Decode on negatives without changing language semantics or reducing the original mixed-sign inputs [int:]←•load "lib/numeric.bpl" I←¯3 2 ¯1 0 J←2 ¯5 ¯2 ¯1 w←1+⌈2⊛1+⌈/|I,J -w int 2⊥ ≥⌿⍤2 (wρ2)⊤[I◇J]ᵀ ⍝ ¯3 6 ¯1 0 +w int 2⊥ ≥⌿² (wρ2)⊤[I◇J]ᵀ ⍝ ¯3 6 ¯1 0 ⍝ aplcart/table.tsv:2076 — 2's-complement bit-wise nonimplication; Prepared signed-bitwise algorithm using ordinary fixed-width encoding; Python integer truth-table expectations retained; Use an explicit sufficient two’s-complement width, ordinary Encode, and the existing int signed-decoding helper; This avoids undefined inverse Decode on negatives without changing language semantics or reducing the original mixed-sign inputs [int:]←•load "lib/numeric.bpl" I←¯3 2 ¯1 0 J←2 ¯5 ¯2 ¯1 w←1+⌈2⊛1+⌈/|I,J -w int 2⊥ >⌿⍤2 (wρ2)⊤[I◇J]ᵀ ⍝ ¯3 0 1 0 +w int 2⊥ >⌿² (wρ2)⊤[I◇J]ᵀ ⍝ ¯3 0 1 0 ⍝ aplcart/table.tsv:2077 — 2's-complement bit-wise XOR; Prepared signed-bitwise algorithm using ordinary fixed-width encoding; Python integer truth-table expectations retained; Use an explicit sufficient two’s-complement width, ordinary Encode, and the existing int signed-decoding helper; This avoids undefined inverse Decode on negatives without changing language semantics or reducing the original mixed-sign inputs [int:]←•load "lib/numeric.bpl" I←¯3 2 ¯1 0 J←2 ¯5 ¯2 ¯1 w←1+⌈2⊛1+⌈/|I,J -w int 2⊥ ≠⌿⍤2 (wρ2)⊤[I◇J]ᵀ ⍝ ¯1 ¯7 1 ¯1 +w int 2⊥ ≠⌿² (wρ2)⊤[I◇J]ᵀ ⍝ ¯1 ¯7 1 ¯1 ⍝ aplcart/table.tsv:2078 — 2's-complement bit-wise NOR; Prepared signed-bitwise algorithm using ordinary fixed-width encoding; Python integer truth-table expectations retained; Use an explicit sufficient two’s-complement width, ordinary Encode, and the existing int signed-decoding helper; This avoids undefined inverse Decode on negatives without changing language semantics or reducing the original mixed-sign inputs [int:]←•load "lib/numeric.bpl" I←¯3 2 ¯1 0 J←2 ¯5 ¯2 ¯1 w←1+⌈2⊛1+⌈/|I,J -w int 2⊥ ⊽⌿⍤2 (wρ2)⊤[I◇J]ᵀ ⍝ 0 4 0 0 +w int 2⊥ ⊽⌿² (wρ2)⊤[I◇J]ᵀ ⍝ 0 4 0 0 ⍝ aplcart/table.tsv:2079 — 2's-complement bit-wise NAND; Prepared signed-bitwise algorithm using ordinary fixed-width encoding; Python integer truth-table expectations retained; Use an explicit sufficient two’s-complement width, ordinary Encode, and the existing int signed-decoding helper; This avoids undefined inverse Decode on negatives without changing language semantics or reducing the original mixed-sign inputs [int:]←•load "lib/numeric.bpl" I←¯3 2 ¯1 0 J←2 ¯5 ¯2 ¯1 w←1+⌈2⊛1+⌈/|I,J -w int 2⊥ ⊼⌿⍤2 (wρ2)⊤[I◇J]ᵀ ⍝ ¯1 ¯3 1 ¯1 +w int 2⊥ ⊼⌿² (wρ2)⊤[I◇J]ᵀ ⍝ ¯1 ¯3 1 ¯1 ⍝ aplcart/table.tsv:652 — Convert (⎕TS-style or Dyalog date number) date-times to ISO day-of-week components time-stamps; Prepared existing-array arithmetic with independently captured date components; Explicit timestamp: ISO week uses the year of its Thursday; subsecond components are rescaled arithmetically; No clock or general date-conversion API needed [date: days:]←•load "lib/dyalog.bpl" @@ -9544,11 +9544,11 @@ f2021 1 1 12 34 56 123 2020 53 5 12 34 56 123000 ⍝ aplcart/table.tsv:653 — Convert (⎕TS-style or Dyalog date number) date-times to microsecond precision ⎕TS-style time-stamps; Prepared existing-array arithmetic with independently captured date components; Explicit timestamp: ISO week uses the year of its Thursday; subsecond components are rescaled arithmetically; No clock or general date-conversion API needed -1000↣×∘@6 [2024 2 29 12 34 56 123] +1000↣× @6 [2024 2 29 12 34 56 123] 2024 2 29 12 34 56 123000 ⍝ aplcart/table.tsv:655 — Convert (⎕TS-style or Dyalog date number) date-times to nanosecond precision ⎕TS-style time-stamps; Prepared existing-array arithmetic with independently captured date components; Explicit timestamp: ISO week uses the year of its Thursday; subsecond components are rescaled arithmetically; No clock or general date-conversion API needed -1000000↣×∘@6 [2024 2 29 12 34 56 123] +1000000↣× @6 [2024 2 29 12 34 56 123] 2024 2 29 12 34 56 123000000 ⍝ aplcart/table.tsv:2188 — Trace of function application; Prepared tracing dop using first-class function values and explicit output; no function-source introspection required; Trace ordinary function values rather than reconstructing a function name through ⎕OR. Preserve monadic/dyadic calls and return the operand result @@ -9680,7 +9680,7 @@ T←•csv "name,score",(•ucs 10),"Ada,12",(•ucs 10),"Ben,7" {⍬:⍬}¨ι3ₓ ⍝ [(⍬:⍬) (⍬:⍬) (⍬:⍬)] ⍝ aplcart/table.tsv:1515 — Header-row matrix to records -{K←↑ω ◇ K↣:∘¨↓1↓ω}["Name" "Age" "Zipcode"◇"Bob" "21" "30102"◇"Sally" "32" "43001"] +{K←↑ω ◇ K↣: ¨↓1↓ω}["Name" "Age" "Zipcode"◇"Bob" "21" "30102"◇"Sally" "32" "43001"] [["Name":"Bob" "Age":"21" "Zipcode":"30102"] ["Name":"Sally" "Age":"32" "Zipcode":"43001"]] ⍝ aplcart/table.tsv:1891 — Name–value pairs to a keyed record @@ -9745,7 +9745,7 @@ T.[["aa" "bb"]]←1 2 T ⍝ "aa" "bb":1 2 ⍝ aplcart/table.tsv:2167 — Apply a function to every record value -×↢2∘¨["price":[10 20] "qty":[2 4]] ⍝ ["price":[20 40] "qty":[4 8]] +×↢2 ¨["price":[10 20] "qty":[2 4]] ⍝ ["price":[20 40] "qty":[4 8]] ⍝ aplcart/table.tsv:2320 — Apply a function stored in a record T←["increment":{ω+1}] ◇ T.increment 5 ⍝ 6 @@ -10089,13 +10089,13 @@ op←{⍶ω} •vfi "12 nope ¯3 1.5" ⍝ [[1 0 1 1]ₓ;12 0 ¯3 1.5] ⍝ aplcart/table.tsv:1241 — Conversion of each row to a number (default zero) -(↑∘(1↣⊃)∘•vfi)⍤1 ⊃ "12" "nope" "¯3" ⍝ 12 0 ¯3 +(↑∘(1↣⊃)∘•vfi)¹ ⊃ "12" "nope" "¯3" ⍝ 12 0 ¯3 ⍝ aplcart/table.tsv:1284 — Sum of numbers in character matrix Dm -+/((↑∘(1↣⊃)∘•vfi)⍤1)⊃"12" '5' "¯3" ⍝ 14 ++/((↑∘(1↣⊃)∘•vfi)¹)⊃"12" '5' "¯3" ⍝ 14 ⍝ aplcart/table.tsv:1560 — Conversion of each row to a number with defaults X -8({[v n]←•vfiω ◇ α@ ⍸~v n}⍤1)⊃"12" "bad" "¯3" ⍝ 3 1ρ12 8 ¯3 +8({[v n]←•vfiω ◇ α@ ⍸~v n}¹)⊃"12" "bad" "¯3" ⍝ 3 1ρ12 8 ¯3 ⍝ aplcart/table.tsv:1441 — Read raw bytes of file Dv as 8-bit unsigned characters testpath •nput 0 65 127 128 255 @@ -10654,7 +10654,7 @@ $t ⍝ aplcart/table.tsv:2408 — Singular Value Decomposition; Ported as `"svd" •decompose`. The case checks that the factors multiply back to the matrix, rounded to integers r←"svd" •decompose m←3 2ρ1 2 3 4 5 6 -m≡⌊0.5+(r.u×⍤1 r.s)+.×+⍉r.v ⍝ $t +m≡⌊0.5+(r.u×¹ r.s)+.×+⍉r.v ⍝ $t ⍝ aplcart/table.tsv:2703 — Deserialise Array; Ported as `•literal`, which reads data from BPL source text; Dyalog's serialised form is binary, and BPL's is text •literal "[1 [2 3ₓ] ""ab""]" ⍝ [1 [2 3ₓ] "ab"] diff --git a/tests/reference/april.bpl b/tests/reference/april.bpl index c378d151..7e00c7fb 100644 --- a/tests/reference/april.bpl +++ b/tests/reference/april.bpl @@ -486,10 +486,10 @@ v←1 2 3 ◇ ⊂v ≡ ⊂1 2 3 ⍝ $t ⊃[(3 4ρι9ₓ)] ⍝ [[0 1 2 3◇4 5 6 7◇8 0 1 2]◇]ₓ ⍝ april:761 — -{⊃[ω]}⍤1 [3 4]ρι9ₓ ⍝ [[0 1 2 3◇]◇[4 5 6 7◇]◇[8 0 1 2◇]]ₓ +{⊃[ω]}¹ [3 4]ρι9ₓ ⍝ [[0 1 2 3◇]◇[4 5 6 7◇]◇[8 0 1 2◇]]ₓ ⍝ april:762 — -,⍤0 [3 4]ρι9ₓ ⍝ ([[[0]◇[1]◇[2]◇[3]]◇[[4]◇[5]◇[6]◇[7]]◇[[8]◇[0]◇[1]◇[2]]])ₓ +,⁰ [3 4]ρι9ₓ ⍝ ([[[0]◇[1]◇[2]◇[3]]◇[[4]◇[5]◇[6]◇[7]]◇[[8]◇[0]◇[1]◇[2]]])ₓ ⍝ april:763 — ,₀ ₁(2 3 3ρι12ₓ) ⍝ [0 1 2◇3 4 5◇6 7 8◇9 10 11◇0 1 2◇3 4 5]ₓ @@ -582,13 +582,13 @@ v←1 2 3 ◇ ⊂v ≡ ⊂1 2 3 ⍝ $t ⊃[1 2 3 4;1 2 3 4] ⍝ [1 2 3 4◇1 2 3 4] ⍝ april:804 — -1 2 3 4 ,⍤0 [1 2 3 4] ⍝ [1 1◇2 2◇3 3◇4 4] +1 2 3 4 ,⁰ [1 2 3 4] ⍝ [1 1◇2 2◇3 3◇4 4] ⍝ april:805 — ⊃[2 3ρι9ₓ;2 3ρι9ₓ] ⍝ [[0 1 2◇3 4 5]◇[0 1 2◇3 4 5]]ₓ ⍝ april:806 — -(2 3ρι9ₓ) ,⍤0 [2 3]ρι9ₓ ⍝ [[0 0◇1 1◇2 2]◇[3 3◇4 4◇5 5]]ₓ +(2 3ρι9ₓ) ,⁰ [2 3]ρι9ₓ ⍝ [[0 0◇1 1◇2 2]◇[3 3◇4 4◇5 5]]ₓ ⍝ april:807 — "UNDER",⍠0.0'-' ⍝ "UNDER-" @@ -597,14 +597,14 @@ v←1 2 3 ◇ ⊂v ≡ ⊂1 2 3 ⍝ $t ↓⊃["UNDER" 5ρ'-'] ⍝ "UNDER" "-----" ⍝ april:810 — -↓"HELLO",⍤0'.' ⍝ "H." "E." "L." "L." "O." +↓"HELLO",⁰'.' ⍝ "H." "E." "L." "L." "O." ⍝ april:811 — -(8+2 2 2ρι8ₓ){⊃[α ω]}⍤2(2 2 2ρι8ₓ) +(8+2 2 2ρι8ₓ){⊃[α ω]}²(2 2 2ρι8ₓ) [[[8 9◇10 11]◇[0 1◇2 3]]◇[[12 13◇14 15]◇[4 5◇6 7]]] ⍝ april:813 — -(8+2 2 2ρι8ₓ){⊃[α ω]}⍤1(2 2 2ρι8ₓ) +(8+2 2 2ρι8ₓ){⊃[α ω]}¹(2 2 2ρι8ₓ) [[[8 9◇0 1]◇[10 11◇2 3]]◇[[12 13◇4 5]◇[14 15◇6 7]]] ⍝ april:815 — @@ -1616,11 +1616,11 @@ st←"aodjeignwug" ◇ [⍒st]⌷st ⍝ "wuonjiggeda" 65 105 943 ⍝ april:1404 — Respelled to decode along the first axis, as Dyalog does -(3#₋₁⍪ι4ₓ)⊥⍤1 2⍉[0 0 0 0 1 1 1 1◇0 0 1 1 0 0 1 1◇0 1 0 1 0 1 0 1] +(3#₋₁⍪ι4ₓ)⊥¹ ²⍉[0 0 0 0 1 1 1 1◇0 0 1 1 0 0 1 1◇0 1 0 1 0 1 0 1] [0 1 0 1 0 1 0 1◇0 1 1 2 1 2 2 3◇0 1 2 3 4 5 6 7◇0 1 3 4 9 10 12 13] ⍝ april:1407 — Respelled to decode along the first axis, as Dyalog does -(⍪2 10)⊥⍤1 2⍉[0 0 0 0 1 1 1 1◇0 0 1 1 0 0 1 1◇0 1 0 1 0 1 0 1] +(⍪2 10)⊥¹ ²⍉[0 0 0 0 1 1 1 1◇0 0 1 1 0 0 1 1◇0 1 0 1 0 1 0 1] [0 1 2 3 4 5 6 7◇0 1 10 11 100 101 110 111] ⍝ april:1409 — Respelled to decode along the first axis, as Dyalog does @@ -1793,7 +1793,7 @@ g←÷ ◇ g/⍬ ⍝ 1 [[0 1 2 3] [1 2 3 4] [2 3 4 5] [3 4 5 6] [4 5 6 7] [5 6 7 8] [6 7 8 9] [7 8 9 10] [8 9 10 11]]ₓ ⍝ april:1528 — -,/3 4{+/∘(α↣↕)⍤1 ω}¨⊂3 6ρι9ₓ +,/3 4{+/∘(α↣↕)¹ ω}¨⊂3 6ρι9ₓ [3 6 9 12 6 10 14◇21 15 9 3 21 16 11◇12 15 18 21 18 22 26]ₓ ⍝ april:1530 — @@ -4251,7 +4251,7 @@ dscan(ι10ₓ)ᵣ ⍝ [0 0 0 0 0 0 0 0 0 0]ᵣ ⍝ april/libraries/dfns/array/demo.lisp:342 — [shannon:]←•load "lib/array.bpl" -⌊(1000,10ρ1)×⍤1(shannon⍤1 , ⊣) 1+~ (ι10ₓ) >⊗ ι10ₓ +⌊(1000,10ρ1)×¹(shannon¹ , ⊣) 1+~ (ι10ₓ) >⊗ ι10ₓ ⍝ => [0 2 2 2 2 2 2 2 2 2 2◇468 1 2 2 2 2 2 2 2 2 2◇721 1 1 2 2 2 2 2 2 2 2◇881 1 1 1 2 2 2 2 2 2 2◇970 1 1 1 1 2 2 2 2 2 2◇1000 1 1 1 1 1 2 2 2 2 2◇970 1 1 1 1 1 1 2 2 2 2◇881 1 1 1 1 1 1 1 2 2 2◇721 1 1 1 1 1 1 1 1 2 2◇468 1 1 1 1 1 1 1 1 1 2]ₓ diff --git a/tests/reference/april_mathish.bpl b/tests/reference/april_mathish.bpl index 8a452507..55c04300 100644 --- a/tests/reference/april_mathish.bpl +++ b/tests/reference/april_mathish.bpl @@ -62,7 +62,7 @@ cfract¯2.3 ⍝ [¯3 1 2 3]ₓ ⍝ april/libraries/dfns/numeric/demo.lisp:211 — Real rational recovery uses the first continued-fraction convergent within relative error 1e-14. Pi recovers 5419351/1725033, whose canonical continued fraction ends in 4. April's 14-column float-round-trip expectation is retained separately; 0+ makes coefficients approximate [cfract: rational:]←•load "lib/numeric.bpl" -rational +↢÷∘/¨,\ 0+(0 cfract π1) +rational +↢÷ /¨,\ 0+(0 cfract π1) ⍝ => [3 22 333 355 103993 104348 208341 312689 833719 1146408 5419351◇1 7 106 113 33102 33215 66317 99532 265381 364913 1725033] diff --git a/tests/reference/bqn.bpl b/tests/reference/bqn.bpl index 92d6ca47..ac502c69 100644 --- a/tests/reference/bqn.bpl +++ b/tests/reference/bqn.bpl @@ -27,11 +27,11 @@ fn←"rtd"ι↑ ⍚[⌽ 1↑ 1↓ ⊢] ◇ [fn "r123";fn "d123";fn "123"] +\@∊ [3 1 0] [2 5] [0 0 6] ⍝ (3 4 4◇6 11◇11 11 17) ⍝ bqn:under:61 — Rotate the first column -a←[0 1 2◇3 4 5◇6 7 8◇9 10 11] ◇ 1⌽∘@(↑⍤1) a +a←[0 1 2◇3 4 5◇6 7 8◇9 10 11] ◇ 1⌽ @(↑¹) a [3 1 2◇6 4 5◇9 7 8◇0 10 11] ⍝ bqn:under:69 — Reverse the first half of a list -⌽@(2÷⍨≢∘↣↑)"abcdef" ⍝ "cbadef" +⌽@(2÷⍨≢ ↣↑)"abcdef" ⍝ "cbadef" ⍝ bqn:under:73 — Add 10 to the elements below 5, with the mask computed from the argument 10+@[5>] 3 8 2 2 6 ⍝ 13 8 12 12 6 @@ -43,7 +43,7 @@ a←[0 1 2◇3 4 5◇6 7 8◇9 10 11] ◇ 1⌽∘@(↑⍤1) a +/÷≢ @(×⍨) 2 3 4 5 ⍝ 3.6742346141747673 ⍝ bqn:under:99 — An arithmetic progression up to a limit, through an inverted transformation -ι∘⌈@(4+3×⊢∘⁻) 20 ⍝ 4 7 10 13 16 19 +ι∘⌈@(4+3×⊢ ⁻) 20 ⍝ 4 7 10 13 16 19 ⍝ bqn:under:109 — Replace selected positions with the same positions of the left argument "abcd" ⊣@([[1 2]]⌷) "0123" ⍝ "0bc3" @@ -56,7 +56,7 @@ a←[0 1 2◇3 4 5◇6 7 8◇9 10 11] ◇ 1⌽∘@(↑⍤1) a ["ab" "cde" "fg"] ⊣@∊ ["---" "----"] ⍝ "abc" "defg" ⍝ bqn:under:123 — Add to the selected elements, keeping the others -1 2 3+∘@(1 1 0 1#) 10 20 30 40 ⍝ 11 22 30 43 +1 2 3+ @(1 1 0 1#) 10 20 30 40 ⍝ 11 22 30 43 ⍝⍝ Undo @@ -67,7 +67,7 @@ a←[0 1 2◇3 4 5◇6 7 8◇9 10 11] ◇ 1⌽∘@(↑⍤1) a ×⍨⁻ ×⍨ ¯3 ⍝ 3 ⍝ bqn:undo:36 — Undo multiplication by a bound left argument -3×∘⁻ 12 ⍝ 4 +3× ⁻12 ⍝ 4 ⍝ bqn:undo:51 — Undo Left accepts arguments that already match 3 ⊣⁻ 3 ⍝ 3 @@ -78,7 +78,7 @@ a←[0 1 2◇3 4 5◇6 7 8◇9 10 11] ◇ 1⌽∘@(↑⍤1) a 3 (+⍣2) 7 ⍝ 13 ⍝ bqn:repeat:39 — Halve the numbers above 6, using a computed count of 0 or 1 -{÷↢2∘⍣(6<ω)ω}¨ 3 7 2 1 8 ⍝ 3 3.5 2 1 4 +{÷↢2 ⍣(6<ω)ω}¨ 3 7 2 1 8 ⍝ 3 3.5 2 1 4 ⍝ bqn:repeat:49 — A negative count applies the inverse 1 (⌽⍣¯1) "abcde" ⍝ "eabcd" @@ -167,7 +167,7 @@ c ⍝ 9 ⍝⍝ Rank ⍝ bqn:rank:92 — Join the strings in each row -s←["words" "go" "here"◇"some" "other" "words"] ◇ ⊂∘∊⍤1 s +s←["words" "go" "here"◇"some" "other" "words"] ◇ ⊂∘∊¹ s "wordsgohere" "someotherwords" ⍝ bqn:rank:146 — Rank 2 on an array with empty cells keeps the frame and the cell shape @@ -187,10 +187,10 @@ m←[0 1 0◇¯1 0 0◇0 0 1] ◇ m (+⌿∘×)⍤[1 ∞] 1 2 3×⊗1 10 ⍝⍝ Fold ⍝ bqn:fold:115 — A continued fraction for e -+↢÷∘/2 1 2 1 1 4 1 1 ⍝ 2.7183098591549295 ++↢÷ /2 1 2 1 1 4 1 1 ⍝ 2.7183098591549295 ⍝ bqn:fold:139 — A seeded fold starts from the right end -"STOP" ⌽↣,∘/ ["ABCDE" "012" "abcd"] ⍝ "EDCBA210dcbaSTOP" +"STOP" ⌽↣, / ["ABCDE" "012" "abcd"] ⍝ "EDCBA210dcbaSTOP" ⍝ bqn:fold:158 — Reducing an empty first axis gives one identity per cell +⌿0 4ρ0 ⍝ 0 0 0 0 diff --git a/tests/reference/core.bpl b/tests/reference/core.bpl index d507bd00..a5af57d4 100644 --- a/tests/reference/core.bpl +++ b/tests/reference/core.bpl @@ -1725,7 +1725,7 @@ k←0 2 1 2 ◇ k⍚[- ⊢ 10×] 1 2 3 4 ⍝ ¯1 20 3 40 (0<⊣/)⍚[1 ⊢] [¯1 2◇3 4] ⍝ [1 1◇3 4] ⍝ — A result of one item spreads across each of its cells, even where other cases' cells differ in shape -0 1 2⍚[5 (1↓)⍤1 ⊢] [1 2 3◇4 5 6◇7 8 9] ⍝ [5 5 5◇5 6 0◇7 8 9] +0 1 2⍚[5 (1↓)¹ ⊢] [1 2 3◇4 5 6◇7 8 9] ⍝ [5 5 5◇5 6 0◇7 8 9] ⍝ agenda:singleton-fill — A one-item list fills a cell even when only one cell picks its case 0 1⍚[[5] ⊢] [1 2 3◇4 5 6] ⍝ [5 5 5◇4 5 6] diff --git a/tests/reference/core_mathish.bpl b/tests/reference/core_mathish.bpl index a460b96a..279b68b3 100644 --- a/tests/reference/core_mathish.bpl +++ b/tests/reference/core_mathish.bpl @@ -86,7 +86,7 @@ s←["ab";"cd";"ef";"gh";"ij";"kl";"mn";"op"] ◇ t←32ρs,⊂"zz" [$t;$t;$t;$t;[1 8 2 3 4 5 0 8 6 7]ₓ;[7 7]ₓ] ⍝ — Interval index in each cell's own boundaries, and index of within the tolerance -[({ω⍸2.5}⍤1)[2 3]ρ1 2 3 0 5 10 ; ({ωι0.3}⍤1)[2 3]ρ0.1 0.2 0.30000000000000004 0.3 0.1 0.2] ⍝ [[2 1]ₓ ; [2 0]ₓ] +[({ω⍸2.5}¹)[2 3]ρ1 2 3 0 5 10 ; ({ωι0.3}¹)[2 3]ρ0.1 0.2 0.30000000000000004 0.3 0.1 0.2] ⍝ [[2 1]ₓ ; [2 0]ₓ] ⍝ — `≡` compares a batch's exact-integer or Boolean cells with a float constant on the batch's whole, within the tolerance [batched] m←3 2ρι6ₓ ◇ b←2 2ρ$t $f $f $t ◇ c←2 3.0000000000000004 diff --git a/tests/reference/distributions.bpl b/tests/reference/distributions.bpl index e23189a9..73f26435 100644 --- a/tests/reference/distributions.bpl +++ b/tests/reference/distributions.bpl @@ -197,7 +197,7 @@ b←•explain "[h.roll 1ρ6;h.roll 3ρ6]" •prefs ["seed":7] x←{¿6}¨ι4 •prefs ["seed":7] -y←({¿6}⍤0)ι4 +y←({¿6}⁰)ι4 x≡y ⍝ $t ⍝ distribution:batched-draws — A batched draw reproduces its whole result when reseeded and called with the same spelling diff --git a/tests/reference/graphics.bpl b/tests/reference/graphics.bpl index 27fd0c11..46a2b662 100644 --- a/tests/reference/graphics.bpl +++ b/tests/reference/graphics.bpl @@ -83,7 +83,7 @@ h←0.2×3 2 2ρ5ₓ|ι12ₓ 0.2×3 2 2 1ρ5ₓ|ι12ₓ ⍝ image-delay — delay sets each frame's seconds, stored exactly as 1/n for a whole rate n, otherwise in milliseconds or seconds -delays←{t←⍸"fcTL"⍷•ucs ω ◇ {256⊥2 2ρω}⍤1 (⊂t+⊗24ₓ+ι4ₓ)⌷ω} +delays←{t←⍸"fcTL"⍷•ucs ω ◇ {256⊥2 2ρω}¹ (⊂t+⊗24ₓ+ι4ₓ)⌷ω} delays ["delay":[1÷24 0.04 1.6 100]]•image⁻ 4 2 2ρ0.2 ⍝ => [1 24◇1 25◇1600 1000◇100 1] diff --git a/tests/test_expressions.py b/tests/test_expressions.py index 263e378c..c13c6072 100644 --- a/tests/test_expressions.py +++ b/tests/test_expressions.py @@ -21,9 +21,6 @@ def test_expression_parts(): assert fn(mean, [2., 4., 9.]).py == 5. assert fn(plus.reduce, divide, b.tally, b.space, [2., 4., 9.]).py == 5. assert fn(plus.reduce, divide, b.tally, [2., 4., 9.]).py == 0 - stage = b.bpl('∘') - matrix = b.Array(np.array([[2., 4.], [6., 8.]])) - teq(fn(plus.reduce, divide, b.tally, stage, b.rank, 1, matrix).py, [3., 7.]) table = b.Array(a=[1, 2, 3], b=[4, 5, 6]) selected = fn(table, b.dot, [[1, 0]]) assert selected.keys == (('b', 'a'),)