Rank (operator): Difference between revisions

Jump to navigation Jump to search
2,513 bytes added ,  15:37, 22 October 2020
no edit summary
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 ==

Navigation menu