Skip to content

Instantly share code, notes, and snippets.

@PolarNick239
Created September 17, 2021 11:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PolarNick239/57763c464d2930e531d109a0c25b2e0d to your computer and use it in GitHub Desktop.
Save PolarNick239/57763c464d2930e531d109a0c25b2e0d to your computer and use it in GitHub Desktop.
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