Skip to content

Python NumPy: How to Calculate Matrix Determinant in NumPy

Learn how to compute matrix determinants in NumPy using np.linalg.det(), handle singular matrices, and use slogdet() for large matrices to avoid overflow while checking invertibility and volume scaling.

The determinant is a scalar value that reveals important matrix properties: whether a matrix is invertible, how it scales volumes, and its relationship to eigenvalues.

Basic Calculation

Use np.linalg.det() to compute the determinant:

import numpy as np

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

det = np.linalg.det(matrix)
print(f"Determinant: {det}")

Output:

Determinant: -2.0000000000000004

Manual Verification (2×2)

For a 2×2 matrix [[a, b], [c, d]], the determinant is ad - bc:

import numpy as np

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

manual_det = matrix[0, 0] * matrix[1, 1] - matrix[0, 1] * matrix[1, 0]

numpy_det = np.linalg.det(matrix)

print(f"Manual: {manual_det}")
print(f"NumPy: {numpy_det}")

Output:

Manual: -2
NumPy: -2.0000000000000004

Checking for Singular Matrices

A determinant of zero means the matrix is singular (non-invertible):

import numpy as np

singular = np.array([
    [1, 2],
    [2, 4]  # 2× first row
])

det = np.linalg.det(singular)
print(f"Determinant: {det}")  # 0.0 (or very close to 0)

try:
    inv = np.linalg.inv(singular)
except np.linalg.LinAlgError:
    print("Cannot invert singular matrix")

Output:

Determinant: 0.0
Cannot invert singular matrix

Floating-Point Precision

Due to floating-point arithmetic, check for near-zero rather than exact zero:

import numpy as np

nearly_singular = np.array([
    [1, 2],
    [2, 4.0000000001]
])

det = np.linalg.det(nearly_singular)
print(f"Determinant: {det}")  # Very small, not exactly 0

if np.isclose(det, 0, atol=1e-10):
    print("Matrix is effectively singular")
else:
    print("Matrix is invertible")

Output:

Determinant: 1.0000000827403705e-10
Matrix is invertible

Determinant Properties

import numpy as np

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

det_AB = np.linalg.det(A @ B)
det_A_times_det_B = np.linalg.det(A) * np.linalg.det(B)
print(f"det(AB) = {det_AB:.4f}")
print(f"det(A)×det(B) = {det_A_times_det_B:.4f}")

print(f"det(A) = {np.linalg.det(A):.4f}")
print(f"det(A.T) = {np.linalg.det(A.T):.4f}")

c = 2
n = A.shape[0]
print(f"det(2A) = {np.linalg.det(c * A):.4f}")
print(f"2^2 × det(A) = {c**n * np.linalg.det(A):.4f}")

if not np.isclose(np.linalg.det(A), 0):
    A_inv = np.linalg.inv(A)
    print(f"det(A^-1) = {np.linalg.det(A_inv):.4f}")
    print(f"1/det(A) = {1/np.linalg.det(A):.4f}")

Output:

det(AB) = -12.0000
det(A)×det(B) = -12.0000
det(A) = -2.0000
det(A.T) = -2.0000
det(2A) = -8.0000
2^2 × det(A) = -8.0000
det(A^-1) = -0.5000
1/det(A) = -0.5000

Large Matrices: Using slogdet()

For large matrices, determinants can overflow or underflow. Use slogdet() to get the sign and log of the absolute determinant:

import numpy as np

large_matrix = np.random.randn(100, 100)

det = np.linalg.det(large_matrix)
print(f"Regular det: {det}")  # May show inf or 0

sign, logdet = np.linalg.slogdet(large_matrix)
print(f"Sign: {sign}")
print(f"Log|det|: {logdet}")

reconstructed = sign * np.exp(logdet)
print(f"Reconstructed: {reconstructed}")

Output:

Regular det: -1.0398456917186009e+78
Sign: -1.0
Log|det|: 179.64070958233293
Reconstructed: -1.0398456917186009e+78

When to Use slogdet()

import numpy as np

def stable_determinant(matrix):
    """Compute determinant with overflow protection."""
    sign, logdet = np.linalg.slogdet(matrix)
    
    if sign == 0:
        return 0.0  # Singular matrix
    
    if logdet > 700:  # exp(700) ≈ 10^304
        print(f"Warning: |det| ≈ exp({logdet:.1f}) - extremely large")
        return sign * np.inf
    elif logdet < -700:
        print(f"Warning: |det| ≈ exp({logdet:.1f}) - extremely small")
        return 0.0
    
    return sign * np.exp(logdet)

for n in [10, 50, 100, 200]:
    matrix = np.random.randn(n, n)
    det = stable_determinant(matrix)
    print(f"{n}×{n} matrix: det ≈ {det:.2e}")

Output:

10×10 matrix: det ≈ 1.13e+04
50×50 matrix: det ≈ -3.88e+31
100×100 matrix: det ≈ 5.68e+77
200×200 matrix: det ≈ -1.36e+185

Determinant and Volume

The absolute value of the determinant represents the scaling factor for volumes under the linear transformation:

import numpy as np
import matplotlib.pyplot as plt

unit_square = np.array([
    [0, 0],
    [1, 0],
    [1, 1],
    [0, 1],
    [0, 0]  # Close the square
]).T

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

transformed = A @ unit_square

det = np.linalg.det(A)
print(f"Determinant: {det}")
print(f"Original area: 1")
print(f"Transformed area: {abs(det)}")

Output:

Determinant: 6.0
Original area: 1
Transformed area: 6.0

Determinant and Eigenvalues

The determinant equals the product of eigenvalues:

import numpy as np

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

det = np.linalg.det(matrix)

eigenvalues = np.linalg.eigvals(matrix)
product_of_eigenvalues = np.prod(eigenvalues)

print(f"Determinant: {det:.4f}")
print(f"Eigenvalues: {eigenvalues}")
print(f"Product of eigenvalues: {product_of_eigenvalues.real:.4f}")

Output:

Determinant: 10.0000
Eigenvalues: [5. 2.]
Product of eigenvalues: 10.0000

Practical Example: Checking System Solvability

import numpy as np

def analyze_system(A, b):
    """Analyze a linear system Ax = b."""
    det = np.linalg.det(A)
    
    print(f"Coefficient matrix:\n{A}")
    print(f"Determinant: {det:.6f}")
    
    if np.isclose(det, 0, atol=1e-10):
        print("System is singular - no unique solution")
        print("Possible scenarios:")
        print("  - No solution (inconsistent)")
        print("  - Infinite solutions (dependent)")
        return None
    
    x = np.linalg.solve(A, b)
    print(f"Unique solution: {x}")
    
    residual = np.linalg.norm(A @ x - b)
    print(f"Residual: {residual:.2e}")
    
    return x

A1 = np.array([[2, 1], [1, 3]])
b1 = np.array([5, 5])
analyze_system(A1, b1)

print("\n" + "="*40 + "\n")

A2 = np.array([[1, 2], [2, 4]])
b2 = np.array([3, 6])
analyze_system(A2, b2)

Output:

Coefficient matrix:
[[2 1]
 [1 3]]
Determinant: 5.000000
Unique solution: [2. 1.]
Residual: 0.00e+00

========================================

Coefficient matrix:
[[1 2]
 [2 4]]
Determinant: 0.000000
System is singular - no unique solution
Possible scenarios:
  - No solution (inconsistent)
  - Infinite solutions (dependent)

Summary

Function Use Case Returns
np.linalg.det(A) Standard determinant float
np.linalg.slogdet(A) Large matrices (sign, log|det|)
Determinant Value Matrix Property
≠ 0 Invertible (non-singular)
= 0 Singular (no inverse)
> 0 Preserves orientation
< 0 Reverses orientation
|det| Volume scaling factor

Best Practice: Use np.linalg.det() for standard calculations and np.isclose(det, 0) for singularity checks. Switch to slogdet() for matrices larger than ~50×50 to avoid numerical overflow.

Navigation