Skip to main content

Python NumPy: How to Calculate Matrix Inverse in NumPy

The matrix inverse A⁻¹ satisfies A × A⁻¹ = I (identity matrix). NumPy provides efficient methods for computing inverses, though understanding when to use alternatives is equally important.

Basic Inverse Calculation​

Use np.linalg.inv() to compute the inverse of a square matrix:

import numpy as np

A = np.array([
[1, 2],
[3, 4]
])

A_inv = np.linalg.inv(A)
print("Inverse:")
print(A_inv)

# Verify: A @ A_inv should equal identity matrix
identity = A @ A_inv
print("\nA @ A_inv:")
print(identity)

Output:

Inverse:
[[-2. 1. ]
[ 1.5 -0.5]]

A @ A_inv:
[[1.0000000e+00 0.0000000e+00]
[8.8817842e-16 1.0000000e+00]

Verification with np.allclose()​

Due to floating-point precision, use np.allclose() for verification:

import numpy as np

A = np.array([[1, 2], [3, 4]])
A_inv = np.linalg.inv(A)

# Check if product equals identity
is_identity = np.allclose(A @ A_inv, np.eye(2))
print(f"A @ A_inv ≈ I: {is_identity}") # True

# Also verify A_inv @ A = I
is_identity_2 = np.allclose(A_inv @ A, np.eye(2))
print(f"A_inv @ A ≈ I: {is_identity_2}") # True

Output:

A @ A_inv ≈ I: True
A_inv @ A ≈ I: True

Handling Singular Matrices​

A singular matrix (determinant = 0) has no inverse:

import numpy as np

# Singular matrix: second row is 2× first row
singular = np.array([
[1, 2],
[2, 4]
])

# Check determinant first
det = np.linalg.det(singular)
print(f"Determinant: {det}") # 0.0

np.linalg.inv(singular) # Error: Singular matrix

Output:

Determinant: 0.0
numpy.linalg.LinAlgError: Singular matrix

Safe Inverse Function​

import numpy as np

def safe_inverse(matrix, tolerance=1e-10):
"""Compute inverse with singularity check."""
det = np.linalg.det(matrix)

if np.abs(det) < tolerance:
print(f"Warning: Matrix is singular or near-singular (det={det:.2e})")
return None

return np.linalg.inv(matrix)

# Test
A = np.array([[1, 2], [3, 4]])
print(safe_inverse(A))

B = np.array([[1, 2], [2, 4]])
print(safe_inverse(B)) # Returns None with warning

Output:

[[-2. 1. ]
[ 1.5 -0.5]]
Warning: Matrix is singular or near-singular (det=0.00e+00)
None

Don't Use inv() to Solve Linear Systems​

For solving Ax = b, use np.linalg.solve() instead of computing the inverse:

import numpy as np

A = np.array([[1, 2], [3, 4]])
b = np.array([5, 11])

# ❌ Slow and less accurate
x_slow = np.linalg.inv(A) @ b
print(f"Using inv(): {x_slow}")

# ✅ Faster and more stable
x_fast = np.linalg.solve(A, b)
print(f"Using solve(): {x_fast}")

# Verify both solutions
print(f"\nVerification (A @ x = b):")
print(f"inv method: {A @ x_slow}")
print(f"solve method: {A @ x_fast}")

Output:

Using inv(): [1. 2.]
Using solve(): [1. 2.]

Verification (A @ x = b):
inv method: [ 5. 11.]
solve method: [ 5. 11.]
warning

Computing the inverse explicitly is slower and introduces more numerical error than using solve(). Only compute the inverse when you specifically need the inverse matrix itself.

Performance Comparison​

import numpy as np
import timeit

n = 500
A = np.random.randn(n, n)
b = np.random.randn(n)

# Ensure A is invertible
A = A + n * np.eye(n)

# Method 1: Using inverse
def solve_with_inv():
return np.linalg.inv(A) @ b

# Method 2: Using solve
def solve_direct():
return np.linalg.solve(A, b)

inv_time = timeit.timeit(solve_with_inv, number=10)
solve_time = timeit.timeit(solve_direct, number=10)

print(f"inv() method: {inv_time:.4f}s")
print(f"solve() method: {solve_time:.4f}s")
print(f"solve() is {inv_time/solve_time:.1f}x faster")

Output:

inv() method: 17.3293s
solve() method: 0.1554s
solve() is 111.5x faster

Pseudo-Inverse for Non-Square Matrices​

The Moore-Penrose pseudo-inverse works for any matrix shape:

import numpy as np

# Non-square matrix (3×2)
A = np.array([
[1, 2],
[3, 4],
[5, 6]
])

# Regular inverse fails
try:
np.linalg.inv(A)
except np.linalg.LinAlgError as e:
print(f"inv() error: {e}")

# Pseudo-inverse works
A_pinv = np.linalg.pinv(A)
print(f"Shape of A: {A.shape}") # (3, 2)
print(f"Shape of pinv(A): {A_pinv.shape}") # (2, 3)
print(A_pinv)

Output:

inv() error: Last 2 dimensions of the array must be square
Shape of A: (3, 2)
Shape of pinv(A): (2, 3)
[[-1.33333333 -0.33333333 0.66666667]
[ 1.08333333 0.33333333 -0.41666667]]

Pseudo-Inverse for Least Squares​

import numpy as np

# Overdetermined system (more equations than unknowns)
A = np.array([
[1, 1],
[1, 2],
[1, 3]
])
b = np.array([1, 2, 2])

# Least squares solution using pseudo-inverse
x = np.linalg.pinv(A) @ b
print(f"Least squares solution: {x}")

# Equivalent using lstsq
x_lstsq, residuals, rank, s = np.linalg.lstsq(A, b, rcond=None)
print(f"lstsq solution: {x_lstsq}")

Output:

Least squares solution: [0.66666667 0.5 ]
lstsq solution: [0.66666667 0.5 ]

Inverse of Special Matrices​

Diagonal Matrix​

import numpy as np

# Diagonal matrix: inverse is reciprocal of diagonal
D = np.diag([2, 4, 5])
D_inv = np.linalg.inv(D)

print("D:")
print(D)
print("\nD_inv (1/diagonal):")
print(D_inv)

Output:

D:
[[2 0 0]
[0 4 0]
[0 0 5]]

D_inv (1/diagonal):
[[0.5 0. 0. ]
[0. 0.25 0. ]
[0. 0. 0.2 ]]

Orthogonal Matrix​

import numpy as np

# Orthogonal matrix: inverse equals transpose
Q, _ = np.linalg.qr(np.random.randn(3, 3))

Q_inv = np.linalg.inv(Q)
Q_T = Q.T

print("Q_inv ≈ Q.T:", np.allclose(Q_inv, Q_T)) # True

# For orthogonal matrices, use transpose instead of inv()

Output:

Q_inv ≈ Q.T: True
tip

For orthogonal matrices, the inverse equals the transpose. Use Q.T instead of np.linalg.inv(Q) for better performance.

Checking Invertibility​

Multiple ways to check if a matrix is invertible:

import numpy as np

def check_invertibility(matrix):
"""Check if a matrix is invertible using multiple methods."""
n = matrix.shape[0]

# Method 1: Determinant
det = np.linalg.det(matrix)
print(f"Determinant: {det:.6f}")

# Method 2: Rank
rank = np.linalg.matrix_rank(matrix)
print(f"Rank: {rank} (need {n} for invertibility)")

# Method 3: Condition number
cond = np.linalg.cond(matrix)
print(f"Condition number: {cond:.2e}")

# Verdict
is_invertible = not np.isclose(det, 0) and rank == n
print(f"Invertible: {is_invertible}")

return is_invertible

# Test
A = np.array([[1, 2], [3, 4]])
check_invertibility(A)

print()

B = np.array([[1, 2], [2, 4]])
check_invertibility(B)

Output:

Determinant: -2.000000
Rank: 2 (need 2 for invertibility)
Condition number: 1.49e+01
Invertible: True

Determinant: 0.000000
Rank: 1 (need 2 for invertibility)
Condition number: 2.52e+16
Invertible: False

Batch Inverse (Multiple Matrices)​

Invert multiple matrices efficiently:

import numpy as np

# Stack of 3 matrices, each 2×2
matrices = np.array([
[[1, 2], [3, 4]],
[[2, 0], [0, 2]],
[[1, 1], [0, 1]]
])

print(f"Shape: {matrices.shape}") # (3, 2, 2)

# Invert all at once
inverses = np.linalg.inv(matrices)
print(f"Inverses shape: {inverses.shape}") # (3, 2, 2)

# Verify first matrix
print(np.allclose(matrices[0] @ inverses[0], np.eye(2))) # True

Output:

Shape: (3, 2, 2)
Inverses shape: (3, 2, 2)
True

Summary​

MethodUse CaseMatrix Shape
np.linalg.inv(A)True inverse neededSquare, invertible
np.linalg.pinv(A)Pseudo-inverse, least squaresAny shape
np.linalg.solve(A, b)Solving Ax = bSquare
A.TOrthogonal matrix inverseOrthogonal
CheckPurpose
np.linalg.det(A) ≠ 0Invertibility
np.linalg.cond(A)Numerical stability
np.linalg.matrix_rank(A)Full rank check

Best Practice: Use np.linalg.solve() for linear systems-it's faster and more numerically stable. Only compute the explicit inverse when you need to apply it multiple times or analyze the inverse matrix itself.