CHOLESKY
Overview
The CHOLESKY function computes the Cholesky factorization of a real, symmetric positive-definite matrix. The decomposition factors a matrix into the product for the lower-triangular factor or for the upper-triangular factor, enabling efficient solutions to linear systems, covariance matrix simulations, and numerical optimization routines. For algorithmic details, see the scipy.linalg.cholesky documentation .
This wrapper exposes the lower option from SciPy and defaults the overwrite_a and check_finite flags to preserve Excel-friendly behavior. This example function is provided as-is without any representation of accuracy.
Usage
To use the function in Excel:
=CHOLESKY(matrix, [lower])matrix(2D list of floats, required): Real symmetric positive-definite matrix to factor. Must be square with at least one row.lower(bool, optional, default=FALSE): When TRUE, returns the lower-triangular factor such that ; otherwise returns the upper-triangular factor .
The function returns a 2D list of floats representing the requested Cholesky factor. If validation fails or the matrix is not positive-definite, a 2D list containing an explanatory error string is returned.
Examples
Example 1: Lower-triangular factor for a matrix
Inputs:
| matrix | lower | |
|---|---|---|
| 4 | 12 | TRUE |
| 12 | 37 |
Excel formula:
=CHOLESKY({4,12;12,37}, TRUE)Expected output:
| Result | |
|---|---|
| 2.000 | 0.000 |
| 6.000 | 1.000 |
Example 2: Upper-triangular factor for the same matrix
Inputs:
| matrix | lower | |
|---|---|---|
| 4 | 12 | FALSE |
| 12 | 37 |
Excel formula:
=CHOLESKY({4,12;12,37}, FALSE)Expected output:
| Result | |
|---|---|
| 2.000 | 6.000 |
| 0.000 | 1.000 |
Example 3: Lower factor for a 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.000 | 0.000 | 0.000 |
| 3.000 | 3.000 | 0.000 |
| -1.000 | 1.000 | 3.000 |
Example 4: Lower factor with mixed signs
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.000 | 0.000 | 0.000 |
| -2.000 | 2.000 | 0.000 |
| 1.000 | 0.000 | 1.414 |
Python Code
from typing import List, Union
import numpy as np
from scipy.linalg import cholesky as scipy_cholesky
MatrixInput = List[List[Union[float, int, bool, str, None]]]
ResultMatrix = List[List[Union[float, str]]]
def cholesky(matrix: MatrixInput, lower: Union[bool, int, float, str, None] = False) -> ResultMatrix:
"""
Compute the Cholesky decomposition of a real, symmetric positive-definite matrix.
Args:
matrix: 2D list (square) containing numeric values representing a symmetric positive-definite matrix.
lower: Optional bool-like flag; if True, return the lower-triangular factor instead of the upper-triangular factor.
Returns:
2D list of floats representing the Cholesky factor, or 2D list of strings with an error message if the input is invalid.
This example function is provided as-is without any representation of accuracy.
"""
# Validate matrix structure
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."]]
n = len(matrix)
if any(len(row) != n for row in matrix):
return [["Invalid input: matrix must be square (n x n)."]]
numeric_rows: List[List[complex]] = []
for row in matrix:
numeric_row: List[complex] = []
for value in row:
try:
# Convert Excel-compatible scalars into complex numbers for SciPy
numeric_row.append(complex(value))
except Exception:
return [["Invalid input: matrix entries must be numeric values."]]
numeric_rows.append(numeric_row)
arr = np.array(numeric_rows, dtype=np.complex128)
if not np.isfinite(arr).all():
return [["Invalid input: matrix entries must be finite numbers."]]
if np.any(np.abs(arr.imag) > 1e-12):
return [["Invalid input: matrix must contain real numbers."]]
real_matrix = arr.real
if not np.allclose(real_matrix, real_matrix.T, atol=1e-9):
return [["Invalid input: matrix must be symmetric."]]
# Normalize the lower flag from Excel-friendly inputs
lower_flag: bool
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:
# Delegate to SciPy for the actual decomposition
result = scipy_cholesky(real_matrix, lower=lower_flag)
except Exception as exc:
return [[f"Error: {exc}"]]
result_matrix: ResultMatrix = []
for row in result:
result_row: List[Union[float, str]] = []
for value in row:
if abs(value.imag) > 1e-12:
return [["Error: Result contains complex values; provide a real-valued positive-definite matrix."]]
real_value = float(value.real)
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