SVD

Overview

The SVD function computes the Singular Value Decomposition of a matrix, one of the most important matrix factorizations in linear algebra. SVD decomposes any m \times n matrix A into the product of three matrices: two orthogonal (unitary) matrices and a diagonal matrix of singular values.

Given a matrix A, the decomposition is expressed as:

A = U \Sigma V^H

where U is an m \times m unitary matrix containing the left singular vectors as columns, \Sigma is an m \times n diagonal matrix with non-negative singular values \sigma_i arranged in descending order along the diagonal, and V^H (the conjugate transpose of V) is an n \times n unitary matrix containing the right singular vectors as rows.

This implementation uses scipy.linalg.svd from the SciPy library. The function supports two LAPACK driver options: gesdd (divide-and-conquer algorithm, the default) which is generally faster, and gesvd (general rectangular algorithm) which may be more robust for certain matrices. For more details on the underlying algorithms, see the SciPy linalg module documentation and the SciPy GitHub repository.

SVD has widespread applications across data science and engineering. In principal component analysis (PCA), the singular vectors identify the directions of maximum variance in data. In image compression, truncating the decomposition to the largest singular values provides an efficient low-rank approximation. SVD also forms the foundation for pseudoinverse calculations, least squares solutions, and latent semantic analysis in natural language processing. For background on the mathematical theory, see the Wikipedia article on Singular Value Decomposition.

The function returns one of three components based on the svd_return_type parameter: the left singular vectors (u), the singular values (s), or the right singular vectors (vh). The full_matrices parameter controls whether full-sized or economy-sized matrices are returned—setting it to False reduces memory usage when only the significant components are needed.

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

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.

Examples

Example 1: Demo case 1

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.40455358483375703 -0.9145142956773042
-0.9145142956773045 0.4045535848337568

Example 2: Demo case 2

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.7320508075688772 1

Example 3: Demo case 3

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.5760484367663209 -0.8174155604703631
0.8174155604703631 -0.5760484367663209

Example 4: Demo case 4

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.508032000695724 0.7728696356734844

Python 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.
    """
    # 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 "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 "Invalid input: matrix must be a 2D list with at least one row."
    column_count = len(matrix[0])
    if column_count == 0:
        return "Invalid input: matrix rows must contain at least one value."
    if any(len(row) != column_count for row in matrix):
        return "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 "Invalid input: matrix must contain numeric values."
            if not np.isfinite(numeric_value):
                return "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 "Invalid input: matrix must contain at least one numeric value."

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

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

    if not isinstance(svd_return_type, str):
        return "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 "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"scipy.linalg.svd error: {exc}"

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

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

    if not compute_uv:
        return "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 "scipy.linalg.svd error: result contains non-finite values."
        return u_matrix.tolist()

    if not np.all(np.isfinite(vh_matrix)):
        return "scipy.linalg.svd error: result contains non-finite values."
    return vh_matrix.tolist()

Online Calculator