diff options
| author | Marshall Lochbaum <mwlochbaum@gmail.com> | 2021-07-01 19:34:17 -0400 |
|---|---|---|
| committer | Marshall Lochbaum <mwlochbaum@gmail.com> | 2021-07-01 19:34:17 -0400 |
| commit | 7c24de80e86c8a7eba9ae3eb4adc64bb93977e33 (patch) | |
| tree | 1d6d4f141fbde9b4e7e97ff72b8cc1f221b3f8cd | |
| parent | 0e0bc9b334987e4b0fd17f62946af029688af146 (diff) | |
Finish Scan documentation
| -rw-r--r-- | doc/scan.md | 20 | ||||
| -rw-r--r-- | docs/doc/scan.html | 21 |
2 files changed, 33 insertions, 8 deletions
diff --git a/doc/scan.md b/doc/scan.md index ab4b6669..c4e3a3ad 100644 --- a/doc/scan.md +++ b/doc/scan.md @@ -50,7 +50,7 @@ BQN's Scan is ordered differently from Scan in APL. Both include one result for Scan also differs from Fold or Insert in that it never depends on `π½`'s identity element, because scanning over an empty array simply returns that array. -## Examples +## Lists The best-known use of Scan is the [prefix sum](https://en.wikipedia.org/wiki/Prefix_sum) of a list, in which each element of the result is the sum of that element and all the ones before it. With a [shift](shift.md) this can be modified to sum the previous elements only. @@ -92,7 +92,7 @@ A more complicated boolean scan, which depends on the left-to-right ordering, is {Β¬<`'\'=π©}βΈ/ "ab\\\rs\\\\" -### Reverse scan +## Reverse scan We've discussed how the scan moves forward along `π©`, so that each time `π½` takes an old result as `π¨` and a new value as `π©`. This means that results correspond to prefixes and go left to right on each one. Since the most important scans have associative, commutative operands, the left-to-right ordering often doesn't make a difference. But sometimes a suffix rather than prefix scan is wanted. For these cases, Scan Under [Reverse](reverse.md) (`` `βΎβ½ ``) does the trick. @@ -109,10 +109,22 @@ The new value is still the right argument to `π½`, even though with the revers {"("βΎπ¨βΎ")π½"βΎπ©}Λ`βΎβ½ "a"βΏ"b"βΏ"c"βΏ"d" -### Higher ranks +## Higher ranks -Scan moves along the [leading axis](leading.md) of `π©`. Results are produced in index order. +Scan moves along the [leading axis](leading.md) of `π©`: vertically, for a table. To apply a scan to later axes, use `Λ` or `β`. Since a scan returns an array with the same shape as its argument, this can't cause an error from differing result cell shapes, unlike Fold or Insert. β’ a β Β―2βΏ0.25βΏ'a'βΏβ βΎ 3βΏ4β₯Β―1βΏ0βΏ1 +` a + +If `π¨` is given, it must have the same shape as a major cell of `π©` (this is why `π¨` needs to be enclosed when `π©` is a list: in general it's an array). Then the first result cell is found by applying `π½` to elements of `π¨` and `βπ©`, and the computation continues as in the one-argument case for remaining cells. + + 3βΏ2βΏ1βΏ0 +` a + +Results are produced in index order. This means that instead of moving along each column in turn, a scan produces the first result cell one element at a time, then the next, and so on. Something like a breadth-first as opposed to depth-first ordering. + +## Definition + +Scan admits a simple recursive definition. `π©` is an array of rank one or more and `π¨`, if given, is an atom or array with shape `1ββ’π©`. The result ``zβπ¨π½`π©`` is an array with the same shape as `π©`. If it has length at least one, `βz` is `βπ©` if `π¨` isn't given and `π¨π½Β¨βπ©` if it is. For `0β€i`, `(i+1)βz` is `(iβz)π½Β¨(i+1)βπ©`. + +The ordering of `π½` application is the natural one for this definition: cells are computed in turn, and each instance of `π½Β¨` goes in index order. diff --git a/docs/doc/scan.html b/docs/doc/scan.html index 64deae85..1f572239 100644 --- a/docs/doc/scan.html +++ b/docs/doc/scan.html @@ -61,7 +61,7 @@ <p>The 1-modifier Scan (<code><span class='Modifier'>`</span></code>) moves along the first axis of the array <code><span class='Value'>π©</span></code>, building up an array of results by applying <code><span class='Function'>π½</span></code> repeatedly beginning with <code><span class='Value'>π¨</span></code> or <code><span class='Function'>β</span><span class='Value'>π©</span></code>. It's related to the fold modifiers, and most closely resembles the <a href="fold.html#apl2-reduction">APL2-style reduction</a> <code><span class='Modifier'>Β¨Λ</span></code>, but it traverses the array in forward rather than reverse index order, and includes all intermediate results of <code><span class='Function'>π½</span></code> in its output instead of just the final one.</p> <p>BQN's Scan is ordered differently from Scan in APL. Both include one result for each non-empty prefix of <code><span class='Value'>π©</span></code>. In BQN this is a left-to-right fold, so that each new result requires one application of <code><span class='Function'>π½</span></code>. APL uses a right-to-left ordering, which matches with reduction, but requires starting over at the end for each new prefix, except in special cases. If needed, this definition can be obtained with a fold on each <a href="prefixes.html">prefix</a> except the first (which is empty). In the particular case of <code><span class='Function'>-</span><span class='Value'>β</span></code>, that nested solution isn't needed: negate odd-indexed elements and then apply <code><span class='Function'>+</span><span class='Modifier'>`</span></code>.</p> <p>Scan also differs from Fold or Insert in that it never depends on <code><span class='Function'>π½</span></code>'s identity element, because scanning over an empty array simply returns that array.</p> -<h2 id="examples">Examples</h2> +<h2 id="lists">Lists</h2> <p>The best-known use of Scan is the <a href="https://en.wikipedia.org/wiki/Prefix_sum">prefix sum</a> of a list, in which each element of the result is the sum of that element and all the ones before it. With a <a href="shift.html">shift</a> this can be modified to sum the previous elements only.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=K2AgMuKAvzTigL8z4oC/MQoKK2DCuzLigL804oC/M+KAvzEgICMgRXhjbHVzaXZlIHByZWZpeCBzdW0=">βοΈ</a><pre> <span class='Function'>+</span><span class='Modifier'>`</span> <span class='Number'>2</span><span class='Ligature'>βΏ</span><span class='Number'>4</span><span class='Ligature'>βΏ</span><span class='Number'>3</span><span class='Ligature'>βΏ</span><span class='Number'>1</span> β¨ 2 6 9 10 β© @@ -108,7 +108,7 @@ <span class='Brace'>{</span><span class='Function'>Β¬<</span><span class='Modifier'>`</span><span class='String'>'\'</span><span class='Function'>=</span><span class='Value'>π©</span><span class='Brace'>}</span><span class='Modifier2'>βΈ</span><span class='Function'>/</span> <span class='String'>"ab\\\rs\\\\"</span> "ab\rs\\" </pre> -<h3 id="reverse-scan">Reverse scan</h3> +<h2 id="reverse-scan">Reverse scan</h2> <p>We've discussed how the scan moves forward along <code><span class='Value'>π©</span></code>, so that each time <code><span class='Function'>π½</span></code> takes an old result as <code><span class='Value'>π¨</span></code> and a new value as <code><span class='Value'>π©</span></code>. This means that results correspond to prefixes and go left to right on each one. Since the most important scans have associative, commutative operands, the left-to-right ordering often doesn't make a difference. But sometimes a suffix rather than prefix scan is wanted. For these cases, Scan Under <a href="reverse.html">Reverse</a> (<code><span class='Modifier'>`</span><span class='Modifier2'>βΎ</span><span class='Function'>β½</span></code>) does the trick.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oioYCAgIDDigL8w4oC/MeKAvzDigL8w4oC/MeKAvzAKCuKIqGDijL7ijL0gMOKAvzDigL8x4oC/MOKAvzDigL8x4oC/MA==">βοΈ</a><pre> <span class='Function'>β¨</span><span class='Modifier'>`</span> <span class='Number'>0</span><span class='Ligature'>βΏ</span><span class='Number'>0</span><span class='Ligature'>βΏ</span><span class='Number'>1</span><span class='Ligature'>βΏ</span><span class='Number'>0</span><span class='Ligature'>βΏ</span><span class='Number'>0</span><span class='Ligature'>βΏ</span><span class='Number'>1</span><span class='Ligature'>βΏ</span><span class='Number'>0</span> β¨ 0 0 1 1 1 1 1 β© @@ -124,8 +124,8 @@ <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=eyIoIuKIvvCdlajiiL4iKfCdlL0i4oi+8J2VqX3LnGDijL7ijL0gImEi4oC/ImIi4oC/ImMi4oC/ImQi">βοΈ</a><pre> <span class='Brace'>{</span><span class='String'>"("</span><span class='Function'>βΎ</span><span class='Value'>π¨</span><span class='Function'>βΎ</span><span class='String'>")π½"</span><span class='Function'>βΎ</span><span class='Value'>π©</span><span class='Brace'>}</span><span class='Modifier'>Λ`</span><span class='Modifier2'>βΎ</span><span class='Function'>β½</span> <span class='String'>"a"</span><span class='Ligature'>βΏ</span><span class='String'>"b"</span><span class='Ligature'>βΏ</span><span class='String'>"c"</span><span class='Ligature'>βΏ</span><span class='String'>"d"</span> β¨ "(a)π½(b)π½(c)π½d" "(b)π½(c)π½d" "(c)π½d" "d" β© </pre> -<h3 id="higher-ranks">Higher ranks</h3> -<p>Scan moves along the <a href="leading.html">leading axis</a> of <code><span class='Value'>π©</span></code>. Results are produced in index order.</p> +<h2 id="higher-ranks">Higher ranks</h2> +<p>Scan moves along the <a href="leading.html">leading axis</a> of <code><span class='Value'>π©</span></code>: vertically, for a table. To apply a scan to later axes, use <code><span class='Modifier'>Λ</span></code> or <code><span class='Modifier2'>β</span></code>. Since a scan returns an array with the same shape as its argument, this can't cause an error from differing result cell shapes, unlike Fold or Insert.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqiIGEg4oaQIMKvMuKAvzAuMjXigL8nYSfigL/iiJ4g4oi+IDPigL804qWKwq8x4oC/MOKAvzEKCitgIGE=">βοΈ</a><pre> <span class='Function'>β’</span> <span class='Value'>a</span> <span class='Gets'>β</span> <span class='Number'>Β―2</span><span class='Ligature'>βΏ</span><span class='Number'>0.25</span><span class='Ligature'>βΏ</span><span class='String'>'a'</span><span class='Ligature'>βΏ</span><span class='Number'>β</span> <span class='Function'>βΎ</span> <span class='Number'>3</span><span class='Ligature'>βΏ</span><span class='Number'>4</span><span class='Function'>β₯</span><span class='Number'>Β―1</span><span class='Ligature'>βΏ</span><span class='Number'>0</span><span class='Ligature'>βΏ</span><span class='Number'>1</span> ββ β΅ Β―2 0.25 'a' β @@ -142,3 +142,16 @@ Β―2 0.25 'a' β β </pre> +<p>If <code><span class='Value'>π¨</span></code> is given, it must have the same shape as a major cell of <code><span class='Value'>π©</span></code> (this is why <code><span class='Value'>π¨</span></code> needs to be enclosed when <code><span class='Value'>π©</span></code> is a list: in general it's an array). Then the first result cell is found by applying <code><span class='Function'>π½</span></code> to elements of <code><span class='Value'>π¨</span></code> and <code><span class='Function'>β</span><span class='Value'>π©</span></code>, and the computation continues as in the one-argument case for remaining cells.</p> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=M+KAvzLigL8x4oC/MCArYCBh">βοΈ</a><pre> <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'>0</span> <span class='Function'>+</span><span class='Modifier'>`</span> <span class='Value'>a</span> +ββ +β΅ 1 2.25 'b' β + 0 2.25 'c' β + 0 3.25 'b' β + 1 2.25 'b' β + β +</pre> +<p>Results are produced in index order. This means that instead of moving along each column in turn, a scan produces the first result cell one element at a time, then the next, and so on. Something like a breadth-first as opposed to depth-first ordering.</p> +<h2 id="definition">Definition</h2> +<p>Scan admits a simple recursive definition. <code><span class='Value'>π©</span></code> is an array of rank one or more and <code><span class='Value'>π¨</span></code>, if given, is an atom or array with shape <code><span class='Number'>1</span><span class='Function'>ββ’</span><span class='Value'>π©</span></code>. The result <code><span class='Value'>z</span><span class='Gets'>β</span><span class='Value'>π¨</span><span class='Function'>π½</span><span class='Modifier'>`</span><span class='Value'>π©</span></code> is an array with the same shape as <code><span class='Value'>π©</span></code>. If it has length at least one, <code><span class='Function'>β</span><span class='Value'>z</span></code> is <code><span class='Function'>β</span><span class='Value'>π©</span></code> if <code><span class='Value'>π¨</span></code> isn't given and <code><span class='Value'>π¨</span><span class='Function'>π½</span><span class='Modifier'>Β¨</span><span class='Function'>β</span><span class='Value'>π©</span></code> if it is. For <code><span class='Number'>0</span><span class='Function'>β€</span><span class='Value'>i</span></code>, <code><span class='Paren'>(</span><span class='Value'>i</span><span class='Function'>+</span><span class='Number'>1</span><span class='Paren'>)</span><span class='Function'>β</span><span class='Value'>z</span></code> is <code><span class='Paren'>(</span><span class='Value'>i</span><span class='Function'>β</span><span class='Value'>z</span><span class='Paren'>)</span><span class='Function'>π½</span><span class='Modifier'>Β¨</span><span class='Paren'>(</span><span class='Value'>i</span><span class='Function'>+</span><span class='Number'>1</span><span class='Paren'>)</span><span class='Function'>β</span><span class='Value'>π©</span></code>.</p> +<p>The ordering of <code><span class='Function'>π½</span></code> application is the natural one for this definition: cells are computed in turn, and each instance of <code><span class='Function'>π½</span><span class='Modifier'>Β¨</span></code> goes in index order.</p> |
