230 KiB
230 KiB
In [1]:
import numpy as np
# SVD inversion
def SVD(A):
''' Takes as input a numpy matrix A and returns inv(A) based on singular value decomposition (SVD).
SVD is numerically more stable than the inversion algorithms provided by
numpy and scipy.linalg at the cost of being slower.
'''
U, S, VT = np.linalg.svd(A,full_matrices=True)
print('test U')
print( (np.transpose(U) @ U - U @np.transpose(U)))
print('test VT')
print( (np.transpose(VT) @ VT - VT @np.transpose(VT)))
print(U)
print(S)
print(VT)
D = np.zeros((len(U),len(VT)))
for i in range(0,len(VT)):
D[i,i]=S[i]
return U @ D @ VT
X = np.array([ [1.0,-1.0], [1.0,-1.0]])
#X = np.array([[1, 2], [3, 4], [5, 6]])
print(X)
C = SVD(X)
# Print the difference between the original matrix and the SVD one
print(C-X)[[ 1. -1.] [ 1. -1.]] test U [[0. 0.] [0. 0.]] test VT [[0. 0.] [0. 0.]] [[-0.70710678 -0.70710678] [-0.70710678 0.70710678]] [2.00000000e+00 3.35470445e-17] [[-0.70710678 0.70710678] [ 0.70710678 0.70710678]] [[-3.33066907e-16 4.44089210e-16] [ 0.00000000e+00 2.22044605e-16]]
In [2]:
#Ainv = np.linlag.pinv(A)In [3]:
import numpy as np
# SVD inversion
def SVDinv(A):
''' Takes as input a numpy matrix A and returns inv(A) based on singular value decomposition (SVD).
SVD is numerically more stable than the inversion algorithms provided by
numpy and scipy.linalg at the cost of being slower.
'''
U, s, VT = np.linalg.svd(A)
print('test U')
print( (np.transpose(U) @ U - U @np.transpose(U)))
print('test VT')
print( (np.transpose(VT) @ VT - VT @np.transpose(VT)))
D = np.zeros((len(U),len(VT)))
D = np.diag(s)
UT = np.transpose(U); V = np.transpose(VT); invD = np.linalg.inv(D)
return np.matmul(V,np.matmul(invD,UT))
#X = np.array([ [1.0, -1.0, 2.0], [1.0, 0.0, 1.0], [1.0, 2.0, -1.0], [1.0, 1.0, 0.0] ])
# Non-singular square matrix
X = np.array( [ [1,2,3],[2,4,5],[3,5,6]])
print(X)
A = np.transpose(X) @ X
# Brute force inversion
B = np.linalg.pinv(A) # here we could use np.linalg.inv(A), try it!
C = SVDinv(A)
print(np.abs(B-C))[[1 2 3] [2 4 5] [3 5 6]] test U [[ 4.44089210e-16 -4.69484813e-16 -6.67314874e-16] [-4.69484813e-16 -4.44089210e-16 -1.54041041e-16] [-6.67314874e-16 -1.54041041e-16 1.11022302e-16]] test VT [[ 2.22044605e-16 3.78156479e-17 1.85278920e-16] [ 3.78156479e-17 0.00000000e+00 -6.33166055e-17] [ 1.85278920e-16 -6.33166055e-17 -1.11022302e-16]] [[0. 0. 0.] [0. 0. 0.] [0. 0. 0.]]
In [4]:
import numpy as np
# SVD inversion
def SVDinv(A):
U, s, VT = np.linalg.svd(A)
# reciprocals of singular values of s
d = 1.0 / s
# create m x n D matrix
D = np.zeros(A.shape)
# populate D with n x n diagonal matrix
D[:A.shape[1], :A.shape[1]] = np.diag(d)
UT = np.transpose(U)
V = np.transpose(VT)
return np.matmul(V,np.matmul(D.T,UT))
A = np.array([ [0.3, 0.4], [0.5, 0.6], [0.7, 0.8],[0.9, 1.0]])
print(A)
# Brute force inversion of super-collinear matrix
B = np.linalg.pinv(A)
print(B)
# Compare our own algorithm with pinv
C = SVDinv(A)
print(np.abs(C-B))[[0.3 0.4] [0.5 0.6] [0.7 0.8] [0.9 1. ]] [[-13. -6. 1. 8. ] [ 11.5 5.5 -0.5 -6.5]] [[0. 0. 0. 0.] [0. 0. 0. 0.]]
Warning:
Output truncated. This notebook contains too many cells to display efficiently.