Take: Difference between revisions

From APL Wiki
Jump to navigation Jump to search
Miraheze>Marshall
(Undo revision 428 by Marshall (talk))
m (→‎History: Prefix and suffix vector link)
 
(53 intermediate revisions by 5 users not shown)
Line 1: Line 1:
Take (<code></code>) is a [[primitive function]] which shortens or extends an array along one or more [[Axis|axes]]. The [[vector]] left argument indicates the lengths of result axes, with a sign to denote whether elements should be taken starting from the beginning or end of each axis. Take was introduced in [[APL\360]] with the requirement that the left argument length match the right argument rank, and was extended in [[SHARP APL 19.0]] to allow short left arguments. It is closely related to [[Drop]], which removes the parts of each axis that Take would include.
{{Built-in|Take|}} is a [[Primitive function|primitive]] [[dyadic function]] which shortens or extends the right [[argument]] array along zero or more [[Axis|axes]]. The [[vector]] left argument indicates the lengths of result axes, with a sign to denote whether [[element]]s should be taken starting from the beginning or end of each axis. Take was introduced in [[APL\360]] with the requirement that the left argument length match the right argument rank, and was extended in [[SHARP APL]] 19.0 to allow short left arguments. It is closely related to [[Drop]], which removes the parts of each axis that Take would include.


== Examples ==
== Examples ==


Take may be used to get the first few, or last few, elements of a vector:
Take may be used to get the first few, or last few, elements of a vector:
<source lang=apl>
<syntaxhighlight lang=apl>
       3 ↑ 5 4 3 2 1
       3 ↑ 5 4 3 2 1
5 4 3
5 4 3
       ¯3 ↑ 5 4 3 2 1
       ¯3 ↑ 5 4 3 2 1
3 2 1
3 2 1
</source>
</syntaxhighlight>
The left argument to length specifies a length, and not an index. It does not depend on [[index origin]].
The left argument to length specifies a length, and not an index. It does not depend on [[index origin]].
 
=== Overtaking ===
A length which is larger than the argument length causes [[Fill element|fills]] to be inserted. The alignment remains the same: if two different positive arguments are used to take from an array, the one which is closer to zero gives a [[prefix]] of the other result. If they are both negative, it is a [[suffix]] instead. When Take makes an axis longer, it is said to "overtake" along that axis.
A length which is larger than the argument length causes [[Fill element|fills]] to be inserted. The alignment remains the same: if two different positive arguments are used to take from an array, the one which is closer to zero gives a [[prefix]] of the other result. If they are both negative, it is a [[suffix]] instead. When Take makes an axis longer, it is said to "overtake" along that axis.
<source lang=apl>
<syntaxhighlight lang=apl>
       8 ↑ 5 4 3 2 1
       8 ↑ 5 4 3 2 1
5 4 3 2 1 0 0 0
5 4 3 2 1 0 0 0
       ¯8 ↑ 5 4 3 2 1
       ¯8 ↑ 5 4 3 2 1
0 0 0 5 4 3 2 1
0 0 0 5 4 3 2 1
</source>
</syntaxhighlight>
{{Works in|[[Dyalog APL]], [[ngn/apl]]}}
{{Works in|[[Dyalog APL]], [[ngn/apl]]}}
 
=== Truncation ===
A higher-[[rank]] array can be shortened by using a left argument with one element for each axis:
A higher-[[rank]] array can be shortened by using a left argument with one element for each axis:
<source lang=apl>
<syntaxhighlight lang=apl>
       ¯2 3↑⍳4 5
       ¯2 3↑⍳4 5
┌───┬───┬───┐
┌───┬───┬───┐
Line 29: Line 29:
│4 1│4 2│4 3│
│4 1│4 2│4 3│
└───┴───┴───┘
└───┴───┴───┘
</source>
</syntaxhighlight>
{{Works in|[[Dyalog APL]], [[dzaima/APL]], [[ngn/apl]]}}
{{Works in|[[Dyalog APL]], [[dzaima/APL]], [[ngn/apl]]}}
 
=== Leading axes ===
In languages with the SHARP APL extension, the left argument can be shortened. This causes leading axes of the right argument to be modified while trailing axes are ignored.
In languages with the SHARP APL extension, the left argument can be shortened. This causes leading axes of the right argument to be modified while trailing axes are ignored.
<source lang=apl>
<syntaxhighlight lang=apl>
       ¯2↑⍳4 5
       ¯2↑⍳4 5
┌───┬───┬───┬───┬───┐
┌───┬───┬───┬───┬───┐
Line 40: Line 40:
│4 1│4 2│4 3│4 4│4 5│
│4 1│4 2│4 3│4 4│4 5│
└───┴───┴───┴───┴───┘
└───┴───┴───┴───┴───┘
</source>
</syntaxhighlight>
{{Works in|[[Dyalog APL]], [[ngn/apl]]}}
{{Works in|[[Dyalog APL]], [[ngn/apl]]}}
 
=== Function axis ===
An [[Function axis|axis]] may be specified to apply left argument elements to specific axes of the right argument. Here the last axis is specified in order to take two columns of the argument.
An [[Function axis|axis]] may be specified to apply left argument elements to specific axes of the right argument. Here the last axis is specified in order to take two columns of the argument.
<source lang=apl>
<syntaxhighlight lang=apl>
       ¯2↑[2]⍳4 5
       ¯2↑[2]⍳4 5
┌───┬───┐
┌───┬───┐
Line 55: Line 55:
│4 4│4 5│
│4 4│4 5│
└───┴───┘
└───┴───┘
</source>
</syntaxhighlight>
{{Works in|[[Dyalog APL]]}}
{{Works in|[[Dyalog APL]]}}
If the [[Rank operator]] is available then <code>¯2↑⍤1⍳4 5</code> is an equivalent expression.
If the [[Rank operator]] is available then <syntaxhighlight lang=apl inline>¯2↑⍤1⍳4 5</syntaxhighlight> is an equivalent expression.


== Description ==
== Description ==


In the expression <code>X↑Y</code>, <code>X</code> may be any array, and <code>Y</code> is a [[Simple array|simple]] [[numeric]] [[vector]] whose length is less than or equal to the [[rank]] of <code>Y</code>. Many APLs require the length to be exactly equal; however, an extension by [[SHARP APL]] to allow a shorter left argument has been widely adopted by recent APLs. <code>X</code> may also be a scalar, in which case it is treated as a one-element vector in an instance of [[scalar rank extension]]. In some APLs, <code>Y</code> is also subject to [[scalar rank extension]]: if it is scalar then it will be extended so its rank is the length <code>≢X</code>.
In the expression <syntaxhighlight lang=apl inline>X↑Y</syntaxhighlight>, <syntaxhighlight lang=apl inline>X</syntaxhighlight> may be any array, and <syntaxhighlight lang=apl inline>Y</syntaxhighlight> is a [[Simple array|simple]] [[numeric]] [[vector]] whose length is less than or equal to the [[rank]] of <syntaxhighlight lang=apl inline>Y</syntaxhighlight>. Many APLs require the length to be exactly equal; however, an extension by [[SHARP APL]] to allow a shorter left argument has been widely adopted by recent APLs. <syntaxhighlight lang=apl inline>X</syntaxhighlight> may also be a scalar, in which case it is treated as a one-element vector in an instance of [[scalar rank extension]]. In some APLs, <syntaxhighlight lang=apl inline>Y</syntaxhighlight> is also subject to [[scalar rank extension]]: if it is scalar then it will be extended so its rank is the length <syntaxhighlight lang=apl inline>≢X</syntaxhighlight>.


Elements of <code>X</code> are matched with axes of <code>Y</code> with the same [[index]], that is, the left argument corresponds to [[Leading axis theory|leading axes]] of the right. The trailing axes of <code>Y</code> which are not matched in this way are unchanged by Take; this may also be modelled by extending <code>X</code> using the lengths of those axes.
Elements of <syntaxhighlight lang=apl inline>X</syntaxhighlight> are matched with axes of <syntaxhighlight lang=apl inline>Y</syntaxhighlight> with the same [[index]], that is, the left argument corresponds to [[Leading axis theory|leading axes]] of the right. The trailing axes of <syntaxhighlight lang=apl inline>Y</syntaxhighlight> which are not matched in this way are unchanged by Take; this may also be modelled by extending <syntaxhighlight lang=apl inline>X</syntaxhighlight> using the lengths of those axes.


For each modified axis the result length along that axis is equal to the corresponding element of <code>|X</code>. If the original element in <code>X</code> is positive then the result is aligned with the argument at the beginning of that axis, and if that element is negative they are aligned at the end. If it is zero then the result is empty, so both are true. Elements from the right argument are used in the result until the result is filled. If the argument axis is shorter than the result axis then [[Fill element|fills]] are used once it is exhausted. If the result is empty, its [[prototype]] is the same as the right argument's.
For each modified axis the result length along that axis is equal to the corresponding element of <syntaxhighlight lang=apl inline>|X</syntaxhighlight>. If the original element in <syntaxhighlight lang=apl inline>X</syntaxhighlight> is positive then the result is aligned with the argument at the beginning of that axis, and if that element is negative they are aligned at the end. If it is zero then the result is empty, so both are true. Elements from the right argument are used in the result until the result is filled. If the argument axis is shorter than the result axis then [[Fill element|fills]] are used once it is exhausted. If the result is empty, its [[prototype]] is the same as the right argument's.


If the result is no larger than the right argument along each axis (equivalently, no fills are used, or <code>(|X)≤(≢X)↑⍴Y</code>), then the result is a [[subarray]] of <code>Y</code>. Not all subarrays can be produced in this way: only those which align with one boundary of the argument along each axis.
If the result is no larger than the right argument along each axis (equivalently, no fills are used, or <syntaxhighlight lang=apl inline>(|X)≤(≢X)↑⍴Y</syntaxhighlight>), then the result is a [[subarray]] of <syntaxhighlight lang=apl inline>Y</syntaxhighlight>. Not all subarrays can be produced in this way: only those which have the same rank and align with one boundary of the argument along each axis.


=== Axis specification ===
=== Axis specification ===


When Take is called with [[Function axis|axis]], the axis determines how elements of the left argument correspond to axes of the right argument. The left argument and axis are required to have rank no more than 1 and are treated as vectors. Their lengths must match, and be less than or equal to the rank of the right argument. Then each element of the left argument applies to the right argument axis given by the corresponding element of the axis vector. Each axis may only be specified once, and unspecified axes are left unchanged.
When Take is called with [[Function axis|axis]], the axis determines how elements of the left argument correspond to axes of the right argument. The left argument and axis are required to have rank no more than 1 and are treated as vectors. Their lengths must match, and be less than or equal to the rank of the right argument. Then each element of the left argument applies to the right argument axis given by the corresponding element of the axis vector. Each axis may only be specified once, and unspecified axes are left unchanged.
=== Infinite left arguments ===
In [[J]] 4.02 (released 1998) and later, an [[infinity|infinite]] value in the left argument causes the corresponding axis of the right argument to be unchanged. In [[ngn/apl]], it simply causes an error.
=== APLX fills ===
In [[APLX]], the [[fill element]]s used in Take are not always the argument array's [[prototype]]: new elements in rows (that is, 1-[[cell]]s) that already exist are filled based on the first element of that row while new rows use the prototype of the whole array.


=== APL model ===
=== APL model ===
Line 77: Line 85:
The following [[dfn]] models Take as defined by [[Dyalog APL]] but with no axis specification or error checking. It is implemented by construction a [[nested array]] of indices and using these to select from the right argument, with prototypes used for out-of-range indices. It explicitly includes [[scalar rank extension]] for the right argument and the SHARP APL extension; if these extensions are not wanted those lines can be removed. [[Scalar rank extension]] of the left argument is inherited from [[Iota]] and [[scalar function]] extension.
The following [[dfn]] models Take as defined by [[Dyalog APL]] but with no axis specification or error checking. It is implemented by construction a [[nested array]] of indices and using these to select from the right argument, with prototypes used for out-of-range indices. It explicitly includes [[scalar rank extension]] for the right argument and the SHARP APL extension; if these extensions are not wanted those lines can be removed. [[Scalar rank extension]] of the left argument is inherited from [[Iota]] and [[scalar function]] extension.


<source class=apl>
<syntaxhighlight lang=apl>
Take ← {
Take ← {
  ⎕IO←0                        ⍝ For index comparisons
    ⎕IO←0                        ⍝ For index comparisons
  r s ← ≢¨(⍴⍵)(⍺)              ⍝ Rank and number of modified axes
    r s ← ≢¨(⍴⍵)(⍺)              ⍝ Rank and number of modified axes
  (r=0)∧s>0: ⍺∇(s⍴1)⍴⍵          ⍝ Right argument scalar rank extension
    (r=0)∧s>0: ⍺∇(s⍴1)⍴⍵          ⍝ Right argument scalar rank extension
  s<r: (⍺,(s-r)∇⍴⍵)∇⍵          ⍝ SHARP APL extension
    s<r: (⍺,(s-r)∇⍴⍵)∇⍵          ⍝ SHARP APL extension
  inds ← ((⍺<0)×⍺+⍴⍵)∘+¨ ⍳|⍺    ⍝ Indices to select
    inds ← ((⍺<0)×⍺+⍴⍵)∘+¨ ⍳|⍺    ⍝ Indices to select
  sel ← {
    sel ← {
    ∧/(0≤⍺)∧⍺<⍴⍵: (⊂⍺)⊃⍵       ⍝ In range: use Pick
        ∧/(0≤⍺)∧⍺<⍴⍵: (⊂⍺)⊃⍵     ⍝ In range: use Pick
    ⊃0⍴⍵                       ⍝ Otherwise, get prototype
        ⊃0⍴⍵                     ⍝ Otherwise, get prototype
  }
    }
  sel∘⍵¨ inds
    sel∘⍵¨ inds
}
}
</source>
</syntaxhighlight>
{{Works in|[[Dyalog APL]]}}
{{Works in|[[Dyalog APL]]}}


This definition could be converted to work in a [[Flat array model|flat]] APL with the [[Rank operator]] by using an [[odometer function]] like <code>⊢⊤(⍳×/)</code> in place of [[Iota]] and changing the two subsequent uses of [[Each]] to Rank 1.
This definition could be converted to work in a [[Flat array model|flat]] APL with the [[Rank operator]] by using an [[odometer function]] like <syntaxhighlight lang=apl inline>⊢⊤(⍳×/)</syntaxhighlight> in place of [[Iota]] and changing the two subsequent uses of [[Each]] to Rank 1.


== History ==
== History ==


In [[A Programming Language]], prefix and suffix operations were described using the syntax <code>⍺<sup>j</sup>/x</code> to take the first <code>j</code> elements of vector <code>x</code> and <code>⍵<sup>j</sup>/x</code> for the last <code>j</code> elements. This combined a use of the special prefix and suffix vectors <code>⍺<sup>j</sup>(n)</code> and <code>⍵<sup>j</sup>(n)</code> with [[Compress|compression]], with the length <code>n</code> inferred based on the length of <code>x</code>. The symbol <code></code> was used for vector [[Rotate]], while <code></code> rotated in the opposite direction.<ref>Iverson, K.E. (1962). A Programming Language. Wiley. ISBN 978-0-471-43014-8.</ref>
In [[A Programming Language]], [[prefix]] and [[suffix]] operations were described using the syntax <math>\alpha^j/x</math> to take the first <math>j</math> elements of vector <math>x</math> and <math>\omega^j/x</math> for the last <math>j</math> elements. This combined a use of the special [[prefix and suffix vectors]] <math>\alpha^j(n)</math> and <math>\omega^j(n)</math> with [[Compress|compression]], with the length <math>n</math> inferred based on the length of <math>x</math>. The symbol <math>\uparrow</math> was used for vector [[Rotate]], while <math>\downarrow</math> rotated in the opposite direction.<ref>[[Ken Iverson|Iverson, K.E.]] (1962). A Programming Language. Wiley. ISBN 978-0-471-43014-8.</ref> All these definitions appear in [[IVSYS/7090]], with adjustments to fit a linear syntax.


Take using the symbol <code>↑</code> was absent from the first version of [[APL\360]]<ref>Falkoff, A.D., and K.E. Iverson. [https://www.jsoftware.com/papers/APL360TerminalSystem.htm "The APL\360 Terminal System"]. Research Report RC-1922, IBM, 1967-10-16.</ref> but was introduced by 1968<ref>Falkoff, A.D., and K.E. Iverson, "[http://keiapl.org/archive/APL360_UsersMan_Aug1968.pdf APL\360 User's Manual]". IBM, August 1968.</ref>.
The first version of [[APL\360]]<ref>[[Adin Falkoff|Falkoff, A.D.]], and [[Ken Iverson|K.E. Iverson]]. [https://www.jsoftware.com/papers/APL360TerminalSystem.htm "The APL\360 Terminal System"]. Research Report RC-1922, IBM, 1967-10-16.</ref> followed Iverson notation in defining prefix (<syntaxhighlight lang=apl inline>n ⍺ j</syntaxhighlight>) and suffix (<syntaxhighlight lang=apl inline>n ⍵ j</syntaxhighlight>) vectors but not Take, even though the arrow symbols were no longer used for Rotate. For a vector <syntaxhighlight lang=apl inline>x</syntaxhighlight>, what is now <syntaxhighlight lang=apl inline>j↑x</syntaxhighlight> would have been written <syntaxhighlight lang=apl inline>((⍴x)⍺j)/x</syntaxhighlight> while <syntaxhighlight lang=apl inline>(-j)↑x</syntaxhighlight> would be <syntaxhighlight lang=apl inline>((⍴x)⍵j)/x</syntaxhighlight>. The functions Take and Drop using arrow symbols were introduced by 1968.<ref>[[Adin Falkoff|Falkoff, A.D.]], and [[Ken Iverson|K.E. Iverson]], "[http://keiapl.org/archive/APL360_UsersMan_Aug1968.pdf APL\360 User's Manual]". [[IBM]], August 1968.</ref> They were implemented for arrays (not just vectors), and extended to allow the left argument to be larger than the right argument's shape (introducing overtaking and [[fill element]]s) in 1970.<ref>"[[IBM|I.B.M.]] Report". [[APL Quote-Quad]] Volume 2, Number 1. 1970-04.</ref>


The [[Function axis|axis]] specification for Take was defined in [[APL2]]. It is shared by [[SHARP APL]] and [[Rationalized APL]], and continues to be supported in [[Dyalog APL]].
The [[Function axis|axis]] specification for Take was defined in [[APL2]]. It is shared by [[SHARP APL]] and [[Rationalized APL]], and continues to be supported in [[Dyalog APL]].


[[SHARP APL 19.0]], released in 1987, extended Take to allow short left arguments. The choice to align left argument elements with the leading axes of the right argument was made according to the nascent [[leading axis theory]]: while a user may not have any preference for manipulating the earlier dimensions, this choice makes Take more flexible when used with the [[Rank operator]].<ref>Bernecky, Robert. [https://dl.acm.org/citation.cfm?id=55632 "An Introduction to Function Rank"]. APL88 Conference Proceedings. ''ACM SIGAPL Quote Quad'', 18(2), December 1987.</ref> This extension is also used in [[Dyalog APL]], [[J]], and [[ngn/apl]]. It was not adopted in [[ISO/IEC 13751:2001]].
[[SHARP APL]] 19.0, released in 1987, extended Take to allow short left arguments. The choice to align left argument elements with the leading axes of the right argument was made according to the nascent [[leading axis theory]]: while a user may not have any preference for manipulating the earlier dimensions, this choice makes Take more flexible when used with the [[Rank operator]].<ref>[[Bob Bernecky|Bernecky, Robert]]. [https://dl.acm.org/citation.cfm?id=55632 "An Introduction to Function Rank"]. [[APL88]] Conference Proceedings. ''ACM SIGAPL Quote Quad'', 18(2), December 1987.</ref> It has been present in [[J]] and [[ngn/apl]] since early development, and was adopted in [[Dyalog APL 13.0]] (2011), as well as [[NARS2000]] between 2017 and 2019.<ref>[[Bob Smith|Smith, Bob]]. [http://www.sudleyplace.com/APL/Progress%202017-2019.pdf "Progress in NARS2000 October 2017 to September 2019"]. Presented at [[Minnowbrook]] 2019 and published independently.</ref>


== Extension support ==
== Extension support ==
In the table below, "Scalar right arg" indicates [[scalar rank extension]] of the right argument, and "Short left arg" is the [[SHARP APL]] extension.


{| class=wikitable
{| class=wikitable
! Language                !! Scalar right arg !! Short left arg !! Axis specification
! Languages                                  !! Scalar right arg !! Short left arg !! Axis specification
|-
| [[APL\360]]            || N                || N              || N
|-
| [[APL2]]                || Y                || N              || Y
|-
| [[SHARP APL]]          || Y                || Y              || Y
|-
|-
| [[Dyalog APL]]         || Y                || Y              || Y
| [[APL\360]]                                 || {{No}}          || {{No}}        || {{No}}
|-
|-
| [[J]] (<code>{.</code>) || Y                || Y              || N
| [[APL2]], [[APLX]], [[GNU APL]]            || {{Yes}}          || {{No}}        || {{Yes}}
|-
|-
| [[GNU APL]]             || Y                || N              || Y
| [[SHARP APL]], [[Dyalog APL]], [[NARS2000]], [[Kap]]
                                              | {{Yes}}          || {{Yes}}        || {{Yes}}
|-
|-
| [[ngn/apl]]             || Y                || Y              || N
| [[A+]], [[ngn/apl]], [[J]] (<syntaxhighlight lang=j inline>{.</syntaxhighlight>), [[BQN]] || {{Yes}}          || {{Yes}}        || {{No}}
|-
|-
| [[dzaima/APL]]         || N                || Y              || N
| [[dzaima/APL]], [[Uiua]]                    || {{No}}          || {{Yes}}        || {{No}}
|}
|}


== Documentation ==
Additionally, [[A+]] requires the left argument to be a [[singleton]], and [[dzaima/APL]] does not allow overtaking (so that the result of Take cannot contain fills).
 
== See also ==
* [[Reshape]]
* [[First]]
== External links ==
 
=== Lessons ===
 
* [https://chat.stackexchange.com/transcript/52405?m=41304361#41304361 APL Cultivation]
 
=== Documentation ===


[http://help.dyalog.com/latest/Content/Language/Primitive%20Functions/Take.htm Dyalog] [http://help.dyalog.com/latest/Content/Language/Primitive%20Functions/Take%20with%20Axes.htm with axis]
* [https://help.dyalog.com/latest/index.htm#Language/Primitive%20Functions/Take.htm Dyalog] ([https://help.dyalog.com/latest/index.htm#Language/Primitive%20Functions/Take%20with%20Axes.htm with axis])


[http://wiki.nars2000.org/index.php/Symbol_Take NARS2000]
* [http://wiki.nars2000.org/index.php/Symbol_Take NARS2000]


J [https://www.jsoftware.com/help/dictionary/d521.htm dictionary], [https://code.jsoftware.com/wiki/Vocabulary/curlylfdot#dyadic NuVoc]
* [http://microapl.com/apl_help/ch_020_020_560.htm APLX]


== Other resources ==
* [https://www.jsoftware.com/help/dictionary/d521.htm J dictionary], [https://code.jsoftware.com/wiki/Vocabulary/curlylfdot#dyadic J NuVoc]


[https://chat.stackexchange.com/transcript/52405?m=41304361#41304361 APL Cultivation]
* [https://mlochbaum.github.io/BQN/doc/take.html BQN]


== References ==
== References ==


<references />
<references />
{{APL built-ins}}[[Category:Primitive functions]]

Latest revision as of 01:23, 2 March 2024

Take () is a primitive dyadic function which shortens or extends the right argument array along zero or more axes. The vector left argument indicates the lengths of result axes, with a sign to denote whether elements should be taken starting from the beginning or end of each axis. Take was introduced in APL\360 with the requirement that the left argument length match the right argument rank, and was extended in SHARP APL 19.0 to allow short left arguments. It is closely related to Drop, which removes the parts of each axis that Take would include.

Examples

Take may be used to get the first few, or last few, elements of a vector:

      3 ↑ 5 4 3 2 1
5 4 3
      ¯3 ↑ 5 4 3 2 1
3 2 1

The left argument to length specifies a length, and not an index. It does not depend on index origin.

Overtaking

A length which is larger than the argument length causes fills to be inserted. The alignment remains the same: if two different positive arguments are used to take from an array, the one which is closer to zero gives a prefix of the other result. If they are both negative, it is a suffix instead. When Take makes an axis longer, it is said to "overtake" along that axis.

      8 ↑ 5 4 3 2 1
5 4 3 2 1 0 0 0
      ¯8 ↑ 5 4 3 2 1
0 0 0 5 4 3 2 1
Works in: Dyalog APL, ngn/apl

Truncation

A higher-rank array can be shortened by using a left argument with one element for each axis:

      ¯2 3↑⍳4 5
┌───┬───┬───┐
│3 1│3 2│3 3│
├───┼───┼───┤
│4 1│4 2│4 3│
└───┴───┴───┘

Leading axes

In languages with the SHARP APL extension, the left argument can be shortened. This causes leading axes of the right argument to be modified while trailing axes are ignored.

      ¯2↑⍳4 5
┌───┬───┬───┬───┬───┐
│3 1│3 2│3 3│3 4│3 5│
├───┼───┼───┼───┼───┤
│4 1│4 2│4 3│4 4│4 5│
└───┴───┴───┴───┴───┘
Works in: Dyalog APL, ngn/apl

Function axis

An axis may be specified to apply left argument elements to specific axes of the right argument. Here the last axis is specified in order to take two columns of the argument.

      ¯2↑[2]⍳4 5
┌───┬───┐
│1 4│1 5│
├───┼───┤
│2 4│2 5│
├───┼───┤
│3 4│3 5│
├───┼───┤
│4 4│4 5│
└───┴───┘
Works in: Dyalog APL

If the Rank operator is available then ¯2↑⍤1⍳4 5 is an equivalent expression.

Description

In the expression X↑Y, X may be any array, and Y is a simple numeric vector whose length is less than or equal to the rank of Y. Many APLs require the length to be exactly equal; however, an extension by SHARP APL to allow a shorter left argument has been widely adopted by recent APLs. X may also be a scalar, in which case it is treated as a one-element vector in an instance of scalar rank extension. In some APLs, Y is also subject to scalar rank extension: if it is scalar then it will be extended so its rank is the length ≢X.

Elements of X are matched with axes of Y with the same index, that is, the left argument corresponds to leading axes of the right. The trailing axes of Y which are not matched in this way are unchanged by Take; this may also be modelled by extending X using the lengths of those axes.

For each modified axis the result length along that axis is equal to the corresponding element of |X. If the original element in X is positive then the result is aligned with the argument at the beginning of that axis, and if that element is negative they are aligned at the end. If it is zero then the result is empty, so both are true. Elements from the right argument are used in the result until the result is filled. If the argument axis is shorter than the result axis then fills are used once it is exhausted. If the result is empty, its prototype is the same as the right argument's.

If the result is no larger than the right argument along each axis (equivalently, no fills are used, or (|X)≤(≢X)↑⍴Y), then the result is a subarray of Y. Not all subarrays can be produced in this way: only those which have the same rank and align with one boundary of the argument along each axis.

Axis specification

When Take is called with axis, the axis determines how elements of the left argument correspond to axes of the right argument. The left argument and axis are required to have rank no more than 1 and are treated as vectors. Their lengths must match, and be less than or equal to the rank of the right argument. Then each element of the left argument applies to the right argument axis given by the corresponding element of the axis vector. Each axis may only be specified once, and unspecified axes are left unchanged.

Infinite left arguments

In J 4.02 (released 1998) and later, an infinite value in the left argument causes the corresponding axis of the right argument to be unchanged. In ngn/apl, it simply causes an error.

APLX fills

In APLX, the fill elements used in Take are not always the argument array's prototype: new elements in rows (that is, 1-cells) that already exist are filled based on the first element of that row while new rows use the prototype of the whole array.

APL model

The following dfn models Take as defined by Dyalog APL but with no axis specification or error checking. It is implemented by construction a nested array of indices and using these to select from the right argument, with prototypes used for out-of-range indices. It explicitly includes scalar rank extension for the right argument and the SHARP APL extension; if these extensions are not wanted those lines can be removed. Scalar rank extension of the left argument is inherited from Iota and scalar function extension.

Take ← {
    ⎕IO←0                         ⍝ For index comparisons
    r s ← ≢¨(⍴⍵)(⍺)               ⍝ Rank and number of modified axes
    (r=0)∧s>0: ⍺∇(s⍴1)⍴⍵          ⍝ Right argument scalar rank extension
    s<r: (⍺,(s-r)∇⍴⍵)∇⍵           ⍝ SHARP APL extension
    inds ← ((⍺<0)×⍺+⍴⍵)∘+¨ ⍳|⍺    ⍝ Indices to select
    sel ← {
        ∧/(0≤⍺)∧⍺<⍴⍵: (⊂⍺)⊃⍵      ⍝ In range: use Pick
        ⊃0⍴⍵                      ⍝ Otherwise, get prototype
    }
    sel∘⍵¨ inds
}
Works in: Dyalog APL

This definition could be converted to work in a flat APL with the Rank operator by using an odometer function like ⊢⊤(⍳×/) in place of Iota and changing the two subsequent uses of Each to Rank 1.

History

In A Programming Language, prefix and suffix operations were described using the syntax to take the first elements of vector and for the last elements. This combined a use of the special prefix and suffix vectors and with compression, with the length inferred based on the length of . The symbol was used for vector Rotate, while rotated in the opposite direction.[1] All these definitions appear in IVSYS/7090, with adjustments to fit a linear syntax.

The first version of APL\360[2] followed Iverson notation in defining prefix (n ⍺ j) and suffix (n ⍵ j) vectors but not Take, even though the arrow symbols were no longer used for Rotate. For a vector x, what is now j↑x would have been written ((⍴x)⍺j)/x while (-j)↑x would be ((⍴x)⍵j)/x. The functions Take and Drop using arrow symbols were introduced by 1968.[3] They were implemented for arrays (not just vectors), and extended to allow the left argument to be larger than the right argument's shape (introducing overtaking and fill elements) in 1970.[4]

The axis specification for Take was defined in APL2. It is shared by SHARP APL and Rationalized APL, and continues to be supported in Dyalog APL.

SHARP APL 19.0, released in 1987, extended Take to allow short left arguments. The choice to align left argument elements with the leading axes of the right argument was made according to the nascent leading axis theory: while a user may not have any preference for manipulating the earlier dimensions, this choice makes Take more flexible when used with the Rank operator.[5] It has been present in J and ngn/apl since early development, and was adopted in Dyalog APL 13.0 (2011), as well as NARS2000 between 2017 and 2019.[6]

Extension support

In the table below, "Scalar right arg" indicates scalar rank extension of the right argument, and "Short left arg" is the SHARP APL extension.

Languages Scalar right arg Short left arg Axis specification
APL\360 No No No
APL2, APLX, GNU APL Yes No Yes
SHARP APL, Dyalog APL, NARS2000, Kap Yes Yes Yes
A+, ngn/apl, J ({.), BQN Yes Yes No
dzaima/APL, Uiua No Yes No

Additionally, A+ requires the left argument to be a singleton, and dzaima/APL does not allow overtaking (so that the result of Take cannot contain fills).

See also

External links

Lessons

Documentation

References

  1. Iverson, K.E. (1962). A Programming Language. Wiley. ISBN 978-0-471-43014-8.
  2. Falkoff, A.D., and K.E. Iverson. "The APL\360 Terminal System". Research Report RC-1922, IBM, 1967-10-16.
  3. Falkoff, A.D., and K.E. Iverson, "APL\360 User's Manual". IBM, August 1968.
  4. "I.B.M. Report". APL Quote-Quad Volume 2, Number 1. 1970-04.
  5. Bernecky, Robert. "An Introduction to Function Rank". APL88 Conference Proceedings. ACM SIGAPL Quote Quad, 18(2), December 1987.
  6. Smith, Bob. "Progress in NARS2000 October 2017 to September 2019". Presented at Minnowbrook 2019 and published independently.
APL built-ins [edit]
Primitives (Timeline) Functions
Scalar
Monadic ConjugateNegateSignumReciprocalMagnitudeExponentialNatural LogarithmFloorCeilingFactorialNotPi TimesRollTypeImaginarySquare RootRound
Dyadic AddSubtractTimesDivideResiduePowerLogarithmMinimumMaximumBinomialComparison functionsBoolean functions (And, Or, Nand, Nor) ∙ GCDLCMCircularComplexRoot
Non-Scalar
Structural ShapeReshapeTallyDepthRavelEnlistTableCatenateReverseRotateTransposeRazeMixSplitEncloseNestCut (K)PairLinkPartitioned EnclosePartition
Selection FirstPickTakeDropUniqueIdentityStopSelectReplicateExpandSet functions (IntersectionUnionWithout) ∙ Bracket indexingIndexCartesian ProductSort
Selector Index generatorGradeIndex OfInterval IndexIndicesDealPrefix and suffix vectors
Computational MatchNot MatchMembershipFindNub SieveEncodeDecodeMatrix InverseMatrix DivideFormatExecuteMaterialiseRange
Operators Monadic EachCommuteConstantReplicateExpandReduceWindowed ReduceScanOuter ProductKeyI-BeamSpawnFunction axisIdentity (Null, Ident)
Dyadic BindCompositions (Compose, Reverse Compose, Beside, Withe, Atop, Over) ∙ Inner ProductDeterminantPowerAtUnderRankDepthVariantStencilCutDirect definition (operator)Identity (Lev, Dex)
Quad names Index originComparison toleranceMigration levelAtomic vector