aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarshall Lochbaum <mwlochbaum@gmail.com>2021-11-13 15:37:14 -0500
committerMarshall Lochbaum <mwlochbaum@gmail.com>2021-11-13 15:37:14 -0500
commit7faf96746f2d9a051c048b312480583494b5ee7b (patch)
tree6f26ce7cfab803126945e074c8e2eab8d97008d7
parentdaf62afe673613c8a90f5d9e494ede2ccaf7ef72 (diff)
Add multidimensional Join to docs
-rw-r--r--doc/join.md19
-rw-r--r--docs/doc/join.html38
2 files changed, 46 insertions, 11 deletions
diff --git a/doc/join.md b/doc/join.md
index f244db59..656a12db 100644
--- a/doc/join.md
+++ b/doc/join.md
@@ -42,16 +42,25 @@ To join with a separator in between, we might prepend the separator to each stri
1↓∾' '∾¨"time"‿"to"‿"join"‿"some"‿"words"
-Join requires each element of its argument to be an array, and their ranks to match exactly. No rank extension is performed.
+Join also extends the rank of a unit element (including an atom) to allow it to fit into the list. The highest-rank element determines the rank of the result.
- ∾"abc"‿'d'‿"ef" # Includes an atom
- ∾"abc"‿(<'d')‿"ef" # Includes a unit
+ ∾"abc"‿'d'‿"ef"‿(<'g')
+
+ ∾"abcd" # Result has to be rank 0, impossible
However, Join has higher-dimensional uses as well. Given a rank-`m` array of rank-`n` arrays (requiring `m≤n`), it will merge arrays along their first `m` axes. For example, if the argument is a matrix of matrices representing a [block matrix](https://en.wikipedia.org/wiki/Block_matrix), Join will give the corresponding unblocked matrix as its result.
⊢ m ← (3‿1≍⌜4‿2‿5) ⥊¨ 2‿3⥊↕6
∾ m # Join all that together
-Join has fairly strict requirements on the shapes of its argument elements—although less strict than those of Merge, which requires they all have identical shape. Suppose the argument to Join has rank `m`. Each of its elements must have the same rank, `n`, which is at least `m`. The trailing shapes `m↓⟜≢¨𝕩` must all be identical (the trailing shape `m↓≢∾𝕩` of the result will match these shapes as well). The other entries in the leading shapes need not be the same, but the shape of an element along a particular axis must depend only on the location of the element along that axis in the full array. For a list argument this imposes no restriction, since the one leading shape element is allowed to depend on position along the only axis. But for higher ranks the structure quickly becomes more rigid.
+Axes with length 1 in the argument can also be left out, if it's done consistently for all elements in that position. One use of this is to add borders to an array, as in the multiplication table below.
+
+ ⊢ n ← 2‿4‿6 ×{⟨𝕗,𝕩⟩≍⟨𝕨,𝕨𝔽⌜𝕩⟩} 5‿6‿7‿8
+
+ ≢¨ n # Different ranks but compatible shapes
+
+ ∾ n
+
+Even with the extension, Join has fairly strict requirements on the shapes of its argument elements—although less strict than those of Merge, which requires they all have identical shape. Suppose the argument to Join has rank `m`. The highest element rank (call it `n`) must be at least `m`. The trailing shapes `(-n-m)↑⟜≢¨𝕩` must all be identical (the trailing shape `(-n-m)↑≢∾𝕩` of the result will match these shapes as well). The other entries in the leading shapes need not be the same, but the shape of an element along a particular axis must depend only on the location of the element along that axis in the full array. For a list argument this imposes no restriction, since the one leading shape element is allowed to depend on position along the only axis. But for higher ranks the structure quickly becomes more rigid.
-To state this requirement more formally in BQN, we say that there is some list `s` of lists of lengths, so that `(≢¨s)≡≢𝕩`. We require element `i⊑𝕩` to have shape `i⊑¨s`. Then the first `m` axes of the result are `+´¨s`.
+To state this requirement more formally in BQN, we say that there is some list `s` of lists of lengths, so that `(≢¨s)≡≢𝕩`. We require element `i⊑𝕩` to have shape `i⊑¨s`. Then the first `m` axes of the result are `+´¨s`. To handle omitted axes, we change `s` to contain lists of length 0 or 1 instead of lengths, and require `i⊑𝕩` to have shape `∾i⊑¨s` instead. In the result, an omitted axis behaves exactly like a length-1 axis, so the result can be found using shapes derived from `1⊣´¨¨s`.
diff --git a/docs/doc/join.html b/docs/doc/join.html
index 220c6631..56975907 100644
--- a/docs/doc/join.html
+++ b/docs/doc/join.html
@@ -60,10 +60,11 @@
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=MeKGk+KIvicgJ+KIvsKoInRpbWUi4oC/InRvIuKAvyJqb2luIuKAvyJzb21lIuKAvyJ3b3JkcyI=">↗️</a><pre> <span class='Number'>1</span><span class='Function'>↓∾</span><span class='String'>' '</span><span class='Function'>∾</span><span class='Modifier'>¨</span><span class='String'>&quot;time&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;to&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;join&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;some&quot;</span><span class='Ligature'>‿</span><span class='String'>&quot;words&quot;</span>
"time to join some words"
</pre>
-<p>Join requires each element of its argument to be an array, and their ranks to match exactly. No rank extension is performed.</p>
-<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oi+ImFiYyLigL8nZCfigL8iZWYiICAjIEluY2x1ZGVzIGFuIGF0b20K4oi+ImFiYyLigL8oPCdkJynigL8iZWYiICAjIEluY2x1ZGVzIGEgdW5pdA==">↗️</a><pre> <span class='Function'>∾</span><span class='String'>&quot;abc&quot;</span><span class='Ligature'>‿</span><span class='String'>'d'</span><span class='Ligature'>‿</span><span class='String'>&quot;ef&quot;</span> <span class='Comment'># Includes an atom
-</span>ERROR
- <span class='Function'>∾</span><span class='String'>&quot;abc&quot;</span><span class='Ligature'>‿</span><span class='Paren'>(</span><span class='Function'>&lt;</span><span class='String'>'d'</span><span class='Paren'>)</span><span class='Ligature'>‿</span><span class='String'>&quot;ef&quot;</span> <span class='Comment'># Includes a unit
+<p>Join also extends the rank of a unit element (including an atom) to allow it to fit into the list. The highest-rank element determines the rank of the result.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oi+ImFiYyLigL8nZCfigL8iZWYi4oC/KDwnZycpCgriiL4iYWJjZCIgICMgUmVzdWx0IGhhcyB0byBiZSByYW5rIDAsIGltcG9zc2libGU=">↗️</a><pre> <span class='Function'>∾</span><span class='String'>&quot;abc&quot;</span><span class='Ligature'>‿</span><span class='String'>'d'</span><span class='Ligature'>‿</span><span class='String'>&quot;ef&quot;</span><span class='Ligature'>‿</span><span class='Paren'>(</span><span class='Function'>&lt;</span><span class='String'>'g'</span><span class='Paren'>)</span>
+"abcdefg"
+
+ <span class='Function'>∾</span><span class='String'>&quot;abcd&quot;</span> <span class='Comment'># Result has to be rank 0, impossible
</span>ERROR
</pre>
<p>However, Join has higher-dimensional uses as well. Given a rank-<code><span class='Value'>m</span></code> array of rank-<code><span class='Value'>n</span></code> arrays (requiring <code><span class='Value'>m</span><span class='Function'>≤</span><span class='Value'>n</span></code>), it will merge arrays along their first <code><span class='Value'>m</span></code> axes. For example, if the argument is a matrix of matrices representing a <a href="https://en.wikipedia.org/wiki/Block_matrix">block matrix</a>, Join will give the corresponding unblocked matrix as its result.</p>
@@ -86,5 +87,30 @@
3 3 3 3 4 4 5 5 5 5 5
</pre>
-<p>Join has fairly strict requirements on the shapes of its argument elements—although less strict than those of Merge, which requires they all have identical shape. Suppose the argument to Join has rank <code><span class='Value'>m</span></code>. Each of its elements must have the same rank, <code><span class='Value'>n</span></code>, which is at least <code><span class='Value'>m</span></code>. The trailing shapes <code><span class='Value'>m</span><span class='Function'>↓</span><span class='Modifier2'>⟜</span><span class='Function'>≢</span><span class='Modifier'>¨</span><span class='Value'>𝕩</span></code> must all be identical (the trailing shape <code><span class='Value'>m</span><span class='Function'>↓≢∾</span><span class='Value'>𝕩</span></code> of the result will match these shapes as well). The other entries in the leading shapes need not be the same, but the shape of an element along a particular axis must depend only on the location of the element along that axis in the full array. For a list argument this imposes no restriction, since the one leading shape element is allowed to depend on position along the only axis. But for higher ranks the structure quickly becomes more rigid.</p>
-<p>To state this requirement more formally in BQN, we say that there is some list <code><span class='Value'>s</span></code> of lists of lengths, so that <code><span class='Paren'>(</span><span class='Function'>≢</span><span class='Modifier'>¨</span><span class='Value'>s</span><span class='Paren'>)</span><span class='Function'>≡≢</span><span class='Value'>𝕩</span></code>. We require element <code><span class='Value'>i</span><span class='Function'>⊑</span><span class='Value'>𝕩</span></code> to have shape <code><span class='Value'>i</span><span class='Function'>⊑</span><span class='Modifier'>¨</span><span class='Value'>s</span></code>. Then the first <code><span class='Value'>m</span></code> axes of the result are <code><span class='Function'>+</span><span class='Modifier'>´¨</span><span class='Value'>s</span></code>.</p>
+<p>Axes with length 1 in the argument can also be left out, if it's done consistently for all elements in that position. One use of this is to add borders to an array, as in the multiplication table below.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqiIG4g4oaQIDLigL804oC/NiDDl3vin6jwnZWXLPCdlanin6niiY3in6jwnZWoLPCdlajwnZS94oyc8J2VqeKfqX0gNeKAvzbigL834oC/OAoK4omiwqggbiAgIyBEaWZmZXJlbnQgcmFua3MgYnV0IGNvbXBhdGlibGUgc2hhcGVzCgriiL4gbg==">↗️</a><pre> <span class='Function'>⊢</span> <span class='Value'>n</span> <span class='Gets'>←</span> <span class='Number'>2</span><span class='Ligature'>‿</span><span class='Number'>4</span><span class='Ligature'>‿</span><span class='Number'>6</span> <span class='Function'>×</span><span class='Brace'>{</span><span class='Bracket'>⟨</span><span class='Value'>𝕗</span><span class='Separator'>,</span><span class='Value'>𝕩</span><span class='Bracket'>⟩</span><span class='Function'>≍</span><span class='Bracket'>⟨</span><span class='Value'>𝕨</span><span class='Separator'>,</span><span class='Value'>𝕨</span><span class='Function'>𝔽</span><span class='Modifier'>⌜</span><span class='Value'>𝕩</span><span class='Bracket'>⟩</span><span class='Brace'>}</span> <span class='Number'>5</span><span class='Ligature'>‿</span><span class='Number'>6</span><span class='Ligature'>‿</span><span class='Number'>7</span><span class='Ligature'>‿</span><span class='Number'>8</span>
+┌─
+╵ × ⟨ 5 6 7 8 ⟩
+ ⟨ 2 4 6 ⟩ ┌─
+ ╵ 10 12 14 16
+ 20 24 28 32
+ 30 36 42 48
+ ┘
+ ┘
+
+ <span class='Function'>≢</span><span class='Modifier'>¨</span> <span class='Value'>n</span> <span class='Comment'># Different ranks but compatible shapes
+</span>┌─
+╵ ⟨⟩ ⟨ 4 ⟩
+ ⟨ 3 ⟩ ⟨ 3 4 ⟩
+ ┘
+
+ <span class='Function'>∾</span> <span class='Value'>n</span>
+┌─
+╵ × 5 6 7 8
+ 2 10 12 14 16
+ 4 20 24 28 32
+ 6 30 36 42 48
+ ┘
+</pre>
+<p>Even with the extension, Join has fairly strict requirements on the shapes of its argument elements—although less strict than those of Merge, which requires they all have identical shape. Suppose the argument to Join has rank <code><span class='Value'>m</span></code>. The highest element rank (call it <code><span class='Value'>n</span></code>) must be at least <code><span class='Value'>m</span></code>. The trailing shapes <code><span class='Paren'>(</span><span class='Function'>-</span><span class='Value'>n</span><span class='Function'>-</span><span class='Value'>m</span><span class='Paren'>)</span><span class='Function'>↑</span><span class='Modifier2'>⟜</span><span class='Function'>≢</span><span class='Modifier'>¨</span><span class='Value'>𝕩</span></code> must all be identical (the trailing shape <code><span class='Paren'>(</span><span class='Function'>-</span><span class='Value'>n</span><span class='Function'>-</span><span class='Value'>m</span><span class='Paren'>)</span><span class='Function'>↑≢∾</span><span class='Value'>𝕩</span></code> of the result will match these shapes as well). The other entries in the leading shapes need not be the same, but the shape of an element along a particular axis must depend only on the location of the element along that axis in the full array. For a list argument this imposes no restriction, since the one leading shape element is allowed to depend on position along the only axis. But for higher ranks the structure quickly becomes more rigid.</p>
+<p>To state this requirement more formally in BQN, we say that there is some list <code><span class='Value'>s</span></code> of lists of lengths, so that <code><span class='Paren'>(</span><span class='Function'>≢</span><span class='Modifier'>¨</span><span class='Value'>s</span><span class='Paren'>)</span><span class='Function'>≡≢</span><span class='Value'>𝕩</span></code>. We require element <code><span class='Value'>i</span><span class='Function'>⊑</span><span class='Value'>𝕩</span></code> to have shape <code><span class='Value'>i</span><span class='Function'>⊑</span><span class='Modifier'>¨</span><span class='Value'>s</span></code>. Then the first <code><span class='Value'>m</span></code> axes of the result are <code><span class='Function'>+</span><span class='Modifier'>´¨</span><span class='Value'>s</span></code>. To handle omitted axes, we change <code><span class='Value'>s</span></code> to contain lists of length 0 or 1 instead of lengths, and require <code><span class='Value'>i</span><span class='Function'>⊑</span><span class='Value'>𝕩</span></code> to have shape <code><span class='Function'>∾</span><span class='Value'>i</span><span class='Function'>⊑</span><span class='Modifier'>¨</span><span class='Value'>s</span></code> instead. In the result, an omitted axis behaves exactly like a length-1 axis, so the result can be found using shapes derived from <code><span class='Number'>1</span><span class='Function'>⊣</span><span class='Modifier'>´¨¨</span><span class='Value'>s</span></code>.</p>