Built-in Functions

Table of Contents

  1. Elemental Functions
  2. Reduction and Scan Functions
  3. Metadata Functions
  4. Functions which change shape or order
  5. Linear-algebra Functions
  6. Correlation
  7. Grid Functions
  8. Functions related to Special Data-types
  9. Morphological Functions
    1. Morphological Binary Dilation and Erosion
    2. Moving Range

Elemental Functions

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 0r < 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

Reduction and Scan Functions

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
If x is a matrix and r is the result (with the same shape) then each element of r is defined by
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.

Metadata Functions

Metadata functions return information (other than data values) from a NAO. The same information can be obtained using an OOC, but these functions are more convenient within expressions.

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

Functions which change shape or order

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

Linear-algebra Functions

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

Correlation

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.
The correlation between columns 0 and 1 is 0.8196.
The correlation between columns 0 and 2 is 0.7698.
The correlation between columns 1 and 2 is 0.7984.
There is no missing data, so all values in layer 1 are 12.

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)

Grid Functions

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

  • Dimension 0 has the specified coordinate-variable ycv
  • Dimension 1 has the specified coordinate-variable xcv.
  • dimension 2 is of size 2, corresponding to the i and j mappings We can think of the result as two matrices defining mappings from xy space to i and j respectively.

    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 180
    
    The first row of ig is
    52.5 13.5
    
    Let 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)"]
    150
    
    Note 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
    

    Functions related to Special Data-types

    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
    

    Morphological Functions

    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

    Morphological Binary Dilation and Erosion

    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.

    Moving Range

    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.

    Author: Harvey Davies       © 2002, CSIRO Australia.       Legal Notice and Disclaimer
    CVS Version Details: $Id: function.html,v 1.4 2003/08/25 07:28:01 dav480 Exp $