3 min read

APL a Day #4: Arrays have elements

An array that only describes a box which may contain elements, but that does not contain any elements, does not mean much. While shapes help to clarify the APL language, when doing any work, they really only describe how to arrange the elements of an array. The monadic ravel function (written as the comma ,) describes a vector of all the elements of an array taken from the array in row major order. Thus, the following property holds:

A ←→ (⍴A)⍴,A ⍝ A is the reshape of the elements of A with the
             ⍝ shape of A.

That is, the shape of an array, together with its elements, fully describes an array.

Given the ravel of an array, how does the shape of an array describe the arrangement of those elements? The official computer science term for this is row major order. To understand how row major order works, consider a matrix, that is, an array of two dimensions. Supposing that the matrix has no non-zero dimensions, the shape of that matrix will be some positive integers N M. Since APL uses row major order, the N is said to be the number of rows in the matrix, while M is said to be the number of columns. Notice that the "most major" dimension appears first in the vector N M; the dimensions of an array are arranged in the array's shape from most to least major. That is, the first element in the shape is the most major dimension, the second element the second most major, and so forth.

The monadic function "Index" () helps to illustrate these concepts. The notation ⍳N where N is a natural number, describes a vector of the first N natural numbers.

    ⍳7
0 1 2 3 4 5 6

The index function helps provide a set of sample values from which to describe arrays of various shapes. The following examples illustrate how the shape of an array arranges elements of an array:

    ⍬⍴⍳9   ⍝ An empty shape gives a scalar
0
    3⍴⍳9   ⍝ A vector fills from the elements as needed
0 1 2
    8⍴⍳4   ⍝ An array fills repeatedly from its elements
0 1 2 3 0 1 2 3
    2 3⍴⍳9 ⍝ Matrices fill rows at a time
0 1 2
3 4 5
    3 3⍴⍳4 ⍝ Matrices also fill repeatedly
0 1 2
3 0 1
2 3 0

Notice that matrices fill from the elements repeatedly starting a row at a time. This explains the term row major. When arranging elements according to the shape, the first index of the most major dimension fills before the second most major index. In the examples above, the row was the most major dimension, so each row filled before the next row.

This process generalizes to any number of dimensions. To give an intuition to this, consider a 3-dimensional array with shape 2 3 3 fill from the elements ⍳4.

    2 3 3⍴⍳4
0 1 2
3 0 1
2 3 0

1 2 3
0 1 2
3 0 1

In this case, APL needs to represent a 3-dimensional array on a two-dimensional grid of characters. To do this, it arranges each sub-matrix as normal, but then separates each sub-matrix with a blank line. Thus, for a shape of 2 3 3, APL displays such an array as two matrices separated by a blank line. Notice what happens if the shape changes to 3 2 3.

    3 2 3⍴⍳4
0 1 2
3 0 1

2 3 0
1 2 3

0 1 2
3 0 1

See how the elements continue to be arranged in the same way, but the size of the first dimension (the most major one) increased, while the second dimension size decreased. Now, instead of having two 3 3 matrices, APL displays three 2 3 matrices.

Play with using different elements in the array and using different shapes, with both the same and different elements. Gaining a good intuition for the concept of elements and shape together and how they work can take a little time. Don't worry.

As a final note, the astute reader will realize that the number of elements given as the right argument to the reshape () function do not necessarily need to match the number of elements that the reshape function describes, as given in the left argument corresponding to the shape of the described array. Indeed, reshaping an array will continue to pull elements from the ravel of that array, as many as needed, repeatedly, without complaint. As a parting gift, spend some time pondering these properties, which speak more about this unique feature and others.

×/S ⍝ The product of the elements of shape S
    ⍝ also known as the number of elements in an array 
    ⍝ of shape S

S⍴A ←→ S⍴,A ⍝ Reshaping any array is the same as reshaping its
            ⍝ ravel

(×/S)⍴A ←→ ,S⍴A ⍝ The ravel of a reshaped array is the same as 
                ⍝ the reshape of that array with the product 
                ⍝ of all the dimensions in the shape

S⍴A ←→ S⍴(×/S)⍴A ⍝ Reshaping an array A is the same as reshaping 
                 ⍝ the ravel of A replicated to match the product 
                 ⍝ of the dimensions of the shape