Algoritmos para Resolver Sistemas de Ecuaciones Lineales
Una guía profunda que cubre los métodos más usados, comparativas de rendimiento, buenas prácticas de implementación y ejemplos listos para ejecutar en Python.
¿Qué es un sistema de ecuaciones lineales?
Un sistema de ecuaciones lineales está compuesto por n ecuaciones con n incógnitas que pueden expresarse en forma matricial Ax = b, donde:
A– matriz de coeficientes (n×n)x– vector de incógnitasb– vector de términos independientes
Resolver el sistema consiste en encontrar x que satisfaga la igualdad.
Métodos Directos
Los métodos directos calculan la solución exacta (hasta la precisión de la aritmética) en un número finito de operaciones.
- Eliminación de Gauss (LU): descomposición
A = LUy sustitución hacia adelante/atrás. - Factorización de Cholesky: para matrices simétricas y definidas positivas.
- Descomposición QR: útil cuando
Aes rectangular o mal condicionada. - Resolución con
numpy.linalg.solve: envoltorio de LAPACK altamente optimizado.
Métodos Iterativos
Los métodos iterativos aproximan la solución mediante una sucesión de iteraciones, ideales para sistemas grandes y dispersos.
- Jacobi y Gauss‑Seidel: simples, requieren diagonal dominante.
- Conjugado Gradiente (CG): para matrices simétricas y definidas positivas.
- GMRES / BiCGSTAB: para matrices no simétricas o indefinidas.
- Precondicionadores: mejoran la convergencia (e.g., ILU, Jacobi).
Comparativa de Rendimiento y Escalabilidad
| Método | Complejidad Teórica | Mejor Uso | Ventajas | Desventajas |
|---|---|---|---|---|
| LU (Gauss) | O(n³) | n ≤ 10⁴ y matrices densas | Solución exacta, robusta | Costoso en memoria para n grande |
| Cholesky | O(n³/3) | Matrices simétricas‑positivas | Mitad del tiempo que LU | Requiere condición de positividad |
| Conjugado Gradiente | O(k·n²) (k = iteraciones) | n > 10⁵, matrices dispersas | Escala linealmente con n | Convergencia depende del condicionamiento |
| GMRES | O(k·nnz) | Sistemas no simétricos, muy grandes | Generalidad | Alto costo de almacenamiento de Krylov |
Implementación en Python
Usaremos numpy, scipy.linalg y scipy.sparse.linalg. Cada bloque incluye buenas prácticas como verificación de singularidad, precondicionamiento y manejo de excepciones.
1️⃣ Solución Directa con numpy.linalg.solve
import numpy as np
# Matriz A (densamente poblada) y vector b
a = np.array([[3, 2, -1],
[2, -2, 4],
[-1, 0.5, -1]], dtype=float)
b = np.array([1, -2, 0], dtype=float)
try:
x = np.linalg.solve(a, b)
print("Solución directa:", x)
except np.linalg.LinAlgError as e:
print("Error de factorización:", e)
Este método lanza LinAlgError si A es singular o casi singular.
2️⃣ Factorización LU con scipy.linalg.lu_factor y lu_solve
import scipy.linalg as la
lu, piv = la.lu_factor(a)
# Resolver usando la factorización pre‑calculada
x = la.lu_solve((lu, piv), b)
print("LU + solve:", x)
Ventaja: reutilizar lu_factor para múltiples b (sistemas con mismo A).
3️⃣ Solución Iterativa con Conjugado Gradiente (CG)
import numpy as np
from scipy.sparse import csr_matrix
from scipy.sparse.linalg import cg
# Crear una matriz dispersa grande (ejemplo 10,000×10,000)
n = 10000
A_dense = np.random.rand(n, n)
A_dense = (A_dense + A_dense.T) / 2 # Simétrica
A_dense += n * np.eye(n) # Asegurar PD
A_sparse = csr_matrix(A_dense)
b = np.random.rand(n)
# Precondicionador Jacobi (diagonal)
M = csr_matrix(np.diag(1 / A_sparse.diagonal()))
x, info = cg(A_sparse, b, M=M, tol=1e-8, maxiter=1000)
if info == 0:
print("CG convergió en menos de 1000 iteraciones")
else:
print("CG no convergió, código:", info)
El parámetro tol controla la precisión; info indica convergencia (0 = éxito).
4️⃣ GMRES para Matrices No Simétricas
from scipy.sparse.linalg import gmres
# Matriz aleatoria no simétrica
A = csr_matrix(np.random.rand(n, n))
x, info = gmres(A, b, restart=50, tol=1e-8, maxiter=500)
print("GMRES info:", info)
Mejores Prácticas y Consideraciones de Seguridad
- Validar la condición numérica: usar
np.linalg.cond(A). Sicond> 1e12, la solución será inestable. - Escalar los datos: normalizar filas/columnas para mejorar la convergencia iterativa.
- Evitar inyección de código al cargar matrices desde fuentes externas; usar
np.loadtxtcondtype=floaty validar tamaños. - Gestión de memoria en matrices dispersas: siempre usar
csr_matrixocsc_matrixpara operaciones de producto‑matriz‑vector. - Logging y monitoreo: registrar número de iteraciones y residuo final para depuración futura.
Resolución de Problemas Comunes
❗ Matriz Singular o Casi Singular
Symptom: LinAlgError: Singular matrix. Soluciones:
- Revisar si el modelo está mal planteado (ecuaciones linealmente dependientes).
- Aplicar regularización:
A_reg = A + λ·Iconλpequeño (ridge). - Usar
numpy.linalg.lstsqpara obtener solución de mínimos cuadrados.
❗ Convergencia Lenta en CG/GMRES
Posibles causas y remedios:
- Condicionamiento pobre → aplicar precondicionador más fuerte (ILU, AMG).
- Escala de variables → normalizar filas/columnas.
- Parámetro
toldemasiado estricto → relajar a 1e‑6 para pruebas.
Conclusión
Los sistemas de ecuaciones lineales siguen siendo el núcleo de innumerables aplicaciones (optimización, simulaciones físicas, IA). Elegir el algoritmo correcto depende del tamaño, densidad y propiedades de la matriz A. Con Python y las bibliotecas NumPy y SciPy dispones de herramientas altamente optimizadas que cubren desde soluciones directas para sistemas pequeños hasta métodos iterativos escalables para millones de variables.
Aplica las buenas prácticas descritas, monitoriza la condición numérica y aprovecha los precondicionadores para garantizar rapidez y robustez.
Algoritmos para Resolver Sistemas de Ecuaciones Lineales: Guía Completa con Ejemplos en Python