diff options
| author | Marshall Lochbaum <mwlochbaum@gmail.com> | 2021-07-16 18:23:52 -0400 |
|---|---|---|
| committer | Marshall Lochbaum <mwlochbaum@gmail.com> | 2021-07-16 18:24:01 -0400 |
| commit | 2010e8b2897a5741e211980c9f8ec9177299c939 (patch) | |
| tree | 4b3476744be928724da2fd5d83b0bf2e9a8ba502 | |
| parent | e3366f9e18a8791c43110e080b9ea45cfceefed8 (diff) | |
Finish links and editing documentation pass
| -rw-r--r-- | doc/reverse.md | 10 | ||||
| -rw-r--r-- | doc/scan.md | 10 | ||||
| -rw-r--r-- | doc/select.md | 12 | ||||
| -rw-r--r-- | doc/selfcmp.md | 12 | ||||
| -rw-r--r-- | doc/shape.md | 6 | ||||
| -rw-r--r-- | doc/shift.md | 24 | ||||
| -rw-r--r-- | doc/train.md | 14 | ||||
| -rw-r--r-- | doc/transpose.md | 27 | ||||
| -rw-r--r-- | doc/types.md | 10 | ||||
| -rw-r--r-- | doc/windows.md | 19 | ||||
| -rw-r--r-- | docs/doc/reverse.html | 10 | ||||
| -rw-r--r-- | docs/doc/scan.html | 10 | ||||
| -rw-r--r-- | docs/doc/select.html | 11 | ||||
| -rw-r--r-- | docs/doc/selfcmp.html | 12 | ||||
| -rw-r--r-- | docs/doc/shape.html | 6 | ||||
| -rw-r--r-- | docs/doc/shift.html | 34 | ||||
| -rw-r--r-- | docs/doc/train.html | 14 | ||||
| -rw-r--r-- | docs/doc/transpose.html | 33 | ||||
| -rw-r--r-- | docs/doc/types.html | 10 | ||||
| -rw-r--r-- | docs/doc/windows.html | 21 |
20 files changed, 164 insertions, 141 deletions
diff --git a/doc/reverse.md b/doc/reverse.md index 0ee7766d..e1e85d46 100644 --- a/doc/reverse.md +++ b/doc/reverse.md @@ -2,7 +2,7 @@ # Reverse and Rotate -The symbol `⌽` indicates two different array transformations: with no left argument, it reverses the major cells of the array, but with a left argument, it rotates or cycles them around. These two possibilities, first put together in very early versions of APL, can't be considered restrictions or different views of some unifying function, but there are connections between them. Each returns an array with the same shape and all the same elements as `ð•©`, possibly in a different arrangement. And elements that start out next to each other in `ð•©` generally stay next to each other—always, if we consider an element on one edge to be next to the one opposite to it. One might think of them as [isometries](https://en.wikipedia.org/wiki/Isometry) preserving a discrete subgroup of the torus, if one were inclined to think such things. On major cells, the two functions decompose the [dihedral group](https://en.wikipedia.org/wiki/Dihedral_group) okay I'll stop. +The symbol `⌽` indicates two different array transformations: with no left argument, it reverses the major cells of the array, but with a left argument, it rotates or cycles them around. These two possibilities, first put together in very early versions of APL, can't be considered restrictions or different views of some unifying function, but there are connections between them. Each returns an array with the same [shape](shape.md) and all the same elements as `ð•©`, possibly in a different arrangement. And elements that start out next to each other in `ð•©` generally stay next to each other—always, if we consider an element on one edge to be next to the one opposite to it. One might think of them as [isometries](https://en.wikipedia.org/wiki/Isometry) preserving a discrete subgroup of the torus, if one were inclined to think such things. On major cells, the two functions decompose the [dihedral group](https://en.wikipedia.org/wiki/Dihedral_group) okay I'll stop. Many uses of Rotate in APL are better handled by [shift](shift.md) functions in BQN. If there's no reason to treat the data as cyclic or periodic, it's best to avoid Rotate. @@ -36,7 +36,7 @@ Reverse is its own inverse `⌽â¼`. As a result, `ð”½âŒ¾âŒ½` reverses the argu ## Rotate -Rotate moves elements in a list around cyclically. It can also rotate any number of axes of the argument array by different amounts at once. That's discussed in the next section; for now we'll stick to a single number in the left argument. It has to be an integer, and the right argument has to be an array with at least one axis. +Rotate moves elements in a list around cyclically. It can also rotate any number of axes of the argument array by different amounts at once. That's discussed in the next section; for now we'll stick to a single number for `ð•¨`. It has to be an integer, and `ð•©` has to be an array with at least one axis. 2 ⌽ "rotate" @@ -44,13 +44,13 @@ Rotate moves elements in a list around cyclically. It can also rotate any number 2 ⌽ 'c' # No axes to rotate -Elements are always rotated to the left, so that entry `i` of the result is entry `ð•¨+i` of the argument—or rather, entry `(≠ð•©)|ð•¨+i` to enable elements to cycle around. This can be seen directly by using `↕n` as an argument: in this case, the value of `ð•©` at index `i` is just `i`. +Elements are always rotated to the left, so that entry `i` of the result is entry `ð•¨+i` of the argument—or rather, entry `(≠ð•©)|ð•¨+i` to enable elements to cycle around. This can be seen directly by using the [range](range.md) `↕n` as an argument: then the value of `ð•©` at index `i` is just `i`. 2 ⌽ ↕6 -The rotation `(≠ð•©)⌽ð•©` moves each element the entire length of `ð•©`, which just places it back where it started. In fact, adding `≠ð•©` to the rotation amount never changes the behavior or the rotation. In terms of indices, this is because `(≠ð•©)|(≠ð•©)+a` is `a`. +The rotation `(≠ð•©)⌽ð•©` moves each element the entire [length](shape.md) of `ð•©`, which just places it back where it started. In fact, adding `≠ð•©` to the rotation amount never changes the behavior or the rotation. In terms of indices, this is because `(≠ð•©)|(≠ð•©)+a` is `a`. -To rotate the other way, use a negative left argument (so `-⊸⌽` is a simple way to write "reverse rotate"). This will always be the same as a leftwards rotation, since `(-r)⌽ð•©` is `((≠ð•©)-r)⌽ð•©`, but could be more convenient. +To rotate the other way, use a negative left argument (so `-⊸⌽` is a simple way to write "reverse rotate"). This will always be the same as some leftwards rotation, since `(-r)⌽ð•©` is `((≠ð•©)-r)⌽ð•©`, but could be more convenient. ¯2 ⌽ "rotate" diff --git a/doc/scan.md b/doc/scan.md index c4e3a3ad..85758875 100644 --- a/doc/scan.md +++ b/doc/scan.md @@ -46,9 +46,9 @@ dim ↠⟨2.5+≠tx,0.75+1⊑ty⟩ â‹„ sh ↠¯2.3‿0 The 1-modifier Scan (`` ` ``) moves along the first axis of the array `ð•©`, building up an array of results by applying `ð”½` repeatedly beginning with `ð•¨` or `âŠð•©`. It's related to the fold modifiers, and most closely resembles the [APL2-style reduction](fold.md#apl2-reduction) `¨Ë`, but it traverses the array in forward rather than reverse index order, and includes all intermediate results of `ð”½` in its output instead of just the final one. -BQN's Scan is ordered differently from Scan in APL. Both include one result for each non-empty prefix of `ð•©`. In BQN this is a left-to-right fold, so that each new result requires one application of `ð”½`. 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 [prefix](prefixes.md) except the first (which is empty). In the particular case of `-â€`, that nested solution isn't needed: negate odd-indexed elements and then apply `` +` ``. +BQN's Scan is ordered differently from Scan in APL. Both include one result for each non-empty prefix of `ð•©`. In BQN this is a left-to-right fold, so that each new result requires one application of `ð”½`. APL uses right-to-left folds, 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 [prefix](prefixes.md) except the first (which is empty). In the particular case of `-â€`, that nested solution isn't needed: negate odd-indexed elements and then apply `` +` ``. -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. +Scan also differs from Fold or Insert in that it never depends on `ð”½`'s [identity value](fold.md#identity-values), because scanning over an empty array simply returns that array. ## Lists @@ -58,7 +58,7 @@ The best-known use of Scan is the [prefix sum](https://en.wikipedia.org/wiki/Pre +`»2‿4‿3‿1 # Exclusive prefix sum -The pattern is generalized to any function `ð”½`. With an operand of `×`, it can find the first *n* factorials. With `⌈`, it returns the largest element so far. +The pattern is generalized to any function `ð”½`. With an operand of `×`, it can find the first *n* factorials. With [Maximum](arithmetic.md#additional-arithmetic) (`⌈`), it returns the largest element so far. ×` 1+↕6 @@ -80,7 +80,7 @@ The left argument in each result element is always the previous element, if ther {c+↩1â‹„ð•¨+ð•©}` ↕10 c -Some other useful scans apply to boolean lists. The function `` ∨` `` tests whether this or any previous element is 1, so that the result starts at 0 but permanently switches to 1 as soon as the first 1 is found. Similarly, `` ∧` `` turns all instances of 1 after the first 0 to 0. +Some other useful scans apply to boolean lists. The function `` ∨` `` (with [Or](logic.md)) tests whether this or any previous element is 1, so that the result starts at 0 but permanently switches to 1 as soon as the first 1 is found. Similarly, `` ∧` `` turns all instances of 1 after the first 0 to 0. ∨` 0‿0‿1‿0‿0‿1‿0‿1 @@ -94,7 +94,7 @@ A more complicated boolean scan, which depends on the left-to-right ordering, is ## 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. +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](prefixes.md) 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. ∨` 0‿0‿1‿0‿0‿1‿0 diff --git a/doc/select.md b/doc/select.md index c9da2304..c9ed2765 100644 --- a/doc/select.md +++ b/doc/select.md @@ -32,7 +32,7 @@ tp ↠(1‿2/tx‿tw) â‰Â¨Â¨ y ⟩ --> -The function Select (`âŠ`) reorganizes the array `ð•©` along one or more axes based on [indices](indices.md) given by `ð•¨`. The result has the same [depth](depth.md) as `ð•©`, since its elements are always elements of `ð•©`. This means it differs from Pick (`⊑`), which takes elements from `ð•©` but can arrange them in any nested structure, including returning an element directly. +The function Select (`âŠ`) reorganizes the array `ð•©` along one or more axes based on [indices](indices.md) given by `ð•¨`. The result has the same [depth](depth.md) as `ð•©`, since its elements are always elements of `ð•©`. This means it differs from [Pick](pick.md) (`⊑`), which takes elements from `ð•©` but can arrange them in any nested structure, including returning an element directly. The monadic form First Cell (`âŠ`) gets the major cell with index 0, so that `âŠð•©` is identical to `0âŠð•©`. @@ -80,7 +80,9 @@ To find the first and last cells of `ð•©`, use `0‿¯1` for the left argument. 0‿¯1 ⊠m -More generally, `ð•¨` can be an array of any rank. Each of its 0-cells—containing a single number—is replaced with a cell of `ð•©` in the result. The result's shape is then made up of the shape of `ð•¨` and the major cell shape of `ð•©`: it's `(≢ð•¨)∾1↓≢ð•©`. When `ð•©` is a list, the result has the same shape as `ð•¨`. Elements of `ð•¨` are replaced one-for-one with elements of `ð•©`. +More generally, `ð•¨` can be an array of any rank. Each of its 0-cells—containing a single number—is replaced with a cell of `ð•©` in the result. The result's shape is then made up of the shape of `ð•¨` and the major cell shape of `ð•©`: it's `(≢ð•¨)∾1↓≢ð•©`. + +When `ð•©` is a list, the result has the same shape as `ð•¨`. Elements of `ð•¨` are replaced one-for-one with elements of `ð•©`. 2|m @@ -102,9 +104,9 @@ Select also allows `ð•¨` to apply to multiple axes of `ð•©` simultaneously. Fo ⟨2‿1, 3‿0‿0⟩ ⊠↕3‿4 -Using a [range](range.md) for `ð•©` shows the structure of the selected elements more clearly, because each element is its own index. Each element of `ð•¨` acts independently, giving a structure like the Table modifier. +Using a [range](range.md) for `ð•©` shows the structure of the selected elements more clearly, because each element is its own index. Each element of `ð•¨` acts independently, giving a structure like the [Table](map.md#table) modifier. -While `ð•¨` must have rank one or less, its elements can have any rank. When the elements are units, the corresponding axis of `ð•©` disappears from the result. We can select a 0-cell of `ð•©` in this way, although the more common case or selecting an element is handled by Pick. +While `ð•¨` must have rank one or less, its elements can have any rank. When the elements are units, the corresponding axis of `ð•©` disappears from the result. We can select a 0-cell of `ð•©` in this way, although the more common case of selecting an element is handled by [Pick](pick.md). ⟨<4,<5,<1⟩ ⊠(3⥊10)⥊↕1e3 ⟨ 4, 5, 1⟩ ⊑ (3⥊10)⥊↕1e3 @@ -115,4 +117,4 @@ However, the `<¨⊸âŠ` construct can select a cell of any rank from `ð•©`, be If an element of `ð•¨` has rank more than 1, it increases the rank of `ð•©` rather than decreasing it. The general rule is that in the result, one axis of `ð•©` is replaced by all the axes of the corresponding element of `ð•¨` (trailing axes are unchanged). So the final shape `≢ð•¨âŠð•©` is `(∾≢¨ð•¨)∾ð•¨â‰ ⊸↓≢ð•©`. But this shape doesn't affect the elements retrieved from `ð•©`. In all cases, using `⥊¨ð•¨` for the left argument and then [reshaping](reshape.md) the result would yield the same value. -Selection only ever applies to leading axes of `ð•©`. But you can skip some leading axes using `˘` or `⎉`, to select on any contiguous set of axes. In particular, use the one-axis case `ð•¨âЏâŠâމ(-k) ð•©` to select along axis `k` of `ð•©`. +Selection only ever applies to leading axes of `ð•©`. However, you can skip some leading axes using `˘` or `⎉`, to select on any contiguous set of axes. In particular, use the one-axis case `ð•¨âЏâŠâމ(-k) ð•©` to select along axis `k` of `ð•©`. diff --git a/doc/selfcmp.md b/doc/selfcmp.md index e4f1616c..e4330dd9 100644 --- a/doc/selfcmp.md +++ b/doc/selfcmp.md @@ -75,7 +75,7 @@ Classify is also related to [Deduplicate](#deduplicate). In a way they are compl ⷠ⊠c ⊠ⷠc -Applying both separately, in contrast, gives completely interesting results. These results contain all information from the original argument, as `â·` indicates which cells it contained and `âŠ` indicates where they were located. The function Select (`âŠ`) reconstructs the argument from the two values. +Applying both separately, in contrast, gives completely interesting results. These results contain all information from the original argument, as `â·` indicates which cells it contained and `âŠ` indicates where they were located. The function [Select](select.md) (`âŠ`) reconstructs the argument from the two values. â· c ⊠c @@ -89,15 +89,15 @@ Applying both Classify and Deduplicate gives an array that has both properties ( *See the [APL Wiki page](https://aplwiki.com/wiki/Unique_Mask) on this function as well.* -Mark Firsts (`∊`) is the simplest self-search function: it returns `0` for any major cell of the argument that is a duplicate of an earlier cell and `1` for a major cell that's the first with its value. To implement [Deduplicate](#deduplicate) in terms of Mark Firsts, just filter out the duplicates with `∊⊸/`. +Mark Firsts (`∊`) is the simplest self-search function: it returns `0` for any major cell of the argument that is a duplicate of an earlier cell and `1` for a major cell that's the first with its value. To implement [Deduplicate](#deduplicate) in terms of Mark Firsts, just [filter](replicate.md) out the duplicates with `∊⊸/`. ∊ 3‿1‿4‿1‿5‿9‿2‿6‿5 ∊⊸/ 3‿1‿4‿1‿5‿9‿2‿6‿5 -Mark Firsts has other uses, of course. Instead of keeping the unique values, you might remove the first of each value with `¬∘∊⊸/`. You can use `∧´∊` to check that an array has no duplicate major cells, or `+´∘∊` to count the number of unique ones. +Mark Firsts has other uses, of course. Instead of keeping the unique values, you might remove the first of each value with `¬∘∊⊸/`. You can use `∧´∊` to check that an array has no duplicate major cells, or `+´∊` to count the number of unique ones. -What about marking the elements that appear exactly once? There's a trick for this: find the cells that are firsts running both forwards (`∊`) and backwards (`∊⌾⌽`). Such a cell has no equal before it, nor after it, so it's unique in the entire array. +What about marking the elements that appear exactly once? There's a trick for this: find the cells that are firsts running both forwards (`∊`) and [backwards](reverse.md) (`∊⌾⌽`). Such a cell has no equal before it, nor after it, so it's unique in the entire array. (∊∧∊⌾⌽) "duck"‿"duck"‿"teal"‿"duck"‿"goose" @@ -121,11 +121,11 @@ One easy example with Occurrence count is to take a list that has duplicates and (1=⊒)⊸/ "aaaabcddcc" -An interesting combination is Occurrence Count applied to the result of Indices (`/`). The result counts up to each number from the argument in turn; in other symbols, it's `∾↕¨`. This version is interesting because it doesn't create any nested arrays, just lists of natural numbers. +An interesting combination is Occurrence Count applied to the result of [Indices](replicate.md#indices) (`/`). The result counts up to each number from the argument in turn; in other symbols, it's `∾↕¨`. This version is interesting because it doesn't create any nested arrays, just lists of natural numbers. ⊒ / 2‿3‿4 -A more efficient way when the interpreter doesn't optimize `⊒` here is `` /(¯1⊸⊑↕⊸-âŠâŸœÂ»)+` ``, but that's clearly quite a bit more complicated. +A more efficient way when `⊒` doesn't have a fast implementation is `` /(¯1⊸⊑↕⊸-âŠâŸœÂ»)+` ``, but that's clearly quite a bit more complicated. ### Deduplicate diff --git a/doc/shape.md b/doc/shape.md index 1cb98d46..4c45280f 100644 --- a/doc/shape.md +++ b/doc/shape.md @@ -8,7 +8,7 @@ Rank can be defined as `≠∘≢` while Length can be defined with a [fold](fol ## Examples -The function [Reshape](reshape.md) (`⥊`) always returns an array of shape `ð•¨`, so we use it to make an array of shape `1‿3‿2‿6` in the example below ([Take](take.md) (`↑`) shares this property). +The function [Reshape](reshape.md) (`⥊`) always returns an array of shape `ð•¨`, so we use it to make an array of shape `1‿3‿2‿6` in the example below ([Take](take.md) (`↑`) shares this property if `(≠ð•¨)≤=ð•©`). ⊢ arr ↠1‿3‿2‿6 ⥊ '0'+↕10 @@ -18,11 +18,11 @@ The function [Reshape](reshape.md) (`⥊`) always returns an array of shape `ð• = arr # Rank -The length is the first element of the shape, and the rank is the length of the shape—the number of axes. For another example, taking the first (and only) cell of `arr` gives an array with shape `3‿2‿6`, length `3`, and rank `3`, as we can see by applying each function to `âŠarr`. +The length is the first element of the shape, and the rank is the length of the shape—the number of axes. For another example, taking the first (and only) cell of `arr` gives an array with shape `3‿2‿6`, length `3`, and rank `3`, as we can see by applying [each](map.md#each) function to `âŠarr`. ≢‿=‿≠{ð•Žð•©}¨< âŠarr -Applying Shape and the other two functions to an atom shows a shape of `⟨⟩`, the empty list, and a rank of zero and length of 1. The same is true of an enclosed array, which like an atom is a kind of unit. +Applying Shape and the other two functions to an atom shows a shape of `⟨⟩` (the empty list), and a rank of zero and length of 1. The same is true of an enclosed array, which like an atom is a kind of unit. ≢ 5 diff --git a/doc/shift.md b/doc/shift.md index 13c388cc..d20d4eff 100644 --- a/doc/shift.md +++ b/doc/shift.md @@ -2,9 +2,9 @@ # Shift functions -The shift functions `«` and `»` are two new primitives added to BQN based on a pattern used heavily in the compiler and a reasonable amount everywhere else. Shifts resemble but are more general than the bit-based shift operations used in low-level languages. They replace the APL pattern of a 2-wise reduction after appending or prepending an element (APL's `2≠/0,v` translates to `»⊸≠v`), one of the more common uses of 2-wise reduction. +The shift functions `«` and `»` add major cells to one side an array, displacing cells on the opposite side and moving those in between. Shifts resemble but are more general than the bit-based shift operations used in low-level languages. They replace the APL pattern of a 2-wise reduction after appending or prepending an element (APL's `2≠/0,v` translates to `»⊸≠v`), one of the more common uses of 2-wise reduction. -The result of a shift function always has the same shape as its right argument. The function adds major cells to the beginning (`»`) or end (`«`) of `ð•©`, moving the cells already in `ð•©` to accomodate them. Some cells on the opposite side from those added will "fall off" and not be included in the result. +The result of a shift function always has the same shape as `ð•©`. The function adds major cells to the beginning (`»`) or end (`«`) of `ð•©`, moving the cells already in `ð•©` to accomodate them. Some cells on the opposite side from those added will "fall off" and not be included in the result. 0‿0 » 3‿2‿1 # Shift Before "end" « "add to the " # Shift After @@ -18,7 +18,7 @@ If `ð•¨` is longer than `ð•©`, some cells from `ð•¨` will be discarded, as we ## Sequence processing with shifts -When working with a sequence of data such as text, daily measurements, or audio data, shift functions are generally the best way to handle the concept of "next" or "previous" in the data. In the following example `s` is shown alongside the shifted-right data `»s`, and each element is compared to the previous with `-⟜»`, which we see is the inverse of `` +` ``. +When working with a sequence of data such as text, daily measurements, or audio data, shift functions are generally the best way to handle the concept of "next" or "previous". In the following example `s` is shown alongside the shifted-right data `»s`, and each element is compared to the previous with `-⟜»`, which we see is the inverse of Plus [Scan](scan.md) `` +` ``. s ↠1‿2‿2‿4‿3‿5‿6 s ≠»s @@ -29,6 +29,7 @@ When working with a sequence of data such as text, daily measurements, or audio In this way `»` refers to a sequence containing the previous element at each position. By default the array's fill is used for the element before the first, and a right argument can be given to provide a different one. ∞ » s + âŠâŠ¸Â» s It may appear backwards that `»`, which typically means "go to the next item", is used to represent the previous item. In fact there is no conflict: the symbol `»` describes what position each cell of `ð•©` will have in the result, but in this context we are interested in knowing what argument value occurs in a particular result position. By moving all numbers into the future we ensure that a number in the present comes from the past. To keep your intuition functioning in these situations, it may help to think of the arrow point as fixed at some position in the result while the tail stretches back to land on the argument position where it comes from. @@ -64,15 +65,17 @@ With a number in big-endian format, a right shift might be logical, shifting in ## Other examples -In Take (`↑`), there's no way to specify the fill element when the result is longer than the argument. To take along the first axis with a specified, constant fill value, you can use Shift Before instead, where the right argument is an array of fills with the desired final shape. +In [Take](take.md) (`↑`), there's no way to specify the fill element when the result is longer than the argument. To take along the first axis with a specified, constant fill value, you can use Shift Before instead, where the right argument is an array of fills with the desired final shape. "abc" » 5⥊'F' -When using Scan (`` ` ``), the result at a particular index is obtained from values up to and including the one at that index. But it's common to want to use the values up to but not including that one instead. This can be done either by joining or shifting in that value before scanning. The difference is that with Join the result is longer than the argument. Either form might be wanted depending on how it will be used. +When using [Scan](scan.md) (`` ` ``), the result at a particular index is obtained from values up to and including the one at that index. But it's common to want to use the values up to but not including that one instead. This can be done either by [joining](join.md#join-to) or shifting in that value before scanning. The difference is that with Join the result is longer than the argument. Either form might be wanted depending on how it will be used. + + 2 +` 1‿0‿1‿0 # Initial value not retained + + 2 +`∘∾ 1‿0‿1‿0 # All values - +` 1‿1‿1‿1 - 2 +`∘∾ 1‿1‿1‿1 - 2 +`∘» 1‿1‿1‿1 + 2 +`∘» 1‿0‿1‿0 # Final value not created The *strides* of an array are the distances between one element and the next along any given axis. It's the product of all axis lengths below that axis, since these are all the axes that have to be "skipped" to jump along the axis. The strides of an array `ð•©` are `` (×`1»⊢)⌾⌽∘≢𕩠``. @@ -83,14 +86,17 @@ The *strides* of an array are the distances between one element and the next alo Shifting always works on the first axis of `ð•©` (which must have rank 1 or more), and shifts in major cells. A left argument can have rank equal to `ð•©`, or one less than it, in which case it becomes a single cell of the result. With no left argument, a cell of fills `1↑0↑ð•©` is nudged in. ⊢ a ↠⥊⟜(↕×´) 4‿3 + » a # Nudge adds a cell of fills + "one" « a # Shift in a cell + ("two"â‰"cel") « a # Shift in multiple cells ## Definition In any instance of `»` or `«`, `ð•©` must have rank at least 1. -For a dyadic shift function, `ð•¨` must be Join-compatible with `ð•©` (that is, `ð•¨âˆ¾ð•©` completes without error) and cannot have greater rank than `ð•©`. Then Shift Before (`»`) is `{(≠ð•©)↑ð•¨âˆ¾ð•©}` and Shift After (`«`) is `{(-≠ð•©)↑ð•©âˆ¾ð•¨}` +For a dyadic shift function, `ð•¨` must be [Join](join.md#join-to)-compatible with `ð•©` (that is, `ð•¨âˆ¾ð•©` completes without error) and cannot have greater rank than `ð•©`. Then Shift Before (`»`) is `{(≠ð•©)↑ð•¨âˆ¾ð•©}` and Shift After (`«`) is `{(-≠ð•©)↑ð•©âˆ¾ð•¨}` When called monadically, the default argument is a cell of fills `1↑0↑ð•©`. That is, Nudge (`»`) is `(1↑0↑⊢)⊸»` and Nudge Back (`«`) is `(1↑0↑⊢)⊸«`. This default argument always satisfies the compatibility requirement above and so the only conditions for nudge are that `ð•©` has rank at least 1 and has a fill element. diff --git a/doc/train.md b/doc/train.md index afad29ba..4f58f454 100644 --- a/doc/train.md +++ b/doc/train.md @@ -2,7 +2,7 @@ # Function trains -Trains are an important aspect of BQN's [tacit](tacit.md) programming capabilities. In fact, a crucial one: with trains and the identity functions Left (`⊣`) and Right (`⊢`), a fully tacit program can express any explicit function whose body is a statement with `ð•¨` and `ð•©` used only as arguments (that is, there are no assignments and `ð•¨` and `ð•©` are not used in operands or lists. Functions with assignments may have too many variables active at once to be directly translated but can be emulated by constructing lists. But it's probably a bad idea). Without trains it isn't possible to have two different functions that each use both arguments to a dyadic function. With trains it's perfectly natural. +Trains are an important aspect of BQN's [tacit](tacit.md) programming capabilities. In fact, a crucial one: with trains and the [identity functions](identity.md) Left (`⊣`) and Right (`⊢`), a fully tacit program can express any explicit function whose body is a statement with `ð•¨` and `ð•©` used only as arguments (that is, there are no assignments and `ð•¨` and `ð•©` are not used in operands or lists. Functions with assignments may have too many variables active at once to be directly translated but can be emulated by constructing lists. But it's probably a bad idea). Without trains it isn't possible to have two different functions that each use both arguments to a dyadic function. With trains it's perfectly natural. BQN's trains are the same as those of Dyalog APL, except that Dyalog is missing the minor convenience of BQN's Nothing (`·`). There are many Dyalog-based documents and videos on trains you can view on the [APL Wiki](https://aplwiki.com/wiki/Train). @@ -22,7 +22,7 @@ Here [Couple](couple.md) (`â‰`) is used to combine two units into a list, so we (·∾⌽) "ab"‿"cde"‿"f" ∾∘⌽ "ab"‿"cde"‿"f" -The three functions `∾⌽`, `·∾⌽`, and `∾∘⌽` are completely identical. Why might we want **three** different ways to write the same thing? If we only want to define a function, there's hardly any difference. However, these three forms have different syntax, and might be easier or harder to use in different contexts. As we'll see, we can use `∾∘⌽` inside a train without parenthesizing it, and string `·∾⌽` but not `∾⌽` together with other trains. Let's look at how the train syntax extends to longer expressions. +The three functions `∾⌽`, `·∾⌽`, and `∾∘⌽` are completely identical: [Join](join.md#join) of [Reverse](reverse.md). Why might we want **three** different ways to write the same thing? If we only want to define a function, there's hardly any difference. However, these three forms have different syntax, and might be easier or harder to use in different contexts. As we'll see, we can use `∾∘⌽` inside a train without parenthesizing it, and string `·∾⌽` but not `∾⌽` together with other trains. Let's look at how the train syntax extends to longer expressions. ## Longer trains @@ -46,7 +46,7 @@ In a train, arguments alternate strictly with combining functions between them. ## Practice training -The train `` ⊢>¯1»⌈` `` is actually a nice trick for marking first occurrences `∊ð•©` given the self-classify `âŠð•©` without doing another search. Let's take a closer look, first by applying it mechanically. To do this, we apply each "argument" to the train's argument, and then combine them with the combining functions. +The train `` ⊢>¯1»⌈` `` is actually a nice trick to get the result of [Mark Firsts](selfcmp.md#mark-firsts) `∊ð•©` given the result of [Classify](selfcmp.md#classify) `âŠð•©`, without doing another search. Let's take a closer look, first by applying it mechanically. To do this, we apply each "argument" to the train's argument, and then combine them with the combining functions. (⊢ > ¯1 » ⌈`) ð•© (⊢ð•©) > (¯1) » (⌈`ð•©) @@ -54,15 +54,15 @@ The train `` ⊢>¯1»⌈` `` is actually a nice trick for marking first occurre So—although not all trains simplify so much—this confusing train is just `` {ð•©>¯1»⌈`ð•©} ``! Why would I write it in such an obtuse way? To someone used to working with trains, the function `` (⊢>¯1»⌈`) `` isn't any more complicated to read: `⊢` in an argument position of a train just means `ð•©` while `` ⌈` `` will be applied to the arguments. Using the train just means slightly shorter code and two fewer `ð•©`s to trip over. -This function's argument is the self-classify `âŠ` of some list (in fact this technique also works on the self-indices `ð•©âŠð•©`). Self-classify moves along its argument, giving each major cell a number: the first unused natural number if that value hasn't been seen yet, and otherwise the number chosen when it was first seen. It can be implemented as `∊âŠâŠ¢`, another train! +This function's argument is Classify (`âŠ`) of some list (in fact this technique also works on the [index-of](search.md#index-of)-self `ð•©âŠð•©`). Classify moves along its argument, giving each major cell a number: the first unused natural number if that value hasn't been seen yet, and otherwise the number chosen when it was first seen. It can be implemented as `â·âŠâŠ¢`, another train! ⊢ sc ↠⊠"tacittrains" -Each `'t'` is `0`, each `'a'` is `1`, and so on. We'd like to discard some of the information in the self-classify, to just find whether each major cell had a new value. Here are the input and desired result: +Each `'t'` is `0`, each `'a'` is `1`, and so on. We'd like to discard some of the information from Classify, to just find whether each major cell had a new value. Here are the input and desired result: sc ≠∊ "tacittrains" -The result should be `1` when a new number appears, higher than all the previous numbers. To do this, we first find the highest previous number by taking the maximum-scan `` ⌈` `` of the argument, then [shifting](shift.md) to move the previous maximum to the current position. The first cell is always new, so we shift in a `¯1`, so it will be less than any element of the argument. +The result should be `1` when a new number appears, higher than all the previous numbers. To do this, we first find the highest previous number by taking the [maximum](arithmetic.md#additional-arithmetic)-[scan](scan.md) `` ⌈` `` of the argument, then [shifting](shift.md) to move the previous maximum to the current position. The first cell is always new, so we shift in a `¯1`, so it will be less than any element of the argument. ¯1 » ⌈`sc (¯1»⌈`) sc @@ -76,7 +76,7 @@ Now we compare the original list with the list of previous-maximums. The example above uses a train with five functions: an odd number. Trains with an odd length are always composed of length-3 trains, and they themselves are composed the same way as subject expressions: an odd-length train can be placed in the last position of another train without parentheses, but it needs parentheses to go in any other position. -But we also saw the length-2 train `∾⌽` above. Even-length trains consist of a single function (`∾`) applied to a function or odd-length train (`⌽`); another perspective is that an even-length train is an odd-length train where the left argument of the final (leftmost) function is left out, so it's called with only a right argument. An even-length train *always* needs parentheses if it's used as one of the functions in another train. However, it can also be turned into an odd-length train by placing `·` at the left, making the implicit missing argument explicit. After this it can be used at the end of an odd-length train without parentheses. To get some intuition for even-length trains, let's look at an example of three functions used together: the unique (`â·`) sorted (`∧`) absolute values (`|`) of an argument list. +But we also saw the length-2 train `∾⌽` above. Even-length trains consist of a single function (`∾`) applied to a function or odd-length train (`⌽`); another perspective is that an even-length train is an odd-length train where the left argument of the final (leftmost) function is left out, so it's called with only a right argument. An even-length train *always* needs parentheses if it's used as one of the functions in another train. However, it can also be turned into an odd-length train by placing `·` at the left, making the implicit missing argument explicit. After this it can be used at the end of an odd-length train without parentheses. To get some intuition for even-length trains, let's look at an example of three functions used together: the [unique](selfcmp.md#deduplicate) (`â·`) [sorted](order.md#sort) (`∧`) [absolute values](arithmetic.md#additional-arithmetic) (`|`) of an argument list. â·âˆ§| 3‿4‿¯3‿¯2‿0 diff --git a/doc/transpose.md b/doc/transpose.md index ab573390..c3d0807b 100644 --- a/doc/transpose.md +++ b/doc/transpose.md @@ -2,7 +2,7 @@ # Transpose -As in APL, Transpose (`â‰`) is a tool for rearranging the axes of an array. BQN's version is tweaked to align better with the leading axis model and make common operations easier. +Transpose (`â‰`) is a tool for rearranging the axes of an array. BQN's version is tweaked relative to APL to align better with the leading axis model and make common operations easier. ## Transpose basics @@ -22,12 +22,13 @@ With two axes the only interesting operation of this sort is to swap them (and w APL extends matrix transposition to any rank by reversing all axes for its monadic `â‰`, but this generalization isn't very natural and is almost never used. The main reason for it is to maintain the equivalence `a MP b â†â†’ b MP⌾≠a`, where `MP ↠+Ë∘×⎉1‿∞` is the generalized matrix product. But even here APL's Transpose is suspect. It does much more work than it needs to, as we'll see. -BQN's transpose takes the first axis of its argument and moves it to the end. +BQN's transpose takes the first axis of `ð•©` and moves it to the end. ≢ a23456 ↠↕2‿3‿4‿5‿6 + ≢ ≠a23456 -In terms of the argument data as given by Deshape (`⥊`), this looks like a simple 2-dimensional transpose: one axis is exchanged with a compound axis made up of the other axes. Here we transpose a rank 3 matrix: +In terms of the argument data as given by [Deshape](reshape.md#deshape) (`⥊`), this looks like a simple 2-dimensional transpose: one axis is exchanged with a compound axis made up of the other axes. Here we transpose a rank 3 matrix: a322 ↠3‿2‿2⥊↕12 â‰â—‹<⟜≠a322 @@ -36,9 +37,10 @@ But, ignoring the whitespace and going in reading order, the argument and result â‰â—‹<⟜≠⥊˘ a322 -To exchange multiple axes, use the Power modifier. A negative power moves axes in the other direction, just like how Rotate handles negative left arguments. In particular, to move the last axis to the front, use Undo (as you might expect, this exactly inverts `â‰`). +To exchange multiple axes, use the [Repeat](repeat.md) modifier. A negative power moves axes in the other direction, just like how [Rotate](reverse.md#rotate) handles negative left arguments. In particular, to move the last axis to the front, use Undo (as you might expect, this exactly inverts `â‰`). ≢ â‰âŸ3 a23456 + ≢ â‰â¼ a23456 In fact, we have `≢â‰âŸk a â†â†’ k⌽≢a` for any whole number `k` and array `a`. @@ -47,11 +49,11 @@ To move axes other than the first, use the Rank modifier in order to leave initi ≢ â‰âމ3 a23456 -And of course, Rank and Power can be combined to do more complicated transpositions: move a set of contiguous axes with any starting point and length to the end. +And of course, Rank and Repeat can be combined to do more complicated transpositions: move a set of contiguous axes with any starting point and length to the end. ≢ â‰â¼âŽ‰Â¯1 a23456 -Using these forms, we can state BQN's generalized matrix product swapping rule: +Using these forms (and the [Rank](shape.md) function), we can state BQN's generalized matrix product swapping rule: a MP b â†â†’ â‰âŸ(1-=a) (â‰b) MP (â‰â¼a) @@ -65,20 +67,21 @@ In a case like this BQN's Dyadic transpose is much easier. ## Dyadic Transpose -Transpose also allows a left argument that specifies a permutation of the right argument's axes. For each index `pâ†iâŠð•¨` in the left argument, axis `i` of the argument is used for axis `p` of the result. Multiple argument axes can be sent to the same result axis, in which case that axis goes along a diagonal of the argument array, and the result will have a lower rank than the argument. +Transpose also allows a left argument that specifies a permutation of `ð•©`'s axes. For each index `pâ†i⊑ð•¨` in the left argument, axis `i` of `ð•©` is used for axis `p` of the result. Multiple argument axes can be sent to the same result axis, in which case that axis goes along a diagonal of `ð•©`, and the result will have a lower rank than `ð•©`. ≢ 1‿3‿2‿0‿4 ≠a23456 + ≢ 1‿2‿2‿0‿0 ≠a23456 # Don't worry too much about this case though Since this kind of rearrangement can be counterintuitive, it's often easier to use `â‰â¼` when specifying all axes. If `p≡○≠≢a`, then we have `≢pâ‰â¼a â†â†’ pâŠâ‰¢a`. ≢ 1‿3‿2‿0‿4 â‰â¼ a23456 -So far, all like APL. BQN makes one little extension, which is to allow only some axes to be specified. The left argument will be matched up with leading axes of the right argument. Those axes are moved according to the left argument, and remaining axes are placed in order into the gaps between them. +So far, all like APL. BQN makes one little extension, which is to allow only some axes to be specified. Then `ð•¨` will be matched up with [leading axes](leading.md) of `ð•©`. Those axes are moved according to `ð•¨`, and remaining axes are placed in order into the gaps between them. ≢ 0‿2‿4 ≠a23456 -In particular, the case with only one argument specified is interesting. Here, the first axis ends up at the given location. This gives us a much better solution to the problem at the end of the last section. +In particular, the case with only one axis specified is interesting. Here, the first axis ends up at the given location. This gives us a much better solution to the problem at the end of the last section. ≢ 2 ≠a23456 # Restrict Transpose to the first three axes @@ -88,8 +91,8 @@ Finally, it's worth noting that, as monadic Transpose moves the first axis to th Here we define the two valences of Transpose more precisely. -Monadic transpose is identical to `(=-1Ë™)⊸â‰`, except that if the argument is a unit it is returned unchanged rather than giving an error. +An atom right argument to either valence of Transpose is always enclosed to get an array before doing anything else. -An atom right argument to dyadic Transpose is always enclosed to get an array before doing anything else. +Monadic transpose is identical to `(=-1Ë™)⊸â‰`, except that if `ð•©` is a unit it is returned unchanged (after enclosing, if it's an atom) rather than giving an error. -In dyadic Transpose, the left argument is a number or numeric array of rank 1 or less, and `ð•¨â‰¤â—‹â‰ ≢ð•©`. Define the result rank `râ†(=ð•©)-+´¬∊ð•¨` to be the argument rank minus the number of duplicate entries in the left argument. We require `∧´ð•¨<r`. Bring `ð•¨` to full length by appending the missing indices: `ð•¨âˆ¾â†©ð•¨(¬∘∊˜/⊢)↕r`. Now the result shape is defined to be `⌊´¨ð•¨âŠ”â‰¢ð•©`. Element `i⊑z` of the result `z` is element `(ð•¨âŠi)⊑ð•©` of the argument. +In dyadic Transpose, `ð•¨` is a number or numeric array of rank 1 or less, and `ð•¨â‰¤â—‹â‰ ≢ð•©`. Define the result rank `râ†(=ð•©)-+´¬∊ð•¨` to be the right argument rank minus the number of duplicate entries in the left argument. We require `∧´ð•¨<r`. Bring `ð•¨` to full length by appending the missing indices: `ð•¨âˆ¾â†©ð•¨(¬∘∊˜/⊢)↕r`. Now the result shape is defined to be `⌊´¨ð•¨âŠ”â‰¢ð•©`. Element `i⊑z` of the result `z` is element `(ð•¨âŠi)⊑ð•©` of the argument. diff --git a/doc/types.md b/doc/types.md index 3e37ffed..2564d698 100644 --- a/doc/types.md +++ b/doc/types.md @@ -44,13 +44,13 @@ FS ↠{ð•© EncËœ "g"Attr⟨"font-size",(Fmtð•¨)∾"px"⟩} ⟩ --> -The reason operations and namespaces are called "mutable" is that the values obtained from them—by calling an operation on particular arguments or reading a field from a namespace—may change over the course of the program. This property is caused by variable modification `↩`, which can directly change a namespace field, or change the behavior of an operation that uses the modified variable. This means that a program that doesn't include `↩` won't have such changes in behavior. However, there will still be an observable difference between immutable data and the mutable types: code that creates a mutable value (for example, a block function `{ð•©}`) creates a different one each time, so that two different instances don't match (`≡`) each other. Data values created at different times may match, but mutable values never will. +The reason operations and namespaces are called "mutable" is that the values obtained from them—by calling an operation on particular arguments or reading a field from a namespace—may change over the course of the program. This property is caused by variable modification `↩`, which can directly change a namespace field, or change the behavior of an operation that uses the modified variable. This means that a program that doesn't include `↩` won't have such changes in behavior. However, there will still be an observable difference between immutable data and the mutable types: code that creates a mutable value (for example, a block function `{ð•©}`) creates a different one each time, so that two different instances don't [match](match.md) (`≡`) each other. Data values created at different times may match, but mutable values never will. An array is considered immutable because its shape, and what elements it contains, cannot change. An array has no identity outside these properties (and possibly its fill element), so an array with a different shape or different elements would simply be a different array. However, any element of an array could be mutable, in which case the behavior of the array would change with respect to the operation of selecting that element and calling it or accessing a field. ## Data types -Data types—numbers, characters, and arrays—are more like "things" than "actions". If called as a function, a value of one of these types simply returns itself. Data can be uniquely represented, compared for equality, and ordered using BQN's array ordering; in contrast, determining whether two functions always return the same result can be undecidable. For arrays, these properties apply only if there are no operations inside. We might say that "data" in BQN refers to numbers, characters, and arrays of data. +Data types—numbers, characters, and arrays—are more like "things" than "actions". If called as a function, a value of one of these types simply returns itself. Data can be uniquely represented, compared for equality, and ordered using BQN's [array ordering](order.md#array-ordering); in contrast, determining whether two functions always return the same result can be undecidable. For arrays, these properties apply only if there are no operations inside. We might say that "data" in BQN refers to numbers, characters, and arrays of data. ### Numbers @@ -60,16 +60,16 @@ The BQN spec allows for different numeric models to be used, but requires there A character in BQN is always a [Unicode](https://en.wikipedia.org/wiki/Unicode) code point. BQN does not use encodings such as UTF-8 or UTF-16 for characters, although it would be possible to store arrays of integers or characters that correspond to data in these encodings. Because every code point corresponds to a single unit in UTF-32, BQN characters can be thought of as UTF-32 encoded. -Addition and subtraction treat characters as an [affine space](http://videocortex.io/2018/Affine-Space-Types/) relative to the linear space of numbers. This means that: +Addition and subtraction [treat](arithmetic.md#character-arithmetic) characters as an [affine space](http://videocortex.io/2018/Affine-Space-Types/) relative to the linear space of numbers. This means that: * A number can be added to or subtracted from a character. * Two characters can be subtracted to get the distance between them—a number. Other linear combinations such as adding two characters or negating a character are not allowed. You can check whether an application of `+` or `-` on numbers and characters is allowed by applying the same function to the "characterness" of each value: `0` for a number and `1` for a character. The result will be a number if this application gives `0` and a character if this gives `1`, and otherwise the operation is not allowed. ### Arrays -A BQN array is a multidimensional arrangement of data. This means it has a certain *shape*, which is a finite list of natural numbers giving the length along each axis, and it contains an *element* for each possible *index*, which is a choice of one natural number that's less than each axis length in the shape. The total number of elements, or *bound*, is then the product of all the lengths in the shape. The shape may have any length including zero, and this shape is known as the array's *rank*. An array of rank 0, which always contains exactly one element, is called a *unit*, while an array of rank 1 is called a *list* and an array of rank 2 is called a *table*. +A BQN array is a multidimensional arrangement of data. This means it has a certain [*shape*](shape.md), which is a finite list of natural numbers giving the length along each axis, and it contains an *element* for each possible [*index*](indices.md), which is a choice of one natural number that's less than each axis length in the shape. The total number of elements, or *bound*, is then the product of all the lengths in the shape. The shape may have any length including zero, and this shape is known as the array's *rank*. An array of rank 0, which always contains exactly one element, is called a *unit*, while an array of rank 1 is called a *list* and an array of rank 2 is called a *table*. -Each array—empty or nonempty—has an inferred property called a *fill*. The fill either indicates what element should be used to pad an array, or that such an element is not known and an error should result. Fills are used by Take (`↑`) and the two Nudge functions (`»«`). +Each array—empty or nonempty—has an inferred property called a *fill*. The fill either indicates what element should be used to pad an array, or that such an element is not known and an error should result. Fills can be used by [Take](take.md) (`↑`), the two [Nudge](shift.md) functions (`»«`), [First](pick.md) (`⊑`), and [Reshape](reshape.md) (`⥊`). Arrays are value types (or immutable), so that there is no way to "change" the shape or elements of an array. An array with different properties is a different array. As a consequence, arrays are an inductive type, and it's not possible for an array to contain itself, or contain an array that contains itself, and so on. However, it is possible for an array to contain a function or other operation that has access to the array through a variable, and in this sense an array can "know about" itself. diff --git a/doc/windows.md b/doc/windows.md index 30cb344a..379bf644 100644 --- a/doc/windows.md +++ b/doc/windows.md @@ -12,9 +12,9 @@ We'll start with the one-axis case. Here Window's left argument is a number betw 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 by these two endpoints. +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 `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: +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: 2âŠ5↕"abcdefg" 5↑2↓"abcdefg" @@ -33,7 +33,7 @@ Passing a list as the left argument to Windows takes slices along any number of 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. -If the left argument has length `0`, then the argument 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 the same as the argument. +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. ### More formally @@ -43,7 +43,7 @@ Using [Group](group.md) we could also write `i⊑z` â†â†’ `ð•©âŠ‘Ëœ(ð•¨âˆ¾â—‹ ## Symmetry -Let's look at an earlier example, along with its transpose. +Let's look at an earlier example, along with its [Transpose](transpose.md) (`â‰`). {⟨ð•©,â‰ð•©âŸ©}5↕"abcdefg" @@ -55,21 +55,22 @@ In other words, the i'th element of slice j is the same as the j'th element of s {(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, our slice-length to slice-number converter. +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. {((5‿6¬2‿2)↕ð•©) ≡ 2‿3â‰(2‿2↕ð•©)} ↕5‿6‿7 ## Applications -Windows can be followed up with a reduction on each slice to give a windowed reduction. Here we take running sums of 3 values. +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. - +´˘3↕ ⟨2,6,0,1,4,3⟩ + +ˢ3↕ ⟨2,6,0,1,4,3⟩ -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 [shift functions](shift.md) like `«` 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 `` +` ``, which requires we take pairwise differences starting at initial value 0. +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. -⟜(0»⊢) +` 3‿2‿1‿1 + (-ËœË≠↕0∾⊢) +` 3‿2‿1‿1 -With Windows, we can modify the 3-element running sum above to keep the length constant by starting with two zeros. +With Windows, we can modify the 3-element running sum from before to keep the length constant by starting with two zeros. (+Ë≠↕(2⥊0)⊸∾) ⟨2,6,0,1,4,3⟩ diff --git a/docs/doc/reverse.html b/docs/doc/reverse.html index edcb37a7..62eae902 100644 --- a/docs/doc/reverse.html +++ b/docs/doc/reverse.html @@ -5,7 +5,7 @@ </head> <div class="nav"><a href="https://github.com/mlochbaum/BQN">BQN</a> / <a href="../index.html">main</a> / <a href="index.html">doc</a></div> <h1 id="reverse-and-rotate">Reverse and Rotate</h1> -<p>The symbol <code><span class='Function'>⌽</span></code> indicates two different array transformations: with no left argument, it reverses the major cells of the array, but with a left argument, it rotates or cycles them around. These two possibilities, first put together in very early versions of APL, can't be considered restrictions or different views of some unifying function, but there are connections between them. Each returns an array with the same shape and all the same elements as <code><span class='Value'>ð•©</span></code>, possibly in a different arrangement. And elements that start out next to each other in <code><span class='Value'>ð•©</span></code> generally stay next to each other—always, if we consider an element on one edge to be next to the one opposite to it. One might think of them as <a href="https://en.wikipedia.org/wiki/Isometry">isometries</a> preserving a discrete subgroup of the torus, if one were inclined to think such things. On major cells, the two functions decompose the <a href="https://en.wikipedia.org/wiki/Dihedral_group">dihedral group</a> okay I'll stop.</p> +<p>The symbol <code><span class='Function'>⌽</span></code> indicates two different array transformations: with no left argument, it reverses the major cells of the array, but with a left argument, it rotates or cycles them around. These two possibilities, first put together in very early versions of APL, can't be considered restrictions or different views of some unifying function, but there are connections between them. Each returns an array with the same <a href="shape.html">shape</a> and all the same elements as <code><span class='Value'>ð•©</span></code>, possibly in a different arrangement. And elements that start out next to each other in <code><span class='Value'>ð•©</span></code> generally stay next to each other—always, if we consider an element on one edge to be next to the one opposite to it. One might think of them as <a href="https://en.wikipedia.org/wiki/Isometry">isometries</a> preserving a discrete subgroup of the torus, if one were inclined to think such things. On major cells, the two functions decompose the <a href="https://en.wikipedia.org/wiki/Dihedral_group">dihedral group</a> okay I'll stop.</p> <p>Many uses of Rotate in APL are better handled by <a href="shift.html">shift</a> functions in BQN. If there's no reason to treat the data as cyclic or periodic, it's best to avoid Rotate.</p> <h2 id="reverse">Reverse</h2> <p>There's not too much to say about Reverse. It puts the elements of a list the other way around, or more generally the major cells of an array.</p> @@ -46,7 +46,7 @@ ⟨ 1 1 1 1 1 1 0 ⟩ </pre> <h2 id="rotate">Rotate</h2> -<p>Rotate moves elements in a list around cyclically. It can also rotate any number of axes of the argument array by different amounts at once. That's discussed in the next section; for now we'll stick to a single number in the left argument. It has to be an integer, and the right argument has to be an array with at least one axis.</p> +<p>Rotate moves elements in a list around cyclically. It can also rotate any number of axes of the argument array by different amounts at once. That's discussed in the next section; for now we'll stick to a single number for <code><span class='Value'>ð•¨</span></code>. It has to be an integer, and <code><span class='Value'>ð•©</span></code> has to be an array with at least one axis.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MiDijL0gInJvdGF0ZSIKCjIgKOKKoiDiiY3il4s8IOKMvSkgNeKAvzLipYoicm90YXRlQ0VMTCIKCjIg4oy9ICdjJyAgIyBObyBheGVzIHRvIHJvdGF0ZQ==">↗ï¸</a><pre> <span class='Number'>2</span> <span class='Function'>⌽</span> <span class='String'>"rotate"</span> "tatero" @@ -64,12 +64,12 @@ <span class='Number'>2</span> <span class='Function'>⌽</span> <span class='String'>'c'</span> <span class='Comment'># No axes to rotate </span>ERROR </pre> -<p>Elements are always rotated to the left, so that entry <code><span class='Value'>i</span></code> of the result is entry <code><span class='Value'>ð•¨</span><span class='Function'>+</span><span class='Value'>i</span></code> of the argument—or rather, entry <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><span class='Function'>+</span><span class='Value'>i</span></code> to enable elements to cycle around. This can be seen directly by using <code><span class='Function'>↕</span><span class='Value'>n</span></code> as an argument: in this case, the value of <code><span class='Value'>ð•©</span></code> at index <code><span class='Value'>i</span></code> is just <code><span class='Value'>i</span></code>.</p> +<p>Elements are always rotated to the left, so that entry <code><span class='Value'>i</span></code> of the result is entry <code><span class='Value'>ð•¨</span><span class='Function'>+</span><span class='Value'>i</span></code> of the argument—or rather, entry <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><span class='Function'>+</span><span class='Value'>i</span></code> to enable elements to cycle around. This can be seen directly by using the <a href="range.html">range</a> <code><span class='Function'>↕</span><span class='Value'>n</span></code> as an argument: then the value of <code><span class='Value'>ð•©</span></code> at index <code><span class='Value'>i</span></code> is just <code><span class='Value'>i</span></code>.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MiDijL0g4oaVNg==">↗ï¸</a><pre> <span class='Number'>2</span> <span class='Function'>⌽</span> <span class='Function'>↕</span><span class='Number'>6</span> ⟨ 2 3 4 5 0 1 ⟩ </pre> -<p>The rotation <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> moves each element the entire length of <code><span class='Value'>ð•©</span></code>, which just places it back where it started. In fact, adding <code><span class='Function'>≠</span><span class='Value'>ð•©</span></code> to the rotation amount never changes the behavior or the rotation. In terms of indices, this is because <code><span class='Paren'>(</span><span class='Function'>≠</span><span class='Value'>ð•©</span><span class='Paren'>)</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'>a</span></code> is <code><span class='Value'>a</span></code>.</p> -<p>To rotate the other way, use a negative left argument (so <code><span class='Function'>-</span><span class='Modifier2'>⊸</span><span class='Function'>⌽</span></code> is a simple way to write "reverse rotate"). This will always be the same as a leftwards rotation, since <code><span class='Paren'>(</span><span class='Function'>-</span><span class='Value'>r</span><span class='Paren'>)</span><span class='Function'>⌽</span><span class='Value'>ð•©</span></code> is <code><span class='Paren'>((</span><span class='Function'>≠</span><span class='Value'>ð•©</span><span class='Paren'>)</span><span class='Function'>-</span><span class='Value'>r</span><span class='Paren'>)</span><span class='Function'>⌽</span><span class='Value'>ð•©</span></code>, but could be more convenient.</p> +<p>The rotation <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> moves each element the entire <a href="shape.html">length</a> of <code><span class='Value'>ð•©</span></code>, which just places it back where it started. In fact, adding <code><span class='Function'>≠</span><span class='Value'>ð•©</span></code> to the rotation amount never changes the behavior or the rotation. In terms of indices, this is because <code><span class='Paren'>(</span><span class='Function'>≠</span><span class='Value'>ð•©</span><span class='Paren'>)</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'>a</span></code> is <code><span class='Value'>a</span></code>.</p> +<p>To rotate the other way, use a negative left argument (so <code><span class='Function'>-</span><span class='Modifier2'>⊸</span><span class='Function'>⌽</span></code> is a simple way to write "reverse rotate"). This will always be the same as some leftwards rotation, since <code><span class='Paren'>(</span><span class='Function'>-</span><span class='Value'>r</span><span class='Paren'>)</span><span class='Function'>⌽</span><span class='Value'>ð•©</span></code> is <code><span class='Paren'>((</span><span class='Function'>≠</span><span class='Value'>ð•©</span><span class='Paren'>)</span><span class='Function'>-</span><span class='Value'>r</span><span class='Paren'>)</span><span class='Function'>⌽</span><span class='Value'>ð•©</span></code>, but could be more convenient.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=wq8yIOKMvSAicm90YXRlIg==">↗ï¸</a><pre> <span class='Number'>¯2</span> <span class='Function'>⌽</span> <span class='String'>"rotate"</span> "terota" </pre> diff --git a/docs/doc/scan.html b/docs/doc/scan.html index 1f572239..cc806de6 100644 --- a/docs/doc/scan.html +++ b/docs/doc/scan.html @@ -59,8 +59,8 @@ </svg> <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> +<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 right-to-left folds, 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 <a href="fold.html#identity-values">identity value</a>, because scanning over an empty array simply returns that array.</p> <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> @@ -69,7 +69,7 @@ <span class='Function'>+</span><span class='Modifier'>`</span><span class='Function'>»</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> <span class='Comment'># Exclusive prefix sum </span>⟨ 0 2 6 9 ⟩ </pre> -<p>The pattern is generalized to any function <code><span class='Function'>ð”½</span></code>. With an operand of <code><span class='Function'>×</span></code>, it can find the first <em>n</em> factorials. With <code><span class='Function'>⌈</span></code>, it returns the largest element so far.</p> +<p>The pattern is generalized to any function <code><span class='Function'>ð”½</span></code>. With an operand of <code><span class='Function'>×</span></code>, it can find the first <em>n</em> factorials. With <a href="arithmetic.html#additional-arithmetic">Maximum</a> (<code><span class='Function'>⌈</span></code>), it returns the largest element so far.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=w5dgIDEr4oaVNgoK4oyIYCDCrzHigL/CrzLigL8w4oC/NOKAvzLigL8x4oC/NeKAv8KvMg==">↗ï¸</a><pre> <span class='Function'>×</span><span class='Modifier'>`</span> <span class='Number'>1</span><span class='Function'>+↕</span><span class='Number'>6</span> ⟨ 1 2 6 24 120 720 ⟩ @@ -94,7 +94,7 @@ <span class='Value'>c</span> 9 </pre> -<p>Some other useful scans apply to boolean lists. The function <code><span class='Function'>∨</span><span class='Modifier'>`</span></code> tests whether this or any previous element is 1, so that the result starts at 0 but permanently switches to 1 as soon as the first 1 is found. Similarly, <code><span class='Function'>∧</span><span class='Modifier'>`</span></code> turns all instances of 1 after the first 0 to 0.</p> +<p>Some other useful scans apply to boolean lists. The function <code><span class='Function'>∨</span><span class='Modifier'>`</span></code> (with <a href="logic.html">Or</a>) tests whether this or any previous element is 1, so that the result starts at 0 but permanently switches to 1 as soon as the first 1 is found. Similarly, <code><span class='Function'>∧</span><span class='Modifier'>`</span></code> turns all instances of 1 after the first 0 to 0.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oioYCAw4oC/MOKAvzHigL8w4oC/MOKAvzHigL8w4oC/MQoK4oinYCAx4oC/MeKAvzHigL8w4oC/MOKAvzHigL8w4oC/MQ==">↗ï¸</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><span class='Ligature'>‿</span><span class='Number'>1</span> ⟨ 0 0 1 1 1 1 1 1 ⟩ @@ -109,7 +109,7 @@ "ab\rs\\" </pre> <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> +<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 <a href="prefixes.html">prefixes</a> 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 ⟩ diff --git a/docs/doc/select.html b/docs/doc/select.html index 48f2af19..61a0f38d 100644 --- a/docs/doc/select.html +++ b/docs/doc/select.html @@ -48,7 +48,7 @@ </g> </svg> -<p>The function Select (<code><span class='Function'>âŠ</span></code>) reorganizes the array <code><span class='Value'>ð•©</span></code> along one or more axes based on <a href="indices.html">indices</a> given by <code><span class='Value'>ð•¨</span></code>. The result has the same <a href="depth.html">depth</a> as <code><span class='Value'>ð•©</span></code>, since its elements are always elements of <code><span class='Value'>ð•©</span></code>. This means it differs from Pick (<code><span class='Function'>⊑</span></code>), which takes elements from <code><span class='Value'>ð•©</span></code> but can arrange them in any nested structure, including returning an element directly.</p> +<p>The function Select (<code><span class='Function'>âŠ</span></code>) reorganizes the array <code><span class='Value'>ð•©</span></code> along one or more axes based on <a href="indices.html">indices</a> given by <code><span class='Value'>ð•¨</span></code>. The result has the same <a href="depth.html">depth</a> as <code><span class='Value'>ð•©</span></code>, since its elements are always elements of <code><span class='Value'>ð•©</span></code>. This means it differs from <a href="pick.html">Pick</a> (<code><span class='Function'>⊑</span></code>), which takes elements from <code><span class='Value'>ð•©</span></code> but can arrange them in any nested structure, including returning an element directly.</p> <p>The monadic form First Cell (<code><span class='Function'>âŠ</span></code>) gets the major cell with index 0, so that <code><span class='Function'>âŠ</span><span class='Value'>ð•©</span></code> is identical to <code><span class='Number'>0</span><span class='Function'>âŠ</span><span class='Value'>ð•©</span></code>.</p> <h2 id="single-selection">Single selection</h2> <p>Each axis of a BQN array is numbered starting at zero. Major cells are arranged along the first axis; in accordance with the <a href="leading.html">leading axis</a> principle, Select returns a major cell of <code><span class='Value'>ð•©</span></code> when <code><span class='Value'>ð•¨</span></code> is an atom.</p> @@ -114,7 +114,8 @@ ERROR 0 1 4 9 5 3 3 ┘ </pre> -<p>More generally, <code><span class='Value'>ð•¨</span></code> can be an array of any rank. Each of its 0-cells—containing a single number—is replaced with a cell of <code><span class='Value'>ð•©</span></code> in the result. The result's shape is then made up of the shape of <code><span class='Value'>ð•¨</span></code> and the major cell shape of <code><span class='Value'>ð•©</span></code>: it's <code><span class='Paren'>(</span><span class='Function'>≢</span><span class='Value'>ð•¨</span><span class='Paren'>)</span><span class='Function'>∾</span><span class='Number'>1</span><span class='Function'>↓≢</span><span class='Value'>ð•©</span></code>. When <code><span class='Value'>ð•©</span></code> is a list, the result has the same shape as <code><span class='Value'>ð•¨</span></code>. Elements of <code><span class='Value'>ð•¨</span></code> are replaced one-for-one with elements of <code><span class='Value'>ð•©</span></code>.</p> +<p>More generally, <code><span class='Value'>ð•¨</span></code> can be an array of any rank. Each of its 0-cells—containing a single number—is replaced with a cell of <code><span class='Value'>ð•©</span></code> in the result. The result's shape is then made up of the shape of <code><span class='Value'>ð•¨</span></code> and the major cell shape of <code><span class='Value'>ð•©</span></code>: it's <code><span class='Paren'>(</span><span class='Function'>≢</span><span class='Value'>ð•¨</span><span class='Paren'>)</span><span class='Function'>∾</span><span class='Number'>1</span><span class='Function'>↓≢</span><span class='Value'>ð•©</span></code>.</p> +<p>When <code><span class='Value'>ð•©</span></code> is a list, the result has the same shape as <code><span class='Value'>ð•¨</span></code>. Elements of <code><span class='Value'>ð•¨</span></code> are replaced one-for-one with elements of <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=MnxtCgooMnxtKSDiio8gIiAqIg==">↗ï¸</a><pre> <span class='Number'>2</span><span class='Function'>|</span><span class='Value'>m</span> ┌─ ╵ 0 1 1 0 1 1 0 @@ -168,8 +169,8 @@ ERROR ⟨ 1 3 ⟩ ⟨ 1 0 ⟩ ⟨ 1 0 ⟩ ┘ </pre> -<p>Using a <a href="range.html">range</a> for <code><span class='Value'>ð•©</span></code> shows the structure of the selected elements more clearly, because each element is its own index. Each element of <code><span class='Value'>ð•¨</span></code> acts independently, giving a structure like the Table modifier.</p> -<p>While <code><span class='Value'>ð•¨</span></code> must have rank one or less, its elements can have any rank. When the elements are units, the corresponding axis of <code><span class='Value'>ð•©</span></code> disappears from the result. We can select a 0-cell of <code><span class='Value'>ð•©</span></code> in this way, although the more common case or selecting an element is handled by Pick.</p> +<p>Using a <a href="range.html">range</a> for <code><span class='Value'>ð•©</span></code> shows the structure of the selected elements more clearly, because each element is its own index. Each element of <code><span class='Value'>ð•¨</span></code> acts independently, giving a structure like the <a href="map.html#table">Table</a> modifier.</p> +<p>While <code><span class='Value'>ð•¨</span></code> must have rank one or less, its elements can have any rank. When the elements are units, the corresponding axis of <code><span class='Value'>ð•©</span></code> disappears from the result. We can select a 0-cell of <code><span class='Value'>ð•©</span></code> in this way, although the more common case of selecting an element is handled by <a href="pick.html">Pick</a>.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4p+oPDQsPDUsPDHin6kg4oqPICgz4qWKMTAp4qWK4oaVMWUzCuKfqCA0LCA1LCAx4p+pIOKKkSAoM+KlijEwKeKliuKGlTFlMw==">↗ï¸</a><pre> <span class='Bracket'>⟨</span><span class='Function'><</span><span class='Number'>4</span><span class='Separator'>,</span><span class='Function'><</span><span class='Number'>5</span><span class='Separator'>,</span><span class='Function'><</span><span class='Number'>1</span><span class='Bracket'>⟩</span> <span class='Function'>âŠ</span> <span class='Paren'>(</span><span class='Number'>3</span><span class='Function'>⥊</span><span class='Number'>10</span><span class='Paren'>)</span><span class='Function'>⥊↕</span><span class='Number'>1e3</span> ┌· · 451 @@ -182,4 +183,4 @@ ERROR ⟨ 450 451 452 453 454 455 456 457 458 459 ⟩ </pre> <p>If an element of <code><span class='Value'>ð•¨</span></code> has rank more than 1, it increases the rank of <code><span class='Value'>ð•©</span></code> rather than decreasing it. The general rule is that in the result, one axis of <code><span class='Value'>ð•©</span></code> is replaced by all the axes of the corresponding element of <code><span class='Value'>ð•¨</span></code> (trailing axes are unchanged). So the final shape <code><span class='Function'>≢</span><span class='Value'>ð•¨</span><span class='Function'>âŠ</span><span class='Value'>ð•©</span></code> is <code><span class='Paren'>(</span><span class='Function'>∾≢</span><span class='Modifier'>¨</span><span class='Value'>ð•¨</span><span class='Paren'>)</span><span class='Function'>∾</span><span class='Value'>ð•¨</span><span class='Function'>≠</span><span class='Modifier2'>⊸</span><span class='Function'>↓≢</span><span class='Value'>ð•©</span></code>. But this shape doesn't affect the elements retrieved from <code><span class='Value'>ð•©</span></code>. In all cases, using <code><span class='Function'>⥊</span><span class='Modifier'>¨</span><span class='Value'>ð•¨</span></code> for the left argument and then <a href="reshape.html">reshaping</a> the result would yield the same value.</p> -<p>Selection only ever applies to leading axes of <code><span class='Value'>ð•©</span></code>. But you can skip some leading axes using <code><span class='Modifier'>˘</span></code> or <code><span class='Modifier2'>⎉</span></code>, to select on any contiguous set of axes. In particular, use the one-axis case <code><span class='Value'>ð•¨</span><span class='Modifier2'>⊸</span><span class='Function'>âŠ</span><span class='Modifier2'>⎉</span><span class='Paren'>(</span><span class='Function'>-</span><span class='Value'>k</span><span class='Paren'>)</span> <span class='Value'>ð•©</span></code> to select along axis <code><span class='Value'>k</span></code> of <code><span class='Value'>ð•©</span></code>.</p> +<p>Selection only ever applies to leading axes of <code><span class='Value'>ð•©</span></code>. However, you can skip some leading axes using <code><span class='Modifier'>˘</span></code> or <code><span class='Modifier2'>⎉</span></code>, to select on any contiguous set of axes. In particular, use the one-axis case <code><span class='Value'>ð•¨</span><span class='Modifier2'>⊸</span><span class='Function'>âŠ</span><span class='Modifier2'>⎉</span><span class='Paren'>(</span><span class='Function'>-</span><span class='Value'>k</span><span class='Paren'>)</span> <span class='Value'>ð•©</span></code> to select along axis <code><span class='Value'>k</span></code> of <code><span class='Value'>ð•©</span></code>.</p> diff --git a/docs/doc/selfcmp.html b/docs/doc/selfcmp.html index bc99ef43..8e9540f2 100644 --- a/docs/doc/selfcmp.html +++ b/docs/doc/selfcmp.html @@ -185,7 +185,7 @@ <span class='Function'>âŠ</span> <span class='Function'>â·</span> <span class='Value'>c</span> ⟨ 0 1 2 ⟩ </pre> -<p>Applying both separately, in contrast, gives completely interesting results. These results contain all information from the original argument, as <code><span class='Function'>â·</span></code> indicates which cells it contained and <code><span class='Function'>âŠ</span></code> indicates where they were located. The function Select (<code><span class='Function'>âŠ</span></code>) reconstructs the argument from the two values.</p> +<p>Applying both separately, in contrast, gives completely interesting results. These results contain all information from the original argument, as <code><span class='Function'>â·</span></code> indicates which cells it contained and <code><span class='Function'>âŠ</span></code> indicates where they were located. The function <a href="select.html">Select</a> (<code><span class='Function'>âŠ</span></code>) reconstructs the argument from the two values.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4o23IGMK4oqQIGMKKOKKkGMpIOKKjyAo4o23Yyk=">↗ï¸</a><pre> <span class='Function'>â·</span> <span class='Value'>c</span> ┌─ ╵"yellow @@ -208,15 +208,15 @@ <p>Applying both Classify and Deduplicate gives an array that has both properties (this isn't the case for all pairs of projections—we need to know that Classify maintains the uniqueness property for Deduplicate and vice-versa). It has no duplicate major cells, <em>and</em> it's a list of natural numbers that starts with 0 and never goes up by more than one. Taken together, these are a tight constraint! The first element of the argument has to be 0. The next can't be 0 because it's already appeared, but it can't be more than one higher—it has to be 1. The next can't be 0 or 1, and has to be 2. And so on. So the result is always <code><span class='Function'>↕</span><span class='Value'>n</span></code> for some <code><span class='Value'>n</span></code>. In fact it's possible to determine the length as well, by noting that each function preserves the number of unique major cells in its argument. Classify does this because distinct numbers in the output correspond exactly to distinct major cells in the input; Deduplicate does this because it only removes duplicate cells, not distinct ones. So the final result is <code><span class='Function'>↕</span><span class='Value'>n</span></code>, where <code><span class='Value'>n</span></code> is the number of unique major cells in the argument.</p> <h3 id="mark-firsts">Mark Firsts</h3> <p><em>See the <a href="https://aplwiki.com/wiki/Unique_Mask">APL Wiki page</a> on this function as well.</em></p> -<p>Mark Firsts (<code><span class='Function'>∊</span></code>) is the simplest self-search function: it returns <code><span class='Number'>0</span></code> for any major cell of the argument that is a duplicate of an earlier cell and <code><span class='Number'>1</span></code> for a major cell that's the first with its value. To implement <a href="#deduplicate">Deduplicate</a> in terms of Mark Firsts, just filter out the duplicates with <code><span class='Function'>∊</span><span class='Modifier2'>⊸</span><span class='Function'>/</span></code>.</p> +<p>Mark Firsts (<code><span class='Function'>∊</span></code>) is the simplest self-search function: it returns <code><span class='Number'>0</span></code> for any major cell of the argument that is a duplicate of an earlier cell and <code><span class='Number'>1</span></code> for a major cell that's the first with its value. To implement <a href="#deduplicate">Deduplicate</a> in terms of Mark Firsts, just <a href="replicate.html">filter</a> out the duplicates with <code><span class='Function'>∊</span><span class='Modifier2'>⊸</span><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=4oiKICAgM+KAvzHigL804oC/MeKAvzXigL854oC/MuKAvzbigL81CgriiIriirgvIDPigL8x4oC/NOKAvzHigL814oC/OeKAvzLigL824oC/NQ==">↗ï¸</a><pre> <span class='Function'>∊</span> <span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>9</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Ligature'>‿</span><span class='Number'>5</span> ⟨ 1 1 1 0 1 1 1 1 0 ⟩ <span class='Function'>∊</span><span class='Modifier2'>⊸</span><span class='Function'>/</span> <span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>9</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Ligature'>‿</span><span class='Number'>5</span> ⟨ 3 1 4 5 9 2 6 ⟩ </pre> -<p>Mark Firsts has other uses, of course. Instead of keeping the unique values, you might remove the first of each value with <code><span class='Function'>¬</span><span class='Modifier2'>∘</span><span class='Function'>∊</span><span class='Modifier2'>⊸</span><span class='Function'>/</span></code>. You can use <code><span class='Function'>∧</span><span class='Modifier'>´</span><span class='Function'>∊</span></code> to check that an array has no duplicate major cells, or <code><span class='Function'>+</span><span class='Modifier'>´</span><span class='Modifier2'>∘</span><span class='Function'>∊</span></code> to count the number of unique ones.</p> -<p>What about marking the elements that appear exactly once? There's a trick for this: find the cells that are firsts running both forwards (<code><span class='Function'>∊</span></code>) and backwards (<code><span class='Function'>∊</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span></code>). Such a cell has no equal before it, nor after it, so it's unique in the entire array.</p> +<p>Mark Firsts has other uses, of course. Instead of keeping the unique values, you might remove the first of each value with <code><span class='Function'>¬</span><span class='Modifier2'>∘</span><span class='Function'>∊</span><span class='Modifier2'>⊸</span><span class='Function'>/</span></code>. You can use <code><span class='Function'>∧</span><span class='Modifier'>´</span><span class='Function'>∊</span></code> to check that an array has no duplicate major cells, or <code><span class='Function'>+</span><span class='Modifier'>´</span><span class='Function'>∊</span></code> to count the number of unique ones.</p> +<p>What about marking the elements that appear exactly once? There's a trick for this: find the cells that are firsts running both forwards (<code><span class='Function'>∊</span></code>) and <a href="reverse.html">backwards</a> (<code><span class='Function'>∊</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span></code>). Such a cell has no equal before it, nor after it, so it's unique in the entire array.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=KOKIiuKIp+KIiuKMvuKMvSkgImR1Y2si4oC/ImR1Y2si4oC/InRlYWwi4oC/ImR1Y2si4oC/Imdvb3NlIg==">↗ï¸</a><pre> <span class='Paren'>(</span><span class='Function'>∊∧∊</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span><span class='Paren'>)</span> <span class='String'>"duck"</span><span class='Ligature'>‿</span><span class='String'>"duck"</span><span class='Ligature'>‿</span><span class='String'>"teal"</span><span class='Ligature'>‿</span><span class='String'>"duck"</span><span class='Ligature'>‿</span><span class='String'>"goose"</span> ⟨ 0 0 1 0 1 ⟩ </pre> @@ -243,11 +243,11 @@ <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=KDE94oqSKeKKuC8gImFhYWFiY2RkY2Mi">↗ï¸</a><pre> <span class='Paren'>(</span><span class='Number'>1</span><span class='Function'>=⊒</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>/</span> <span class='String'>"aaaabcddcc"</span> "adc" </pre> -<p>An interesting combination is Occurrence Count applied to the result of Indices (<code><span class='Function'>/</span></code>). The result counts up to each number from the argument in turn; in other symbols, it's <code><span class='Function'>∾↕</span><span class='Modifier'>¨</span></code>. This version is interesting because it doesn't create any nested arrays, just lists of natural numbers.</p> +<p>An interesting combination is Occurrence Count applied to the result of <a href="replicate.html#indices">Indices</a> (<code><span class='Function'>/</span></code>). The result counts up to each number from the argument in turn; in other symbols, it's <code><span class='Function'>∾↕</span><span class='Modifier'>¨</span></code>. This version is interesting because it doesn't create any nested arrays, just lists of natural numbers.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqSIC8gMuKAvzPigL80">↗ï¸</a><pre> <span class='Function'>⊒</span> <span class='Function'>/</span> <span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>4</span> ⟨ 0 1 0 1 2 0 1 2 3 ⟩ </pre> -<p>A more efficient way when the interpreter doesn't optimize <code><span class='Function'>⊒</span></code> here is <code><span class='Function'>/</span><span class='Paren'>(</span><span class='Number'>¯1</span><span class='Modifier2'>⊸</span><span class='Function'>⊑↕</span><span class='Modifier2'>⊸</span><span class='Function'>-âŠ</span><span class='Modifier2'>⟜</span><span class='Function'>»</span><span class='Paren'>)</span><span class='Function'>+</span><span class='Modifier'>`</span></code>, but that's clearly quite a bit more complicated.</p> +<p>A more efficient way when <code><span class='Function'>⊒</span></code> doesn't have a fast implementation is <code><span class='Function'>/</span><span class='Paren'>(</span><span class='Number'>¯1</span><span class='Modifier2'>⊸</span><span class='Function'>⊑↕</span><span class='Modifier2'>⊸</span><span class='Function'>-âŠ</span><span class='Modifier2'>⟜</span><span class='Function'>»</span><span class='Paren'>)</span><span class='Function'>+</span><span class='Modifier'>`</span></code>, but that's clearly quite a bit more complicated.</p> <h3 id="deduplicate">Deduplicate</h3> <p><em>There's also an <a href="https://aplwiki.com/wiki/Unique">APL Wiki page</a> on this function.</em></p> <p>Deduplicate removes every major cell from the argument that matches an earlier cell, resulting in an array with the same rank but possibly a shorter length. It might also be described as returning the unique major cells of the argument, ordered by first occurrence. Deduplicate Under Reverse (<code><span class='Function'>â·</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span></code>) orders by last occurrence instead.</p> diff --git a/docs/doc/shape.html b/docs/doc/shape.html index 5852a698..118353c6 100644 --- a/docs/doc/shape.html +++ b/docs/doc/shape.html @@ -8,7 +8,7 @@ <p>The function Shape (<code><span class='Function'>≢</span></code>) returns an array's shape, and Rank (<code><span class='Function'>=</span></code>) and Length (<code><span class='Function'>≠</span></code>) return properties that can be derived from the shape. BQN's arrays are multidimensional, so that the shape is a list of natural numbers (the length along each axis), while the rank (length of the shape) and length (of the first axis) are numbers. In these functions, an atom is treated as a unit array, which has rank 0 and empty shape. A unit has no first axis, but its length is defined to be 1.</p> <p>Rank can be defined as <code><span class='Function'>≠</span><span class='Modifier2'>∘</span><span class='Function'>≢</span></code> while Length can be defined with a <a href="fold.html">fold</a> to be <code><span class='Number'>1</span><span class='Function'>⊣</span><span class='Modifier'>´</span><span class='Function'>≢</span></code>.</p> <h2 id="examples">Examples</h2> -<p>The function <a href="reshape.html">Reshape</a> (<code><span class='Function'>⥊</span></code>) always returns an array of shape <code><span class='Value'>ð•¨</span></code>, so we use it to make an array of shape <code><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span></code> in the example below (<a href="take.html">Take</a> (<code><span class='Function'>↑</span></code>) shares this property).</p> +<p>The function <a href="reshape.html">Reshape</a> (<code><span class='Function'>⥊</span></code>) always returns an array of shape <code><span class='Value'>ð•¨</span></code>, so we use it to make an array of shape <code><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span></code> in the example below (<a href="take.html">Take</a> (<code><span class='Function'>↑</span></code>) shares this property if <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>).</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqiIGFyciDihpAgMeKAvzPigL8y4oC/NiDipYogJzAnK+KGlTEwCgriiaIgYXJyICAjIFNoYXBlCgriiaAgYXJyICAjIExlbmd0aAoKPSBhcnIgICMgUmFuaw==">↗ï¸</a><pre> <span class='Function'>⊢</span> <span class='Value'>arr</span> <span class='Gets'>â†</span> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span> <span class='Function'>⥊</span> <span class='String'>'0'</span><span class='Function'>+↕</span><span class='Number'>10</span> ┌─ ┆"012345 @@ -30,11 +30,11 @@ <span class='Function'>=</span> <span class='Value'>arr</span> <span class='Comment'># Rank </span>4 </pre> -<p>The length is the first element of the shape, and the rank is the length of the shape—the number of axes. For another example, taking the first (and only) cell of <code><span class='Value'>arr</span></code> gives an array with shape <code><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span></code>, length <code><span class='Number'>3</span></code>, and rank <code><span class='Number'>3</span></code>, as we can see by applying each function to <code><span class='Function'>âŠ</span><span class='Value'>arr</span></code>.</p> +<p>The length is the first element of the shape, and the rank is the length of the shape—the number of axes. For another example, taking the first (and only) cell of <code><span class='Value'>arr</span></code> gives an array with shape <code><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>6</span></code>, length <code><span class='Number'>3</span></code>, and rank <code><span class='Number'>3</span></code>, as we can see by applying <a href="map.html#each">each</a> function to <code><span class='Function'>âŠ</span><span class='Value'>arr</span></code>.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omi4oC/PeKAv+KJoCB78J2VjvCdlal9wqg8IOKKj2Fycg==">↗ï¸</a><pre> <span class='Function'>≢</span><span class='Ligature'>‿</span><span class='Function'>=</span><span class='Ligature'>‿</span><span class='Function'>≠</span> <span class='Brace'>{</span><span class='Function'>ð•Ž</span><span class='Value'>ð•©</span><span class='Brace'>}</span><span class='Modifier'>¨</span><span class='Function'><</span> <span class='Function'>âŠ</span><span class='Value'>arr</span> ⟨ ⟨ 3 2 6 ⟩ 3 3 ⟩ </pre> -<p>Applying Shape and the other two functions to an atom shows a shape of <code><span class='Bracket'>⟨⟩</span></code>, the empty list, and a rank of zero and length of 1. The same is true of an enclosed array, which like an atom is a kind of unit.</p> +<p>Applying Shape and the other two functions to an atom shows a shape of <code><span class='Bracket'>⟨⟩</span></code> (the empty list), and a rank of zero and length of 1. The same is true of an enclosed array, which like an atom is a kind of unit.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiIDUKCig9IOKJjSDiiaApIDUKCig9IOKJjSDiiaApIDzihpUxMA==">↗ï¸</a><pre> <span class='Function'>≢</span> <span class='Number'>5</span> ⟨⟩ diff --git a/docs/doc/shift.html b/docs/doc/shift.html index 0d162721..c4b142c6 100644 --- a/docs/doc/shift.html +++ b/docs/doc/shift.html @@ -5,8 +5,8 @@ </head> <div class="nav"><a href="https://github.com/mlochbaum/BQN">BQN</a> / <a href="../index.html">main</a> / <a href="index.html">doc</a></div> <h1 id="shift-functions">Shift functions</h1> -<p>The shift functions <code><span class='Function'>«</span></code> and <code><span class='Function'>»</span></code> are two new primitives added to BQN based on a pattern used heavily in the compiler and a reasonable amount everywhere else. Shifts resemble but are more general than the bit-based shift operations used in low-level languages. They replace the APL pattern of a 2-wise reduction after appending or prepending an element (APL's <code><span class='Number'>2</span><span class='Function'>≠/</span><span class='Number'>0</span><span class='Separator'>,</span><span class='Value'>v</span></code> translates to <code><span class='Function'>»</span><span class='Modifier2'>⊸</span><span class='Function'>≠</span><span class='Value'>v</span></code>), one of the more common uses of 2-wise reduction.</p> -<p>The result of a shift function always has the same shape as its right argument. The function adds major cells to the beginning (<code><span class='Function'>»</span></code>) or end (<code><span class='Function'>«</span></code>) of <code><span class='Value'>ð•©</span></code>, moving the cells already in <code><span class='Value'>ð•©</span></code> to accomodate them. Some cells on the opposite side from those added will "fall off" and not be included in the result.</p> +<p>The shift functions <code><span class='Function'>«</span></code> and <code><span class='Function'>»</span></code> add major cells to one side an array, displacing cells on the opposite side and moving those in between. Shifts resemble but are more general than the bit-based shift operations used in low-level languages. They replace the APL pattern of a 2-wise reduction after appending or prepending an element (APL's <code><span class='Number'>2</span><span class='Function'>≠/</span><span class='Number'>0</span><span class='Separator'>,</span><span class='Value'>v</span></code> translates to <code><span class='Function'>»</span><span class='Modifier2'>⊸</span><span class='Function'>≠</span><span class='Value'>v</span></code>), one of the more common uses of 2-wise reduction.</p> +<p>The result of a shift function always has the same shape as <code><span class='Value'>ð•©</span></code>. The function adds major cells to the beginning (<code><span class='Function'>»</span></code>) or end (<code><span class='Function'>«</span></code>) of <code><span class='Value'>ð•©</span></code>, moving the cells already in <code><span class='Value'>ð•©</span></code> to accomodate them. Some cells on the opposite side from those added will "fall off" and not be included in the result.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MOKAvzAgwrsgM+KAvzLigL8xICAgICAgICAgICAgICMgU2hpZnQgQmVmb3JlCiJlbmQiIMKrICJhZGQgdG8gdGhlICIgICAjIFNoaWZ0IEFmdGVy">↗ï¸</a><pre> <span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>0</span> <span class='Function'>»</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='Comment'># Shift Before </span>⟨ 0 0 3 ⟩ <span class='String'>"end"</span> <span class='Function'>«</span> <span class='String'>"add to the "</span> <span class='Comment'># Shift After @@ -20,7 +20,7 @@ </pre> <p>If <code><span class='Value'>ð•¨</span></code> is longer than <code><span class='Value'>ð•©</span></code>, some cells from <code><span class='Value'>ð•¨</span></code> will be discarded, as well as all of <code><span class='Value'>ð•©</span></code>. In this case <code><span class='Value'>ð•¨</span><span class='Function'>»</span><span class='Value'>ð•©</span></code> is <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> and <code><span class='Value'>ð•¨</span><span class='Function'>«</span><span class='Value'>ð•©</span></code> is <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>. For similar reasons, nudging an array of length 0 returns it unchanged.</p> <h2 id="sequence-processing-with-shifts">Sequence processing with shifts</h2> -<p>When working with a sequence of data such as text, daily measurements, or audio data, shift functions are generally the best way to handle the concept of "next" or "previous" in the data. In the following example <code><span class='Value'>s</span></code> is shown alongside the shifted-right data <code><span class='Function'>»</span><span class='Value'>s</span></code>, and each element is compared to the previous with <code><span class='Function'>-</span><span class='Modifier2'>⟜</span><span class='Function'>»</span></code>, which we see is the inverse of <code><span class='Function'>+</span><span class='Modifier'>`</span></code>.</p> +<p>When working with a sequence of data such as text, daily measurements, or audio data, shift functions are generally the best way to handle the concept of "next" or "previous". In the following example <code><span class='Value'>s</span></code> is shown alongside the shifted-right data <code><span class='Function'>»</span><span class='Value'>s</span></code>, and each element is compared to the previous with <code><span class='Function'>-</span><span class='Modifier2'>⟜</span><span class='Function'>»</span></code>, which we see is the inverse of Plus <a href="scan.html">Scan</a> <code><span class='Function'>+</span><span class='Modifier'>`</span></code>.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=cyDihpAgMeKAvzLigL8y4oC/NOKAvzPigL814oC/NgpzIOKJjSDCu3MKLeKfnMK7IHMKCitgIC3in5zCuyBz">↗ï¸</a><pre> <span class='Value'>s</span> <span class='Gets'>â†</span> <span class='Number'>1</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'>4</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>6</span> <span class='Value'>s</span> <span class='Function'>â‰</span> <span class='Function'>»</span><span class='Value'>s</span> ┌─ @@ -34,8 +34,9 @@ ⟨ 1 2 2 4 3 5 6 ⟩ </pre> <p>In this way <code><span class='Function'>»</span></code> refers to a sequence containing the previous element at each position. By default the array's fill is used for the element before the first, and a right argument can be given to provide a different one.</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oieIMK7IHMK4oqP4oq4wrsgcw==">↗ï¸</a><pre> <span class='Number'>∞</span> <span class='Function'>»</span> <span class='Value'>s</span> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oieIMK7IHMKCuKKj+KKuMK7IHM=">↗ï¸</a><pre> <span class='Number'>∞</span> <span class='Function'>»</span> <span class='Value'>s</span> ⟨ ∞ 1 2 2 4 3 5 ⟩ + <span class='Function'>âŠ</span><span class='Modifier2'>⊸</span><span class='Function'>»</span> <span class='Value'>s</span> ⟨ 1 1 2 2 4 3 5 ⟩ </pre> @@ -76,17 +77,19 @@ </span>⟨ 1 1 1 1 0 0 1 1 ⟩ </pre> <h2 id="other-examples">Other examples</h2> -<p>In Take (<code><span class='Function'>↑</span></code>), there's no way to specify the fill element when the result is longer than the argument. To take along the first axis with a specified, constant fill value, you can use Shift Before instead, where the right argument is an array of fills with the desired final shape.</p> +<p>In <a href="take.html">Take</a> (<code><span class='Function'>↑</span></code>), there's no way to specify the fill element when the result is longer than the argument. To take along the first axis with a specified, constant fill value, you can use Shift Before instead, where the right argument is an array of fills with the desired final shape.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=ImFiYyIgwrsgNeKliidGJw==">↗ï¸</a><pre> <span class='String'>"abc"</span> <span class='Function'>»</span> <span class='Number'>5</span><span class='Function'>⥊</span><span class='String'>'F'</span> "abcFF" </pre> -<p>When using Scan (<code><span class='Modifier'>`</span></code>), the result at a particular index is obtained from values up to and including the one at that index. But it's common to want to use the values up to but not including that one instead. This can be done either by joining or shifting in that value before scanning. The difference is that with Join the result is longer than the argument. Either form might be wanted depending on how it will be used.</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=K2AgMeKAvzHigL8x4oC/MQoyICtg4oiY4oi+IDHigL8x4oC/MeKAvzEKMiArYOKImMK7IDHigL8x4oC/MeKAvzE=">↗ï¸</a><pre> <span class='Function'>+</span><span class='Modifier'>`</span> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span> -⟨ 1 2 3 4 ⟩ - <span class='Number'>2</span> <span class='Function'>+</span><span class='Modifier'>`</span><span class='Modifier2'>∘</span><span class='Function'>∾</span> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span> -⟨ 2 3 4 5 6 ⟩ - <span class='Number'>2</span> <span class='Function'>+</span><span class='Modifier'>`</span><span class='Modifier2'>∘</span><span class='Function'>»</span> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>1</span> -⟨ 2 3 4 5 ⟩ +<p>When using <a href="scan.html">Scan</a> (<code><span class='Modifier'>`</span></code>), the result at a particular index is obtained from values up to and including the one at that index. But it's common to want to use the values up to but not including that one instead. This can be done either by <a href="join.html#join-to">joining</a> or shifting in that value before scanning. The difference is that with Join the result is longer than the argument. Either form might be wanted depending on how it will be used.</p> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MiArYCAx4oC/MOKAvzHigL8wICAgICMgSW5pdGlhbCB2YWx1ZSBub3QgcmV0YWluZWQKCjIgK2DiiJjiiL4gMeKAvzDigL8x4oC/MCAgIyBBbGwgdmFsdWVzCgoyICtg4oiYwrsgMeKAvzDigL8x4oC/MCAgIyBGaW5hbCB2YWx1ZSBub3QgY3JlYXRlZA==">↗ï¸</a><pre> <span class='Number'>2</span> <span class='Function'>+</span><span class='Modifier'>`</span> <span class='Number'>1</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='Comment'># Initial value not retained +</span>⟨ 3 3 4 4 ⟩ + + <span class='Number'>2</span> <span class='Function'>+</span><span class='Modifier'>`</span><span class='Modifier2'>∘</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><span class='Ligature'>‿</span><span class='Number'>0</span> <span class='Comment'># All values +</span>⟨ 2 3 3 4 4 ⟩ + + <span class='Number'>2</span> <span class='Function'>+</span><span class='Modifier'>`</span><span class='Modifier2'>∘</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><span class='Ligature'>‿</span><span class='Number'>0</span> <span class='Comment'># Final value not created +</span>⟨ 2 3 3 4 ⟩ </pre> <p>The <em>strides</em> of an array are the distances between one element and the next along any given axis. It's the product of all axis lengths below that axis, since these are all the axes that have to be "skipped" to jump along the axis. The strides of an array <code><span class='Value'>ð•©</span></code> are <code><span class='Paren'>(</span><span class='Function'>×</span><span class='Modifier'>`</span><span class='Number'>1</span><span class='Function'>»⊢</span><span class='Paren'>)</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span><span class='Modifier2'>∘</span><span class='Function'>≢</span><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=KMOXYDHCu+KKoinijL7ijL0gNeKAvzLigL804oC/Mw==">↗ï¸</a><pre> <span class='Paren'>(</span><span class='Function'>×</span><span class='Modifier'>`</span><span class='Number'>1</span><span class='Function'>»⊢</span><span class='Paren'>)</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span> <span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>3</span> @@ -94,13 +97,14 @@ </pre> <h2 id="higher-rank">Higher rank</h2> <p>Shifting always works on the first axis of <code><span class='Value'>ð•©</span></code> (which must have rank 1 or more), and shifts in major cells. A left argument can have rank equal to <code><span class='Value'>ð•©</span></code>, or one less than it, in which case it becomes a single cell of the result. With no left argument, a cell of fills <code><span class='Number'>1</span><span class='Function'>↑</span><span class='Number'>0</span><span class='Function'>↑</span><span class='Value'>ð•©</span></code> is nudged in.</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqiIGEg4oaQIOKliuKfnCjihpXDl8K0KSA04oC/MwrCuyBhICAgICAgICAgICAgICAgICMgTnVkZ2UgYWRkcyBhIGNlbGwgb2YgZmlsbHMKIm9uZSIgwqsgYSAgICAgICAgICAjIFNoaWZ0IGluIGEgY2VsbAooInR3byLiiY0iY2VsIikgwqsgYSAgIyBTaGlmdCBpbiBtdWx0aXBsZSBjZWxscw==">↗ï¸</a><pre> <span class='Function'>⊢</span> <span class='Value'>a</span> <span class='Gets'>â†</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='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>3</span> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqiIGEg4oaQIOKliuKfnCjihpXDl8K0KSA04oC/MwoKwrsgYSAgICAgICAgICAgICAgICAjIE51ZGdlIGFkZHMgYSBjZWxsIG9mIGZpbGxzCgoib25lIiDCqyBhICAgICAgICAgICMgU2hpZnQgaW4gYSBjZWxsCgooInR3byLiiY0iY2VsIikgwqsgYSAgIyBTaGlmdCBpbiBtdWx0aXBsZSBjZWxscw==">↗ï¸</a><pre> <span class='Function'>⊢</span> <span class='Value'>a</span> <span class='Gets'>â†</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='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>3</span> ┌─ ╵ 0 1 2 3 4 5 6 7 8 9 10 11 ┘ + <span class='Function'>»</span> <span class='Value'>a</span> <span class='Comment'># Nudge adds a cell of fills </span>┌─ ╵ 0 0 0 @@ -108,6 +112,7 @@ 3 4 5 6 7 8 ┘ + <span class='String'>"one"</span> <span class='Function'>«</span> <span class='Value'>a</span> <span class='Comment'># Shift in a cell </span>┌─ ╵ 3 4 5 @@ -115,6 +120,7 @@ 9 10 11 'o' 'n' 'e' ┘ + <span class='Paren'>(</span><span class='String'>"two"</span><span class='Function'>â‰</span><span class='String'>"cel"</span><span class='Paren'>)</span> <span class='Function'>«</span> <span class='Value'>a</span> <span class='Comment'># Shift in multiple cells </span>┌─ ╵ 6 7 8 @@ -125,5 +131,5 @@ </pre> <h2 id="definition">Definition</h2> <p>In any instance of <code><span class='Function'>»</span></code> or <code><span class='Function'>«</span></code>, <code><span class='Value'>ð•©</span></code> must have rank at least 1.</p> -<p>For a dyadic shift function, <code><span class='Value'>ð•¨</span></code> must be Join-compatible with <code><span class='Value'>ð•©</span></code> (that is, <code><span class='Value'>ð•¨</span><span class='Function'>∾</span><span class='Value'>ð•©</span></code> completes without error) and cannot have greater rank than <code><span class='Value'>ð•©</span></code>. Then Shift Before (<code><span class='Function'>»</span></code>) is <code><span class='Brace'>{</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><span class='Function'>∾</span><span class='Value'>ð•©</span><span class='Brace'>}</span></code> and Shift After (<code><span class='Function'>«</span></code>) is <code><span class='Brace'>{</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><span class='Function'>∾</span><span class='Value'>ð•¨</span><span class='Brace'>}</span></code></p> +<p>For a dyadic shift function, <code><span class='Value'>ð•¨</span></code> must be <a href="join.html#join-to">Join</a>-compatible with <code><span class='Value'>ð•©</span></code> (that is, <code><span class='Value'>ð•¨</span><span class='Function'>∾</span><span class='Value'>ð•©</span></code> completes without error) and cannot have greater rank than <code><span class='Value'>ð•©</span></code>. Then Shift Before (<code><span class='Function'>»</span></code>) is <code><span class='Brace'>{</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><span class='Function'>∾</span><span class='Value'>ð•©</span><span class='Brace'>}</span></code> and Shift After (<code><span class='Function'>«</span></code>) is <code><span class='Brace'>{</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><span class='Function'>∾</span><span class='Value'>ð•¨</span><span class='Brace'>}</span></code></p> <p>When called monadically, the default argument is a cell of fills <code><span class='Number'>1</span><span class='Function'>↑</span><span class='Number'>0</span><span class='Function'>↑</span><span class='Value'>ð•©</span></code>. That is, Nudge (<code><span class='Function'>»</span></code>) is <code><span class='Paren'>(</span><span class='Number'>1</span><span class='Function'>↑</span><span class='Number'>0</span><span class='Function'>↑⊢</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>»</span></code> and Nudge Back (<code><span class='Function'>«</span></code>) is <code><span class='Paren'>(</span><span class='Number'>1</span><span class='Function'>↑</span><span class='Number'>0</span><span class='Function'>↑⊢</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>«</span></code>. This default argument always satisfies the compatibility requirement above and so the only conditions for nudge are that <code><span class='Value'>ð•©</span></code> has rank at least 1 and has a fill element.</p> diff --git a/docs/doc/train.html b/docs/doc/train.html index d55bb290..8800d7f5 100644 --- a/docs/doc/train.html +++ b/docs/doc/train.html @@ -5,7 +5,7 @@ </head> <div class="nav"><a href="https://github.com/mlochbaum/BQN">BQN</a> / <a href="../index.html">main</a> / <a href="index.html">doc</a></div> <h1 id="function-trains">Function trains</h1> -<p>Trains are an important aspect of BQN's <a href="tacit.html">tacit</a> programming capabilities. In fact, a crucial one: with trains and the identity functions Left (<code><span class='Function'>⊣</span></code>) and Right (<code><span class='Function'>⊢</span></code>), a fully tacit program can express any explicit function whose body is a statement with <code><span class='Value'>ð•¨</span></code> and <code><span class='Value'>ð•©</span></code> used only as arguments (that is, there are no assignments and <code><span class='Value'>ð•¨</span></code> and <code><span class='Value'>ð•©</span></code> are not used in operands or lists. Functions with assignments may have too many variables active at once to be directly translated but can be emulated by constructing lists. But it's probably a bad idea). Without trains it isn't possible to have two different functions that each use both arguments to a dyadic function. With trains it's perfectly natural.</p> +<p>Trains are an important aspect of BQN's <a href="tacit.html">tacit</a> programming capabilities. In fact, a crucial one: with trains and the <a href="identity.html">identity functions</a> Left (<code><span class='Function'>⊣</span></code>) and Right (<code><span class='Function'>⊢</span></code>), a fully tacit program can express any explicit function whose body is a statement with <code><span class='Value'>ð•¨</span></code> and <code><span class='Value'>ð•©</span></code> used only as arguments (that is, there are no assignments and <code><span class='Value'>ð•¨</span></code> and <code><span class='Value'>ð•©</span></code> are not used in operands or lists. Functions with assignments may have too many variables active at once to be directly translated but can be emulated by constructing lists. But it's probably a bad idea). Without trains it isn't possible to have two different functions that each use both arguments to a dyadic function. With trains it's perfectly natural.</p> <p>BQN's trains are the same as those of Dyalog APL, except that Dyalog is missing the minor convenience of BQN's Nothing (<code><span class='Nothing'>·</span></code>). There are many Dyalog-based documents and videos on trains you can view on the <a href="https://aplwiki.com/wiki/Train">APL Wiki</a>.</p> <h2 id="2-train-3-train">2-train, 3-train</h2> <p>Trains are an adaptation of the mathematical convention that, for example, two functions <code><span class='Function'>F</span></code> and <code><span class='Function'>G</span></code> can be added to get a new function <code><span class='Function'>F+G</span></code> that applies as <code><span class='Paren'>(</span><span class='Function'>F+G</span><span class='Paren'>)(</span><span class='Value'>x</span><span class='Paren'>)</span> <span class='Function'>=</span> <span class='Function'>F</span><span class='Paren'>(</span><span class='Value'>x</span><span class='Paren'>)</span><span class='Function'>+G</span><span class='Paren'>(</span><span class='Value'>x</span><span class='Paren'>)</span></code>. With a little change to the syntax, we can do exactly this in BQN:</p> @@ -24,7 +24,7 @@ <span class='Function'>∾</span><span class='Modifier2'>∘</span><span class='Function'>⌽</span> <span class='String'>"ab"</span><span class='Ligature'>‿</span><span class='String'>"cde"</span><span class='Ligature'>‿</span><span class='String'>"f"</span> "fcdeab" </pre> -<p>The three functions <code><span class='Function'>∾⌽</span></code>, <code><span class='Nothing'>·</span><span class='Function'>∾⌽</span></code>, and <code><span class='Function'>∾</span><span class='Modifier2'>∘</span><span class='Function'>⌽</span></code> are completely identical. Why might we want <strong>three</strong> different ways to write the same thing? If we only want to define a function, there's hardly any difference. However, these three forms have different syntax, and might be easier or harder to use in different contexts. As we'll see, we can use <code><span class='Function'>∾</span><span class='Modifier2'>∘</span><span class='Function'>⌽</span></code> inside a train without parenthesizing it, and string <code><span class='Nothing'>·</span><span class='Function'>∾⌽</span></code> but not <code><span class='Function'>∾⌽</span></code> together with other trains. Let's look at how the train syntax extends to longer expressions.</p> +<p>The three functions <code><span class='Function'>∾⌽</span></code>, <code><span class='Nothing'>·</span><span class='Function'>∾⌽</span></code>, and <code><span class='Function'>∾</span><span class='Modifier2'>∘</span><span class='Function'>⌽</span></code> are completely identical: <a href="join.html#join">Join</a> of <a href="reverse.html">Reverse</a>. Why might we want <strong>three</strong> different ways to write the same thing? If we only want to define a function, there's hardly any difference. However, these three forms have different syntax, and might be easier or harder to use in different contexts. As we'll see, we can use <code><span class='Function'>∾</span><span class='Modifier2'>∘</span><span class='Function'>⌽</span></code> inside a train without parenthesizing it, and string <code><span class='Nothing'>·</span><span class='Function'>∾⌽</span></code> but not <code><span class='Function'>∾⌽</span></code> together with other trains. Let's look at how the train syntax extends to longer expressions.</p> <h2 id="longer-trains">Longer trains</h2> <p>Function application in trains, as in other contexts, shares the lowest precedence level with assignment. Modifiers and strands (with <code><span class='Ligature'>‿</span></code>) have higher precedence, so they are applied before forming any trains. Once this is done, an expression is a <em>subject expression</em> if it ends with a subject and a <em>function expression</em> if it ends with a function (there are also modifier expressions, which aren't relevant here). A train is any function expression with multiple functions or subjects in it: while we've seen examples with two or three functions, any number are allowed.</p> <p>Subject expressions are the domain of "old-school" APL, and just apply one function after another to a subject, possibly assigning some of the results (that's the top-level picture—anything can still happen within parentheses). Subjects other than the first appear only as left arguments to functions, which means that two subjects can't appear next to each other because the one on the left would have no corresponding function. Here's an example from the compiler (at one point), with functions and assignments numbered in the order they are applied and their arguments marked with <code><span class='Function'>«»</span></code>, and a fully-parenthesized version shown below.</p> @@ -41,24 +41,24 @@ </pre> <p>In a train, arguments alternate strictly with combining functions between them. Arguments can be either functions or subjects, except for the rightmost one, which has to be a function to indicate that the expression is a train. Trains tend to be shorter than subject expressions partly because to keep track of this alternation in a train of all functions, you need to know where each function is relative to the end of the train (subjects like the <code><span class='Number'>¯1</span></code> above only occur as left arguments, so they can also serve as anchors).</p> <h2 id="practice-training">Practice training</h2> -<p>The train <code><span class='Function'>⊢></span><span class='Number'>¯1</span><span class='Function'>»⌈</span><span class='Modifier'>`</span></code> is actually a nice trick for marking first occurrences <code><span class='Function'>∊</span><span class='Value'>ð•©</span></code> given the self-classify <code><span class='Function'>âŠ</span><span class='Value'>ð•©</span></code> without doing another search. Let's take a closer look, first by applying it mechanically. To do this, we apply each "argument" to the train's argument, and then combine them with the combining functions.</p> +<p>The train <code><span class='Function'>⊢></span><span class='Number'>¯1</span><span class='Function'>»⌈</span><span class='Modifier'>`</span></code> is actually a nice trick to get the result of <a href="selfcmp.html#mark-firsts">Mark Firsts</a> <code><span class='Function'>∊</span><span class='Value'>ð•©</span></code> given the result of <a href="selfcmp.html#classify">Classify</a> <code><span class='Function'>âŠ</span><span class='Value'>ð•©</span></code>, without doing another search. Let's take a closer look, first by applying it mechanically. To do this, we apply each "argument" to the train's argument, and then combine them with the combining functions.</p> <pre><span class='Paren'>(</span><span class='Function'>⊢</span> <span class='Function'>></span> <span class='Number'>¯1</span> <span class='Function'>»</span> <span class='Function'>⌈</span><span class='Modifier'>`</span><span class='Paren'>)</span> <span class='Value'>ð•©</span> <span class='Paren'>(</span><span class='Function'>⊢</span><span class='Value'>ð•©</span><span class='Paren'>)</span> <span class='Function'>></span> <span class='Paren'>(</span><span class='Number'>¯1</span><span class='Paren'>)</span> <span class='Function'>»</span> <span class='Paren'>(</span><span class='Function'>⌈</span><span class='Modifier'>`</span><span class='Value'>ð•©</span><span class='Paren'>)</span> <span class='Value'>ð•©</span> <span class='Function'>></span> <span class='Number'>¯1</span> <span class='Function'>»</span> <span class='Function'>⌈</span><span class='Modifier'>`</span><span class='Value'>ð•©</span> </pre> <p>So—although not all trains simplify so much—this confusing train is just <code><span class='Brace'>{</span><span class='Value'>ð•©</span><span class='Function'>></span><span class='Number'>¯1</span><span class='Function'>»⌈</span><span class='Modifier'>`</span><span class='Value'>ð•©</span><span class='Brace'>}</span></code>! Why would I write it in such an obtuse way? To someone used to working with trains, the function <code><span class='Paren'>(</span><span class='Function'>⊢></span><span class='Number'>¯1</span><span class='Function'>»⌈</span><span class='Modifier'>`</span><span class='Paren'>)</span></code> isn't any more complicated to read: <code><span class='Function'>⊢</span></code> in an argument position of a train just means <code><span class='Value'>ð•©</span></code> while <code><span class='Function'>⌈</span><span class='Modifier'>`</span></code> will be applied to the arguments. Using the train just means slightly shorter code and two fewer <code><span class='Value'>ð•©</span></code>s to trip over.</p> -<p>This function's argument is the self-classify <code><span class='Function'>âŠ</span></code> of some list (in fact this technique also works on the self-indices <code><span class='Value'>ð•©</span><span class='Function'>âŠ</span><span class='Value'>ð•©</span></code>). Self-classify moves along its argument, giving each major cell a number: the first unused natural number if that value hasn't been seen yet, and otherwise the number chosen when it was first seen. It can be implemented as <code><span class='Function'>∊âŠâŠ¢</span></code>, another train!</p> +<p>This function's argument is Classify (<code><span class='Function'>âŠ</span></code>) of some list (in fact this technique also works on the <a href="search.html#index-of">index-of</a>-self <code><span class='Value'>ð•©</span><span class='Function'>âŠ</span><span class='Value'>ð•©</span></code>). Classify moves along its argument, giving each major cell a number: the first unused natural number if that value hasn't been seen yet, and otherwise the number chosen when it was first seen. It can be implemented as <code><span class='Function'>â·âŠâŠ¢</span></code>, another train!</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqiIHNjIOKGkCDiipAgInRhY2l0dHJhaW5zIg==">↗ï¸</a><pre> <span class='Function'>⊢</span> <span class='Value'>sc</span> <span class='Gets'>â†</span> <span class='Function'>âŠ</span> <span class='String'>"tacittrains"</span> ⟨ 0 1 2 3 0 0 4 1 3 5 6 ⟩ </pre> -<p>Each <code><span class='String'>'t'</span></code> is <code><span class='Number'>0</span></code>, each <code><span class='String'>'a'</span></code> is <code><span class='Number'>1</span></code>, and so on. We'd like to discard some of the information in the self-classify, to just find whether each major cell had a new value. Here are the input and desired result:</p> +<p>Each <code><span class='String'>'t'</span></code> is <code><span class='Number'>0</span></code>, each <code><span class='String'>'a'</span></code> is <code><span class='Number'>1</span></code>, and so on. We'd like to discard some of the information from Classify, to just find whether each major cell had a new value. Here are the input and desired result:</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=c2Mg4omNIOKIiiAidGFjaXR0cmFpbnMi">↗ï¸</a><pre> <span class='Value'>sc</span> <span class='Function'>â‰</span> <span class='Function'>∊</span> <span class='String'>"tacittrains"</span> ┌─ ╵ 0 1 2 3 0 0 4 1 3 5 6 1 1 1 1 0 0 1 0 0 1 1 ┘ </pre> -<p>The result should be <code><span class='Number'>1</span></code> when a new number appears, higher than all the previous numbers. To do this, we first find the highest previous number by taking the maximum-scan <code><span class='Function'>⌈</span><span class='Modifier'>`</span></code> of the argument, then <a href="shift.html">shifting</a> to move the previous maximum to the current position. The first cell is always new, so we shift in a <code><span class='Number'>¯1</span></code>, so it will be less than any element of the argument.</p> +<p>The result should be <code><span class='Number'>1</span></code> when a new number appears, higher than all the previous numbers. To do this, we first find the highest previous number by taking the <a href="arithmetic.html#additional-arithmetic">maximum</a>-<a href="scan.html">scan</a> <code><span class='Function'>⌈</span><span class='Modifier'>`</span></code> of the argument, then <a href="shift.html">shifting</a> to move the previous maximum to the current position. The first cell is always new, so we shift in a <code><span class='Number'>¯1</span></code>, so it will be less than any element of the argument.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=wq8xIMK7IOKMiGBzYwoowq8xwrvijIhgKSBzYw==">↗ï¸</a><pre> <span class='Number'>¯1</span> <span class='Function'>»</span> <span class='Function'>⌈</span><span class='Modifier'>`</span><span class='Value'>sc</span> ⟨ ¯1 0 1 2 3 3 3 4 4 4 5 ⟩ <span class='Paren'>(</span><span class='Number'>¯1</span><span class='Function'>»⌈</span><span class='Modifier'>`</span><span class='Paren'>)</span> <span class='Value'>sc</span> @@ -72,7 +72,7 @@ </pre> <h2 id="composing-trains">Composing trains</h2> <p>The example above uses a train with five functions: an odd number. Trains with an odd length are always composed of length-3 trains, and they themselves are composed the same way as subject expressions: an odd-length train can be placed in the last position of another train without parentheses, but it needs parentheses to go in any other position.</p> -<p>But we also saw the length-2 train <code><span class='Function'>∾⌽</span></code> above. Even-length trains consist of a single function (<code><span class='Function'>∾</span></code>) applied to a function or odd-length train (<code><span class='Function'>⌽</span></code>); another perspective is that an even-length train is an odd-length train where the left argument of the final (leftmost) function is left out, so it's called with only a right argument. An even-length train <em>always</em> needs parentheses if it's used as one of the functions in another train. However, it can also be turned into an odd-length train by placing <code><span class='Nothing'>·</span></code> at the left, making the implicit missing argument explicit. After this it can be used at the end of an odd-length train without parentheses. To get some intuition for even-length trains, let's look at an example of three functions used together: the unique (<code><span class='Function'>â·</span></code>) sorted (<code><span class='Function'>∧</span></code>) absolute values (<code><span class='Function'>|</span></code>) of an argument list.</p> +<p>But we also saw the length-2 train <code><span class='Function'>∾⌽</span></code> above. Even-length trains consist of a single function (<code><span class='Function'>∾</span></code>) applied to a function or odd-length train (<code><span class='Function'>⌽</span></code>); another perspective is that an even-length train is an odd-length train where the left argument of the final (leftmost) function is left out, so it's called with only a right argument. An even-length train <em>always</em> needs parentheses if it's used as one of the functions in another train. However, it can also be turned into an odd-length train by placing <code><span class='Nothing'>·</span></code> at the left, making the implicit missing argument explicit. After this it can be used at the end of an odd-length train without parentheses. To get some intuition for even-length trains, let's look at an example of three functions used together: the <a href="selfcmp.html#deduplicate">unique</a> (<code><span class='Function'>â·</span></code>) <a href="order.html#sort">sorted</a> (<code><span class='Function'>∧</span></code>) <a href="arithmetic.html#additional-arithmetic">absolute values</a> (<code><span class='Function'>|</span></code>) of an argument list.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4o234oinfCAz4oC/NOKAv8KvM+KAv8KvMuKAvzA=">↗ï¸</a><pre> <span class='Function'>â·âˆ§|</span> <span class='Number'>3</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'>¯2</span><span class='Ligature'>‿</span><span class='Number'>0</span> ⟨ 0 2 3 4 ⟩ </pre> diff --git a/docs/doc/transpose.html b/docs/doc/transpose.html index f86029a7..ee3e926c 100644 --- a/docs/doc/transpose.html +++ b/docs/doc/transpose.html @@ -5,7 +5,7 @@ </head> <div class="nav"><a href="https://github.com/mlochbaum/BQN">BQN</a> / <a href="../index.html">main</a> / <a href="index.html">doc</a></div> <h1 id="transpose">Transpose</h1> -<p>As in APL, Transpose (<code><span class='Function'>â‰</span></code>) is a tool for rearranging the axes of an array. BQN's version is tweaked to align better with the leading axis model and make common operations easier.</p> +<p>Transpose (<code><span class='Function'>â‰</span></code>) is a tool for rearranging the axes of an array. BQN's version is tweaked relative to APL to align better with the leading axis model and make common operations easier.</p> <h2 id="transpose-basics">Transpose basics</h2> <p>The name for the primitive <code><span class='Function'>â‰</span></code> comes from the <a href="https://en.wikipedia.org/wiki/Transpose">Transpose</a> operation on matrices. Given a matrix as an array of rank 2, <code><span class='Function'>â‰</span></code> will transpose it:</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqiIG1hdCDihpAgMuKAvzMg4qWKIOKGlTYK4o2JIG1hdA==">↗ï¸</a><pre> <span class='Function'>⊢</span> <span class='Value'>mat</span> <span class='Gets'>â†</span> <span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>3</span> <span class='Function'>⥊</span> <span class='Function'>↕</span><span class='Number'>6</span> @@ -29,13 +29,14 @@ <p>With two axes the only interesting operation of this sort is to swap them (and with one or zero axes there's nothing interesting to do, and <code><span class='Function'>â‰</span></code> just returns the argument array). But a BQN programmer may well want to work with higher-rank arrays—although such a programmer might call them "tensors"—and this means there are many more ways to rearrange the axes. Transpose extends to high-rank arrays to allow some useful special cases as well as completely general axis rearrangement, as described below.</p> <h2 id="monadic-transpose">Monadic Transpose</h2> <p>APL extends matrix transposition to any rank by reversing all axes for its monadic <code><span class='Function'>â‰</span></code>, but this generalization isn't very natural and is almost never used. The main reason for it is to maintain the equivalence <code><span class='Value'>a</span> <span class='Function'>MP</span> <span class='Value'>b</span> <span class='Gets'>â†â†’</span> <span class='Value'>b</span> <span class='Function'>MP</span><span class='Modifier2'>⌾</span><span class='Function'>â‰</span> <span class='Value'>a</span></code>, where <code><span class='Function'>MP</span> <span class='Gets'>â†</span> <span class='Function'>+</span><span class='Modifier'>Ë</span><span class='Modifier2'>∘</span><span class='Function'>×</span><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>∞</span></code> is the generalized matrix product. But even here APL's Transpose is suspect. It does much more work than it needs to, as we'll see.</p> -<p>BQN's transpose takes the first axis of its argument and moves it to the end.</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiIGEyMzQ1NiDihpAg4oaVMuKAvzPigL804oC/NeKAvzYK4omiIOKNiSBhMjM0NTY=">↗ï¸</a><pre> <span class='Function'>≢</span> <span class='Value'>a23456</span> <span class='Gets'>â†</span> <span class='Function'>↕</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>6</span> +<p>BQN's transpose takes the first axis of <code><span class='Value'>ð•©</span></code> and moves it to the end.</p> +<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiIGEyMzQ1NiDihpAg4oaVMuKAvzPigL804oC/NeKAvzYKCuKJoiDijYkgYTIzNDU2">↗ï¸</a><pre> <span class='Function'>≢</span> <span class='Value'>a23456</span> <span class='Gets'>â†</span> <span class='Function'>↕</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>6</span> ⟨ 2 3 4 5 6 ⟩ + <span class='Function'>≢</span> <span class='Function'>â‰</span> <span class='Value'>a23456</span> ⟨ 3 4 5 6 2 ⟩ </pre> -<p>In terms of the argument data as given by Deshape (<code><span class='Function'>⥊</span></code>), this looks like a simple 2-dimensional transpose: one axis is exchanged with a compound axis made up of the other axes. Here we transpose a rank 3 matrix:</p> +<p>In terms of the argument data as given by <a href="reshape.html#deshape">Deshape</a> (<code><span class='Function'>⥊</span></code>), this looks like a simple 2-dimensional transpose: one axis is exchanged with a compound axis made up of the other axes. Here we transpose a rank 3 matrix:</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=YTMyMiDihpAgM+KAvzLigL8y4qWK4oaVMTIK4omN4peLPOKfnOKNiSBhMzIy">↗ï¸</a><pre> <span class='Value'>a322</span> <span class='Gets'>â†</span> <span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Function'>⥊↕</span><span class='Number'>12</span> <span class='Function'>â‰</span><span class='Modifier2'>â—‹</span><span class='Function'><</span><span class='Modifier2'>⟜</span><span class='Function'>â‰</span> <span class='Value'>a322</span> ┌─ @@ -62,9 +63,10 @@ ┘ ┘ </pre> -<p>To exchange multiple axes, use the Power modifier. A negative power moves axes in the other direction, just like how Rotate handles negative left arguments. In particular, to move the last axis to the front, use Undo (as you might expect, this exactly inverts <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=4omiIOKNieKNnzMgYTIzNDU2CuKJoiDijYnigbwgYTIzNDU2">↗ï¸</a><pre> <span class='Function'>≢</span> <span class='Function'>â‰</span><span class='Modifier2'>âŸ</span><span class='Number'>3</span> <span class='Value'>a23456</span> +<p>To exchange multiple axes, use the <a href="repeat.html">Repeat</a> modifier. A negative power moves axes in the other direction, just like how <a href="reverse.html#rotate">Rotate</a> handles negative left arguments. In particular, to move the last axis to the front, use Undo (as you might expect, this exactly inverts <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=4omiIOKNieKNnzMgYTIzNDU2CgriiaIg4o2J4oG8IGEyMzQ1Ng==">↗ï¸</a><pre> <span class='Function'>≢</span> <span class='Function'>â‰</span><span class='Modifier2'>âŸ</span><span class='Number'>3</span> <span class='Value'>a23456</span> ⟨ 5 6 2 3 4 ⟩ + <span class='Function'>≢</span> <span class='Function'>â‰</span><span class='Modifier'>â¼</span> <span class='Value'>a23456</span> ⟨ 6 2 3 4 5 ⟩ </pre> @@ -73,11 +75,11 @@ <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiIOKNieKOiTMgYTIzNDU2">↗ï¸</a><pre> <span class='Function'>≢</span> <span class='Function'>â‰</span><span class='Modifier2'>⎉</span><span class='Number'>3</span> <span class='Value'>a23456</span> ⟨ 2 3 5 6 4 ⟩ </pre> -<p>And of course, Rank and Power can be combined to do more complicated transpositions: move a set of contiguous axes with any starting point and length to the end.</p> +<p>And of course, Rank and Repeat can be combined to do more complicated transpositions: move a set of contiguous axes with any starting point and length to the end.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiIOKNieKBvOKOicKvMSBhMjM0NTY=">↗ï¸</a><pre> <span class='Function'>≢</span> <span class='Function'>â‰</span><span class='Modifier'>â¼</span><span class='Modifier2'>⎉</span><span class='Number'>¯1</span> <span class='Value'>a23456</span> ⟨ 2 6 3 4 5 ⟩ </pre> -<p>Using these forms, we can state BQN's generalized matrix product swapping rule:</p> +<p>Using these forms (and the <a href="shape.html">Rank</a> function), we can state BQN's generalized matrix product swapping rule:</p> <pre><span class='Value'>a</span> <span class='Function'>MP</span> <span class='Value'>b</span> <span class='Gets'>â†â†’</span> <span class='Function'>â‰</span><span class='Modifier2'>âŸ</span><span class='Paren'>(</span><span class='Number'>1</span><span class='Function'>-=</span><span class='Value'>a</span><span class='Paren'>)</span> <span class='Paren'>(</span><span class='Function'>â‰</span><span class='Value'>b</span><span class='Paren'>)</span> <span class='Function'>MP</span> <span class='Paren'>(</span><span class='Function'>â‰</span><span class='Modifier'>â¼</span><span class='Value'>a</span><span class='Paren'>)</span> </pre> <p>Certainly not as concise as APL's version, but not a horror either. BQN's rule is actually more parsimonious in that it only performs the axis exchanges necessary for the computation: it moves the two axes that will be paired with the matrix product into place before the product, and directly exchanges all axes afterwards. Each of these steps is equivalent in terms of data movement to a matrix transpose, the simplest nontrivial transpose to perform. Also remember that for two-dimensional matrices both kinds of transposition are the same, so that APL's simpler rule <code><span class='Function'>MP</span> <span class='Function'>≡</span> <span class='Function'>MP</span><span class='Modifier2'>⌾</span><span class='Function'>â‰</span><span class='Modifier'>Ëœ</span></code> holds in BQN.</p> @@ -87,9 +89,10 @@ </pre> <p>In a case like this BQN's Dyadic transpose is much easier.</p> <h2 id="dyadic-transpose">Dyadic Transpose</h2> -<p>Transpose also allows a left argument that specifies a permutation of the right argument's axes. For each index <code><span class='Value'>p</span><span class='Gets'>â†</span><span class='Value'>i</span><span class='Function'>âŠ</span><span class='Value'>ð•¨</span></code> in the left argument, axis <code><span class='Value'>i</span></code> of the argument is used for axis <code><span class='Value'>p</span></code> of the result. Multiple argument axes can be sent to the same result axis, in which case that axis goes along a diagonal of the argument array, and the result will have a lower rank than the argument.</p> -<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiIDHigL8z4oC/MuKAvzDigL80IOKNiSBhMjM0NTYK4omiIDHigL8y4oC/MuKAvzDigL8wIOKNiSBhMjM0NTYgICMgRG9uJ3Qgd29ycnkgdG9vIG11Y2ggYWJvdXQgdGhpcyBjYXNlIHRob3VnaA==">↗ï¸</a><pre> <span class='Function'>≢</span> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>4</span> <span class='Function'>â‰</span> <span class='Value'>a23456</span> +<p>Transpose also allows a left argument that specifies a permutation of <code><span class='Value'>ð•©</span></code>'s axes. For each index <code><span class='Value'>p</span><span class='Gets'>â†</span><span class='Value'>i</span><span class='Function'>⊑</span><span class='Value'>ð•¨</span></code> in the left argument, axis <code><span class='Value'>i</span></code> of <code><span class='Value'>ð•©</span></code> is used for axis <code><span class='Value'>p</span></code> of the result. Multiple argument axes can be sent to the same result axis, in which case that axis goes along a diagonal of <code><span class='Value'>ð•©</span></code>, and the result will have a lower rank than <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=4omiIDHigL8z4oC/MuKAvzDigL80IOKNiSBhMjM0NTYKCuKJoiAx4oC/MuKAvzLigL8w4oC/MCDijYkgYTIzNDU2ICAjIERvbid0IHdvcnJ5IHRvbyBtdWNoIGFib3V0IHRoaXMgY2FzZSB0aG91Z2g=">↗ï¸</a><pre> <span class='Function'>≢</span> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>4</span> <span class='Function'>â‰</span> <span class='Value'>a23456</span> ⟨ 5 2 4 3 6 ⟩ + <span class='Function'>≢</span> <span class='Number'>1</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'>0</span><span class='Ligature'>‿</span><span class='Number'>0</span> <span class='Function'>â‰</span> <span class='Value'>a23456</span> <span class='Comment'># Don't worry too much about this case though </span>⟨ 5 2 3 ⟩ </pre> @@ -97,17 +100,17 @@ <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiIDHigL8z4oC/MuKAvzDigL80IOKNieKBvCBhMjM0NTY=">↗ï¸</a><pre> <span class='Function'>≢</span> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>4</span> <span class='Function'>â‰</span><span class='Modifier'>â¼</span> <span class='Value'>a23456</span> ⟨ 3 5 4 2 6 ⟩ </pre> -<p>So far, all like APL. BQN makes one little extension, which is to allow only some axes to be specified. The left argument will be matched up with leading axes of the right argument. Those axes are moved according to the left argument, and remaining axes are placed in order into the gaps between them.</p> +<p>So far, all like APL. BQN makes one little extension, which is to allow only some axes to be specified. Then <code><span class='Value'>ð•¨</span></code> will be matched up with <a href="leading.html">leading axes</a> of <code><span class='Value'>ð•©</span></code>. Those axes are moved according to <code><span class='Value'>ð•¨</span></code>, and remaining axes are placed in order into the gaps between them.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiIDDigL8y4oC/NCDijYkgYTIzNDU2">↗ï¸</a><pre> <span class='Function'>≢</span> <span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>4</span> <span class='Function'>â‰</span> <span class='Value'>a23456</span> ⟨ 2 5 3 6 4 ⟩ </pre> -<p>In particular, the case with only one argument specified is interesting. Here, the first axis ends up at the given location. This gives us a much better solution to the problem at the end of the last section.</p> +<p>In particular, the case with only one axis specified is interesting. Here, the first axis ends up at the given location. This gives us a much better solution to the problem at the end of the last section.</p> <a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiIDIg4o2JIGEyMzQ1NiAgIyBSZXN0cmljdCBUcmFuc3Bvc2UgdG8gdGhlIGZpcnN0IHRocmVlIGF4ZXM=">↗ï¸</a><pre> <span class='Function'>≢</span> <span class='Number'>2</span> <span class='Function'>â‰</span> <span class='Value'>a23456</span> <span class='Comment'># Restrict Transpose to the first three axes </span>⟨ 3 4 2 5 6 ⟩ </pre> <p>Finally, it's worth noting that, as monadic Transpose moves the first axis to the end, it's equivalent to dyadic Transpose with a "default" left argument: <code><span class='Paren'>(</span><span class='Function'>=-</span><span class='Number'>1</span><span class='Modifier'>Ë™</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>â‰</span></code>.</p> <h2 id="definitions">Definitions</h2> <p>Here we define the two valences of Transpose more precisely.</p> -<p>Monadic transpose is identical to <code><span class='Paren'>(</span><span class='Function'>=-</span><span class='Number'>1</span><span class='Modifier'>Ë™</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>â‰</span></code>, except that if the argument is a unit it is returned unchanged rather than giving an error.</p> -<p>An atom right argument to dyadic Transpose is always enclosed to get an array before doing anything else.</p> -<p>In dyadic Transpose, the left argument is a number or numeric array of rank 1 or less, and <code><span class='Value'>ð•¨</span><span class='Function'>≤</span><span class='Modifier2'>â—‹</span><span class='Function'>≠≢</span><span class='Value'>ð•©</span></code>. Define the result rank <code><span class='Value'>r</span><span class='Gets'>â†</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='Function'>¬∊</span><span class='Value'>ð•¨</span></code> to be the argument rank minus the number of duplicate entries in the left argument. We require <code><span class='Function'>∧</span><span class='Modifier'>´</span><span class='Value'>ð•¨</span><span class='Function'><</span><span class='Value'>r</span></code>. Bring <code><span class='Value'>ð•¨</span></code> to full length by appending the missing indices: <code><span class='Value'>ð•¨</span><span class='Function'>∾</span><span class='Gets'>↩</span><span class='Value'>ð•¨</span><span class='Paren'>(</span><span class='Function'>¬</span><span class='Modifier2'>∘</span><span class='Function'>∊</span><span class='Modifier'>Ëœ</span><span class='Function'>/⊢</span><span class='Paren'>)</span><span class='Function'>↕</span><span class='Value'>r</span></code>. Now the result shape is defined to be <code><span class='Function'>⌊</span><span class='Modifier'>´¨</span><span class='Value'>ð•¨</span><span class='Function'>⊔≢</span><span class='Value'>ð•©</span></code>. Element <code><span class='Value'>i</span><span class='Function'>⊑</span><span class='Value'>z</span></code> of the result <code><span class='Value'>z</span></code> is element <code><span class='Paren'>(</span><span class='Value'>ð•¨</span><span class='Function'>âŠ</span><span class='Value'>i</span><span class='Paren'>)</span><span class='Function'>⊑</span><span class='Value'>ð•©</span></code> of the argument.</p> +<p>An atom right argument to either valence of Transpose is always enclosed to get an array before doing anything else.</p> +<p>Monadic transpose is identical to <code><span class='Paren'>(</span><span class='Function'>=-</span><span class='Number'>1</span><span class='Modifier'>Ë™</span><span class='Paren'>)</span><span class='Modifier2'>⊸</span><span class='Function'>â‰</span></code>, except that if <code><span class='Value'>ð•©</span></code> is a unit it is returned unchanged (after enclosing, if it's an atom) rather than giving an error.</p> +<p>In dyadic Transpose, <code><span class='Value'>ð•¨</span></code> is a number or numeric array of rank 1 or less, and <code><span class='Value'>ð•¨</span><span class='Function'>≤</span><span class='Modifier2'>â—‹</span><span class='Function'>≠≢</span><span class='Value'>ð•©</span></code>. Define the result rank <code><span class='Value'>r</span><span class='Gets'>â†</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='Function'>¬∊</span><span class='Value'>ð•¨</span></code> to be the right argument rank minus the number of duplicate entries in the left argument. We require <code><span class='Function'>∧</span><span class='Modifier'>´</span><span class='Value'>ð•¨</span><span class='Function'><</span><span class='Value'>r</span></code>. Bring <code><span class='Value'>ð•¨</span></code> to full length by appending the missing indices: <code><span class='Value'>ð•¨</span><span class='Function'>∾</span><span class='Gets'>↩</span><span class='Value'>ð•¨</span><span class='Paren'>(</span><span class='Function'>¬</span><span class='Modifier2'>∘</span><span class='Function'>∊</span><span class='Modifier'>Ëœ</span><span class='Function'>/⊢</span><span class='Paren'>)</span><span class='Function'>↕</span><span class='Value'>r</span></code>. Now the result shape is defined to be <code><span class='Function'>⌊</span><span class='Modifier'>´¨</span><span class='Value'>ð•¨</span><span class='Function'>⊔≢</span><span class='Value'>ð•©</span></code>. Element <code><span class='Value'>i</span><span class='Function'>⊑</span><span class='Value'>z</span></code> of the result <code><span class='Value'>z</span></code> is element <code><span class='Paren'>(</span><span class='Value'>ð•¨</span><span class='Function'>âŠ</span><span class='Value'>i</span><span class='Paren'>)</span><span class='Function'>⊑</span><span class='Value'>ð•©</span></code> of the argument.</p> diff --git a/docs/doc/types.html b/docs/doc/types.html index f228bd0f..297989c1 100644 --- a/docs/doc/types.html +++ b/docs/doc/types.html @@ -42,23 +42,23 @@ </g> </svg> -<p>The reason operations and namespaces are called "mutable" is that the values obtained from them—by calling an operation on particular arguments or reading a field from a namespace—may change over the course of the program. This property is caused by variable modification <code><span class='Gets'>↩</span></code>, which can directly change a namespace field, or change the behavior of an operation that uses the modified variable. This means that a program that doesn't include <code><span class='Gets'>↩</span></code> won't have such changes in behavior. However, there will still be an observable difference between immutable data and the mutable types: code that creates a mutable value (for example, a block function <code><span class='Brace'>{</span><span class='Value'>ð•©</span><span class='Brace'>}</span></code>) creates a different one each time, so that two different instances don't match (<code><span class='Function'>≡</span></code>) each other. Data values created at different times may match, but mutable values never will.</p> +<p>The reason operations and namespaces are called "mutable" is that the values obtained from them—by calling an operation on particular arguments or reading a field from a namespace—may change over the course of the program. This property is caused by variable modification <code><span class='Gets'>↩</span></code>, which can directly change a namespace field, or change the behavior of an operation that uses the modified variable. This means that a program that doesn't include <code><span class='Gets'>↩</span></code> won't have such changes in behavior. However, there will still be an observable difference between immutable data and the mutable types: code that creates a mutable value (for example, a block function <code><span class='Brace'>{</span><span class='Value'>ð•©</span><span class='Brace'>}</span></code>) creates a different one each time, so that two different instances don't <a href="match.html">match</a> (<code><span class='Function'>≡</span></code>) each other. Data values created at different times may match, but mutable values never will.</p> <p>An array is considered immutable because its shape, and what elements it contains, cannot change. An array has no identity outside these properties (and possibly its fill element), so an array with a different shape or different elements would simply be a different array. However, any element of an array could be mutable, in which case the behavior of the array would change with respect to the operation of selecting that element and calling it or accessing a field.</p> <h2 id="data-types">Data types</h2> -<p>Data types—numbers, characters, and arrays—are more like "things" than "actions". If called as a function, a value of one of these types simply returns itself. Data can be uniquely represented, compared for equality, and ordered using BQN's array ordering; in contrast, determining whether two functions always return the same result can be undecidable. For arrays, these properties apply only if there are no operations inside. We might say that "data" in BQN refers to numbers, characters, and arrays of data.</p> +<p>Data types—numbers, characters, and arrays—are more like "things" than "actions". If called as a function, a value of one of these types simply returns itself. Data can be uniquely represented, compared for equality, and ordered using BQN's <a href="order.html#array-ordering">array ordering</a>; in contrast, determining whether two functions always return the same result can be undecidable. For arrays, these properties apply only if there are no operations inside. We might say that "data" in BQN refers to numbers, characters, and arrays of data.</p> <h3 id="numbers">Numbers</h3> <p>The BQN spec allows for different numeric models to be used, but requires there to be only one numeric type from the programmer's perspective: while programs can often be executed faster by using limited-range integer types, there is no need to expose these details to the programmer. Existing BQN implementations are based on <a href="https://en.wikipedia.org/wiki/IEEE-754">double-precision floats</a>, like Javascript or Lua.</p> <h3 id="characters">Characters</h3> <p>A character in BQN is always a <a href="https://en.wikipedia.org/wiki/Unicode">Unicode</a> code point. BQN does not use encodings such as UTF-8 or UTF-16 for characters, although it would be possible to store arrays of integers or characters that correspond to data in these encodings. Because every code point corresponds to a single unit in UTF-32, BQN characters can be thought of as UTF-32 encoded.</p> -<p>Addition and subtraction treat characters as an <a href="http://videocortex.io/2018/Affine-Space-Types/">affine space</a> relative to the linear space of numbers. This means that:</p> +<p>Addition and subtraction <a href="arithmetic.html#character-arithmetic">treat</a> characters as an <a href="http://videocortex.io/2018/Affine-Space-Types/">affine space</a> relative to the linear space of numbers. This means that:</p> <ul> <li>A number can be added to or subtracted from a character.</li> <li>Two characters can be subtracted to get the distance between them—a number.</li> </ul> <p>Other linear combinations such as adding two characters or negating a character are not allowed. You can check whether an application of <code><span class='Function'>+</span></code> or <code><span class='Function'>-</span></code> on numbers and characters is allowed by applying the same function to the "characterness" of each value: <code><span class='Number'>0</span></code> for a number and <code><span class='Number'>1</span></code> for a character. The result will be a number if this application gives <code><span class='Number'>0</span></code> and a character if this gives <code><span class='Number'>1</span></code>, and otherwise the operation is not allowed.</p> <h3 id="arrays">Arrays</h3> -<p>A BQN array is a multidimensional arrangement of data. This means it has a certain <em>shape</em>, which is a finite list of natural numbers giving the length along each axis, and it contains an <em>element</em> for each possible <em>index</em>, which is a choice of one natural number that's less than each axis length in the shape. The total number of elements, or <em>bound</em>, is then the product of all the lengths in the shape. The shape may have any length including zero, and this shape is known as the array's <em>rank</em>. An array of rank 0, which always contains exactly one element, is called a <em>unit</em>, while an array of rank 1 is called a <em>list</em> and an array of rank 2 is called a <em>table</em>.</p> -<p>Each array—empty or nonempty—has an inferred property called a <em>fill</em>. The fill either indicates what element should be used to pad an array, or that such an element is not known and an error should result. Fills are used by Take (<code><span class='Function'>↑</span></code>) and the two Nudge functions (<code><span class='Function'>»«</span></code>).</p> +<p>A BQN array is a multidimensional arrangement of data. This means it has a certain <a href="shape.html"><em>shape</em></a>, which is a finite list of natural numbers giving the length along each axis, and it contains an <em>element</em> for each possible <a href="indices.html"><em>index</em></a>, which is a choice of one natural number that's less than each axis length in the shape. The total number of elements, or <em>bound</em>, is then the product of all the lengths in the shape. The shape may have any length including zero, and this shape is known as the array's <em>rank</em>. An array of rank 0, which always contains exactly one element, is called a <em>unit</em>, while an array of rank 1 is called a <em>list</em> and an array of rank 2 is called a <em>table</em>.</p> +<p>Each array—empty or nonempty—has an inferred property called a <em>fill</em>. The fill either indicates what element should be used to pad an array, or that such an element is not known and an error should result. Fills can be used by <a href="take.html">Take</a> (<code><span class='Function'>↑</span></code>), the two <a href="shift.html">Nudge</a> functions (<code><span class='Function'>»«</span></code>), <a href="pick.html">First</a> (<code><span class='Function'>⊑</span></code>), and <a href="reshape.html">Reshape</a> (<code><span class='Function'>⥊</span></code>).</p> <p>Arrays are value types (or immutable), so that there is no way to "change" the shape or elements of an array. An array with different properties is a different array. As a consequence, arrays are an inductive type, and it's not possible for an array to contain itself, or contain an array that contains itself, and so on. However, it is possible for an array to contain a function or other operation that has access to the array through a variable, and in this sense an array can "know about" itself.</p> <p>Different elements of an array should not influence each other. While some APLs force numbers placed in the same array to a common representation, which may have different precision properties, BQN values must not change behavior when placed in an array. However, this doesn't preclude changing the storage type of an array for better performance: for example, in a BQN implementation using 64-bit floats, an array whose elements are all integers that fit in 32-bit int range might be represented as an array of 32-bit ints.</p> <h2 id="operation-types">Operation types</h2> diff --git a/docs/doc/windows.html b/docs/doc/windows.html index dc84bc73..bbfc50c3 100644 --- a/docs/doc/windows.html +++ b/docs/doc/windows.html @@ -16,8 +16,8 @@ cdefg" ┘ </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 spanned 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 <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> +<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> "cdefg" <span class='Number'>5</span><span class='Function'>↑</span><span class='Number'>2</span><span class='Function'>↓</span><span class='String'>"abcdefg"</span> @@ -48,12 +48,12 @@ ┘ </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 the left argument has length <code><span class='Number'>0</span></code>, then the argument 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 the same as the argument.</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">More formally</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">Symmetry</h2> -<p>Let's look at an earlier example, along with its transpose.</p> +<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> ┌─ · ┌─ ┌─ @@ -73,22 +73,23 @@ <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> 1 </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 Span, our slice-length to slice-number converter.</p> +<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">Applications</h2> -<p>Windows can be followed up with a reduction 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=K8K0y5gz4oaVIOKfqDIsNiwwLDEsNCwz4p+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> +<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 href="shift.html">shift functions</a> like <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 <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/MeKAvzEKKC3LnMud4omg4oaVMOKIvuKKoikgK2AgM+KAvzLigL8x4oC/MQ==">↗ï¸</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> +<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 above to keep the length constant by starting with two zeros.</p> +<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> |
