TheAlgorithms-Python
71 строка · 2.1 Кб
1import numpy as np2
3
4def qr_householder(a: np.ndarray):5"""Return a QR-decomposition of the matrix A using Householder reflection.6
7The QR-decomposition decomposes the matrix A of shape (m, n) into an
8orthogonal matrix Q of shape (m, m) and an upper triangular matrix R of
9shape (m, n). Note that the matrix A does not have to be square. This
10method of decomposing A uses the Householder reflection, which is
11numerically stable and of complexity O(n^3).
12
13https://en.wikipedia.org/wiki/QR_decomposition#Using_Householder_reflections
14
15Arguments:
16A -- a numpy.ndarray of shape (m, n)
17
18Note: several optimizations can be made for numeric efficiency, but this is
19intended to demonstrate how it would be represented in a mathematics
20textbook. In cases where efficiency is particularly important, an optimized
21version from BLAS should be used.
22
23>>> A = np.array([[12, -51, 4], [6, 167, -68], [-4, 24, -41]], dtype=float)
24>>> Q, R = qr_householder(A)
25
26>>> # check that the decomposition is correct
27>>> np.allclose(Q@R, A)
28True
29
30>>> # check that Q is orthogonal
31>>> np.allclose(Q@Q.T, np.eye(A.shape[0]))
32True
33>>> np.allclose(Q.T@Q, np.eye(A.shape[0]))
34True
35
36>>> # check that R is upper triangular
37>>> np.allclose(np.triu(R), R)
38True
39"""
40m, n = a.shape41t = min(m, n)42q = np.eye(m)43r = a.copy()44
45for k in range(t - 1):46# select a column of modified matrix A':47x = r[k:, [k]]48# construct first basis vector49e1 = np.zeros_like(x)50e1[0] = 1.051# determine scaling factor52alpha = np.linalg.norm(x)53# construct vector v for Householder reflection54v = x + np.sign(x[0]) * alpha * e155v /= np.linalg.norm(v)56
57# construct the Householder matrix58q_k = np.eye(m - k) - 2.0 * v @ v.T59# pad with ones and zeros as necessary60q_k = np.block([[np.eye(k), np.zeros((k, m - k))], [np.zeros((m - k, k)), q_k]])61
62q = q @ q_k.T63r = q_k @ r64
65return q, r66
67
68if __name__ == "__main__":69import doctest70
71doctest.testmod()72