Empty array: Difference between revisions
m (Kinds of array category) |
m (Text replacement - "</source>" to "</syntaxhighlight>") |
||
(One intermediate revision by the same user not shown) | |||
Line 1: | Line 1: | ||
In the APL [[array model]], an '''empty''' array is one with a [[bound]] of zero, that is, an array with no [[element]]s. While a nested list model has only one empty list, APL has many different empty arrays. These arrays are distinguished by their [[shape]] and [[prototype]]. | In the APL [[array model]], an '''empty''' array is one with a [[bound]] of zero, that is, an array with no [[element]]s. While a nested list model has only one empty list, APL has many different empty arrays. These arrays are distinguished by their [[shape]] and [[prototype]]. | ||
Examples of empty arrays are the empty [[numeric]] array [[Zilde]] (< | Examples of empty arrays are the empty [[numeric]] array [[Zilde]] (<syntaxhighlight lang=apl inline>⍬</syntaxhighlight>) and the empty [[character]] array <syntaxhighlight lang=apl inline>''</syntaxhighlight>. These arrays have different prototypes, and do not [[match]] in most APLs. | ||
== Empty array shape == | == Empty array shape == | ||
Line 8: | Line 8: | ||
The primary exception is when using the [[Rank operator]] on an array with no [[cell]]s of the specified rank. Because the shape of each result cell might be determined by values in an argument cell, the appropriate shape may be impossible to determine. | The primary exception is when using the [[Rank operator]] on an array with no [[cell]]s of the specified rank. Because the shape of each result cell might be determined by values in an argument cell, the appropriate shape may be impossible to determine. | ||
< | <syntaxhighlight lang=apl> | ||
⍴ ⍳⍤0 ⊢2⍴3 | ⍴ ⍳⍤0 ⊢2⍴3 | ||
2 3 | 2 3 | ||
Line 15: | Line 15: | ||
⍴ ⍳⍤0 ⊢0⍴3 | ⍴ ⍳⍤0 ⊢0⍴3 | ||
0 0 | 0 0 | ||
</ | </syntaxhighlight> | ||
{{Works in|[[Dyalog APL]], [[NARS2000]]}} | {{Works in|[[Dyalog APL]], [[NARS2000]]}} | ||
The example above shows how an arithmetic rule can fail when using Rank with an empty array. For any positive integer < | The example above shows how an arithmetic rule can fail when using Rank with an empty array. For any positive integer <syntaxhighlight lang=apl inline>n</syntaxhighlight>, it's clear that <syntaxhighlight lang=apl inline>(n,3) ≡ ⍴ ⍳⍤0 ⊢n⍴3</syntaxhighlight> because each result cell is the array <syntaxhighlight lang=apl inline>⍳3</syntaxhighlight>. However, the empty array <syntaxhighlight lang=apl inline>0⍴3</syntaxhighlight> is indistinguishable from any other empty numeric array because it has shape <syntaxhighlight lang=apl inline>,0</syntaxhighlight> and prototype <syntaxhighlight lang=apl inline>0</syntaxhighlight>. This means Rank cannot determine the appropriate result shape. The Rank operator still attempts to find a sensible result shape: it executes the operand on a prototype cell obtained by reshaping the argument to the argument cell shape (here, the prototype cell is a scalar <syntaxhighlight lang=apl inline>0</syntaxhighlight>), and uses the resulting shape to determine the shape of its final result. In this case, this succeeds in finding the appropriate result rank but not the desired shape. | ||
If Rank is implemented by [[split]]ting the argument(s) into cells, applying the operand with [[Each]], and [[mix]]ing, then the above problem actually becomes an issue of empty array prototypes: the result of Split is empty, and calling Each on an empty array uses prototypes to determine prototypes, an unreliable operation. | If Rank is implemented by [[split]]ting the argument(s) into cells, applying the operand with [[Each]], and [[mix]]ing, then the above problem actually becomes an issue of empty array prototypes: the result of Split is empty, and calling Each on an empty array uses prototypes to determine prototypes, an unreliable operation. | ||
Line 28: | Line 28: | ||
Consider the following identities for [[Catenate]] on [[vector]]s, one of which is empty. | Consider the following identities for [[Catenate]] on [[vector]]s, one of which is empty. | ||
< | <syntaxhighlight lang=apl> | ||
a ≡ ⍬,a | a ≡ ⍬,a | ||
b ≡ b,'' | b ≡ b,'' | ||
</ | </syntaxhighlight> | ||
These identities always hold when < | These identities always hold when <syntaxhighlight lang=apl inline>a</syntaxhighlight> and <syntaxhighlight lang=apl inline>b</syntaxhighlight> are non-empty, because the result is non-empty and its elements are entirely determined by the non-empty argument. However, if we consider the catenation | ||
< | <syntaxhighlight lang=apl> | ||
⍬,'' | ⍬,'' | ||
</ | </syntaxhighlight> | ||
then the first identity tells us that the result should be < | then the first identity tells us that the result should be <syntaxhighlight lang=apl inline>''</syntaxhighlight> while the second gives a result of <syntaxhighlight lang=apl inline>⍬</syntaxhighlight>. These two arrays do not match, so one of the identities must be wrong! In fact, the choice of which prototype to use for the result is a source of incompatibility among APLs. In [[Dyalog APL]] it has even been changed in the past. At one point the right argument's prototype was used; now we can inspect the [[first]] element of <syntaxhighlight lang=apl inline>⍬,''</syntaxhighlight> to see that the left argument's prototype is used. | ||
< | <syntaxhighlight lang=apl> | ||
⊃⍬,'' | ⊃⍬,'' | ||
0 | 0 | ||
</ | </syntaxhighlight> | ||
{{Works in|[[Dyalog APL]]}} | {{Works in|[[Dyalog APL]]}} | ||
== Reduction over a length-0 axis == | == Reduction over a length-0 axis == | ||
If a [[Reduce|reduction]] (using one of < | If a [[Reduce|reduction]] (using one of <syntaxhighlight lang=apl inline>/</syntaxhighlight>, <syntaxhighlight lang=apl inline>⌿</syntaxhighlight>, <syntaxhighlight lang=apl inline>\</syntaxhighlight>, or <syntaxhighlight lang=apl inline>⍀</syntaxhighlight>) is performed over an axis of length 0, the resulting array is filled with [[identity element]]s. For example, the sum of an empty list is <syntaxhighlight lang=apl inline>0</syntaxhighlight> because the identity element for [[addition]] is <syntaxhighlight lang=apl inline>0</syntaxhighlight>: | ||
< | <syntaxhighlight lang=apl> | ||
+/0⍴0 | +/0⍴0 | ||
0 | 0 | ||
</ | </syntaxhighlight> | ||
The identity element for a specific reduction always depends on the operand, and may depend on the argument array prototype. Dialects differ in their support for such reductions. All define identity elements for most [[scalar functions#Standard scalar functions|scalar primitives]], and some stop there (e.g. [[SAX]]), while others (e.g. [[Dyalog APL]] and [[APL2]]) define identity elements for various [[mixed function]]s. | The identity element for a specific reduction always depends on the operand, and may depend on the argument array prototype. Dialects differ in their support for such reductions. All define identity elements for most [[scalar functions#Standard scalar functions|scalar primitives]], and some stop there (e.g. [[SAX]]), while others (e.g. [[Dyalog APL]] and [[APL2]]) define identity elements for various [[mixed function]]s. | ||
{{APL features}}[[Category:Kinds of array]] | {{APL features}}[[Category:Kinds of array]] |
Latest revision as of 22:29, 10 September 2022
In the APL array model, an empty array is one with a bound of zero, that is, an array with no elements. While a nested list model has only one empty list, APL has many different empty arrays. These arrays are distinguished by their shape and prototype.
Examples of empty arrays are the empty numeric array Zilde (⍬
) and the empty character array ''
. These arrays have different prototypes, and do not match in most APLs.
Empty array shape
The shape of an empty array is usually determined by shape arithmetic in the function which produces it. Because in most primitive functions the result shape is determined by the argument shapes and sometimes the numeric values of elements from the arguments (for instance, in the left argument of Reshape), the shape of an empty array is rarely in doubt.
The primary exception is when using the Rank operator on an array with no cells of the specified rank. Because the shape of each result cell might be determined by values in an argument cell, the appropriate shape may be impossible to determine.
⍴ ⍳⍤0 ⊢2⍴3 2 3 ⍴ ⍳⍤0 ⊢1⍴3 1 3 ⍴ ⍳⍤0 ⊢0⍴3 0 0
The example above shows how an arithmetic rule can fail when using Rank with an empty array. For any positive integer n
, it's clear that (n,3) ≡ ⍴ ⍳⍤0 ⊢n⍴3
because each result cell is the array ⍳3
. However, the empty array 0⍴3
is indistinguishable from any other empty numeric array because it has shape ,0
and prototype 0
. This means Rank cannot determine the appropriate result shape. The Rank operator still attempts to find a sensible result shape: it executes the operand on a prototype cell obtained by reshaping the argument to the argument cell shape (here, the prototype cell is a scalar 0
), and uses the resulting shape to determine the shape of its final result. In this case, this succeeds in finding the appropriate result rank but not the desired shape.
If Rank is implemented by splitting the argument(s) into cells, applying the operand with Each, and mixing, then the above problem actually becomes an issue of empty array prototypes: the result of Split is empty, and calling Each on an empty array uses prototypes to determine prototypes, an unreliable operation.
Empty array prototype
Because an empty array has no elements from which a prototype could be derived, prototype or type information must be stored with the array.
Determining the prototype of an empty array when it is produced is often difficult, and may break identities even for simple functions. An empty array's prototype is far less reliable than its shape.
Consider the following identities for Catenate on vectors, one of which is empty.
a ≡ ⍬,a b ≡ b,''
These identities always hold when a
and b
are non-empty, because the result is non-empty and its elements are entirely determined by the non-empty argument. However, if we consider the catenation
⍬,''
then the first identity tells us that the result should be ''
while the second gives a result of ⍬
. These two arrays do not match, so one of the identities must be wrong! In fact, the choice of which prototype to use for the result is a source of incompatibility among APLs. In Dyalog APL it has even been changed in the past. At one point the right argument's prototype was used; now we can inspect the first element of ⍬,''
to see that the left argument's prototype is used.
⊃⍬,'' 0
Reduction over a length-0 axis
If a reduction (using one of /
, ⌿
, \
, or ⍀
) is performed over an axis of length 0, the resulting array is filled with identity elements. For example, the sum of an empty list is 0
because the identity element for addition is 0
:
+/0⍴0 0
The identity element for a specific reduction always depends on the operand, and may depend on the argument array prototype. Dialects differ in their support for such reductions. All define identity elements for most scalar primitives, and some stop there (e.g. SAX), while others (e.g. Dyalog APL and APL2) define identity elements for various mixed functions.
APL features [edit] | |
---|---|
Built-ins | Primitives (functions, operators) ∙ Quad name |
Array model | Shape ∙ Rank ∙ Depth ∙ Bound ∙ Index (Indexing) ∙ Axis ∙ Ravel ∙ Ravel order ∙ Element ∙ Scalar ∙ Vector ∙ Matrix ∙ Simple scalar ∙ Simple array ∙ Nested array ∙ Cell ∙ Major cell ∙ Subarray ∙ Empty array ∙ Prototype |
Data types | Number (Boolean, Complex number) ∙ Character (String) ∙ Box ∙ Namespace ∙ Function array |
Concepts and paradigms | Conformability (Scalar extension, Leading axis agreement) ∙ Scalar function (Pervasion) ∙ Identity element ∙ Complex floor ∙ Array ordering (Total) ∙ Tacit programming (Function composition, Close composition) ∙ Glyph ∙ Leading axis theory ∙ Major cell search ∙ First-class function |
Errors | LIMIT ERROR ∙ RANK ERROR ∙ SYNTAX ERROR ∙ DOMAIN ERROR ∙ LENGTH ERROR ∙ INDEX ERROR ∙ VALUE ERROR ∙ EVOLUTION ERROR |