aboutsummaryrefslogtreecommitdiff
path: root/docs/doc/transpose.html
diff options
context:
space:
mode:
Diffstat (limited to 'docs/doc/transpose.html')
-rw-r--r--docs/doc/transpose.html32
1 files changed, 25 insertions, 7 deletions
diff --git a/docs/doc/transpose.html b/docs/doc/transpose.html
index 807173ba..8c9841b3 100644
--- a/docs/doc/transpose.html
+++ b/docs/doc/transpose.html
@@ -36,7 +36,7 @@
<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 <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>
+<p>In terms of the index-ordered elements 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+KAvzLigL8y4qWK4oaVMTIK4ouI4p+c4o2JIGEzMjI=">↗️</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='Value'>a322</span>
┌─
@@ -71,7 +71,7 @@
⟨ 6 2 3 4 5 ⟩
</pre>
<p>In fact, we have <code><span class='Function'>≢⍉</span><span class='Modifier2'>⍟</span><span class='Value'>k</span> <span class='Value'>a</span> <span class='Gets'>←→</span> <span class='Value'>k</span><span class='Function'>⌽≢</span><span class='Value'>a</span></code> for any whole number <code><span class='Value'>k</span></code> and array <code><span class='Value'>a</span></code>.</p>
-<p>To move axes other than the first, use the Rank modifier in order to leave initial axes untouched. A rank of <code><span class='Value'>k</span><span class='Function'>&gt;</span><span class='Number'>0</span></code> transposes only the last <code><span class='Value'>k</span></code> axes while a rank of <code><span class='Value'>k</span><span class='Function'>&lt;</span><span class='Number'>0</span></code> ignores the first <code><span class='Function'>|</span><span class='Value'>k</span></code> axes.</p>
+<p>To move axes other than the first, use the <a href="rank.html">Rank modifier</a> in order to leave initial axes untouched. A rank of <code><span class='Value'>k</span><span class='Function'>&gt;</span><span class='Number'>0</span></code> transposes only the last <code><span class='Value'>k</span></code> axes while a rank of <code><span class='Value'>k</span><span class='Function'>&lt;</span><span class='Number'>0</span></code> ignores the first <code><span class='Function'>|</span><span class='Value'>k</span></code> axes.</p>
<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>
@@ -82,14 +82,14 @@
<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>
+<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 on rank 2.</p>
<p>Axis permutations of the types we've shown generate the complete permutation group on any number of axes, so you could produce any transposition you want with the right sequence of monadic transpositions with Rank. However, this can be unintuitive and tedious. What if you want to transpose the first three axes, leaving the rest alone? With monadic Transpose you have to send some axes to the end, then bring them back to the beginning. For example [following four or five failed tries]:</p>
<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4omiIOKNieKBvOKOicKvMiDijYkgYTIzNDU2ICAjIFJlc3RyaWN0IFRyYW5zcG9zZSB0byB0aGUgZmlyc3QgdGhyZWUgYXhlcw==">↗️</a><pre> <span class='Function'>≢</span> <span class='Function'>⍉</span><span class='Modifier'>⁼</span><span class='Modifier2'>⎉</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>In a case like this the dyadic version of <code><span class='Function'>⍉</span></code>, called Reorder Axes, is much easier.</p>
<h2 id="reorder-axes"><a class="header" href="#reorder-axes">Reorder Axes</a></h2>
-<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>
+<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> (see the next section).</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 ⟩
@@ -109,8 +109,26 @@
</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 Reorder Axes with a &quot;default&quot; 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>
+<h3 id="taking-diagonals"><a class="header" href="#taking-diagonals">Taking diagonals</a></h3>
+<p>When <code><span class='Value'>𝕨</span></code> contains an axis index more than once, the corresponding axes of <code><span class='Value'>𝕩</span></code> will <em>all</em> be sent to that axis of the result. This isn't a special case: it follows the same rule that <code><span class='Value'>i</span><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='Value'>𝕨</span><span class='Function'>⊏</span><span class='Value'>i</span><span class='Paren'>)</span><span class='Function'>⊑</span><span class='Value'>𝕩</span></code>. Only the result shape has to be adjusted for this case: the length along a result axis is the minimum of all the axes of <code><span class='Value'>𝕩</span></code> that go into it, because any indices outside this range will be out of bounds along at least one axis.</p>
+<p>A bit abstract. This rule is almost always used simply as <code><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Function'>⍉</span><span class='Value'>𝕩</span></code> to get the main diagonal of a matrix.</p>
+<a class="replLink" title="Open in the REPL" target="_blank" href="https://mlochbaum.github.io/BQN/try.html#code=4oqiIGEg4oaQIDPigL814qWKJ2EnK+KGlTE1Cgow4oC/MCDijYkgYQoK4p+oMuKfqeKKkTDigL8w4o2JYSAgIyBTaW5nbGUgaW5kZXggaW50byByZXN1bHQK4p+oMiwy4p+p4oqRYSAgICAjIGlzIGxpa2UgYSBkb3VibGVkIGluZGV4IGludG8gYQ==">↗️</a><pre> <span class='Function'>⊢</span> <span class='Value'>a</span> <span class='Gets'>←</span> <span class='Number'>3</span><span class='Ligature'>‿</span><span class='Number'>5</span><span class='Function'>⥊</span><span class='String'>'a'</span><span class='Function'>+↕</span><span class='Number'>15</span>
+┌─
+╵"abcde
+ fghij
+ klmno"
+ ┘
+
+ <span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>0</span> <span class='Function'>⍉</span> <span class='Value'>a</span>
+"agm"
+
+ <span class='Bracket'>⟨</span><span class='Number'>2</span><span class='Bracket'>⟩</span><span class='Function'>⊑</span><span class='Number'>0</span><span class='Ligature'>‿</span><span class='Number'>0</span><span class='Function'>⍉</span><span class='Value'>a</span> <span class='Comment'># Single index into result
+</span>'m'
+ <span class='Bracket'>⟨</span><span class='Number'>2</span><span class='Separator'>,</span><span class='Number'>2</span><span class='Bracket'>⟩</span><span class='Function'>⊑</span><span class='Value'>a</span> <span class='Comment'># is like a doubled index into a
+</span>'m'
+</pre>
<h2 id="definitions"><a class="header" href="#definitions">Definitions</a></h2>
<p>Here we define the two valences of Transpose more precisely.</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 Reorder Axes, <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'>&lt;</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 Transpose or Reorder Axes is always <a href="enclose.html">enclosed</a> 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's returned unchanged (after enclosing, if it's an atom) rather than giving an error.</p>
+<p>In Reorder Axes, <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 rank of <code><span class='Value'>𝕩</span></code> minus the number of duplicate entries in <code><span class='Value'>𝕨</span></code>. We require <code><span class='Function'>∧</span><span class='Modifier'>´</span><span class='Value'>𝕨</span><span class='Function'>&lt;</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>