Chapter 9 Lists
9.10 Matrices as Lists of Lists¶
Matrices can be represented by lists of lists, with each sub list representing a row in the matrix. For example, the matrix \(M = \begin{pmatrix} 1 & 2 & 3 & 4 \\ 5 & 6 & 7 & 8 \\ 9 & 10 & 11 & 12\end{pmatrix}\) can be represented by the list
>>> m = [ [1, 2, 3, 4],
... [5, 6, 7, 8],
... [9, 10, 11, 12] ]
Using this formulation, the ith row of m can be accessed by the expression m[i-1]:
(continued from above)
>>> m[0] # the first first row
[1, 2, 3, 4]
>>> m[2] # the third row
[9, 10, 11, 12]
The item \(m_{i,j}\) can be accessed by m[i-1][j-1]:
(continued from above)
>>> m[0][0] # the first row, the first column
1
>>> m[2][1] # the third row, the second column
10
As nested lists, matrices can be processed using loops. The following examples give a set of functions for matrix manipulation.
The functions get_row and get_column take a matrix argument, and additionally an integer argument that specifies an index i, and return a copy of the ith row and column of the matrix as a list, respectively.
The function get_column above works by initializing the return value to an empty list, and updating it by iterating through each row in the matrix. At each iteration, the item in the specified column is added to the back of the result. After all the rows have been enumerated, the return value contains the specified column.
A simple matrix operation is scaling. Given a matrix M and a scalar a, a M results in a matrix N, which has the same width and height as M, and satisfies \(N_{i,j} = aM_{i,j}\) for all i, j. Matrix scaling can be performed by initializing the result as a copy of M, and then scaling each element by traversal of the new matrix.
There are two things to note on the function scale above. First, copy.deepcopy is used to make a copy of M. Because M is a list of lists, it needs copied recursively to avoid sharing of sub lists between the copies. Second, iteration over N is based on indices rather than values, because modification of sub lists (i.e. rows) requires setitem, which uses indices.
Another common matrix operation is addition, which adds two matrixes of the same size by each element. Matrix addition can be performed by initializing the result as one input matrix, and then updating each element by addition with the corresponding element in the other input matrix.
Traversal by index can also be used to perform the transposition operation. Given a matrix M with width w and height h, the transpose \(M^T\) has width h and height w, and satisfies \(M^T_{i,j} = M_{j,i}\) for all i, j.
The function transpose initializes the output N using a loop. N is initialized as an empty list, and then updated by appending h zero-valued rows, each consisting of w zeroes. Here w and h are the width and height of the input matrix, respectively.
Note that N cannot be initialized by the expression [[0] ∗ h] ∗ w, the object [0] ∗ h is a list, which is mutable. Making w copies of [0] ∗ h will result in all the rows in N sharing the same list (i.e. [0] ∗ h), rather than having w copies of the list.
The function transpose works by generalized summation. The result is initialized as all zeros, and then iterating updated by iterating through each index i, j, assigning M[j][i] to N[i][j]. Note that the nested loop can be viewed as an enumeration of all possible item combinations of [0, 1, · · ·, len(M[0]) − 1] and [0, 1, · · ·, len(M) − 1].
Matrix multiplication is one of the most difficult operations. Multiplying two matrixes M and N results in a matrix R, in which the item \(R_{i,j}\) is the dot product of the ith row of M and the jth column of N. Matrix multiplication can be written by slightly modifying the previous example of matrix transposition, using the dot product operation \(M_i \cdot N_j\) instead of \(M_{i,j}\) as the incremental operation.
© Copyright 2024 GS Ng.