Copyright (C) 2021 Andreas Kloeckner
import numpy as np
import numpy.linalg as la
np.set_printoptions(linewidth=150, suppress=True, precision=3)
n = 5
np.random.seed(235)
A = np.random.randn(n, n)
A[0,0] = 0
A
This function returns a matrix that swas rows i
and j
:
def row_swap_mat(i, j):
P = np.eye(n)
P[i] = 0
P[j] = 0
P[i, j] = 1
P[j, i] = 1
return P
We're trying to obtain $PA=LU$. Initialize:
i = 0
I = np.eye(n)
P = I.copy()
Lsub = np.zeros_like(A)
U = np.zeros_like(A)
remaining = A.copy()
remaining
First, find the pivot as ipiv
:
#clear
ipiv = i + np.argmax(np.abs(remaining[i:, i]))
ipiv
Swap the rows in remaining
, record in P
:
#clear
swap_mat = row_swap_mat(i, ipiv)
P = swap_mat @ P
remaining = swap_mat @ remaining
remaining
Now carry out a step of LU, as above:
U[i, i:] = remaining[i, i:]
Lsub[i+1:,i] = remaining[i+1:,i]/U[i,i]
remaining[i+1:, i+1:] -= np.outer(Lsub[i+1:,i], U[i, i+1:])
i = i + 1
print(P@A-(Lsub+I)@U)
Find the pivot and perform the swaps so that you still have a valid $PA=LU$ factorization:
#clear
ipiv = i + np.argmax(np.abs(remaining[i:, i]))
swap_mat = row_swap_mat(i, ipiv)
P = swap_mat @ P
Lsub = swap_mat @ Lsub
remaining = swap_mat @ remaining
Here are some checks to make sure you're on the right track:
print("Should maintain the same 'zero fringe' as the previous step:")
print(P @ A - (Lsub+I) @ U)
print("Should be zero:")
print(remaining[i:, i:] - (P @ A - (Lsub+I) @ U)[i:, i:])
Carry out a step of LU, as always:
U[i, i:] = remaining[i, i:]
Lsub[i+1:,i] = remaining[i+1:,i]/U[i,i]
remaining[i+1:, i+1:] -= np.outer(Lsub[i+1:,i], U[i, i+1:])
i = i + 1
print(P@A-(Lsub+I)@U)
P
I+Lsub
U
Lsub
instead of all of L
?