def decompose(self): """Compute the SVD in 2 steps: 1. Compute the eigenvalue decomposition of `A.T @ A` using the QR algorithm. From this decomposition, we can derive V and and Σ. 2. Solve the system `UΣ = AV` for U using a QR factorization. This algorithm isn't usually used in practice because of its sensitivity to the gram matrix `A.T @ A`. Returns: U: A numpy array of shape (M, M) S: A numpy array of shape (M, N). V: A numpy array of shape (N, N). """ A = np.array(self.backup) M, N = A.shape eigvals, V = qr_algorithm(A.T @ A) S = create_diag(np.sqrt(eigvals), (M, N)) U = QR(S.T, reduce=False).solve(V.T @ A.T) U = U.T return U, S, V
def test_qr_algorithm_with_hessenberg(self): M = random_symmetric(4) eigvals, eigvecs = LA.eig(M) idx = np.abs(eigvals).argsort()[::-1] expected_eigvecs = eigvecs[:, idx] expected_eigvals = eigvals[idx] actual_eigvals, actual_eigvecs = multi.qr_algorithm(M) self.assertTrue(self.absallclose(actual_eigvecs, expected_eigvecs)) self.assertTrue(self.absallclose(actual_eigvals, expected_eigvals))
"""QR algorithm vs projected iteration. """ import time import numpy as np import numpy.linalg as LA from linalg.eigen import multi from linalg import utils if __name__ == "__main__": M = utils.random_spd(10) tic = time.time() eigvals, eigvecs = multi.qr_algorithm(M, hess=False) toc = time.time() time_qr = toc - tic print("QR: {}s".format(time_qr)) tic = time.time() eigvals, eigvecs = multi.projected_iteration(M, len(M)) toc = time.time() time_proj = toc - tic print("Projected Iteration: {}s".format(time_proj))
Specifically, the QR decomposition doesn't take advantage of the Hessenberg form by skipping row elements that are already zero when applying reflectors to each column of the matrix. """ import time import numpy as np import scipy.linalg as LA from linalg.eigen import multi from linalg import utils if __name__ == "__main__": M = utils.random_spd(10) tic = time.time() eigvals, eigvecs = multi.qr_algorithm(LA.hessenberg(M), hess=False) toc = time.time() time_with_hess = toc - tic print("With hessenberg: {}s".format(time_with_hess)) tic = time.time() eigvals, eigvecs = multi.qr_algorithm(M, hess=False) toc = time.time() time_without_hess = toc - tic print("Without hessenberg: {}s".format(time_without_hess)) speedup = time_without_hess / time_with_hess print("Speedup: {}x".format(speedup))