Skip to content

Python NumPy: How to Calculate Matrix Condition Number in NumPy

Learn how to use NumPy's np.linalg.cond() to calculate matrix condition numbers and assess numerical stability for reliable linear algebra operations.

The condition number measures how sensitive a matrix's solution is to small changes in input data. High condition numbers indicate numerical instability, making matrix operations unreliable.

Basic Calculation

Use np.linalg.cond() to compute the condition number:

import numpy as np

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

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

What It Means

The condition number indicates how much output error can result from input error. A condition number of 100 means a 1% error in input could produce up to 100% error in output.

import numpy as np

good_matrix = np.array([
    [1, 0.1],
    [0.1, 1]
])
print(f"Well-conditioned: {np.linalg.cond(good_matrix):.2f}")    # ~1.22

bad_matrix = np.array([
    [1, 1],
    [1, 1.0001]
])
print(f"Ill-conditioned: {np.linalg.cond(bad_matrix):.2f}")     # ~40000

Output:

Well-conditioned: 1.22
Ill-conditioned: 40002.00

Interpreting Condition Numbers

Condition Number Status Reliability
~1 ✅ Ideal Maximum precision
< 100 ✅ Well-conditioned Results reliable
100 - 1,000 ⚠️ Moderate Some precision loss
> 1,000,000 ❌ Ill-conditioned Results unreliable
∞ (inf) ❌ Singular No unique solution
import numpy as np

def assess_condition(matrix):
    """Evaluate matrix conditioning."""
    cond = np.linalg.cond(matrix)
    
    if np.isinf(cond):
        return f"Condition: ∞ - Singular matrix (no inverse)"
    elif cond < 100:
        return f"Condition: {cond:.2f} - Well-conditioned ✅"
    elif cond < 10000:
        return f"Condition: {cond:.2f} - Moderately conditioned ⚠️"
    else:
        return f"Condition: {cond:.2e} - Ill-conditioned ❌"

matrices = [
    np.eye(3),                          # Identity
    np.array([[1, 2], [3, 4]]),         # Normal
    np.array([[1, 2], [2, 4.0001]]),    # Nearly singular
    np.array([[1, 2], [2, 4]])          # Singular
]

for m in matrices:
    print(assess_condition(m))

Output:

Condition: 1.00 - Well-conditioned ✅
Condition: 14.93 - Well-conditioned ✅
Condition: 2.50e+05 - Ill-conditioned ❌
Condition: 2.52e+16 - Ill-conditioned ❌

Examples of Ill-Conditioned Matrices

Nearly Proportional Rows

import numpy as np

nearly_singular = np.array([
    [1, 2, 3],
    [2, 4, 6.0001],  # Almost 2× row 1
    [1, 1, 1]
])

print(f"Condition: {np.linalg.cond(nearly_singular):.2e}")

Hilbert Matrix (Classic Example)

import numpy as np
from scipy.linalg import hilbert

for n in [3, 5, 7, 10]:
    H = hilbert(n)
    cond = np.linalg.cond(H)
    print(f"Hilbert {n}×{n}: condition = {cond:.2e}")

Output:

Hilbert 3×3: condition = 5.24e+02
Hilbert 5×5: condition = 4.77e+05
Hilbert 7×7: condition = 4.75e+08
Hilbert 10×10: condition = 1.60e+13

Using Different Norms

The condition number depends on the matrix norm used:

import numpy as np

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

cond_2 = np.linalg.cond(matrix)
print(f"2-norm condition: {cond_2:.4f}")

cond_inf = np.linalg.cond(matrix, p=np.inf)
print(f"∞-norm condition: {cond_inf:.4f}")

cond_1 = np.linalg.cond(matrix, p=1)
print(f"1-norm condition: {cond_1:.4f}")

cond_fro = np.linalg.cond(matrix, p='fro')
print(f"Frobenius condition: {cond_fro:.4f}")

Output:

2-norm condition: 14.9330
∞-norm condition: 21.0000
1-norm condition: 21.0000
Frobenius condition: 15.0000

Norm Options

Parameter p Norm Type Formula
None or 2 2-norm (default) σ_max / σ_min
np.inf Infinity norm max row sum
1 1-norm max column sum
-np.inf Negative infinity min row sum
'fro' Frobenius √(Σ

Practical Example: Linear System Solving

Check conditioning before solving systems:

import numpy as np

def safe_solve(A, b):
    """Solve Ax = b with condition check."""
    cond = np.linalg.cond(A)
    
    if np.isinf(cond):
        raise ValueError("Matrix is singular - no unique solution")
    
    if cond > 1e10:
        print(f"Warning: High condition number ({cond:.2e})")
        print("Solution may be inaccurate!")
    
    x = np.linalg.solve(A, b)
    
    residual = np.linalg.norm(A @ x - b)
    print(f"Condition: {cond:.2e}, Residual: {residual:.2e}")
    
    return x

A_good = np.array([[4, 1], [1, 3]])
b = np.array([1, 2])
x = safe_solve(A_good, b)
print(f"Solution: {x}\n")

A_bad = np.array([[1, 1], [1, 1.00000001]])
x = safe_solve(A_bad, b)
print(f"Solution: {x}")

Output:

Condition: 1.94e+00, Residual: 0.00e+00
Solution: [0.09090909 0.63636364]

Condition: 4.00e+08, Residual: 0.00e+00
Solution: [-9.99999996e+07  1.00000001e+08]

Relationship to Singular Values

The 2-norm condition number is the ratio of largest to smallest singular values:

import numpy as np

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

U, s, Vt = np.linalg.svd(matrix)
cond_from_svd = s[0] / s[-1]  # max / min singular value

cond_direct = np.linalg.cond(matrix)

print(f"From SVD: {cond_from_svd:.4f}")
print(f"From cond: {cond_direct:.4f}")

Output:

From SVD: 14.9330
From cond: 14.9330

Checking Before Matrix Inversion

Always check conditioning before computing inverses:

import numpy as np

def safe_inverse(matrix):
    """Compute matrix inverse with stability check."""
    cond = np.linalg.cond(matrix)
    
    digits_lost = np.log10(cond)
    available_digits = 15  # float64 precision
    
    print(f"Condition number: {cond:.2e}")
    print(f"Digits of precision lost: ~{digits_lost:.1f}")
    print(f"Reliable digits remaining: ~{available_digits - digits_lost:.1f}")
    
    if cond > 1e12:
        print("⚠️ Matrix is too ill-conditioned for reliable inversion")
        return None
    
    return np.linalg.inv(matrix)

matrix = np.array([[1, 2], [2, 4.001]])
inv = safe_inverse(matrix)

Output:

Condition number: 2.50e+04
Digits of precision lost: ~4.4
Reliable digits remaining: ~10.6

Summary

Function Purpose
np.linalg.cond(A) 2-norm condition number
np.linalg.cond(A, p=1) 1-norm condition number
np.linalg.cond(A, p=np.inf) Infinity-norm condition number

Best Practice: Always check np.linalg.cond() before matrix inversion or solving linear systems. Condition numbers above 10⁶ suggest results may be unreliable, and values approaching machine epsilon reciprocal (~10¹⁶ for float64) indicate the matrix is effectively singular.

Navigation