-
Notifications
You must be signed in to change notification settings - Fork 12
02 Matrix
This documentation is structured as follows:
- Introduction
-
Matrix basic methods like
dim()
,get()
,rewrap()
,select()
, ... -
Data initialization methods like
fill()
,zeros()
,linspace()
, ... -
Serialization as
toString()
,toFilename()
, ... -
Low level access as
size()
,stride()
,offset()
,data()
, ... - Sliding window
- Math operations using stndard operators.
-
BLAS API as
axpy()
,gemv()
,gemm()
, ... -
LAPACK API as
svd()
,inv()
, ... -
Component-wise operations as
tan()
,tanh()
, ... -
Matrix level operations as
min()
,sum()
,eq()
, ... -
Indexing and sorting as
index()
,indexed_fill()
,order()
, ... -
Matrix functions as
repmat()
,triu()
, ... -
Matrix extensions as
real_fftwh()
,iterate()
,convolution()
. - Sparse matrix
- Other matrix flavours
- Matrix dictionaries
Package matrix
could be loaded via the standalone binary, or in Lua with
require("aprilann.matrix")
.
A matrix is a multidimensional data container, by default float data. It is similar to the concept of tensor, as defined in libraries like Torch. This notion of tensor is not to be confused with tensors in physics and engineering, known as tensor fields.
The data would be stored following row_major
order by default, but different
methods can change the stride of the dimensions. Additionally a matrix
can
be transposed or not, being the transposition a symbolical state, sharing
the same data reference as the non-transposed matrix
.
From Lua, a matrix is declared using one of the available constructors:
> -- row major constructor
> m1 = matrix(3,3) -- this is a uninitialitzed 3x3 matrix of floats
> -- It is also possible to receive a table with data (in row-major order)
> m2 = matrix(3,3, {1, 2, 3, 4, 5, 6, 7, 8, 9})
> print(m2)
1 2 3
4 5 6
7 8 9
# Matrix of size [3,3] in row_major [0x23d5b20 data= 0x23d5e90]
Observe that print
function shows the same for m2
and m3
, but internally
the data is in different order. The pretty print of a matrix shows the data and
a commented line with the size of the matrix and two memory pointers values, the
first is the pointer to the C++ object related with the given matrix, and the
second is a pointer to the C++ data object where values are stored (memory
block, explained below).
The matrix and its data is separated to allow the declaration of sub-matrices:
> m4 = m2:slice({2,1},{1,3})
> print(m4)
4 5 6
# Matrix of size [1,3] in row_major [0x2218a90 data= 0x23d5e90]
In this case, the matrix m4
is a slice which begins at position {2,1}
of
matrix m2
, and has sizes {1,3}
in each dimension. Note that the matrix
pointer is different, but the data pointer is the same as for m2
(any change
to m4
will be reflected at m2
.)
Besides, it is possible to do a sub-matrix cloning the data (deep copy) if you
add to slice
method a new boolean argument with true
value:
> m5 = m2:slice({2,1},{1,3}, true)
> print(m5)
4 5 6
# Matrix of size [1,3] in row_major [0x220c6f0 data= 0x2250d60]
A shortcut for slicing is to use the operator m[...]
, which has a meaning
similar to Matlab or Octave. It is overloaded and it is parsed into a slice
or
select
method call, so, it is slower than using directly the slice
or
select
methods, but it is easier to understand and use. This operator receives
as argument a number or a table.
-
m[n]
In case of given a number, the operator is equivalent to am:select(1,n)
in case the matrix has more than one dimension, and returns amatrix
object with one less dimension. In case of uni-dimensional matrix, this call is equivalent tom:get(n)
and returns a Lua number value. -
m[{s1,s2,...}]
In case of given a table, the should be the same length of the matrix number of dimensions. In every dimension position, three possible values could be given:- A number, indicating an exact dimension position:
m = m2[{2,3}]
- A table, with start and end positions in the dimension:
m = m2[{2, {1,3}}]
- A string, with start and end positions in the dimension:
m = m2[{2, '1:3'}]
- A number, indicating an exact dimension position:
The following examples are equivalent:
> = m2:slice({2,1},{1,3})
4 5 6
# Matrix of size [1,3] in row_major [0xf44470 data= 0xdeae90]
> = m2[{2, {1,3}]}
4 5 6
# Matrix of size [1,3] in row_major [0xf3c8d0 data= 0xdeae90]
> = m2[{2, '1:3'}]
4 5 6
# Matrix of size [1,3] in row_major [0xe32dc0 data= 0xdeae90]
It is possible to use the string shortcut to indicate a whole dimension, or only start/end positions:
> = m2[{':', '2:3'}]
2 3
5 6
8 9
# Matrix of size [3,2] in row_major [0xef1260 data= 0xdeae90]
> = m2[{'2:', '2:3'}]
5 6
8 9
# Matrix of size [2,2] in row_major [0xe08f50 data= 0xdeae90]
> = m2[{':2', '2:3'}]
2 3
5 6
# Matrix of size [2,2] in row_major [0xf04290 data= 0xdeae90]
A different shortcut exists for assignation operator, using newindex
metamethod. The matrix will be indexed using []
operator or [{}]
operator:
> -- assigns a 0 to all the row values at columns 2:3
> m2[{ ':', '2:3' }] = 0
> -- assigns another matrix all the row values at columns 2:3
> m2[{ ':', '2:3' }] = matrix(m2:dim(1),2):linspace()
> -- assigns 5 to all the values at position 2 in dimension 1
> m2[2] = 5
> -- assigns 10 to all values less than 3
> m2[m2:lt(3)] = 10
Every matrix
has an underlying block of memory which is reinterpreted with the
matrix
shape (dimension sizes, and offset). It is possible to build a memory
block in Lua by using any of the mathcore.block
table constructors.
Currently, mathcore.block.float
, mathcore.block.double
and
mathcore.block.int32
are available.
> b = mathcore.block.float{1,2,3,4,5} -- initialized to a table
> print(b)
1 2 3 4 ... 5
# Float block size 5 [data= 0x1ab98e0]
> b = mathcore.block.float(20) -- not initialized
Every memory block has three basic methods:
-
n = b:size()
returns the number of elements in the memory block. -
v = b:raw_get(p)
returns the value at the givenp
position. Note that the position is 0-indexed as in C, because this is a low-level C++ method. -
b:raw_set(p, v)
setsv
as the value at the givenp
position. Note that the position is 0-indexed as in C.
Like in matrix
objects, it is possible to use operator[]
:
-
v = b[p]
is equivalent tov = b:raw_get(p)
. -
b[p] = v
is equivalent tob:raw_set(p, v)
.
Remember that memory blocks are indexed from 0, like in C, because they are a wrapper around a C pointer.
NOTICE: Almost all matrix methods returns the caller matrix (when it is possible), allowing to chain transformation sequences.
NOTICE: In Lua the arrays start at 1 instead of 0, so, in the matrix
methods the dimensions start at 1.
There are different valid matrix
constructors.
-
m = matrix(d1, d2, ..., dn)
a list of dimension sizes. -
m = matrix(d1, d2, ..., dn, table)
a list of dimension sizes besides an array table with all thematrix
elements in row-major order. -
m = matrix(d1, d2, ..., dn, block)
a list of dimension sizes plus a float memory block (mathcore.block.float
). -
m = matrix{ e1, e2, ..., en }
creates a one-dimensionalmatrix
with the given data elements. -
m = matrix(block)
creates a one-dimensionalmatrix
with the given float memory block as data.
m = matrix.MMapped(...)
It is possible to force the declaration of matrix
memory as a mmapped
anonymous file. This function receives exactly same arguments as the
default matrix
constructor.
> -- the following matrix will be allocated as mmapped memory
> -- shared when forking the process
> m = matrix.MMapped(2,2):linear()
> print(m)
0 1
2 3
# Matrix of size [2,2] stride [2,1] ref [0x14c1f50 data= 0x14c2020]
Another way is to serialize a matrix in MMap format (see serialization section).
[table | number] = m:dim([number])
It returns the size of matrix dimensions. Without arguments, it returns a Lua table with the sizes. If an argument is given, it returns the size of the given dimension.
> a = matrix(4,3,2)
> = a:dim()
table: 0x23a4780
> = table.concat(a:dim(), " ")
4 3 2
> = a:dim(1), a:dim(2), a:dim(3)
4 3 2
number = m:get(p1, p2, ...)
This method returns the value of a given matrix position.
> a = matrix(3,4,{1,2,3,4, 5,6,7,8, 10,11,12,13})
> = a:get(1,1)
1
> = a:get(2,3)
7
matrix = m:set(p1, p2, ..., value)
This method sets the value of a matrix position, and returns the caller matrix, allowing a sequence of sets.
> a = matrix(3,4,{1,2,3,4, 5,6,7,8, 10,11,12,13})
> a:set(2,3, 10000)
> a:set(2,4, 500):set(4,1, 200)
> = a
1 2 3 4
5 6 10000 500
200 11 12 13
# Matrix of size [3,4] in row_major [0x27093d0 data= 0x2709960]
matrix = m:clone()
It allows to clone matrices (deep copy). If the caller matrix
was transposed,
the resulting clone will contain the data in a transposed shape, but with its
stride in row major order.
> a = matrix(2,3,{1,2,3, 4,5,6}) -- row major matrix
> b = a:clone() -- clone (or deep copy) of a
> c = a:transpose() -- clone of a with different order
> c = c:clone() -- clone of a in row major order
matrix = m:copy_from_table(table)
This method copies the data in the given table into the caller matrix
,
traversing the matrix
in row_major
order, as in matrix
constructor. The
table must fit in matrix
size. The caller matrix
is returned.
> a = matrix(2,3)
> a:copy_from_table({1,2,3, 4,5,6})
matrix = m:map(m1, m2, ..., function)
Maps the matrix values by a given list of matrices and a Lua map function. The
Lua function will be called for every possible matrix position. The Lua function
receives the caller matrix value at the given position, the value of the second
matrix, the value of the third matrix, and so on. The Lua function returns
nil
, or only one value which will be assigned to the caller matrix
in-place. All the matrices must have the same dimension sizes. The number of
given matrices could be >= 0.
> m = matrix(2,2):linear()
> m2 = matrix(2,2):linear(10)
> m3 = matrix(2,2):linear(100)
> = m
0 1
2 3
# Matrix of size [2,2] in row_major [0x1f12050 data= 0x1f0f6a0]
> = m2
10 11
12 13
# Matrix of size [2,2] in row_major [0x1f11cc0 data= 0x1f12110]
> = m3
100 101
102 103
# Matrix of size [2,2] in row_major [0x1f12740 data= 0x1f11e00]
> m:map(m2,m3,function(x,y,z) return x+y+z end)
> = m
110 113
116 119
# Matrix of size [2,2] in row_major [0x1f12050 data= 0x1f0f6a0]
matrix = m:rewrap(size1, size2, ...)
This method only works if the data is contiguous in memory. The caller matrix is reinterpreted as if it was of another number of dimensions and sizes. A different matrix instance is returned, but the data pointer is shared.
> a = matrix(2,3,{1,2,3, 4,5,6})
> = a
1 2 3
4 5 6
# Matrix of size [2,3] in row_major [0x2700850 data= 0x2700900]
> b = a:rewrap(3,2)
> = b
1 2
3 4
5 6
# Matrix of size [3,2] in row_major [0x2701360 data= 0x2700900]
matrix = m:select(dimension, index [, matrix])
This methods returns a matrix with one less dimension, resulting of select at
the caller matrix the indicated dimension at the given index. The resulting
matrix references the internal data of original matrix. If given, the third
argument must be a matrix
which will be used to store the result of the
select
call, and must fit the expected dimensions. In this last case, the
computation effort is dismissed to constant.
> m = matrix(4,3):zeros()
> = m
0 0 0
0 0 0
0 0 0
0 0 0
# Matrix of size [4,3] [0x23dcab0 data= 0x23727e0]
> = m:select(2,2):fill(9)
9 9 9 9
# Matrix of size [4] [0x23dd330 data= 0x23727e0]
> = m:select(1,3):fill(4)
4 4 4
# Matrix of size [3] [0x23dd790 data= 0x23727e0]
> = m
0 9 0
0 9 0
4 4 4
0 9 0
# Matrix of size [4,3] [0x23dcab0 data= 0x23727e0]
NOTE that the third argument matrix must be created by a previous call to
select
over the same dimension (but not the same index). As example, the
following design pattern gives the same variable as third argument result and as
left-side of the expression, allocating the memory in the first loop iteration,
and reusing it in the following:
> m = matrix(4,5):linear()
> for i=1,m:dim(2) do
result = m:select(2,i,result)
end
matrix = m:transpose()
This method returns a matrix
which is a transposition of the caller object.
Note that both, the caller and the transposition, reference the same data.
> m = matrix(3,4):linear()
> = m
0 1 2 3
4 5 6 7
8 9 10 11
# Matrix of size [3,4] in row_major [0x2777140 data= 0x27799b0]
> = m:transpose()
0 4 8
1 5 9
2 6 10
3 7 11
# Matrix of size [4,3] in row_major [0x274e620 data= 0x27799b0]
matrix = m:slice(position, size [, clone])
This methods produces a sub-matrix of the caller matrix. By default, the returned sub-matrix shares the data pointer with the caller, but it is also possible to do a deep copy sub-matrix. The syntax is:
m:slice(pos_table, size_table, clone=false)
being pos_table
a Lua table with the position of first element (starting at 1,
not 0), and size_table
a Lua table with the size of each dimension. The last
argument, clone
, is an optional boolean (by default false
) indicating if the
resulting matrix will be a clone or not.
> a = matrix(3,4,{1,2,3,4, 5,6,7,8, 10,11,12,13}) -- row major matrix
> = a
1 2 3 4
5 6 7 8
10 11 12 13
# Matrix of size [3,4] in row_major [0x2706530 data= 0x2706b00]
> b = a:slice({2,1},{2,2}) -- slice at position (2,1) with size 2x2
> = b
5 6
10 11
# Matrix of size [2,2] in row_major [0x2707cd0 data= 0x2706b00]
> -- same slice as before but making a clone (deep copy)
> b = a:slice({2,1},{2,2}, true)
> = b
5 6
10 11
# Matrix of size [2,2] in row_major [0x2708a20 data= 0x2708ad0]
matrix = m[number]
A shortcut for select or get methods. The operator is equivalent to a
m:select(1,n)
in case the matrix has more than one dimension, and returns a
matrix
object with one less dimension. In case of uni-dimensional matrix, this
call is equivalent to m:get(n)
and returns a Lua number value.
This operator can be used in left and/or right hand of an assignment. In the right hand:
-
m[key] = number
is equivalent tom[key]:fill( number )
in case the right-hand is a number. -
m[key] = matrix
is equivalent tom[key]:copy( matrix )
in case the right-hand is amatrix
.
matrix = m[{s1, s2, ...}]
A shortcut for slicing, using the __index
metamethod. It is similar to Matlab
or Octave slice operators. The call is parsed and converted into a slice
method call, so, it is slower than using directly the slice
method, but it
is easier to understand. This operator receives a variable number of arguments,
as many as dimensions has the caller matrix
object. In every dimension
position, three possible values could be given:
-
A number, indicating an exact dimension position:
m = m2[{2,3}]
-
A table, with start and end positions in the dimension:
m = m2[{2, {1,3}}]
-
A string, with start and end positions in the dimension:
m = m2[{2, '1:3'}]
The following examples are equivalent:
> = m2:slice({2,1},{1,3})
4 5 6
# Matrix of size [1,3] in row_major [0xf44470 data= 0xdeae90]
> = m2[{2, {1,3}}]
4 5 6
# Matrix of size [1,3] in row_major [0xf3c8d0 data= 0xdeae90]
> = m2[{2, '1:3'}]
4 5 6
# Matrix of size [1,3] in row_major [0xe32dc0 data= 0xdeae90]
It is possible to use the string shortcut to indicate a whole dimension, or only start/end positions:
> = m2[{':', '2:3'}]
2 3
5 6
8 9
# Matrix of size [3,2] in row_major [0xef1260 data= 0xdeae90]
> = m2[{'2:', '2:3'}]
5 6
8 9
# Matrix of size [2,2] in row_major [0xe08f50 data= 0xdeae90]
> = m2[{':2', '2:3'}]
2 3
5 6
# Matrix of size [2,2] in row_major [0xf04290 data= 0xdeae90]
m[key] = value
Different cases depending in the type of key
and the type of value
.
- key=number, value=number: it is equivalent to
m:select(1,key):fill(value)
- key=number, value=matrix: it is equivalent to
m:select(1,key):copy(value)
- key=table, value=number: it is equivalent to
m[key]:fill(value)
- key=table, value=matrix: it is equivalent to
m[key]:copy(value)
- key=matrixBool, value=number: it is equivalent to
m:masked_fill(key, value)
- key=matrixBool, value=matrix: it is equivalent to
m:masked_copy(key, value)
> -- assigns a 0 to all the row values at columns 2:3
> m2[{ ':', '2:3' }] = 0
> -- assigns another matrix all the row values at columns 2:3
> m2[{ ':', '2:3' }] = matrix(m2:dim(1),2):linspace()
matrix = matrix.join(dimension, m1, m2, ...)
This function joins the given matrices by the given dimension. All the
dimensions of the matrices must be the same, except the given dimension, which
could differ. It is possible to add a new axis at left and join all matrices
using the new added axis given a dimension=0
parameter. Similarly, it is possible
to add a new axis at right for joining all matrices using this new axis given a
dimension=num_dims+1
, being num_dim the number of dimensions of the given
matrices.
Warning, this method duplicates the memory needed, because all the matrices are copied to the destination matrix.
> m1 = matrix(10,2):linear()
> m2 = matrix(10,3):linear()
> outm = matrix.join(2, m1, m2)
> = outm
0 1 0 1 2
2 3 3 4 5
4 5 6 7 8
6 7 9 10 11
8 9 12 13 14
10 11 15 16 17
12 13 18 19 20
14 15 21 22 23
16 17 24 25 26
18 19 27 28 29
# Matrix of size [10,5] in row_major [0x1f9c100 data= 0x1f9c1c0]
>
> m1 = matrix(10,3):linear()
> -- m2 remains the same
> -- add new axis at left
> = matrix.join(0, m1, m2)
# pos [1,1,1]
0 1 2
3 4 5
6 7 8
9 10 11
12 13 14
...
27 28 29
# pos [2,1,1]
0 1 2
3 4 5
6 7 8
9 10 11
12 13 14
...
27 28 29
# Matrix of size [2,10,3] stride [30,3,1] ref [0x1940f90 data= 0x177c280]
>
> -- add new axis at right
> = matrix.join(3, m1, m2)
# pos [1,1,1]
0 0
1 1
2 2
# pos [2,1,1]
3 3
4 4
5 5
...
# pos [10,1,1]
27 27
28 28
29 29
# Matrix of size [10,3,2] stride [6,2,1] ref [0x1b42ef0 data= 0x1b42fe0]
matrix = m:clamp(lower, upper)
This method clamps the matrix components to a given range [min,max], modifying the matrix in-place. The caller matrix instance is returned.
> a = matrix(3,3,{1,2,3,4,5,6,7,8,9})
> = a
1 2 3
4 5 6
7 8 9
# Matrix of size [3,3] in row_major [0xe56a30 data= 0xe56f40]
> a:clamp(3,6)
> = a
3 3 3
4 5 6
6 6 6
# Matrix of size [3,3] in row_major [0xe56a30 data= 0xe56f40]
matrix = m:adjust_range(min, max)
This method modifies in-place the matrix components, interpolating the values to be in the given range [min,max]. The caller matrix is returned.
> a = matrix(3,3,{1,2,3,4,5,6,7,8,9})
> a:adjust_range(3,6)
> = a
3 3.375 3.75
4.125 4.5 4.875
5.25 5.625 6
# Matrix of size [3,3] in row_major [0x25cca30 data= 0x25ccf40]
> = a:adjust_range(0,1)
0 0.125 0.25
0.375 0.5 0.625
0.75 0.875 1
# Matrix of size [3,3] in row_major [0x25cca30 data= 0x25ccf40]
> = a:adjust_range(1,9)
1 2 3
4 5 6
7 8 9
# Matrix of size [3,3] in row_major [0x25cca30 data= 0x25ccf40]
boolean = m:is_contiguous()
Indicates if the matrix internal data is contiguous at memory (in row major order).
matrix = m:contiguous()
Returns a contiguous version of the caller matrix. If the matrix is contiguous, returns itself. Otherwise, returns a copy of the caller. Note that, if the matrix is a slice or a transposition of another matrix, therefore it could be non-contiguous.
matrix = m:fill(number)
This is an in-place method which sets all components to a given value.
> a = matrix(2,3):fill(4) -- a 2x3 matrix filled with 4
> = a
4 4 4
4 4 4
# Matrix of size [2,3] in row_major [0x26ff9b0 data= 0x26ffa20]
matrix = m:zeros()
This is equivalent to m:fill(0)
matrix = m:ones()
This is equivalent to m:fill(1)
matrix = m:linear(start=0, step=1)
Initializes the matrix starting at the given index and using the given step. The index and the step is optional.
> m = matrix(3,2,2):linear(1,2)
> = m
# pos [1,1,1]
1 3
5 7
# pos [2,1,1]
9 11
13 15
# pos [3,1,1]
17 19
21 23
# Matrix of size [3,2,2] in row_major [0x149de00 data= 0x149daa0]
> m = matrix(2,2):linear()
> = m
0 1
2 3
# Matrix of size [2,2] in row_major [0x149f110 data= 0x149f1e0]
matrix = m:linspace(a=1, b=m:size())
Initializes the matrix
with a linear space distribution. It receives
two optional arguments, why default a=1
and b=m:size()
. It returns
the caller matrix
.
> m = matrix(5):linspace(1,20)
> = m
1 5.75 10.5 15.25 20
# Matrix of size [5] in row_major [0x291f200 data= 0x291ecd0]
matrix = m:logspace(a=1, b=m:size(), base=10)
Initializes the matrix
with a logarithmic distribution between a
and b
with the given logarithm base
. It receives three optional arguments, why
default a=1
, b=m:size()
and base=10
. It returns the caller matrix
.
> m = matrix(5):logspace(0.001,0.1)
> = m
0.001 0.00316228 0.01 0.0316228 0.1
# Matrix of size [5] in row_major [0x291fed0 data= 0x291fd50]
matrix = m:uniform(lower, upper [, random] )
This method initializes the matrix with random integers taken uniformly from the given range of values:
> m = matrix(10):uniform(0,10,random(1234))
> = m
3 6 5 4 8 9 1 7 9 10
# Matrix of size [10] in row_major [0x2716b10 data= 0x2716490]
The random object is optional, but to ensure reproducibility it is recommended.
matrix = m:uniformf(lower=0, upper=1 [, random] )
This method initializes the matrix with random floats taken uniformly from the given range of values:
> m = matrix(2,2):uniformf(-10, 10, random(1234))
> = m
-6.16961 -0.0467267
2.44218 6.35677
# Matrix of size [2,2] in row_major [0x1000e90 data= 0xe47410]
The random object is optional, but to ensure reproducibility it is recommended.
matrix = m:diag(number)
This method sets the matrix diagonal components to a given value, modifying in-place the caller matrix. For any number of dimensions, the diagonal are whose components which positions are equals at all dimensions.
> a = matrix(3,3,3):ones():diag(5)
> = a
# pos [1,1,1]
5 1 1
1 1 1
1 1 1
# pos [2,1,1]
1 1 1
1 5 1
1 1 1
# pos [3,1,1]
1 1 1
1 1 1
1 1 5
# Matrix of size [3,3,3] in row_major [0x1718f10 data= 0x1718d50]
string = m:toString( mode='ascii' )
This method returns a Lua string which represents the caller matrix. It receives
an optional argument indicating if the matrix data will be stored in ascii
or
binary
format (by default ascii
).
> a = matrix(3,5):ones()
> = a
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
# Matrix of size [3,5] in row_major [0xd80a10 data= 0xd815d0]
> = a:toString()
3 5
ascii
1 1 1 1 1 1 1 1 1
1 1 1 1 1 1
> = a:toString("ascii")
3 5
ascii
1 1 1 1 1 1 1 1 1
1 1 1 1 1 1
> = a:toString("binary")
3 5
binary
8Ffe98Ffe98Ffe98Ffe98Ffe98Ffe98Ffe98Ffe98Ffe98Ffe98Ffe98Ffe98Ffe98Ffe98Ffe9
matrix = matrix.fromString(filename)
This method loads a matrix from a Lua string generated by method matrix.toString
.
> a = matrix.fromString[[3 5
>> ascii
>> 1 1 1 1 1 1 1 1 1
>> 1 1 1 1 1 1
>> ]]
> = a
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
# Matrix of size [3,5] in row_major [0xd983b0 data= 0xdfe5c0]
m:toFilename(filename, mode='ascii')
This method stores a matrix in a given filename. It also receives an optional
argument with ascii
or binary
(by default ascii
). It allows to compress the output file
using GZIP, if the filename has '.gz' extension.
> a = matrix(3,3)
> a:toFilename("a.mat", "binary")
> a:toFilename("a.mat.gz", "binary")
matrix = matrix.fromFilename(filename)
This method loads a matrix from a given filename, expecting the format used by
matrix.toFilename
method. It allows to load compressed files using GZIP, if
the filename has '.gz' extension.
> a = matrix.fromFilename("a.mat")
> a = matrix.fromFilename("a.mat.gz")
m:toTabFilename(filename)
This method stores a matrix in a given filename, but without header, and formatting the data to be formatted by lines and spaces, one matrix row per line. It is limited to bi-dimensional matrices. It allows to compress the output file using GZIP, if the filename has '.gz' extension.
> a = matrix(3,3)
> a:toTabFilename("a.mat")
> a:toTabFilename("a.mat.gz")
matrix = matrix.fromTabFilename(filename)
This method loads a matrix from a given filename, formatted as done by
matrix.toTabFilename
. The size of the matrix
is computed in a first loop
over all the data, so this method needs two passes to load the matrix. It
allows to load compressed files using GZIP, if the filename has '.gz'
extension.
> a = matrix.fromTabFilename("a.mat")
> a = matrix.fromTabFilename("a.mat.gz")
m:toMMap(filename)
Stores the matrix
in a file in a binary machine-dependent format, so it could be
loaded using mmap function (matrix.fromMMap
). The endianism must be the same
between machines where matrix is stored/loaded.
matrix = matrix.fromMMap(filename [,write [,shared]])
Loads the matrix
from a file in a binary machine-dependent format, by using
the mmap function (matrix.toMMap
). The endianism must be the same between
machines where matrix is stored/loaded. Two additional boolean arguments are
allowed. The second boolean argument indicates if writing is available,
by default it is true
. Be careful, if writing is set to false
, any attempt
of writing will throw a segmentation fault. The third boolean argument
indicates if the data is shared between different processes, by default it is
true
. If both arguments are true
, any writing will be available to any
process which shares this map. Besides, writings will be synchronized in the
hard disk (but not instantly). If writing is true
, but shared is false
,
then the memory is mapped as copy-on-write. For more info, see the manual
page of mmap function (PROTECT_WRITE, MAP_SHARED and MAP_PRIVATE).
table = m:toTable()
This method returns a plain Lua table (one-dimensional table) which contains the matrix
data in row_major
order, as expected by matrix
constructors.
> a = matrix(3,2,{1,2,3,4,5,6})
> = a
1 2
3 4
5 6
# Matrix of size [3,2] in row_major [0x9ddce0 data= 0x9ddd30]
> t = a:toTable()
> = table.concat(t, " ")
1 2 3 4 5 6
These methods allows raw accessing of matrix components.
number = m:size()
This method returns the number of elements in the matrix.
> a = matrix(3,4,{1,2,3,4, 5,6,7,8, 10,11,12,13})
> = a:size()
12
table = m:stride()
This method is similar to m:dim
, but returning the stride of the
dimension (the offset between elements at each dimension)
> a = matrix(4,3,2)
> = a:stride()
table: 0x23a5fe0
> = table.concat(a:stride(), " ")
6 2 1
> = a:stride(1), a:stride(2), a:stride(3)
6 2 1
> a = a:transpose()
> = a:stride(1), a:stride(2), a:stride(3)
1 4 12
number = m:offset()
It returns the offset from data first position. Only sub-matrices has an offset!=0.
> a = matrix(2,3)
> = a:offset()
0
> b = a:slice({2,1},{1,1})
> = b:offset()
3
block = m:data()
Returns a float memory block (mathcore.block.float
) with the underlying data
pointer.
number = m:raw_get(pos)
It receives a raw position at the underlying data pointer, and returns its
value. It is useful to combine stride
and offset
methods in order to
compute the raw position.
> a = matrix(3,2, {1,2,3,4,5,6})
> = a
1 2
3 4
5 6
# Matrix of size [3,2] in row_major [0x144fce0 data= 0x144fd90]
> = a:raw_get(a:offset() + a:stride(1)*1 + a:stride(2)*0), a:get(2,1)
3 3
NOTE! that the strides are multiplied by matrix position minus 1.
m:raw_set(pos, value)
It receives a raw position at the underlying data pointer and a number. The
given position is set to given number value. It is useful to combine stride
and offset
methods in order to compute the raw position.
> a = matrix(3,2, {1,2,3,4,5,6})
> = a
1 2
3 4
5 6
# Matrix of size [3,2] in row_major [0x144fce0 data= 0x144fd90]
> -- equivalent to a:set(2,1, 10)
> a:raw_set(a:offset() + a:stride(1)*1 + a:stride(2)*0, 10)
> = a
1 2
10 4
5 6
# Matrix of size [3,2] in row_major [0x144fce0 data= 0x144fd90]
NOTE! that the strides are multiplied by matrix position minus 1.
For fast and easy matrix traversal, a C++ sliding window object is binded to
Lua. It works similarly to dataset.matrix
, but circularity and out-of-matrix
default values are not supported. The object is constructed using the method
sliding_window
of matrix
, and could be iterated using its method
iterate()
:
> m = matrix(4,2,3):uniformf(-10,10,random(1234)) -- randomly initialized matrix
> for submat in m:sliding_window():iterate() do print(submat) end
# pos [1,1,1]
-6.16961 -0.0467267 2.44218
6.35677 -1.24545 2.24224
# Matrix of size [1,2,3] in row_major [0x253f160 data= 0x253dec0]
# pos [1,1,1]
5.70717 5.4272 5.59952
7.2134 -4.54815 -6.98726
# Matrix of size [1,2,3] in row_major [0x253fa40 data= 0x253dec0]
# pos [1,1,1]
-4.47071 -6.02962 6.03744
6.30326 9.16279 -6.82369
# Matrix of size [1,2,3] in row_major [0x2540230 data= 0x253dec0]
# pos [1,1,1]
7.51865 -7.67724 -2.84365
-9.74185 0.0199025 -0.263331
# Matrix of size [1,2,3] in row_major [0x25409c0 data= 0x253dec0]
It is possible to modify the default behavior giving this parameters to sliding_window
method:
-
offset
: a Lua table with offset applied to the window in each coordinate (starting at 0). -
size
: a Lua table with the window size for each coordinate. -
step
: a Lua table with the step size at each coordinate (each value must be >= 1). -
numSteps
: a Lua table with the number of steps in each coordinate (each value must be >= 1). -
orderStep
: a Lua table with the traversal order of coordinates (starting at 1).
> m = matrix(4,2,3):uniformf(-10,10,random(1234))
> for w in m:sliding_window{ step={2,1,1}, size={1,1,2} }:iterate() do print(w) end
# pos [1,1,1]
-6.16961 -0.0467267
# Matrix of size [1,1,2] in row_major [0x9fdb90 data= 0x9cf2d0]
# pos [1,1,1]
-4.47071 -6.02962
# Matrix of size [1,1,2] in row_major [0x9fe0f0 data= 0x9cf2d0]
Manual iteration of the sliding_window is also possible using the following methods:
-
matrix = sw:get_matrix([matrix])
: returns the matrix generated by the window at its current position. It is possible to pass an optional argument, a destinationmatrix
, so the computation effort is dismissed to constant. NOTE that this matrix must be created by a previous call toget_matrix
over the samesliding_window
. -
sw:next()
: moves the window to the next position. -
sw:is_end()
: returns true if the window has finished the matrix traversal.
> m = matrix(4,2,3):uniformf(-10,10,random(1234))
> wo = m:sliding_window{ step={2,1,1}, size={1,1,2} }
> while not wo:is_end() do m=wo:get_matrix(m) print(m) wo:next() end
This operations uses standard Lua math operators for friendly user interaction, but they work with BLAS API for best performance. However, all this operations return a new instantiated matrix, for best performance it is recommended to use directly the BLAS interface.
The operators binary +, -, *, /, and unary operators -, ^, are implemented as algebraic operations. The + and - operators only work when the matrices has the same sizes:
> a= matrix(3,3,3,{1,2,3,4,5,6,7,8,9,
10,11,12,13,14,15,16,17,18,
19,20,21,22,23,24,25,26,27})
> = a+a
# pos [1,1,1]
2 4 6
8 10 12
14 16 18
# pos [2,1,1]
20 22 24
26 28 30
32 34 36
# pos [3,1,1]
38 40 42
44 46 48
50 52 54
# Matrix of size [3,3,3] in row_major [0x1196d90 data= 0x1196e40]
> = a-a
# pos [1,1,1]
0 0 0
0 0 0
0 0 0
# pos [2,1,1]
0 0 0
0 0 0
0 0 0
# pos [3,1,1]
0 0 0
0 0 0
0 0 0
# Matrix of size [3,3,3] in row_major [0x1198d80 data= 0x1198a50]
The operator * only works with vectors or bi-dimensional matrices. If needed,
you can rewrap
the matrix data before the operation. Depending on the
dimension of the two matrices, the multiplication could be:
- A dot product between two vectors: when the two matrices are unidimensional vectors, the first one a vector and the second one a column vector:
> a, b = matrix(4,{1,2,3,4}), matrix(4,1,{5,6,7,8})
> = a*b
70
# Matrix of size [1] in row_major [0xfa9230 data= 0xfc2300]
- An outter product between two vectors: when the first matrix is a column vector, and the second matrix is a unidimensional matrix or a bi-dimensional matrix (row or column vector).
> a = matrix(4,{1,2,3,4})
> b = matrix(4,1,{5,6,7,8})
> = b*a
5 10 15 20
6 12 18 24
7 14 21 28
8 16 24 32
# Matrix of size [4,4] in row_major [0x1001940 data= 0x1176a80]
- A matrix-vector product when the first matrix is a bi-dimensional matrix and the second is a vector. The output has the same number of dimensions as the given vector.
> a = matrix(2,2,{1,2,3,4})
> b = matrix(2,{5,6})
> = a*b
17 39
# Matrix of size [2] in row_major [0x105baa0 data= 0xfe80f0]
> b = matrix(1,2,{5,6})
> = a*b
17
39
# Matrix of size [2,1] in row_major [0x107e3c0 data= 0x107fb30]
> b = matrix(2,1,{5,6})
> = a*b
17
39
# Matrix of size [2,1] in row_major [0x10c4700 data= 0x10c6890]
- A matrix-matrix product when the two matrices are bi-dimensional and not vectors.
> a=matrix(3,2,{1,2,3,4,5,6})
> b=matrix(2,4,{1,2,3,4,5,6,7,8})
> = a*b
11 14 17 20
23 30 37 44
35 46 57 68
# Matrix of size [3,4] in row_major [0x1114270 data= 0x11165d0]
A multiplication by a scalar is also possible, if you multiply one matrix by one number.
> a=matrix(3,2,{1,2,3,4,5,6})
> = a*5
5 10
15 20
25 30
# Matrix of size [3,2] in row_major [0x10f2160 data= 0x10d14e0]
The component-wise operator / is allowed for division between matrix and a scalar, or between a scalar and a matrix.
The operator ^ is also allowed only with scalars.
The unary operator - is equivalent to multiply by -1.
matrix = m:scalar_add(number)
Adds to all the components, in-place, the given scalar number. Returns the caller matrix object.
matrix = m:div(scalar)
Produces the computation between the component-wise inversion of the matrix
and the given scalar. This operation is done in-place.
> m = matrix(2,2,{1,2,3,4})
> m:div(1)
> = m
1 0.5
0.3333 0.25
# Matrix of size [3,2] in row_major [0x1cf2160 data= 0x10d15e0]
The most efficient way to do operations if using the BLAS interface directly. All the methods are prepared to adjust the BLAS operations to the given matrices, so you don't need to be worried about strides and sizes.
All of this methods are in-place, so they modify the caller object, and returns it to allow operation sequences.
matrix = m:axpy(alpha, X)
The AXPY operation computes addition of vectors:
Y = alpha * X + Y
The method receives two positional parameters: the alpha scalar and the matrix X. The X and Y matrix sizes must be equals, and the number of dimensions is not a problem. This method interprets all the data as a sequence, calling several times to AXPY BLAS function if necessary:
> a = matrix(4,{1,2,3,4})
> b = matrix(4,{5,6,7,8})
> a:axpy(2.0, b)
> = a
11 14 17 20
# Matrix of size [4] in row_major [0x107e3c0 data= 0x1110970]
> a = matrix(2,2,2,{1,2,3,4,5,6,7,8})
> b = matrix(2,2,2,{9,10,11,12,13,14,15,16})
> a:axpy(1.0, b)
> = a
# pos [1,1,1]
10 12
14 16
# pos [2,1,1]
18 20
22 24
# Matrix of size [2,2,2] in row_major [0xfb1f40 data= 0x1056f00]
matrix = m:gemv{ beta, alpha, Y, X, trans_A}
The GEMV operation computes matrix-vector multiplication:
Y = beta * Y + alpha * op(A) * X
being Y the caller matrix (a vector), A another matrix, and X a vector (unidimensional matrix, or bi-dimensional with one row (or one column)), and beta and alpha are scalars. The op(A) is transposition operation.
The method receives a table with:
-
A
field, the other matrix. -
X
field, the vector. -
alpha
field, the scalar -
beta
field, the other scalar. -
trans_A
field, a boolean which indicates if the A matrix will be transposed or not. It is optional, by default isfalse
.
> a = matrix(3,2,{1,2, 3,4, 5,6})
> b = matrix(2,{7,8})
> c = matrix(3)
> c:gemv{ A=a, X=b, alpha=2, beta=0 }
> = c
46 106 166
# Matrix of size [3] in row_major [0xfbeff0 data= 0xfaf640]
matrix = m:gemm{ beta, alpha, A, B, ... }
The GEMM operation computes matrix-matrix multiplication:
Y = beta * Y + alpha * op(A) * op(B)
being Y the caller matrix (a vector), A another matrix, and B a matrix, and beta and alpha are scalars. The op(A) and op(B) are transposition operations.
The method receives a table with:
-
A
field, the other matrix. -
B
field, the vector. -
alpha
field, the scalar -
beta
field, the other scalar. -
trans_A
field, a boolean which indicates if the A matrix will be transposed or not. It is optional, by default isfalse
. -
trans_B
field, a boolean which indicates if the B matrix will be transposed or not. It is optional, by default isfalse
.
> a = matrix(3,2,{1,2, 3,4, 5,6})
> b = matrix(4,2,{7,8, 9,10, 11,12, 13,14})
> c = matrix(3,4):ones()
> c:gemm{ A=a, B=b, alpha=1, beta=1, trans_B=true}
> = c
24 30 36 42
54 68 82 96
84 106 128 150
# Matrix of size [3,4] in row_major [0x1452a20 data= 0x144cbf0]
matrix = m:ger{ X, Y, alpha }
The GER operation computes outter product of vectors:
Z = Z + alpha * X * Y'
being Z the caller matrix (a squared matrix), X and Y two vectors, and beta and alpha are scalars. The Y vector is transposed.
> a = matrix(3,{1,2,3})
> b = matrix(3,{4,5,6})
> c = matrix(3,3):zeros()
> c:ger{ X=a, Y=b, alpha=2 }
> = c
8 10 12
16 20 24
24 30 36
# Matrix of size [3,3] in row_major [0x1f06b20 data= 0x1f18080]
number = m:dot(matrix)
The DOT operation computes the dot-product of two vectors, the caller matrix and a given matrix. It returns a number.
> a = matrix(3,{1,2,3})
> b = matrix(3,{4,5,6})
> = a:dot(b)
32
# Matrix of size [1] in row_major [0x1f4ffe0 data= 0x2076e20]
matrix = m:scal(number)
The SCAL operation computes the multiplication of a matrix by a scalar.
> a = matrix(3,{1,2,3})
> a:scal(4)
> = a
4 8 12
# Matrix of size [3] in row_major [0x1f3b230 data= 0x201e9a0]
matrix = m:copy(matrix)
The COPY operation copies the content of a given matrix in the caller matrix object.
> a = matrix(3,3,{1,2,3,4,5,6,7,8,9})
> b = matrix(3,3):fill(5)
> a:copy(b)
> = a
5 5 5
5 5 5
5 5 5
# Matrix of size [3,3] in row_major [0x1f7e870 data= 0x1f49ef0]
> a = matrix(3,3,{1,2,3,4,5,6,7,8,9})
> b = matrix(2,2,{1,2,3,4})
> c = a:slice({2,1},{2,2})
> c:copy(b)
> = a
1 2 3
1 2 6
3 4 9
# Matrix of size [3,3] in row_major [0x1fb64e0 data= 0x1fbd600]
U,S,VT = m:svd()
This method computes the Singular Values Decomposition of the caller matrix
.
It returns three matrices:
-
U
a matrix with the left singular vectors. -
S
a sparse diagonal matrix with singular values. -
VT
a matrix with the transposed right singular vectors.
matrix = m:inv()
Computes the inverse of the caller matrix. Check that your matrix is not singular, otherwise the returned matrix won't be correct.
matrix = m:pinv()
Computes the pseudo-inverse of the caller matrix, using the SVD method.
This operations are applied in-place and over all the components of the caller matrix. If it is possible, the caller matrix is returned.
matrix = m:tan()
Computes the TAN function of all the components.
matrix = m:tanh()
Computes in-place the TANH function of all the components.
matrix = m:atan()
Computes in-place the ATAN function of all the components.
matrix = m:atanh()
Computes in-place the ATANH function of all the components.
matrix = m:sin()
Computes in-place the SIN function of all the components.
matrix = m:sinh()
Computes in-place the SINH function of all the components.
matrix = m:asin()
Computes in-place the ASIN function of all the components.
matrix = m:asinh()
Computes in-place the ASINH function of all the components.
matrix = m:cos()
Computes in-place the COS function of all the components.
matrix = m:cosh()
Computes in-place the COSH function of all the components.
matrix = m:acos()
Computes in-place the ACOS function of all the components.
matrix = m:acosh()
Computes in-place the ACOSH function of all the components.
matrix = m:abs()
Computes in-place the ABS function of all the components.
matrix = m:complement()
Computes in-place the complement function of all the components: X = 1 - X
matrix = m:log()
Computes in-place the LOG function of all the components.
matrix = m:log1p()
Computes in-place the LOG1P function of all the components.
matrix = m:plogp()
Computes in-place the p*log(p) operation over all components. It is useful to compute entropy related measures.
matrix = m:exp()
Computes in-place the EXP function of all the components.
matrix = m:pow(number)
Computes in-place the POWER of all the components by a given scalar.
matrix = m:sqrt()
Computes the SQRT function of all the components.
matrix = m:cmul(matrix)
Computes in-place a component-wise multiplication between the caller and a given matrix.
This operations are applied taking into account all the data at the matrix.
min,argmin = m:min()
Returns the minimum and its position in the matrix.
> a = matrix(3,4,{1,2,3,4,5,6,7,12,9,10,11,8})
> = a:min()
1 1
matrix,matrixInt32 = m:min(dim [, matrix[, matrixInt32]] )
Applies the min operator over the elements of the given dimension, and returns a matrix with the same number
of dimensions, but with the size of dimension dim
equals 1. The second matrix argument is optional,
and if given, the returned matrix will be this second argument.
> a = matrix(3,4,{1,2,3,4,
>> 5,6,7,12,
>> 9,10,11,8})
> = a:min(1)
1 2 3 4
# Matrix of size [1,4] in row_major [0x1f06bb0 data= 0x1f06cb0]
> = a:min(2)
1
5
8
# Matrix of size [3,1] in row_major [0x1f07560 data= 0x1f06d90]
max,argmax = m:max()
Returns the maximum and its position in the matrix.
> a = matrix(3,4,{1,2,3,4,5,6,7,12,9,10,11,8})
> = a:max()
12 8
matrix,matrixInt32 = m:max(dim [, matrix[, matrixInt32] ] )
Applies the max operator over the elements of the given dimension, and returns a matrix with the same number
of dimensions, but with the size of dimension dim
equals 1. The second matrix argument is optional,
and if given, the returned matrix will be this second argument.
> a = matrix(3,4,{1,2,3,4,
>> 5,6,7,12,
>> 9,10,11,8})
> = a:max(1)
9 10 11 12
# Matrix of size [1,4] in row_major [0x1f05500 data= 0x1f05600]
> = a:max(2)
4
12
11
matrixBool = m:eq(number or matrix)
This method computes in-place a comparison between all the components with
the given value, and converts the component in true
or false
if it is less
than the given value or not. If the value is another matrix
, both matrices
will be compared component-by-component.
matrixBool = m:lt(number or matrix)
This method computes in-place a comparison between all the components
with the given value, and converts the component in true
or false
if it is
less than the given value or not. If the value is another matrix
,
both matrices will be compared component-by-component.
matrixBool = m:gt(number or matrix)
This method computes in-place a comparison between all the components
with the given value, and converts the component in true
or false
if it is
greater than the given value or not. If the value is another matrix
,
both matrices will be compared component-by-component.
number = m:sum( )
Computes the sum of all the components of the caller matrix, and returns its value.
matrix = m:sum( number [, matrix] )
Receives a number indicating the dimension where the sum must be run, and returns a matrix with each possible sum of the given dimension. The second matrix argument is optional, and if given, the returned matrix will be this argument.
> m = matrix(2,2,{1,2,3,4})
> = m:sum(1)
4 6
# Matrix of size [1,2] in row_major [0x19e0620 data= 0x19d2480]
> = m:sum(2)
3
7
# Matrix of size [2,1] in row_major [0x19e0a40 data= 0x19d3b90]
number = m:norm2()
The NORM2 operation computes the euclidean norm of the caller matrix. It returns a number.
> a = matrix(2,2,2,{1,2,3,4,5,6,7,8})
> = a:norm2()
14.282856941223
This operations allow to extract or sort matrices by indexing any of its dimensions.
matrix = m:index(dim, idx)
This method returns a new deep cloned matrix
but taking only the indexes of
dimension dim
indicated at idx
object. The idx
object can be three
different data types:
- A one-dimensional
matrixInt32
with all the indices you want to take. - A Lua
table
with the indices you want to keep. This table will be converted into amatrixInt32
instance. - A one-dimensional
matrixBool
weretrue
value in the indices you want to keep.
This method can be combined with eq
, lt
, gt
methods to select a bunch of
rows or columns depending in a simple condition. The following example uses
index
and lt
to select all the rows where its first column is less than
0.
> m = matrix(10,2):uniform(-10,10,random(1234))
> print(m)
5 9
-4 2
10 5
7 -1
1 2
...
-5 -8
# Matrix of size [10,2] stride [2,1] ref [0x204cce0 data= 0x1e3c310]
> m_neg_idx = m:select(2,1):lt(0)
> print(m_neg_idx)
F T F F F F F F F T
# MatrixBool of size [10] stride [1] ref [0x1f64820 data= 0x1e886a0]
> m_neg = m:index(1, m_neg_idx)
> print(m_neg)
-4 2
-5 -8
# Matrix of size [2,2] stride [2,1] ref [0x1d72450 data= 0x1f499a0]
m = m:indexed_fill(dim, idx, number)
This method fills with number
all the values at the given dimension dim
whose indices are in idx
object. The idx
object can be three
different data types:
- A one-dimensional
matrixInt32
with all the indices you want to take. - A Lua
table
with the indices you want to keep. This table will be converted into amatrixInt32
instance. - A one-dimensional
matrixBool
weretrue
value in the indices you want to keep.
The following example fills with 0 the values at column 1 which are negative.
> m = matrix(10,2):uniform(-10,10,random(1234))
> print(m)
5 9
-4 2
10 5
7 -1
1 2
...
-5 -8
# Matrix of size [10,2] stride [2,1] ref [0x204cce0 data= 0x1e3c310]
> m_neg = m:index(1, m:select(2,1):lt(0))
> m_neg_idx = m:select(2,1):lt(0)
> print(m_neg_idx)
F T F F F F F F F T
# MatrixBool of size [10] stride [1] ref [0x1f64820 data= 0x1e886a0]
> col1 = m(':',1)
> col1:indexed_fill(1, m_neg_idx, 0)
> print(m)
5 9
0 2
10 5
7 -1
1 2
...
0 -8
# Matrix of size [10,2] stride [2,1] ref [0x237cba0 data= 0x237cc70]
m = m:indexed_copy(dim, idx, matrix)
This method copies the values of matrix
at the indices of dimension dim
indicated by idx
object. The idx
object can be three
different data types:
- A one-dimensional
matrixInt32
with all the indices you want to take. - A Lua
table
with the indices you want to keep. This table will be converted into amatrixInt32
instance. - A one-dimensional
matrixBool
weretrue
value in the indices you want to keep.
m:masked_fill(mask, value)
m:masked_copy(mask, value)
matrixInt32 = m:order()
Returns a permutation of the caller matrix
which sorts its data. The
permutation is given as a matrixInt32
with the indices of the caller matrix
.
The caller matrix
shold be a one-dimensional matrix (rank 1 tensor).
> m = matrix(10,2):uniform(-10,10,random(1234))
> print(m)
5 9
-4 2
10 5
7 -1
1 2
...
-5 -8
# Matrix of size [10,2] stride [2,1] ref [0x10bf090 data= 0x10bf160]
> ord = m:select(2,1):order()
> print(ord)
10 2 5 1 ... 3
# MatrixInt32 of size [10] stride [1] ref [0xe4eba0 data= 0xeb3230]
> sorted = m:index(1, ord)
> print(sorted)
-5 -8
-4 2
1 2
5 9
5 8
...
10 5
# Matrix of size [10,2] stride [2,1] ref [0x1c270c0 data= 0x1ef0080]
matrixInt32 = m:order_rank()
Returns the rank of the matrix
elements in its sorted permutation. The
caller matrix
should be a one-dimensional matrix (rank 1 tensor).
> m = matrix(10,2):uniform(-10,10,random(1234))
> print(m)
5 9
-4 2
10 5
7 -1
1 2
...
-5 -8
# Matrix of size [10,2] stride [2,1] ref [0x10bf090 data= 0x10bf160]
> rnk = m:select(2,1):order_rank()
> print(rnk)
4 2 10 9 ... 1
# MatrixInt32 of size [10] stride [1] ref [0x2cf0100 data= 0x2cf0020]
More matrix operations are located at matrix.op
, most of them are equivalent
to methods in matrix
objects, but implemented to be allocate new memory
instead of being in-place, and receiving the caller matrix
as first
argument. New operations have been defined in this table to reduce the overhead
of matrix
instance table. Only the new operations are documented here.
The table matrix.ext
contains new function extensions which work over
matrices. This functions are here because the extensions are pretty new, still
in testing, and to not polute too much the matrix
class with new methods.
matrix = matrix.ext.real_fftwh(m, wsize=m:size(), wadvance=wsize, dest=nil)
This functions computes real FFT with Hamming window to the given matrix m
.
The FFT is computed for all the possible positions of a sliding window of size
wisize
. The sliding window advances wadvance
samples every iteration. By
default, the function configures wsize
and wadvance
just to compute FFT over
the whole given matrix m
. The matrix m
should have only one dimension (rank
1). The result is new allocated matrix with size NxF
where N=(m:size() - wsize)/wadvance + 1
and F
is the size of the FFT output. In case the argument
dest
is given, it should be a matrix
instance of size NxF
, and it would
be the result matrix
, avoiding the allocation of a new matrix
.
> a = matrix(200):uniformf(0,1,random(1234))
> f = matrix.ext.real_fftwh(a, 20, 10)
> print(f)
5.78204 17.9694 2.60205 1.93296 ... 0.210018
4.80782 11.8858 0.97495 1.46241 ... 2.67692
4.15355 9.48432 1.71497 0.480176 ... 0.498562
5.12262 16.0089 3.65927 0.276271 ... 1.00497
5.57981 16.7664 2.00985 0.0188873 ... 0.336096
...
4.96313 15.267 3.44396 0.307427 ... 0.539195
# Matrix of size [19,16] stride [16,1] ref [0x1efbe50 data= 0x1f46330]
matrix.sparse
s = matrix.sparse(matrix)
s = matrix.sparse(d1, d2, values, indices, first_index)
s = matrix.sparse.csc(matrix)
s = matrix.sparse.csr(matrix)
s = matrix.sparse.diag(obj, [format="csr"])
- A
number
- A
matrix
- A
table
dok = matrix.sparse.builders.dok()
dok = dok:set(row, col, value)
sparse = dok:build([num_rows, [num_cols, [format="csr"]]])
Currently is possible to use complex, double, int32 and char matrices, supporting load and save, matrix structural methods, and some of them also support mathematical operations:
-
matrixBool
: a matrix of boolean values. Basic functionality. -
matrixComplex
: fully working matrix type, with almost all the methods described above. -
matrixDouble
: partial working matrix type, only allow structural methods (explained at MatFormat section). -
matrixInt32
: partial working matrix type, only allow structural methods (explained at MatFormat section). -
matrixChar
: partial working matrix type, only allow structural methods (explained at MatFormat section).
In all cases, you could use april_help
to ask which methods are available.
Complex, MatrixChar type implements a method to_string_table
.
All matrices implement method convert_to(type)
which receives a type string
with one of these values: "float", "double", "complex", "int32", "bool", "char"
; allowing to convert a matrix of one type into a different type with
a casting and precision loss in some cases.
> m = matrix(5,5):uniformf(-10,10,random(12354))
> print(m)
1.03926 -6.82017 -7.80579 -2.02109 -9.40496
1.54086 -1.43963 7.11541 1.20382 -2.91477
5.89334 9.04666 -0.688719 -9.25703 -3.0825
5.4027 -3.25782 -0.7066 -5.90035 -8.35659
-0.986174 8.1467 -7.01133 -9.03494 5.69565
# Matrix of size [5,5] stride [5,1] ref [0x16d0410 data= 0x16d04e0]
> print(m:convert_to("int32"))
1 -6 -7 -2 -9
1 -1 7 1 -2
5 9 0 -9 -3
5 -3 0 -5 -8
0 8 -7 -9 5
# MatrixInt32 of size [5,5] stride [5,1] ref [0x187d2b0 data= 0x187d380]
The constructor of a matrixComplex
receives a table with complex numbers (see utils section).
A complex number uses float single precission resolution for real and imaginary part:
> -- using strings which are converted to complex numbers (slow performance)
> m = matrixComplex(2,2, { "1+1i", "2+2i", "3+2i", "4+1i" })
> = m
1+1i 2+2i
3+2i 4+1i
# MatrixComplex of size [2,2] in row_major [0x24d52c0 data= 0x24d4a00]
>
> -- using directly complex numbers
> m = matrixComplex(2,2, { complex(1,1), complex(2,2), complex(3,2), complex(4,1) })
> = m
1+1i 2+2i
3+2i 4+1i
# MatrixComplex of size [2,2] in row_major [0x24d6550 data= 0x24d6650]
Besides the standard matrix
methods, the matrixComplex
implements the following:
-
caller = m:conj()
computes the conjugate in-place, modifying the caller matrix, and returning the caller matrix instance. -
matrix = m:real()
returns the real part of the callermatrixComplex
. -
matrix = m:img()
returns the imaginary part of the callermatrixComplex
. -
matrix = m:abs()
returns the modulus of the polar form ofmatrixComplex
. -
matrix = m:angle()
returns the angle of the polar form ofmatrixComplex
. -
matrix = m:to_float()
converts the caller matrix in amatrix
object which has one additional dimension. This additional dimension has always size 2, and keeps the real and imaginary parts of the callermatrixComplex
. The additional dimension will be the last. Note that the returnedmatrix
and thematrixComplex
caller references the same memory pointer.
matrixDouble
is the type of matrices for double data.
This kind of matrices don't accept mathematical operations, but yes structural
operations as select
, slice
, etc.
> m = matrixDouble(2,3,{1,2,3,4,5,6})
> = m
1 2 3
4 5 6
# MatrixDouble of size [2,3] [0x2512c70 data= 0x251ad70]
matrixInt32
is the type of matrices for integer data.
This kind of matrices don't accept mathematical operations, but yes structural
operations as select
, slice
, etc.
> m = matrixInt32(2,3,{1,2,3,4,5,6})
> = m
1 2 3
4 5 6
# MatrixInt32 of size [2,3] [0x2512c70 data= 0x251ad70]
matrixChar
is the type of matrices for char data.
This kind of matrices don't accept mathematical operations, but yes structural
operations as select
, slice
, etc.
Exists an special method, to_string_table()
, which converts the matrix
in a table of strings, concatenating the chars in row_major
order.
> m = matrixChar(2,2, { "h","ola" })
> = m
[1,1] = h
[1,2] = o
[2,1] = l
[2,2] = a
# MatrixChar of size [2,2] [0x12c3310 data= 0x12c3410]
> = unpack(m:to_string_table())
ho la
The table matrix.dict
contains several functions which allow to execute
matrix
operations over tables of matrices.
another = matrix.dict.clone(tbl)
Returns a deep copy of the table.
another = matrix.dict.clone_only_dims(tbl)
Returns a deep copy of the table, but without copying the matrix data content, only cloning the matrix dimension sizes.
The following list of operations are implemented to be executed over all the contained matrices:
-
number = matrix.dict.size()
-
tbl = matrix.dict.fill(tbl,number)
-
tbl = matrix.dict.ones(tbl)
-
tbl = matrix.dict.zeros(tbl)
-
tbl = matrix.dict.axpy(tbl, number, tbl2)
-
number = matrix.dict.dot(tbl, tbl2)
-
tbl = matrix.dict.copy(tbl, tbl2)
-
tbl = matrix.dict.scalar_add(tbl, number)
-
tbl = matrix.dict.complement(tbl)
-
tbl = matrix.dict.pow(tbl, number)
-
tbl = matrix.dict.scal(tbl, number)
-
tbl = matrix.dict.inv(tbl)
-
tbl = matrix.dict.sqrt(tbl)
-
tbl = matrix.dict.exp(tbl)
-
tbl = matrix.dict.plogp(tbl)
-
tbl = matrix.dict.log1p(tbl)
-
tbl = matrix.dict.cos(tbl)
-
tbl = matrix.dict.cosh(tbl)
-
tbl = matrix.dict.acos(tbl)
-
tbl = matrix.dict.acosh(tbl)
-
tbl = matrix.dict.tan(tbl)
-
tbl = matrix.dict.tanh(tbl)
-
tbl = matrix.dict.atan(tbl)
-
tbl = matrix.dict.atanh(tbl)
-
tbl = matrix.dict.sin(tbl)
-
tbl = matrix.dict.sinh(tbl)
-
tbl = matrix.dict.asin(tbl)
-
tbl = matrix.dict.asinh(tbl)