# Difference between revisions of "Rank (operator)"

Line 120: | Line 120: | ||

=== Publications === | === Publications === | ||

− | * [https:// | + | * [[Dyalog '09]] presentation by [[Roger Hui]]: [https://dyalog.tv/Dyalog09/?v=ui76NE5cMWo The Rank Operator] |

+ | * [[Dyalog Webinar]]s by [[Richard Park]]: [https://dyalog.tv/Webinar/?v=IBct81IopRk Introduction], [https://dyalog.tv/Webinar/?v=zBqdeDJPPRc with Dyadic Transpose], [https://dyalog.tv/Webinar/?v=5wW76XX0kqk advanced use] | ||

+ | * [[APL Cultivation]]s: [https://chat.stackexchange.com/rooms/52405/conversation/lesson-32-basic-use-of- basic use], [https://chat.stackexchange.com/rooms/52405/conversation/lesson-33-advanced-use-of- advanced use] | ||

==References== | ==References== | ||

<references/> | <references/> | ||

{{APL built-ins}}[[Category:Primitive operators]] | {{APL built-ins}}[[Category:Primitive operators]] |

## Latest revision as of 07:26, 11 May 2021

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

## Contents

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

- 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

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