To estimate the condition number of a matrix using the algorithm in part (a) of Computer Problem 2.4 (page 101, with a brief discussion on page 59 of the text), you need to solve a lower triangular system (Utv = c, where your algorithm must determine c as it goes) and then an upper triangular system (Lty = v). In general, if M is a lower triangular matrix (so M[i][j] = 0 for j > i), and the system is Mx = b, then row i of M represents the equation
Most often in implementations of algorithms for solving systems, the vector b[i] is stored in the last column of the Matrix M, so b[i] would be M[i][n] where n = the number of rows of the coefficient matrix (which is also the number of columns of the coefficient matrix but the augmented matrix has one additional column - so in Matrix.cc the index of the last column is either numRows or numCols - 1). In problem 2.4, you don't know what b is -- you want to choose +1 or -1 for each entry so that the component of the solution x is as large (in magnitude) as possible. So, for each row, your program should
An equation similar to the above can be written for solving an upper triangular system. In problem 2.4, the upper triangular system has ones on the diagonal so the last step of dividing by the entry on the diagonal is not needed (just as in solving the original system in my code there is no division when forward substituting using L).
Dealing with the Row Switches: The most efficient and easiest way to deal with the fact that there have been "virtual" row switches (which are kept track of in the row vector) is to use the LU matrix as it is!!!! You just need to think about what the indices are for the transpose of U and of L. As an example, suppose that in doing Gaussian elimination on a 3 by 3 matrix, the first and second row were switched in the first step then the second and third row were switched in the next step. Then (using C++/Java indices), row = 1, row = 2, and row = 0. Suppose that physically LU (this is the way the matrix is physically stored in the computer) is as follows:
1 2 3 4 5 6 7 8 9So, logically it is
4 5 6 (logical row 0 is physically in row 1 of LU) 7 8 9 1 2 3So, the logical transpose is
4 7 1 5 8 2 6 9 3 and hence, Ut is4 0 0 5 8 0 6 9 3and Lt is1 7 1 0 1 2 0 0 1So, Ut[i][j] = LU[_______________][___________________] (fill in the blank -- if you can't see it with i's and j's first use some actual numbers). Similarly, the entries in Lt can be gotten directly from LU using correct indexing and can be used in the backsubstitution algorithm to get a solution vector y.
To complete the approximation of the norm of A inverse you need to solve Az = y (where y is your solution above). To use the forback() function already in the Matrix class (this is the one that SHOULD be used when an LU decomposition has already been obtained), you need to be sure your solution is in the last column of LU. You can put it there as you solve or copy it into that column -- so LU[i] gets y[i]).
Copying LU or its transpose into a new matrix: There were many variations in your programs that involved making one or more new matrices -- many of you got carried away and used the vector row in too many places or the wrong places. If you found the logical transpose (as above -- the one that splits into the U and L) and worked with it (so, after you found the transpose you DO NOT use the vector row in applying the forward and backward substitution algorithms), the components of your solution are not in the same order as the original. For example, if you get a solution vector y, then y[i] does not go with the original row i -- it is a solution of original row[i]. Hence when you copy your solution into the last column of the original LU, LU[row[i]][numRows] gets y[i].
Topics from Chapter 2 that will be on Test #2