The result of an elemental function has the same shape as its argument(s). Each element of the result is defined by applying the function to the corresponding element of the argument.
The following table is very similar to Table 5.3 in Ousterhout's 1994 classic Tcl and the Tk Toolkit:
| Function | Result |
|---|---|
abs(x)
| Absolute value of x |
acos(x)
| Arc cosine of x, in the range 0 to π |
asin(x)
| Arc sine of x, in the range -π/2 to π/2 |
atan(x)
| Arc tangent of x, in the range -π/2 to π/2 |
atan(y,x)
| Arc tangent of y/x, in the range -π to π |
atan2(y,x)
|
Alias for atan
|
ceil(x)
| Smallest integer not less than x |
cos(x)
| Cosine of x (x in radians) |
cosh(x)
| Hyperbolic cosine of x |
exp(x)
| ex, where e is base of natural logarithms |
floor(x)
| Largest integer not greater than x |
fmod(x,y)
|
x%y
|
isnan(x)
| 1 if x is NaN, 0 otherwise |
log(x)
| logex (natural logarithm of x) |
log(x,y)
| logyx |
log10(x)
| log10x |
hypot(x,y)
| √(x2+y2) |
nint(x)
| Nearest integer to x |
pow(x,y)
| xy |
random(x)
|
f32 or f64 random number r such that
0 ≤ r < x
|
round(x)
|
Alias for nint
|
sign(x)
|
Sign of x, i.e.
(x>0)-(x<0)
|
sin(x)
| Sine of x (x in radians) |
sqrt(x)
| √x |
sinh(x)
| Hyperbolic sine of x |
tan(x)
| Tangent of x (x in radians) |
tanh(x)
| Hyperbolic tangent of x |
The following data-type conversion functions are also elemental:
c8(x)
f32(x)
f64(x)
i8(x)
i16(x)
i32(x)
u8(x)
u16(x)
u32(x)
Here are some examples of their use:
% [nap "f32(97 .. 102)"] all; # convert from i32 to f32
::NAP::43-43 f32 MissingValue: NaN References: 0 Unit: (NULL)
Dimension 0 Size: 6 Name: (NULL) Coordinate-variable: (NULL)
Value:
97 98 99 100 101 102
% [nap "u8('abcdef')"]; # Display ASCII codes for 'abcdef'
97 98 99 100 101 102
% [nap "c8(97 .. 102)"]; # Reverse this process
abcdef
A reduction or insert function is one which has the effect of inserting a binary operator between the cells of its argument. If the argument is a vector then its elements are the cells and the result is a scalar. If the argument is a matrix then its rows are the cells and the result is a vector containing the sum of each column. Such functions are termed reductions because the result has a rank which is one less than the argument.
A classic example is the ∑ summation operation, which corresponds to
the NAP function sum.
This can be used as follows to produce a scalar (rank 0) result by summing
a vector (rank 1):
% [nap "sum({0.5 2 -1 8})"]
9.5
This function sum can be applied to a matrix (rank 2) to produce
a vector (rank 1). If the second argument is omitted then we get the sum
of each column. If it is 1 we get the sum of each row. This is shown by:
% nap "mat = {
{2 5 0}
{6 7 1}
}"
::NAP::49-49
% [nap "sum mat"]
8 12 1
% [nap "sum(mat,1)"]
7 14
The NAP reduction and scan functions are listed in the following table:
| Function | Type | Result | |
|---|---|---|---|
count(x[,r])
| reduction | Number of non-missing elements in rank-r sub-arrays of x | |
max(x[,r])
| reduction | Maximum of rank-r sub-arrays of x | |
min(x[,r])
| reduction | Minimum of rank-r sub-arrays of x | |
prod(x[,r])
| reduction | Product of rank-r sub-arrays of x | |
psum(x)
| scan | Partial sums of x (see below) | |
sum(x[,r])
| reduction | Sum of rank-r sub-arrays of x |
The optional second argument of reduction functions is called the verb-rank (as in J). It specifies the rank of the sub-arrays (cells) to which the process is applied. In the above example the verb-rank was 1, so the matrix was split into vectors (corresponding to each row) before doing the summation. This final summation process is always done by summing along the first (most significant) dimension.
It is possible to specify a verb-rank of 0.
This is useful with count() because each (rank 0) element is
processed separately.
If it is missing the result is 0, otherwise it is 1.
So this gives us an elemental function for testing whether values are missing.
Note that the rank does not change in this case!
E.g.
% [nap "count({4 _ 2 -9}, 0)"]
1 0 1 1
The result of psum(x)
has the same shape as
x.
If x is a vector and r
is the result (with the same shape) then each element of
r is defined by
| I | ||
| r I = | ∑ | x i |
| i=0 |
| I | J | ||
| r IJ = | ∑ | ∑ | x ij |
i=0
|
j=0
| |
The following example shows how partial sums can be used to calculate a 3-point moving-average in an efficient manner:
% nap "x = {2 7 1 3 8 2 5 0 2 5}"
::NAP::136-136
% nap "ps = 0 // psum(x)"
::NAP::141-141
% $ps all -col -1
::NAP::141-141 i32 MissingValue: -2147483648 References: 1 Unit: (NULL)
Dimension 0 Size: 11 Name: (NULL) Coordinate-variable: (NULL)
Value:
0 2 9 10 13 21 23 28 28 30 35
% [nap "(ps(3 .. 10) - ps(0 .. 7)) / 3.0"] value
3.33333 3.66667 4 4.33333 5 2.33333 2.33333 2.33333
Can you allow for missing values?
How about averages of a moving window in 2 dimensions?
Other similar scan functions can be defined for partial products and so on.
However NAP currently has only psum.
| Function | Result |
|---|---|
coordinate_variable(x[d])
| Coordinate variable of dimension d (default 0) |
label(x)
| Descriptive title |
missing_value(x)
| Value indicating null or undefined data |
nels(x)
|
Number of elements = prod(shape)
|
rank(x)
|
Number of dimensions = nels(shape)
|
shape(x)
| Vector of dimension sizes |
| Function | Result |
|---|---|
sort(x)
| Sort x into ascending order |
reshape(x)
|
Spread the elements of x into a vector
with shape nels(x)
|
reshape(x,s)
| Reshape the elements of x into an array with shape s |
transpose(x)
| Reverse the order of dimensions of x |
transpose(x,p)
| Permute the dimensions of x to the order specified by p |
Here are some examples of the use of these functions:
% [nap "sort {6.3 0.5 9 -2.1 0}"]
-2.1 0 0.5 6.3 9
% [nap "reshape {{1 3 7}{0 9 2}}"] all
::NAP::217-217 i32 MissingValue: -2147483648 References: 0 Unit: (NULL)
Dimension 0 Size: 6 Name: (NULL) Coordinate-variable: (NULL)
Value:
1 3 7 0 9 2
% [nap "reshape({6.3 0.5 9 -2.1 0}, {2 4})"] all
::NAP::224-224 f64 MissingValue: NaN References: 0 Unit: (NULL)
Dimension 0 Size: 2 Name: (NULL) Coordinate-variable: (NULL)
Dimension 1 Size: 4 Name: (NULL) Coordinate-variable: (NULL)
Value:
6.3 0.5 9.0 -2.1
0.0 6.3 0.5 9.0
% [nap "transpose {{1 3 7}{0 9 2}}"] all
::NAP::228-228 i32 MissingValue: -2147483648 References: 0 Unit: (NULL)
Dimension 0 Size: 3 Name: (NULL) Coordinate-variable: (NULL)
Dimension 1 Size: 2 Name: (NULL) Coordinate-variable: (NULL)
Value:
1 0
3 9
7 2
The function
solve_linear(A[,B])
solves a system
of linear equations defined by matrix A and right-hand-sides
B.
B
can be either a vector or a matrix (representing multiple right-hand sides). If
B is omitted then the result is the matrix inverse.
If the system is over-determined (more equations than unknowns) then the result is the solution of the linear least-squares problem. This solution minimizes the sum of the squares of the differences between the left and right-hand sides.
The following system of linear equations is solved by the following example:
3x − 4y = 20
−5x + 8y = −36
% nap "A = {
{3 -4}
{-5 8}
}"
::NAP::14-14
% nap "B = {20 -36}"
::NAP::17-17
% nap "x = solve_linear(A, B)"
::NAP::20-20
% $x a
::NAP::20-20 f64 MissingValue: NaN References: 1 Unit: (NULL)
Dimension 0 Size: 2 Name: (NULL) Coordinate-variable: (NULL)
Value:
4 -2
We can check the result using matrix multiplication:
% [nap "A +* x"] 20 -36
Function correlation calculates Pearson product-moment correlations
(omitting cases where either value is missing).
If
x
or
y
is f64
then the result is
f64, else it is
f32.
(But calculation is still done using f64.)
Dimension 0 of the result has size 2.
Index 0 of this dimension corresponds to the correlation values themselves, while index 1
corresponds to the sample sizes (number of non-missing data elements)
used to calculate these values .
Usage:
correlation(x[, y,
[lag0,
lag1,
… ]])
If the only argument is x, then it must be a matrix. Let nc be the number of columns in this matrix data argument. In this case the result has the shape 2 by nc by nc. Layer 0 contains the correlation matrix. Element rij of this matrix is the correlation between columns i and j of matrix x.
The following example is from Table 15.2 (page 274) of Schaum's Outline of Theory and Problems of Statistics, M.R. Spiegel, 1961:
% [nap "correlation{
{64 57 8}
{71 59 10}
{53 49 6}
{67 62 11}
{55 51 8}
{58 50 7}
{77 55 10}
{57 48 9}
{56 52 10}
{51 42 6}
{76 61 12}
{68 57 9}
}"] -f %6.4f
1.0000 0.8196 0.7698
0.8196 1.0000 0.7984
0.7698 0.7984 1.0000
12.0000 12.0000 12.0000
12.0000 12.0000 12.0000
12.0000 12.0000 12.0000
Layer 0 of the result is the correlation matrix.If y is specified then the result contains one or more correlations between x and y. The ranks of x and y must be the same. (The current version supports ranks 1 and 2 only.)
If x and y have the same shape then the result contains a single correlation, calculated by treating the elements of each array as two lists of values. An example is:
% [nap "correlation({1 3 _ 6 6}, {6 6 4 2 3})"] all
::NAP::118-118 f32 MissingValue: NaN References: 0 Unit: (NULL)
Dimension 0 Size: 2 Name: (NULL) Coordinate-variable: (NULL)
Dimension 1 Size: 1 Name: (NULL) Coordinate-variable: ::NAP::119-119
Value:
-0.924138
4.000000
Element 2 (base 0) of
x
is missing, so element 2 from
y
is not used and the sample size is 4 (as shown in the second element of the result).
The correlation between {1 3 6 6} and {6 6 2 3}
is calculated to be -0.924138.
If x and y
have different shapes then the smaller of
x and y
is a window (chip) array which is moved around in the other array,
producing a correlation for each position.
lag0
is vector of row lags (default: all possible)
lag1
is vector of column lags (default: all possible)
There is currently just one grid function,
invert_grid, but it has variants for one and two dimensions.
The function defines a piecewise (bi-)linear mapping
as the inverse of a given piecewise (bi-)linear mapping.
In the 1D case, the function is called by
invert_grid(y,ycv),
where
y
is the known mapping (and has a coordinate variable corresponding to
x)
and
ycv
is the desired new y coordinate variable.
We have a piecewise-linear mapping from x to y,
and we want a piecewise-linear mapping from y to x.
The following example starts with a mapping from x to y
defined by the two lines
joining the three points (0, 0), (2, 1) and (5, 4).
It produces the inverse mapping from y to x
defined by the four lines joining the five points
(0, 0),
(1, 0.5),
(2, 1.5),
(2.5, 1.5)
and
(3, 2).
% nap "y = {0 1 4}"
::NAP::90-90
% $y set coo "{0 2 5}"
% [nap "coordinate_variable(y) /// y"]
0 2 5
0 1 4
% [nap "ycv = 0 .. 2 ... 1r2"]
0 0.5 1 1.5 2
% nap "x = invert_grid(y,ycv)"
::NAP::106-106
% $x all
::NAP::106-106 f32 MissingValue: NaN References: 1 Unit: (NULL)
Link: ::NAP::107-107
Dimension 0 Size: 5 Name: (NULL) Coordinate-variable: ::NAP::103-103
Value:
0 1 2 2.5 3
% [nap "coordinate_variable(x) /// x"]
0.0 0.5 1.0 1.5 2.0
0.0 1.0 2.0 2.5 3.0
In the 2D case, the function is called by
invert_grid(y,ycv,x,xcv),
where matrix y defines a mapping from
ij space to y.
matrix x defines a mapping from
ij space to x.
The result is a 3D array whose
The following 2D example shows how a satellite image can be mapped to latitude/longitude space (i.e. a Cylindrical Equidistant map projection). Note that the terms line and pixel refer to the row and column of a raw satellite image respectively. We are interested in an input region bounded by line 40, line 50, pixel 1 and pixel 21. Assume we know the latitude and longitude on a 3×3 grid corresponding to lines 40, 50, 60 and pixels 1, 11, 21. The following defines and displays an inverse grid for latitudes 40°S, 30°S, 25°S and longitudes 150°E, 160°E, 170°E, 180°E:
nap "line = {40 50 60}"
nap "pixel = {1 11 21}"
nap "lat_grid = {{-40 -50 _}{-30 -40 -50}{-20 -30 -40}}"
$lat_grid set coo line pixel
nap "lon_grid = {{200 180 _}{180 160 140}{160 140 120}}"
$lon_grid set coo line pixel
nap "lat_cv = {-40 -30 -25}"
$lat_cv set unit degrees_north
nap "lon_cv = 150 .. 180 ... 10"
$lon_cv set unit degrees_east
nap "ig = invert_grid(lat_grid, lat_cv, lon_grid, lon_cv)"
$ig all
This displays the following inverse grid:
::NAP::46-46 f32 MissingValue: NaN References: 1 Unit: (NULL) Link: ::NAP::47-47 Dimension 0 Size: 3 Name: (NULL) Coordinate-variable: ::NAP::36-36 Dimension 1 Size: 4 Name: (NULL) Coordinate-variable: ::NAP::39-39 Dimension 2 Size: 2 Name: (NULL) Coordinate-variable: (NULL) Value: 52.5 13.5 50.0 11.0 47.5 8.5 45.0 6.0 57.5 8.5 55.0 6.0 52.5 3.5 50.0 1.0 60.0 6.0 57.5 3.5 55.0 1.0 _ _The following displays the coordinate variables of this inverse grid
ig:
% [$ig coo 0] all ::NAP::36-36 f32 MissingValue: NaN References: 1 Unit: degrees_north Dimension 0 Size: 3 Name: (NULL) Coordinate-variable: (NULL) Value: -40 -30 -25 % [$ig coo 1] all ::NAP::39-39 f32 MissingValue: NaN References: 1 Unit: degrees_east Dimension 0 Size: 4 Name: (NULL) Coordinate-variable: (NULL) Value: 150 160 170 180The first row of
ig is
52.5 13.5Let us use these values as indirect indices of the original latitude and longitude grids:
% [nap "lat_grid(@52.5, @13.5)"] -40 % [nap "lon_grid(@52.5, @13.5)"] 150Note that these results correspond to the initial values of the coordinate variables of
ig.
Now let us define a small extract from a raw satellite image:
nap "raw = {
{99 91 91 90}
{95 95 92 91}
{90 89 88 88}
}"
nap "line = 50 .. 52"
nap "pixel = 1 .. 4"
$raw set coo line pixel
The latitudes and longitudes at these points are given by
% [nap "lat_grid(@line, @pixel)"] -30 -31 -32 -33 -29 -30 -31 -32 -28 -29 -30 -31 % [nap "lon_grid(@line, @pixel)"] 180 178 176 174 178 176 174 172 176 174 172 170
We can map this image to a Cylindrical Equidistant projection as follows:
% nap "latitude = f32(-29 .. -33)" ::NAP::135-135 % nap "longitude = f32(170 .. 180)" ::NAP::142-142 % nap "cyl_eq = raw(@ig(@latitude, @longitude, ))" ::NAP::166-166 % $cyl_eq all -f %.1f -col 11 ::NAP::166-166 f32 MissingValue: NaN References: 1 Unit: (NULL) Dimension 0 Size: 5 Name: (NULL) Coordinate-variable: ::NAP::152-152 Dimension 1 Size: 11 Name: (NULL) Coordinate-variable: ::NAP::153-153 Value: 91.0 _ _ _ _ _ _ _ _ _ _ 89.2 88.7 88.0 89.4 91.0 92.9 95.0 94.5 95.0 96.5 99.0 88.0 88.8 89.8 90.8 92.0 92.3 92.2 91.8 91.0 92.1 92.2 91.0 91.1 91.0 91.0 91.0 91.0 91.0 90.3 89.8 89.3 89.0 95.0 94.7 93.8 92.2 90.0 89.7 89.2 88.7 88.0 89.4 91.0 % [$cyl_eq coo 0] all ::NAP::152-152 f32 MissingValue: NaN References: 1 Unit: degrees_north Dimension 0 Size: 5 Name: (NULL) Coordinate-variable: (NULL) Value: -29 -30 -31 -32 -33 % [$cyl_eq coo 1] all -col 11 ::NAP::153-153 f32 MissingValue: NaN References: 1 Unit: degrees_east Dimension 0 Size: 11 Name: (NULL) Coordinate-variable: (NULL) Value: 170 171 172 173 174 175 176 177 178 179 180
| Function | Result |
|---|---|
open_box(x)
| NAO pointed to by boxed NAO x |
pad(x)
| Normal NAO corresponding to ragged NAO x |
prune(x)
| Ragged NAO corresponding to normal NAO x |
The following example illustrates the use of the function
open_box, which allows one to extract NAOs from
a structure created with the operator ",".
% nap "pointers = {4 5} , 'hello' , 9"
::NAP::9776-9776
% $pointers
9772 9773 9775
% [nap "open_box(pointers(0))"] all
::NAP::9772-9772 i32 MissingValue: -2147483648 References: 1 Unit: (NULL)
Dimension 0 Size: 2 Name: (NULL) Coordinate-variable: (NULL)
Value:
4 5
% [nap "open_box(pointers(1))"] all
::NAP::9773-9773 c8 MissingValue: (NULL) References: 1 Unit: (NULL)
Dimension 0 Size: 5 Name: (NULL) Coordinate-variable: (NULL)
Value:
hello
% [nap "open_box(pointers(2))"] all
::NAP::9775-9775 i32 MissingValue: -2147483648 References: 1 Unit: (NULL)
Value:
9
The following example illustrates the use of
functions
prune
and its inverse
pad.
Function
prune
creates a ragged array.
This suppresses missing values at the start and end of the least significant
dimension (column in this matrix case).
In this matrix case it creates a separate NAO for each row and stores an
index (slot number) to these in the result.
% nap "data = {{0 1.5 2 -1}{_ 1 4 1n}{4#_}{2#_ 9 -9}}"
::NAP::9736-9736
% $data
0.0 1.5 2.0 -1.0
_ 1.0 4.0 _
_ _ _ _
_ _ 9.0 -9.0
% nap "compressed_data = prune(data)"
::NAP::9738-9738
% $compressed_data all
::NAP::9738-9738 ragged MissingValue: 0 References: 1 Unit: (NULL)
Dimension 0 Size: 4 Name: (NULL) Coordinate-variable: (NULL)
Dimension 1 Size: 4 Name: (NULL) Coordinate-variable: (NULL)
Value:
0 start-index: 0 ::NAP::9740-9740
1 start-index: 1 ::NAP::9741-9741
2 start-index: 4 ::NAP::9742-9742
3 start-index: 2 ::NAP::9743-9743
% ::NAP::9743-9743
9 -9
% [nap "pad(compressed_data)"] all
::NAP::9745-9745 f64 MissingValue: NaN References: 0 Unit: (NULL)
Dimension 0 Size: 4 Name: (NULL) Coordinate-variable: (NULL)
Dimension 1 Size: 4 Name: (NULL) Coordinate-variable: (NULL)
Value:
0.0 1.5 2.0 -1.0
_ 1.0 4.0 _
_ _ _ _
_ _ 9.0 -9.0
| Function | Result |
|---|---|
dilate(x,se[,seo])
| Binary dilation of x; se = structure-element; seo = origin of structure-element |
erode(x,se[,seo])
| Binary erosion of x; se = structure-element; seo = origin of structure-element |
moving_range(x,s)
| Range (max-min) of moving shape-s window around matrix x |
x is an n by m non-negative matrix that is being
dilated or eroded.
se is the morphological structure element,
an a by b matrix, where a<n
and b<m.
seo is the origin of the structure element indexed from 0 at the top left corner.
Move a window over the matrix x and find the maximum difference between values in the moving window. The result is placed in the element nearest the centre of the moving window.