3 min read

APL a Day #3: Arrays have Shape

Arrays arrange data into a certain rectangular shape. In APL, the shape of an array is a vector --- yes, in APL, shapes are also arrays --- that describes the number and size of layout in terms of dimensions. All arrays have a shape; if A is an array then ⍴A is its shape. The function is a primitive, that is, a built-in, ambivalent function. When used monadically, as in ⍴A, this describes the shape of A. The expression ⍴A describes a vector of natural numbers each corresponding to the size of one of the dimensions of A. Consider these examples:

⍬ ←→ ⍴S ←→ ⍴7 ⍝ Shape of a scalar is the empty vector
               ⍝ Scalars have no dimensions
 ,N ←→ ⍴V      ⍝ Vectors have one dimension
               ⍝ N is the number of elements in the vector
               ⍝ Note: ,N is a vector whose only element is N
 ,3 ←→ ⍴0 1 2  ⍝ An example shape of a vector (1 2 3) 

Consider the following:

0 1 2 3 4 5 6 7 8 

The above matrix contains 9 elements arranged into 3 rows and 3 columns. It therefore has two dimensions, first the rows, second the columns. To those with computer science background, the shape of an array arranges its elements (also called its ravel) in row-major order. The above array therefore has the shape 3 3, since it has two dimensions, and the size of each of these dimensions is 3.

APL only permits directly writing scalars and vectors. One cannot write the above matrix literally into an APL session. Instead, APL allows the use of any array to describe a new array with a different shape. The dyadic use of describes a new array whose shape is the left argument to and whose elements come from its right argument. Consider one way to write the above matrix:

3 3⍴0 1 2 3 4 5 6 7 8 

Note that the following properties hold:

S ←→ ⍴S⍴A   ⍝ The shape of an array reshaped with S is S A ←→ (⍴A)⍴A ⍝ An array reshaped by its own shape is itself 

The expression ⍴⍴A describes the rank of A. The rank of an array is the number of its dimensions. In APL, the rank of an array is a vector of one element containing the count of that array's dimensions. The following interesting little property falls out from this:

,1 ←→ ⍴⍴⍴A ⍝ The shape of a rank is 1
           ⍝ Or, the rank of a shape is 1 

APL's treatment of rank speaks to its philosophy. Firstly, notice how the shape and reshape functions use the same symbol . APL intentionally groups common operations together when possible. Most symbols in APL map to two functions, a monadic and dyadic version, each of which relates to the other in some way. APL primitives also apply to many different areas; that is, primitives have more than one application. Shape, for instance, serves not only as shape, but also provides the Rank function. APL does not provide a separate built-in function for rank, since shape subsumes rank and does so more generally. Finally, notice that arrays themselves can encode their own properties such as shape. The useful generality of arrays can astound even practiced APLers. APL can describe itself, and future sessions describe properties of APL using APL, as done here. In part, APL's power comes from its ability to manipulate directly in code what other languages leave static, not unlike the power Lisp languages afford through their code-data duality. Remember that APL began as a notation for mathematical discourse, and as such, few languages match its concision and descriptive power.

The shapes of arrays give a great deal of information, especially when attempting to understand the language of APL itself, or when reasoning about APL code. Introducing Shape early enables future topics to leverage shape as a method for describing and detailing concepts clearly and concisely, which otherwise might seem arbitrary. Keep shape in mind when reading APL code, as the flow of shapes through a program speaks volumes.

Arrays are more than their shapes; they are shapes and elements. Arguably, the elements of an array aid learning less than the shape of an array, but to understand arrays is to understand shapes and their relation to elements. Next time should complete the treatment of arrays, and thus shall conclude the two fundamental concepts of APL: functions and arrays.