# Rank (operator): Difference between revisions

mNo edit summary |
No edit summary |
||

Line 62: | Line 62: | ||

== History == | == 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"<ref name="hopl4">[https://dl.acm.org/doi/pdf/10.1145/3386319 Hui, R.K. and Kromberg, M.J., 2020. APL Since 1978. Proceedings of the ACM on Programming Languages.]</ref>, 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 product|inner (matrix) product]], [[outer product]], maplist in LISP, map in modern functional programming languages and the broadcast facility in NumPy. | 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"<ref name="hopl4">[https://dl.acm.org/doi/pdf/10.1145/3386319 Hui, R.K. and Kromberg, M.J., 2020. APL Since 1978. Proceedings of the ACM on Programming Languages.]</ref>, 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 product|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 [https://aplwiki.com/wiki/Function_axis bracket-axis]. It provides nearly all of the functionality of the anomalous axis operator (<source lang=apl inline>f[a]</source>) without its draw-backs.<ref name="intro2rank">Bernecky, R., 1987. An introduction to function rank. ACM SIGAPL APL Quote Quad, 18(2), pp.39-43.</ref> | |||

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. | |||

<source 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. | |||

<source 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. | |||

<source lang=apl> | |||

,[(-⍺)↑⍴⍵] ≡ ⊂⍤⍺ | |||

</source> | |||

Merging leading axes is more involved, but can be expressed in one line. | |||

<source lang=apl> | |||

,[⍳⍺] ←→ {(1⌽⍳≢⍴z)⍉z←,⍤⍺((-⍺)⌽⍳≢⍴⍵)⍉⍵} | |||

</source> | |||

The general treatment benefits from being expanded. | |||

<source lang=apl> | |||

MergeAxes←{ | |||

axes←⍳≢⍴⍵ | |||

move←⍋(axes~⍺),⍺ | |||

merged←,⍤(≢⍺)⊢move⍉⍵ | |||

restore←((⍳≢⍴merged)~⊃⍺),⊃⍺ | |||

restored⍉merged | |||

} | |||

,[⍺] ←→ ⍺∘MergeAxes ⍝ for ∧/1=¯2-/⍺ | |||

</source> | |||

== External links == | == External links == |

## Revision as of 15:37, 22 October 2020

*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 `⍺`

and right argument `⍵`

,

⍤ 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)

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, `99`

, `(⌊/⍬)`

or `∞`

, depending on the implementation, is "rank infinity" and always specifies the whole argument array.

## Examples

Rotate rows in matrices of a 3D array:

⊖⍤2⊢3 2 4⍴⎕A EFGH ABCD MNOP IJKL UVWX QRST

Laminate scalars from arrays of differing ranks:

'ABCD',⍤0⍤1⊢2 4⍴⍳8 A 1 B 2 C 3 D 4 A 5 B 6 C 7 D 8

Flat outer product:

-⍤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

## 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 (`f[a]`

) 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.

+/[1+⍺-⍨≢⍴⍵] ≡ +⌿⍤⍺ ⍝ For scalar ⍺ +/[⍺] ≡ +⌿⍤(1+⍺-⍨≢⍴⍵) ⍝ For scalar ⍺

### 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.

EncloseAxes←{ axes←⍳≢⍴⍵ move←⍋(axes~⍺),⍺ ⊂⍤(≢⍺)⊢move⍉⍺ } ⊂[⍺] ≡ ⍺∘EncloseAxes

### 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.

,[(-⍺)↑⍴⍵] ≡ ⊂⍤⍺

Merging leading axes is more involved, but can be expressed in one line.

,[⍳⍺] ←→ {(1⌽⍳≢⍴z)⍉z←,⍤⍺((-⍺)⌽⍳≢⍴⍵)⍉⍵}

The general treatment benefits from being expanded.

MergeAxes←{ axes←⍳≢⍴⍵ move←⍋(axes~⍺),⍺ merged←,⍤(≢⍺)⊢move⍉⍵ restore←((⍳≢⍴merged)~⊃⍺),⊃⍺ restored⍉merged } ,[⍺] ←→ ⍺∘MergeAxes ⍝ for ∧/1=¯2-/⍺

## External links

### Documentation

### Publications

## References

- ↑ Hui, R.K. and Kromberg, M.J., 2020. APL Since 1978. Proceedings of the ACM on Programming Languages.
- ↑ Bernecky, R., 1987. An introduction to function rank. ACM SIGAPL APL Quote Quad, 18(2), pp.39-43.