Cálculo de la inversa de una matriz en Python
Aprende el fundamento matemático, los algoritmos más usados (Gauss‑Jordan, LU, adjunta) y cómo implementarlos paso a paso en Python, con ejemplos reales y comparativas de rendimiento.
1. Fundamentos matemáticos
Una matriz cuadrada A ∈ ℝⁿˣⁿ es invertible si existe A⁻¹ tal que A·A⁻¹ = A⁻¹·A = Iₙ. La existencia depende de que det(A) ≠ 0 y que la matriz sea de rango completo.
1.1. Métodos clásicos
- Gauss‑Jordan: transforma [A|I] en [I|A⁻¹] mediante eliminaciones elementales.
- Descomposición LU: calcula A = L·U y después resuelve dos sistemas triangulares para obtener A⁻¹.
- Método de la adjunta: A⁻¹ = (1/det(A))·adj(A), útil solo para matrices pequeñas por su complejidad O(n³).
2. Implementación paso a paso en Python (sin librerías externas)
2.1. Algoritmo Gauss‑Jordan
import copy
def gauss_jordan_inverse(matrix):
n = len(matrix)
# Copia la matriz y crea la identidad ampliada
A = [list(row) for row in matrix]
I = [[float(i == j) for j in range(n)] for i in range(n)]
for col in range(n):
# 1️⃣ Busca pivote
pivot_row = max(range(col, n), key=lambda r: abs(A[r][col]))
if abs(A[pivot_row][col]) < 1e-12:
raise ValueError('La matriz es singular y no tiene inversa')
# 2️⃣ Intercambia filas si es necesario
A[col], A[pivot_row] = A[pivot_row], A[col]
I[col], I[pivot_row] = I[pivot_row], I[col]
# 3️⃣ Normaliza la fila pivote
piv = A[col][col]
A[col] = [elem / piv for elem in A[col]]
I[col] = [elem / piv for elem in I[col]]
# 4️⃣ Elimina la columna en otras filas
for r in range(n):
if r != col:
factor = A[r][col]
A[r] = [a - factor * b for a, b in zip(A[r], A[col])]
I[r] = [a - factor * b for a, b in zip(I[r], I[col])]
return I
# Ejemplo de uso
A = [[4, 7], [2, 6]]
print('Matriz original:', A)
print('Inversa calculada:', gauss_jordan_inverse(A))
El algoritmo tiene complejidad O(n³) y es adecuado para matrices de tamaño medio (hasta ~500×500) cuando no se dispone de librerías optimizadas.
2.2. Comparativa rápida con numpy.linalg.inv
import numpy as np, time
A = np.random.rand(500, 500)
# Versión NumPy
start = time.time()
inv_np = np.linalg.inv(A)
print('Tiempo NumPy:', time.time() - start)
# Versión Gauss‑Jordan (solo para demostración, no recomendado en producción)
start = time.time()
inv_gj = gauss_jordan_inverse(A.tolist())
print('Tiempo Gauss‑Jordan puro Python:', time.time() - start)
En máquinas modernas, numpy.linalg.inv suele ser entre 10 y 50 veces más rápido gracias a BLAS/LAPACK subyacentes y a la ejecución en C.
3. Tabla comparativa de algoritmos
Métodos clásicos
- Gauss‑Jordan: fácil de implementar, O(n³), sin dependencias externas.
- LU + sustitución: ligeramente más rápido que Gauss‑Jordan, reutilizable para resolver múltiples sistemas.
- Adjunta: solo práctico para n ≤ 3 por su sobrecarga de cálculo de cofactores.
Implementaciones modernas
- NumPy / SciPy: usa LAPACK, multihilo y SIMD; O(n³) pero con constante mucho menor.
- PyTorch / TensorFlow: aceleración GPU, ideal para tensores de gran dimensión en deep learning.
- CuPy: API compatible con NumPy pero ejecuta en GPU (CUDA).
4. Buenas prácticas y optimización
- Evita calcular la inversa cuando sea posible. En la mayoría de los casos, resolver Ax = b mediante
solvees más estable y rápido. - Condición numérica: verifica el número de condición con
np.linalg.cond. Valores > 1e12 indican posible pérdida de precisión. - Uso de tipos de dato adecuados: para matrices muy grandes, considera
float32en GPU para reducir el consumo de memoria. - Paralelismo: si trabajas con lotes de matrices, usa
numpy.einsumotorch.batch_inversepara aprovechar vectorización.
5. Solución de problemas comunes
5.1. "Matrix is singular"
El pivote es cero o cercano a cero. Soluciones:
- Aplicar pivoting parcial (ya incluido en el ejemplo).
- Re‑escalar la matriz para mejorar la estabilidad numérica.
- Si la singularidad es estructural, reconsidera el modelo: tal vez la ecuación no tenga solución única.
5.2. Pérdida de precisión
Usa np.float64 o Decimal para casos críticos; sin embargo, el coste computacional aumenta.
6. Escalabilidad y despliegue en producción
Para entornos de alto rendimiento:
- Empaqueta la lógica en una API REST con
FastAPIy reutiliza la función de inversa de NumPy. - Usa Docker o Podman para garantizar versiones coherentes de BLAS/LAPACK (por ejemplo,
openblas). - En clústeres Kubernetes, habilita
nodeAffinitypara nodos con GPUs y ejecuta la versiónCuPycuando sea necesario.
# Dockerfile minimalista con NumPy y OpenBLAS
FROM python:3.12-slim
RUN apt-get update && apt-get install -y libopenblas-dev && rm -rf /var/lib/apt/lists/*
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . /app
WORKDIR /app
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Algoritmo de cálculo de la inversa de una matriz: teoría, implementación en Python y comparativas de rendimiento