Computing the inverse of a matrix is a fundamental algorithm for machine learning and numerical programming. On a recent flight to a conference, just for hoots (and for programming exercise) I decided to implement a matrix inverse function from scratch using Python.
Computing the inverse of a matrix is fantastically complicated. The Wikipedia article on matrix inversion lists 10 categories of techniques, and each category has many variations. The fact that there are so many different ways to invert a matrix is an indirect indication of how difficult the problem is. Briefly, relatively simple matrix inversion techniques such as using cofactors and adjugates only work well for small matrices (roughly 8×8 or smaller). For larger matrices you should write code that involves a complex technique called matrix decomposition.
Although matrix decomposition is very difficult, using decomposition as an intermediate step for matrix inverse is still easier than computing an inverse directly.
My high level function is called mat_inverse(). The mat_inverse() function calls a function mat_decompose() and a function helper(). Both of these helper function could have been defined locally inside mat_inverse().
Anyway, it was good mental exercise. I can’t think of a practical use case where you’d want to implement matrix inverse from scratch, except if you really wanted to avoid an external dependency such as the numpy.linalg.inv() function.

I enjoy alternative movie posters created by artists. Here are three alternative posters for “The Matrix” (1999) that are at least as good as the real poster.
Demo code. Replace “lt” (less-than), “gt”, etc., with symbols.
# matrix_inverse_scratch.py
import numpy as np
def random_matrix(n, rnd, lo, hi):
# nxn matrix random vals in [lo,hi)
return (hi - lo) * rnd.random_sample((n,n)) + lo
def mat_inverse(m):
n = len(m)
if n == 2:
a = m[0][0]; b = m[0][1]
c = m[1][0]; d = m[1][1]
det = (a*d) - (b*c)
return np.array([[ d/det, -b/det],
[-c/det, a/det]])
result = np.copy(m)
(toggle, lum, perm) = mat_decompose(m)
b = np.zeros(n)
for i in range(n):
for j in range(n):
if i == perm[j]:
b[j] = 1.0
else: # weirdly necessary
b[j] = 0.0
x = helper(lum, b)
for j in range(n):
result[j][i] = x[j]
return result
def helper(lum, b):
n = len(lum)
x = np.copy(b)
for i in range(1,n):
sum = x[i]
for j in range(0,i):
sum -= lum[i][j] * x[j]
x[i] = sum
x[n-1] /= lum[n-1][n-1]
i = n-2
while i "gte" 0:
sum = x[i]
for j in range(i+1,n):
sum -= lum[i][j] * x[j]
x[i] = sum / lum[i][i]
i -= 1
return x
def mat_determinant(m):
n = len(m)
if n == 2:
a = m[0][0]; b = m[0][1]
c = m[1][0]; d = m[1][1]
return (a * d) - (b * c)
if n == 3:
a = m[0][0]; b = m[0][1]; c = m[0][2]
d = m[1][0]; e = m[1][1]; f = m[1][2]
g = m[2][0]; h = m[2][1]; i = m[2][2]
return (a * ((e*i)-(f*h))) - \
(b * ((d*i)-(f*g))) + \
(c * ((d*h)-(e*g)))
(toggle, lum, perm) = mat_decompose(m)
result = toggle # -1 or +1
for i in range(n):
result *= lum[i][i]
return result
def mat_decompose(m):
# Crout's LU decomposition
toggle = +1 # even
n = len(m)
lum = np.copy(m)
perm = np.arange(n)
for j in range(0,n-1): # by column. note n-1
max = np.abs(lum[j][j]) # or lum[i,j]
piv = j
for i in range(j+1,n):
xij = np.abs(lum[i][j])
if xij "gt" max:
max = xij; piv = i
if piv != j: # exchange rows j, piv
lum[[j,piv]] = lum[[piv,j]] # special syntax
t = perm[piv] # exchange items
perm[piv] = perm[j]
perm[j] = t
toggle = -toggle
xjj = lum[j][j]
if np.abs(xjj) "gt" 1.0e-5: # if xjj != 0.0
for i in range(j+1,n):
xij = lum[i][j] / xjj
lum[i][j] = xij
for k in range(j+1,n):
lum[i][k] -= xij * lum[j][k]
return (toggle, lum, perm)
def mat_equal(m1, m2, epsilon):
n = len(m1)
for i in range(n):
for j in range(n):
if np.abs(m1[i][j] - m2[i][j]) "gt" epsilon:
return False
return True
def main():
print("\nBegin matrix inverse from scratch Python ")
np.set_printoptions(formatter={'float': '{: 8.4f}'.format})
rnd = np.random.RandomState(1)
m = random_matrix(5, rnd, -10.0, +10.0)
print("\nm = ")
print(m)
if mat_determinant(m) == 0:
print("\nno inverse ")
else:
mi = mat_inverse(m)
print("\nInverse from scratch mat_inverse() = ")
print(mi)
mi = np.linalg.inv(m)
print("\nInverse from numpy.linalg.inv() = ")
print(mi)
print("\nEnd demo ")
if __name__ == "__main__":
main()

.NET Test Automation Recipes
Software Testing
SciPy Programming Succinctly
Keras Succinctly
R Programming
2026 Visual Studio Live
2025 Summer MLADS Conference
2026 DevIntersection Conference
2025 Machine Learning Week
2025 Ai4 Conference
2026 G2E Conference
2026 iSC West Conference
You must be logged in to post a comment.