diff options
| -rw-r--r-- | doc/under.md | 12 | ||||
| -rw-r--r-- | doc/undo.md | 8 | ||||
| -rw-r--r-- | doc/windows.md | 63 | ||||
| -rw-r--r-- | docs/doc/under.html | 12 | ||||
| -rw-r--r-- | docs/doc/undo.html | 11 | ||||
| -rw-r--r-- | docs/doc/windows.html | 119 |
6 files changed, 119 insertions, 106 deletions
diff --git a/doc/under.md b/doc/under.md index 78e09ea1..60935da4 100644 --- a/doc/under.md +++ b/doc/under.md @@ -60,15 +60,15 @@ A *structural function* is one that moves elements around without performing com 1⊸⌽⌾(⊏˘) a -When used with Under, the function `1⊸⌽` applies to the first column, rotating it. The result of `𝔽` needs to be compatible with the selection function, so Rotate works but trying to remove an element is no good: +When used with Under, the function `1⊸⌽` applies to the first column, [rotating](reverse.md#rotate) it. The result of `𝔽` needs to be compatible with the selection function, so Rotate works but trying to drop an element is no good: 1⊸↓⌾(⊏˘) a -BQN can detect lots of structural functions when written in [tacit](tacit.md) form; see the list of functions [in the spec](../spec/inferred.md#required-structural-inverses). You can also include computations on the shape. For example, here's a function to reverse the first half of a list. +BQN can detect lots of structural functions when written [tacitly](tacit.md); see the list of recognized forms [in the spec](../spec/inferred.md#required-structural-inverses). You can also include computations on the shape. For example, here's a function to reverse the first half of a list. ⌽⌾(⊢↑˜≠÷2˙) "abcdef" -But you can't use a computation that uses array values, such as `10⊸+⌾((<⊸5)⊸/)` to add 10 to each element below 5. This is because Under can change the array values, so that the function `𝔾` doesn't select the same elements before and after applying it (at the same time, Under can't change array structure, or at least not the parts that matter to `𝔾`). To use a dynamic selection function, compute the mask or indices based on a copy of the argument and use those as part of `𝔾`. +But you can't use a computation that uses array values, such as `10⊸+⌾((<⊸5)⊸/)` to add 10 to each element below 5. This is because Under can change the array values, so that the function `𝔾` doesn't select the same elements before and after applying it (contrarily, Under can't change array structure, or at least not the parts that matter to `𝔾`). To use a dynamic selection function, compute the mask or indices based on a copy of the argument and use those as part of `𝔾`. {10⊸+⌾((𝕩<5)⊸/)𝕩} 3‿8‿2‿2‿6 @@ -92,17 +92,17 @@ Under is the idiomatic way to do a round-to-nearest function: ⌊⌾(10⊸×) 3.524‿6.799‿2.031 -See how it works? `⌊` rounds down to an integer, but we can get it to round down to a decimal by first multiplying by 10 (single decimals are now integers), then rounding, then undoing that multiplication. A related idea is to not just round but produce a range. Suppose I want the arithmetic progression 4, 7, 10, ... <20. If I had the right range `↕n`, then it would be `4+3×↕n`, or `(4+3×⊢)↕n`. By using the *inverse* of this transformation function on the desired endpoint, I can make sure it's applied on the way out, and BQN figures out what to do on the way in as if by magic. +See how it works? `⌊` rounds down to an integer, but we can get it to round down to a decimal by first multiplying by 10 (so that single decimals become integers), then rounding, then undoing that multiplication. A related idea is to not just round but produce a range. Suppose I want the arithmetic progression 4, 7, 10, ... <20. If I had the right range `↕n`, then it would be `4+3×↕n`, or `(4+3×⊢)↕n`. By using the *inverse* of this transformation function on the desired endpoint, I can make sure it's applied on the way out, and BQN figures out what to do on the way in as if by magic. ↕∘⌈⌾((4+3×⊢)⁼) 20 -Well, really it's a bit of simple algebra, but if it wants to wear a pointy hat and wave a wand around I won't judge. +Well, really it's some simple algebra, but if it wants to wear a pointy hat and wave a wand around I won't judge. ## Left argument When called dyadically, Under applies `𝔽` dyadically, like [Over](compose.md#over). This doesn't affect the undoing part of Under, which still tries to put the result of `𝔽` back into `𝕩` for structural Under or invert `𝔾` for computational. In fact, `𝕨 𝔽⌾𝔾 𝕩` is equivalent to `(𝔾𝕨)˙⊸𝔽⌾𝔾 𝕩` so no exciting language stuff is happening here at all. -But you can still do some cool stuff with it! One pattern is simply to set `𝔽` to `⊣`, the [identity](identity.md) function that just returns its left argument. Now structural Under will replace everything that `𝔾` selects from `𝕩` with the corresponding values in `𝕨`. Here's an example that replaces elements with indices `1` and `2`. +But you can still do cool things with it! One pattern is simply to set `𝔽` to `⊣`, the [identity](identity.md) function that just returns its left argument. Now structural Under will replace everything that `𝔾` selects from `𝕩` with the corresponding values in `𝕨`. Here's an example that replaces elements with indices `1` and `2`. "abcd" ⊣⌾(1‿2⊸⊏) "0123" diff --git a/doc/undo.md b/doc/undo.md index 4afa2c00..fe27fa37 100644 --- a/doc/undo.md +++ b/doc/undo.md @@ -18,7 +18,7 @@ Here it undoes a function to decrement the last character by incrementing that c ## The rules -If `𝔽` can be inverted exactly, then Undo just does that. However, there are also some other functions that BQN inverts. For example, the squaring function `ט` has both a positive and a negative inverse, and yet: +If `𝔽` can be inverted exactly, then Undo just does that (or tries). However, there are also some other functions that BQN inverts. For example, the squaring function `ט` has both a positive and a negative inverse, and yet: ט ¯3 ט⁼ ט ¯3 # It's not the same! @@ -40,6 +40,7 @@ A few notable inverses are the [logarithm](arithmetic.md#basic-arithmetic) `⋆ Structural functions like [Take](take.md) and [shifts](shift.md) that remove elements from `𝕩` can't be inverted, because given the result there's no way to know what the elements should be. However, there are two special cases that have inverses defined despite losing data: these are `⊣⁼` and `k⁼` where `k` is a constant (a data type, or `k˙`). For these, `𝕩` is required to [match](match.md) the always returned value `𝕨` or `k`, and this value is also used for the result—even though any result would be valid, as these functions ignore `𝕩`. 3 ⊣⁼ 4 + 3 ⊣⁼ 3 ## Undo headers @@ -51,4 +52,7 @@ Of course BQN will never be able to invert all the functions you could write (if 𝕊⁼𝕩: 𝕩÷1-𝕩 } -The above function could also be defined with the automatically invertible `1⊸+⌾÷`, but maybe there's a numerical reason to use the definition above. Like a normal header, an undo header reflects the normal use, but it includes `⁼` and possibly `˜` addition to the function and arguments. +The above function could also be defined with the automatically invertible `1⊸+⌾÷`, but maybe there's a numerical reason to use the definition above. Like a normal header, an undo header reflects the normal use, but it includes `⁼` and possibly `˜` addition to the function and arguments. Any header that includes a function can have these modifiers added—even a fancy modifier header like `𝔽_m1⁼a‿b:` or plain label like `𝕊⁼:`. The three forms are `𝕊⁼𝕩:`, `𝕨𝕊⁼𝕩:`, and `𝕨𝕊˜⁼𝕩:`, and the two dyadic forms are also used to derive `k⊸F⁼𝕩` and `F⟜k⁼𝕩` with a constant `k`. + + G ← { 𝕊˜⁼:𝕩-2×𝕨 ; 𝕨+2×𝕩 } + G⟜2⁼ 7 diff --git a/doc/windows.md b/doc/windows.md index 379bf644..6c009143 100644 --- a/doc/windows.md +++ b/doc/windows.md @@ -2,75 +2,72 @@ # Windows -In BQN, it's strongly preferred to use functions, and not modifiers, for array manipulation. Functions are simpler as they have fewer moving parts. They are more concrete, since the array results can always be viewed right away. They are easier to implement with reasonable performance as well, since there is no need to recognize many possible function operands as special cases. +The Windows function returns all slices, or contiguous subarrays, with shape (well, shape prefix) `𝕨` from `𝕩`. It might also be seen as sliding a moving window along `𝕩`. -The Window function replaces APL's Windowed Reduction, J's more general Infix operator, and Dyalog's Stencil, which is adapted from one case of J's Cut operator. +This function replaces APL's Windowed Reduction, J's more general Infix operator, and Dyalog APL's Stencil, which is adapted from one case of J's Cut operator. In BQN, it's strongly preferred to use functions, and not modifiers, for array manipulation. Functions are simpler with fewer moving parts, and more concrete, since the array results can always be viewed right away. -## Definition +## Basic case -We'll start with the one-axis case. Here Window's left argument is a number between `0` and `1+≠𝕩`. The result is composed of slices of `𝕩` (contiguous sections of major cells) with length `𝕨`, starting at each possible index in order. +We'll start with the one-axis case. Here `𝕨` is a number between `0` and `1+≠𝕩`. The result is composed of slices of `𝕩` (contiguous sections of [major cells](array.md#cells)) with length `𝕨`, starting at each possible index in order. 5↕"abcdefg" There are `1+(≠𝕩)-𝕨`, or `(≠𝕩)¬𝕨`, of these sections, because the starting index must be at least `0` and at most `(≠𝕩)-𝕨`. Another way to find this result is to look at the number of cells in or before a given slice: there are always `𝕨` in the slice and there are only `≠𝕩` in total, so the number of slices is the range [spanned](logic.md) by these two endpoints. -You can take a slice of an array `𝕩` that has length `l` and starts at index `i` using [Take](take.md) with Drop or [Rotate](reverse.md#rotate): `l↑i↓𝕩` or `l↑i⌽𝕩`. The [Prefixes](prefixes.md) function returns all the slices that end at the end of the array (`(≠𝕩)=i+l`), and Suffixes gives the slices that start at the beginning (`i=0`). Windows gives yet another collection of slices: the ones that have a fixed length `l=𝕨`. Selecting one cell from its result gives you the slice starting at that cell's index: +A single slice of an array `𝕩` with length `l` and starting index `i` is `l↑i↓𝕩`, using [Take and Drop](take.md). The [Prefixes](prefixes.md) function returns all the slices that end at the end of the array (`(≠𝕩)=i+l`), and Suffixes gives the slices that start at the beginning (`i=0`). Windows gives yet another collection of slices: the ones that have a fixed length `l=𝕨`. Selecting one cell from its result gives the slice starting at that cell's index: 2⊏5↕"abcdefg" - 5↑2↓"abcdefg" - -Windows differs from Prefixes and Suffixes in that it doesn't add a layer of nesting (it doesn't enclose each slice). This is possible because the slices have a fixed size. -### Multiple dimensions + 5↑2↓"abcdefg" -The above description applies to a higher-rank right argument. As an example, we'll look at two-row slices of a shape `3‿4` array. For convenience, we will enclose each slice. Note that slices always have the same rank as the argument array. +Windows differs from Prefixes and Suffixes in that it doesn't add a layer of nesting (it doesn't enclose each slice). This is possible because the slices have a fixed size, so they fit together as cells of an array. - <⎉2 2↕"0123"∾"abcd"≍"ABCD" +## Windowed reduction -Passing a list as the left argument to Windows takes slices along any number of leading axes. Here are all the shape `2‿2` slices: +Windows can be followed up with [Insert](fold.md#insert) on each slice to give a windowed reduction or fold. Here we take running sums of 3 values. - <⎉2 2‿2↕"0123"∾"abcd"≍"ABCD" + +˝˘3↕ ⟨2,6,0,1,4,3⟩ -The slices are naturally arranged along multiple dimensions according to their starting index. Once again the equivalence `i⊏l↕x` ←→ `l↑i↓x` holds, provided `i` and `l` have the same length. +A common task is to act on windows with an initial or final element so the total length stays the same. When using windows of length 2, the best way to accomplish this is with a [shift](shift.md) `«` or `»`. If the window length is longer or variable, then a trick with Windows works better: add the elements, and then use windows matching the original length. Here we invert Plus [Scan](scan.md) `` +` ``, which requires we take pairwise differences starting at initial value 0. -If `𝕨` has length `0`, then `𝕩` is not sliced along any dimensions. The only slice that results—the entire argument—is then arranged along an additional zero dimensions. In the end, the result is `𝕩`, unchanged. + -⟜(0»⊢) +` 3‿2‿1‿1 -### More formally + (-˜˝≠↕0∾⊢) +` 3‿2‿1‿1 -`𝕩` is an array. `𝕨` is a number, or numeric list or unit, with `𝕨≤○≠≢𝕩`. The result `z` has shape `𝕨∾¬⟜𝕨⌾((≠𝕨)⊸↑)≢𝕩`, and element `i⊑z` is `𝕩⊑˜(≠𝕨)(↑+⌾((≠𝕨)⊸↑)↓)i`. +With Windows, we can modify the 3-element running sum from before to keep the length constant by starting with two zeros. -Using [Group](group.md) we could also write `i⊑z` ←→ `𝕩⊑˜(𝕨∾○(↕∘≠)≢𝕩) +´¨∘⊔ i`. + (+˝≠↕(2⥊0)⊸∾) ⟨2,6,0,1,4,3⟩ ## Symmetry -Let's look at an earlier example, along with its [Transpose](transpose.md) (`⍉`). +Let's look at the first example, paired with its [Transpose](transpose.md) (`⍉`). - {⟨𝕩,⍉𝕩⟩}5↕"abcdefg" + ⋈⟜⍉ 5↕"abcdefg" -Although the two arrays have different shapes, they are identical where they overlap. +Although the two arrays have different shapes, they're identical in the 3×3 region where they overlap. - ≡○(3‿3⊸↑)⟜⍉5↕"abcdefg" + ≡○(3‿3⊸↑)⟜⍉ 5↕"abcdefg" -In other words, the i'th element of slice j is the same as the j'th element of slice i: it is the `i+j`'th element of the argument. So transposing still gives a possible result of Windows, but with a different slice length. +More concretely, the `i`th element of slice `j` is the same as the `j`th element of slice `i`: it's the `i+j`th element of the argument. So transposing still gives a possible result of Windows, but with a different slice length. The two lengths are related by [Span](logic.md), which converts between length and number of slices. {(5↕𝕩)≡⍉(3↕𝕩)}"abcdefg" -In general, we need a more complicated transpose—swapping the first set of `≠𝕨` axes with the second set. Note again the use of [Span](logic.md), our slice-length to slice-number converter. + (≠"abcdefg") ¬ 3 - {((5‿6¬2‿2)↕𝕩) ≡ 2‿3⍉(2‿2↕𝕩)} ↕5‿6‿7 +## Multiple dimensions -## Applications +The right argument can have rank more than 1, and it's viewed as a list of major cells following [leading axis](leading.md) principles. As an example, Windows can take two-row slices of a shape `3‿4` array. -Windows can be followed up with a [reduction](fold.md#insert) on each slice to give a windowed reduction. Here we take running sums of 3 values. + 2↕["0123","abcd","ABCD"] - +˝˘3↕ ⟨2,6,0,1,4,3⟩ + <⎉2 2↕["0123","abcd","ABCD"] -A common task is to act on windows with an initial or final element so the total length stays the same. When using windows of length 2, the best way to accomplish this is with a [shift](shift.md) `«` or `»`. If the window length is longer or variable, then a trick with Windows works better: add the elements, and then use windows matching the original length. Here we invert Plus [Scan](scan.md) `` +` ``, which requires we take pairwise differences starting at initial value 0. +In the second version we've enclosed each slice with `<⎉2` for viewing—a slice has rank 2, the same as `𝕩`. Passing a list as the left argument to Windows takes slices along any number of leading axes. Here are all the shape `2‿2` slices: - -⟜(0»⊢) +` 3‿2‿1‿1 + <⎉2 2‿2↕["0123","abcd","ABCD"] - (-˜˝≠↕0∾⊢) +` 3‿2‿1‿1 +The slices are naturally arranged along multiple dimensions according to their starting index. Once again the equivalence `i⊏l↕x` ←→ `l↑i↓x` holds, provided `i` and `l` have the same length. -With Windows, we can modify the 3-element running sum from before to keep the length constant by starting with two zeros. +If `𝕨` has length `0`, then `𝕩` is not sliced along any dimensions. The only slice that results—the entire argument—is then arranged along an additional zero dimensions. In the end, the result is `𝕩`, unchanged. - (+˝≠↕(2⥊0)⊸∾) ⟨2,6,0,1,4,3⟩ +Here's a more formal definition: `𝕩` is an array. `𝕨` is a number, or numeric list or unit, with `𝕨≤○≠≢𝕩`. The result `z` has shape `𝕨∾¬⟜𝕨⌾((≠𝕨)⊸↑)≢𝕩`, and element `i⊑z` is `i⊑z` ←→ `𝕩⊑˜+´¨(𝕨∾○(↕∘≠)≢𝕩)⊔i`. diff --git a/docs/doc/under.html b/docs/doc/under.html index ae931d47..2a06e458 100644 --- a/docs/doc/under.html +++ b/docs/doc/under.html @@ -57,15 +57,15 @@ 0 10 11 ┘ </pre> -<p>When used with Under, the function <code><span class='Number'>1</span><span class='Modifier2'>⊸</span><span class='Function'>⌽</span></code> applies to the first column, rotating it. The result of <code><span class='Function'>𝔽</span></code> needs to be compatible with the selection function, so Rotate works but trying to remove an element is no good:</p> +<p>When used with Under, the function <code><span class='Number'>1</span><span class='Modifier2'>⊸</span><span class='Function'>⌽</span></code> applies to the first column, <a href="reverse.html#rotate">rotating</a> it. The result of <code><span class='Function'>𝔽</span></code> needs to be compatible with the selection function, so Rotate works but trying to drop an element is no good:</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MeKKuOKGk+KMvijiio/LmCkgYQ==">↗️</a><pre> <span class='Number'>1</span><span class='Modifier2'>⊸</span><span class='Function'>↓</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Function'>⊏</span><span class='Modifier'>˘</span><span class='Paren'>)</span> <span class='Value'>a</span> <span class='Error'>Error: ⁼: Inverse not found</span> </pre> -<p>BQN can detect lots of structural functions when written in <a href="tacit.html">tacit</a> form; see the list of functions <a href="../spec/inferred.html#required-structural-inverses">in the spec</a>. You can also include computations on the shape. For example, here's a function to reverse the first half of a list.</p> +<p>BQN can detect lots of structural functions when written <a href="tacit.html">tacitly</a>; see the list of recognized forms <a href="../spec/inferred.html#required-structural-inverses">in the spec</a>. You can also include computations on the shape. For example, here's a function to reverse the first half of a list.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oy94oy+KOKKouKGkcuc4omgw7cyy5kpICJhYmNkZWYi">↗️</a><pre> <span class='Function'>⌽</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Function'>⊢↑</span><span class='Modifier'>˜</span><span class='Function'>≠÷</span><span class='Number'>2</span><span class='Modifier'>˙</span><span class='Paren'>)</span> <span class='String'>"abcdef"</span> "cbadef" </pre> -<p>But you can't use a computation that uses array values, such as <code><span class='Number'>10</span><span class='Modifier2'>⊸</span><span class='Function'>+</span><span class='Modifier2'>⌾</span><span class='Paren'>((</span><span class='Function'><</span><span class='Modifier2'>⊸</span><span class='Number'>5</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>/</span><span class='Paren'>)</span></code> to add 10 to each element below 5. This is because Under can change the array values, so that the function <code><span class='Function'>𝔾</span></code> doesn't select the same elements before and after applying it (at the same time, Under can't change array structure, or at least not the parts that matter to <code><span class='Function'>𝔾</span></code>). To use a dynamic selection function, compute the mask or indices based on a copy of the argument and use those as part of <code><span class='Function'>𝔾</span></code>.</p> +<p>But you can't use a computation that uses array values, such as <code><span class='Number'>10</span><span class='Modifier2'>⊸</span><span class='Function'>+</span><span class='Modifier2'>⌾</span><span class='Paren'>((</span><span class='Function'><</span><span class='Modifier2'>⊸</span><span class='Number'>5</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>/</span><span class='Paren'>)</span></code> to add 10 to each element below 5. This is because Under can change the array values, so that the function <code><span class='Function'>𝔾</span></code> doesn't select the same elements before and after applying it (contrarily, Under can't change array structure, or at least not the parts that matter to <code><span class='Function'>𝔾</span></code>). To use a dynamic selection function, compute the mask or indices based on a copy of the argument and use those as part of <code><span class='Function'>𝔾</span></code>.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=ezEw4oq4K+KMvigo8J2VqTw1KeKKuC8p8J2VqX0gM+KAvzjigL8y4oC/MuKAvzYKCig84p+cNSniirgvIDPigL844oC/MuKAvzLigL82CgooPOKfnDUp4oq4LyB7MTDiirgr4oy+KCjwnZWpPDUp4oq4LynwnZWpfSAz4oC/OOKAvzLigL8y4oC/Ng==">↗️</a><pre> <span class='Brace'>{</span><span class='Number'>10</span><span class='Modifier2'>⊸</span><span class='Function'>+</span><span class='Modifier2'>⌾</span><span class='Paren'>((</span><span class='Value'>𝕩</span><span class='Function'><</span><span class='Number'>5</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>/</span><span class='Paren'>)</span><span class='Value'>𝕩</span><span class='Brace'>}</span> <span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>8</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span> ⟨ 13 8 12 12 6 ⟩ @@ -89,14 +89,14 @@ <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oyK4oy+KDEw4oq4w5cpIDMuNTI04oC/Ni43OTnigL8yLjAzMQ==">↗️</a><pre> <span class='Function'>⌊</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Number'>10</span><span class='Modifier2'>⊸</span><span class='Function'>×</span><span class='Paren'>)</span> <span class='Number'>3.524</span><span class='Ligature'>‿</span><span class='Number'>6.799</span><span class='Ligature'>‿</span><span class='Number'>2.031</span> ⟨ 3.5 6.7 2 ⟩ </pre> -<p>See how it works? <code><span class='Function'>⌊</span></code> rounds down to an integer, but we can get it to round down to a decimal by first multiplying by 10 (single decimals are now integers), then rounding, then undoing that multiplication. A related idea is to not just round but produce a range. Suppose I want the arithmetic progression 4, 7, 10, ... <20. If I had the right range <code><span class='Function'>↕</span><span class='Value'>n</span></code>, then it would be <code><span class='Number'>4</span><span class='Function'>+</span><span class='Number'>3</span><span class='Function'>×↕</span><span class='Value'>n</span></code>, or <code><span class='Paren'>(</span><span class='Number'>4</span><span class='Function'>+</span><span class='Number'>3</span><span class='Function'>×⊢</span><span class='Paren'>)</span><span class='Function'>↕</span><span class='Value'>n</span></code>. By using the <em>inverse</em> of this transformation function on the desired endpoint, I can make sure it's applied on the way out, and BQN figures out what to do on the way in as if by magic.</p> +<p>See how it works? <code><span class='Function'>⌊</span></code> rounds down to an integer, but we can get it to round down to a decimal by first multiplying by 10 (so that single decimals become integers), then rounding, then undoing that multiplication. A related idea is to not just round but produce a range. Suppose I want the arithmetic progression 4, 7, 10, ... <20. If I had the right range <code><span class='Function'>↕</span><span class='Value'>n</span></code>, then it would be <code><span class='Number'>4</span><span class='Function'>+</span><span class='Number'>3</span><span class='Function'>×↕</span><span class='Value'>n</span></code>, or <code><span class='Paren'>(</span><span class='Number'>4</span><span class='Function'>+</span><span class='Number'>3</span><span class='Function'>×⊢</span><span class='Paren'>)</span><span class='Function'>↕</span><span class='Value'>n</span></code>. By using the <em>inverse</em> of this transformation function on the desired endpoint, I can make sure it's applied on the way out, and BQN figures out what to do on the way in as if by magic.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oaV4oiY4oyI4oy+KCg0KzPDl+KKoinigbwpIDIw">↗️</a><pre> <span class='Function'>↕</span><span class='Modifier2'>∘</span><span class='Function'>⌈</span><span class='Modifier2'>⌾</span><span class='Paren'>((</span><span class='Number'>4</span><span class='Function'>+</span><span class='Number'>3</span><span class='Function'>×⊢</span><span class='Paren'>)</span><span class='Modifier'>⁼</span><span class='Paren'>)</span> <span class='Number'>20</span> ⟨ 4 7 10 13 16 19 ⟩ </pre> -<p>Well, really it's a bit of simple algebra, but if it wants to wear a pointy hat and wave a wand around I won't judge.</p> +<p>Well, really it's some simple algebra, but if it wants to wear a pointy hat and wave a wand around I won't judge.</p> <h2 id="left-argument"><a class="header" href="#left-argument">Left argument</a></h2> <p>When called dyadically, Under applies <code><span class='Function'>𝔽</span></code> dyadically, like <a href="compose.html#over">Over</a>. This doesn't affect the undoing part of Under, which still tries to put the result of <code><span class='Function'>𝔽</span></code> back into <code><span class='Value'>𝕩</span></code> for structural Under or invert <code><span class='Function'>𝔾</span></code> for computational. In fact, <code><span class='Value'>𝕨</span> <span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Function'>𝔾</span> <span class='Value'>𝕩</span></code> is equivalent to <code><span class='Paren'>(</span><span class='Function'>𝔾</span><span class='Value'>𝕨</span><span class='Paren'>)</span><span class='Modifier'>˙</span><span class='Modifier2'>⊸</span><span class='Function'>𝔽</span><span class='Modifier2'>⌾</span><span class='Function'>𝔾</span> <span class='Value'>𝕩</span></code> so no exciting language stuff is happening here at all.</p> -<p>But you can still do some cool stuff with it! One pattern is simply to set <code><span class='Function'>𝔽</span></code> to <code><span class='Function'>⊣</span></code>, the <a href="identity.html">identity</a> function that just returns its left argument. Now structural Under will replace everything that <code><span class='Function'>𝔾</span></code> selects from <code><span class='Value'>𝕩</span></code> with the corresponding values in <code><span class='Value'>𝕨</span></code>. Here's an example that replaces elements with indices <code><span class='Number'>1</span></code> and <code><span class='Number'>2</span></code>.</p> +<p>But you can still do cool things with it! One pattern is simply to set <code><span class='Function'>𝔽</span></code> to <code><span class='Function'>⊣</span></code>, the <a href="identity.html">identity</a> function that just returns its left argument. Now structural Under will replace everything that <code><span class='Function'>𝔾</span></code> selects from <code><span class='Value'>𝕩</span></code> with the corresponding values in <code><span class='Value'>𝕨</span></code>. Here's an example that replaces elements with indices <code><span class='Number'>1</span></code> and <code><span class='Number'>2</span></code>.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=ImFiY2QiIOKKo+KMvigx4oC/MuKKuOKKjykgIjAxMjMi">↗️</a><pre> <span class='String'>"abcd"</span> <span class='Function'>⊣</span><span class='Modifier2'>⌾</span><span class='Paren'>(</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Modifier2'>⊸</span><span class='Function'>⊏</span><span class='Paren'>)</span> <span class='String'>"0123"</span> "0bc3" </pre> diff --git a/docs/doc/undo.html b/docs/doc/undo.html index daf1b60d..7e498365 100644 --- a/docs/doc/undo.html +++ b/docs/doc/undo.html @@ -21,7 +21,7 @@ </pre> <p>Here it undoes a function to decrement the last character by incrementing that character. In part this is enabled by the clean design of BQN primitives, because better-behaved functions like those using structural <a href="under.html">Under</a> are easier to invert.</p> <h2 id="the-rules"><a class="header" href="#the-rules">The rules</a></h2> -<p>If <code><span class='Function'>𝔽</span></code> can be inverted exactly, then Undo just does that. However, there are also some other functions that BQN inverts. For example, the squaring function <code><span class='Function'>×</span><span class='Modifier'>˜</span></code> has both a positive and a negative inverse, and yet:</p> +<p>If <code><span class='Function'>𝔽</span></code> can be inverted exactly, then Undo just does that (or tries). However, there are also some other functions that BQN inverts. For example, the squaring function <code><span class='Function'>×</span><span class='Modifier'>˜</span></code> has both a positive and a negative inverse, and yet:</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=w5fLnCDCrzMKw5fLnOKBvCDDl8ucIMKvMyAgIyBJdCdzIG5vdCB0aGUgc2FtZSE=">↗️</a><pre> <span class='Function'>×</span><span class='Modifier'>˜</span> <span class='Number'>¯3</span> 9 <span class='Function'>×</span><span class='Modifier'>˜⁼</span> <span class='Function'>×</span><span class='Modifier'>˜</span> <span class='Number'>¯3</span> <span class='Comment'># It's not the same! @@ -37,8 +37,9 @@ <p>Arithmetic and simple combinators are usually invertible. A compound function that refers to its argument just once, like <code><span class='Number'>6</span><span class='Function'>+⌽</span><span class='Modifier2'>∘</span><span class='Function'>⍉</span></code>, can typically be undone, but one that uses the argument in two different ways, such as <code><span class='Function'>⊢+⋆</span></code>, probably can't.</p> <p>A few notable inverses are the <a href="arithmetic.html#basic-arithmetic">logarithm</a> <code><span class='Function'>⋆</span><span class='Modifier'>⁼</span></code>, <a href="transpose.html">un-Transpose</a> <code><span class='Function'>⍉</span><span class='Modifier'>⁼</span></code>, and <a href="replicate.html#inverse">Indices inverse</a> <code><span class='Function'>/</span><span class='Modifier'>⁼</span></code>. <a href="enclose.html">Enclose</a> inverse, <code><span class='Function'><</span><span class='Modifier'>⁼</span></code>, is an alternative to <a href="pick.html#first">First</a> that requires its argument to be a unit array.</p> <p>Structural functions like <a href="take.html">Take</a> and <a href="shift.html">shifts</a> that remove elements from <code><span class='Value'>𝕩</span></code> can't be inverted, because given the result there's no way to know what the elements should be. However, there are two special cases that have inverses defined despite losing data: these are <code><span class='Function'>⊣</span><span class='Modifier'>⁼</span></code> and <code><span class='Value'>k</span><span class='Modifier'>⁼</span></code> where <code><span class='Value'>k</span></code> is a constant (a data type, or <code><span class='Value'>k</span><span class='Modifier'>˙</span></code>). For these, <code><span class='Value'>𝕩</span></code> is required to <a href="match.html">match</a> the always returned value <code><span class='Value'>𝕨</span></code> or <code><span class='Value'>k</span></code>, and this value is also used for the result—even though any result would be valid, as these functions ignore <code><span class='Value'>𝕩</span></code>.</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MyDiiqPigbwgNAozIOKKo+KBvCAz">↗️</a><pre> <span class='Number'>3</span> <span class='Function'>⊣</span><span class='Modifier'>⁼</span> <span class='Number'>4</span> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MyDiiqPigbwgNAoKMyDiiqPigbwgMw==">↗️</a><pre> <span class='Number'>3</span> <span class='Function'>⊣</span><span class='Modifier'>⁼</span> <span class='Number'>4</span> <span class='Error'>Error: ⁼: Inverse does not exist</span> + <span class='Number'>3</span> <span class='Function'>⊣</span><span class='Modifier'>⁼</span> <span class='Number'>3</span> 3 </pre> @@ -49,4 +50,8 @@ <span class='Function'>𝕊</span><span class='Modifier'>⁼</span><span class='Value'>𝕩</span><span class='Head'>:</span> <span class='Value'>𝕩</span><span class='Function'>÷</span><span class='Number'>1</span><span class='Function'>-</span><span class='Value'>𝕩</span> <span class='Brace'>}</span> </pre> -<p>The above function could also be defined with the automatically invertible <code><span class='Number'>1</span><span class='Modifier2'>⊸</span><span class='Function'>+</span><span class='Modifier2'>⌾</span><span class='Function'>÷</span></code>, but maybe there's a numerical reason to use the definition above. Like a normal header, an undo header reflects the normal use, but it includes <code><span class='Modifier'>⁼</span></code> and possibly <code><span class='Modifier'>˜</span></code> addition to the function and arguments.</p> +<p>The above function could also be defined with the automatically invertible <code><span class='Number'>1</span><span class='Modifier2'>⊸</span><span class='Function'>+</span><span class='Modifier2'>⌾</span><span class='Function'>÷</span></code>, but maybe there's a numerical reason to use the definition above. Like a normal header, an undo header reflects the normal use, but it includes <code><span class='Modifier'>⁼</span></code> and possibly <code><span class='Modifier'>˜</span></code> addition to the function and arguments. Any header that includes a function can have these modifiers added—even a fancy modifier header like <code><span class='Function'>𝔽</span><span class='Modifier'>_m1⁼</span><span class='Value'>a</span><span class='Ligature'>‿</span><span class='Value'>b</span><span class='Head'>:</span></code> or plain label like <code><span class='Function'>𝕊</span><span class='Modifier'>⁼</span><span class='Head'>:</span></code>. The three forms are <code><span class='Function'>𝕊</span><span class='Modifier'>⁼</span><span class='Value'>𝕩</span><span class='Head'>:</span></code>, <code><span class='Value'>𝕨</span><span class='Function'>𝕊</span><span class='Modifier'>⁼</span><span class='Value'>𝕩</span><span class='Head'>:</span></code>, and <code><span class='Value'>𝕨</span><span class='Function'>𝕊</span><span class='Modifier'>˜⁼</span><span class='Value'>𝕩</span><span class='Head'>:</span></code>, and the two dyadic forms are also used to derive <code><span class='Value'>k</span><span class='Modifier2'>⊸</span><span class='Function'>F</span><span class='Modifier'>⁼</span><span class='Value'>𝕩</span></code> and <code><span class='Function'>F</span><span class='Modifier2'>⟜</span><span class='Value'>k</span><span class='Modifier'>⁼</span><span class='Value'>𝕩</span></code> with a constant <code><span class='Value'>k</span></code>.</p> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=RyDihpAgeyDwnZWKy5zigbw68J2VqS0yw5fwnZWoIDsg8J2VqCsyw5fwnZWpIH0KR+KfnDLigbwgNw==">↗️</a><pre> <span class='Function'>G</span> <span class='Gets'>←</span> <span class='Brace'>{</span> <span class='Function'>𝕊</span><span class='Modifier'>˜⁼</span><span class='Head'>:</span><span class='Value'>𝕩</span><span class='Function'>-</span><span class='Number'>2</span><span class='Function'>×</span><span class='Value'>𝕨</span> <span class='Head'>;</span> <span class='Value'>𝕨</span><span class='Function'>+</span><span class='Number'>2</span><span class='Function'>×</span><span class='Value'>𝕩</span> <span class='Brace'>}</span> + <span class='Function'>G</span><span class='Modifier2'>⟜</span><span class='Number'>2</span><span class='Modifier'>⁼</span> <span class='Number'>7</span> +3 +</pre> diff --git a/docs/doc/windows.html b/docs/doc/windows.html index 77c40f19..67e6a9f8 100644 --- a/docs/doc/windows.html +++ b/docs/doc/windows.html @@ -5,10 +5,10 @@ </head> <div class="nav">(<a href="https://github.com/mlochbaum/BQN">github</a>) / <a href="../index.html">BQN</a> / <a href="index.html">doc</a></div> <h1 id="windows"><a class="header" href="#windows">Windows</a></h1> -<p>In BQN, it's strongly preferred to use functions, and not modifiers, for array manipulation. Functions are simpler as they have fewer moving parts. They are more concrete, since the array results can always be viewed right away. They are easier to implement with reasonable performance as well, since there is no need to recognize many possible function operands as special cases.</p> -<p>The Window function replaces APL's Windowed Reduction, J's more general Infix operator, and Dyalog's Stencil, which is adapted from one case of J's Cut operator.</p> -<h2 id="definition"><a class="header" href="#definition">Definition</a></h2> -<p>We'll start with the one-axis case. Here Window's left argument is a number between <code><span class='Number'>0</span></code> and <code><span class='Number'>1</span><span class='Function'>+≠</span><span class='Value'>𝕩</span></code>. The result is composed of slices of <code><span class='Value'>𝕩</span></code> (contiguous sections of major cells) with length <code><span class='Value'>𝕨</span></code>, starting at each possible index in order.</p> +<p>The Windows function returns all slices, or contiguous subarrays, with shape (well, shape prefix) <code><span class='Value'>𝕨</span></code> from <code><span class='Value'>𝕩</span></code>. It might also be seen as sliding a moving window along <code><span class='Value'>𝕩</span></code>.</p> +<p>This function replaces APL's Windowed Reduction, J's more general Infix operator, and Dyalog APL's Stencil, which is adapted from one case of J's Cut operator. In BQN, it's strongly preferred to use functions, and not modifiers, for array manipulation. Functions are simpler with fewer moving parts, and more concrete, since the array results can always be viewed right away.</p> +<h2 id="basic-case"><a class="header" href="#basic-case">Basic case</a></h2> +<p>We'll start with the one-axis case. Here <code><span class='Value'>𝕨</span></code> is a number between <code><span class='Number'>0</span></code> and <code><span class='Number'>1</span><span class='Function'>+≠</span><span class='Value'>𝕩</span></code>. The result is composed of slices of <code><span class='Value'>𝕩</span></code> (contiguous sections of <a href="array.html#cells">major cells</a>) with length <code><span class='Value'>𝕨</span></code>, starting at each possible index in order.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=NeKGlSJhYmNkZWZnIg==">↗️</a><pre> <span class='Number'>5</span><span class='Function'>↕</span><span class='String'>"abcdefg"</span> ┌─ ╵"abcde @@ -17,44 +17,33 @@ ┘ </pre> <p>There are <code><span class='Number'>1</span><span class='Function'>+</span><span class='Paren'>(</span><span class='Function'>≠</span><span class='Value'>𝕩</span><span class='Paren'>)</span><span class='Function'>-</span><span class='Value'>𝕨</span></code>, or <code><span class='Paren'>(</span><span class='Function'>≠</span><span class='Value'>𝕩</span><span class='Paren'>)</span><span class='Function'>¬</span><span class='Value'>𝕨</span></code>, of these sections, because the starting index must be at least <code><span class='Number'>0</span></code> and at most <code><span class='Paren'>(</span><span class='Function'>≠</span><span class='Value'>𝕩</span><span class='Paren'>)</span><span class='Function'>-</span><span class='Value'>𝕨</span></code>. Another way to find this result is to look at the number of cells in or before a given slice: there are always <code><span class='Value'>𝕨</span></code> in the slice and there are only <code><span class='Function'>≠</span><span class='Value'>𝕩</span></code> in total, so the number of slices is the range <a href="logic.html">spanned</a> by these two endpoints.</p> -<p>You can take a slice of an array <code><span class='Value'>𝕩</span></code> that has length <code><span class='Value'>l</span></code> and starts at index <code><span class='Value'>i</span></code> using <a href="take.html">Take</a> with Drop or <a href="reverse.html#rotate">Rotate</a>: <code><span class='Value'>l</span><span class='Function'>↑</span><span class='Value'>i</span><span class='Function'>↓</span><span class='Value'>𝕩</span></code> or <code><span class='Value'>l</span><span class='Function'>↑</span><span class='Value'>i</span><span class='Function'>⌽</span><span class='Value'>𝕩</span></code>. The <a href="prefixes.html">Prefixes</a> function returns all the slices that end at the end of the array (<code><span class='Paren'>(</span><span class='Function'>≠</span><span class='Value'>𝕩</span><span class='Paren'>)</span><span class='Function'>=</span><span class='Value'>i</span><span class='Function'>+</span><span class='Value'>l</span></code>), and Suffixes gives the slices that start at the beginning (<code><span class='Value'>i</span><span class='Function'>=</span><span class='Number'>0</span></code>). Windows gives yet another collection of slices: the ones that have a fixed length <code><span class='Value'>l</span><span class='Function'>=</span><span class='Value'>𝕨</span></code>. Selecting one cell from its result gives you the slice starting at that cell's index:</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MuKKjzXihpUiYWJjZGVmZyIKNeKGkTLihpMiYWJjZGVmZyI=">↗️</a><pre> <span class='Number'>2</span><span class='Function'>⊏</span><span class='Number'>5</span><span class='Function'>↕</span><span class='String'>"abcdefg"</span> +<p>A single slice of an array <code><span class='Value'>𝕩</span></code> with length <code><span class='Value'>l</span></code> and starting index <code><span class='Value'>i</span></code> is <code><span class='Value'>l</span><span class='Function'>↑</span><span class='Value'>i</span><span class='Function'>↓</span><span class='Value'>𝕩</span></code>, using <a href="take.html">Take and Drop</a>. The <a href="prefixes.html">Prefixes</a> function returns all the slices that end at the end of the array (<code><span class='Paren'>(</span><span class='Function'>≠</span><span class='Value'>𝕩</span><span class='Paren'>)</span><span class='Function'>=</span><span class='Value'>i</span><span class='Function'>+</span><span class='Value'>l</span></code>), and Suffixes gives the slices that start at the beginning (<code><span class='Value'>i</span><span class='Function'>=</span><span class='Number'>0</span></code>). Windows gives yet another collection of slices: the ones that have a fixed length <code><span class='Value'>l</span><span class='Function'>=</span><span class='Value'>𝕨</span></code>. Selecting one cell from its result gives the slice starting at that cell's index:</p> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MuKKjzXihpUiYWJjZGVmZyIKCjXihpEy4oaTImFiY2RlZmci">↗️</a><pre> <span class='Number'>2</span><span class='Function'>⊏</span><span class='Number'>5</span><span class='Function'>↕</span><span class='String'>"abcdefg"</span> "cdefg" + <span class='Number'>5</span><span class='Function'>↑</span><span class='Number'>2</span><span class='Function'>↓</span><span class='String'>"abcdefg"</span> "cdefg" </pre> -<p>Windows differs from Prefixes and Suffixes in that it doesn't add a layer of nesting (it doesn't enclose each slice). This is possible because the slices have a fixed size.</p> -<h3 id="multiple-dimensions"><a class="header" href="#multiple-dimensions">Multiple dimensions</a></h3> -<p>The above description applies to a higher-rank right argument. As an example, we'll look at two-row slices of a shape <code><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>4</span></code> array. For convenience, we will enclose each slice. Note that slices always have the same rank as the argument array.</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=POKOiTIgMuKGlSIwMTIzIuKIviJhYmNkIuKJjSJBQkNEIg==">↗️</a><pre> <span class='Function'><</span><span class='Modifier2'>⎉</span><span class='Number'>2</span> <span class='Number'>2</span><span class='Function'>↕</span><span class='String'>"0123"</span><span class='Function'>∾</span><span class='String'>"abcd"</span><span class='Function'>≍</span><span class='String'>"ABCD"</span> -┌─ -· ┌─ ┌─ - ╵"0123 ╵"abcd - abcd" ABCD" - ┘ ┘ - ┘ +<p>Windows differs from Prefixes and Suffixes in that it doesn't add a layer of nesting (it doesn't enclose each slice). This is possible because the slices have a fixed size, so they fit together as cells of an array.</p> +<h2 id="windowed-reduction"><a class="header" href="#windowed-reduction">Windowed reduction</a></h2> +<p>Windows can be followed up with <a href="fold.html#insert">Insert</a> on each slice to give a windowed reduction or fold. Here we take running sums of 3 values.</p> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=K8udy5gz4oaVIOKfqDIsNiwwLDEsNCwz4p+p">↗️</a><pre> <span class='Function'>+</span><span class='Modifier'>˝˘</span><span class='Number'>3</span><span class='Function'>↕</span> <span class='Bracket'>⟨</span><span class='Number'>2</span><span class='Separator'>,</span><span class='Number'>6</span><span class='Separator'>,</span><span class='Number'>0</span><span class='Separator'>,</span><span class='Number'>1</span><span class='Separator'>,</span><span class='Number'>4</span><span class='Separator'>,</span><span class='Number'>3</span><span class='Bracket'>⟩</span> +⟨ 8 7 5 8 ⟩ </pre> -<p>Passing a list as the left argument to Windows takes slices along any number of leading axes. Here are all the shape <code><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>2</span></code> slices:</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=POKOiTIgMuKAvzLihpUiMDEyMyLiiL4iYWJjZCLiiY0iQUJDRCI=">↗️</a><pre> <span class='Function'><</span><span class='Modifier2'>⎉</span><span class='Number'>2</span> <span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Function'>↕</span><span class='String'>"0123"</span><span class='Function'>∾</span><span class='String'>"abcd"</span><span class='Function'>≍</span><span class='String'>"ABCD"</span> -┌─ -╵ ┌─ ┌─ ┌─ - ╵"01 ╵"12 ╵"23 - ab" bc" cd" - ┘ ┘ ┘ - ┌─ ┌─ ┌─ - ╵"ab ╵"bc ╵"cd - AB" BC" CD" - ┘ ┘ ┘ - ┘ +<p>A common task is to act on windows with an initial or final element so the total length stays the same. When using windows of length 2, the best way to accomplish this is with a <a href="shift.html">shift</a> <code><span class='Function'>«</span></code> or <code><span class='Function'>»</span></code>. If the window length is longer or variable, then a trick with Windows works better: add the elements, and then use windows matching the original length. Here we invert Plus <a href="scan.html">Scan</a> <code><span class='Function'>+</span><span class='Modifier'>`</span></code>, which requires we take pairwise differences starting at initial value 0.</p> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=LeKfnCgwwrviiqIpICtgIDPigL8y4oC/MeKAvzEKCigty5zLneKJoOKGlTDiiL7iiqIpICtgIDPigL8y4oC/MeKAvzE=">↗️</a><pre> <span class='Function'>-</span><span class='Modifier2'>⟜</span><span class='Paren'>(</span><span class='Number'>0</span><span class='Function'>»⊢</span><span class='Paren'>)</span> <span class='Function'>+</span><span class='Modifier'>`</span> <span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span> +⟨ 3 2 1 1 ⟩ + + <span class='Paren'>(</span><span class='Function'>-</span><span class='Modifier'>˜˝</span><span class='Function'>≠↕</span><span class='Number'>0</span><span class='Function'>∾⊢</span><span class='Paren'>)</span> <span class='Function'>+</span><span class='Modifier'>`</span> <span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span> +⟨ 3 2 1 1 ⟩ +</pre> +<p>With Windows, we can modify the 3-element running sum from before to keep the length constant by starting with two zeros.</p> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=KCvLneKJoOKGlSgy4qWKMCniirjiiL4pIOKfqDIsNiwwLDEsNCwz4p+p">↗️</a><pre> <span class='Paren'>(</span><span class='Function'>+</span><span class='Modifier'>˝</span><span class='Function'>≠↕</span><span class='Paren'>(</span><span class='Number'>2</span><span class='Function'>⥊</span><span class='Number'>0</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>∾</span><span class='Paren'>)</span> <span class='Bracket'>⟨</span><span class='Number'>2</span><span class='Separator'>,</span><span class='Number'>6</span><span class='Separator'>,</span><span class='Number'>0</span><span class='Separator'>,</span><span class='Number'>1</span><span class='Separator'>,</span><span class='Number'>4</span><span class='Separator'>,</span><span class='Number'>3</span><span class='Bracket'>⟩</span> +⟨ 2 8 8 7 5 8 ⟩ </pre> -<p>The slices are naturally arranged along multiple dimensions according to their starting index. Once again the equivalence <code><span class='Value'>i</span><span class='Function'>⊏</span><span class='Value'>l</span><span class='Function'>↕</span><span class='Value'>x</span></code> ←→ <code><span class='Value'>l</span><span class='Function'>↑</span><span class='Value'>i</span><span class='Function'>↓</span><span class='Value'>x</span></code> holds, provided <code><span class='Value'>i</span></code> and <code><span class='Value'>l</span></code> have the same length.</p> -<p>If <code><span class='Value'>𝕨</span></code> has length <code><span class='Number'>0</span></code>, then <code><span class='Value'>𝕩</span></code> is not sliced along any dimensions. The only slice that results—the entire argument—is then arranged along an additional zero dimensions. In the end, the result is <code><span class='Value'>𝕩</span></code>, unchanged.</p> -<h3 id="more-formally"><a class="header" href="#more-formally">More formally</a></h3> -<p><code><span class='Value'>𝕩</span></code> is an array. <code><span class='Value'>𝕨</span></code> is a number, or numeric list or unit, with <code><span class='Value'>𝕨</span><span class='Function'>≤</span><span class='Modifier2'>○</span><span class='Function'>≠≢</span><span class='Value'>𝕩</span></code>. The result <code><span class='Value'>z</span></code> has shape <code><span class='Value'>𝕨</span><span class='Function'>∾¬</span><span class='Modifier2'>⟜</span><span class='Value'>𝕨</span><span class='Modifier2'>⌾</span><span class='Paren'>((</span><span class='Function'>≠</span><span class='Value'>𝕨</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>↑</span><span class='Paren'>)</span><span class='Function'>≢</span><span class='Value'>𝕩</span></code>, and element <code><span class='Value'>i</span><span class='Function'>⊑</span><span class='Value'>z</span></code> is <code><span class='Value'>𝕩</span><span class='Function'>⊑</span><span class='Modifier'>˜</span><span class='Paren'>(</span><span class='Function'>≠</span><span class='Value'>𝕨</span><span class='Paren'>)(</span><span class='Function'>↑+</span><span class='Modifier2'>⌾</span><span class='Paren'>((</span><span class='Function'>≠</span><span class='Value'>𝕨</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>↑</span><span class='Paren'>)</span><span class='Function'>↓</span><span class='Paren'>)</span><span class='Value'>i</span></code>.</p> -<p>Using <a href="group.html">Group</a> we could also write <code><span class='Value'>i</span><span class='Function'>⊑</span><span class='Value'>z</span></code> ←→ <code><span class='Value'>𝕩</span><span class='Function'>⊑</span><span class='Modifier'>˜</span><span class='Paren'>(</span><span class='Value'>𝕨</span><span class='Function'>∾</span><span class='Modifier2'>○</span><span class='Paren'>(</span><span class='Function'>↕</span><span class='Modifier2'>∘</span><span class='Function'>≠</span><span class='Paren'>)</span><span class='Function'>≢</span><span class='Value'>𝕩</span><span class='Paren'>)</span> <span class='Function'>+</span><span class='Modifier'>´¨</span><span class='Modifier2'>∘</span><span class='Function'>⊔</span> <span class='Value'>i</span></code>.</p> <h2 id="symmetry"><a class="header" href="#symmetry">Symmetry</a></h2> -<p>Let's look at an earlier example, along with its <a href="transpose.html">Transpose</a> (<code><span class='Function'>⍉</span></code>).</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=e+KfqPCdlaks4o2J8J2VqeKfqX014oaVImFiY2RlZmci">↗️</a><pre> <span class='Brace'>{</span><span class='Bracket'>⟨</span><span class='Value'>𝕩</span><span class='Separator'>,</span><span class='Function'>⍉</span><span class='Value'>𝕩</span><span class='Bracket'>⟩</span><span class='Brace'>}</span><span class='Number'>5</span><span class='Function'>↕</span><span class='String'>"abcdefg"</span> +<p>Let's look at the first example, paired with its <a href="transpose.html">Transpose</a> (<code><span class='Function'>⍉</span></code>).</p> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4ouI4p+c4o2JIDXihpUiYWJjZGVmZyI=">↗️</a><pre> <span class='Function'>⋈</span><span class='Modifier2'>⟜</span><span class='Function'>⍉</span> <span class='Number'>5</span><span class='Function'>↕</span><span class='String'>"abcdefg"</span> ┌─ · ┌─ ┌─ ╵"abcde ╵"abc @@ -65,31 +54,49 @@ ┘ ┘ </pre> -<p>Although the two arrays have different shapes, they are identical where they overlap.</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omh4peLKDPigL8z4oq44oaRKeKfnOKNiTXihpUiYWJjZGVmZyI=">↗️</a><pre> <span class='Function'>≡</span><span class='Modifier2'>○</span><span class='Paren'>(</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Modifier2'>⊸</span><span class='Function'>↑</span><span class='Paren'>)</span><span class='Modifier2'>⟜</span><span class='Function'>⍉</span><span class='Number'>5</span><span class='Function'>↕</span><span class='String'>"abcdefg"</span> +<p>Although the two arrays have different shapes, they're identical in the 3×3 region where they overlap.</p> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omh4peLKDPigL8z4oq44oaRKeKfnOKNiSA14oaVImFiY2RlZmci">↗️</a><pre> <span class='Function'>≡</span><span class='Modifier2'>○</span><span class='Paren'>(</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Modifier2'>⊸</span><span class='Function'>↑</span><span class='Paren'>)</span><span class='Modifier2'>⟜</span><span class='Function'>⍉</span> <span class='Number'>5</span><span class='Function'>↕</span><span class='String'>"abcdefg"</span> 1 </pre> -<p>In other words, the i'th element of slice j is the same as the j'th element of slice i: it is the <code><span class='Value'>i</span><span class='Function'>+</span><span class='Value'>j</span></code>'th element of the argument. So transposing still gives a possible result of Windows, but with a different slice length.</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=eyg14oaV8J2VqSniiaHijYkoM+KGlfCdlakpfSJhYmNkZWZnIg==">↗️</a><pre> <span class='Brace'>{</span><span class='Paren'>(</span><span class='Number'>5</span><span class='Function'>↕</span><span class='Value'>𝕩</span><span class='Paren'>)</span><span class='Function'>≡⍉</span><span class='Paren'>(</span><span class='Number'>3</span><span class='Function'>↕</span><span class='Value'>𝕩</span><span class='Paren'>)</span><span class='Brace'>}</span><span class='String'>"abcdefg"</span> +<p>More concretely, the <code><span class='Value'>i</span></code>th element of slice <code><span class='Value'>j</span></code> is the same as the <code><span class='Value'>j</span></code>th element of slice <code><span class='Value'>i</span></code>: it's the <code><span class='Value'>i</span><span class='Function'>+</span><span class='Value'>j</span></code>th element of the argument. So transposing still gives a possible result of Windows, but with a different slice length. The two lengths are related by <a href="logic.html">Span</a>, which converts between length and number of slices.</p> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=eyg14oaV8J2VqSniiaHijYkoM+KGlfCdlakpfSJhYmNkZWZnIgoKKOKJoCJhYmNkZWZnIikgwqwgMw==">↗️</a><pre> <span class='Brace'>{</span><span class='Paren'>(</span><span class='Number'>5</span><span class='Function'>↕</span><span class='Value'>𝕩</span><span class='Paren'>)</span><span class='Function'>≡⍉</span><span class='Paren'>(</span><span class='Number'>3</span><span class='Function'>↕</span><span class='Value'>𝕩</span><span class='Paren'>)</span><span class='Brace'>}</span><span class='String'>"abcdefg"</span> 1 + + <span class='Paren'>(</span><span class='Function'>≠</span><span class='String'>"abcdefg"</span><span class='Paren'>)</span> <span class='Function'>¬</span> <span class='Number'>3</span> +5 </pre> -<p>In general, we need a more complicated transpose—swapping the first set of <code><span class='Function'>≠</span><span class='Value'>𝕨</span></code> axes with the second set. Note again the use of <a href="logic.html">Span</a>, our slice-length to slice-number converter.</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=eygoNeKAvzbCrDLigL8yKeKGlfCdlakpIOKJoSAy4oC/M+KNiSgy4oC/MuKGlfCdlakpfSDihpU14oC/NuKAvzc=">↗️</a><pre> <span class='Brace'>{</span><span class='Paren'>((</span><span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Function'>¬</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Paren'>)</span><span class='Function'>↕</span><span class='Value'>𝕩</span><span class='Paren'>)</span> <span class='Function'>≡</span> <span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Function'>⍉</span><span class='Paren'>(</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Function'>↕</span><span class='Value'>𝕩</span><span class='Paren'>)</span><span class='Brace'>}</span> <span class='Function'>↕</span><span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Ligature'>‿</span><span class='Number'>7</span> -1 -</pre> -<h2 id="applications"><a class="header" href="#applications">Applications</a></h2> -<p>Windows can be followed up with a <a href="fold.html#insert">reduction</a> on each slice to give a windowed reduction. Here we take running sums of 3 values.</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=K8udy5gz4oaVIOKfqDIsNiwwLDEsNCwz4p+p">↗️</a><pre> <span class='Function'>+</span><span class='Modifier'>˝˘</span><span class='Number'>3</span><span class='Function'>↕</span> <span class='Bracket'>⟨</span><span class='Number'>2</span><span class='Separator'>,</span><span class='Number'>6</span><span class='Separator'>,</span><span class='Number'>0</span><span class='Separator'>,</span><span class='Number'>1</span><span class='Separator'>,</span><span class='Number'>4</span><span class='Separator'>,</span><span class='Number'>3</span><span class='Bracket'>⟩</span> -⟨ 8 7 5 8 ⟩ -</pre> -<p>A common task is to act on windows with an initial or final element so the total length stays the same. When using windows of length 2, the best way to accomplish this is with a <a href="shift.html">shift</a> <code><span class='Function'>«</span></code> or <code><span class='Function'>»</span></code>. If the window length is longer or variable, then a trick with Windows works better: add the elements, and then use windows matching the original length. Here we invert Plus <a href="scan.html">Scan</a> <code><span class='Function'>+</span><span class='Modifier'>`</span></code>, which requires we take pairwise differences starting at initial value 0.</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=LeKfnCgwwrviiqIpICtgIDPigL8y4oC/MeKAvzEKCigty5zLneKJoOKGlTDiiL7iiqIpICtgIDPigL8y4oC/MeKAvzE=">↗️</a><pre> <span class='Function'>-</span><span class='Modifier2'>⟜</span><span class='Paren'>(</span><span class='Number'>0</span><span class='Function'>»⊢</span><span class='Paren'>)</span> <span class='Function'>+</span><span class='Modifier'>`</span> <span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span> -⟨ 3 2 1 1 ⟩ +<h2 id="multiple-dimensions"><a class="header" href="#multiple-dimensions">Multiple dimensions</a></h2> +<p>The right argument can have rank more than 1, and it's viewed as a list of major cells following <a href="leading.html">leading axis</a> principles. As an example, Windows can take two-row slices of a shape <code><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>4</span></code> array.</p> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=ICAgIDLihpVbIjAxMjMiLCJhYmNkIiwiQUJDRCJdCgo84o6JMiAy4oaVWyIwMTIzIiwiYWJjZCIsIkFCQ0QiXQ==">↗️</a><pre> <span class='Number'>2</span><span class='Function'>↕</span><span class='Bracket'>[</span><span class='String'>"0123"</span><span class='Separator'>,</span><span class='String'>"abcd"</span><span class='Separator'>,</span><span class='String'>"ABCD"</span><span class='Bracket'>]</span> +┌─ +╎"0123 + abcd + + ·abcd + ABCD" + ┘ - <span class='Paren'>(</span><span class='Function'>-</span><span class='Modifier'>˜˝</span><span class='Function'>≠↕</span><span class='Number'>0</span><span class='Function'>∾⊢</span><span class='Paren'>)</span> <span class='Function'>+</span><span class='Modifier'>`</span> <span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span> -⟨ 3 2 1 1 ⟩ + <span class='Function'><</span><span class='Modifier2'>⎉</span><span class='Number'>2</span> <span class='Number'>2</span><span class='Function'>↕</span><span class='Bracket'>[</span><span class='String'>"0123"</span><span class='Separator'>,</span><span class='String'>"abcd"</span><span class='Separator'>,</span><span class='String'>"ABCD"</span><span class='Bracket'>]</span> +┌─ +· ┌─ ┌─ + ╵"0123 ╵"abcd + abcd" ABCD" + ┘ ┘ + ┘ </pre> -<p>With Windows, we can modify the 3-element running sum from before to keep the length constant by starting with two zeros.</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=KCvLneKJoOKGlSgy4qWKMCniirjiiL4pIOKfqDIsNiwwLDEsNCwz4p+p">↗️</a><pre> <span class='Paren'>(</span><span class='Function'>+</span><span class='Modifier'>˝</span><span class='Function'>≠↕</span><span class='Paren'>(</span><span class='Number'>2</span><span class='Function'>⥊</span><span class='Number'>0</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>∾</span><span class='Paren'>)</span> <span class='Bracket'>⟨</span><span class='Number'>2</span><span class='Separator'>,</span><span class='Number'>6</span><span class='Separator'>,</span><span class='Number'>0</span><span class='Separator'>,</span><span class='Number'>1</span><span class='Separator'>,</span><span class='Number'>4</span><span class='Separator'>,</span><span class='Number'>3</span><span class='Bracket'>⟩</span> -⟨ 2 8 8 7 5 8 ⟩ +<p>In the second version we've enclosed each slice with <code><span class='Function'><</span><span class='Modifier2'>⎉</span><span class='Number'>2</span></code> for viewing—a slice has rank 2, the same as <code><span class='Value'>𝕩</span></code>. Passing a list as the left argument to Windows takes slices along any number of leading axes. Here are all the shape <code><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>2</span></code> slices:</p> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=POKOiTIgMuKAvzLihpVbIjAxMjMiLCJhYmNkIiwiQUJDRCJd">↗️</a><pre> <span class='Function'><</span><span class='Modifier2'>⎉</span><span class='Number'>2</span> <span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Function'>↕</span><span class='Bracket'>[</span><span class='String'>"0123"</span><span class='Separator'>,</span><span class='String'>"abcd"</span><span class='Separator'>,</span><span class='String'>"ABCD"</span><span class='Bracket'>]</span> +┌─ +╵ ┌─ ┌─ ┌─ + ╵"01 ╵"12 ╵"23 + ab" bc" cd" + ┘ ┘ ┘ + ┌─ ┌─ ┌─ + ╵"ab ╵"bc ╵"cd + AB" BC" CD" + ┘ ┘ ┘ + ┘ </pre> +<p>The slices are naturally arranged along multiple dimensions according to their starting index. Once again the equivalence <code><span class='Value'>i</span><span class='Function'>⊏</span><span class='Value'>l</span><span class='Function'>↕</span><span class='Value'>x</span></code> ←→ <code><span class='Value'>l</span><span class='Function'>↑</span><span class='Value'>i</span><span class='Function'>↓</span><span class='Value'>x</span></code> holds, provided <code><span class='Value'>i</span></code> and <code><span class='Value'>l</span></code> have the same length.</p> +<p>If <code><span class='Value'>𝕨</span></code> has length <code><span class='Number'>0</span></code>, then <code><span class='Value'>𝕩</span></code> is not sliced along any dimensions. The only slice that results—the entire argument—is then arranged along an additional zero dimensions. In the end, the result is <code><span class='Value'>𝕩</span></code>, unchanged.</p> +<p>Here's a more formal definition: <code><span class='Value'>𝕩</span></code> is an array. <code><span class='Value'>𝕨</span></code> is a number, or numeric list or unit, with <code><span class='Value'>𝕨</span><span class='Function'>≤</span><span class='Modifier2'>○</span><span class='Function'>≠≢</span><span class='Value'>𝕩</span></code>. The result <code><span class='Value'>z</span></code> has shape <code><span class='Value'>𝕨</span><span class='Function'>∾¬</span><span class='Modifier2'>⟜</span><span class='Value'>𝕨</span><span class='Modifier2'>⌾</span><span class='Paren'>((</span><span class='Function'>≠</span><span class='Value'>𝕨</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>↑</span><span class='Paren'>)</span><span class='Function'>≢</span><span class='Value'>𝕩</span></code>, and element <code><span class='Value'>i</span><span class='Function'>⊑</span><span class='Value'>z</span></code> is <code><span class='Value'>i</span><span class='Function'>⊑</span><span class='Value'>z</span></code> ←→ <code><span class='Value'>𝕩</span><span class='Function'>⊑</span><span class='Modifier'>˜</span><span class='Function'>+</span><span class='Modifier'>´¨</span><span class='Paren'>(</span><span class='Value'>𝕨</span><span class='Function'>∾</span><span class='Modifier2'>○</span><span class='Paren'>(</span><span class='Function'>↕</span><span class='Modifier2'>∘</span><span class='Function'>≠</span><span class='Paren'>)</span><span class='Function'>≢</span><span class='Value'>𝕩</span><span class='Paren'>)</span><span class='Function'>⊔</span><span class='Value'>i</span></code>.</p> |
