PINV
The Moore–Penrose pseudoinverse generalizes the matrix inverse to non-square or singular matrices. It is widely used for computing least-squares solutions and analyzing the effective rank of a matrix.
Given a matrix A with singular value decomposition A = U\Sigma V^H, the pseudoinverse is defined as A^+ = V \Sigma^+ U^H, where \Sigma^+ replaces each nonzero singular value \sigma with 1/\sigma and transposes the diagonal.
Excel Usage
=PINV(matrix, atol, rtol, return_rank, check_finite)
matrix(list[list], required): Matrix to pseudo-invert. Scalars are treated as 1x1 matrices.atol(float, optional, default: 0): Absolute threshold for small singular values to be treated as zero.rtol(float, optional, default: null): Relative threshold for small singular values. If None, uses max(M, N) * eps.return_rank(bool, optional, default: false): If True, return the effective rank instead of the pseudoinverse.check_finite(bool, optional, default: true): If True, verify the input contains only finite numbers.
Returns (list[list]): 2D pseudoinverse matrix, or error message string.
Example 1: Pseudoinverse of a 2x2 invertible matrix
Inputs:
| matrix | |
|---|---|
| 1 | 2 |
| 3 | 4 |
Excel formula:
=PINV({1,2;3,4})
Expected output:
| Result | |
|---|---|
| -2 | 1 |
| 1.5 | -0.5 |
Example 2: Pseudoinverse of a 3x2 rectangular matrix
Inputs:
| matrix | |
|---|---|
| 1 | 2 |
| 3 | 4 |
| 5 | 6 |
Excel formula:
=PINV({1,2;3,4;5,6})
Expected output:
| Result | ||
|---|---|---|
| -1.33333 | -0.333333 | 0.666667 |
| 1.08333 | 0.333333 | -0.416667 |
Example 3: Effective rank of a 2x2 matrix
Inputs:
| matrix | return_rank | |
|---|---|---|
| 1 | 2 | true |
| 3 | 4 |
Excel formula:
=PINV({1,2;3,4}, TRUE)
Expected output:
2
Example 4: Pseudoinverse with custom atol and rtol thresholds
Inputs:
| matrix | atol | rtol | |
|---|---|---|---|
| 1 | 2 | 0.00001 | 0.00001 |
| 3 | 4 |
Excel formula:
=PINV({1,2;3,4}, 0.00001, 0.00001)
Expected output:
| Result | |
|---|---|
| -2 | 1 |
| 1.5 | -0.5 |
Python Code
import numpy as np
from scipy.linalg import pinv as scipy_pinv
def pinv(matrix, atol=0, rtol=None, return_rank=False, check_finite=True):
"""
Compute the Moore-Penrose pseudoinverse of a matrix using singular value decomposition (SVD).
See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.pinv.html
This example function is provided as-is without any representation of accuracy.
Args:
matrix (list[list]): Matrix to pseudo-invert. Scalars are treated as 1x1 matrices.
atol (float, optional): Absolute threshold for small singular values to be treated as zero. Default is 0.
rtol (float, optional): Relative threshold for small singular values. If None, uses max(M, N) * eps. Default is None.
return_rank (bool, optional): If True, return the effective rank instead of the pseudoinverse. Default is False.
check_finite (bool, optional): If True, verify the input contains only finite numbers. Default is True.
Returns:
list[list]: 2D pseudoinverse matrix, or error message string.
"""
try:
# Helper function to normalize scalar/single-element input to 2D list
def to2d(x):
return [[x]] if not isinstance(x, list) else x
# Normalize scalar input into a 2D list for consistent handling
matrix = to2d(matrix)
if not isinstance(matrix[0], list):
# Handle case where input was a 1D list
return "Error: Invalid input: matrix must be a 2D list or scalar numeric value."
# Convert scalar values that came from Excel single-element arrays
for i, row in enumerate(matrix):
for j, val in enumerate(row):
if isinstance(val, (int, float, bool)):
matrix[i][j] = float(val)
elif isinstance(val, str):
try:
matrix[i][j] = float(val)
except Exception:
return "Error: Invalid input: matrix must contain only numeric values."
# Ensure the matrix is a 2D list with consistent row lengths
if not matrix or not all(isinstance(row, list) for row in matrix):
return "Error: Invalid input: matrix must be a 2D list with at least one row."
if any(len(row) == 0 for row in matrix):
return "Error: Invalid input: matrix rows must contain at least one value."
row_length = len(matrix[0])
if any(len(row) != row_length for row in matrix):
return "Error: Invalid input: all rows in matrix must have the same length."
# Validate optional parameters
try:
atol_value = float(atol)
except Exception:
return "Error: Invalid input: atol must be a numeric value."
if rtol is not None:
try:
rtol_value = float(rtol)
except Exception:
return "Error: Invalid input: rtol must be a numeric value or None."
else:
rtol_value = None
if not isinstance(return_rank, bool):
return "Error: Invalid input: return_rank must be a boolean."
if not isinstance(check_finite, bool):
return "Error: Invalid input: check_finite must be a boolean."
# Convert the matrix elements to floats, ensuring numeric values
numeric_rows = []
for row in matrix:
numeric_row = []
for value in row:
try:
numeric_row.append(float(value))
except Exception:
return "Error: Invalid input: matrix must contain only numeric values."
numeric_rows.append(numeric_row)
arr = np.array(numeric_rows, dtype=float)
# Compute the pseudoinverse and optionally the rank
if return_rank:
_, rank = scipy_pinv(
arr,
atol=atol_value,
rtol=rtol_value,
return_rank=True,
check_finite=check_finite,
)
if not np.isfinite(rank):
return "Error: scipy.linalg.pinv error: effective rank is not finite."
return float(rank)
result = scipy_pinv(
arr,
atol=atol_value,
rtol=rtol_value,
return_rank=False,
check_finite=check_finite,
)
# Ensure the result does not contain non-finite values before returning to Excel
if not np.all(np.isfinite(result)):
return "Error: scipy.linalg.pinv error: result contains non-finite values."
return result.tolist()
except Exception as e:
return f"Error: {str(e)}"Online Calculator
Matrix to pseudo-invert. Scalars are treated as 1x1 matrices.
Absolute threshold for small singular values to be treated as zero.
Relative threshold for small singular values. If None, uses max(M, N) * eps.
If True, return the effective rank instead of the pseudoinverse.
If True, verify the input contains only finite numbers.