Problem 7.2.6
We are supposed to compute the determinant of the matrix $$ M=\left[ \begin{array}{rrrr} 1&2&-1&1\\ 0&1&2&1\\ 0&2&1&3\\ 1&4&0&2 \end{array} \right] $$
By expanding first along the second row, and then along the first column. What this expansion thing means, is described in Definition 7.9 of our textbook, and entails computing cofactors for our matrix. SymPy knows how to do this (it also knows how to compute minors, incidentally).
from sympy import *
init_printing(use_latex='mathjax')
M=Matrix([[1,2,-1,1],[0,1,2,1],[0,2,1,3],[1,4,0,2]]); M
Before we start asking for our cofactors to plug into the determinant, there's one caveat: Python (so also SymPy) numbers things starting with $0$ (rather than $1$). So what we would call the first column (or row), Python knows as the $0^{th}$ column (or row respectively). You need to take this into account when programming.
Concretely, in this specific case, we'll want to ask SymPy for cofactors with first entry $1$ (because those correspond to the second matrix row in common parlance) and also for cofactors with second entry $0$ (because those correspond to the first column in plain English rather than Python).
With this in mind, here's, say, what we (and our textbook) would call $C_{11}$ (for the matrix $M$):
M.cofactor(0,0)
See what we did? The '$11$' subscript from our common notation became $0,0$. Similarly, the cofactor we would call $C_{23}$ is
M.cofactor(1,2)
In short, you take the indices you are used to and decrement each by 1. Now on to that expansion along the second row. Since $M$ is a small enough matrix, only $4\times 4$, we could simply write out the four summands; but this being a programming environment, the natural (and, generally, more efficient) thing to do is to use a for loop to iterate over an index $i$ counting my columns.
I don't even need to plug in the number of rows/columns by hand: SymPy can give it back to you from the matrix as a function of the matrix. Let's put all of this together into asking for the expansion along the second row then:
sum=0
for j in range(0,M.cols):
sum=sum+M[1,j]*M.cofactor(1,j)
sum
That tells me the number I am after (i.e. the determinant of $M$) is $6$. Let's also try the expansion along the first column (we'd better get the same number; there's only one determinant, regardless of how you expand!):
sum=0
for i in range(0,M.rows):
sum=sum+M[i,0]*M.cofactor(i,0)
sum
Phew! It did work out. Let's also check, for good measure, by just plain asking for the determinant directly:
M.det()
It does indeed check out. Before we finish, let me also do what it would have been most natural to do to begin with, given, again, that we are in a programming environment: instead of "manually" asking for the expansion along, say, the second row, I should have defined a function that takes in an index $i$ and spits out the expansion along the $i^{th}$ row. That way we could have asked for any of the expansions in single, short commands.
So here we go: I'll define two functions, one expanding along row $i$ and one expanding along column $j$ (in our, human language, so that you can ask for row 1 and actually mean row 1 rather than Python's shifted numbering).
def rowExp(M,i):
sum=0
for j in range(0,M.cols):
sum=sum+M[i-1,j]*M.cofactor(i-1,j)
return sum
That's for rows. Note the shift from $i$ to $i-1$, to translate from our numbering (starting at 1) to Python's numbering (starting at 0). Also one for columns:
def colExp(M,j):
sum=0
for i in range(0,M.rows):
sum=sum+M[i,j-1]*M.cofactor(i,j-1)
return sum
Let's now simply apply these functions to our matrix with various entries for our rows and columns, and check that we always get $6$ for the determinant:
rowExp(M,3)
colExp(M,2)
colExp(M,1)
rowExp(M,4)
Finally, note that because our $M$ only has four rows and columns, asking for expansions outside that range will return an error:
rowExp(M,5)
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) File ~/.local/lib/python3.11/site-packages/sympy/polys/matrices/sdm.py:82, in SDM.getitem(self, i, j) 81 try: ---> 82 return self[i][j] 83 except KeyError: KeyError: 4 During handling of the above exception, another exception occurred: IndexError Traceback (most recent call last) File ~/.local/lib/python3.11/site-packages/sympy/matrices/repmatrix.py:712, in _getitem_RepMatrix(self, key) 711 try: --> 712 return self._rep.getitem_sympy(index_(i), index_(j)) 713 except (TypeError, IndexError): File ~/.local/lib/python3.11/site-packages/sympy/polys/matrices/domainmatrix.py:173, in DomainMatrix.getitem_sympy(self, i, j) 172 def getitem_sympy(self, i, j): --> 173 return self.domain.to_sympy(self.rep.getitem(i, j)) File ~/.local/lib/python3.11/site-packages/sympy/polys/matrices/sdm.py:91, in SDM.getitem(self, i, j) 90 else: ---> 91 raise IndexError("index out of range") IndexError: index out of range During handling of the above exception, another exception occurred: IndexError Traceback (most recent call last) Cell In[27], line 1 ----> 1 rowExp(M,5) Cell In[17], line 4, in rowExp(M, i) 2 sum=0 3 for j in range(0,M.cols): ----> 4 sum=sum+M[i-1,j]*M.cofactor(i-1,j) 5 return sum File ~/.local/lib/python3.11/site-packages/sympy/matrices/repmatrix.py:233, in RepMatrix.__getitem__(self, key) 232 def __getitem__(self, key): --> 233 return _getitem_RepMatrix(self, key) File ~/.local/lib/python3.11/site-packages/sympy/matrices/repmatrix.py:733, in _getitem_RepMatrix(self, key) 731 else: 732 j = [j] --> 733 return self.extract(i, j) 735 else: 736 # Index/slice like a flattened list 737 rows, cols = self.shape File ~/.local/lib/python3.11/site-packages/sympy/matrices/common.py:370, in MatrixShaping.extract(self, rowsList, colsList) 367 colsList = [index for index, item in enumerate(colsList) if item] 369 # ensure everything is in range --> 370 rowsList = [a2idx(k, self.rows) for k in rowsList] 371 colsList = [a2idx(k, self.cols) for k in colsList] 373 return self._eval_extract(rowsList, colsList) File ~/.local/lib/python3.11/site-packages/sympy/matrices/common.py:370, in <listcomp>(.0) 367 colsList = [index for index, item in enumerate(colsList) if item] 369 # ensure everything is in range --> 370 rowsList = [a2idx(k, self.rows) for k in rowsList] 371 colsList = [a2idx(k, self.cols) for k in colsList] 373 return self._eval_extract(rowsList, colsList) File ~/.local/lib/python3.11/site-packages/sympy/matrices/common.py:3189, in a2idx(j, n) 3187 j += n 3188 if not (j >= 0 and j < n): -> 3189 raise IndexError("Index out of range: a[%s]" % (j,)) 3190 return int(j) IndexError: Index out of range: a[4]