Index Generator: Difference between revisions

From APL Wiki
Jump to navigation Jump to search
m (Text replacement - "</source>" to "</syntaxhighlight>")
Line 2: Line 2:
{{Built-in|Index Generator|⍳}} or '''Interval''', often called by the name of its [[glyph]] '''Iota''', is a [[monadic]] [[primitive function]] which returns an array of [[index|indices]] with [[shape]] given by the right [[argument]]. In the result, the [[element]] at each [[index]] is that index.
{{Built-in|Index Generator|⍳}} or '''Interval''', often called by the name of its [[glyph]] '''Iota''', is a [[monadic]] [[primitive function]] which returns an array of [[index|indices]] with [[shape]] given by the right [[argument]]. In the result, the [[element]] at each [[index]] is that index.


Originally, Iota was defined only on a single number. In [[APL/360]], and all later APLs, <source lang=apl inline>⍳l</source> for a [[scalar]] <source lang=apl inline>l</source> returns a [[simple]] [[numeric]] [[vector]] of length <source lang=apl inline>l</source> counting from the [[index origin]] up. In [[Nested array theory|nested]] APLs, this result may be seen as an array of [[scalar]] indices; [[NARS]] extended Iota to allow a vector argument by making the result for a non-[[singleton]] vector be an array of vector indices. [[Flat array theory|Flat]] APLs do not use this extension, but may extend to multiple argument elements in different ways. [[A Dictionary of APL]] defines Iota to have [[function rank]] 0, and [[SHARP APL]] gives it rank 1 but requires each row (1-[[cell]]) of the argument to have length 1. In [[A+]] and [[J]] Iota of a vector returns an array which counts up in [[ravel order]], that is, it matches Iota of its [[bound]], [[reshape]]d. A+ refers to this function as '''Interval''' while J calls it '''Integers'''.
Originally, Iota was defined only on a single number. In [[APL/360]], and all later APLs, <source lang=apl inline>⍳l</syntaxhighlight> for a [[scalar]] <source lang=apl inline>l</syntaxhighlight> returns a [[simple]] [[numeric]] [[vector]] of length <source lang=apl inline>l</syntaxhighlight> counting from the [[index origin]] up. In [[Nested array theory|nested]] APLs, this result may be seen as an array of [[scalar]] indices; [[NARS]] extended Iota to allow a vector argument by making the result for a non-[[singleton]] vector be an array of vector indices. [[Flat array theory|Flat]] APLs do not use this extension, but may extend to multiple argument elements in different ways. [[A Dictionary of APL]] defines Iota to have [[function rank]] 0, and [[SHARP APL]] gives it rank 1 but requires each row (1-[[cell]]) of the argument to have length 1. In [[A+]] and [[J]] Iota of a vector returns an array which counts up in [[ravel order]], that is, it matches Iota of its [[bound]], [[reshape]]d. A+ refers to this function as '''Interval''' while J calls it '''Integers'''.


== Examples ==
== Examples ==


<source lang=apl inline>⍳n</source> returns the first <source lang=apl inline>n</source> [[index|indices]] in order:
<source lang=apl inline>⍳n</syntaxhighlight> returns the first <source lang=apl inline>n</syntaxhighlight> [[index|indices]] in order:
<source lang=apl>
<source lang=apl>
       ⍳ 5
       ⍳ 5
1 2 3 4 5
1 2 3 4 5
</source>
</syntaxhighlight>
This result depends on [[index origin]]: if the index origin is set to zero, it starts counting from zero instead:
This result depends on [[index origin]]: if the index origin is set to zero, it starts counting from zero instead:
<source lang=apl>
<source lang=apl>
Line 16: Line 16:
       ⍳ 5
       ⍳ 5
0 1 2 3 4
0 1 2 3 4
</source>
</syntaxhighlight>
An argument of <source lang=apl inline>0</source> produces the [[empty]] [[vector]], [[Zilde]]:
An argument of <source lang=apl inline>0</syntaxhighlight> produces the [[empty]] [[vector]], [[Zilde]]:
<source lang=apl>
<source lang=apl>
       ⍳ 0
       ⍳ 0
Line 23: Line 23:
       ⍬ ≡ ⍳ 0
       ⍬ ≡ ⍳ 0
1
1
</source>
</syntaxhighlight>


=== Vector arguments ===
=== Vector arguments ===


In [[A+]] and [[J]], Iota always returns a [[simple]] array. The equivalence <source lang=apl inline>⍳V</source> {{←→}} <source lang=apl inline>V⍴⍳×/V</source> defines the result for non-singleton vectors. If the argument is an [[empty]] vector, the result is a [[scalar]]: the [[index origin]] (which is always 0 in these languages).
In [[A+]] and [[J]], Iota always returns a [[simple]] array. The equivalence <source lang=apl inline>⍳V</syntaxhighlight> {{←→}} <source lang=apl inline>V⍴⍳×/V</syntaxhighlight> defines the result for non-singleton vectors. If the argument is an [[empty]] vector, the result is a [[scalar]]: the [[index origin]] (which is always 0 in these languages).
<source lang=apl>
<source lang=apl>
   ⍳ 2 3 4
   ⍳ 2 3 4
Line 39: Line 39:
   ⍳ 0⍴0
   ⍳ 0⍴0
0
0
</source>{{Works in|[[A+]]}}
</syntaxhighlight>{{Works in|[[A+]]}}
We might call such a function a "[[ravel index]] generator" since the result is an array of [[scalar]] indices into its own [[ravel]]. In contrast, [[nested array theory|nested]] APLs, if they implement Iota for a vector argument ([[APL2]] and [[APLX]], for example, do not), use [[index|indices]] of [[element]]s:
We might call such a function a "[[ravel index]] generator" since the result is an array of [[scalar]] indices into its own [[ravel]]. In contrast, [[nested array theory|nested]] APLs, if they implement Iota for a vector argument ([[APL2]] and [[APLX]], for example, do not), use [[index|indices]] of [[element]]s:
<source lang=apl>
<source lang=apl>
Line 54: Line 54:
       (⊂⍬) ≡ ⍳⍬
       (⊂⍬) ≡ ⍳⍬
1
1
</source>{{Works in|[[NARS]], [[NARS2000]], [[Dyalog APL]], [[GNU APL]], [[ngn/apl]], [[dzaima/APL]]}}
</syntaxhighlight>{{Works in|[[NARS]], [[NARS2000]], [[Dyalog APL]], [[GNU APL]], [[ngn/apl]], [[dzaima/APL]]}}
The result of <source lang=apl inline>⍳⍬</source> should have [[shape]] <source lang=apl inline>⍬</source>, implying it is a [[scalar]], and its only [[element]] must be the only possible [[index]] into a scalar, the [[empty]] vector. This means it must be <source lang=apl inline>⊂⍬</source>. However, [[Dyalog APL]] returned the scalar <source lang=apl inline>⎕IO</source> instead prior to [[Dyalog APL 13.0|version 13.0]].
The result of <source lang=apl inline>⍳⍬</syntaxhighlight> should have [[shape]] <source lang=apl inline>⍬</syntaxhighlight>, implying it is a [[scalar]], and its only [[element]] must be the only possible [[index]] into a scalar, the [[empty]] vector. This means it must be <source lang=apl inline>⊂⍬</syntaxhighlight>. However, [[Dyalog APL]] returned the scalar <source lang=apl inline>⎕IO</syntaxhighlight> instead prior to [[Dyalog APL 13.0|version 13.0]].


=== Negative arguments ===
=== Negative arguments ===
Line 66: Line 66:
  1 ¯2  1 ¯1  1 0
  1 ¯2  1 ¯1  1 0
  2 ¯2  2 ¯1  2 0
  2 ¯2  2 ¯1  2 0
</source>{{Works in|[[NARS2000]], <source lang=apl inline>⎕FEATURE[⎕IO]←1</source>}}
</syntaxhighlight>{{Works in|[[NARS2000]], <source lang=apl inline>⎕FEATURE[⎕IO]←1</syntaxhighlight>}}


In [[J]], a negative number [[reverse]]s the result along that axis.
In [[J]], a negative number [[reverse]]s the result along that axis.
Line 73: Line 73:
2 1 0
2 1 0
5 4 3
5 4 3
</source>{{Works in|[[J]]}}
</syntaxhighlight>{{Works in|[[J]]}}


== Scalar-vector discrepancy in nested APLs ==
== Scalar-vector discrepancy in nested APLs ==
Line 81: Line 81:
Such an extension breaks compatibility with earlier non-nested APLs: although these APLs required the argument of Iota to be a [[singleton]], they always allowed a [[scalar]] or [[vector]], and sometimes any [[singleton]]. This is because a shape to be passed to Iota would often naturally be a vector: for example, [[Shape]] always returns a vector, and a function such as [[Tally]] to return a scalar length did not exist.
Such an extension breaks compatibility with earlier non-nested APLs: although these APLs required the argument of Iota to be a [[singleton]], they always allowed a [[scalar]] or [[vector]], and sometimes any [[singleton]]. This is because a shape to be passed to Iota would often naturally be a vector: for example, [[Shape]] always returns a vector, and a function such as [[Tally]] to return a scalar length did not exist.


[[NARS]] defines its extension using the equivalence <source lang=apl inline>⍳R</source> {{←→}} <source lang=apl inline>⊃∘.,/⍳¨R</source> based on an [[Outer Product]] [[reduction]]. For a singleton vector <source lang=apl inline>R</source>, this does yield a simple result, because <source lang=apl inline>∘.,/</source> leaves a singleton argument unchanged. However, this is arguably due to inconsistent design in [[Reduce]]: [[NARS]]'s creator, [[Bob Smith]], argues that [[Catenate]] reduction should yield a [[DOMAIN ERROR]], and the same arguments apply to its Outer Product.<ref>[[Bob Smith|Smith, Bob]]. [http://www.sudleyplace.com/APL/Reduction%20Of%20Singletons.pdf "Reduction of Singletons"]. [[Minnowbrook]] 2010.</ref>
[[NARS]] defines its extension using the equivalence <source lang=apl inline>⍳R</syntaxhighlight> {{←→}} <source lang=apl inline>⊃∘.,/⍳¨R</syntaxhighlight> based on an [[Outer Product]] [[reduction]]. For a singleton vector <source lang=apl inline>R</syntaxhighlight>, this does yield a simple result, because <source lang=apl inline>∘.,/</syntaxhighlight> leaves a singleton argument unchanged. However, this is arguably due to inconsistent design in [[Reduce]]: [[NARS]]'s creator, [[Bob Smith]], argues that [[Catenate]] reduction should yield a [[DOMAIN ERROR]], and the same arguments apply to its Outer Product.<ref>[[Bob Smith|Smith, Bob]]. [http://www.sudleyplace.com/APL/Reduction%20Of%20Singletons.pdf "Reduction of Singletons"]. [[Minnowbrook]] 2010.</ref>


== History ==
== History ==
Line 92: Line 92:


The name "iota" has sometimes been used to indicate an increasing sequence of integers even in languages other than APL:
The name "iota" has sometimes been used to indicate an increasing sequence of integers even in languages other than APL:
* The [[wikipedia:C++|C++11]] standard library has <source lang=c++ inline>std::iota()</source> fills an iterator with such a sequence, and was named after the APL glyph.<ref>cppreference.com. [https://en.cppreference.com/w/cpp/algorithm/iota std::iota]. Retrieved 2020-04-28.</ref><ref name="iotashaming"/><ref>Rob Mayoff. [https://stackoverflow.com/a/9244949 Answer to "What does iota of std::iota stand for?"] on Stack Overflow.  Retrieved 2020-04-28.</ref>
* The [[wikipedia:C++|C++11]] standard library has <source lang=c++ inline>std::iota()</syntaxhighlight> fills an iterator with such a sequence, and was named after the APL glyph.<ref>cppreference.com. [https://en.cppreference.com/w/cpp/algorithm/iota std::iota]. Retrieved 2020-04-28.</ref><ref name="iotashaming"/><ref>Rob Mayoff. [https://stackoverflow.com/a/9244949 Answer to "What does iota of std::iota stand for?"] on Stack Overflow.  Retrieved 2020-04-28.</ref>
* The [[wikipedia:Go (programming language)|Go]] language also uses the name <source lang=go inline>iota</source> as a predeclared identifier which represents increasing integers: each time it is used within a single constant declaration its value will be one higher.<ref>The Go Programming Language Specification. [https://golang.org/ref/spec#Iota Iota]. 2020-01-14.</ref>
* The [[wikipedia:Go (programming language)|Go]] language also uses the name <source lang=go inline>iota</syntaxhighlight> as a predeclared identifier which represents increasing integers: each time it is used within a single constant declaration its value will be one higher.<ref>The Go Programming Language Specification. [https://golang.org/ref/spec#Iota Iota]. 2020-01-14.</ref>
* The popular [[wikipedia:Scheme (programming language)|Scheme]] list library SRFI 1 also includes a function called <source lang=scheme inline>iota</source> in reference to APL, which takes a count as well as optional starting value (default 0) and step size (default 1) arguments.<ref>Olin Shivers. [https://srfi.schemers.org/srfi-1/srfi-1.html#iota SRFI 1: List Library]. Finalized 1999-10-09.</ref>
* The popular [[wikipedia:Scheme (programming language)|Scheme]] list library SRFI 1 also includes a function called <source lang=scheme inline>iota</syntaxhighlight> in reference to APL, which takes a count as well as optional starting value (default 0) and step size (default 1) arguments.<ref>Olin Shivers. [https://srfi.schemers.org/srfi-1/srfi-1.html#iota SRFI 1: List Library]. Finalized 1999-10-09.</ref>
* The [[wikipedia:ArrayFire|ArrayFire]] library for [[wikipedia:general-purpose computing on graphics processing units|general-purpose computing on graphics processing units]] has an <source lang=c inline>iota</source> function with a result similar to that of A+ and J when given a [[#Vector_arguments|vector argument]].<ref>ArrayFire: Functions. [https://arrayfire.org/docs/group__data__func__iota.htm iota]. Jun 2, 2015.</ref>
* The [[wikipedia:ArrayFire|ArrayFire]] library for [[wikipedia:general-purpose computing on graphics processing units|general-purpose computing on graphics processing units]] has an <source lang=c inline>iota</syntaxhighlight> function with a result similar to that of A+ and J when given a [[#Vector_arguments|vector argument]].<ref>ArrayFire: Functions. [https://arrayfire.org/docs/group__data__func__iota.htm iota]. Jun 2, 2015.</ref>
* The [[wikipedia:Berkeley Software Distribution|BSD]] operating system and its derivatives, for example [[wikipedia:macOS|macOS]], have a <source lang=shell inline>jot</source> which can print sequential data. The name <source lang=shell inline>jot</source> derives in part from APL's glyph.<ref>openbsd.org. [https://man.openbsd.org/jot#DESCRIPTION jot]. Retrieved 2022-08-04.</ref>
* The [[wikipedia:Berkeley Software Distribution|BSD]] operating system and its derivatives, for example [[wikipedia:macOS|macOS]], have a <source lang=shell inline>jot</syntaxhighlight> which can print sequential data. The name <source lang=shell inline>jot</syntaxhighlight> derives in part from APL's glyph.<ref>openbsd.org. [https://man.openbsd.org/jot#DESCRIPTION jot]. Retrieved 2022-08-04.</ref>


== See also ==
== See also ==

Revision as of 21:31, 10 September 2022

This page is about generating indices for an array of a given size. See Indexing, Indices, Index of, and Interval Index for other operations named after indices.

Index Generator () or Interval, often called by the name of its glyph Iota, is a monadic primitive function which returns an array of indices with shape given by the right argument. In the result, the element at each index is that index.

Originally, Iota was defined only on a single number. In APL/360, and all later APLs, <source lang=apl inline>⍳l</syntaxhighlight> for a scalar <source lang=apl inline>l</syntaxhighlight> returns a simple numeric vector of length <source lang=apl inline>l</syntaxhighlight> counting from the index origin up. In nested APLs, this result may be seen as an array of scalar indices; NARS extended Iota to allow a vector argument by making the result for a non-singleton vector be an array of vector indices. Flat APLs do not use this extension, but may extend to multiple argument elements in different ways. A Dictionary of APL defines Iota to have function rank 0, and SHARP APL gives it rank 1 but requires each row (1-cell) of the argument to have length 1. In A+ and J Iota of a vector returns an array which counts up in ravel order, that is, it matches Iota of its bound, reshaped. A+ refers to this function as Interval while J calls it Integers.

Examples

<source lang=apl inline>⍳n</syntaxhighlight> returns the first <source lang=apl inline>n</syntaxhighlight> indices in order: <source lang=apl>

     ⍳ 5

1 2 3 4 5 </syntaxhighlight> This result depends on index origin: if the index origin is set to zero, it starts counting from zero instead: <source lang=apl>

     ⎕IO ← 0
     ⍳ 5

0 1 2 3 4 </syntaxhighlight> An argument of <source lang=apl inline>0</syntaxhighlight> produces the empty vector, Zilde: <source lang=apl>

     ⍳ 0
     ⍬ ≡ ⍳ 0

1 </syntaxhighlight>

Vector arguments

In A+ and J, Iota always returns a simple array. The equivalence <source lang=apl inline>⍳V</syntaxhighlight> <source lang=apl inline>V⍴⍳×/V</syntaxhighlight> defines the result for non-singleton vectors. If the argument is an empty vector, the result is a scalar: the index origin (which is always 0 in these languages). <source lang=apl>

  ⍳ 2 3 4
0  1  2  3
4  5  6  7
8  9 10 11

12 13 14 15 16 17 18 19 20 21 22 23

  ⍳ 0⍴0

0

</syntaxhighlight>

Works in: A+

We might call such a function a "ravel index generator" since the result is an array of scalar indices into its own ravel. In contrast, nested APLs, if they implement Iota for a vector argument (APL2 and APLX, for example, do not), use indices of elements: <source lang=apl>

     ⍳ 2 5

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

     ⍳⍬

┌┐ ││ └┘

     (⊂⍬) ≡ ⍳⍬

1

</syntaxhighlight>

The result of <source lang=apl inline>⍳⍬</syntaxhighlight> should have shape <source lang=apl inline>⍬</syntaxhighlight>, implying it is a scalar, and its only element must be the only possible index into a scalar, the empty vector. This means it must be <source lang=apl inline>⊂⍬</syntaxhighlight>. However, Dyalog APL returned the scalar <source lang=apl inline>⎕IO</syntaxhighlight> instead prior to version 13.0.

Negative arguments

Two languages extend Iota to allow negative arguments. In both cases, the shape of the result is the absolute value of the argument.

In the nested APL NARS2000, negating one number in the argument subtracts that value from each index along the corresponding axis. <source lang=apl>

     ⍳2 ¯3
1 ¯2  1 ¯1  1 0
2 ¯2  2 ¯1  2 0

</syntaxhighlight>

Works in: NARS2000, <source lang=apl inline>⎕FEATURE[⎕IO]←1</syntaxhighlight>

In J, a negative number reverses the result along that axis. <source lang=j>

  i. 2 _3

2 1 0 5 4 3

</syntaxhighlight>

Works in: J

Scalar-vector discrepancy in nested APLs

In NARS and later nested APLs which share its definition, the result of Iota is simple when the argument is a singleton and nested otherwise. This is because, when the argument is a singleton, each index in the result is represented as a scalar rather than a 1-element vector. dzaima/APL breaks from this definition by using vector indices whenever the argument is a vector, and scalar indices if the argument is a scalar, so that the result is only simple if the argument was scalar. This definition has the property that the shape of each index matches the shape of the argument.

Such an extension breaks compatibility with earlier non-nested APLs: although these APLs required the argument of Iota to be a singleton, they always allowed a scalar or vector, and sometimes any singleton. This is because a shape to be passed to Iota would often naturally be a vector: for example, Shape always returns a vector, and a function such as Tally to return a scalar length did not exist.

NARS defines its extension using the equivalence <source lang=apl inline>⍳R</syntaxhighlight> <source lang=apl inline>⊃∘.,/⍳¨R</syntaxhighlight> based on an Outer Product reduction. For a singleton vector <source lang=apl inline>R</syntaxhighlight>, this does yield a simple result, because <source lang=apl inline>∘.,/</syntaxhighlight> leaves a singleton argument unchanged. However, this is arguably due to inconsistent design in Reduce: NARS's creator, Bob Smith, argues that Catenate reduction should yield a DOMAIN ERROR, and the same arguments apply to its Outer Product.[1]

History

The Greek letter iota, corresponding to the Latin letter i, now usually treated as a mnemonic for "integers" or "index", more likely stood for "identity" in early Iverson notation. Iverson's 1960 paper The Description of Finite Sequential Processes states that "the identity permutation vector is defined by the relation ."[2] Since is a more typical letter to use for the identity permutation, it's possible that Iverson's choice was also motivated by the convention of using for an inclusion map, where iota now indicates "inclusion" or "injection".[3] The term "inclusion" typically indicates that a particular injection is meant to be treated as an identity.

The notation , "Interval", was used in A Programming Language for the vector of the first indices starting at index origin . Both arguments were optional, with being implied by conformability if omitted. It was adopted with the obvious alterations in APL\360, and extended to a vector argument for nested APLs by NARS and for flat arrays by A+.

Outside of APL

The name "iota" has sometimes been used to indicate an increasing sequence of integers even in languages other than APL:

  • The C++11 standard library has <source lang=c++ inline>std::iota()</syntaxhighlight> fills an iterator with such a sequence, and was named after the APL glyph.[4][3][5]
  • The Go language also uses the name <source lang=go inline>iota</syntaxhighlight> as a predeclared identifier which represents increasing integers: each time it is used within a single constant declaration its value will be one higher.[6]
  • The popular Scheme list library SRFI 1 also includes a function called <source lang=scheme inline>iota</syntaxhighlight> in reference to APL, which takes a count as well as optional starting value (default 0) and step size (default 1) arguments.[7]
  • The ArrayFire library for general-purpose computing on graphics processing units has an <source lang=c inline>iota</syntaxhighlight> function with a result similar to that of A+ and J when given a vector argument.[8]
  • The BSD operating system and its derivatives, for example macOS, have a <source lang=shell inline>jot</syntaxhighlight> which can print sequential data. The name <source lang=shell inline>jot</syntaxhighlight> derives in part from APL's glyph.[9]

See also

External links

Tutorials

Documentation

References

  1. Smith, Bob. "Reduction of Singletons". Minnowbrook 2010.
  2. Ken Iverson. The Description of Finite Sequential Processes. Proceedings of a Conference on Information Theory, C. Cherry and W. Jackson, Editors, Imperial College, London, 1960-08-29.
  3. 3.0 3.1 Sean Parent. "#iotashaming". sean-parent.stlab.cc. 2019-01-04.
  4. cppreference.com. std::iota. Retrieved 2020-04-28.
  5. Rob Mayoff. Answer to "What does iota of std::iota stand for?" on Stack Overflow. Retrieved 2020-04-28.
  6. The Go Programming Language Specification. Iota. 2020-01-14.
  7. Olin Shivers. SRFI 1: List Library. Finalized 1999-10-09.
  8. ArrayFire: Functions. iota. Jun 2, 2015.
  9. openbsd.org. jot. Retrieved 2022-08-04.
APL built-ins [edit]
Primitive functions
Scalar
Monadic ConjugateNegateSignumReciprocalMagnitudeExponentialNatural LogarithmFloorCeilingFactorialNotPi TimesRollTypeImaginarySquare Root
Dyadic AddSubtractTimesDivideResiduePowerLogarithmMinimumMaximumBinomialComparison functionsBoolean functions (And, Or, Nand, Nor) ∙ GCDLCMCircularComplexRoot
Non-Scalar
Structural ShapeReshapeTallyDepthRavelEnlistTableCatenateReverseRotateTransposeRazeMixSplitEncloseNestCut (K)PairLinkPartitioned EnclosePartition
Selection FirstPickTakeDropUniqueIdentitySelectReplicateExpandSet functions (IntersectionUnionWithout) ∙ Bracket indexingIndex
Selector Index generatorGradeIndex OfInterval IndexIndicesDeal
Computational MatchNot MatchMembershipFindNub SieveEncodeDecodeMatrix InverseMatrix DivideFormatExecuteMaterialiseRange
Primitive operators Monadic EachCommuteConstantReplicateExpandReduceWindowed ReduceScanOuter ProductKeyI-BeamSpawnFunction axis
Dyadic BindCompositions (Compose, Reverse Compose, Beside, Withe, Atop, Over) ∙ Inner ProductPowerAtUnderRankDepthVariantStencilCut (J)
Quad names
Arrays Index originMigration levelAtomic vector
Functions Name classCase convertUnicode convert
Operators SearchReplace