def lstsq(A, b): """ Solves the linear system of equations Ax = b by computing a vector x that minimizes the Euclidean norm ||b - Ax||^2. Concretely, uses the QR decomposition of A to deal with an over or well determined system. Params ------ - A: a numpy array of shape (M, N). - b: a numpy array of shape (M,). Returns: - x: a numpy array of shape (N, ). """ M, N = A.shape # if well-determined, use PLU if (M == N): solver = LU(A, pivoting='partial') else: solver = QR(A) # solve for x x = solver.solve(b) return x
def test_solve_multi_reduce(self): A = np.random.randn(100, 60) b = np.random.randn(100, 10) actual = QR(A, reduce=True).solve(b) expected = LA.lstsq(A, b)[0] self.assertTrue(np.allclose(actual, expected))
def test_solve_single_complete(self): A = np.random.randn(100, 60) b = np.random.randn(100) actual = QR(A, reduce=False).solve(b) expected = LA.lstsq(A, b)[0] self.assertTrue(np.allclose(actual, expected))
def test_householder_reduce(self): T = np.random.randn(100, 60) actual = QR(T, reduce=True).householder() expected = LA.qr(T, mode='reduced') self.assertTrue( all(np.allclose(a, e) for a, e in zip(actual, expected)) )
def test_gram_schmidt(self): T = np.random.randn(100, 60) actual = QR(T).gram_schmidt() Q, R = LA.qr(T) # enforce uniqueness for numpy version D = create_diag(np.sign(diag(R))) Q = np.dot(Q, D) R = np.dot(D, R) expected = (Q, R) self.assertTrue( all(np.allclose(a, e) for a, e in zip(actual, expected)) )