I like the logical indexing like with R:
a=1:100 a(modulo(a,2)==0) // selects the even numbers
When you work with matrices, one frequent operation is of extracting a sub-matrix from an existing matrix and its inverse operation of replacing a sub-matrix of an existing matrix with a specified matrix. Scilab offers handy operations to perform these two tasks.To simplify these operations, Scilab uses the concept of the range. To a beginner, these operation appear to be somewhat confusing but learning them gives you a powerful technique that you will need often.
These techniques are the same ones that are available in Matlab and in Python. If you are familiar with one of them, you will find this session pretty simple. Otherwise, it is time to roll up the sleeves and get down to work.
In this session you will learn the following:
Range is a sequences of numbers that can be generated using the range operator, namely, colon(:). You can define a variety of ranges:
Let us try out a few examples:
-->1:5 // increment is 1 ans = 1. 2. 3. 4. 5. -->1:2:10 // increment is 2 qns = 1. 3. 5. 7. 9. -->1:0.5:4 // increment is 0.5 ans = 1. 1.5 2. 2.5 3. 3.5 4. -->4:-1:1 // decrement is 1 ans = 4. 3. 2. 1. -->4:-0.5:2 // decrement is 2. Stop at 2 ans = 4. 3.5 3. 2.5 2. -->b = 1:5 // Row vector, same as b = [1 2 3 4 5]
Ranges are useful because they can be used to select rows and columns of a matrix. To select rows 2 to 4 and column 3 to 5 of a matrix a, the expression is a(2:4, 3:5). Here, the range 2:4 selects rows 2, 3 and 4 and the range 3:5 select columns 3, 4 and 5. Thus, a contiguous submatrix of size 3x3, starting at element 2,3 and ending at (4, 5) is selected for extraction.
An element in a matrix can be addressed by referring to its row and column. First row and column are numbered 1 (unlike some programming languages such as C/C++, Java and Python which begin numbering rows and columns with 0). Thus a(2, 3) refers to the element of matrix a, on the second row and third column.
If a matrix is a vector (either a row or a column vector), you can refer to one of its element in one of the following ways:
Even when a matrix is a two dimensioned matrix, Scilab allows you to refer to its elements as if it were a one dimensioned vector (either a row or a column vector the way you wish to view it). In such a case, the matrix must be viewed as a vector with elements of the matrix counted column-wise. Thus the elements of a 3x2 matrix could be mapped to a 1x6 vector as follows:
(1,1) (2,1) (3,1) ((1,2) (2,2) (3,2)
(1) (2) (3) (4) (5) (6)
Viewed this way:
and so on. Therefore:
-->a = [1 2 3; 4 5 6]
1. 2. 3.
4. 5. 6.
-->a(1), a(2), a(3)
-->a(4), a(5), a(6)
As discussed above, it is possible to extract a sub-matrix from an existing matrix and store it in another variable.
It is important to note that Scilab can extract any rows and columns as specified by a range. The extracted sub-matrix need not consist of contiguous rows and columns. Let us try out a few examples to understand this concept:
-->a = int(rand(5, 8)*100); // Create matrix a of size 5x8, containing random numbers -->b = a(2, 3) // Extract element on row 2 column 3 of a and store it in b. Scalar -->b = a(2:4, 3:5) // Extract sub-matrix of size 3x3 from a and store it in b -->c = a(1:2:5, 2:2:8) // Extract odd numbered rows and even numbered column of a, and stored in c // Rows 1, 3, 5 and columns 2, 4, 6, 8 are extracted. Size 3x4 -->d = a(5:-2:1, 8:-2:2) // Rows 5, 3, 1 and columns 8, 6, 4, 2 are extracted from a and stored in d -->x = a([1, 4, 5], [2, 7]) // Rows 1, 4, 5 and columns 2, 7 of a are extracted from a and stored in x -->y = a([5, 1, 2], [7, 6]) // Rows 5, 1, 2 and columns 7, 6 are extracted from a and stored in y
As you can see, this logic of selecting rows and columns is quite logical. The row and column numbers can be a scalar, a range or a vector. Elements on the rows and columns selected are selected for extraction.
While specifying ranges for row and column selection, you can use the following conventions:
When the sub-matrix specification is applied to a matrix on the right hand side of an assignment statement, it is an extraction operation. In the same way, it is possible to replace a sub-matrix of an existing matrix with new values. To achieve this, sub-matrix specification must be applied to a matrix on the left hand side of an assignment statement.
To set the element on row 2, column 3 of a to zero, the command is:
-->a(2, 3) = 0
The above operation can be performed on a sub-matrix of a instead of on only one element of a, as long as the right hand side is a zero matrix of the appropriate size. Let us try this:
-->a(2:4, 3:5) = zeros(3,3)
The zero matrix on the right side is of size 3x3. The sub-matrix of a selected on the left side is also of size 3x3. Therefore this is a valid assignment operation and it replaces the 3x3 sub-matrix of a, on rows 2, 3, 4 and columns 3, 4, 5 with zeros.
You can now try out all possible tricks we performed while illustrating sub-matrix extraction. As long as you remember the rule that the matrices on either side of the assignment are of the same size, the operation will succeed.
A hint for the impatient. If you don't want to bother counting the number of rows and columns to be replaced on the left side in order to specify the correct size for the matrix on the right side, you can leave it to Scilab to do that for you. Thus, the following will work:
-->a(2:4, 3:5) = ones() // No need to specify rows and columns to the function ones() -->a(2:4, 3:5) = zeros() // Same as for ones() -->a(2:4, 3:5) = eye() // ERROR. Doesn't work
Use these tricks at your own risk, some of them don't work as expected. For example, a(2:4, 3:5) = eye(1,1) works, but results are what you expect.
You can concatenate any number of compatible matrices into a single matrix. All the matrices being concatenated must have the same number of rows. Assuming a, b and c have the same number of rows, the following command concatenates them into a single matrix d
-->d = [a b c]
Thus, the columns of d are the columns of a, b and c concatenated in that order. Try out the following command, and guest the output:
-->a = int(rand(4,2)*10), b = int(rand(4,1)*50), c = int(rand(4,1)*100)
-->d = [c a b]
Yes, that will work perfectly since modulo(a, 2) returns a matrix of boolean values, and only those elements of a are displayed where the boolean value is TRUE. As an example:
-->a = [1:10];
-->modulo(a, 2) // returns remainder of integer division
1. 0. 1. 0. 1. 0. 1. 0. 1. 0.
-->modulo(a, 2) == 0 // F for odd index elements, T for even index values
F T F T F T F T F T
-->a(modulo(a, 2) == 0) // displays elements whose index is T
2. 4. 6. 8. 10.
This will also work for a matrix (unlike for a vector in the above example), but the final result returned is a vector, not a matrix. For example, try the commands above with a = [1 2 3 4; 5 6 7 8].