From 4047a43539be76ad838f937051da5f701fcac0c4 Mon Sep 17 00:00:00 2001 From: BhaktiVagadia Date: Thu, 7 May 2026 12:28:33 +0530 Subject: [PATCH 1/2] add QR Decomposition of matrix in linear algebra --- linear_algebra/qr_decomposition.py | 92 ++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 linear_algebra/qr_decomposition.py diff --git a/linear_algebra/qr_decomposition.py b/linear_algebra/qr_decomposition.py new file mode 100644 index 000000000000..a76408c0f4ae --- /dev/null +++ b/linear_algebra/qr_decomposition.py @@ -0,0 +1,92 @@ +""" +In linear algebra, a QR decomposition, also known as a QR factorization or QU factorization, +is a decomposition of a matrix A into a product A = QR +of an orthonormal matrix Q and an upper triangular matrix R. +QR decomposition is often used to solve the linear least squares (LLS) problem +and is the basis for a particular eigenvalue algorithm, the QR algorithm. + +This algorithm will simply attempt to perform QR decomposition on any square matrix. + +Reference: https://en.wikipedia.org/wiki/QR_decomposition +""" + +from __future__ import annotations +import numpy as np +from scipy.linalg import qr + +def qr_decomposition(A: np.ndarray) -> tuple[np.ndarray, np.ndarray]: + """ + Perform QR decomposition on a given matrix and raises an error if in + m×n matrix A if m is smaller than n or m,n is less than 2 + + >>> A = np.array([[1, 2, 3], [4, 5, 9], [7, 8, 15]]) + >>> Q,R = qr_decomposition(A) + >>> Q + array([[-0.17, 0.9 , 0.41], + [-0.51, 0.28, -0.82], + [-0.85, -0.35, 0.41]]) + >>> R + array([[-17.75, -9.63, -8.11], + [ 0. , 0.41, -0.41], + [ 0. , 0. , 0. ]]) + >>> A = np.array([[1, 2], [4, 5], [7, 8]]) + >>> Q,R = qr_decomposition(A) + >>> Q + array([[-0.21, 0.89, 0.41], + [-0.52, 0.25, -0.82], + [-0.83, -0.38, 0.41]]) + >>> R + array([[-9.64, -8.09], + [ 0. , -0.76], + [ 0. , 0. ]]) + >>> A = np.array([[1, 2, 3], [4, 5, 6]]) + >>> Q,R = qr_decomposition(A) + Traceback (most recent call last): + ... + ValueError: row size should be greater than column size + >>> A = np.array([[1], [4]]) + >>> Q,R = qr_decomposition(A) + Traceback (most recent call last): + ... + ValueError: row size and column size should be greater than 2 + >>> A = np.array([[1,4]]) + >>> Q,R = qr_decomposition(A) + Traceback (most recent call last): + ... + ValueError: row size should be greater than column size + """ + + + rows, columns = np.shape(A) + if rows < columns: + msg = ( + "row size should be greater than column size" + ) + raise ValueError(msg) + if rows < 2 or columns < 2: + msg = ( + "row size and column size should be greater than 2" + ) + raise ValueError(msg) + # Perform QR decomposition with pivoting + # Q: Orthogonal matrix + # R: Upper triangular matrix + # P: Pivot indices (permutation vector) + + Q, R, P = qr(A, pivoting=True) + + # Note: The bottom row of R is all zeros because the matrix is rank-deficient. + # Verification: A[:, P] should equal Q @ R + AP = A[:, P] + if(np.allclose(AP, Q @ R)): + return np.round(Q,2), np.round(R,2) + else: + msg = ( + "No matrix found which decompose given matrix" + ) + raise ValueError(msg) + +if __name__ == "__main__": + import doctest + + doctest.testmod() From db844e65e8968a369c5b049c0f08348c0c1f2c77 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 07:02:49 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- linear_algebra/qr_decomposition.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/linear_algebra/qr_decomposition.py b/linear_algebra/qr_decomposition.py index a76408c0f4ae..88c248bd3bfd 100644 --- a/linear_algebra/qr_decomposition.py +++ b/linear_algebra/qr_decomposition.py @@ -14,6 +14,7 @@ import numpy as np from scipy.linalg import qr + def qr_decomposition(A: np.ndarray) -> tuple[np.ndarray, np.ndarray]: """ Perform QR decomposition on a given matrix and raises an error if in @@ -56,17 +57,12 @@ def qr_decomposition(A: np.ndarray) -> tuple[np.ndarray, np.ndarray]: ValueError: row size should be greater than column size """ - rows, columns = np.shape(A) if rows < columns: - msg = ( - "row size should be greater than column size" - ) + msg = "row size should be greater than column size" raise ValueError(msg) if rows < 2 or columns < 2: - msg = ( - "row size and column size should be greater than 2" - ) + msg = "row size and column size should be greater than 2" raise ValueError(msg) # Perform QR decomposition with pivoting # Q: Orthogonal matrix @@ -78,14 +74,13 @@ def qr_decomposition(A: np.ndarray) -> tuple[np.ndarray, np.ndarray]: # Note: The bottom row of R is all zeros because the matrix is rank-deficient. # Verification: A[:, P] should equal Q @ R AP = A[:, P] - if(np.allclose(AP, Q @ R)): - return np.round(Q,2), np.round(R,2) + if np.allclose(AP, Q @ R): + return np.round(Q, 2), np.round(R, 2) else: - msg = ( - "No matrix found which decompose given matrix" - ) + msg = "No matrix found which decompose given matrix" raise ValueError(msg) + if __name__ == "__main__": import doctest