Inverse of a Matrix in Python (NumPy and Pure Python)

Use numpy.linalg.inv() to get the inverse of a matrix in Python. It returns the matrix that, multiplied by the original, gives the identity matrix:

import numpy as np
A = np.array([[4, 7], [2, 6]])
np.linalg.inv(A)    # [[ 0.6, -0.7], [-0.2, 0.4]]

Every result here was checked on Python 3.12.5 with NumPy 2.5.3, including the error you get for a matrix that can’t be inverted.

You’ll see how to invert and verify a matrix, why solve() usually beats inv(), what to do with singular matrices, how to spot unstable ones, and an exact inverse in plain Python.

How to find the inverse of a matrix with NumPy

Pass a square array to np.linalg.inv(). Then check the answer: the original times its inverse should be the identity matrix, give or take tiny rounding errors:

import numpy as np

A = np.array([[4, 7],
              [2, 6]])

A_inv = np.linalg.inv(A)
print("inverse:\n", A_inv)
print("A @ A_inv:\n", A @ A_inv)
print("is identity?", np.allclose(A @ A_inv, np.eye(2)))

Output:

inverse:
 [[ 0.6 -0.7]
 [-0.2  0.4]]
A @ A_inv:
 [[ 1.00000000e+00 -1.11022302e-16]
 [ 1.11022302e-16  1.00000000e+00]]
is identity? True
Command Prompt output of numpy.linalg.inv inverting a 2x2 matrix and np.allclose confirming the product is the identity matrix
np.allclose() is the right check, since floating-point results are rarely exactly 0 and 1.

@ is matrix multiplication. Don’t use *, which multiplies element by element. For building matrices in the first place, see making a matrix in Python.

Solving equations: use solve() instead of inv()

The most common reason to want an inverse is solving Ax = b. Here three receipts tell us how many coffees, bagels and juices were bought and the totals. What does each item cost?

import numpy as np

# three receipts: coffees, bagels, juices bought -> total paid (USD)
counts = np.array([[2, 1, 1],
                   [1, 2, 0],
                   [1, 0, 3]])
totals = np.array([16.75, 11.25, 18.50])

prices_inv = np.linalg.inv(counts) @ totals      # works...
prices = np.linalg.solve(counts, totals)         # ...but solve is the better tool

for item, price in zip(["coffee", "bagel", "juice"], prices):
    print(f"{item:<7} ${price:.2f}")
print("same answer:", np.allclose(prices, prices_inv))

Output:

coffee  $4.25
bagel   $3.50
juice   $4.75
same answer: True
Command Prompt output of numpy.linalg.solve finding coffee, bagel and juice prices in USD from three receipts
Both approaches find the prices, but solve() skips computing the full inverse.

np.linalg.solve() is faster and more accurate than inv(A) @ b, because it never builds the inverse. Here’s the difference I measured on a 500 by 500 system:

import timeit
import numpy as np

rng = np.random.default_rng(0)
M = rng.random((500, 500))
b = rng.random(500)

t_inv = timeit.timeit(lambda: np.linalg.inv(M) @ b, number=50)
t_solve = timeit.timeit(lambda: np.linalg.solve(M, b), number=50)
err_inv = np.abs(M @ (np.linalg.inv(M) @ b) - b).max()
err_solve = np.abs(M @ np.linalg.solve(M, b) - b).max()

print(f"inv() then @ : {t_inv:.3f} s, max error {err_inv:.1e}")
print(f"solve()      : {t_solve:.3f} s, max error {err_solve:.1e}")

Output:

inv() then @ : 2.046 s, max error 4.0e-13
solve()      : 3.948 s, max error 1.4e-13

What happens with a singular matrix?

A matrix whose rows depend on each other has a determinant of 0 and no inverse. NumPy raises LinAlgError. The pseudo-inverse, pinv(), still gives a best-fit answer:

import numpy as np

S = np.array([[1, 2],
              [2, 4]])          # second row is just 2 x the first

print("determinant:", np.linalg.det(S))
try:
    np.linalg.inv(S)
except np.linalg.LinAlgError as err:
    print("LinAlgError:", err)

print("pseudo-inverse:\n", np.linalg.pinv(S).round(4))

Output:

determinant: 0.0
LinAlgError: Singular matrix
pseudo-inverse:
 [[0.04 0.08]
 [0.08 0.16]]
Command Prompt output of a singular matrix with determinant 0 raising numpy LinAlgError, and its pseudo-inverse from pinv
The second row is twice the first, so the matrix is singular. pinv() works anyway.

pinv() also handles non-square matrices, which is useful for least-squares fitting.

Checking if a matrix is close to singular

Some matrices can technically be inverted but are so close to singular that tiny input changes swing the answer wildly. The condition number warns you:

import numpy as np

good = np.array([[4.0, 7.0], [2.0, 6.0]])
shaky = np.array([[1.0, 1.0], [1.0, 1.0000001]])

for name, M in [("good", good), ("shaky", shaky)]:
    print(f"{name:<5} condition number: {np.linalg.cond(M):,.0f}")

b = np.array([2.0, 2.0])
print(np.linalg.solve(shaky, b))
print(np.linalg.solve(shaky, b + [0, 0.0001]))   # tiny change, huge swing

Output:

good  condition number: 10
shaky condition number: 40,000,002
[2. 0.]
[-997.99999942  999.99999942]

When I see a condition number in the millions or more, I don’t trust the digits much. Rescale your data or rethink the model before relying on the inverse.

Inverse of a matrix without NumPy

For learning, or when you need exact answers, Gauss-Jordan elimination with Python’s Fraction type gives a precise inverse with no rounding at all:

from fractions import Fraction

def inverse(matrix):
    n = len(matrix)
    # augment [A | I] with exact fractions
    aug = [[Fraction(x) for x in row] + [Fraction(int(i == j)) for j in range(n)]
           for i, row in enumerate(matrix)]
    for col in range(n):
        pivot = next((r for r in range(col, n) if aug[r][col] != 0), None)
        if pivot is None:
            raise ValueError("matrix is singular")
        aug[col], aug[pivot] = aug[pivot], aug[col]
        p = aug[col][col]
        aug[col] = [x / p for x in aug[col]]
        for r in range(n):
            if r != col and aug[r][col] != 0:
                f = aug[r][col]
                aug[r] = [a - f * b for a, b in zip(aug[r], aug[col])]
    return [row[n:] for row in aug]

for row in inverse([[4, 7], [2, 6]]):
    print([str(x) for x in row])

Output:

['3/5', '-7/10']
['-1/5', '2/5']
Command Prompt output of a pure Python Gauss-Jordan matrix inverse using fractions, showing 3/5 and -7/10
Exact fractions: 3/5 is the 0.6 NumPy printed, and -7/10 is -0.7.

It’s far slower than NumPy on big matrices, so I treat it as a teaching tool. The row operations use list comprehensions; see list of lists in Python for more on nested lists.

Matrix inverse functions at a glance

FunctionUse it for
np.linalg.inv(A)The inverse of a square, non-singular matrix
np.linalg.solve(A, b)Solving Ax = b (preferred over inv)
np.linalg.pinv(A)Singular or non-square matrices
np.linalg.det(A)Checking for singularity (det = 0)
np.linalg.cond(A)How sensitive the inverse is to errors

For more on NumPy and matrices, try these guides:

Frequently asked questions

How do I find the inverse of a matrix in Python?

Use numpy.linalg.inv(A) on a square NumPy array. Verify it with np.allclose(A @ A_inv, np.eye(n)).

Why do I get LinAlgError: Singular matrix?

The matrix has no inverse because its rows or columns are linearly dependent. Use np.linalg.pinv() or fix the data.

Should I use inv() to solve linear equations?

No. np.linalg.solve(A, b) is faster and more accurate.

Can I invert a non-square matrix?

Not with inv(). Use the pseudo-inverse, np.linalg.pinv().

How do I get an exact inverse with fractions?

Use Gauss-Jordan elimination with fractions.Fraction, as shown above, or a symbolic library such as SymPy.

Where is numpy.linalg.inv documented?

See numpy.linalg.inv in the NumPy reference.