Decompositions

Overview

Matrix decomposition is the process of expressing a matrix as a product of structured factors that are easier to analyze, invert, or solve against. In numerical computing, decompositions are the backbone of stable algorithms for linear systems, least-squares fitting, eigenvalue workflows, dimensionality reduction, and matrix function evaluation. Rather than operating directly on a dense matrix A, decomposition methods expose geometric and algebraic structure such as orthogonality, triangular form, or singular directions. This structure improves both computational efficiency and numerical robustness in data science, optimization, and scientific engineering.

The unifying idea is to rewrite A so that expensive operations become cheap on the factors. For example, triangular factors support fast substitution, orthogonal/unitary factors preserve norms and reduce error amplification, and diagonal-like factors reveal spectral content. Common identities include A=PLU, A=QR, and A=U\Sigma V^*, each emphasizing a different property of the same linear map. In practice, factorization choice depends on matrix properties: symmetry, definiteness, conditioning, sparsity, and whether the goal is solving, compression, or eigen-analysis.

These tools are implemented with SciPy Linear Algebra, especially routines from scipy.linalg, with NumPy arrays as the underlying data model. SciPy wraps mature LAPACK/BLAS kernels, providing well-tested, high-performance decompositions suitable for both teaching examples and production numerical pipelines.

For positive-definite and general system solving, CHOLESKY, LDL, and LU provide complementary triangular factorizations. CHOLESKY is typically the fastest and most stable option for symmetric positive-definite matrices because it exploits symmetry and avoids pivoting in well-behaved cases. LDL extends triangular-style factorization to symmetric (or Hermitian) matrices that may be indefinite, separating scaling/sign information into the block-diagonal D. LU is the broad-purpose workhorse for generic square systems via permutation and triangular factors, and it is widely used in direct solvers, determinant workflows, and condition diagnostics.

For orthogonal reductions and eigenvalue-oriented workflows, QR, HESSENBERG, and SCHUR are tightly connected. QR decomposes a matrix into an orthogonal/unitary basis and an upper-triangular factor, making it central to least-squares problems and numerically stable basis construction. HESSENBERG reduces a dense matrix to near-triangular form as a standard preprocessing step before iterative eigenvalue methods. SCHUR then represents a matrix as A=ZTZ^* with quasi-triangular T, giving a numerically robust alternative to explicit diagonalization for spectral computations and matrix functions.

For geometric decomposition and low-rank structure, POLAR and SVD expose complementary views of matrix action. POLAR splits A into a unitary/orthogonal factor and a positive-semidefinite factor, separating pure rotation/reflection from stretch and making it useful in continuum mechanics, computer vision, and shape analysis. SVD provides the canonical decomposition A=U\Sigma V^*, directly ranking latent directions by singular values and enabling denoising, PCA-style compression, pseudoinverse construction, and ill-posed inverse problem regularization. Together, these methods support both interpretable modeling and numerically controlled approximations across modern linear-algebra-heavy applications.

CHOLESKY

The Cholesky decomposition factors a symmetric positive-definite matrix into a product of a lower-triangular matrix and its transpose. It is a numerically efficient method for solving linear systems and for computing matrix square roots.

For a matrix A, the decomposition yields:

A = LL^T \qquad \text{or} \qquad A = U^TU

depending on whether the lower or upper triangular factor is requested.

Excel Usage

=CHOLESKY(matrix, lower)
  • matrix (list[list], required): Real symmetric positive-definite matrix to factor (must be square)
  • lower (bool, optional, default: false): If TRUE, return lower-triangular factor L; if FALSE, return upper-triangular factor U

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

Example 1: Lower-triangular Cholesky factor of 2x2 matrix

Inputs:

matrix lower
4 12 true
12 37

Excel formula:

=CHOLESKY({4,12;12,37}, TRUE)

Expected output:

Result
2 0
6 1
Example 2: Upper-triangular Cholesky factor of 2x2 matrix

Inputs:

matrix lower
4 12 false
12 37

Excel formula:

=CHOLESKY({4,12;12,37}, FALSE)

Expected output:

Result
2 6
0 1
Example 3: Lower-triangular Cholesky factor of 3x3 matrix

Inputs:

matrix lower
25 15 -5 true
15 18 0
-5 0 11

Excel formula:

=CHOLESKY({25,15,-5;15,18,0;-5,0,11}, TRUE)

Expected output:

Result
5 0 0
3 3 0
-1 1 3
Example 4: Non-trivial 3x3 matrix with irrational entries

Inputs:

matrix lower
9 -6 3 true
-6 8 -2
3 -2 3

Excel formula:

=CHOLESKY({9,-6,3;-6,8,-2;3,-2,3}, TRUE)

Expected output:

Result
3 0 0
-2 2 0
1 0 1.41421

Python Code

Show Code
import numpy as np
from scipy.linalg import cholesky as scipy_cholesky

def cholesky(matrix, lower=False):
    """
    Compute the Cholesky decomposition of a real, symmetric positive-definite matrix.

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

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

    Args:
        matrix (list[list]): Real symmetric positive-definite matrix to factor (must be square)
        lower (bool, optional): If TRUE, return lower-triangular factor L; if FALSE, return upper-triangular factor U Default is False.

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

        # Normalize input to ensure it's a 2D list
        matrix = to2d(matrix)

        # Validate matrix structure: must be a non-empty 2D list
        if not isinstance(matrix, list) or not matrix:
            return "Error: Invalid input: matrix must be a 2D list with at least one row."
        if any(not isinstance(row, list) for row in matrix):
            return "Error: Invalid input: matrix must be a 2D list with at least one row."

        # Validate matrix is square (n x n)
        n = len(matrix)
        if any(len(row) != n for row in matrix):
            return "Error: Invalid input: matrix must be square (n x n)."

        # Convert matrix entries to numeric values
        numeric_rows = []
        for row in matrix:
            numeric_row = []
            for value in row:
                try:
                    numeric_row.append(float(value))
                except (ValueError, TypeError):
                    return "Error: Invalid input: matrix entries must be numeric values."
            numeric_rows.append(numeric_row)

        # Convert to numpy array and validate numeric properties
        arr = np.array(numeric_rows, dtype=np.float64)
        if not np.isfinite(arr).all():
            return "Error: Invalid input: matrix entries must be finite numbers."

        # Verify symmetry (required for Cholesky decomposition)
        if not np.allclose(arr, arr.T, atol=1e-9):
            return "Error: Invalid input: matrix must be symmetric."

        real_matrix = arr

        # Parse and normalize the 'lower' parameter from Excel-friendly inputs
        if isinstance(lower, list):
            return "Error: Invalid input: lower must be a scalar value."
        if isinstance(lower, str):
            lower_normalized = lower.strip().lower()
            if lower_normalized in ("true", "1", "yes"):
                lower_flag = True
            elif lower_normalized in ("false", "0", "no", ""):
                lower_flag = False
            else:
                return "Error: Invalid input: lower must be TRUE or FALSE."
        elif isinstance(lower, (bool, int, float)):
            lower_flag = bool(lower)
        elif lower is None:
            lower_flag = False
        else:
            return "Error: Invalid input: lower must be TRUE or FALSE."

        try:
            # Perform Cholesky decomposition using SciPy
            result = scipy_cholesky(real_matrix, lower=lower_flag)
        except np.linalg.LinAlgError:
            return "Error: Matrix is not positive-definite."
        except Exception:
            return "Error: Failed to compute Cholesky decomposition."

        # Convert result to Python list format
        result_matrix = []
        for row in result:
            result_row = []
            for value in row:
                real_value = float(value)
                if not np.isfinite(real_value):
                    return "Error: Result contains non-finite values."
                result_row.append(real_value)
            result_matrix.append(result_row)

        return result_matrix
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

Real symmetric positive-definite matrix to factor (must be square)
If TRUE, return lower-triangular factor L; if FALSE, return upper-triangular factor U

HESSENBERG

The Hessenberg decomposition factors a square matrix A into a unitary matrix Q and a Hessenberg matrix H.

Excel Usage

=HESSENBERG(matrix, hess_ret_type)
  • matrix (list[list], required): Square 2D array of numeric values to decompose.
  • hess_ret_type (str, optional, default: “h”): The component of the decomposition to return.

Returns (list[list]): 2D array representing the requested component (H or Q).

Example 1: Hessenberg form H of 4x4 matrix

Inputs:

matrix hess_ret_type
2 5 8 7 h
5 2 2 8
7 5 6 6
5 4 4 8

Excel formula:

=HESSENBERG({2,5,8,7;5,2,2,8;7,5,6,6;5,4,4,8}, "h")

Expected output:

Result
2 -11.6584 1.42005 0.253491
-9.94987 14.5354 -5.31022 2.43082
0 -1.83299 0.3897 -0.51527
0 0 -3.8319 1.07495
Example 2: Transformation matrix Q

Inputs:

matrix hess_ret_type
2 5 8 7 q
5 2 2 8
7 5 6 6
5 4 4 8

Excel formula:

=HESSENBERG({2,5,8,7;5,2,2,8;7,5,6,6;5,4,4,8}, "q")

Expected output:

Result
1 0 0 0
0 -0.502519 -0.475751 -0.721897
0 -0.703526 -0.260306 0.66128
0 -0.502519 0.84018 -0.203895

Python Code

Show Code
import numpy as np
from scipy.linalg import hessenberg as scipy_hessenberg

def hessenberg(matrix, hess_ret_type='h'):
    """
    Compute Hessenberg form of a matrix.

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

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

    Args:
        matrix (list[list]): Square 2D array of numeric values to decompose.
        hess_ret_type (str, optional): The component of the decomposition to return. Valid options: Hessenberg Form (H), Transformation Matrix (Q). Default is 'h'.

    Returns:
        list[list]: 2D array representing the requested component (H or Q).
    """
    try:
        def to2d(x):
            return [[x]] if not isinstance(x, list) else x

        matrix = to2d(matrix)

        if not isinstance(matrix, list) or not matrix or not all(isinstance(row, list) for row in matrix):
            return "Error: matrix must be a non-empty 2D list"

        n = len(matrix)
        if any(len(row) != n for row in matrix):
            return "Error: matrix must be square (n x n)"

        try:
            a = np.array(matrix, dtype=float)
        except (ValueError, TypeError):
            return "Error: matrix must contain numeric values"

        if not np.all(np.isfinite(a)):
            return "Error: matrix must contain only finite numbers"

        try:
            if hess_ret_type.lower() == "q":
                h, q = scipy_hessenberg(a, calc_q=True)
                return q.tolist()
            else:
                h = scipy_hessenberg(a, calc_q=False)
                return h.tolist()
        except Exception as e:
            return f"Error: {str(e)}"

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

Online Calculator

Square 2D array of numeric values to decompose.
The component of the decomposition to return.

LDL

The LDL factorization factors a symmetric matrix A into a unit lower triangular matrix L, a block diagonal matrix D, and a permutation matrix P.

Excel Usage

=LDL(matrix, lower, ldl_ret_type)
  • matrix (list[list], required): Square symmetric 2D array of numeric values to decompose.
  • lower (bool, optional, default: true): If TRUE, compute the lower triangular factor; if FALSE, use the upper part.
  • ldl_ret_type (str, optional, default: “d”): The component of the decomposition to return.

Returns (list[list]): 2D array representing the requested component (LU, D, or perm).

Example 1: Block diagonal matrix D

Inputs:

matrix ldl_ret_type
2 -1 3 d
-1 2 0
3 0 1

Excel formula:

=LDL({2,-1,3;-1,2,0;3,0,1}, "d")

Expected output:

Result
2 0 0
0 1.5 0
0 0 -5
Example 2: Triangular factor matrix LU

Inputs:

matrix ldl_ret_type
2 -1 3 lu
-1 2 0
3 0 1

Excel formula:

=LDL({2,-1,3;-1,2,0;3,0,1}, "lu")

Expected output:

Result
1 0 0
-0.5 1 0
1.5 1 1
Example 3: Permutation indices

Inputs:

matrix ldl_ret_type
2 -1 3 perm
-1 2 0
3 0 1

Excel formula:

=LDL({2,-1,3;-1,2,0;3,0,1}, "perm")

Expected output:

Result
0 1 2

Python Code

Show Code
import numpy as np
from scipy.linalg import ldl as scipy_ldl

def ldl(matrix, lower=True, ldl_ret_type='d'):
    """
    Compute the LDLt or Bunch-Kaufman factorization of a symmetric matrix.

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

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

    Args:
        matrix (list[list]): Square symmetric 2D array of numeric values to decompose.
        lower (bool, optional): If TRUE, compute the lower triangular factor; if FALSE, use the upper part. Default is True.
        ldl_ret_type (str, optional): The component of the decomposition to return. Valid options: Triangular Factor (L/U), Block Diagonal (D), Permutation (perm). Default is 'd'.

    Returns:
        list[list]: 2D array representing the requested component (LU, D, or perm).
    """
    try:
        def to2d(x):
            return [[x]] if not isinstance(x, list) else x

        matrix = to2d(matrix)

        if not isinstance(matrix, list) or not matrix or not all(isinstance(row, list) for row in matrix):
            return "Error: matrix must be a non-empty 2D list"

        n = len(matrix)
        if any(len(row) != n for row in matrix):
            return "Error: matrix must be square (n x n)"

        try:
            a = np.array(matrix, dtype=float)
        except (ValueError, TypeError):
            return "Error: matrix must contain numeric values"

        if not np.all(np.isfinite(a)):
            return "Error: matrix must contain only finite numbers"

        try:
            lu, d, perm = scipy_ldl(a, lower=lower)
        except Exception as e:
            return f"Error: {str(e)}"

        rt = ldl_ret_type.lower()
        if rt == "lu":
            return lu.tolist()
        elif rt == "d":
            return d.tolist()
        else:
            return [perm.tolist()]

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

Online Calculator

Square symmetric 2D array of numeric values to decompose.
If TRUE, compute the lower triangular factor; if FALSE, use the upper part.
The component of the decomposition to return.

LU

The LU decomposition factors a matrix A into the product of a permutation matrix P, a lower triangular matrix L (with unit diagonal), and an upper triangular matrix U:

A = PLU

If permute_l is set to TRUE, the function returns a permuted lower triangular matrix L' such that A = L'U.

Excel Usage

=LU(matrix, permute_l, lu_ret_type)
  • matrix (list[list], required): 2D array of numeric values to decompose.
  • permute_l (bool, optional, default: false): If TRUE, return a permuted L matrix satisfying A = LU.
  • lu_ret_type (str, optional, default: “u”): The component of the decomposition to return.

Returns (list[list]): 2D array representing the requested component (P, L, U, or PL).

Example 1: Upper triangular matrix of 2x2

Inputs:

matrix lu_ret_type
1 2 u
3 4

Excel formula:

=LU({1,2;3,4}, "u")

Expected output:

Result
3 4
0 0.666667
Example 2: Lower triangular matrix of 2x2

Inputs:

matrix lu_ret_type
1 2 l
3 4

Excel formula:

=LU({1,2;3,4}, "l")

Expected output:

Result
1 0
0.333333 1
Example 3: Permutation matrix of 2x2

Inputs:

matrix lu_ret_type
1 2 p
3 4

Excel formula:

=LU({1,2;3,4}, "p")

Expected output:

Result
0 1
1 0
Example 4: Permuted L matrix

Inputs:

matrix permute_l lu_ret_type
1 2 true pl
3 4

Excel formula:

=LU({1,2;3,4}, TRUE, "pl")

Expected output:

Result
0.333333 1
1 0

Python Code

Show Code
import numpy as np
from scipy.linalg import lu as scipy_lu

def lu(matrix, permute_l=False, lu_ret_type='u'):
    """
    Compute LU decomposition of a matrix with partial pivoting.

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

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

    Args:
        matrix (list[list]): 2D array of numeric values to decompose.
        permute_l (bool, optional): If TRUE, return a permuted L matrix satisfying A = LU. Default is False.
        lu_ret_type (str, optional): The component of the decomposition to return. Valid options: Permutation Matrix (P), Lower Triangular (L), Upper Triangular (U), Permuted L (PL). Default is 'u'.

    Returns:
        list[list]: 2D array representing the requested component (P, L, U, or PL).
    """
    try:
        def to2d(x):
            return [[x]] if not isinstance(x, list) else x

        matrix = to2d(matrix)

        if not isinstance(matrix, list) or not matrix or not all(isinstance(row, list) for row in matrix):
            return "Error: matrix must be a non-empty 2D list"

        n_rows = len(matrix)
        n_cols = len(matrix[0])
        if n_cols == 0 or any(len(row) != n_cols for row in matrix):
            return "Error: All rows must have the same non-zero length"

        try:
            a = np.array(matrix, dtype=float)
        except (ValueError, TypeError):
            return "Error: matrix must contain numeric values"

        if not np.all(np.isfinite(a)):
            return "Error: matrix must contain only finite numbers"

        try:
            if permute_l:
                pl, u = scipy_lu(a, permute_l=True)
            else:
                p, l, u = scipy_lu(a, permute_l=False)
        except Exception as e:
            return f"Error: {str(e)}"

        rt = lu_ret_type.lower()
        if permute_l:
            if rt == "pl":
                return pl.tolist()
            elif rt == "u":
                return u.tolist()
            else:
                return "Error: With permute_l=TRUE, return_type must be 'pl' or 'u'"
        else:
            if rt == "p":
                return p.tolist()
            elif rt == "l":
                return l.tolist()
            elif rt == "u":
                return u.tolist()
            else:
                return "Error: With permute_l=FALSE, return_type must be 'p', 'l', or 'u'"

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

Online Calculator

2D array of numeric values to decompose.
If TRUE, return a permuted L matrix satisfying A = LU.
The component of the decomposition to return.

POLAR

The polar decomposition factors a matrix A into the product of an orthonormal matrix U and a positive semidefinite Hermitian matrix P.

Excel Usage

=POLAR(matrix, polar_side, polar_ret_type)
  • matrix (list[list], required): 2D array of numeric values to decompose.
  • polar_side (str, optional, default: “right”): Determines whether a right (A=UP) or left (A=PU) polar decomposition is computed.
  • polar_ret_type (str, optional, default: “u”): The component of the decomposition to return.

Returns (list[list]): 2D array representing the requested component (U or P).

Example 1: Unitary matrix U of 2x2

Inputs:

matrix polar_ret_type
1 -1 u
2 4

Excel formula:

=POLAR({1,-1;2,4}, "u")

Expected output:

Result
0.857493 -0.514496
0.514496 0.857493
Example 2: Positive semidefinite matrix P of 2x2

Inputs:

matrix polar_ret_type
1 -1 p
2 4

Excel formula:

=POLAR({1,-1;2,4}, "p")

Expected output:

Result
1.88648 1.20049
1.20049 3.94447

Python Code

Show Code
import numpy as np
from scipy.linalg import polar as scipy_polar

def polar(matrix, polar_side='right', polar_ret_type='u'):
    """
    Compute the polar decomposition of a matrix.

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

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

    Args:
        matrix (list[list]): 2D array of numeric values to decompose.
        polar_side (str, optional): Determines whether a right (A=UP) or left (A=PU) polar decomposition is computed. Valid options: Right (A=UP), Left (A=PU). Default is 'right'.
        polar_ret_type (str, optional): The component of the decomposition to return. Valid options: Unitary/Orthonormal (U), Positive Semidefinite (P). Default is 'u'.

    Returns:
        list[list]: 2D array representing the requested component (U or P).
    """
    try:
        def to2d(x):
            return [[x]] if not isinstance(x, list) else x

        matrix = to2d(matrix)

        if not isinstance(matrix, list) or not matrix or not all(isinstance(row, list) for row in matrix):
            return "Error: matrix must be a non-empty 2D list"

        try:
            a = np.array(matrix, dtype=float)
        except (ValueError, TypeError):
            return "Error: matrix must contain numeric values"

        if not np.all(np.isfinite(a)):
            return "Error: matrix must contain only finite numbers"

        try:
            u_matrix, p_matrix = scipy_polar(a, side=polar_side.lower())
        except Exception as e:
            return f"Error: {str(e)}"

        if polar_ret_type.lower() == "u":
            return u_matrix.tolist()
        else:
            return p_matrix.tolist()

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

Online Calculator

2D array of numeric values to decompose.
Determines whether a right (A=UP) or left (A=PU) polar decomposition is computed.
The component of the decomposition to return.

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

Show 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.

SCHUR

The Schur decomposition factors a square matrix A into a unitary matrix Z and an upper triangular matrix T such that A = ZTZ^H.

Excel Usage

=SCHUR(matrix, schur_output, schur_ret_type)
  • matrix (list[list], required): Square 2D array of numeric values to decompose.
  • schur_output (str, optional, default: “real”): Construct the real or complex Schur decomposition.
  • schur_ret_type (str, optional, default: “t”): The component of the decomposition to return.

Returns (list[list]): 2D array representing the requested component (T or Z).

Example 1: Schur form T of 3x3 matrix

Inputs:

matrix schur_ret_type
0 2 2 t
0 1 2
1 0 1

Excel formula:

=SCHUR({0,2,2;0,1,2;1,0,1}, "t")

Expected output:

Result
2.65897 1.4244 -1.92933
0 -0.329484 -0.490637
0 1.31179 -0.329484
Example 2: Transformation matrix Z

Inputs:

matrix schur_ret_type
0 2 2 z
0 1 2
1 0 1

Excel formula:

=SCHUR({0,2,2;0,1,2;1,0,1}, "z")

Expected output:

Result
0.727116 -0.601562 0.330796
0.528394 0.798019 0.289768
0.438294 0.0359041 -0.898114
Example 3: Complex Schur decomposition (T real part) 2x2

Inputs:

matrix schur_output schur_ret_type
0 1 complex t
-1 0

Excel formula:

=SCHUR({0,1;-1,0}, "complex", "t")

Expected output:

Result
[object Object] [object Object]
0 [object Object]

Python Code

Show Code
import numpy as np
from scipy.linalg import schur as scipy_schur

def schur(matrix, schur_output='real', schur_ret_type='t'):
    """
    Compute Schur decomposition of a matrix.

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

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

    Args:
        matrix (list[list]): Square 2D array of numeric values to decompose.
        schur_output (str, optional): Construct the real or complex Schur decomposition. Valid options: Real, Complex. Default is 'real'.
        schur_ret_type (str, optional): The component of the decomposition to return. Valid options: Schur Form (T), Unitary Matrix (Z). Default is 't'.

    Returns:
        list[list]: 2D array representing the requested component (T or Z).
    """
    try:
        def to2d(x):
            return [[x]] if not isinstance(x, list) else x

        matrix = to2d(matrix)

        if not isinstance(matrix, list) or not matrix or not all(isinstance(row, list) for row in matrix):
            return "Error: matrix must be a non-empty 2D list"

        n = len(matrix)
        if any(len(row) != n for row in matrix):
            return "Error: matrix must be square (n x n)"

        try:
            a = np.array(matrix, dtype=float)
        except (ValueError, TypeError):
            return "Error: matrix must contain numeric values"

        if not np.all(np.isfinite(a)):
            return "Error: matrix must contain only finite numbers"

        try:
            T, Z = scipy_schur(a, output=schur_output.lower())
        except Exception as e:
            return f"Error: {str(e)}"

        def format_complex(res):
            if not np.iscomplexobj(res):
                return (res.reshape(1, -1) if res.ndim == 1 else res).tolist()

            out = []
            for row in (res.reshape(1, -1) if res.ndim == 1 else res):
                out_row = []
                for val in row:
                    if val.imag == 0.0:
                        out_row.append(float(val.real))
                    else:
                        out_row.append({
                            "type": "Double",
                            "basicValue": float(val.real),
                            "properties": {
                                "Real": {"type": "Double", "basicValue": float(val.real)},
                                "Imaginary": {"type": "Double", "basicValue": float(val.imag)},
                                "Magnitude": {"type": "Double", "basicValue": float(np.abs(val))},
                                "Phase": {"type": "Double", "basicValue": float(np.angle(val))}
                            }
                        })
                out.append(out_row)
            return out

        if schur_ret_type.lower() == "t":
            return format_complex(T)
        else:
            return format_complex(Z)

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

Online Calculator

Square 2D array of numeric values to decompose.
Construct the real or complex Schur decomposition.
The component of the decomposition to return.

SVD

Singular value decomposition factors a matrix into orthogonal (or unitary) bases and nonnegative singular values. It is fundamental for rank analysis, dimensionality reduction, and stable least-squares methods.

For a matrix A, the factorization is:

A = U\Sigma V^H

where U and V^H are orthogonal/unitary factors and \Sigma contains singular values on its diagonal in non-increasing order.

Excel Usage

=SVD(matrix, full_matrices, compute_uv, overwrite_a, check_finite, lapack_driver, svd_return_type)
  • matrix (list[list], required): 2D list containing numeric values to decompose
  • full_matrices (bool, optional, default: true): If True, U and Vh have full shapes; if False, reduced shapes
  • compute_uv (bool, optional, default: true): If True, computes U, S, Vh; if False, returns only singular values
  • overwrite_a (bool, optional, default: false): If True, allows overwriting the input matrix to improve performance
  • check_finite (bool, optional, default: true): If True, scipy checks that input contains only finite numbers
  • lapack_driver (str, optional, default: “gesdd”): LAPACK driver to use for the computation
  • svd_return_type (str, optional, default: “u”): Component to return from the decomposition

Returns (list[list]): 2D SVD component, or error message string.

Example 1: Left singular vectors of 2x2 matrix using GESDD

Inputs:

matrix full_matrices compute_uv overwrite_a check_finite lapack_driver svd_return_type
1 2 true true false true gesdd u
3 4

Excel formula:

=SVD({1,2;3,4}, TRUE, TRUE, FALSE, TRUE, "gesdd", "u")

Expected output:

Result
-0.404554 -0.914514
-0.914514 0.404554
Example 2: Singular values of 3x2 tall matrix with reduced output

Inputs:

matrix full_matrices compute_uv overwrite_a check_finite lapack_driver svd_return_type
1 0 false true true false gesdd s
0 1
1 1

Excel formula:

=SVD({1,0;0,1;1,1}, FALSE, TRUE, TRUE, FALSE, "gesdd", "s")

Expected output:

Result
1.73205 1
Example 3: Right singular vectors of 2x2 matrix using GESVD

Inputs:

matrix full_matrices compute_uv overwrite_a check_finite lapack_driver svd_return_type
1 2 true true false true gesvd vh
3 4

Excel formula:

=SVD({1,2;3,4}, TRUE, TRUE, FALSE, TRUE, "gesvd", "vh")

Expected output:

Result
-0.576048 -0.817416
0.817416 -0.576048
Example 4: Singular values of 2x3 wide matrix

Inputs:

matrix full_matrices compute_uv overwrite_a check_finite lapack_driver svd_return_type
1 2 3 true true false true gesdd s
4 5 6

Excel formula:

=SVD({1,2,3;4,5,6}, TRUE, TRUE, FALSE, TRUE, "gesdd", "s")

Expected output:

Result
9.50803 0.77287

Python Code

Show Code
import numpy as np
from scipy.linalg import svd as scipy_svd

def svd(matrix, full_matrices=True, compute_uv=True, overwrite_a=False, check_finite=True, lapack_driver='gesdd', svd_return_type='u'):
    """
    Compute the Singular Value Decomposition (SVD) of a matrix using scipy.linalg.svd.

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

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

    Args:
        matrix (list[list]): 2D list containing numeric values to decompose
        full_matrices (bool, optional): If True, U and Vh have full shapes; if False, reduced shapes Default is True.
        compute_uv (bool, optional): If True, computes U, S, Vh; if False, returns only singular values Default is True.
        overwrite_a (bool, optional): If True, allows overwriting the input matrix to improve performance Default is False.
        check_finite (bool, optional): If True, scipy checks that input contains only finite numbers Default is True.
        lapack_driver (str, optional): LAPACK driver to use for the computation Valid options: Divide-and-conquer, Classic. Default is 'gesdd'.
        svd_return_type (str, optional): Component to return from the decomposition Valid options: Left singular vectors, Singular values, Right singular vectors. Default is 'u'.

    Returns:
        list[list]: 2D SVD component, or error message string.
    """
    try:
        # Helper to normalize scalar/single-element input to 2D list
        def to2d(x):
            return [[x]] if not isinstance(x, list) else x

        # Normalize scalar inputs into a 2D list structure
        matrix = to2d(matrix)

        # Handle scalar string conversion
        if len(matrix) == 1 and len(matrix[0]) == 1:
            val = matrix[0][0]
            if isinstance(val, str):
                try:
                    matrix = [[float(val)]]
                except Exception:
                    return "Error: Invalid input: matrix must be a 2D list of numeric values."
            elif isinstance(val, (int, float, bool)):
                matrix = [[float(val)]]

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

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

        array = np.array(numeric_rows, dtype=float)
        if array.size == 0:
            return "Error: Invalid input: matrix must contain at least one numeric value."

        # Validate boolean flags
        if not isinstance(full_matrices, bool):
            return "Error: Invalid input: full_matrices must be a boolean."
        if not isinstance(compute_uv, bool):
            return "Error: Invalid input: compute_uv must be a boolean."
        if not isinstance(overwrite_a, bool):
            return "Error: Invalid input: overwrite_a must be a boolean."
        if not isinstance(check_finite, bool):
            return "Error: Invalid input: check_finite must be a boolean."

        # Normalize lapack_driver and return_type values
        if not isinstance(lapack_driver, str):
            return "Error: Invalid input: lapack_driver must be 'gesdd' or 'gesvd'."
        normalized_driver = lapack_driver.lower()
        if normalized_driver not in {"gesdd", "gesvd"}:
            return "Error: Invalid input: lapack_driver must be 'gesdd' or 'gesvd'."

        if not isinstance(svd_return_type, str):
            return "Error: Invalid input: svd_return_type must be 'u', 's', or 'vh'."
        normalized_return_type = svd_return_type.lower()
        if normalized_return_type not in {"u", "s", "vh"}:
            return "Error: Invalid input: svd_return_type must be 'u', 's', or 'vh'."

        # Execute the SciPy SVD with the requested options
        try:
            if compute_uv:
                u_matrix, singular_values, vh_matrix = scipy_svd(
                    array,
                    full_matrices=full_matrices,
                    compute_uv=True,
                    overwrite_a=overwrite_a,
                    check_finite=check_finite,
                    lapack_driver=normalized_driver,
                )
            else:
                singular_values = scipy_svd(
                    array,
                    compute_uv=False,
                    overwrite_a=overwrite_a,
                    check_finite=check_finite,
                    lapack_driver=normalized_driver,
                )
                u_matrix = None
                vh_matrix = None
        except Exception as exc:
            return f"Error: scipy.linalg.svd error: {exc}"

        # Ensure results are finite before converting back to Python lists
        if not np.all(np.isfinite(singular_values)):
            return "Error: scipy.linalg.svd error: result contains non-finite values."

        if normalized_return_type == "s":
            return [singular_values.tolist()]

        if not compute_uv:
            return "Error: Invalid input: compute_uv must be True when svd_return_type is 'u' or 'vh'."

        if normalized_return_type == "u":
            if not np.all(np.isfinite(u_matrix)):
                return "Error: scipy.linalg.svd error: result contains non-finite values."
            return u_matrix.tolist()

        if not np.all(np.isfinite(vh_matrix)):
            return "Error: scipy.linalg.svd error: result contains non-finite values."
        return vh_matrix.tolist()
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

2D list containing numeric values to decompose
If True, U and Vh have full shapes; if False, reduced shapes
If True, computes U, S, Vh; if False, returns only singular values
If True, allows overwriting the input matrix to improve performance
If True, scipy checks that input contains only finite numbers
LAPACK driver to use for the computation
Component to return from the decomposition