⍴⌽⊖⍉⍎⍕
Contents
⍴⌽⊖⍉⍎⍕
#
Reshape ⍴
#
We’ve met ⍴ (Greek Rho) in passing before. Let’s cover it in more depth. ⍴
is maybe the most fundamental function in an array language, as it allows the formation of multi-dimensional (high-rank) arrays. Note that ⍴
is not actually the Greek Rho in Unicode. Dyalog APL only uses the special Unicode APL Rho.
The Greek letter Rho is has the sound of the letter R, and stands for reshape. The right argument of ⍴
is used in ravel order to fill an array with the dimensions given by the left argument. The left argument must therefore be a vector (list) of dimension lengths (although for ease of use, we do allow a scalar instead of a one-element vector). Another way to look at it is that the left argument of ⍴
is the index of the last element in the resulting array (if you stick to the default ⎕IO
of 1). If you omit the shape (left argument) then the current shape is returned.
3⍴'a'
3⍴'ab'
3⍴'abcd'
2 3⍴'abc'
aaa
aba
abc
abc abc
That’s two rows and three columns. The order of the left argument is the number of major cells first and of “leaf” cells last.
3 4 5∘.+10 20 30 40
⍴3 4 5∘.+10 20 30 40
13 23 33 43 14 24 34 44 15 25 35 45
3 4
A scalar doesn’t have any dimensions, so the corresponding left argument is ⍬
(or 0⍴0
):
⍬⍴3 4 5∘.+10 20 30 40
13
If one or more dimensions are 0, then the array doesn’t have any elements, but it is still there. If it has rank 2 or higher, then it has an empty default display. If an array has no elements, then ⍴
will uses its prototype to fill any array it needs to form:
2 3⍴⍬
0 0 0 0 0 0
Recall that ⍬
is just 0⍴0
so it being simple and numeric, its prototype is 0.
Reverse ⌽
#
Monadic ⌽
is reverse. It reverses the leaf rank-1 sub-arrays of an array. For a matrix, it means reversing each row:
2 4⍴⍳8
⌽2 4⍴⍳8
1 2 3 4 5 6 7 8
4 3 2 1 8 7 6 5
For a vector, it simply means reversing the vector:
⎕A
⌽⎕A
ABCDEFGHIJKLMNOPQRSTUVWXYZ
ZYXWVUTSRQPONMLKJIHGFEDCBA
Of course, it doesn’t affect scalars.
Reverse first ⊖
#
⌽
has a sibling, just like /
and \
have ⌿
and ⍀
, namely reverse first, ⊖
, which I usually call “Flip”. ⊖
reverses the order of major cells, which for a matrix means reversing the order of the rows, i.e. flipping it upside down:
⊖2 4⍴⍳8
5 6 7 8 1 2 3 4
For vectors, it is the same as ⌽
and again it does nothing to scalars. For a 3D array, it reverses the order of layers:
4 2 3⍴⎕A
⊖4 2 3⍴⎕A
ABC DEF GHI JKL MNO PQR STU VWX
STU VWX MNO PQR GHI JKL ABC DEF
Dyadic ⌽
and ⊖
do rotations instead of reversals:
3⊖⎕A
1⊖4 2 3⍴⎕A
DEFGHIJKLMNOPQRSTUVWXYZABC
GHI JKL MNO PQR STU VWX ABC DEF
Negative rotation amounts just rotate to the other way:
¯3⊖⎕A
XYZABCDEFGHIJKLMNOPQRSTUVW
Here is a cool feature of ⌽
and ⊖
: If you give them a vector of rotation amounts, they get distributed on the relevant cells:
3 4⍴⎕A
1 0 2⌽3 4⍴⎕A
1 0 ¯1 0⊖3 4⍴⎕A
ABCD EFGH IJKL
BCDA EFGH KLIJ
EBKD IFCH AJGL
Transpose ⍉
#
⌽
and ⊖
also have a cousin named ⍉
(Transpose). The monadic function does not reverse the major cells or the rank 1 cells, but rather reverses the order of the indices. For matrices this is normal transposing:
3 4⍴⎕A
⍉3 4⍴⎕A
ABCD EFGH IJKL
AEI BFJ CGK DHL
For arrays of rank higher than 2 it helps to think of the shape as being reversed:
⍉2 3 4⍴⎕A
AM EQ IU BN FR JV CO GS KW DP HT LX
If you look carefully, you can see that the runs like ABCD which originally spanned rows are now spanning layers. Look at the top left corner of each new layer. So, too, are the layers now spanning rows. Look how the top left of the layers, A and M are now next to each other in a row. Whilst the column AEI is still a column, because reversing the shape 2 3 4 (layers, rows, columns) gives 4 3 2 (columns, rows, layers) so the runs spanning rows are in the same position, still spanning rows.
Now you know how to reverse the order of axes, but what if you want an entirely new order? That’s what dyadic ⍉
does. The left argument is the indices of the axes in the desired order. Therefore, if we reverse the indices of the rank, it is the same as monadic transpose:
3 2 1⍉2 3 4⍴⎕A
AM EQ IU BN FR JV CO GS KW DP HT LX
Now we can keep the layers and only reverse (i.e. transpose) columns/rows:
1 3 2⍉2 3 4⍴⎕A
AEI BFJ CGK DHL MQU NRV OSW PTX
Here is a very cool thing: You can duplicate indices in the left argument. If so, APL will merge the indicated axes, taking only the elements that have equal indices along those two axes. This is the diagonal or diagonal plane, or diagonal 3D array (!), etc.
3 4⍴⎕A
1 1⍉3 4⍴⎕A
1 1 1⍉2 3 4⍴⎕A
1 1 2⍉2 3 4⍴⎕A
ABCD EFGH IJKL
AFK
AR
ABCD QRST
Here the layers and rows got merged, i.e. 1st row of 1st layer and 2nd row of 2nd layer, while the columns stayed as is.
1 2 1⍉2 3 4⍴⎕A
AEI NRV
Here we merged layers and columns, i.e. 1st column of 1st layer and second column of 2nd layer. Dyadic ⍉
is pretty advanced and quite rarely used, but when you need it (and can figure out the correct left argument — experiment!) it is really handy.
Here’s an example. Given a multiplication table, what were the numbers that generated it?
3 3⍴9 6 12 6 4 8 12 8 16 ⍝ A multiplication table
9 6 12 6 4 8 12 8 16
In this case, the answer is 3 2 4
:
∘.×⍨3 2 4
9 6 12 6 4 8 12 8 16
We can ‘reverse engineer’ this by finding the square root of the diagonal elements:
1 1⍉3 3⍴9 6 12 6 4 8 12 8 16 ⍝ main diagonal
0.5*⍨1 1⍉3 3⍴9 6 12 6 4 8 12 8 16
9 4 16
3 2 4
Execute ⍎
#
Execute, ⍎
, evaluates a string representing a line of APL. This can be any valid APL expression, including functions and multiple statements:
⍎'2+3'
2(⍎'+')3
⍎'a←2 ⋄ a←a+3 ⋄ a'
5
5
5
The result of ⍎
is the result of the last statement, if that has a result. If it doesn’t (e.g. it is an empty statement or has a leading {}
), then ⍎
doesn’t have a result either. The result of ⍎
can be a monadic operator:
≢(⍎'¨')'abc' 'defg'
3 4
⍎
has all the features of a line of APL. You can run your entire program from ⍎
. Indeed, when a workspace is loaded, APL automatically does ⍎⎕LX
to bootstrap your application. This is what causes the greeting message when you load a workspace like dfns.
Dyadic ⍎
is exactly like the monadic, but executes the expression in the namespace named in the left argument.
0 0⍴a←'base'
ns←⎕NS⍬
ns.a←'sub'
⍎'a'
'ns'⍎'a'
base
sub
Here we first set a
to 'base'
in #
(the root namespace), then we created the empty namespace ns
, populated it there, then evaluated a
here (in #
) and then in ns
. In other words, monadic ⍎
is the same as dyadic ⍎
but with the default left argument of ⎕THIS
(this current namespace).
Nowadays, we usually “dot into” namespaces to evaluate there:
0 0⍴a←'base'
ns←⎕NS⍬
ns.a←'sub'
⍎'a'
ns.⍎'a'
base
sub
Same as before, but here we used the “value” of ⍎
inside ns
instead of ⍎
’s value here.
Format ⍕
#
Format, ⍕
, is really quite simple. It returns a simple character vector or matrix which displays exactly as if its argument had been displayed:
]display 1 2 3 4 ⍝ numeric vector
≢1 2 3 4
]display ⍕1 2 3 4 ⍝ convert to character vector
≢⍕1 2 3 4
┌→──────┐ │1 2 3 4│ └~──────┘
4
┌→──────┐ │1 2 3 4│ └───────┘
7
If you give ⍕
a left argument, it will display numeric values with that many decimals, rounding 5 up:
4⍕2÷3 ⍝ character vector of 2÷3 rounded to 4 dp
4⍕1 2 3÷3
0.6667
0.3333 0.6667 1.0000
If you give it two values as left argument, it will use the first as “field width” and the second as the number of decimal places:
20 4⍕1 2 3÷3
0.3333 0.6667 1.0000
You can also use twice as many elements on the left as there are leaf cells on the right, and it will pair each two on the left to each one on the right:
10 4 20 0 15 1⍕1 2 3÷3
0.3333 1 1.0