def lu(A): """ A -> P, L, U LU factorisation of a square matrix A. L is the lower, U the upper part. P is the permutation matrix indicating the row swaps. P*A = L*U If you need efficiency, use the low-level method LU_decomp instead, it's much more memory efficient. """ # get factorization A, p = LU_decomp(A.copy()) n = A.rows L = matrix(n) U = matrix(n) for i in xrange(n): for j in xrange(n): if i > j: L[i, j] = A[i, j] elif i == j: L[i, j] = 1 U[i, j] = A[i, j] else: U[i, j] = A[i, j] # calculate permutation matrix P = eye(n) for k in xrange(len(p)): swap_row(P, k, p[k]) return P, L, U
def lu(A): """ A -> P, L, U LU factorisation of a square matrix A. L is the lower, U the upper part. P is the permutation matrix indicating the row swaps. P*A = L*U If you need efficiency, use the low-level method LU_decomp instead, it's much more memory efficient. """ # get factorization A, p = LU_decomp(A) n = A.rows L = matrix(n) U = matrix(n) for i in xrange(n): for j in xrange(n): if i > j: L[i,j] = A[i,j] elif i == j: L[i,j] = 1 U[i,j] = A[i,j] else: U[i,j] = A[i,j] # calculate permutation matrix P = eye(n) for k in xrange(len(p)): swap_row(P, k, p[k]) return P, L, U
def L_solve(L, b, p=None): """ Solve the lower part of a LU factorized matrix for y. """ L.rows == L.cols, 'need n*n matrix' n = L.rows assert len(b) == n b = copy(b) if p: # swap b according to p for k in xrange(0, len(p)): swap_row(b, k, p[k]) # solve for i in xrange(1, n): for j in xrange(i): b[i] -= L[i, j] * b[j] return b
def L_solve(L, b, p=None): """ Solve the lower part of a LU factorized matrix for y. """ assert L.rows == L.cols, 'need n*n matrix' n = L.rows assert len(b) == n b = copy(b) if p: # swap b according to p for k in xrange(0, len(p)): swap_row(b, k, p[k]) # solve for i in xrange(1, n): for j in xrange(i): b[i] -= L[i,j] * b[j] return b
def LU_decomp(A, overwrite=False, use_cache=True): """ LU-factorization of a n*n matrix using the Gauss algorithm. Returns L and U in one matrix and the pivot indices. Use overwrite to specify whether A will be overwritten with L and U. """ if not A.rows == A.cols: raise ValueError('need n*n matrix') # get from cache if possible if use_cache and isinstance(A, matrix) and A._LU: return A._LU if not overwrite: orig = A A = A.copy() tol = absmin(mnorm(A,1) * eps) # each pivot element has to be bigger n = A.rows p = [None]*(n - 1) for j in xrange(n - 1): # pivoting, choose max(abs(reciprocal row sum)*abs(pivot element)) biggest = 0 for k in xrange(j, n): s = fsum([absmin(A[k,l]) for l in xrange(j, n)]) if absmin(s) <= tol: raise ZeroDivisionError('matrix is numerically singular') current = 1/s * absmin(A[k,j]) if current > biggest: # TODO: what if equal? biggest = current p[j] = k # swap rows according to p swap_row(A, j, p[j]) if absmin(A[j,j]) <= tol: raise ZeroDivisionError('matrix is numerically singular') # calculate elimination factors and add rows for i in xrange(j + 1, n): A[i,j] /= A[j,j] for k in xrange(j + 1, n): A[i,k] -= A[i,j]*A[j,k] if absmin(A[n - 1,n - 1]) <= tol: raise ZeroDivisionError('matrix is numerically singular') # cache decomposition if not overwrite and isinstance(orig, matrix): orig._LU = (A, p) return A, p