SciPy - pinvh() Function



The scipy.linalg.pinvh() method computes the pseudo-inverse of a Hermitian (or symmetric) matrix using its eigenvalue decomposition. This method is useful in solving linear equation systems. It offers numerical stability and efficiency through eigenvalue decomposition.

Pinvh() is usually combined with other methods, including least squares solvers for underdetermined or overdetermined systems, and matrix decompositions like Cholesky or QR for greater stability in solving linear equations.

This method is used in regression, machine learning, and signal processing when direct inversion is not possible because of a unique or nearly singular matrix. This method has a flexibility with atol and rtol for rank estimation and handles real and complex symmetric matrices well.

Syntax

The syntax for the Scipy pinvh() method is as follows −

.pinvh(a, atol=None, rtol=None, lower=True, return_rank=False, check_finite=True)

Parameters

This method accepts the following parameters −

  • a (array_like)− Input Hermitian or symmetric matrix.

  • atol (float, optional) − Absolute tolerance for small eigenvalues to be considered zero.

  • rtol (float, optional) − Relative tolerance for small eigenvalues to be considered zero.

  • lower (bool, optional) − If True, the input matrix a is considered to be lower triangular.

  • return_rank (bool, optional) − If True, then the function returns the matrix's numerical rank as well as its pseudo-inverse.

  • check_finite (bool, optional) − If True, checks if the input matrix contains finite numbers.

Return Value

This method returns the following −

  • B (ndarray) − The pseudo-inverse of the input matrix a.

  • rank (int, optional) − The numerical rank of the matrix if return_rank=True.

Example 1: Pseudo-inverse of Matrix

The pseudo-inverse is calculated for symmetric matrices because their properties make computations easier. A matrix is symmetric if it equals its transpose, that is, A = A^T.

This code describes how the pseudo inverse of a symmetric matrix may be computed by using pinvh() method.

import numpy as np

import scipy.linalg
from scipy.linalg import pinvh

# Define a symmetric matrix
A = np.array([[1, 2], [2, 3]])
pinv_A = scipy.linalg.pinvh(A)

print("Pseudo-inverse of A:\n", pinv_A)

When we run above program, it produces following result −

Pseudo-inverse of A:
 [[-3.  2.]
 [ 2. -1.]]

Example 2: Using atol and rtol for Rank Estimation

The atol and rtol parameters set the limitations for determining a matrix's rank, making it easier to handle matrices that are almost singular. This, ensures the precision while computing pseudo inverse if the matrix carries minor errors or noise.

The below example show how to use pinvh() with custom atol and rtol parameters for the computation of a pseudo inverse of a nearly singular matrix.

import numpy as np
from scipy.linalg import pinvh

# Define a nearly singular matrix
B = np.array([[1, 2], [2, 4]])
pinv_B = pinvh(B, atol=1e-10, rtol=1e-10)

print("Pseudo-inverse of B with tolerance:", pinv_B)

Following is an output of the above code −

Pseudo-inverse of B with tolerance:
[[0.04 0.08]
 [0.08 0.16]]

Example 3: Retuning rank with return_rank= True

The rank of the matrix is determined by the return_rank parameter, which is important in understanding its properties and whether it is full rank or deficient. If the matrix is full rank, it means the rows and columns of the matrix are linearly independent and the matrix is invertible.

The code calculates the pseudo-inverse and returns the matrix rank, using the return_rank = True parameter to detect rank-deficient matrices.

import numpy as np
from scipy.linalg import pinvh

# Define a rank-deficient matrix
C = np.array([[1, 2], [1, 2]])

# Compute pseudo-inverse and return the rank
pinv_C, rank = pinvh(C, return_rank=True)

print("Pseudo-inverse of C:", pinv_C)
print("Rank of C:", rank)

Output of the above code is as follows −

Pseudo-inverse of C:
[[ 2. -1.]
 [-1.  1.]]
Rank of C: 2

Example 4: Using lower=True for Triangular Matrices

This example uses a 3x3 lower triangular matrix to demonstrate pinvh(a, lower=True) for more advanced cases.

When lower=True is utilized with pinvh() the function knows that the input matrix is lower triangular to optimize the calculation of the pseudo-inversion. This is useful because lower triangular have non-zero values just below the diagonal, increasing the speed and efficiency of their inversion.

import numpy as np
from scipy.linalg import pinvh

D = np.array([[4, 0, 0], 
              [2, 5, 0], 
              [1, 3, 6]])
pinv_D = pinvh(D, lower=True)

print("Pseudo-inverse of D (lower triangular):")
print(pinv_D)

Following is an output of the above code −

Pseudo-inverse of D (lower triangular):
[[ 0.31343284 -0.13432836  0.01492537]
 [-0.13432836  0.34328358 -0.14925373]
 [ 0.01492537 -0.14925373  0.23880597]] 

Example 5: Comparing pinv and pinvh

Unlike pinv()'s SVD, pinvh() uses eigenvalue decomposition, which is faster and more efficient when dealing with symmetric or Hermitian matrices. The eigenvalues of symmetric or Hermitian matrices are well-defined. In such scenarios, eigenvalue decomposition used by pinvh() is also more reliable.

In the below example we will compute pseudo-inverse of the symmetric matrix using pinv and pinvh to show case the efficiency of using pinvh for symmetric or hermitian matrices by comparing their results of running time.

import numpy as np
from scipy.linalg import pinvh, pinv
import time

# Define a large symmetric matrix
size = 1000
A = np.random.rand(size, size)
A = (A + A.T) / 2  # Make the matrix symmetric

# Compute pseudo-inverse using pinvh() and measure time
start_pinvh = time.time()
pinvh_A = pinvh(A)
end_pinvh = time.time()

# Compute pseudo-inverse using pinv() and measure time
start_pinv = time.time()
pinv_A = pinv(A)
end_pinv = time.time()

# Print computation times
print("Time taken by pinvh():", end_pinvh - start_pinvh, "seconds")
print("Time taken by pinv():", end_pinv - start_pinv, "seconds")

Output of the above code is as follows −

Time taken by pinvh(): 0.5259866714477539 seconds
Time taken by pinv(): 0.9690115451812744 seconds
scipy_linalg.htm
Advertisements