import numpy as np
def MATINV(N, A):
'''
A = [B | D]
returns
A = [I | B^-1 * D]
if A[:,:N] \= eye(N)
then deter(B) == 0
N - number of rows (N <= number of columns)
BTRY - largest value in a row
BNEXT - second largest value in a row
BMAX - ratio of the two largest magnitude values in a row (BNEXT / BTRY)
ID - keeps track of available pivot rows (array)
pivot row - row with the smallest BMAX value (excluding already used pivot rows)
pivot column - max magnitude index in pivot row (excluding already used pivot columns)
'''
Determ = 0.0
ID = np.zeros(N)
for NN in range(N):
#########################################################################################
# Don't quite understand why this is done
#########################################################################################
BMAX = 1.1
# print(A[:,:N])
for I in range(N): # I - row index
if (ID[I] == 0):
BNEXT = 0.0
BTRY = 0.0
for J in range(N): # J - column index
if (ID[J] == 0):
if not(abs(A[I,J]) <= BNEXT): # if (abs(A[I,J]) > BNEXT)):
BNEXT = abs(A[I,J])
if not(BNEXT <= BTRY): # if (BNEXT > BTRY):
BNEXT = BTRY
BTRY = abs(A[I,J])
JC = J
# print('({},{})'.format(I,J), JC, 'BMAX', BMAX, 'BNEXT', BNEXT, 'BTRY', BTRY)
if not(BNEXT >= BMAX*BTRY): # if (BNEXT < BMAX*BTRY):
BMAX = BNEXT/BTRY # if (BNEXT / BTRY < BMAX)
IROW = I
JCOL = JC
#########################################################################################
if (ID[JC] != 0):
DETERM = 0.0
return
# print('ID', ID)
# print("IROW", "JCOL:", IROW, JCOL)
# print('BMAX', BMAX, 'BNEXT', BNEXT, 'BTRY', BTRY)
ID[JCOL] = 1
# else:
# swap rows(JCOL, IROW)
if JCOL != IROW:
A_temp = A[JCOL,:].copy()
A[JCOL,:] = A[IROW,:]
A[IROW,:] = A_temp
# make the leading value 1
A[JCOL, :] /= A[JCOL, JCOL]
# subtract pivot row from all rows BELOW / ABOVE pivot row
for ii in range(N):
if ii == JCOL:
continue
f = A[ii,JCOL]
A[ii,:] -= f * A[JCOL,:]
return A
I'm working to convert some fortran code to python and one of the subroutines is MATINV. I understand the code at a high level:
- input: matrix
Athat is composed of two matricesBandD. MatrixBis N by N and matrixDhas N rows, but can have more columns. - returns
B^-1 * Dusing Gaussian-elimination. (MatrixAis returned asA = [ I | B^-1 * D], whereIis the identity matrix and the relevant portion isA[:,N:])
The part I do not quite understand is marked with hash symbols (#). I understand what the code is doing:
- it is looking for the matrix row with the smallest ratio of
BNEXT/BTRY, whereBNEXTis the value with the second largest magnitude, andBTRYis the value with the largest magnitude (BMAX = BNEXT / BTRY) - The row with with
min(BMAX)is selected as the pivot row
I believe that this conditioning of the pivot rows is done for numerical stability, but the specific numerical theory behind it is not clear to me. The current structure of the code seems a bit nebulous to me, and I think understanding the fundamental idea guiding this algorithm might help me write clearer code. Any insights will be helpful.
Seems to be tailored to a particular class of B matrices. More than preconditioning, the code block seems to be looking for instances when the determinant of B can be zero and terminate gracefully.