3.9. Matrices, Vectors, Tensors, Indexes and IDX


Lush has a powerful mechanism for manipulating tabular data such as scalars, vectors, matrices, and tensors from 0 to 8 dimensions.

The basic Lush type for tabular data is called an INDEX or an IDX. The IDX is merely an access structure, the actual data is stored in a STORAGE associated with the IDX.

The data contained in a storage, and accessed with an IDX, can be of type double, float, int, short, byte, ubyte, gptr (generic pointer), atom (lisp object), and packed (one-byte fixed point number).

There are many IDX-related functions in Lush. Some are described in this section, but the vast majority is described in the Standard Libraries section.

creating a tensor of float is done simply with:

  ? (setq m (float-matrix 10 8 4))   ; create 3D matrix
  = ::INDEX3:<10x8x4>
  ? (m 3 4 2 45.6)       ; set value of element (3,4,2) to 45.6
  = ::INDEX3:<10x8x4>
  ? (m 3 4 2)            ; get value of element (3,4,2).
  = 45.6
Tensors of various basic types can be created with the functions listed below. Each function has two versions, the regular version initializes all the elements to zero, while the version with -nc at the end do not (no clear) and are a bit faster. All of these functions take 0 to 8 integer arguments that are the sizes in each dimension: Tables of lisp objects (atoms) are created with the array function.



3.9.0. IDX Structure


An IDX is a structure that contains a pointer to the STORAGE where the data resides, and offset indicating where the IDX data starts in the storage, a number of dimensions (between 0 and 8), a size for each dimension, and a modulo for each dimension. The modulo determines by how much a pointer would have to be incremented to go from one element of the IDX to the next element in the given dimension.

Multiple IDXs can point to the same STORAGE and provide access to the same data in multiple ways.

an IDX with 0 dimension is called a scalar, and can be seen as a pointer to a number.



3.9.1. IDX Creation and Allocation


Tensors of various basic types can be created with the functions listed below. Each function has two versions, the regular version initializes all the elements to zero, while the version with -nc at the end do not (no clear) and are a bit faster. All of these functions take 0 to 8 integer arguments that are the sizes in each dimension:



3.9.1.0. (double-matrix s1...sn)
[DX]


create an n -dimensional tensor of double . The arguments are the sizes in each dimension. The elements are initialized to 0.

3.9.1.1. (double-matrix-nc s1...sn)
[DX]


create an n -dimensional tensor of double . The arguments are the sizes in each dimension. The elements are not initialized and may contain non-sensical values.



3.9.1.2. (float-matrix s1...sn)
[DX]


create an n -dimensional tensor of float . The arguments are the sizes in each dimension. The elements are initialized to 0.



3.9.1.3. (float-matrix-nc s1...sn)
[DX]


create an n -dimensional tensor of float . The arguments are the sizes in each dimension. The elements are not initialized and may contain non-sensical values.



3.9.1.4. (int-matrix s1...sn)
[DX]


create an n -dimensional tensor of 32-bit int . The arguments are the sizes in each dimension. The elements are initialized to 0.



3.9.1.5. (int-matrix-nc> s1...sn)


create an n -dimensional tensor of 32-bit int . The arguments are the sizes in each dimension. The elements are not initialized



3.9.1.6. (short-matrix s1...sn)
[DX]


create an n -dimensional tensor of 16-bit short . The arguments are the sizes in each dimension. The elements are initialized to 0.



3.9.1.7. (short-matrix-nc> s1...sn)


create an n -dimensional tensor of 16-bit short . The arguments are the sizes in each dimension. The elements are not initialized



3.9.1.8. (byte-matrix s1...sn)
[DX]


create an n -dimensional tensor of signed byte . The arguments are the sizes in each dimension. The elements are initialized to 0.



3.9.1.9. (byte-matrix-nc> s1...sn)


create an n -dimensional tensor of signed byte . The arguments are the sizes in each dimension. The elements are not initialized



3.9.1.10. (ubyte-matrix s1...sn)
[DX]


create an n -dimensional tensor of unsigned byte . The arguments are the sizes in each dimension. The elements are initialized to 0.



3.9.1.11. (ubyte-matrix-nc> s1...sn)


create an n -dimensional tensor of unsigned byte . The arguments are the sizes in each dimension. The elements are not initialized



3.9.1.12. (gptr-matrix s1...sn)
[DX]


create an n -dimensional tensor of generic pointers (void *). The arguments are the sizes in each dimension. The elements are initialized to NULL.



3.9.1.13. (gptr-matrix-nc> s1...sn)


create an n -dimensional tensor of generic pointers (void *). The arguments are the sizes in each dimension. The elements are not initialized and may cause memory faults if dereferenced carelessly.



3.9.1.14. (array m s1...sn)
[DX]


create an n -dimensional tensor lisp objects. The arguments are the sizes in each dimension. The elements are initialy nil.



3.9.1.15. (new-index srg slist)
[DX]


Creates a new IDX pointing to the storage srg . slist is a list of integers that specifies the size in each of the dimensions. The srg is allocated and resized if necessary.



3.9.2. IDX Literals


The IDX literal syntax can be used to create an IDX and fill it up with values in one fell swoop. Here is how to create a vector of doubles:
  (setq m [3 4 5])
A two-dimensional matrix of doubles can be created as follows:
  (setq m [[1 2 3] [3 4 5]])
Vectors and matrices of other types than doubles can be created by specifying the type with a single character right after the first open bracket. Similarly, IDX of double, floats, int, short, bytes, ubytes, and atoms (lisp objects) can be created by placing one the following characters right after the opening bracket d, f, i, s, b, u, a respectively. Here are a few examples:
  (setq m [d 1 2 3])   ; doubles
  (setq m [f 1 2 3])   ; floats
  (setq m [i 1 2 3])   ; ints
  (setq m [s 1 2 3])   ; shorts
  (setq m [b 1 2 3])   ; bytes
  (setq m [u 1 2 3])   ; ubytes
  (setq m [a "choucroute" "garnie"])  ; lisp objects
Another syntax is provided for IDX of atoms (lisp objects):
  (setq m #["choucroute" "garnie" #])



3.9.2.0. Scalar Literals


Scalars literals (i.e. idx0) can be entered by placing an @ sign after the type indicator. Here is an examples:
  (idx-dotm0 vector [f@ 34] output)
Here are examples for each of the IDX types:
  (setq s [d@ 42])
  (setq s [f@ 42])
  (setq s [i@ 42])
  (setq s [s@ 42])
  (setq s [b@ 42])
  (setq s [u@ 42])
  (setq s [a@ "choucroute"])
  (setq s #[@ "choucroute" #])
The last two lines are equivalent.



3.9.2.1. IDX Literals as Local Variables in Functions


A very important fact about array literals created as local variables within functions is that they are "static" variables (a bit like closures in lexically-bound Lisps). Here is an example:
  ? (de foo () (let ((v [0 1])) (v 0 (+ (v 0) 1)) v))
  = foo
  ? (foo)
  = [  1.00  1.00 ]
  ? (foo)
  = [  2.00  1.00 ]
The values in the IDX are retained from one call to the next. This is true in interpreted mode and in compiled mode. Preventing this behavior can be done by copying the literal each time the function is called:
  (de foo () (let ((v (idx-copy [0 1]))) (v 0 (+ (v 0) 1)) v))



3.9.2.2. Array Literals as Closures


Being dynamically bound, Lush has no lexical closure mechanism. However, array literals provide a way to emulate the behavior of lexical closures (i.e. bundling "static" variables within a function):
  ? (de new-counter () (lambda () (let ((v [@ 0])) (v (1+ (v))) (v))))
  = new-counter
  ? (setq c (new-counter))
  = ::DE:8805898
  ? (c)
  = 1
  ? (c)
  = 2



3.9.3. IDX Copying and Cloning




3.9.3.0. (idx-copy m1 [m2])
[DX]


Copy m1 into m2 . If m1 and m2 are of different numerical types, appropriate conversion will be performed. m1 and m2 must have the same dimensions. If m2 is not present, a fresh copy of m1 is returned (the data is copied).



3.9.3.1. (copy-matrix m1 [m2])
[DX]


Copy m1 into m2 . Unlike idx-copy , this function does not require that m1 and m2 have the same structure as long as they have the same number of elements. In other words, m1 can be a 4 by 5 matrix, and m2 a 20-dimensional vector.



3.9.3.2. (idx-clone m)
[DX]


Return a clone of IDX m . The returned IDX is identical to m and points to the same storage at the same place. This does not actually copy any data.



3.9.3.3. (copy-any-matrix m1 [m2])
[DX]


obsolete function. Works like copy-matrix (sort of). If m2 is omitted return a new copy of m1 (a new storage is created and m1 is copied in it). If m2 is present, the storage of m1 is copied into the storage of m2 . Return m2 .



3.9.4. IDX Iterators




3.9.4.0. (idx-bloop ((symb1 idx1) [ (symb2 idx2) [...(symbn idxn) ]]) body)
[DY]


make each symbi be an idx that loops over the first dimension of its corresponding idxi . Execute body for each value.

More precisely, each si will be an idx with one less dimension than the corresponding idxi , and will simulataneously loop over the successive "slices" of idxi for each possible value of the first index. In other words, applying function myfunc to each element of a vector v1 and putting the result in the corresponding element in v2 can be done with:

  (idx-bloop ((x1 v1) (x2 v2)) (x2 (myfunc (x1))))
x1 and x2 are scalars (i.e. zero-dimensional tensors). The above function work just as well is v1 and v2 are n -dimensional tensors and myfunc accepts n-1 -th dimensional tensors as arguments.



3.9.4.1. (idx-pbloop ((symb1 idx1) [ (symb2> idx2) [...(symbn idxn) ]]) body)
[DY]


Works just like idx-bloop, but the multiple evaluations of the body may be executed in parallel on some implementations of Lush.



3.9.4.2. (idx-eloop ((symb1 idx1) [ (symb2> idx2) [...(symbn idxn) ]]) body)
[DY]


Make each symbi be an idx that loops over the last dimension of its corresponding idxi . Execute body for each value.

This is like idx-bloop, but it loops on the last dimension, instead of the first. For example, the matrix product operation C = A*B can be written as follows:

  (de idx-m2timesm2 (A B C) 
     (idx-eloop ((Bj B)(Cj C)) (idx-m2dotm1 A Bj Cj)))
where idx-m2dotm1 is the usual matrix-vector product. The idx-eloop construct simultaneously iterates over all columns of B and C .



3.9.4.3. (idx-peloop ((symb1 idx1) [ (symb2> idx2) [...(symbn idxn) ]]) body)
[DY]


Works just like idx-pbloop, but the multiple evaluations of the body may be executed in parallel on some implementations of Lush.



3.9.4.4. (cidx-bloop (i_1 [i_2...i_n] (c_1 l_1) [(c_1 l_1)...(c_m l_m)) p_1 [p_2...])
[DF]


This iterator is desinged to facilitate the implementation of inner loops of tensor functions in C, while leaving all the bookkeeping to the Lisp.

A call to cidx-bloop as shown in the synopsis is somewhat equivalent to n nested idx-bloop s, which will loop over the first n dimensions of idxs l_1 to l_m simultaneously. The arguments i_1 to i_n are strings containing names of C local variables that will be created and set to the loop index in each of the n dimensions. At each iteration, the C variables provided in strings c_1 to c_m will point to the appropriate values in the idxs l_1 to l_m . For example, the following function will fill matrix a with cos(i+j).

    (de foo (a)
       ((-idx2- (-flt-)) a)
       (cidx-bloop ("i" "j" ("a" a)) #{ *a = cos(i+j); #}) a)
The return value is (like in idx-bloop) the last IDX specified in the declaration (in the example above, the return value is superfluous).



3.9.4.5. (idx-gloop (p1...[pn]) body)
[DM]


an enhanced version of bloop which allows to "bloop" through a pointer table, and to have access to the current index value of the loop. Each pi is a list with 1, 2, or 3 elements. if it has 2 elements the meaning is like a in reguler bloop. if it has 1 element, which must be a symbol, it will be used as a local variable which contains the current index of the loop. if it has 3 elements. It must be of the form ( symbol p m ), where p is a 1D index and m an index of at least one dimension. symbol will take the values (idx-select m 0 (p i)) for all possible values of i.



3.9.5. IDX Information




3.9.5.0. (indexp m)
[DX]


Return true if m is an IDX.



3.9.5.1. (matrixp m)
[DX]


Return true if m is an IDX whose storage is of a numerical or generic pointer type, as opposed to lisp objects.



3.9.5.2. (arrayp m)
[DX]


return true if m is an IDX over a storage of lisp objects (as opposed to numerical types). For historical reasons, this kind of IDX is also known as an array.



3.9.5.3. (idx-storage m)
[DX]


return the storage on which IDX m points.



3.9.5.4. (idx-size m)
[DX]


return the memory size occupied by the elements of m in bytes.



3.9.5.5. (idx-nelements m)
[DX]


return the number of elements of IDX m . This function is not compilable (no reason, we just forgot to write the macros).



3.9.5.6. (idx-ndim m)
[DX]


return the number of dimensions of IDX m .



3.9.5.7. (idx-offset m)
[DX]


return the offset of the first element of IDX m in its storage. The offset is in number of elements, not bytes.



3.9.5.8. (idx-dim m [n])
[DX]


With two arguments, return the size of IDX m in its n -th dimension (starting at zero). With one argument, return the size of IDX m in each dimension in the form of a list of integers.

Example:

  ? (idx-dim [[2 3 4][5 6 7]])
  = (2 3)



3.9.5.9. (idx-bound m)
[DX]


Return the largest index in each dimension in the form of a list. This function is mostly here for historical reasons.



3.9.5.10. (idx-modulo m [n])
[DX]


With two arguments: return the number of elements that separate two elements that have successive indices in the n -th dimension (starting at zero). With one argument, return a list of all the modulos in all the dimensions.



3.9.5.11. (contiguousp m)
[DE]


returns true if the elements of m are contiguous in memory. IDX resulting from idx-transclone or narrow are generally non-contiguous.



3.9.5.12. (idx-ptr m)
[DX]


return a gptr that points to the first element of m . This must be used with caution because the data pointed to by the pointer may be garbage collected (when m is destroyed), or even displaced (when m is resized). idx-ptr is primarily used when calling C function that require a pointer to numerical data.



3.9.6. IDX Manipulations




3.9.6.0. Cloning Manipulations


These functions take an IDX as argument and return a modified clone of this IDX pointing to the same data (or a subset of it).



3.9.6.0.0. (select m n s)
[DM]


Return a clone of IDX m (on the same storage), with the n -th dimension removed, and which is the s -th "slice" of m , in the n -th dimension.
  ? (setq m [[0 1 2 3 4][10 11 12 13 14]])
  = [[ 0.00  1.00  2.00  3.00  4.00 ]
     [10.00 11.00 12.00 13.00 14.00 ]]
  ? (select m 1 2)
  = [ 2.00 12.00 ]



3.9.6.0.1. (narrow m n s [o])
[DM]


Make a clone of IDX m , and reduce its size in the n -th dimension to s elements, offset by o .
  ? (setq m [[0 1 2 3 4][10 11 12 13 14]])
  = [[ 0.00  1.00  2.00  3.00  4.00 ]
     [10.00 11.00 12.00 13.00 14.00 ]]
  ? (narrow m 1 3 2)
  = [[ 2.00  3.00  4.00 ]
     [12.00 13.00 14.00 ]]



3.9.6.0.2. (unfold m n ksize step)
[DM]


Return an idx on the same storage as m (pointing to the same data) with an added dimension at the end obtained by "unfolding" the n -th dimension. The size of the new dimension is ksize . This essentially manipulates the modulos to make convolutions look like matrix-vector multiplies. For example, a one-dimensional convolution between vector v and kernel k can be done as follows:
  ? (setq v [0 1 2 3 4 5 6])
  = [ 0.00  1.00  2.00  3.00  4.00  5.00  6.00 ]
  ? (setq k [1 2 1])
  = [ 1.00  2.00  1.00 ]
  ? (setq uv (unfold v 0 3 1))
  = [[ 0.00  1.00  2.00 ]
     [ 1.00  2.00  3.00 ]
     [ 2.00  3.00  4.00 ]
     [ 3.00  4.00  5.00 ]
     [ 4.00  5.00  6.00 ]]
  ? (setq r (matrix 5))
  = [ 0.00  0.00  0.00  0.00  0.00 ]
  ? (idx-m2dotm1 uv k r)
  = [ 4.00  8.00 12.00 16.00 20.00 ]
A subsampled convolution (where the kernel is stepped by more than one element) can be performed by setting the step parameter to a value other than 1:
  ? (setq uv (unfold v 0 3 2))
  = [[ 0.00  1.00  2.00 ]
     [ 2.00  3.00  4.00 ]
     [ 4.00  5.00  6.00 ]]
  ? (setq r (matrix 3))
  = [ 0.00  0.00  0.00 ]
  ? (idx-m2dotm1 uv k r)
  = [ 4.00 12.00 20.00 ]
Here are other amusing examples:
  ? (unfold [3 4 5 6 7] 0 5 1)
  = [[ 3.00  4.00  5.00  6.00  7.00 ]]
  ? (unfold [3 4] 0 1 1)      
  = [[ 3.00 ]
     [ 4.00 ]]
Naturally, there is no real need for most programmers to use the unfold construct directly because the standard library contains efficient predefined 1D and 2D convolutions.



3.9.6.0.3. (idx-transclone m dimlist)
[DX]


return a clone of idx m where the dimensions have been permuted according to the list of dimension indices dimlist . For example:
  (idx-transclone m '(0 2 1))
permutes the second and third dimensions.



3.9.6.0.4. (transpose m)
[DE]


Simple transpose function for 1D vectors and 2D matrices. This does not copy any data, but simply returns a new IDX on the same data with the appropriate structure.



3.9.6.0.5. (diagonal m d)
[DM]


return a clone of m where the modulos and dimensions have been hacked so as to grab the diagonal of the last d dimensions. Those dimensions must all have the same size. The result has d-1 less dimensions than the original IDX.
  ? (setq m [[[111 112 113][121 122 123][131 132 133]] 
             [[211 212 213][221 222 223][231 232 233]]])
  = [[[111.00 112.00 113.00 ]
      [121.00 122.00 123.00 ]
      [131.00 132.00 133.00 ]]
     [[211.00 212.00 213.00 ]
      [221.00 222.00 223.00 ]
      [231.00 232.00 233.00 ]]]
  ? (diagonal m 2)
  = [[111.00 122.00 133.00 ]
     [211.00 222.00 233.00 ]]



3.9.6.1. Compilable Direct IDX Manipulations




3.9.6.1.0. (idx-changedim m n v)
[DX]


change the size of the n -th dimension of m to v . This generates an error if the resulting IDX overflows its storage.
  ? (setq m (matrix 3 4))
  = [[ 0.00  0.00  0.00  0.00 ]
     [ 0.00  0.00  0.00  0.00 ]
     [ 0.00  0.00  0.00  0.00 ]]
  ? (m () () (range 0 11))
  = [[ 0.00  1.00  2.00  3.00 ]
     [ 4.00  5.00  6.00  7.00 ]
     [ 8.00  9.00 10.00 11.00 ]]
  ? (idx-changedim m 1 3)
  = ()
  ? m
  = [[ 0.00  1.00  2.00 ]
     [ 4.00  5.00  6.00 ]
     [ 8.00  9.00 10.00 ]]



3.9.6.1.1. (idx-changemod m n v)
[DX]


change modulo of n -th dimension of m to v .



3.9.6.1.2. (idx-changeoffset m n)
[DX]


change offset of m in its storage to n



3.9.6.2. Non-compilable Direct IDX manipulations


These functions directly hack into the IDX passed as argument. Because of those bad side effects, they cannot be called in compiled code.



3.9.6.2.0. (idx-redim m dimlist)
[DX]


Redimensions IDX m to the list of dimensions passed as argument.



3.9.6.2.1. (idx-undim m)
[DX]


Turn m into an un-dimensioned IDX.



3.9.6.2.2. (idx-unfold m n ksize step)
[DX]


same as unfold , but hacks m directly instead of cloning it.



3.9.6.2.3. (idx-diagonal m d)
[DX]


same as diagonal , but hacks m directly instead of cloning it.



3.9.6.2.4. (idx-narrow m n s [o])>


Works like narrow, but hack m "in place" instead of returning a hacked clone.



3.9.6.2.5. (idx-select m n s)
[DX]


same as select , but hacks m directly instead of cloning it.



3.9.6.2.6. (idx-transpose m perm-list)
[DX]


Permute the dimensions of idx using the list of int's perm-list as a permutation matrix.



3.9.6.2.7. (idx-transpose2 idx d1 d2)
[DX]


permute dimesnions d1 and d2 if IDX idx .



3.9.7. Loading and Saving


There are two ways to load and save matrices and tensors in Lush which deal with two incompatible formats. The functions listed below use the so-called "classic" format, but cannot be used in compiled code. The other set of functions, described in the standard library section uses a different format (so-called IDX format) and are based on the C stdio library. This discrepancy exists largely for historical reasons and will be fixed eventually.



3.9.7.0. Loading, Saving, and Mapping Matrices


There are two types of "classic" matrix files: ASCII files and binary files. Binary files are a more accurate, more compact, and more efficient way of saving matrix data. ASCII matrix files should be used only reserved to



3.9.7.0.0. (save-matrix mat file)
[DX]


Stores the matrix mat into the binary file file . Argument file may be a filename string or a file descriptor created with open-write or open-append . When file is a file name, a suffix ".mat" is added when needed. Binary Matrix File Format.



3.9.7.0.1. (save-ascii-matrix mat file)
[DX]


Stores the matrix mat into the text file file . Argument file may be a filename string or a file descriptor created with open-write or open-append . When file is a file name, a suffix ".mat" is added when needed. Ascii Matrix File Format.



3.9.7.0.2. (load-matrix [mat] file)
[DX]


Loads a matrix from file file and returns it. This function senses the file format and performs the adequate actions. If a symbol mat is specified, it stores the new matrix in symbol mat .

Argument file may be a filename string or a file descriptor created with open-read . When file is a file name, a suffix ".mat" is added when needed. Binary Matrix File Format. Ascii Matrix File Format.



3.9.7.0.3. (map-matrix [mat] filename)
[DX]


This function is available on certain systems only. It loads a binary matrix file by mapping the file to certain memory addresses using the virtual memory facilities provided by the operating system. This function is especially handy for handling very large matrices. Mapped matrices however are always read-only.



3.9.7.1. Native Matrix File Formats


This section describes the "classic" or "native" file formats used for Lush matrices. The IDX format (used by compilable matrix I/O functions) is not described here.



3.9.7.1.0. Ascii Matrix File Format


ASCII matrix files are generated with function save-ascii-matrix . These machine independent files are handy for transferring data between different computers. They tend however to eat a lot of disk space.

The first line of the file is a matrix header. It is composed of the letters ``.MAT'', the number of dimensions and the size of each dimension. The array elements are written then, separated by spaces and newlines characters.

The following lines display the content of a valid ascii matrix file.

        .MAT 2 3 4
         1 -1  1  2  -1  1 -3
         1 -1
         4  0  0
The same matrix could have been written in the following, more natural way.
        .MAT 2 3 4
         1 -1  1
         2 -1  1
        -3  1 -1
         4  0  0



3.9.7.1.1. Binary Matrix File Format


Binary matrix files are generated with function save-matrix . Binary matrix files begin with a header which describes the type and the size of the matrix. Then comes a binary image of the matrix.

The core header is a C structure defined as follows :

struct header {
        int magic;
        int ndim;
        int dim[3];
};
It can be followed by further int when the matrix has more than 3 dimensions.

The first member, magic , of this structure is a ``magic'' number, which encodes the type of the matrix. This number must be:

The second member of this structure, ndim , is the number of dimensions of the matrix. Then come the dimensions themselves in the array dim . If there are more than three dimensions, the array dim is extended to accomodate the extra dimensions.

When the number of dimensions (specified in ndim ) is greater than 3, the header is completed by ndim - 3 further integers.

This header is followed by a binary image of the matrix. Elements are stored with the last index changing faster, i.e.

(0,0,0) (0,0,1) (0,0,2) ...  (0,1,0) (0,1,2) etc...

In this latter case, each byte represents a fixed point number between -8 and +8 (+8 not included), the first 4 bits (most significant nybble) contain the integral part and the remaining 4 bits contain the fractional part. It uses a two's complement format. Here are two C functions which convert a ``compacted fixed point'' number into a floating point number and back.

/* Converts a packed number to a float */
float unpack(b)
int b;
{
    if (b & 0x80)
        b |= ~0x7f;
    else
        b &= 0x7f;
    return (float)b / 16.0;
}

/* Converts a float into a single byte packed number */
unsigned char pack(x)
float x;
{
    if (x > 8.0-1.0/16.0)
        return 0x7f;
    else if (x < -8.0)
        return 0x80;
    else
        return x*16;
}



3.9.7.2. Foreign Matrix Files


The following functions are for reading and writing information stored in files created by other programs than Lush. These functions make it easy to read binary or text files into a Lush matrix.



3.9.7.2.0. Foreign Binary Matrices




3.9.7.2.0.0. (import-raw-matrix mat file [offset])
[DX]


This function just reads the contents of file file into matrix mat . Accessing the matrix then access this data as single precision numbers (float), double precision numbers (double), integers (int), short integers (short), bytes (unsigned char) or packed numbers according to the type of matrix mat .

Argument mat must be a matrix freshly created with functions matrix , dmatrix , imatrix , smatrix , bmatrix or pmatrix . Submatrices are usually rejected. Argument file might be a file name or a file descriptor created with open-read . When argument offset is specified, a header of offset bytes is skipped.

After executing this function, the file descriptor file points to the first byte following the matrix data.



3.9.7.2.0.1. (export-raw-matrix mat file)
[DX]


Stores the data of the matrix mat into the binary file file . Argument file may be a filename string or a file descriptor created with open-write or open-append . No header is written.



3.9.7.2.1. Foreign Ascii Matrices




3.9.7.2.1.0. (import-text-matrix mat file)
[DX]


This function reads numbers in the text file file and stores them in matrix mat . Argument mat must be a freshly created matrix (submatrices are not accepted). Argument file might be or a file descriptor created with open-read .

After executing this function, the file descriptor file points to the first non blank character following the matrix data.



3.9.7.2.1.1. (export-text-matrix mat file)
[DX]


Stores the data of the matrix mat into the text file file . Argument file may be a filename string or a file descriptor created with open-write or open-append . No header is stored.



3.9.8. Component-wise Unary Operations


All of these functions apply a unary function to each element and either write the result in the elements of the second argument if it is present, or return a new tensor with the result if the second argument is not present (except for idx-clear). The two argument must have the same dimensions. If their numerical types are different, appropriate conversions are performed.



3.9.8.0. (idx-clear src)
[DX]


Set elements of src to 0.



3.9.8.1. (idx-minus src [dst])
[DX]


negate all elements of src .



3.9.8.2. (idx-abs src [dst])
[DX]


absolute value of elements of src .



3.9.8.3. (idx-sqrt src [dst])
[DX]


square root of elements of src .



3.9.8.4. (idx-inv src [dst])
[DX]


inverse of elements of src .



3.9.8.5. (idx-sin src [dst])
[DX]


apply sine to elements of src .



3.9.8.6. (idx-cos src [dst])
[DX]


apply cosine to elements of src .



3.9.8.7. (idx-atan src [dst])
[DX]


apply arctangent to elements of src .



3.9.8.8. (idx-log src [dst])
[DX]


apply log to elements of src .



3.9.8.9. (idx-exp src [dst])
[DX]


apply exp to elements of src .



3.9.8.10. (idx-qtanh src [dst])
[DX]


apply rational approximation to hyperbolic tangent to elements of src .



3.9.8.11. (idx-qdtanh src [dst])
[DX]


apply derivative of the rational approximation to hyperbolic tangent to elements of src .



3.9.8.12. (idx-stdsigmoid src [dst])
[DX]


apply the "standard" neural-net sigmoid function to elements of src .



3.9.8.13. (idx-dstdsigmoid src [dst])
[DX]


apply derivative of the "standard" neural-net sigmoid function to elements of src .



3.9.8.14. (idx-expmx src [dst])
[DX]


apply a rational approximation of (exp -x) to elements of src .



3.9.8.15. (idx-dexpmx src [dst])
[DX]


apply derivative of expmx to elements of src .



3.9.9. Component-wise Dyadic Operations


All of these functions apply a dyadic function to each pair of corresponding elements in the first two arguments. They either write the result in the elements of the third argument if it is present, or return a new tensor with the result if the third argument is not present All the arguments must have the same dimensions. If their numerical types are different, appropriate conversions are performed.



3.9.9.0. (idx-add m1 m2 [r])
[DX]


component-wise addition of m1 and m2 . Result in r if present, or returned if not present.



3.9.9.1. (idx-sub m1 m2 [r])
[DX]


component-wise subtraction of m1 and m2 . Result in r if present, or returned if not present.



3.9.9.2. (idx-mul m1 m2 [r])
[DX]


component-wise multiplication of m1 and m2 . Result in r if present, or returned if not present.



3.9.9.3. (idx-div m1 m2 [r])
[DX]


component-wise division of m1 and m2 . Result in r if present, or returned if not present.



3.9.10. Contracting Operations with Scalar Result


The following functions include dot products, distances, sums of terms, min, max, etc and return scalars. These operations "contract" all the dimensions. The dyadic ones can be seen as generalized dot product of two tensors (e.g. the sum of all the products of corresponding terms in the two tensors). These function have a base form and an accumulating form (which accumulates the result in idx0 past as last argument). If the last (and optional) idx0 argument is present, the result is written in it. If it is not present, a number (not an idx0) is returned.



3.9.10.0. (idx-sum m [r])
[DX]


sum of all terms of m .



3.9.10.1. (idx-sup m [r])
[DX]


max of all terms of m .



3.9.10.2. (idx-inf m [r])
[DX]


min of all terms of m .



3.9.10.3. (idx-sumsqr m [r])
[DX]


sum of squares of all terms of m .



3.9.10.4. (idx-dot m1 m2 [r])
[DX]


generalized dot product of m1 and m2 , i.e. the sum of all products of corresponding terms in m1 and m2 .



3.9.10.5. (idx-sqrdist m1 m2 [r])
[DX]


generalized Uclidean distance between m1 and m2 , i.e. the sum of squares of all the differences between corresponding terms of m1 and m2 .



3.9.10.6. (idx-sumacc m r)
[DX]


sum of terms of m . Result accumulated in idx0 r .



3.9.10.7. (idx-supacc m r)
[DX]


max of terms of m . Result accumulated in idx0 r .



3.9.10.8. (idx-infacc m r)
[DX]


min of terms of m . Result accumulated in idx0 r .



3.9.10.9. (idx-sumsqracc m r)
[DX]


sum square of terms of m . Result accumulated in idx0 r .



3.9.10.10. (idx-dotacc m1 m2 r)
[DX]


generalized dot product of m1 and m2 , i.e. the sum of all products of corresponding terms in m1 and m2 . Result accumulated in idx0 r .



3.9.10.11. (idx-sqrdistacc m1 m2 r)
[DX]


generalized Uclidean distance between m1 and m2 , i.e. the sum of squares of all the differences between corresponding terms of m1 and m2 . Result accumulated in idx0 r .



3.9.11. Operations between Tensors and Scalars




3.9.11.0. (idx-dotm0 m s [r])
[DX]


multiply all terms of m by scalar s (an idx0).



3.9.11.1. (idx-addm0 m s [r])
[DX]


add scalar s (an idx0) to all terms of m .



3.9.11.2. (idx-dotm0acc m s r)
[DX]


multiply all terms of m by scalar s (an idx0). Result accumulated in r .



3.9.11.3. (idx-addm0acc m s r)
[DX]


add scalar s (an idx0) to all terms of m . Result accumulated in r .



3.9.12. Matrix/Vector and 4-Tensor/Matrix Products




3.9.12.0. (idx-m2dotm1 m1 m2 [r])
[DX]


matrix-vector multiply.



3.9.12.1. (idx-m4dotm2 m1 m2 [r])
[DX]


4-tensor by 2-matrix multiplication: R_ij = sum_kl M1_ijkl * M2_kl



3.9.12.2. (idx-m2dotm1acc m1 m2 r)
[DX]


matrix-vector multiply. Result accumulated in r .



3.9.12.3. (idx-m4dotm2acc m1 m2 r)
[DX]


4-tensor by 2-matrix multiplication with accumulation: R_ij += sum_kl M1_ijkl M2_kl



3.9.13. Outer Products




3.9.13.0. (idx-m1extm1 m1 m2 [r])
[DX]


outer product between vectors: R_ij = M1_i * M_j



3.9.13.1. (idx-m2extm2 m1 m2 [r])
[DX]


outer product between matrices. Gives a 4-tensor: R_ijkl = M1_ij * M2_kl



3.9.13.2. (idx-m1extm1acc m1 m2 r]


outer product between vectors with accumulation: R_ij + = M1_i * M_j



3.9.13.3. (idx-m2extm2acc m1 m2 [r])
[DX]


outer product between matrices with accumulation. Gives a 4-tensor: R_ijkl += M1_ij * M2_kl



3.9.14. Backward Compatibility Functions


These functions are here for historical reasons.



3.9.14.0. (matrix [n0...np])
[DX]


same as (double-matrix [ n0 ... np ]): allocate a matrix of doubles.



3.9.14.1. (submatrix m '(low0 hi0) '(low1 hi1)...)
[DX]


This is superseded by narrow. Return a new index that points to a subset of the elements of m . The lists passed as arguments contain lower and upper index of the selected elements in each dimension.



3.9.14.2. (bound m)
[DX]


Return a list of upper bound for the index in each dimension.



3.9.14.3. (nrvectorp m)
[DX]


Obsolete function.



3.9.14.4. (nrmatrixp m)
[DX]


Obsolete function.



3.9.14.5. (dot-product a b)
[DM]


return the dot product of a and b



3.9.14.6. (m*m a b [c])
[DE]


obsolete and non-compilable matrix product function.



3.9.14.7. (m+m a b [c])
[DE]


obsolete and non-compilable matrix addition function.



3.9.14.8. (mxm a b [c])
[DE]


obsolete and non-compilable component-wise matrix multiply function.



3.9.14.9. (m-m a b [c])
[DE]


obsolete and non-compilable matrix subtraction function.



3.9.14.10. (m*c a b [c])
[DE]


obsolete and non-compilable multiplication of a matrix by a scalar.



3.9.14.11. (m+c a b [c])
[DE]


obsolete and non-compilable addition of a scalar to the elements of a matrix.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;