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 /docs/doc/transpose.html | |
| parent | e3366f9e18a8791c43110e080b9ea45cfceefed8 (diff) | |
Finish links and editing documentation pass
Diffstat (limited to 'docs/doc/transpose.html')
| -rw-r--r-- | docs/doc/transpose.html | 33 |
1 files changed, 18 insertions, 15 deletions
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> |
