For this project, you'll write functions that perform certain operations on matrices.
What are matrices? We'll discuss them in class, but also I need you to read this. It's a short introduction to matrices; it describes just those matrix operations you'll implement. I also suggest that you peruse the Wikipedia article. (I did say peruse. You won't read it start to finish. It's too much for that.) If you haven't taken a Linear Algebra course yet, you probably will at some point; and in that course, you'll study matrices in much greater depth.
So, I assume you've read my introduction and know what a matrix is. Of course we'll need a way to get matrices into our code. What's the right data structure? I suggest that we use lists of lists. The outer list in each case will be the matrix; each inner list will be a row from the matrix. So for instance the list [[1, 2], [2, 3], [3, 4]] represents the 3 × 2 matrix whose rows are [1, 2], [2, 3] and [3, 4].
Write the six functions described below. Each takes a matrix or matrices; some return a matrix or a tuple, and one returns a scalar. (A scalar is just a single number.) None of the functions are mutators. Note that some should raise value errors. Recall the syntax:
if <boolean_expression>:
raise ValueError(<string>)
As always, you should try to make every function your write single-task. Thus if as you work on a function, you realize that it carries out multiple tasks, you should break it apart into multiple functions. This means that you'll likely write helper functions in addition to those that I require you to write, and the required functions will call those helper functions. Keep in mind as well that, as soon as you have a function written, you should test it and thereby convince yourself that it does indeed work. I suggest that you create a number of test matrices at the end of your code, and then call your functions of them from the console. I do have some test cases below. You should also create your own.
To get a grade, I'll have you send inputs that I'll create to your functions and ask you to write down their outputs.
Function name: mat_size
Parameter(s): a matrix A
Return: the tuple (m, n) where m is the number of rows in A and n is the number of columns
Note: the statement return m, n returns a tuple. Also note: the matrix with no elements, represented by us as [[]], has size (0, 0).
Function name: mat_add
Parameter(s): two matrices A and B
Return: the sum of A and B (which of course will be a matrix)
Raise a value error if A and B do not have the same size.
Function name: scalar_mult
Parameter(s): a scalar s and a matrix A
Return: the scalar product of s and A
Function name: mat_sub
Parameter(s): two matrices A and B
Return: A minus B (which as I'm sure you recall is A plus -1 times B)
Raise a value error if A and B do not have the same size.
Hint: the body can have just one line if you call functions described above.
Function name: mat_mult
Parameter(s): two matrices A and B
Return: the product of A and B
Raise a value error if the number of columns of A does not equal the number of rows of B.
Function name: transpose
Parameter(s): matrix A
Return: the transpose of A (which, if has dimensions m-by-n, will have dimensions n-by-m)
Function name: are_inverses
Parameter(s): two square matrices A and B of equal size (a matrix is square when it number of rows equals its number of columns)
Return: True and A and B are multiplicative inverses, False if they are not (and, as I explained in my short introduction to matrices, two matrices are multiplicative inverses when and only when their product is the identity matrix.)
Function name: det
Parameters: a square matrix A
Return: the determinant of A (which is a single number)
Raise a value error if A isn't square
Do this non-recursively; that is, do it with for or while loops. This will be a bit of a challenge. Note that you'll have to rely on examples I provide in class
Test cases are below. Note that the determinates shown are only approximations of the true values. No doubt the first is really 1 and the second is really -23598. If your answers are exact, I commend you. If like mine they're approximate, that's fine too.
>>> L = [[-8, 3, 0], [12, -10, -10], [-6, 10, -12], [12, 11, -9]] # 4 by 3
>>> M = [[-10, 1, 1], [-12, -11, -7], [-5, -6, 3], [-8, 12, -4]] # 4 by 3
>>> N = [[-1, 5, -9, 8], [-3, -4, 2, -4], [-10, 7, 8, 4], [3, 8, -8, 0]] # 4 by 4
>>> r = -3
>>> mat_size(M)
(4, 3)
>>> mat_add(L, M)
[[-18, 4, 1], [0, -21, -17], [-11, 4, -9], [4, 23, -13]]
>>> mat_sub(L, M)
[[2, 2, -1], [24, 1, -3], [-1, 16, -15], [20, -1, -5]]
>>> scalar_mult(r, N)
[[3, -15, 27, -24], [9, 12, -6, 12], [30, -21, -24, -12], [-9, -24, 24, 0]]
>>> transpose(N)
[[-1, -3, -10, 3], [5, -4, 7, 8], [-9, 2, 8, -8], [8, -4, 4, 0]]
>>> mat_mult(N, L)
[[218, -55, -14], [-84, 7, 52], [164, 24, -202], [120, -151, 16]]
>>> O = [[7, 2, 1], [0, 3, -1], [-3, 4, -2]]
>>> determinate(O)
0.9999999999999964
>>> P = [[1, -3, 2, 11], [-2, 13, 9, 4], [17, 4, -4, 12], [21, 1, -19, 6]]
>>> determinate(P)
-23597.999999999938