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:
- double-matrix,
double-matrix-nc, real-matrix, real-matrix-nc : doubles
- float-matrix, float-matrix-nc, flt-matrix,
flt-matrix-nc : floats
- int-matrix, int-matrix-nc :
32-bit ints
- short-matrix, short-matrix-nc :
16-bit shorts
- byte-matrix, byte-matrix-nc :
8-bit bytes
- ubyte-matrix, ubyte-matrix-nc :
8-bit unsigned bytes
- gptr-matrix, gptr-matrix-nc :
generic pointers (void*)
Tables of lisp objects (atoms) are created with the
array function.
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.
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" #])
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.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.
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.
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.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:
- 0x1E3D4C51
for a single precision matrix
- 0x1E3D4C53 for a double precision
matrix
- 0x1E3D4C54 for an integer matrix
- 0x1E3D4C56 for a short matrix
- 0x1E3D4C55 for a byte matrix
- 0x1E3D4C52 for a packed matrix
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...
- as float numbers for single precision matrix
- as double numbers for double precision matrix
- as int numbers for integer matrix
- as short numbers for short matrix
- as unsigned char numbers for byte matrix
- and as char for packed matrix.
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.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.
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.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;