Built-in Operators (11 of 14)

Operators form a powerful extension to the repertoire of the language. They can be used to specify the way in which a function or functions are to be applied to data - they allow a function to be applied repeatedly and cumulatively over all the elements of a vector, matrix or multidimensional array.

They can be thought of as instructions to built-in and user-defined functions on how to carry out their operations. You can even define your own operators!

The operators available are:

Operator

Name

/

Slash

\

Backslash

.

Inner Product

∘.

Outer Product

¨

Each

[ ]

Axis

Reduce and scan

When used with functions as their operand, slash and backslash are known as reduce and scan. Reduce and scan apply a single function to all the elements of an argument. For example, to add up a vector of arguments, you can either type:

      22 + 93 + 4.6 + 10 + 3.3
132.9

or alternatively:

      +/22 93 4.6 10 3.3
132.9

The / operator in the last example had the effect of inserting a plus sign between all the elements in the vector to its right.

The \ operator is similar except that it works cumulatively on the data, and gives all the intermediate results. So:

      +\22 93 4.6 10 3.3
 22 115 119.6 129.6 132.9

from the results of:

      22 (22+93) (115+4.6) (119.6+10) (129.6+3.3)

Compress and Expand

When used with one or more numbers as their operand, slash and backslash carry out operations known as compression and expansion.

Compress can be used to select all or part of an object, according to the value of the numbers forming its operand. For example, to select some characters from a vector:

      1 0 1 1 0 1 / 'ABCDEF'
ACDF

Conversely, expand will insert fill data into objects:

      TAB ← 2 3⍴⍳6
      TAB
1 2 3
4 5 6
      1 0 1 0 1 \[2]TAB
1 0 2 0 3
4 0 5 0 6

Columns are inserted in positions indicated by the 0s. (Note also the use of the axis operator - see below).

Outer and inner products

The product operators allow APL functions to be applied between all the elements in one argument and all the elements in another.

This is an important extension because previously functions have only applied to corresponding elements as in this example:

      1 2 3 + 4 5 6
5 7 9

The outer product gives the result of applying the function to all combinations of the elements in the two arguments. For example, to find the outer product of the two arguments used in the last example:

      1 2 3 ∘.+ 4 5 6
5 6 7
6 7 8
7 8 9

The first row is the result of adding the first element on the left to every element on the right, the second row is the result of adding the second element in the left to every element on the right and so on till all combinations are exhausted.

This example works out a matrix of powers:

      1 2 3 4 ∘.*1 2 3 4
1  1  1   1
2  4  8  16
3  9 27  81
4 16 64 256

as can be seen more clearly if we lay it out like this:

1

2

3

4

1

1

2

3

4

2

2

4

6

8

3

3

9

27

81

4

4

16

64

256

(Since the outer product involves operations between all elements, rather than just between corresponding elements, it's not necessary for the arguments to conform in shape or size.)

The inner product allows two functions to be applied to the arguments. The operations take place between the last dimension of the left argument and the first dimension of the right argument, hence 'inner' product since the two inner dimensions are used.

In the case of matrices, first each row of the left argument is applied to each column of the right argument using the rightmost function of the inner product, then the leftmost function is applied to the result, in a reduction (/) operation.

Given that you can use a combination of any two suitable functions, there are over 400 possible inner products! Obviously these can perform a variety of useful operations. Some of the more common uses are:

Each

As its name implies, the each operator will apply a function to each element of an array.

So, to find the lengths of an array of vectors

      ⍴¨(1 2 3)(1 2)(1 2 3 4 5)
3 2 5

As with other operators, each can be used for user-defined functions. Here we use an average function on an array of vectors.

      AVERAGE 1 2 3
2
      AVERAGE ¨ (1 2 3) (4 5 6) (10 100 1000)
2 5 370

Axis

When a function operates on data of more than one dimension, there is a choice as to which dimension it should work on.

The default which APL takes if you don't specify otherwise is to operate on the last dimension. The order of dimensions is the order in which they are defined in a statement, so the last dimension is that of the columns. (This was discussed more fully in the Data chapter under the heading 'Dimension Ordering'.)

If you want to specify a different dimension, you can do so by putting the number of the required dimension in square brackets after the function or operator.

Here's a data structure of two dimensions, called TAB, which we'll use in some examples;

      TAB ← 2 3 ⍴ ⍳6
      TAB
1 2 3
4 5 6
      +/TAB
6 15

Since no dimension was specified, the summing operation requested by +/ was done on the last dimension, the columns. The elements in column 1 were added to the corresponding elements in columns 2 and 3. This gave the sum of the elements in row 1 and the sum of those in row 2.

This statement specifies that the operation should be done, instead, on the first dimension, the rows;

      +/[1]TAB
5 7 9

The elements in row 1 were added to the corresponding elements in row 2.

As you would expect, the following statement (which specifies the second dimension, the columns) is equivalent to the first example where no dimension was specified:

      +/[2] TAB
6 15

Here's an example using the function which (when used with one argument as here) reverses the order of the elements in the data specified by the argument:

      ⌽TAB
3 2 1
6 5 4

Again it has been applied to the last dimension (the columns) by default. What was column 3 is now column 1 and visa-versa.

Here the first dimension is specified:

      ⌽[1]TAB
4 5 6
1 2 3

Row 1 has changed places with row 2.

Below is a three-dimensional structure such as would be set up by this statement:

      DATA ← 2 2 3⍴⍳12
      DATA
 1  2  3
 4  5  6
 
 7  8  9
10 11 12

The first dimension consists of two planes (the two blocks of numbers). The second dimension is the rows, two in each plane. The third is the columns, three in each row.

The following statement specifies a multiplication operation on the second dimension. In other words, row 1 is to be multiplied by row 2 in both planes

      ×/[2]DATA
 4 10  18
70 88 108

The first line is the result of multiplying row 1 by row 2 in the first plane. The second line is the result of the equivalent operation for the second plane.

The first dimension consists of the two planes. A multiplication on the first dimension will multiply each element in plane 1 by the corresponding element in plane 2:

      ×/[1]DATA
 7 16 27
40 55 72

Axis Specifications

The list of built-in functions and operators that accept an axis specification is:

Mixed Functions: ,

Operators: / \


CategoryAboutApl

LearnApl/AplOperators (last edited 2017-02-16 19:44:07 by KaiJaeger)