Similar to Vector data structure that is specialized to manage 1D numeric data, Matrix is also very flexible but to work with 2D numeric data. The following are the possible cases to access (read/write) the elements of a matrix:
>>m=std.tomatrix{ {1, 2, 3} , {3, 4, 5} , {6 , 7, 8} }
>>m
1 2 3
3 4 5
6 7 8
>>m[1][1]=10
>>m[{2}]=20
>>m
10 20 3
3 4 5
6 7 8
Command (m[1][1]=10): We access the matrix using m[row][column] access style. Here we changed the first row and first column from 1 to 10.
Command (m[{2}]=20): We accessed the matrix using the linear_indexing concept. The linear indexing for the (3x3) matrix, m, ranges from 1 to 9, where index 1 is equal to m[1][1] and index 9 is equal to m[3][3].
>>m[2][3] or >>m(2,3)
5
>>m[{7}]
6
One can quickly notice that the call m[2][3] is equivalent to m(2,3). Similar to Vector, Matrix also supports reading both with index, [][], and function call, (), styles.
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>m
1 2 3
4 5 6
7 8 9
>>m[{1, 3, 5}]
1 3 5 COL
>>m({1, 3, 5})
1 3 5 COL
It is seen that if the return value is a single number then the return type is number; however, if it is more than a single value and 1D, then the return type is Vector.
>>m[ {from=3, to=5} ] = {30, 40, 50, 60}
>>m
1 2 30
40 50 6
7 8 9
Here using linear indexing we request that elements 3, 4 and 5 be equal to 30, 40 and 50. Since we request only 3 elements to be changed, the 4th element on the right-hand side, number 60, was ignored. Following is another case.
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>m[ {from=3, to=5} ] = {30, 40}
>>m
1 2 30
40 5 6
7 8 9
This time we have requested 3 elements on the left-hand side to be changed but only provided 2 numbers on the right-hand side. Therefore, only 2 elements were changed.
In the following example, notice the use of keyword by:
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>m[ {from=3, to=9, by=4} ] = {30, 70, 90}
>>m
1 2 30
4 5 6
70 8 9
The following is doable as well:
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>m[ {} ]={10, 20, 30, 40}
>>m
10 20 30
40 5 6
7 8 9
On the right-hand side we can also use a Vector. The following example demonstrates this:
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>v=std.tovector{10, 20, 30}
>>m[{}] = v
>>m
10 20 30
4 5 6
7 8 9
To change all the elements of a matrix to a single value:
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>m[{}] = 10
>>m
10 10 10
10 10 10
10 10 10
To read a single-column or a row, the following syntax can be used:
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>m({}, 1)
- read the first column
1 4 7 COL
- read the first row
>>m(1, {})
1 2 3 ROW
Internally a matrix is composed of vectors. Therefore, it is highly efficient to read a row in the following way:
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>m[1]
1 2 3 LINK
However, although it can be noticed that the return type is a Vector, it is neither row nor a column vector, but a link vector. A link vector shares the same memory space with the row of a matrix and as mentioned above this is due to the fact that Matrix is made up of Vectors.
The following example is illustrative what could happen if caution is not exercised when working with link vectors.
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>v=m[1]
>>v[1]=10
>>m
10 2 3
4 5 6
7 8 9
In the above example:
We notice that the first element of the first row of the matrix was also changed.
Question arises, what happens if v is garbage collected by Lua (such as v=nil or when it is out of scope):
--Continuing from the previous example
>>>v=nil
>>m
10 2 3
4 5 6
7 8 9
It is seen that the matrix remains intact. Internally, when link vectors are destroyed, the memory shared by the vector is not deleted, therefore the matrix is not affected.
Matrix structure supports essential arithmetic operations: Let m1, m2 and m3 denote matrix of same size, and a an arbitrary number.
Besides the arithmetic operators, Matrix also supports __pairs and next methods, therefore is an iteratable container.
append (elem, align)
Appends a vector or a Lua table to the matrix (please see insert). The parameters: elem: Either a Vector or a Lua table. align:Alignment of the inserted element, either "row" or "col".
1 | 2 | 3 | 11 |
4 | 5 | 6 | 12 |
7 | 8 | 9 | 13 |
10 | 20 | 30 | 14 |
Appending a vector is as same as appending a Lua table:
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>v=std.tovector{10, 20, 30}
>>m:append(v, "row")
>>m
1 2 3
4 5 6
7 8 9
10 20 30
clone() → Matrix
Makes an exact copy of the existing matrix. Notice the difference in the following commands.
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
-- array access via linear indexing (return type is vector)
>>m1=m[{}]
>>m1
1 2 3 4
5 6 7 8 9 COL
-- function call access via two empty Lua tables (return type is matrix)
>>m2=m({},{})
>>m2
1 2 3
4 5 6
7 8 9
-- direct call of the clone member function equivalent to m({},{})
>>m3=m:clone()
>>m3
1 2 3
4 5 6
7 8 9
delc(pos=)
Deletes a column at the specified position, if the matrix will have at least 2 columns after the deletion. Otherwise an error message is returned.
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>m:delc(2)
>>m
1 3
4 6
7 9
delr(pos=)
Deletes a row at the specified position, if the matrix will have at least 2 rows after the deletion. Otherwise an error message is returned.
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>m:delr(2)
>>m
1 2 3
7 8 9
Alternatively, m[2]=nil would have given the same result.
equal(arg, [tol=1E-5]) → Matrix
Tests whether the elements of the Matrix is equal to a number (mij==a) or elements of the Matrix is equal to the elements of another Matrix (m1ij==m2ij). The equality test is done using a predefined tolerance, which is 1E-5. The tolerance level can be specified by the user.
>>m=std.tomatrix{ {1, 2, 3} , {1.1, 2.1, 3.1} , {7, 8, 9} }
>>m
1 2 3
1.1 2.1 3.1
7 8 9
>>m:equal(3)--default tolerance level
0 0 1
0 0 0
0 0 0
>>m:equal(3, 0.11)--tolerance level is set to 0.11
0 0 1
0 0 1
0 0 0
>>m=std.tomatrix{ {1, 2, 3} , {4, 5, 6} , {7, 8, 9} }
>>m2=std.tomatrix{ {1, 2, 3} , {1.1, 2.1, 3.1} , {7, 8, 9} }
>>m:equal(m2)
1 1 1
0 0 0
1 1 1
greater(arg) → Matrix
Works the same way as member function equal, except there is no tolerance defined. Tests for the > operator.
greater_equal(arg, tol=1E-5) → Matrix
The function first tests for equality of the element with the given tolerance as detailed in the equal member function, if this test fails then tests whether it is greater. Tests for the >= operator.
insert (elem, pos, align)
Inserts a vector or a Lua table to the matrix (please see append). The parameters:
elem: | Either a Vector or a Lua table. |
pos: | A valid position starting from 1. |
align: | Alignment of the inserted element, either "row" or "col". |
The syntax of inserting a Vector to the matrix is same as inserting a Lua table.
less(arg) → Matrix
Works the same way as member function equal, except there is no tolerance defined. Tests for the < operator.
less_equal(arg, tol=1E-5) → Matrix
The function first tests for equality of the element with the given tolerance as described in the equal member function, if this test fails then tests whether it is smaller. Tests for the <= operator.
ncols() → integer
Returns the number of columns.
nrows() → integer
Returns the number of rows.
sort(pos, order)
Sorts the matrix by given column position.
pos: | Column number according to which the matrix will be sorted. |
order: | Sort order, either "A" or "D" for ascending and descending sorts. |
>>m=std.floor( std.rand(3, 3)*10 )
>>m
6 7 2
5 8 9
6 9 6
>>m:sort(1, "D")
>>m
6 7 2
6 9 6
5 8 9