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

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