Session 5: Ranges, Sub-matrix Extraction and Replacement [June 12, 2011, 5:58 p.m.]
Objectives
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 a handy operation 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 frequently.
These techniques are the same ones that are available in Matlab and to 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:
- Ranges and their use to define sequences
- Extracting a submatrix from an existing matrix
- Replacing a submatrix within an existing matrix with different values
Ranges
Ranges are sequences of numbers that can be generated using the range operator, namely, colon(:). You can define a variety of ranges:
- Ranges incrementing by 1, Requires start and end values. End value must be greater than the start value.
- Ranges incrementing by a value other than 1. Increment can be fraction. End value must be greater than the start value.
- Ranges decrementing by a specified value. End value must be smaller than the start value.
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.
Indexing
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:
- As a one dimensioned array: a(2) refers to the element in the second element of the vector
- As a two dimensioned matrix: a(1, 2) referes to the second element of a row vector. a(2,1) referes to the second element of a column vector.
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 thus way:
- a(1,1) can be referred to as a(1)
- a(1,2) can be referred to as a(4)
and so on. Therefore:
-->a = [1 2 3; 4 5 6]
a =
1. 2. 3.
4. 5. 6.
-->a(1), a(2), a(3)
ans =
1.
ans =
4.
ans =
2.
-->a(4), a(5), a(6)
ans =
5.
ans =
3.
ans =
6.
Sub-matrix Extraction
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:
- The symbol $ represents the number of the last row/column. Thus, to specify rows 2 to the last, and columns 3 to the last, you can specify a(2:$, 3:$). This makes it unnecessary to know the number of last row or column while selecting them.
- The range 1:$ essentially means all rows/columns. This can be written simply as :, without specifying either the start or the end value. Thus a(:, 2:$) means all rows and columns starting from 2ns to the last.
- Either both start start and end values must be specified, or both must be left out. Specifying only one of them is an error.
Sub-matrix Replacement
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.
Concatenating Matrices
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]