Indices
- This page about finding indices of non-zero values. See Index for the page on indices themselves. See Indexing, Index Generator, Index of, and Interval Index for other operations named after indices.
⍸
|
Indices (⍸
), or Where, is a monadic primitive function which returns the indices of all ones in a Boolean array. More generally, Indices accepts an array of non-negative integers and copies each index the corresponding number of times. It is closely related to Replicate, and may be seen as an index-based equivalent to Replicate in the same way that Grade is an index-based equivalent of sorting.
In K, the first language to include the primitive, it is called Where (&
). In J, it is called Indices (<source lang=j inline>I.</syntaxhighlight>).
Examples
In all implementations, Indices gives the indices of ones in a Boolean vector. <source lang=apl>
⍸ 0 0 1 0 0 0 1 0
3 7 </syntaxhighlight>
In nested APLs it returns nested indices when passed a matrix or higher-dimensional array. <source lang=apl>
⍸ 3 3⍴0 0 1 0 0 0 1 0
┌───┬───┐ │1 3│3 1│ └───┴───┘
⍸ 1 ⍝ An index into a scalar is empty!
┌┐ ││ └┘ </syntaxhighlight>
If numbers higher than 1 are allowed, they indicate that the index of the number is repeated. Negative numbers are never allowed. <source lang=apl>
⍸ 3 0 2
1 1 1 3 3 </syntaxhighlight>
Description and APL model
Indices replicates each index in the argument by the number of times it appears. It is identical to the APL function: <source lang=apl> Where ← {(,⍵)⌿,⍳⍴⍵} </syntaxhighlight>
The argument is restricted to be an array of non-negative integers, or, in Dyalog APL, Booleans.
Because Indices returns indices (like Iota), it is subject to index origin.
The only flat array language which implements Indices is J. Because J's Iota does not return multidimensional indices, J defines Indices to have function rank 1 so that only vector indices are used.
Mathematical interpretation
Indices may be viewed as a way to convert between two ways of writing multisets of array indices. The argument uses a dense representation indicating for each index the number of times it appears, and the result uses a sparse representation which lists all the indices contained in the set.
Relation with Replicate
Indices on a vector is closely related to Replicate: for vectors <source lang=apl inline>V</syntaxhighlight> and <source lang=apl inline>W</syntaxhighlight>, we have <source lang=apl inline>⍸V</syntaxhighlight> <source lang=apl inline>V/⍳≢V</syntaxhighlight> and <source lang=apl inline>V⌿X</syntaxhighlight> <source lang=apl inline>X[⍸V]</syntaxhighlight>. While Replicate performs a transformation on another array, Indices gives a representation of that transformation using indices. The relationship between Indices and Replicate parallels that between Grade and Sort By.
K takes advantage of this relationship by removing the primitive Replicate entirely: the glyph &
is paired with Minimum instead. In K, Replicate is performed by using Where and then indexing.
Inverse
The inverse of Indices, <source lang=apl inline>⍸⍣¯1</syntaxhighlight>, is the mapping from an ordered (multi-)set of indices to an array where each element is the count for its position. For a simple non-empty vector <source lang=apl inline>Y</syntaxhighlight> without duplicates, the expression <source lang=apl inline>R←(⍸⍣¯1)Y</syntaxhighlight> gives a Boolean vector <source lang=apl inline>R</syntaxhighlight> with ones at the indices in <source lang=apl inline>Y</syntaxhighlight>. This is equivalent to <source lang=apl inline>R←(1@Y)0⍴⍨⌈/Y</syntaxhighlight> which is useful in conversion between partition representations.
It should be noted that the inverse is not unique because <source lang=apl inline>(⍸Y) ≡ (⍸Z)</syntaxhighlight> if <source lang=apl inline>Y</syntaxhighlight> and <source lang=apl inline>Z</syntaxhighlight> differ only by the number of trailing zeros. <source lang=apl inline>⍸⍣¯1</syntaxhighlight> does not add any trailing zeros, and it may be necessary to add those separately, for example using overtake.
History
Idioms with similar behavior to Indices were widely used in APL long before it was made into a primitive. For example, the FinnAPL idiom library, first presented in 1984, lists <source lang=apl inline>X/⍳⍴X</syntaxhighlight> as "594. Indices of ones in logical vector X".
Where (&
) with a Boolean argument was present in K by K2 in 1996,[1] and extended to non-negative integers by K4 in 2000. It was added to J for the domain of non-negative integer vectors as Indices (<source lang=j inline>I.</syntaxhighlight>) in release 5.02 (2003), introducing the pairing of Indices and Interval Index now used in APL.[2]
Indices (<source lang=apl inline>⍸</syntaxhighlight>) was first introduced to APL, and the nested array model, by NARS2000. Originally defined only for vectors, the generalised definition <source lang=apl inline>(,R)/,⍳⍴1/R</syntaxhighlight> was introduced in about 2013 after some experimentation with alternatives.[3] Where (<source lang=apl inline>⍸</syntaxhighlight>) was added to Dyalog APL 16.0 (June 2017), with the nearly-identical definition <source lang=apl inline>{(,⍵)⌿,⍳⍴⍵}</syntaxhighlight>, but also with the restriction that the argument be Boolean. This restriction that was lifted to allow non-negative integers in 18.0 (2020). For a scalar <source lang=apl inline>I</syntaxhighlight>, Dyalog's definition gives <source lang=apl inline>I⍴⊂⍬</syntaxhighlight> for <source lang=apl inline>⍸I</syntaxhighlight>, while NARS2000 returned <source lang=apl inline>I⍴1</syntaxhighlight>. By January 2018, NARS2000 switched to Dyalog's definition, removing the discrepancy for scalar arguments.
The inverse of Indices became supported with Dyalog APL 18.0.
External links
Lessons
Documentation
- Dyalog
- NARS2000
- J Dictionary, NuVoc (as <source lang=j inline>I.</syntaxhighlight>)
- BQN (as
/
) - Kona (K3) (as
&
)
References
- ↑ Kx Systems. "K User Manual". 1998.
- ↑ Jsoftware. "I. Implements Indices. 2003.
- ↑ NARS2000 Wiki. Indices. Old revision: 2013-05-26.