aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarshall Lochbaum <mwlochbaum@gmail.com>2022-05-27 21:48:16 -0400
committerMarshall Lochbaum <mwlochbaum@gmail.com>2022-05-27 21:48:16 -0400
commit525ac8dad3fb20a6db0606549dda94617373a396 (patch)
tree25c9c7a38e2416cbbb13f87c4e2428557d438302
parent5d063e99f26ca5566a14e711f846f78fa29e1eb5 (diff)
Finish Rank documentation
-rw-r--r--doc/rank.md54
-rw-r--r--docs/doc/rank.html63
2 files changed, 109 insertions, 8 deletions
diff --git a/doc/rank.md b/doc/rank.md
index 83a0972b..949640fd 100644
--- a/doc/rank.md
+++ b/doc/rank.md
@@ -137,10 +137,30 @@ The function `𝔽⎉k`, for `k≥0`, operates on the `k`-cells of its arguments
"∘∘" »⎉1 a
-The rank for a given argument is clamped, so that on a rank 3 argument for example, a rank of ¯5 counts as ¯3 and a rank of 6 counts as 3 (same for any other value less than ¯3 or greater than 3, although it does have to be a whole number). You may have noticed there's [no](../commentary/problems.md#rankdepth-negative-zero) option for ¯0, "don't map over anything", but ∞ serves that purpose as it indicates the highest possible rank and thus the entire array. More on why that's useful later.
+The rank for a given argument is clamped, so that on a rank 3 argument for example, a rank of ¯5 counts as ¯3 and a rank of 6 counts as 3 (same for any other value less than ¯3 or greater than 3, although it does have to be a whole number). You may have noticed there's [no](../commentary/problems.md#rankdepth-negative-zero) option for ¯0, "don't map over anything", but ∞ serves that purpose, as it indicates the highest possible rank and thus the entire array. More on why that's useful later.
### Frame and Cells
+Lets look at things more systematically. Suppose `x` has shape `4‿3‿2‿1‿0`, and we'd like to approach it with `⎉2`, or equivalently `⎉¯3`. This choice splits the axes of `x` into two parts: leading axes (shapes `4‿3‿2`) make up the *frame* of `x`, while trailing axes give the shape `1‿0` of each *cell* of `x`.
+
+ ≢ <⎉2 ↕4‿3‿2‿1‿0
+
+ ≢ ⊑ <⎉2 ↕4‿3‿2‿1‿0
+
+We can build a frame array using `<⎉2`, as shown above. In the general case, the frame remains conceptual: the actual array `<⎉2 x` is never created, and the result might also not have the shape `4‿3‿2`. But the result shape does always have `4‿3‿2` as a prefix. Rank maps over these axes, leaving them intact. And it can be defined in terms of the cell-splitting function `<⎉k`, and its inverse [Merge](couple.md#merge-and-array-theory) (`>`).
+
+ F⎉k x ←→ >F¨<⎉k x
+
+That is, `F⎉k` splits its argument into `k`-cells, applies `F` to each of these (in index order, of course), then merges the results into a single array.
+
+ +˝⎉1 4‿2⥊↕8
+
+ +˝¨<⎉1 4‿2⥊↕8 # +˝ of a list is a unit
+
+ >+˝¨<⎉1 4‿2⥊↕8
+
+Each can be implemented by acting on 0-cells with Rank too: `F⌾⊑⎉0 x ←→ F¨x`, meaning that `F¨` applies `F` to the interior of each 0-cell, that is, each element. Some half-way identities are `<∘F⎉k ←→ F¨<⎉k` and `F∘⊑⎉0 ←→ >F¨`.
+
### Multiple and computed ranks
The Rank modifier also accepts a list of one to three numbers for `𝕘`, as well as a function `𝔾` returning such a list. Practically speaking, here's what you need to know:
@@ -148,14 +168,42 @@ The Rank modifier also accepts a list of one to three numbers for `𝕘`, as wel
- A single number or one-element list indicates the ranks for all arguments.
- Two numbers indicate the ranks for `𝕨` and `𝕩`.
+As an example, we'll define the matrix-vector product. A matrix is a rank-2 array and a vector is a list, and their product is a list. It's made up of the elements `+´ row × vec` for each row `row` of the matrix. To define this using Rank, we'll change `+´` to `+˝` to get a unit out, and we need to map over the rows of the left argument but not of the right one. Following the rules above, there are several ways to do this, including `+˝∘×⎉1`, `+˝∘×⎉¯1‿1`, and `+˝∘×⎉¯1‿∞`. When correctly defined we can see that multiplication by the matrix `m` below negates the first element of a list, and also swaps it with the second.
+
⊢ m ← >⟨0‿1‿0,¯1‿0‿0,0‿0‿1⟩
+ +˝ 0‿1‿0 × 1‿2‿3
+
m +˝∘×⎉1‿∞ 1‿2‿3
+But a rank of `1‿∞` works the best because it also defines a matrix-*matrix* product. Which as shown below does the same transformation to the *cells* of the right-hand-side matrix, instead of the elements of a vector. This works because `×` and `+˝` work on the leading axes of their arguments. When `⎉1‿∞` is applied, these axes are the last axis of `𝕨` and the first axis of `𝕩`. Which… is kind of weird, but it's what a matrix product is.
+
+ +˝ 0‿1‿0 × 1‿2‿3×⌜1‿10
+
m +˝∘×⎉1‿∞ 1‿2‿3×⌜1‿10
+For completeness, here's the whole, boring description of how `𝔾` is handled. The operand `𝔾` is called on the arguments `𝕨𝔾𝕩` before doing anything else (if it's not a function, this just returns `𝕘`). Then it's converted to a list. It's required to have rank 0 or 1, but numbers and enclosed numbers are fine. This list can have one to three elements; three elements is the general case, as the elements give the ranks for monadic `𝕩`, dyadic `𝕨`, and dyadic `𝕩` in order. If there are less than three elements, the list `r` is expanded backwards-cyclically to `3⊸⥊⌾⌽r`, turning `⟨a⟩` into `a‿a‿a` and `a‿b` into `b‿a‿b`. So `3⊸⥊⌾⌽⥊𝕨𝔾𝕩` is the final formula.
+
+### Leading axis agreement
+
+In the preceding sections we've been somewhat loose with the way two arguments are paired up. The simple answer is [leading axis agreement](leading.md#leading-axis-agreement) on the frames.
+
+This is why the rank of `⎉1‿∞` that leads to a frame `⟨3⟩` on the left and `⟨⟩` on the right is fine: more generally, either argument can have a longer frame as long as the elements in the shorter one agree with it. So frames of `⟨3,2⟩` and `⟨3⟩` would also be fine, but `⟨2,3⟩` and `⟨3⟩` wouldn't: the first axes of these frames need to have the same length.
+
+ ≢ (↕3‿2‿5) ∾⎉1 (↕3‿4)
+
+ ≢ (↕2‿3‿5) ∾⎉1 (↕3‿4)
+
+On the other hand, Rank doesn't care about the argument cell shapes—it leaves that up to the function `𝔽`. If `𝔽` is an arithmetic function, you'll get *two* layers of prefix agreement: one outer matching with `⎉`, and an inner one with `𝔽`.
+
+It's also possible to apply multiple copies of Rank, which in general is powerful enough to match and not-match axes in any combination as long as the axes for each argument stay in order (of course, BQN also provides the tools to [reorder axes](transpose.md#dyadic-transpose)).
+
+One of the relatively more common instance of this pattern is a variation on the [Table](map.md#table) modifier, to work with cells instead of elements. Here we'll make a table of all combinations of one row (1-cell) from `𝕨` and one from `𝕩`. To do this, we want to first line up each row of `𝕨` with the whole of `𝕩`. As in a matrix product, that's `⎉1‿∞`. But then we'd like to pair that row with the rows of `𝕩` individually, which could be written `⎉∞‿1`. But since we know the left argument has been reduced to lists, `⎉1` also works. We then arrange the two layers of mapping with `⎉1` on the inside, giving `(∾⎉1)⎉1‿∞`.
+
("abc"≍"def") ∾⎉1⎉1‿∞ >"QR"‿"ST"‿"UV"
-Here's the full, boring description of how `𝔾` is handled. The operand `𝔾` is called on the arguments `𝕨𝔾𝕩` before doing anything else (if it's not a function, this just returns `𝕘`). Then it's converted to a list. It's required to have rank 0 or 1, but numbers and enclosed numbers are fine. This list can have one to three elements; three elements is the general case, as the elements give the ranks for monadic `𝕩`, dyadic `𝕨`, and dyadic `𝕩` in order. If there are less than three elements, the list `r` is expanded backwards-cyclically to `3⊸⥊⌾⌽r`, turning `⟨a⟩` into `a‿a‿a` and `a‿b` into `b‿a‿b`. So `3⊸⥊⌾⌽⥊𝕨𝔾𝕩` is the final formula.
+ ≢ ("abc"≍"def") ∾⎉1⎉1‿∞ >"QR"‿"ST"‿"UV"
-### Leading axis agreement
+ ≢ (↕3‿4‿5) ∾⎉1⎉1‿∞ ↕0‿1‿2‿8
+
+The flexibility of Rank also means we're able to apply this pattern with ranks other than 1. In particular, `𝔽⎉∞‿¯1⎉¯1‿∞` applies `𝔽` to all combinations of one major cell from either argument—an equivalent to `>𝔽⌜○(<˘)`. In this case the left rank of `𝔽⎉∞‿¯1` is unknown, so the only way to apply `𝔽` to the entire cell from `𝕨` is to use rank ∞.
diff --git a/docs/doc/rank.html b/docs/doc/rank.html
index a6752ea1..7253f3b1 100644
--- a/docs/doc/rank.html
+++ b/docs/doc/rank.html
@@ -210,23 +210,58 @@
∘∘qrstuv"
</pre>
-<p>The rank for a given argument is clamped, so that on a rank 3 argument for example, a rank of ¯5 counts as ¯3 and a rank of 6 counts as 3 (same for any other value less than ¯3 or greater than 3, although it does have to be a whole number). You may have noticed there's <a href="../commentary/problems.html#rankdepth-negative-zero">no</a> option for ¯0, &quot;don't map over anything&quot;, but ∞ serves that purpose as it indicates the highest possible rank and thus the entire array. More on why that's useful later.</p>
+<p>The rank for a given argument is clamped, so that on a rank 3 argument for example, a rank of ¯5 counts as ¯3 and a rank of 6 counts as 3 (same for any other value less than ¯3 or greater than 3, although it does have to be a whole number). You may have noticed there's <a href="../commentary/problems.html#rankdepth-negative-zero">no</a> option for ¯0, &quot;don't map over anything&quot;, but ∞ serves that purpose, as it indicates the highest possible rank and thus the entire array. More on why that's useful later.</p>
<h3 id="frame-and-cells"><a class="header" href="#frame-and-cells">Frame and Cells</a></h3>
+<p>Lets look at things more systematically. Suppose <code><span class='Value'>x</span></code> has shape <code><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'>1</span><span class='Ligature'>‿</span><span class='Number'>0</span></code>, and we'd like to approach it with <code><span class='Modifier2'>⎉</span><span class='Number'>2</span></code>, or equivalently <code><span class='Modifier2'>⎉</span><span class='Number'>¯3</span></code>. This choice splits the axes of <code><span class='Value'>x</span></code> into two parts: leading axes (shapes <code><span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span></code>) make up the <em>frame</em> of <code><span class='Value'>x</span></code>, while trailing axes give the shape <code><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>0</span></code> of each <em>cell</em> of <code><span class='Value'>x</span></code>.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiICAgPOKOiTIg4oaVNOKAvzPigL8y4oC/MeKAvzAKCuKJoiDiipEgPOKOiTIg4oaVNOKAvzPigL8y4oC/MeKAvzA=">↗️</a><pre> <span class='Function'>≢</span> <span class='Function'>&lt;</span><span class='Modifier2'>⎉</span><span class='Number'>2</span> <span class='Function'>↕</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'>1</span><span class='Ligature'>‿</span><span class='Number'>0</span>
+⟨ 4 3 2 ⟩
+
+ <span class='Function'>≢</span> <span class='Function'>⊑</span> <span class='Function'>&lt;</span><span class='Modifier2'>⎉</span><span class='Number'>2</span> <span class='Function'>↕</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'>1</span><span class='Ligature'>‿</span><span class='Number'>0</span>
+⟨ 1 0 ⟩
+</pre>
+<p>We can build a frame array using <code><span class='Function'>&lt;</span><span class='Modifier2'>⎉</span><span class='Number'>2</span></code>, as shown above. In the general case, the frame remains conceptual: the actual array <code><span class='Function'>&lt;</span><span class='Modifier2'>⎉</span><span class='Number'>2</span> <span class='Value'>x</span></code> is never created, and the result might also not have the shape <code><span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span></code>. But the result shape does always have <code><span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>2</span></code> as a prefix. Rank maps over these axes, leaving them intact. And it can be defined in terms of the cell-splitting function <code><span class='Function'>&lt;</span><span class='Modifier2'>⎉</span><span class='Value'>k</span></code>, and its inverse <a href="couple.html#merge-and-array-theory">Merge</a> (<code><span class='Function'>&gt;</span></code>).</p>
+<pre><span class='Function'>F</span><span class='Modifier2'>⎉</span><span class='Value'>k</span> <span class='Value'>x</span> <span class='Gets'>←→</span> <span class='Function'>&gt;F</span><span class='Modifier'>¨</span><span class='Function'>&lt;</span><span class='Modifier2'>⎉</span><span class='Value'>k</span> <span class='Value'>x</span>
+</pre>
+<p>That is, <code><span class='Function'>F</span><span class='Modifier2'>⎉</span><span class='Value'>k</span></code> splits its argument into <code><span class='Value'>k</span></code>-cells, applies <code><span class='Function'>F</span></code> to each of these (in index order, of course), then merges the results into a single array.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=K8ud4o6JMSA04oC/MuKliuKGlTgKCivLncKoPOKOiTEgNOKAvzLipYrihpU4ICAjICvLnSBvZiBhIGxpc3QgaXMgYSB1bml0Cgo+K8udwqg84o6JMSA04oC/MuKliuKGlTg=">↗️</a><pre> <span class='Function'>+</span><span class='Modifier'>˝</span><span class='Modifier2'>⎉</span><span class='Number'>1</span> <span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Function'>⥊↕</span><span class='Number'>8</span>
+⟨ 1 5 9 13 ⟩
+
+ <span class='Function'>+</span><span class='Modifier'>˝¨</span><span class='Function'>&lt;</span><span class='Modifier2'>⎉</span><span class='Number'>1</span> <span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Function'>⥊↕</span><span class='Number'>8</span> <span class='Comment'># +˝ of a list is a unit
+</span>┌─
+· ┌· ┌· ┌· ┌·
+ · 1 · 5 · 9 · 13
+ ┘ ┘ ┘ ┘
+ ┘
+
+ <span class='Function'>&gt;+</span><span class='Modifier'>˝¨</span><span class='Function'>&lt;</span><span class='Modifier2'>⎉</span><span class='Number'>1</span> <span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Function'>⥊↕</span><span class='Number'>8</span>
+⟨ 1 5 9 13 ⟩
+</pre>
+<p>Each can be implemented by acting on 0-cells with Rank too: <code><span class='Function'>F</span><span class='Modifier2'>⌾</span><span class='Function'>⊑</span><span class='Modifier2'>⎉</span><span class='Number'>0</span> <span class='Value'>x</span> <span class='Gets'>←→</span> <span class='Function'>F</span><span class='Modifier'>¨</span><span class='Value'>x</span></code>, meaning that <code><span class='Function'>F</span><span class='Modifier'>¨</span></code> applies <code><span class='Function'>F</span></code> to the interior of each 0-cell, that is, each element. Some half-way identities are <code><span class='Function'>&lt;</span><span class='Modifier2'>∘</span><span class='Function'>F</span><span class='Modifier2'>⎉</span><span class='Value'>k</span> <span class='Gets'>←→</span> <span class='Function'>F</span><span class='Modifier'>¨</span><span class='Function'>&lt;</span><span class='Modifier2'>⎉</span><span class='Value'>k</span></code> and <code><span class='Function'>F</span><span class='Modifier2'>∘</span><span class='Function'>⊑</span><span class='Modifier2'>⎉</span><span class='Number'>0</span> <span class='Gets'>←→</span> <span class='Function'>&gt;F</span><span class='Modifier'>¨</span></code>.</p>
<h3 id="multiple-and-computed-ranks"><a class="header" href="#multiple-and-computed-ranks">Multiple and computed ranks</a></h3>
<p>The Rank modifier also accepts a list of one to three numbers for <code><span class='Value'>𝕘</span></code>, as well as a function <code><span class='Function'>𝔾</span></code> returning such a list. Practically speaking, here's what you need to know:</p>
<ul>
<li>A single number or one-element list indicates the ranks for all arguments.</li>
<li>Two numbers indicate the ranks for <code><span class='Value'>𝕨</span></code> and <code><span class='Value'>𝕩</span></code>.</li>
</ul>
-<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqiIG0g4oaQID7in6gw4oC/MeKAvzAswq8x4oC/MOKAvzAsMOKAvzDigL8x4p+pCgptICvLneKImMOX4o6JMeKAv+KIniAx4oC/MuKAvzMKCm0gK8ud4oiYw5fijokx4oC/4oieIDHigL8y4oC/M8OX4oycMeKAvzEwCgooImFiYyLiiY0iZGVmIikg4oi+4o6JMeKOiTHigL/iiJ4gPiJRUiLigL8iU1Qi4oC/IlVWIg==">↗️</a><pre> <span class='Function'>⊢</span> <span class='Value'>m</span> <span class='Gets'>←</span> <span class='Function'>&gt;</span><span class='Bracket'>⟨</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='Separator'>,</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='Separator'>,</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='Bracket'>⟩</span>
+<p>As an example, we'll define the matrix-vector product. A matrix is a rank-2 array and a vector is a list, and their product is a list. It's made up of the elements <code><span class='Function'>+</span><span class='Modifier'>´</span> <span class='Value'>row</span> <span class='Function'>×</span> <span class='Value'>vec</span></code> for each row <code><span class='Value'>row</span></code> of the matrix. To define this using Rank, we'll change <code><span class='Function'>+</span><span class='Modifier'>´</span></code> to <code><span class='Function'>+</span><span class='Modifier'>˝</span></code> to get a unit out, and we need to map over the rows of the left argument but not of the right one. Following the rules above, there are several ways to do this, including <code><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></code>, <code><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'>1</span></code>, and <code><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>. When correctly defined we can see that multiplication by the matrix <code><span class='Value'>m</span></code> below negates the first element of a list, and also swaps it with the second.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqiIG0g4oaQID7in6gw4oC/MeKAvzAswq8x4oC/MOKAvzAsMOKAvzDigL8x4p+pCgory50gMOKAvzHigL8wIMOXIDHigL8y4oC/MwoKbSAry53iiJjDl+KOiTHigL/iiJ4gMeKAvzLigL8z">↗️</a><pre> <span class='Function'>⊢</span> <span class='Value'>m</span> <span class='Gets'>←</span> <span class='Function'>&gt;</span><span class='Bracket'>⟨</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='Separator'>,</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='Separator'>,</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='Bracket'>⟩</span>
┌─
╵ 0 1 0
¯1 0 0
0 0 1
+ <span class='Function'>+</span><span class='Modifier'>˝</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='Function'>×</span> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>3</span>
+┌·
+· 2
+ ┘
+
<span class='Value'>m</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> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>3</span>
⟨ 2 ¯1 3 ⟩
+</pre>
+<p>But a rank of <code><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>∞</span></code> works the best because it also defines a matrix-<em>matrix</em> product. Which as shown below does the same transformation to the <em>cells</em> of the right-hand-side matrix, instead of the elements of a vector. This works because <code><span class='Function'>×</span></code> and <code><span class='Function'>+</span><span class='Modifier'>˝</span></code> work on the leading axes of their arguments. When <code><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>∞</span></code> is applied, these axes are the last axis of <code><span class='Value'>𝕨</span></code> and the first axis of <code><span class='Value'>𝕩</span></code>. Which… is kind of weird, but it's what a matrix product is.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=K8udIDDigL8x4oC/MCDDlyAx4oC/MuKAvzPDl+KMnDHigL8xMAoKbSAry53iiJjDl+KOiTHigL/iiJ4gMeKAvzLigL8zw5fijJwx4oC/MTA=">↗️</a><pre> <span class='Function'>+</span><span class='Modifier'>˝</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='Function'>×</span> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Function'>×</span><span class='Modifier'>⌜</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>10</span>
+⟨ 2 20 ⟩
<span class='Value'>m</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> <span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>3</span><span class='Function'>×</span><span class='Modifier'>⌜</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>10</span>
┌─
@@ -234,8 +269,21 @@
¯1 ¯10
3 30
+</pre>
+<p>For completeness, here's the whole, boring description of how <code><span class='Function'>𝔾</span></code> is handled. The operand <code><span class='Function'>𝔾</span></code> is called on the arguments <code><span class='Value'>𝕨</span><span class='Function'>𝔾</span><span class='Value'>𝕩</span></code> before doing anything else (if it's not a function, this just returns <code><span class='Value'>𝕘</span></code>). Then it's converted to a list. It's required to have rank 0 or 1, but numbers and enclosed numbers are fine. This list can have one to three elements; three elements is the general case, as the elements give the ranks for monadic <code><span class='Value'>𝕩</span></code>, dyadic <code><span class='Value'>𝕨</span></code>, and dyadic <code><span class='Value'>𝕩</span></code> in order. If there are less than three elements, the list <code><span class='Value'>r</span></code> is expanded backwards-cyclically to <code><span class='Number'>3</span><span class='Modifier2'>⊸</span><span class='Function'>⥊</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span><span class='Value'>r</span></code>, turning <code><span class='Bracket'>⟨</span><span class='Value'>a</span><span class='Bracket'>⟩</span></code> into <code><span class='Value'>a</span><span class='Ligature'>‿</span><span class='Value'>a</span><span class='Ligature'>‿</span><span class='Value'>a</span></code> and <code><span class='Value'>a</span><span class='Ligature'>‿</span><span class='Value'>b</span></code> into <code><span class='Value'>b</span><span class='Ligature'>‿</span><span class='Value'>a</span><span class='Ligature'>‿</span><span class='Value'>b</span></code>. So <code><span class='Number'>3</span><span class='Modifier2'>⊸</span><span class='Function'>⥊</span><span class='Modifier2'>⌾</span><span class='Function'>⌽⥊</span><span class='Value'>𝕨</span><span class='Function'>𝔾</span><span class='Value'>𝕩</span></code> is the final formula.</p>
+<h3 id="leading-axis-agreement"><a class="header" href="#leading-axis-agreement">Leading axis agreement</a></h3>
+<p>In the preceding sections we've been somewhat loose with the way two arguments are paired up. The simple answer is <a href="leading.html#leading-axis-agreement">leading axis agreement</a> on the frames.</p>
+<p>This is why the rank of <code><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>∞</span></code> that leads to a frame <code><span class='Bracket'>⟨</span><span class='Number'>3</span><span class='Bracket'>⟩</span></code> on the left and <code><span class='Bracket'>⟨⟩</span></code> on the right is fine: more generally, either argument can have a longer frame as long as the elements in the shorter one agree with it. So frames of <code><span class='Bracket'>⟨</span><span class='Number'>3</span><span class='Separator'>,</span><span class='Number'>2</span><span class='Bracket'>⟩</span></code> and <code><span class='Bracket'>⟨</span><span class='Number'>3</span><span class='Bracket'>⟩</span></code> would also be fine, but <code><span class='Bracket'>⟨</span><span class='Number'>2</span><span class='Separator'>,</span><span class='Number'>3</span><span class='Bracket'>⟩</span></code> and <code><span class='Bracket'>⟨</span><span class='Number'>3</span><span class='Bracket'>⟩</span></code> wouldn't: the first axes of these frames need to have the same length.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiICjihpUz4oC/MuKAvzUpIOKIvuKOiTEgKOKGlTPigL80KQoK4omiICjihpUy4oC/M+KAvzUpIOKIvuKOiTEgKOKGlTPigL80KQ==">↗️</a><pre> <span class='Function'>≢</span> <span class='Paren'>(</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'>5</span><span class='Paren'>)</span> <span class='Function'>∾</span><span class='Modifier2'>⎉</span><span class='Number'>1</span> <span class='Paren'>(</span><span class='Function'>↕</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>4</span><span class='Paren'>)</span>
+⟨ 3 2 9 ⟩
- <span class='Paren'>(</span><span class='String'>&quot;abc&quot;</span><span class='Function'>≍</span><span class='String'>&quot;def&quot;</span><span class='Paren'>)</span> <span class='Function'>∾</span><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>∞</span> <span class='Function'>&gt;</span><span class='String'>&quot;QR&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;ST&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;UV&quot;</span>
+ <span class='Function'>≢</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='Ligature'>‿</span><span class='Number'>5</span><span class='Paren'>)</span> <span class='Function'>∾</span><span class='Modifier2'>⎉</span><span class='Number'>1</span> <span class='Paren'>(</span><span class='Function'>↕</span><span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>4</span><span class='Paren'>)</span>
+<span class='Error'>Error: Mapping: Argument shape prefixes don't agree</span>
+</pre>
+<p>On the other hand, Rank doesn't care about the argument cell shapes—it leaves that up to the function <code><span class='Function'>𝔽</span></code>. If <code><span class='Function'>𝔽</span></code> is an arithmetic function, you'll get <em>two</em> layers of prefix agreement: one outer matching with <code><span class='Modifier2'>⎉</span></code>, and an inner one with <code><span class='Function'>𝔽</span></code>.</p>
+<p>It's also possible to apply multiple copies of Rank, which in general is powerful enough to match and not-match axes in any combination as long as the axes for each argument stay in order (of course, BQN also provides the tools to <a href="transpose.html#dyadic-transpose">reorder axes</a>).</p>
+<p>One of the relatively more common instance of this pattern is a variation on the <a href="map.html#table">Table</a> modifier, to work with cells instead of elements. Here we'll make a table of all combinations of one row (1-cell) from <code><span class='Value'>𝕨</span></code> and one from <code><span class='Value'>𝕩</span></code>. To do this, we want to first line up each row of <code><span class='Value'>𝕨</span></code> with the whole of <code><span class='Value'>𝕩</span></code>. As in a matrix product, that's <code><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>∞</span></code>. But then we'd like to pair that row with the rows of <code><span class='Value'>𝕩</span></code> individually, which could be written <code><span class='Modifier2'>⎉</span><span class='Number'>∞</span><span class='Ligature'>‿</span><span class='Number'>1</span></code>. But since we know the left argument has been reduced to lists, <code><span class='Modifier2'>⎉</span><span class='Number'>1</span></code> also works. We then arrange the two layers of mapping with <code><span class='Modifier2'>⎉</span><span class='Number'>1</span></code> on the inside, giving <code><span class='Paren'>(</span><span class='Function'>∾</span><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Paren'>)</span><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>∞</span></code>.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=KCJhYmMi4omNImRlZiIpIOKIvuKOiTHijokx4oC/4oieID4iUVIi4oC/IlNUIuKAvyJVViIKCuKJoiAoImFiYyLiiY0iZGVmIikg4oi+4o6JMeKOiTHigL/iiJ4gPiJRUiLigL8iU1Qi4oC/IlVWIgoK4omiICjihpUz4oC/NOKAvzUpIOKIvuKOiTHijokx4oC/4oieIOKGlTDigL8x4oC/MuKAvzg=">↗️</a><pre> <span class='Paren'>(</span><span class='String'>&quot;abc&quot;</span><span class='Function'>≍</span><span class='String'>&quot;def&quot;</span><span class='Paren'>)</span> <span class='Function'>∾</span><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>∞</span> <span class='Function'>&gt;</span><span class='String'>&quot;QR&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;ST&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;UV&quot;</span>
┌─
╎"abcQR
abcST
@@ -245,6 +293,11 @@
defST
defUV"
+
+ <span class='Function'>≢</span> <span class='Paren'>(</span><span class='String'>&quot;abc&quot;</span><span class='Function'>≍</span><span class='String'>&quot;def&quot;</span><span class='Paren'>)</span> <span class='Function'>∾</span><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>∞</span> <span class='Function'>&gt;</span><span class='String'>&quot;QR&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;ST&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;UV&quot;</span>
+⟨ 2 3 5 ⟩
+
+ <span class='Function'>≢</span> <span class='Paren'>(</span><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'>5</span><span class='Paren'>)</span> <span class='Function'>∾</span><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Modifier2'>⎉</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>∞</span> <span class='Function'>↕</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>1</span><span class='Ligature'>‿</span><span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>8</span>
+⟨ 3 4 0 1 2 13 ⟩
</pre>
-<p>Here's the full, boring description of how <code><span class='Function'>𝔾</span></code> is handled. The operand <code><span class='Function'>𝔾</span></code> is called on the arguments <code><span class='Value'>𝕨</span><span class='Function'>𝔾</span><span class='Value'>𝕩</span></code> before doing anything else (if it's not a function, this just returns <code><span class='Value'>𝕘</span></code>). Then it's converted to a list. It's required to have rank 0 or 1, but numbers and enclosed numbers are fine. This list can have one to three elements; three elements is the general case, as the elements give the ranks for monadic <code><span class='Value'>𝕩</span></code>, dyadic <code><span class='Value'>𝕨</span></code>, and dyadic <code><span class='Value'>𝕩</span></code> in order. If there are less than three elements, the list <code><span class='Value'>r</span></code> is expanded backwards-cyclically to <code><span class='Number'>3</span><span class='Modifier2'>⊸</span><span class='Function'>⥊</span><span class='Modifier2'>⌾</span><span class='Function'>⌽</span><span class='Value'>r</span></code>, turning <code><span class='Bracket'>⟨</span><span class='Value'>a</span><span class='Bracket'>⟩</span></code> into <code><span class='Value'>a</span><span class='Ligature'>‿</span><span class='Value'>a</span><span class='Ligature'>‿</span><span class='Value'>a</span></code> and <code><span class='Value'>a</span><span class='Ligature'>‿</span><span class='Value'>b</span></code> into <code><span class='Value'>b</span><span class='Ligature'>‿</span><span class='Value'>a</span><span class='Ligature'>‿</span><span class='Value'>b</span></code>. So <code><span class='Number'>3</span><span class='Modifier2'>⊸</span><span class='Function'>⥊</span><span class='Modifier2'>⌾</span><span class='Function'>⌽⥊</span><span class='Value'>𝕨</span><span class='Function'>𝔾</span><span class='Value'>𝕩</span></code> is the final formula.</p>
-<h3 id="leading-axis-agreement"><a class="header" href="#leading-axis-agreement">Leading axis agreement</a></h3>
+<p>The flexibility of Rank also means we're able to apply this pattern with ranks other than 1. In particular, <code><span class='Function'>𝔽</span><span class='Modifier2'>⎉</span><span class='Number'>∞</span><span class='Ligature'>‿</span><span class='Number'>¯1</span><span class='Modifier2'>⎉</span><span class='Number'>¯1</span><span class='Ligature'>‿</span><span class='Number'>∞</span></code> applies <code><span class='Function'>𝔽</span></code> to all combinations of one major cell from either argument—an equivalent to <code><span class='Function'>&gt;𝔽</span><span class='Modifier'>⌜</span><span class='Modifier2'>○</span><span class='Paren'>(</span><span class='Function'>&lt;</span><span class='Modifier'>˘</span><span class='Paren'>)</span></code>. In this case the left rank of <code><span class='Function'>𝔽</span><span class='Modifier2'>⎉</span><span class='Number'>∞</span><span class='Ligature'>‿</span><span class='Number'>¯1</span></code> is unknown, so the only way to apply <code><span class='Function'>𝔽</span></code> to the entire cell from <code><span class='Value'>𝕨</span></code> is to use rank ∞.</p>