Rank (operator)
- This article is about the operator. See Rank for the number associated with every array. For numbers associated with a function specifying its argument rank, see function rank.
⍤
|
Rank (⍤
) is a primitive dyadic operator which applies its left operand function to cells of its arguments specified by its right operand array.
Rank specification
The right operand specifies the rank of subarrays to which the left operand function is applied as follows: For left argument <syntaxhighlight lang=apl inline>⍺</source> and right argument <syntaxhighlight lang=apl inline>⍵</source>, <syntaxhighlight lang=apl>
⍤ c ⍝ Rank-c cells of ⍵ (monadic) or both arguments (dyadic) ⍤ b c ⍝ Rank-b cells of ⍺ and rank-c cells of ⍵ (dyadic) ⍤a b c ⍝ Rank-a cells of ⍵ (monadic), b-cells of ⍺ and c-cells of ⍵ (dyadic)
</source>
A non-negative right operand specifies the number of final axes to which the function applies. A negative right operand specifies complementary rank, i.e. the number of leading axes to be excluded. Negative rank can also be thought of as rank specification relative to the overall rank of the argument array.
Since a rank specification greater than the rank of the argument array means to apply the function to the whole array, <syntaxhighlight lang=apl inline>99</source>, <syntaxhighlight lang=apl inline>(⌊/⍬)</source> or <syntaxhighlight lang=apl inline>∞</source>, depending on the implementation, is "rank infinity" and always specifies the whole argument array.
Examples
Reverse order of rows in matrices of a 3D array: <syntaxhighlight lang=apl>
⊖⍤2⊢3 2 4⍴⎕A
EFGH ABCD
MNOP IJKL
UVWX QRST </source>
Laminate scalars from arrays of differing ranks: <syntaxhighlight lang=apl>
'ABCD',⍤0⍤1⊢2 4⍴⍳8
A 1 B 2 C 3 D 4
A 5 B 6 C 7 D 8 </source>
Flat outer product: <syntaxhighlight lang=apl>
-⍤1⍤1 99⍨3 2⍴6 7 1 1 2 4 ⍝ ↑∘.-⍨↓ 0 0 5 6 4 3
¯5 ¯6
0 0
¯1 ¯3
¯4 ¯3
1 3 0 0
</source>
History
The rank operator was invented by Arthur Whitney in 1982 and first implemented in SHARP APL in 1983. It has been described as "a microcosm of APL history"[1], its evolution a progression from scalar extension, which has been in APL since its inception, through leading axis theory to a construct which is a generalisation of scalar extension, inner (matrix) product, outer product, maplist in LISP, map in modern functional programming languages and the broadcast facility in NumPy.
Rank vs Axis
Due to its ability to apply functions to specified subarrays, rank is frequently contrasted with bracket-axis. It provides nearly all of the functionality of the anomalous axis operator (<syntaxhighlight lang=apl inline>f[a]</source>) without its draw-backs.[2]
One of these draw-backs is that bracket-axis is specified ad hoc for each of the specific primitives on which it applies. Rank benefits from consistent behaviour when applied to any function, including user-defined functions. The ad hoc nature of bracket-axis definitions means that a generalised axis operator which works on any function, but behaves just as bracket-axis on those particular primitives, is impossible to formulate.
Here we show some bracket-axis constructs and their equivalent expressions which use rank but do not use bracket-axis.
Sum along axis
Rank k-cells are defined for k trailing axes, whereas axes are numbered from most major (first axis i.e. axis number 1) to least major (last axis). This leads to a simple and symmetrical relationship. <syntaxhighlight lang=apl> +/[1+⍺-⍨≢⍴⍵] ≡ +⌿⍤⍺ ⍝ For scalar ⍺ +/[⍺] ≡ +⌿⍤(1+⍺-⍨≢⍴⍵) ⍝ For scalar ⍺ </source>
Enclose axes
Enclose-with-axis is equivalent to transposing desired axes to the end of the array's shape and enclosing subarrays of a rank matching the number of axes. <syntaxhighlight lang=apl> EncloseAxes←{
axes←⍳≢⍴⍵ move←⍋(axes~⍺),⍺ ⊂⍤(≢⍺)⊢move⍉⍺
} ⊂[⍺] ≡ ⍺∘EncloseAxes </source>
Merge axes
Ravel-with-axis allows data to be merged along specified consecutive axes. The requirement that axes be consecutive is so that the data can remain in its original relative order.
Merging trailing axes is trivial. <syntaxhighlight lang=apl> ,[(-⍺)↑⍴⍵] ≡ ,⍤⍺ </source>
Merging leading axes is more involved, but can be expressed in one line. <syntaxhighlight lang=apl> ,[⍳⍺] ←→ {(1⌽⍳≢⍴z)⍉z←,⍤⍺((-⍺)⌽⍳≢⍴⍵)⍉⍵} </source>
The general treatment benefits from being expanded. <syntaxhighlight lang=apl> MergeAxes←{
axes←⍳≢⍴⍵ move←⍋(axes~⍺),⍺ merged←,⍤(≢⍺)⊢move⍉⍵ restore←((⍳≢⍴merged)~⊃⍺),⊃⍺ restored⍉merged
}
,[⍺] ←→ ⍺∘MergeAxes ⍝ for ∧/1=¯2-/⍺ </source>
External links
Documentation
Publications
- Dyalog '09 presentation by Roger Hui: The Rank Operator
- Dyalog Webinars by Richard Park: Introduction, with Dyadic Transpose, advanced use
- APL Cultivations: basic use, advanced use
References
- ↑ Roger Hui and Morten Kromberg. APL since 1978. ACM HOPL IV. 2020-06.
- ↑ Robert Bernecky. An introduction to function rank at APL88. ACM SIGAPL APL Quote Quad, 18(2), pp.39-43. 1987.