QR

QR decomposition factors a matrix into an orthogonal (or unitary) component and an upper-triangular component. It is commonly used in least-squares solving and numerical linear algebra workflows.

For a matrix A, the decomposition is:

A = QR

where Q is orthogonal (or unitary) and R is upper triangular.

Excel Usage

=QR(a, return_type)
  • a (list[list], required): Matrix to decompose. Each row must have the same number of columns, and entries must be finite numeric values.
  • return_type (str, optional, default: “Q”): Which matrix factor to return from the QR decomposition.

Returns (list[list]): 2D Q or R matrix, or error message string.

Example 1: Orthogonal factor of a 2x2 matrix

Inputs:

a return_type
1 2 Q
3 4

Excel formula:

=QR({1,2;3,4}, "Q")

Expected output:

Result
-0.316228 -0.948683
-0.948683 0.316228
Example 2: Upper-triangular factor of a 2x2 matrix

Inputs:

a return_type
1 2 R
3 4

Excel formula:

=QR({1,2;3,4}, "R")

Expected output:

Result
-3.16228 -4.42719
0 -0.632456
Example 3: Orthogonal factor of a 3x2 rectangular matrix

Inputs:

a return_type
1 2 Q
3 4
5 6

Excel formula:

=QR({1,2;3,4;5,6}, "Q")

Expected output:

Result
-0.169031 0.897085 0.408248
-0.507093 0.276026 -0.816497
-0.845154 -0.345033 0.408248
Example 4: Upper-triangular factor of a 3x2 rectangular matrix

Inputs:

a return_type
1 2 R
3 4
5 6

Excel formula:

=QR({1,2;3,4;5,6}, "R")

Expected output:

Result
-5.91608 -7.43736
0 0.828079
0 0

Python Code

import numpy as np
from scipy.linalg import qr as scipy_linalg_qr

def qr(a, return_type='Q'):
    """
    Compute the QR decomposition of a matrix and return either Q or R.

    See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.qr.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        a (list[list]): Matrix to decompose. Each row must have the same number of columns, and entries must be finite numeric values.
        return_type (str, optional): Which matrix factor to return from the QR decomposition. Valid options: Q, R. Default is 'Q'.

    Returns:
        list[list]: 2D Q or R matrix, or error message string.
    """
    try:
        def to2d(x):
            return [[x]] if not isinstance(x, list) else x

        # Normalize scalar inputs into a 2D list structure
        a = to2d(a)
        if not isinstance(a[0], list):
            # Handle case where input was a 1D list like [1, 2, 3]
            if all(not isinstance(item, list) for item in a):
                try:
                    a = [[float(item)] for item in a]
                except (TypeError, ValueError):
                    return "Error: Invalid input: a must contain only numeric values."

        # Validate the 2D list structure and ensure consistent row lengths
        if not a or not all(isinstance(row, list) for row in a):
            return "Error: Invalid input: a must be a 2D list with at least one row."
        if any(len(row) == 0 for row in a):
            return "Error: Invalid input: rows in a must contain at least one value."
        column_count = len(a[0])
        if any(len(row) != column_count for row in a):
            return "Error: Invalid input: all rows in a must have the same length."

        # Convert entries to floats and check for finite values
        numeric_rows = []
        for row in a:
            numeric_row = []
            for value in row:
                try:
                    numeric_value = float(value)
                except Exception:
                    return "Error: Invalid input: a must contain only numeric values."
                if not np.isfinite(numeric_value):
                    return "Error: Invalid input: a must contain only finite numbers."
                numeric_row.append(numeric_value)
            numeric_rows.append(numeric_row)

        array = np.array(numeric_rows, dtype=float)

        # Validate return_type and normalize casing
        if not isinstance(return_type, str) or return_type.upper() not in ("Q", "R"):
            return "Error: Invalid input: return_type must be 'Q' or 'R'."
        normalized_return_type = return_type.upper()

        # Compute the QR decomposition
        try:
            q_matrix, r_matrix = scipy_linalg_qr(array, mode="full")
        except Exception as exc:
            return f"Error: QR decomposition error: {exc}"

        result = q_matrix if normalized_return_type == "Q" else r_matrix

        # Ensure the result is finite before returning
        if not np.all(np.isfinite(result)):
            return "Error: QR decomposition error: result contains non-finite values."

        return result.tolist()
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

Matrix to decompose. Each row must have the same number of columns, and entries must be finite numeric values.
Which matrix factor to return from the QR decomposition.