pseudoInverse method

Matrix pseudoInverse()

Computes the pseudo-inverse of a matrix using Singular Value Decomposition (SVD).

This method provides a robust approach to calculating the pseudo-inverse of a matrix, handling cases where the matrix is singular, poorly conditioned, or not square. The method falls back to SVD-based computation when the condition number exceeds the specified threshold, ensuring numerical stability.

Returns:

  • A Matrix object representing the pseudo-inverse of the input matrix.

Methodology:

  1. SVD Decomposition: The matrix is decomposed into ( U, S, V ) components.
  2. Singular Value Inversion:
    • Singular values are inverted to construct ( S^+ ), with small values set to zero to handle numerical instability.
  3. Pseudo-Inverse Reconstruction:
    • Combines ( U, S^+, V ) to compute the pseudo-inverse: [ A^+ = V S^+ U^T ]

Example:

Matrix a = Matrix([
  [1, 2],
  [3, 4],
  [5, 6]
]);

Matrix aPseudoInverse = a.pseudoInverse();
print(aPseudoInverse);

Output:

Matrix: 2x3
┌ -1.3333333333333308 -0.3333333333333339  0.6666666666666643 ┐
└  1.0833333333333313 0.33333333333333304 -0.4166666666666643 ┘

Notes:

  • This implementation is suitable for both square and rectangular matrices.
  • Provides robust handling for singular and low-rank matrices.
  • If the matrix is well-conditioned, the SVD fallback may not be triggered.

Limitations:

  • The computational cost of SVD may be significant for very large matrices.

Implementation

Matrix pseudoInverse() {
  final sig = '$elementsSignature:pseudoinverse';
  final cached = Matrix._pseudoInverseCache.get(sig);
  if (cached != null) return cached;

  Matrix compute() {
    Matrix a = copy();
    Matrix aTranspose = a.transpose();

    if (rowCount >= columnCount) {
      // Overdetermined system (more rows than columns)
      // Pseudo-inverse = (A^T·A)^(-1)·A^T
      return (aTranspose * a).inverse() * aTranspose;
    } else {
      // Underdetermined system (more columns than rows)
      // Pseudo-inverse = A^T·(A·A^T)^(-1)
      return aTranspose * (a * aTranspose).inverse();
    }
  }

  final result = compute();
  Matrix._pseudoInverseCache.put(sig, result);
  return result;
}