From 4047a43539be76ad838f937051da5f701fcac0c4 Mon Sep 17 00:00:00 2001 From: BhaktiVagadia Date: Thu, 7 May 2026 12:28:33 +0530 Subject: [PATCH 1/3] 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 58596f354608d9e993138a1c43e981b42da7bdf5 Mon Sep 17 00:00:00 2001 From: BhaktiVagadia Date: Thu, 7 May 2026 12:41:29 +0530 Subject: [PATCH 2/3] changes in description and variable --- linear_algebra/qr_decomposition.py | 49 +++++++++++++++--------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/linear_algebra/qr_decomposition.py b/linear_algebra/qr_decomposition.py index a76408c0f4ae..b48fc29d3452 100644 --- a/linear_algebra/qr_decomposition.py +++ b/linear_algebra/qr_decomposition.py @@ -1,6 +1,7 @@ """ -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 +In linear algebra, a QR decomposition, also known as a QR factorization +or Q 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. @@ -14,50 +15,50 @@ import numpy as np from scipy.linalg import qr -def qr_decomposition(A: np.ndarray) -> tuple[np.ndarray, np.ndarray]: +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 + 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 + >>> 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 + >>> 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 + >>> 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 + >>> 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) + >>> 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) + >>> 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) + >>> 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) + rows, columns = np.shape(a) if rows < columns: msg = ( "row size should be greater than column size" @@ -73,13 +74,13 @@ def qr_decomposition(A: np.ndarray) -> tuple[np.ndarray, np.ndarray]: # R: Upper triangular matrix # P: Pivot indices (permutation vector) - Q, R, P = qr(A, pivoting=True) + 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) + # 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" From 010cd47ffefafe6e416eb0f651920f38228a689a 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:17:35 +0000 Subject: [PATCH 3/3] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- linear_algebra/qr_decomposition.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/linear_algebra/qr_decomposition.py b/linear_algebra/qr_decomposition.py index b48fc29d3452..deebd1fac7ed 100644 --- a/linear_algebra/qr_decomposition.py +++ b/linear_algebra/qr_decomposition.py @@ -1,5 +1,5 @@ """ -In linear algebra, a QR decomposition, also known as a QR factorization +In linear algebra, a QR decomposition, also known as a QR factorization or Q factorization, is a decomposition of a matrix a into a product a = QR of an orthonormal matrix Q and an upper triangular matrix R. @@ -15,6 +15,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 @@ -57,17 +58,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 @@ -79,14 +75,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