mat←3 2⍴⍳6
mat0 1
2 3
4 5
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.
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.
Plus follows the same agreement rule. Add 1 to the first row and 2 to the second.
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.
An inverse can work along the same chosen axis. This subtracts the fixed vector from each row, undoing the addition above.
The comma functions join arrays and change how their axes are arranged.
, (Comma), (Ravel)Ravel returns the items as a vector.
Ravel changes the outer shape. Nested items stay nested.
Ravel loses the original shape. Its inverse accepts a vector and leaves it unchanged.
An empty axis list appends a new axis of length 1. The string becomes a column.
Its shape changes from 3 to 3 1.
Consecutive axes can be merged. Merging axes 0 and 1 turns the two groups of three rows into six rows.
, (Catenate)Catenate joins arrays.
The join is along the last axis. A single value extends to fill the other axes.
With a fixed left argument, Catenate’s inverse removes those items from the beginning. The result must begin with the fixed items.
Add the item 10 to the end of each row.
Choose axis 0 to join along the columns instead. This adds a row. Parentheses keep the argument 10 separate from the axis number 0.
To stack arrays along a new axis, put them in rows of a bracket literal.
⍪ (Comma bar)⍪ (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.
We can make a column from a string.
The first axis stays length 2. The remaining lengths, 3 and 4, multiply to give 12 columns.
Table’s inverse turns a one-column matrix back into a vector. Other matrices stay unchanged.
⍪ (Catenate first)With two arguments, ⍪ joins along the first axis.
With a fixed left argument, Catenate first’s inverse removes those leading rows.
⍨ Self / CommuteCommute swaps a function’s arguments. 3-⍨2 means 2-3.
Commute’s inverse undoes the swapped call. Keeping 3 fixed on the left, the inverse finds the 2 that gave the result ¯1.
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.
With one argument, Self passes that argument to both sides of the function. ×⍨3 means 3×3.
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.
With a number or array as its operand, ⍨ makes a function that always returns that value.
A constant function’s inverse accepts only that constant and returns it.
/ ReduceReduce 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.
Changing the operand to Times multiplies all the items together.
Find the largest item.
Find the smallest item.
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.
For subtraction, read the inserted expression from the right. 10-/1 2 3 is 1-2-3-10, or 1-(2-(3-10)).
The sum of no items is 0. An empty product is 1. With a seed, an empty reduction returns the seed.
The Axis operator chooses the axis to reduce. Sum down the columns along axis 0.
Sum across the rows along axis 1.
↕ WindowsWindows makes overlapping groups of consecutive major cells. With a vector, a size of 3 gives a matrix whose rows are the length-3 windows.
With no left argument, Windows gives adjacent pairs.
Reduce each window to get a moving sum.
For a moving average, divide those sums by the window size. Commute lets us put the 3 before the expression we divide by it.
Windows’ inverse joins overlapping windows back into one array. Their overlapping items must agree. Keep the same size for the dyadic form.
\ ScanScan starts with the first item, then combines each result with the next item, working left to right. Plus gives running totals.
The last division above is (1÷2)÷3. Compare that with Reduce’s 1÷(2÷3). A scan can also start from a seed.
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.
⌿ Reduce firstReduce first works along axis 0. Compare the row sums from +/ with the column sums from +⌿.
⍀ Scan firstScan first works down axis 0.
Scan first’s inverse also works down the first axis.
⍤ RankA 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.
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 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.
At rank 2, each 3×4 matrix formed by the cube’s last two axes is passed to +⌿.
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 [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.
∘ AtopAtop 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).
Atop’s inverse undoes its two steps in reverse order. Here negating a reciprocal is undone by negating, then taking the reciprocal.
↣ Before and ↢ AfterBinding 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.
Before binds an argument on the left. 2↣* raises 2 to its argument.
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.
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.
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.
After’s dyadic form x f↢g y is x f(g y). This negates 3 before adding it to 10.
Before transforms the left argument. With one argument, f↣g y means (f y)g y.
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.
×↢* multiplies its argument by its exponential, computing x×*x.
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.
Here is the direction of 3j4 again. After divides the original number by its magnitude.
A function can also be displayed without calling it. The display shows the operators and operands from which it was built.
⍥ OverOver transforms both arguments before combining them. x f⍥g y is (g x)f(g y). With one argument, it works like Atop.
Over’s inverse undoes the combining function and then the transformation. It works with one argument, or with the same fixed left argument.
Here both arguments are replaced with their factorials before dividing, giving the number of ways to choose and order four items from ten.
⍣ PowerPower applies a function a given number of times. inc⍣3 start means inc inc inc start. A zero count returns the starting value.
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.
Repeating increment gives addition.
Repeating addition gives multiplication. In a dyadic Power call, the left argument stays fixed throughout.
A negative Power count applies the inverse function. Here decrement undoes increment.
Inverting a repeated function negates its repeat count. This undoes three increments.
The superscript ⁻¹ is shorthand for ⍣¯1. Inverting square gives square root.
Repeating multiplication gives exponentiation.
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.
After 15 steps, the approximation is already close.
The literal ∞ means infinity. As a Power count, it repeats until successive results match. Float comparisons allow a small relative difference, called the tolerance.
A list of counts keeps the result after each count. Counts from 0 include the starting value.
A predicate as the right operand stops Power when it returns true. It sees the new value as ⍺ and the previous value as ⍵.
¨ EachEach applies its function to each item. Here the items are themselves arrays; +/¨ sums each of them.
With two arguments, Each pairs their items. Add 2 to the first vector and 3 to the second.
Each’s inverse applies the operand’s inverse to each item.
. Inner productThe 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).
We can also compare each item with 3, then combine the answers with And.
For matrices, each row on the left pairs with each column on the right. Their dot products form the matrix product.
⊗ Outer productOuter 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.
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.
⌹ Matrix inverse / Matrix divideExact inputs give rational results for the inverse and linear solve below. Their products have no floating-point roundoff.
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.
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.
Matrix inverse is its own inverse: ⌹⁻¹ applies ⌹ again.
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.
Use ⍶ inside a dfn to make an operator. It names the left operand. This operator takes the point as ⍺ and the step size as ⍵.
With Commute, we can put the step size first in the division.
A two-operand operator uses ⍹ for its right operand. This one applies its right operand, then its left, like Atop.
For a dfn, attach an inverse to its name with f⁻¹←g. Here shift adds 3, and we supply the dfn that subtracts 3.
∂ DerivativeThe built-in Derivative operator differentiates the operations inside its operand. It needs no step size.
For a function that returns one number from a vector, Derivative gives a gradient: a vector with one derivative for each input number.