Matrix User's Guide

A matrix contains a pointer to a continuous memory block. Since Z-Script uses the term "array" for its hash array. "Matrix" is used here to mean 1D or 2D numerical arrays of C-equivalent types of char, unsigned char, short, unsigned short, int, unsigned int, float, and double.

Data in a matrix are arrange in row major and row and column are counted from 0, as shown in the following figure.

Although matrix operations are intended for handling 1-D or 2D data, it does not mean that the matrix library cannot be used for a higher dimension data. For example, assuming you have data of 3x3x3 stored in a hard disk, you can create a 3x9 matrix, read the data, and then treat each row as a 3x3 matrix.

Matrix Creation

A matrix is created by the matrix() function:

A = matrix("int");    		        // create integer matrix of 1 x 1
B = matrix("float", 10);           // create float matrix of 10 x 1
C = matrix("double", 10, 10);      // create double matrix of 10 x 10
D = matrix(1, 2, 3, 4, 5);         // create a 5 x 1 double initialize it with the numbers

Matrix Duplication

The simplest way to duplicate a matrix is to use "+" operators:

A = matrix("int", 10, 10");      // create in integer matrix of 10 x 10
A:fill(0, 1);                    // a is filled with number from 0 to 99
B = A + 0;                       // duplicate a

When adding 0 to a matrix, nothing more than matrix duplication happens. The same is true for subtracting 0 from a matrix and multiplying or dividing a matrix by 1.

The clone() function let you duplicate matrixes of different types:

A = matrix("int", 10, 10");      // create in integer matrix of 10 x 10
A:fill(0, 1);                    // a is filled with number from 0 to 99
B = matrix("double");
B:clone(A);                      // resize B and transfer data from A to B
C = matrix("double", A)          // alternative way to clone a matrix

Memory Address

The main purpose of the matrix library is for data manipulation. The library has readtext() and parse() for importing data in text format, but is often necessary to read binary data into a matrix. In such a case, you may obtain the pointer of a matrix and pass it to functions of other libraries:

A = matrix("double", 10, 10");
p = A:ptr()
ptr = p[0];              // the pointer
n = p[1];                // the number of matrix element
e = p[2];                // the number of bytes of an element
[ptr, n, e] = A:ptr();   // A shortcut to get ptr, n, and e

Data Manipulation

A matrix may be thought of as an Excel worksheet. The most frequently encountered data manipulations are setting and getting data in cells, in columns, or in rows. Taking the advantage of Z-Script's special array access and assignment features, __get and __set functions are implemented in the matrix library for these operations (See reference for matrix access and assignment). A matrix value may be obtained or changed by

a = A[1,2];         // get the value at the 2nd row and the 3rd column
b = A[5];           // get the value of the 6th element
A[2] = 0;           // set 0 to the 3nd element
A[2,1] = 0;         // set 0 to the element at the 3rd row and the 2nd column.

In the first expression above, The first index refers to row and the second to column. When only one index is used, as in the second expression, it does not care what is the shape of A. If A is 3x3, for example, A[5] means the 2nd row and the 3rd column.

Manipulating matrix element by element is not recommended because of poor efficiency. Whenever possible, try to manipulate matrix by row, by column, or by block:

a = A[1,null];        // get the 2nd row of A;
A[null,0] = b;       // set b to the 1st column of A;  

Here, null index means all elements in a row or column. The token "*" may be used in the place of null; therefore, the following expressions have the same effect as those above:

a = A[1,*];
A[*,0] = b;

A Multiple rows or columns may be specified using array in indexing:

B = A[*,[1,2]];                 // get the 2nd and 3rd columns of A
A[*,[2,1]] = B;                 // set B to the 3rd and 2nd columns of A  
A[*,[2,1]] = A[*,[1,2]];     // same effect as the tow expressions above

These expressions show how to swap columns. The same may be applied to rows.

When both row and column indexes are specified by arrays, The set and get operations are mean to act on block data:

B = A[[1,3],[0,2]];                // get a block of data from A starting
                                   // from row index 1 to 3 and column index 0 to 2
A[[0,6,2],[0,0]] = 0;              // set 0 to rows of 0,2,4,6 of the 2st column

The first value of a block index array means the start-index; the second means the end-index; and the third means index increment step, which is one when not given.

In addition, the char-type matrix resulted from matrix comparison may be used as index. These expressions confine matrix values between 10 and 100:

I = A < 10;           // I is char-matrix of the same shape as A
                      // with 1 for true and 0 for false of
                      // element-wise comparison of A
A[I] = 10;            // set 10 to those elements that are less than 10
A[A>100] = 100;       // a compact way to achieve similar effect

The operators of <<, >>, ^, |, &, ~ for integer variable of Z-Script have been implemented in the matrix library for left column shifting, right column shifting, upward row shifting, vertical concatenation, horizontal concatenation, and transpose. For example,

A = matrix("int", 3, 3);
A:fill(1,1);
A:print();            /* show:  1  2  3
                                4  5  6
                                7  8  9 */
B = A << 1;           
B:print();            /* show   2  3  1
                                5  6  4
                                8  9  7 */

(A^-1):print();       /* show:  7  8  9
                                1  2  3
                                4  5  6 */

(A~):print();         /* show:  1  4  7
                                2  5  6
                                3  6  9 */
B = A | A*10;
C = B & B;
C:print();            /* show:  1 2 3 10 20 30
                                4 5 6 40 50 60
                                7 8 9 70 80 90
                                1 2 3 10 20 30
                                4 5 6 40 50 60
                                7 8 9 70 80 90 */

 

Applying Functions to Matrix

Since nearly all Z-Script operators and all math functions are defined for matrix to return a new matrix, you can treat a matrix just like a regular numerical variable in script programs. This feature greatly simplifies the use of user defined script functions:
// convert longitude and latitude to point on sphere surface
function convert(r, lon, lat)
{

    lon *= 0.017453292519943;    // degree to radius, i.e., 2pi/360
    lat *= 0.017453292519943;
    z = r * sin(lat);
    d = r * cos(lat);
    x = d * cos(lon);
    y = d * sin(lon);
    return [x, y, z];
}

a = convert(100, 180, 30);
x = a[0];           // x is a number
y = a[1];           // so is y
z = a[2];           // and z too

a = convert(100, X, Y);    // assume X and Y are matrixes of the same size
x = a[0];           // now x is a matrix
y = a[1];           // so is y
z = a[2];           // and z too

Set Operators

Using the set-add operator is more efficient then using the add operator because the later involves creation of a temporal matrix:

a = matrix("int", 10, 10);
a = a + 10;

// more efficient
b = matrix("int", 10, 10);
b += 10;

The same is true for -=, *=, /=, and etc.