]box on -style=max -trains=tree -fns=on
┌→─────────────────────────────────────┐ │Was ON -style=max -trains=tree -fns=on│ └──────────────────────────────────────┘
Jeremy Howard
July 5, 2022
This post will explore some introductory operators (aka “higher order functions”) in APL.
]box on -style=max -trains=tree -fns=on
┌→─────────────────────────────────────┐ │Was ON -style=max -trains=tree -fns=on│ └──────────────────────────────────────┘
3 2⍴⍳6
┌→──┐ ↓1 2│ │3 4│ │5 6│ └~──┘
Axis changes how the equal operator consumes the right argument. We specify a dimesion and we broadcast the operator across that dimension. In this case we are comparing the columns of the array to the left argument.
1 4 5 =[1] 3 2⍴⍳6
┌→──┐ ↓1 0│ │0 1│ │1 0│ └~──┘
⎕←mat ← 2 3 ⍴ 10 20 30 40 50 60
┌→───────┐ ↓10 20 30│ │40 50 60│ └~───────┘
Similarly we can modify the plus operator to broadcast along the columns.
mat+[1]1 2 ⍝ add along first axis
┌→───────┐ ↓11 21 31│ │42 52 62│ └~───────┘
,
(Comma),
(Ravel)⎕ ← cube ← 2 2 2 ⍴ ⍳8
┌┌→──┐ ↓↓1 2│ ││3 4│ ││ │ ││5 6│ ││7 8│ └└~──┘
Returns the elemenst as a vector
, cube
┌→──────────────┐ │1 2 3 4 5 6 7 8│ └~──────────────┘
, (1 2)(1 2)
┌→────────────┐ │ ┌→──┐ ┌→──┐ │ │ │1 2│ │1 2│ │ │ └~──┘ └~──┘ │ └∊────────────┘
,
(Ravel) with axis'ABC'
┌→──┐ │ABC│ └───┘
We can use the axis modify insert a new dimension with ravel. We started with a single dimension, and we inserted a new one after it
,[0.5]'ABC'
┌→──┐ ↓ABC│ └───┘
⍴'ABC'
┌→┐ │3│ └~┘
The fraction indicates where the new dimension is inserted
⍴,[0.5]'ABC'
┌→──┐ │1 3│ └~──┘
If we specify a null dimension the dimension is added at the end
⍴,[⍬]'ABC'
┌→──┐ │3 1│ └~──┘
2 2 2⍴⍳8
┌┌→──┐ ↓↓1 2│ ││3 4│ ││ │ ││5 6│ ││7 8│ └└~──┘
⎕←M ← 2 3 4 ⍴ ⍳24
┌┌→──────────┐ ↓↓ 1 2 3 4│ ││ 5 6 7 8│ ││ 9 10 11 12│ ││ │ ││13 14 15 16│ ││17 18 19 20│ ││21 22 23 24│ └└~──────────┘
Specifying more than one dimension will merge the two given dimensions
,[1 2]M
┌→──────────┐ ↓ 1 2 3 4│ │ 5 6 7 8│ │ 9 10 11 12│ │13 14 15 16│ │17 18 19 20│ │21 22 23 24│ └~──────────┘
⍴,[1 2]M
┌→──┐ │6 4│ └~──┘
,[2 3]M
┌→──────────────────────────────────┐ ↓ 1 2 3 4 5 6 7 8 9 10 11 12│ │13 14 15 16 17 18 19 20 21 22 23 24│ └~──────────────────────────────────┘
⍴,[2 3]M
┌→───┐ │2 12│ └~───┘
,
(Catenate/Laminate (Join))Joins arrays together
1 2 3 , 4 5 6
┌→──────────┐ │1 2 3 4 5 6│ └~──────────┘
Will be broadcast along the first dimension.
cube ← 2 2 2 ⍴ ⍳8
cube , 99
┌┌→─────┐ ↓↓1 2 99│ ││3 4 99│ ││ │ ││5 6 99│ ││7 8 99│ └└~─────┘
,
(Ravel) with axisrect←3 2⍴⍳6
rect
┌→──┐ ↓1 2│ │3 4│ │5 6│ └~──┘
⍴rect
┌→──┐ │3 2│ └~──┘
Add the element 10 to the end of each row
rect,10
┌→─────┐ ↓1 2 10│ │3 4 10│ │5 6 10│ └~─────┘
We can modify laminate to add the given element to the columns (axis 1) instead of the rows (axis 2)
rect,[1]10
┌→────┐ ↓ 1 2│ │ 3 4│ │ 5 6│ │10 10│ └~────┘
A fractional axis creates a new axis and laminates that onto the existing rect
rect,[0.5]10
┌┌→────┐ ↓↓ 1 2│ ││ 3 4│ ││ 5 6│ ││ │ ││10 10│ ││10 10│ ││10 10│ └└~────┘
'HEADING',[0.5]'-'
┌→──────┐ ↓HEADING│ │-------│ └───────┘
⍪
(Comma bar)⍪
(Table / Ravel items)Very similar to ravel. Operates on the first axis by default instead of the last axis.
⍪1
┌→┐ ↓1│ └~┘
This can be used to create columns instead of rows
⎕←,5⍴⎕A
⎕←⍪5⍴⎕A
┌→────┐ │ABCDE│ └─────┘
┌→┐ ↓A│ │B│ │C│ │D│ │E│ └─┘
2 3 4⍴⎕A
┌┌→───┐ ↓↓ABCD│ ││EFGH│ ││IJKL│ ││ │ ││MNOP│ ││QRST│ ││UVWX│ └└────┘
Ravels the dimensions down to 2 leaving the size of the first dimension unchanged and merging the others.
⍴⍪2 3 4⍴⎕A
┌→───┐ │2 12│ └~───┘
⍪2 3 4⍴⎕A
┌→───────────┐ ↓ABCDEFGHIJKL│ │MNOPQRSTUVWX│ └────────────┘
⍪
(Catenate first)Operates by catenating the first dimensions
1 2 3 ⍪ 4 5 6
┌→──────────┐ │1 2 3 4 5 6│ └~──────────┘
cube ← 2 2 2 ⍴ ⍳8
cube ⍪ 99
┌┌→────┐ ↓↓ 1 2│ ││ 3 4│ ││ │ ││ 5 6│ ││ 7 8│ ││ │ ││99 99│ ││99 99│ └└~────┘
/
(Slash)/
(Reduce / N-wise Reduce)inserts the function on the right between the elements of the given array
1 2 3 4 5 —> 1+2+3+4+5
⎕ ← a ← ⍳5
+/a
┌→────────┐ │1 2 3 4 5│ └~────────┘
15
Can be used to multiply all elements together
a ← ⍳5
×/a
120
a ← ⍳3
÷/a
1.5
Find the maximum element in an array
a ← 4 6 2
⌈/ a
6
Find the minimum element in the array
a ← 4 6 2
⌊/ a
2
×/⍳5
120
!5
120
Windowed sum with window of 3
:
3+/⍳4 ⍝ (1+2+3) (2+3+4)
┌→──┐ │6 9│ └~──┘
Windowed sum with window of 2
:
2+/⍳4 ⍝ (1+2) (2+3) (3+4)
┌→────┐ │3 5 7│ └~────┘
Moving average
3÷⍨3+/⍳4
┌→──┐ │2 3│ └~──┘
0+/⍳4 ⍝ Identity element for +
┌→────────┐ │0 0 0 0 0│ └~────────┘
0×/⍳4 ⍝ Identity element for ×
┌→────────┐ │1 1 1 1 1│ └~────────┘
¯2,/⍳4⍝ (2,1) (3,2) (4,3)
┌→──────────────────┐ │ ┌→──┐ ┌→──┐ ┌→──┐ │ │ │2 1│ │3 2│ │4 3│ │ │ └~──┘ └~──┘ └~──┘ │ └∊──────────────────┘
Combining reduce with axis allows us to specify the dimension to reduce.
Sum the columns
mat←2 3⍴⍳6
+/[1]mat
┌→────┐ │5 7 9│ └~────┘
Sum the rows
mat←2 3⍴⍳6
+/[2]mat
┌→───┐ │6 15│ └~───┘
mat←2 3⍴⍳6
+/mat
┌→───┐ │6 15│ └~───┘
\
(Slope)\
(Scan)Show all the intermediate steps of reduce
1 (1+2) (1+2+3) (1+2+3+4) (1+2+3+4+5)
a ← ⍳5
+\a
┌→──────────┐ │1 3 6 10 15│ └~──────────┘
a ← ⍳5
×\a
┌→───────────┐ │1 2 6 24 120│ └~───────────┘
⎕ ← a ← ⍳3
÷\a
┌→────┐ │1 2 3│ └~────┘
┌→────────┐ │1 0.5 1.5│ └~────────┘
⌿
(Slash Bar)⌿
(Reduce First)Works similar to reduce. Operates on the first dimension rather than the last.
⎕←mat ← 2 3 ⍴ ⍳6
+/mat
┌→────┐ ↓1 2 3│ │4 5 6│ └~────┘
┌→───┐ │6 15│ └~───┘
⎕←mat ← 2 3 ⍴ ⍳6
+/[1]mat
┌→────┐ ↓1 2 3│ │4 5 6│ └~────┘
┌→────┐ │5 7 9│ └~────┘
+⌿mat
┌→────┐ │5 7 9│ └~────┘
⍀
(Slope Bar)⍀
(Scan first)Similar to scan but operates on the first dimension rather than the last
⎕ ← mat ← 2 3 ⍴ ⍳6
+⍀mat
┌→────┐ ↓1 2 3│ │4 5 6│ └~────┘
┌→────┐ ↓1 2 3│ │5 7 9│ └~────┘
⍤
(Jot Diaresis)⍤
(Rank)trace←{⍺←⊢⋄⎕←'⍺: '⍺ '⍵: '⍵⋄ ⍺ ⍺⍺ ⍵} ⍝ explainer function
⍤ lets you specify the dimensions of the matrix to pass into the next function. In this case we only want plus reduce first to operate across rows.
⎕←cube ← 2 3 4 ⍴ ⍳24
(+⌿⍤1)cube
┌┌→──────────┐ ↓↓ 1 2 3 4│ ││ 5 6 7 8│ ││ 9 10 11 12│ ││ │ ││13 14 15 16│ ││17 18 19 20│ ││21 22 23 24│ └└~──────────┘
┌→───────┐ ↓10 26 42│ │58 74 90│ └~───────┘
(+⌿trace⍤1)cube ⍝ show the input to pluse reduce first
┌→────────────────┐ │ ┌→──┐ ┌→──────┐ │ │ │⍵: │ │1 2 3 4│ │ │ └───┘ └~──────┘ │ └∊────────────────┘ ┌→────────────────┐ │ ┌→──┐ ┌→──────┐ │ │ │⍵: │ │5 6 7 8│ │ │ └───┘ └~──────┘ │ └∊────────────────┘ ┌→───────────────────┐ │ ┌→──┐ ┌→─────────┐ │ │ │⍵: │ │9 10 11 12│ │ │ └───┘ └~─────────┘ │ └∊───────────────────┘ ┌→────────────────────┐ │ ┌→──┐ ┌→──────────┐ │ │ │⍵: │ │13 14 15 16│ │ │ └───┘ └~──────────┘ │ └∊────────────────────┘ ┌→────────────────────┐ │ ┌→──┐ ┌→──────────┐ │ │ │⍵: │ │17 18 19 20│ │ │ └───┘ └~──────────┘ │ └∊────────────────────┘ ┌→────────────────────┐ │ ┌→──┐ ┌→──────────┐ │ │ │⍵: │ │21 22 23 24│ │ │ └───┘ └~──────────┘ │ └∊────────────────────┘ ┌→───────┐ ↓10 26 42│ │58 74 90│ └~───────┘
Sum the columns
⎕←mat ← 3 4 ⍴ ⍳12
+⌿mat
┌→─────────┐ ↓1 2 3 4│ │5 6 7 8│ │9 10 11 12│ └~─────────┘
┌→──────────┐ │15 18 21 24│ └~──────────┘
For each of the 3 4 (the first 2 dimensions) matrices in the larger cube apply plus reduce first
⎕←cube
(+⌿⍤2)cube
┌┌→──────────┐ ↓↓ 1 2 3 4│ ││ 5 6 7 8│ ││ 9 10 11 12│ ││ │ ││13 14 15 16│ ││17 18 19 20│ ││21 22 23 24│ └└~──────────┘
┌→──────────┐ ↓15 18 21 24│ │51 54 57 60│ └~──────────┘
Given ⍺ and ⍵ arguments we can specify dimensions for each. In the following we take the ⍺ argument by element and the ⍵ argument by row
⎕←mat
1 2 3 (+trace⍤0 1) mat
┌→─────────┐ ↓1 2 3 4│ │5 6 7 8│ │9 10 11 12│ └~─────────┘
┌→────────────────────────┐ │ ┌→──┐ ┌→──┐ ┌→──────┐ │ │ │⍺: │ 1 │⍵: │ │1 2 3 4│ │ │ └───┘ └───┘ └~──────┘ │ └∊────────────────────────┘ ┌→────────────────────────┐ │ ┌→──┐ ┌→──┐ ┌→──────┐ │ │ │⍺: │ 2 │⍵: │ │5 6 7 8│ │ │ └───┘ └───┘ └~──────┘ │ └∊────────────────────────┘ ┌→───────────────────────────┐ │ ┌→──┐ ┌→──┐ ┌→─────────┐ │ │ │⍺: │ 3 │⍵: │ │9 10 11 12│ │ │ └───┘ └───┘ └~─────────┘ │ └∊───────────────────────────┘ ┌→──────────┐ ↓ 2 3 4 5│ │ 7 8 9 10│ │12 13 14 15│ └~──────────┘
⍤
(Atop)⍤ used dyadically is a function application rule
f⍤g X → f(gX) → fgX X f⍤g Y → f X g Y
f ← *⍤÷
⎕←*(÷3)
⎕←f 3
1.395612425
1.395612425
⎕←*2÷3
⎕←2 f 3
1.947734041
1.947734041
∘
(Jot)∘
(Bind)Can be used for partial function application. Binds the right argument 2 to the power function returning a new function that takes only a single argument
sqr ← *∘2
sqr 3
9
Can bind the left argument as well
pow2 ← 2∘*
pow2 3
8
∘
(Beside)Another function composition rule
f∘g X → f(gX) → fgX X f∘g Y → X f g Y
f ← *∘÷
*(÷3)
1.395612425
f 3
1.395612425
2 f 3
1.25992105
2 * (÷3)
1.25992105
2*÷3
1.25992105
⍥
(Circle diaresis)⍥
(Over)Another function composition rule.
f⍥g Y → f(gX) → fgX X f⍥g Y → (g X)f(g Y)
f ← *⍥÷
*(÷3)
1.395612425
f 3
1.395612425
2 f 3
0.793700526
(÷2)*÷3
0.793700526
10 (÷⍥!) 6 ⍝ P(10,4)
5040
(!10)÷!(10-4) ⍝ P(10,4)
5040
⍣
(Star Diaeresis)⍣
(Power operator)S ← +∘1
S 0
1
⍣ Calls a function the given number of times.
S(S(S 0))
(S⍣3) 0
3
add ← {(S⍣⍺) ⍵}
2 add 3
5
mult ← {⍺ (add⍣⍵) 0}
3 mult 4
12
P ← S⍣¯1
P 3
2
(S⍣¯3) 5
2
sqr ← *∘2
(sqr⍣¯1)9
3
pow ← {⍺ (mult⍣⍵) 1}
2 pow 3
8
1 +∘÷⍣= 1
1.618033989
f ← +∘÷
1 f 1
2
1 f 2
1.5
1 f 1.5
1.666666667
1 (f⍣15) 1
1.618034448
1 (f⍣=) 1
1.618033989
.
(Dot).
(Inner Product)The ⍵⍵ operator specifies how elements are combined. The ⍺⍺ argument specifies how the results of the ⍵⍵ operation are combined.
(1×4) + (2×5) + (3×6)
1 2 3 +.× 4 5 6 ⍝ Dot product
32
(3=3)∧(3=3)∧(3=3)∧(3=3)
3 ∧.= 3 3 3 3 ⍝ All-equal
1
(1×1)+(2×3) (1×2)+(2×4)
(3×1)+(4×3) (3×2)+(4×4)
⎕←mat←2 2⍴⍳4
mat +.× mat ⍝ matrix product
┌→──┐ ↓1 2│ │3 4│ └~──┘
┌→────┐ ↓ 7 10│ │15 22│ └~────┘
In this case we are going to duplicate the ⍵ argument. Once for each element of the ⍺ argument. The first one is multiplied by the first element of the ⍺ argument. The second by the second element, etc.
1× 4 5 6 7
2× 4 5 6 7
3× 4 5 6 7
1 2 3 ∘.× 4 5 6 7 ⍝ Special case: outer prodct
┌→──────────┐ ↓ 4 5 6 7│ │ 8 10 12 14│ │12 15 18 21│ └~──────────┘
⌹
(Domino;Quad Divide)⌹
(Matrix Inverse Of)mat←2 2⍴⍳4
⎕←inv←⌹ mat
┌→────────┐ ↓¯2 1 │ │ 1.5 ¯0.5│ └~────────┘
inv +.× mat ⍝ Identity
┌→──┐ ↓1 0│ │0 1│ └~──┘
⌹
(Matrix Division By)⎕←div←5 6 ⌹ mat
┌→─────┐ │¯4 4.5│ └~─────┘
mat +.× div
┌→──┐ │5 6│ └~──┘
f ← *∘2
d ← 0.01
x ← 3
((f (x+d)) - f x) ÷ d
6.01
d ← 0.0001
((f (x+d)) - f x) ÷ d
6.0001
grad ← {((⍺⍺ ⍺+⍵) - ⍺⍺ ⍺) ÷ ⍵}
3 f grad 0.01
6.01
⍨
(Tilde Diaeresis)⍨
(Commute)Modifies the given function so its arguments are swapped.
3-2
1
2-3
¯1
3-⍨2
¯1
Normally to use a mask to select elements the mask is the ⍺ argument to /. If we wanted to right this out we would need to calculate the mask first.
(≠v)/v
v←22 10 22 22 21 10 5 10
v/⍨≠v
┌→─────────┐ │22 10 21 5│ └~─────────┘
grad ← {⍵ ÷⍨ (⍺⍺ ⍺+⍵) - ⍺⍺ ⍺}
3 f grad 0.01
6.01
Can also be used to reflect the ⍵ argument to become the ⍺ argument as well.
3 × 3
pow ← ×⍨
pow 3
9
⍨
(Constant)zero ← 0⍨
2 zero 5
0
¨
(Diaresis)¨
(Each)⎕ ← a ← (1 2 3 4)(5 6 7)
┌→──────────────────┐ │ ┌→──────┐ ┌→────┐ │ │ │1 2 3 4│ │5 6 7│ │ │ └~──────┘ └~────┘ │ └∊──────────────────┘
Apply +/ to each of the elements of a. Each element is itself an array. So we sum those up.
+/¨a
┌→────┐ │10 18│ └~────┘
⎕ ← b ← (1 2 3)(4 5 6)
┌→────────────────┐ │ ┌→────┐ ┌→────┐ │ │ │1 2 3│ │4 5 6│ │ │ └~────┘ └~────┘ │ └∊────────────────┘
Distribute the plus and an element to each of the elements of b.
2 + 1 2 3
3 + 4 5 6
2 3 +¨ b
┌→────────────────┐ │ ┌→────┐ ┌→────┐ │ │ │3 4 5│ │7 8 9│ │ │ └~────┘ └~────┘ │ └∊────────────────┘