Created
September 17, 2021 11:14
-
-
Save PolarNick239/57763c464d2930e531d109a0c25b2e0d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import scipy | |
import scipy.linalg | |
def ensure_close(P, A): | |
eps = np.max(np.abs(P)) * 10e-10 | |
assert(np.max(np.abs(P - A)) <= eps) | |
def qr_decomposition_np(A): | |
Q, R = np.linalg.qr(A) | |
ensure_close(A, Q @ R) | |
return Q, R | |
def qr_decomposition_my(A): | |
n, m = A.shape | |
# Gram–Schmidt process | |
# https://en.wikipedia.org/wiki/QR_decomposition#Using_the_Gram%E2%80%93Schmidt_process | |
Q, R = np.zeros((n, n), np.float64), np.zeros((n, m), np.float64) | |
Q[:, 0] = A[:, 0] / np.linalg.norm(A[:, 0]) | |
Q[:, 1] = A[:, 1] - np.dot(Q[:, 0], A[:, 1]) * Q[:, 0] | |
Q[:, 1] = Q[:, 1] / np.linalg.norm(Q[:, 1]) | |
R = Q.transpose() @ A | |
R[1, 0] = 0 | |
ensure_close(A, Q @ R) | |
return Q, R | |
def rq_decomposition_scipy(A): | |
R, Q = scipy.linalg.rq(A, mode='economic') | |
ensure_close(A, R @ Q) | |
return R, Q | |
def rq_decomposition_my(A): | |
A2 = A[::-1].transpose() | |
Q2, R2 = qr_decomposition_my(A2) | |
Q = Q2.transpose()[::-1] | |
R = (R2.transpose())[::-1][:, ::-1] | |
ensure_close(A, R @ Q) | |
# Mimicking mode='economic' https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.rq.html | |
m, n = A.shape | |
assert(Q.shape == (n, n)) | |
assert(R.shape == (m, n)) | |
k = min(m, n) | |
R = R[:, n-k:] | |
Q = Q[n-k:, :] | |
assert(Q.shape == (k, n)) | |
assert(R.shape == (m, k)) | |
ensure_close(A, R @ Q) | |
return R, Q | |
P = np.array([ | |
[1.95397, -0.0048056, -0.323478, 18145.2], | |
[0.0196696, -1.99207, 0.165801, 31412.1], | |
[0, 0, 0, 1] | |
])[:2, :3] | |
print("P={}".format(P)) | |
assert(P.shape == (2, 3)) | |
# P=[[ 1.95397 -0.0048056 -0.323478 ] | |
# [ 0.0196696 -1.99207 0.165801 ]] | |
# QR decomposition | |
Q, R = qr_decomposition_np(P) | |
print("numpy P=QR:") | |
print("Q={}".format(Q)) | |
print("R={}".format(R)) | |
print("max error in (P-Q@R): {}".format(np.max(np.abs(P - Q @ R)))) | |
print() | |
Q, R = qr_decomposition_my(P) | |
print("my P=QR:") | |
print("Q={}".format(Q)) | |
print("R={}".format(R)) | |
print("max error in (P-Q@R): {}".format(np.max(np.abs(P - Q @ R)))) | |
# numpy P=QR: | |
# Q=[[-0.99994934 -0.01006597] | |
# [-0.01006597 0.99994934]] | |
# R=[[-1.954069 0.02485747 0.32179266] | |
# [ 0. -1.9919207 0.16904872]] | |
# max error in (P-Q@R): 1.734723475976807e-18 | |
# my P=QR: | |
# Q=[[ 0.99994934 0.01006597] | |
# [ 0.01006597 -0.99994934]] | |
# R=[[ 1.954069 -0.02485747 -0.32179266] | |
# [ 0. 1.9919207 -0.16904872]] | |
# max error in (P-Q@R): 1.734723475976807e-18 | |
# RQ decomposition | |
R, Q = rq_decomposition_scipy(P) | |
print("scipy P=RQ:") | |
print("R={}".format(R)) | |
print("Q={}".format(Q)) | |
print("max error in (P-R@Q): {}".format(np.max(np.abs(P - R @ Q)))) | |
print() | |
R, Q = rq_decomposition_my(P) | |
print("my P=RQ (via P=QR):") | |
print("R={}".format(R)) | |
print("Q={}".format(Q)) | |
print("max error in (P-R@Q): {}".format(np.max(np.abs(P - R @ Q)))) | |
# scipy P=RQ: | |
# R=[[ 1.98056859 0.00281437] | |
# [ 0. -1.99905471]] | |
# Q=[[ 0.98658421 -0.0038424 -0.16320797] | |
# [-0.00983945 0.99650599 -0.0829397 ]] | |
# max error in (P-R@Q): 2.220446049250313e-16 | |
# my P=RQ (via P=QR): | |
# R=[[ 1.98056859 -0.00281437] | |
# [ 0. 1.99905471]] | |
# Q=[[ 0.98658421 -0.0038424 -0.16320797] | |
# [ 0.00983945 -0.99650599 0.0829397 ]] | |
# max error in (P-R@Q): 2.220446049250313e-16 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment