Operators and axes

Combine functions and work along axes

An operator takes one or two values, called operands, and produces a derived function. For example, / turns its operand + into the summing function +/. We’ll use operators to choose axes, combine functions and repeat calculations.

Axes and agreement

mat←3 2⍴⍳6
mat
0 1
2 3
4 5

Agreement is how the axes of two arguments line up. BPL uses leading agreement, matching axis 0 with axis 0, axis 1 with axis 1, and so on. Here the three values on the left line up with the three rows of the matrix. Each value is compared with every item in its row.

0 3 4=mat
$t $f
$f $t
$t $f
mat←[10 20 30⋄40 50 60]
mat
10 20 30
40 50 60

Plus follows the same agreement rule. Add 1 to the first row and 2 to the second.

mat+1 2
11 21 31
42 52 62

To work along chosen axes, use the Axis operator ⍠. Its left operand is a function and its right operand is an axis number or list of axes. +⍠1 applies Plus to the rows, along axis 1. Each row is paired with the whole right-hand vector.

mat+⍠1[1 2 3]
11 22 33
41 52 63

An inverse can work along the same chosen axis. This subtracts the fixed vector from each row, undoing the addition above.

1 2 3+⁻¹⍠1[11 22 33⋄41 52 63]
10 20 30
40 50 60

Comma functions

The comma functions join arrays and change how their axes are arranged.

, (Comma)

monadic , (Ravel)

cube←2 2 2⍴⍳8
cube
0 1
2 3

4 5
6 7

Ravel returns the items as a vector.

,cube
0 1 2 3 4 5 6 7

Ravel changes the outer shape. Nested items stay nested.

,[[1 2] [1 2]]
(1 2⋄1 2)

Ravel loses the original shape. Its inverse accepts a vector and leaves it unchanged.

,⁻¹1 2 3
1 2 3

Ravel along chosen axes

text←"ABC"
text
ABC

An empty axis list appends a new axis of length 1. The string becomes a column.

,⍠⍬ text
A
B
C
⍴text
[3]ₓ

Its shape changes from 3 to 3 1.

⍴,⍠⍬ text
[3 1]ₓ
m←2 3 4⍴⍳24
m
 0  1  2  3
 4  5  6  7
 8  9 10 11

12 13 14 15
16 17 18 19
20 21 22 23

Consecutive axes can be merged. Merging axes 0 and 1 turns the two groups of three rows into six rows.

,⍠0 1 m
 0  1  2  3
 4  5  6  7
 8  9 10 11
12 13 14 15
16 17 18 19
20 21 22 23
⍴,⍠0 1 m
[6 4]ₓ
,⍠1 2 m
 0  1  2  3  4  5  6  7  8  9 10 11
12 13 14 15 16 17 18 19 20 21 22 23
⍴,⍠1 2 m
[2 12]ₓ

dyadic , (Catenate)

Catenate joins arrays.

1 2 3,4 5 6
1 2 3 4 5 6

The join is along the last axis. A single value extends to fill the other axes.

cube,99
0 1 99
2 3 99

4 5 99
6 7 99

With a fixed left argument, Catenate’s inverse removes those items from the beginning. The result must begin with the fixed items.

1 2,⁻¹1 2 3 4
3 4

Catenate along a chosen axis

rect←3 2⍴⍳6
rect
0 1
2 3
4 5
⍴rect
[3 2]ₓ

Add the item 10 to the end of each row.

rect,10
0 1 10
2 3 10
4 5 10

Choose axis 0 to join along the columns instead. This adds a row. Parentheses keep the argument 10 separate from the axis number 0.

rect,⍠0(10)
 0  1
 2  3
 4  5
10 10

To stack arrays along a new axis, put them in rows of a bracket literal.

heading←"HEADING"
[heading⋄7⍴'-']
HEADING
-------

⍪ (Comma bar)

monadic ⍪ (Table)

Table turns a number into a 1×1 matrix and a vector into a column. For higher-rank arrays it keeps the first axis and merges the remaining axes.

⍪1
1

We can make a column from a string.

⍪"ABCDE"
A
B
C
D
E
2 3 4⍴"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
ABCD
EFGH
IJKL

MNOP
QRST
UVWX

The first axis stays length 2. The remaining lengths, 3 and 4, multiply to give 12 columns.

⍴⍪2 3 4⍴"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
[2 12]ₓ
⍪2 3 4⍴"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
ABCDEFGHIJKL
MNOPQRSTUVWX

Table’s inverse turns a one-column matrix back into a vector. Other matrices stay unchanged.

⍪⁻¹⍪1 2 3
1 2 3

dyadic ⍪ (Catenate first)

With two arguments, ⍪ joins along the first axis.

1 2 3⍪4 5 6
1 2 3 4 5 6
cube⍪99
 0  1
 2  3

 4  5
 6  7

99 99
99 99

With a fixed left argument, Catenate first’s inverse removes those leading rows.

1 2⍪⁻¹[1 2⋄3 4]
3 4

Operator glyphs

⍨ Self / Commute

Swapping arguments

Commute swaps a function’s arguments. 3-⍨2 means 2-3.

3-2
1
2-3
¯1
3-⍨2
¯1

Commute’s inverse undoes the swapped call. Keeping 3 fixed on the left, the inverse finds the 2 that gave the result ¯1.

3-⍨⁻¹¯1
2

Replicate takes its mask on the left. With Commute, we can write the data first and then calculate its mask. The mask ≠v marks the first occurrence of each value.

v←22 10 22 22 21 10 5 10
v#⍨≠v
22 10 21 5

With one argument, Self passes that argument to both sides of the function. ×⍨3 means 3×3.

square←×⍨
square 3
9

Self has known inverses for addition and multiplication. +⍨⁻¹ halves its argument; ×⍨⁻¹ takes its square root. Taking the minimum or maximum of a number with itself leaves it unchanged, and their Self inverses do too.

+⍨⁻¹10
×⍨⁻¹9
⌈⍨⁻¹5
5
3
5

A constant function

With a number or array as its operand, ⍨ makes a function that always returns that value.

zero←0⍨
2 zero 5
0

A constant function’s inverse accepts only that constant and returns it.

zero⁻¹0
0

/ Reduce

Combining the items

Reduce inserts its function operand between the items along the last axis. With Plus, the list 1 2 3 4 5 becomes 1+2+3+4+5.

a←1 2 3 4 5
+/a
15

Changing the operand to Times multiplies all the items together.

×/a
120
÷/1 2 3
1.5

Find the largest item.

⌈/4 6 2
6

Find the smallest item.

⌊/4 6 2
2
×/1 2 3 4 5
120
!5
120

A seed on the right

A seed is a starting value for a reduction. Supply it as the left argument; it goes at the right end of the inserted expression. 10+/1 2 3 is 1+2+3+10.

10+/1 2 3
16

For subtraction, read the inserted expression from the right. 10-/1 2 3 is 1-2-3-10, or 1-(2-(3-10)).

10-/1 2 3
¯8

Empty reductions

+/⍬
0

The sum of no items is 0. An empty product is 1. With a seed, an empty reduction returns the seed.

×/⍬
1
10+/⍬
10

Axis

The Axis operator chooses the axis to reduce. Sum down the columns along axis 0.

mat←[1 2 3⋄4 5 6]
+/⍠0 mat
5 7 9

Sum across the rows along axis 1.

+/⍠1 mat
6 15
+/mat
6 15

↕ Windows

Windows makes overlapping groups of consecutive major cells. With a vector, a size of 3 gives a matrix whose rows are the length-3 windows.

3↕1 2 3 4
1 2 3
2 3 4

With no left argument, Windows gives adjacent pairs.

↕1 2 3 4
1 2
2 3
3 4

Reduce each window to get a moving sum.

+/3↕1 2 3 4
6 9

For a moving average, divide those sums by the window size. Commute lets us put the 3 before the expression we divide by it.

3÷⍨+/3↕1 2 3 4
2 3

Windows’ inverse joins overlapping windows back into one array. Their overlapping items must agree. Keep the same size for the dyadic form.

↕⁻¹[1 2⋄2 3⋄3 4]
3↕⁻¹[1 2 3⋄2 3 4]
1 2 3 4
1 2 3 4

\ Scan

Running totals

Scan starts with the first item, then combines each result with the next item, working left to right. Plus gives running totals.

+\1 2 3 4 5
1 3 6 10 15
×\1 2 3 4 5
1 2 6 24 120
÷\1 2 3
1 0.5 0.1666666667

The last division above is (1÷2)÷3. Compare that with Reduce’s 1÷(2÷3). A scan can also start from a seed.

10-\1 2 3
9 7 4

A superscript applies to the whole derived function on its left. Scan’s inverse recovers the input from its running results. A seeded scan’s inverse needs the same seed.

+\⁻¹1 3 6
10-\⁻¹9 7 4
1 2 3
1 2 3

⌿ Reduce first

Reduce first works along axis 0. Compare the row sums from +/ with the column sums from +⌿.

+/mat
6 15
+/⍠0 mat
5 7 9
+⌿mat
5 7 9

⍀ Scan first

Scan first works down axis 0.

+⍀mat
1 2 3
5 7 9

Scan first’s inverse also works down the first axis.

+⍀⁻¹[1 2 3⋄5 7 9]
1 2 3
4 5 6

⍤ Rank

Choosing cells

A cell consists of an array’s last few axes. A row is a rank-1 cell; a matrix is a rank-2 cell. Rank specifies the cells passed to a function. Here +⌿⍤1 sums each row of a cube.

cube←2 3 4⍴↦24
cube
+⌿⍤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
⎕←{⎕←⍵ ⋄ +⌿⍵}⍤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

The dfn prints each row before summing it. The axes outside the cells form the frame; here the six row sums are assembled into a 2×3 matrix.

Compare this with a column sum on one matrix.

mat←[1 2 3 4⋄5 6 7 8⋄9 10 11 12]
+⌿mat
15 18 21 24

At rank 2, each 3×4 matrix formed by the cube’s last two axes is passed to +⌿.

+⌿⍤2 cube
15 18 21 24
51 54 57 60

With two arguments, we can choose a cell rank for each. Here the left argument supplies individual numbers and the right supplies rows. The dfn prints each pair before adding it.

⎕←1 2 3 {⎕←[⍺ ⍵] ⋄ ⍺+⍵}⍤0 1 mat
[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

Inverting a ranked function applies its inverse to the same cells. Parentheses keep the whole -⍤0 function together.

(-⍤0)⁻¹[¯1 ¯2 ¯3]
1 2 3

∘ Atop

Atop applies the function on the right, then applies the function on the left to its result. f∘g y is f(g y); with two arguments, x f∘g y is f(x g y).

f←*∘÷
f 3
1.395612425
2 f 3
1.947734041

Atop’s inverse undoes its two steps in reverse order. Here negating a reciprocal is undone by negating, then taking the reciprocal.

(-∘÷)⁻¹¯0.5
2

↣ Before and ↢ After

Binding an argument

Binding fixes one of a function’s arguments, leaving the other for a later call. After binds an argument on the right. *↢2 squares its argument.

sqr←*↢2
sqr 3
9

Before binds an argument on the left. 2↣* raises 2 to its argument.

pow_2←2↣*
pow_2 3
8

Inverses apply to bound functions too. 2↣×⁻¹ undoes doubling. A superscript touching a final number would instead apply to that number: +↢3⁻¹ adds a third. Use parentheses, or a space before ⁻¹, to invert the whole bound function.

2↣×⁻¹10
(+↢3)⁻¹10
+↢3 ⁻¹ 10
5
7
7

Binding Catenate’s right argument fixes the items at the end. The inverse removes them. Catenate first works the same way along its first axis.

(,↢3 4)⁻¹1 2 3 4
(⍪↢3 4)⁻¹[1 2⋄3 4]
1 2
1 2

Combining functions

With functions on both sides, After uses its argument on the left and transforms it on the right. f↢g y means y f(g y). We can scale a list by dividing it by its maximum.

scale←÷↢ ⌈/
a←3 5 8 2 7
scale a
0.375 0.625 1 0.25 0.875

After’s dyadic form x f↢g y is x f(g y). This negates 3 before adding it to 10.

10+↢-3
7

Before transforms the left argument. With one argument, f↣g y means (f y)g y.

-↣+5
0
10-↣+3
¯7

Before’s dyadic form x f↣g y is (f x)g y. The last example negates 10 before adding 3.

With a fixed left argument, these two-function combinations also invert. The fixed value stays 10; the inverse recovers the right argument, 3.

10(+↢-)⁻¹7
10(-↣+)⁻¹¯7
3
3

×↢* multiplies its argument by its exponential, computing x×*x.

×↢*1
2.718281828

This particular monadic After combination has a known inverse. It finds the input that gives the requested product. Most monadic After combinations have no known inverse.

(×↢*)⁻¹1
0.5671432904

Here is the direction of 3j4 again. After divides the original number by its magnitude.

÷↢|3j4
0.6ⱼ0.8

A function can also be displayed without calling it. The display shows the operators and operands from which it was built.

÷↢|
÷↢|

⍥ Over

Transforming both arguments

Over transforms both arguments before combining them. x f⍥g y is (g x)f(g y). With one argument, it works like Atop.

f←*⍥÷
*÷3
1.395612425
f 3
1.395612425
2 f 3
0.793700526
(÷2)*÷3
0.793700526

Over’s inverse undoes the combining function and then the transformation. It works with one argument, or with the same fixed left argument.

f⁻¹ f 3
2 f⁻¹ 2 f 3
3
3

Here both arguments are replaced with their factorials before dividing, giving the number of ways to choose and order four items from ten.

10÷⍥!6
5040
(!10)÷!10-4
5040

⍣ Power

Repeating a function

inc←≥
start←0
inc start
1

Power applies a function a given number of times. inc⍣3 start means inc inc inc start. A zero count returns the starting value.

inc⍣3 start
3

On a function, a superscript digit is a repeat count. inc²5 increments twice, giving 7. On a number, it is an arithmetic power: 5² is 25.

inc²5
5²
7
25

Repeating increment gives addition.

add←{inc⍣⍺ ⍵}
2 add 3
5

Repeating addition gives multiplication. In a dyadic Power call, the left argument stays fixed throughout.

mult←{⍺(add⍣⍵)0}
3 mult 4
12

Undoing a function

A negative Power count applies the inverse function. Here decrement undoes increment.

dec←inc⍣¯1
dec 3
2
inc⍣¯3(5)
2

Inverting a repeated function negates its repeat count. This undoes three increments.

(inc⍣3)⁻¹10
7

The superscript ⁻¹ is shorthand for ⍣¯1. Inverting square gives square root.

sqr←*↢2
sqr⁻¹9
3

Repeating multiplication gives exponentiation.

pow←{⍺(mult⍣⍵)1}
2 pow 3
8

Iterating to a fixed point

A fixed point is a value that a function leaves unchanged. This function adds 1 to the reciprocal of its argument. Repeating it approaches the golden ratio, about 1.618.

f←{1+÷⍵}
f 1
2
f 2
1.5
f 1.5
1.666666667

After 15 steps, the approximation is already close.

f⍣15(1)
1.618034448

The literal ∞ means infinity. As a Power count, it repeats until successive results match. Float comparisons allow a small relative difference, called the tolerance.

f⍣∞(1)
1.618033989

Keeping the intermediate values

A list of counts keeps the result after each count. Counts from 0 include the starting value.

twice←2↣×
twice⍣(⍳5)1
1 2 4 8 16

A predicate as the right operand stops Power when it returns true. It sees the new value as ⍺ and the previous value as ⍵.

inc⍣{⍺≥5}0
5

¨ Each

Working on nested items

a←[[1 2 3 4] [5 6 7]]
a
(1 2 3 4⋄5 6 7)

Each applies its function to each item. Here the items are themselves arrays; +/¨ sums each of them.

+/¨a
10 18
b←[[1 2 3] [4 5 6]]
b
(1 2 3⋄4 5 6)

With two arguments, Each pairs their items. Add 2 to the first vector and 3 to the second.

2 3+¨b
(3 4 5⋄7 8 9)

Each’s inverse applies the operand’s inverse to each item.

-¨⁻¹[[¯1 ¯2] [¯3]]
(1 2⋄3)

Linear algebra

. Inner product

Pair, then reduce

The function on the right combines paired items. The function on the left reduces those results. A dot product multiplies each pair and adds the products.

1 2 3+.×4 5 6 is (1×4)+(2×5)+(3×6).

1 2 3+.×4 5 6
32

We can also compare each item with 3, then combine the answers with And.

3∧.=3 3 3 3
$t

For matrices, each row on the left pairs with each column on the right. Their dot products form the matrix product.

mat←[1 2⋄3 4]
mat+.×mat
 7 10
15 22

⊗ Outer product

Outer product combines every item on the left with every item on the right. Here each left item multiplies the whole right vector, giving one row of a multiplication table.

1 2 3×⊗4 5 6 7
 4  5  6  7
 8 10 12 14
12 15 18 21

With one argument fixed, an outer product’s inverse recovers the other argument. These are the sums of 1 2 with every item of 10 20.

1 2+⊗⁻¹[11 21⋄12 22]
10 20

⌹ Matrix inverse / Matrix divide

Inverting a matrix

Exact inputs give rational results for the inverse and linear solve below. Their products have no floating-point roundoff.

mat←[1 2⋄3 4]ₓ
inv←⌹mat
inv
¯2ₓ   1ₓ
3ᵣ2 ¯1ᵣ2

Multiplying the inverse by the original matrix gives the identity matrix. It has 1s on its main diagonal, from top-left to bottom-right, and 0s elsewhere. Multiplying by it leaves a matrix unchanged.

inv+.×mat
[1 0
 0 1]ₓ

Solving a linear system

A linear system asks which vector x gives a known vector b when multiplied by a known matrix a. Matrix divide b⌹a solves it, finding x such that a+.×x is b. Without an exact solution, it gives a least-squares solution, minimizing the sum of squared differences from b.

solution←[5 6]ₓ⌹mat
solution
¯4ₓ 9ᵣ2
mat+.×solution
[5 6]ₓ

Matrix inverse is its own inverse: ⌹⁻¹ applies ⌹ again.

⌹⁻¹inv
[1 2
 3 4]ₓ

Custom operators

A derivative measures how quickly a function’s result changes near a point. We can approximate it by dividing the difference between two nearby results by the distance between their arguments. Here d is that distance, called the step size. A smaller step brings the estimate for square at 3 closer to 6.

f←*↢2
d←0.01
x←3
d÷⍨(f x+d)-f x
6.01
d←0.0001
d÷⍨(f x+d)-f x
6.0001

Use ⍶ inside a dfn to make an operator. It names the left operand. This operator takes the point as ⍺ and the step size as ⍵.

grad←{((⍶ ⍺+⍵)-⍶ ⍺)÷⍵}
3 f grad 0.01
6.01

With Commute, we can put the step size first in the division.

grad←{⍵÷⍨(⍶ ⍺+⍵)-⍶ ⍺}
3 f grad 0.01
6.01

A two-operand operator uses ⍹ for its right operand. This one applies its right operand, then its left, like Atop.

compose←{⍶ ⍹ ⍵}
- compose square 3
¯9

Giving a function its inverse

For a dfn, attach an inverse to its name with f⁻¹←g. Here shift adds 3, and we supply the dfn that subtracts 3.

shift←{⍵+3}
shift⁻¹←{⍵-3}
shift⁻¹10
7

∂ Derivative

The built-in Derivative operator differentiates the operations inside its operand. It needs no step size.

f∂3
6

For a function that returns one number from a vector, Derivative gives a gradient: a vector with one derivative for each input number.

{+/⍵×⍵}∂1 2 3
2 4 6