CHOLESKY

Overview

The CHOLESKY function computes the Cholesky decomposition of a real, symmetric positive-definite matrix. This factorization decomposes a matrix A into the product of a triangular matrix and its transpose, providing an efficient method for solving linear systems, computing determinants, and performing Monte Carlo simulations.

For a symmetric positive-definite matrix A, the Cholesky decomposition produces either:

A = LL^T \quad \text{(lower triangular)}

or equivalently:

A = U^TU \quad \text{(upper triangular)}

where L is a lower-triangular matrix with positive diagonal entries, and U = L^T is the corresponding upper-triangular factor. The decomposition exists and is unique for any symmetric positive-definite matrix.

This implementation uses SciPy’s scipy.linalg.cholesky function from the SciPy library. The underlying algorithm leverages optimized LAPACK routines for numerical stability and performance. For more details on the mathematical background, see the Cholesky decomposition article on Wikipedia.

The Cholesky decomposition is approximately twice as efficient as LU decomposition for solving systems of linear equations when the matrix is symmetric positive-definite. Common applications include:

  • Solving linear systems: Once A = LL^T is computed, solving Ax = b reduces to two triangular solves
  • Computing matrix inverses and determinants: \det(A) = \det(L)^2 = \prod_{i} L_{ii}^2
  • Generating correlated random variables: Used extensively in Monte Carlo simulations and financial modeling
  • Optimization algorithms: Forms the basis for efficient implementations of Newton’s method and quadratic programming

A matrix is positive-definite if all its eigenvalues are positive, which is equivalent to x^T A x > 0 for all non-zero vectors x. If the input matrix is not positive-definite, the decomposition will fail with an error.

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

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.

Examples

Example 1: Demo case 1

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: Demo case 2

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: Demo case 3

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: Demo case 4

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

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.
    """
    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 [["Invalid input: matrix must be a 2D list with at least one row."]]
    if any(not isinstance(row, list) for row in matrix):
        return [["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 [["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 [["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 [["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 [["Invalid input: matrix must be symmetric."]]

    real_matrix = arr

    # Parse and normalize the 'lower' parameter from Excel-friendly inputs
    if isinstance(lower, list):
        return [["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 [["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 [["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

Online Calculator