Stencil: Difference between revisions

 ⌺

Stencil () is a primitive dyadic operator that applies its left operand to (possibly overlapping) rectangular views of the right argument array. The shape and movement of the rectangular views are dictated by the right operand. It was introduced to Dyalog APL in version 16.0 and is also known as tessellation, moving window, stencil code or cut. The operator can be used for computations involving the immediate neighbours of items in an array and has applications in image processing (particularly convolution), artificial neural networks and, most famously, cellular automata. The operator derives from a subset (specifically, case 3) of the functionality of J's Cut operator (;.3),[1] which in turn originates in the 3-cut mentioned in A Dictionary of APL[2]

Description

For a call fs the right operand s can in general be a two-row matrix of strictly positive integers, where the first row describes the dimensions of the rectangles that will be passed to f and the second row describes the movement along the different axes. When using stencil (fs)Y the right operand s in general has ≢⍴Y columns. If it has fewer, the rectangles are cut out of the major cells of the (≢⍴Y) - 1s axis of Y. If s is a vector or scalar it describes only the size of the rectangles and the movement defaults to 1. Rectangles are centred on elements of Y whose indices differ by the movements in s (defaulting to 1), starting with the first element in ravel order. For a matrix, this is the top left. For even window sizes, the centring is instead on the space between elements or cells. Along the edges of the argument array, the windows are thus subject to be padded with fill elements.

The number of fill elements in along each axis is given as a vector left argument on each call of f for the respective subarray. This is designed such that Drop () can take the left and right arguments to remove padding:

({}3 3)3 4⍴⍳12
┌──────┬───────┬────────┬───────┐
0 0 0 0 0 0  0 0 0   0 0 0
0 1 2 1 2 3  2 3 4   3 4 0
0 5 6 5 6 7  6 7 8   7 8 0
├──────┼───────┼────────┼───────┤
0 1  21  2  3 2  3  4 3  4 0
0 5  65  6  7 6  7  8 7  8 0
0 9 109 10 1110 11 1211 12 0
├──────┼───────┼────────┼───────┤
0 5  65  6  7 6  7  8 7  8 0
0 9 109 10 1110 11 1211 12 0
0 0  00  0  0 0  0  0 0  0 0
└──────┴───────┴────────┴───────┘
({}3 3)3 4⍴⍳12
┌────┬────┬────┬─────┐
1 1 1 0 1 0 1 ¯1
├────┼────┼────┼─────┤
0 1 0 0 0 0 0 ¯1
├────┼────┼────┼─────┤
¯1 1¯1 0¯1 0¯1 ¯1
└────┴────┴────┴─────┘
({}3 3)3 4⍴⍳12
┌────┬───────┬────────┬─────┐
1 2 1 2 3  2 3 4   3 4
5 6 5 6 7  6 7 8   7 8
├────┼───────┼────────┼─────┤
1  21  2  3 2  3  4 3  4
5  65  6  7 6  7  8 7  8
9 109 10 1110 11 1211 12
├────┼───────┼────────┼─────┤
5  65  6  7 6  7  8 7  8
9 109 10 1110 11 1211 12
└────┴───────┴────────┴─────┘

Examples

With a default movement in every direction of 1, the rectangles are centred on neighbouring elements of the array. Here, we simply enclose each neighbourhood:

{}3 33 3⍴⍳9
┌─────┬─────┬─────┐
0 0 00 0 00 0 0
0 1 21 2 32 3 0
0 4 54 5 65 6 0
├─────┼─────┼─────┤
0 1 21 2 32 3 0
0 4 54 5 65 6 0
0 7 87 8 98 9 0
├─────┼─────┼─────┤
0 4 54 5 65 6 0
0 7 87 8 98 9 0
0 0 00 0 00 0 0
└─────┴─────┴─────┘

In the following example, each neighbourhood is immediately ravelled and summed:

{+/,}3 33 3⍴⍳9
12 21 16 27 45 33 24 39 28

If the number of columns in the right operand to stencil does not match the rank of the right argument, the windowing is applied on the major cells:

{}(2 2)10 6⍴⍳100
┌──────────────┬─────────────────┬─────────────────┬─────────────────┬─────────────────┐
1 2 3  4  5  613 14 15 16 17 1825 26 27 28 29 3037 38 39 40 41 4249 50 51 52 53 54
7 8 9 10 11 1219 20 21 22 23 2431 32 33 34 35 3643 44 45 46 47 4855 56 57 58 59 60
└──────────────┴─────────────────┴─────────────────┴─────────────────┴─────────────────┘

Stencil allows for a very succinct expression of a dfn that calculates the next iteration in Conway's Game of Life (on a rectangle bound by zeros). Inspired by an algorithm from Arthur Whitney written in K and adapted to APL by Jay Foad:

⎕IO0
life  {3=s-4=s{+/,}3 3}

{'.⍠'[]}¨ (8) {life}¨ glider
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
..⍠...⍠.....⍠...........................
⍠.⍠....⍠⍠....⍠..⍠.⍠....⍠...⍠.....⍠......
.⍠⍠...⍠⍠...⍠⍠⍠...⍠⍠..⍠.⍠....⍠⍠....⍠..⍠.⍠
.................⍠....⍠⍠...⍠⍠...⍠⍠⍠...⍠⍠
......................................⍠.
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘