Álgebra lineal numérica · Tema 17

Métodos iterativos de Jacobi y Gauss-Seidel

Cómo aproximar la solución de sistemas lineales mediante actualizaciones sucesivas, controlar la convergencia y aprovechar matrices grandes con muchos ceros.

01 · Otra forma de resolver

De una factorización exacta a una sucesión de aproximaciones

Gauss y LU son métodos directos: en aritmética exacta producen la solución después de una cantidad finita de operaciones. Los métodos iterativos comienzan con una estimación x⁽⁰⁾ y construyen:

x⁽⁰⁾, x⁽¹⁾, x⁽²⁾, …

El objetivo es que la sucesión se acerque a la solución de Ax=b. Podemos detenerla cuando el residuo o el cambio entre iteraciones alcance la tolerancia requerida.

02 · Cuándo convienen

Sistemas grandes y matrices dispersas

Una matriz es dispersa cuando la mayoría de sus coeficientes son cero. Este patrón aparece al discretizar temperaturas, difusión, redes, estructuras, imágenes y ecuaciones diferenciales.

Métodos directos

Factorizar la matriz

Son robustos para problemas densos moderados, pero pueden consumir mucha memoria y crear nuevos elementos no nulos.

Métodos iterativos

Aplicar actualizaciones

Pueden trabajar con los coeficientes no nulos y detenerse cuando la precisión ya resulta suficiente.

No siempre convergen, por lo que la estructura de A, el orden de las ecuaciones y el criterio de parada son fundamentales.

03 · Construcción

Despejar cada incógnita

La fila i del sistema es:

aiixi + Σj≠iaijxj = bi

Si aᵢᵢ≠0, podemos despejar:

xi = (bi − Σj≠iaijxj) / aii

Al evaluar repetidamente estas expresiones obtenemos un proceso de punto fijo. Jacobi y Gauss-Seidel se diferencian en qué versión de cada componente utilizan durante una iteración.

04 · Actualización simultánea

Método de Jacobi

Jacobi calcula todos los componentes nuevos usando únicamente los valores de la iteración anterior:

xi(k+1) = (bi − Σj≠iaijxj(k)) / aii

Necesita dos vectores: uno conserva x⁽ᵏ⁾ y otro recibe x⁽ᵏ⁺¹⁾. Esto evita mezclar iteraciones.

leer x⁽ᵏ⁾→calcular todos→crear x⁽ᵏ⁺¹⁾→comparar

Como cada componente nuevo depende del mismo vector anterior, muchos cálculos pueden realizarse en paralelo.

05 · Ejemplo manual

Primeras iteraciones de Jacobi

Consideremos el sistema, cuya solución es (1,2,−1):

10x − y + 2z = 6
−x + 11y − z = 22
2x − y + 10z = −10

Despejamos:

x = (6+y−2z)/10
y = (22+x+z)/11
z = (−10−2x+y)/10

Desde x⁽⁰⁾=(0,0,0):

Aproximaciones simultáneas de Jacobi.
kxyz||b−Ax||∞
000022
10.6000002.000000−1.0000004.000000
21.0000001.963636−0.9200000.836364

En la segunda iteración, los tres cálculos usan exclusivamente (0.6,2,−1), aunque un componente nuevo ya haya sido obtenido.

06 · Actualización inmediata

Método de Gauss-Seidel

Gauss-Seidel usa inmediatamente los componentes recién calculados. En la fila i, utiliza valores de la iteración nueva para j<i y valores anteriores para j>i:

xi(k+1) = [bi − Σj<iaijxj(k+1) − Σj>iaijxj(k)] / aii

Con el mismo sistema y x⁽⁰⁾=(0,0,0), la primera iteración es:

  1. x⁽¹⁾=0.6.
  2. y⁽¹⁾=(22+0.6+0)/11≈2.054545, usando el nuevo x.
  3. z⁽¹⁾=(−10−2(0.6)+2.054545)/10≈−0.914545, usando los nuevos x e y.

Esta reutilización suele acelerar la convergencia, pero introduce una dependencia secuencial entre componentes.

07 · Diferencia esencial

Jacobi frente a Gauss-Seidel

Comparación de las dos iteraciones estacionarias.
CaracterísticaJacobiGauss-Seidel
Valores utilizadosTodos de la iteración anteriorNuevos cuando ya están disponibles
Vectores de trabajoDosUno puede bastar
ParalelizaciónMás directaDependencias secuenciales
Velocidad típicaMenorFrecuentemente mayor
Garantía universalNoNo

Que Gauss-Seidel sea frecuentemente más rápido no significa que siempre converja cuando Jacobi converge, ni que cualquier orden de las filas produzca el mismo comportamiento.

08 · Matrices de iteración

Separar A en diagonal, parte inferior y superior

Escribimos A=D+L+U, donde D contiene la diagonal, L la parte estrictamente inferior y U la superior.

Jacobi:   x⁽ᵏ⁺¹⁾ = −D⁻¹(L+U)x⁽ᵏ⁾ + D⁻¹b
Gauss-Seidel:   x⁽ᵏ⁺¹⁾ = −(D+L)⁻¹Ux⁽ᵏ⁾ + (D+L)⁻¹b

Ambos tienen la forma x⁽ᵏ⁺¹⁾=Tx⁽ᵏ⁾+c. La convergencia desde cualquier valor inicial ocurre exactamente cuando el radio espectral de la matriz de iteración satisface:

ρ(T) < 1

El radio espectral es la mayor magnitud de los valores propios de T. En la práctica suelen utilizarse condiciones suficientes más fáciles de comprobar.

09 · Condiciones útiles

Cuándo podemos esperar convergencia

Dominancia diagonal estricta

Si para cada fila se cumple:

|aii| > Σj≠i|aij|

entonces Jacobi y Gauss-Seidel convergen. Es una condición suficiente, no necesaria: algunas matrices no dominantes también convergen.

Matriz simétrica definida positiva

Si A es simétrica y xᵀAx>0 para todo x≠0, Gauss-Seidel converge. Para Jacobi, esta propiedad por sí sola no constituye la misma garantía general.

Orden de ecuaciones

Una permutación puede colocar coeficientes convenientes en la diagonal y mejorar la dominancia. Sin embargo, reordenar no siempre convierte un sistema divergente en convergente.

10 · Diagnóstico

Residuo, cambio y presupuesto

Una implementación robusta combina más de una señal:

residuo relativo = ||b−Ax⁽ᵏ⁾||∞ / max(1,||b||∞)
cambio relativo = ||x⁽ᵏ⁾−x⁽ᵏ⁻¹⁾||∞ / max(1,||x⁽ᵏ⁾||∞)
  • El residuo comprueba la ecuación original.
  • El cambio detecta estabilización o estancamiento.
  • El máximo de iteraciones limita el costo.
  • La finitud evita continuar después de producir NaN o infinito.
  • Un crecimiento sostenido del residuo permite diagnosticar divergencia.

11 · JavaScript

Un solucionador para ambos métodos

function resolverIterativo(A, b, opciones = {}) {
  const n = A.length;
  const metodo = opciones.metodo ?? "jacobi";
  const tolerancia = opciones.tolerancia ?? 1e-10;
  const maxIter = opciones.maxIter ?? 1000;
  let x = opciones.inicial ? [...opciones.inicial] : Array(n).fill(0);

  if (n === 0 || b.length !== n || A.some(fila => fila.length !== n)) {
    throw new Error("Dimensiones incompatibles");
  }
  if (!['jacobi', 'gauss-seidel'].includes(metodo)) {
    throw new Error("Método desconocido");
  }
  if (A.some((fila, i) => !Number.isFinite(fila[i]) || fila[i] === 0)) {
    throw new Error("La diagonal debe ser finita y no nula");
  }

  const normaB = Math.max(1, ...b.map(Math.abs));
  const residuo = vector => Math.max(...A.map((fila, i) =>
    Math.abs(b[i] - fila.reduce((suma, aij, j) =>
      suma + aij * vector[j], 0)))) / normaB;

  for (let iteracion = 1; iteracion <= maxIter; iteracion++) {
    const anterior = [...x];
    const siguiente = metodo === 'jacobi' ? Array(n).fill(0) : x;

    for (let i = 0; i < n; i++) {
      let suma = 0;
      for (let j = 0; j < n; j++) {
        if (j === i) continue;
        const xj = metodo === 'gauss-seidel' && j < i
          ? siguiente[j] : anterior[j];
        suma += A[i][j] * xj;
      }
      siguiente[i] = (b[i] - suma) / A[i][i];
    }
    x = siguiente;
    const cambio = Math.max(...x.map((valor, i) =>
      Math.abs(valor - anterior[i]))) / Math.max(1, ...x.map(Math.abs));
    const r = residuo(x);

    if (!x.every(Number.isFinite)) {
      return { solucion: x, iteraciones: iteracion,
        convergio: false, motivo: "valor_no_finito" };
    }
    if (r <= tolerancia && cambio <= tolerancia) {
      return { solucion: x, iteraciones: iteracion,
        residuo: r, cambio, convergio: true, motivo: "tolerancia" };
    }
  }
  return { solucion: x, iteraciones: maxIter, residuo: residuo(x),
    convergio: false, motivo: "max_iter" };
}

const A = [[10, -1, 2], [-1, 11, -1], [2, -1, 10]];
const b = [6, 22, -10];
console.log(resolverIterativo(A, b, { metodo: 'gauss-seidel' }));

En una aplicación de producción también conviene validar todos los coeficientes, registrar el historial y detectar crecimiento persistente del residuo.

12 · Implementación eficiente

No recorrer ceros innecesarios

Una matriz densa de n×n requiere recorrer n² coeficientes por iteración. Si solo existen nnz valores no nulos, una estructura dispersa reduce el trabajo a aproximadamente:

costo por iteración = O(nnz)

En lugar de almacenar cada fila completa, podemos guardar pares [columna,valor]:

function productoDisperso(filas, x) {
  return filas.map(fila =>
    fila.reduce((suma, [columna, valor]) =>
      suma + valor * x[columna], 0)
  );
}

const filas = [
  [[0, 10], [1, -1], [2, 2]],
  [[0, -1], [1, 11], [2, -1]],
  [[0, 2], [1, -1], [2, 10]]
];
console.log(productoDisperso(filas, [1, 2, -1])); // [6, 22, -10]

Formatos como CSR almacenan todos los valores, índices de columna y comienzos de fila en arreglos compactos. Son habituales en bibliotecas numéricas.

13 · Ajustar la actualización

Relajación y método SOR

Podemos combinar el valor anterior con la propuesta de Gauss-Seidel mediante un parámetro ω:

xi(k+1) ← (1−ω)xi(k) + ω x̂i(k+1)
0<ω<1
Subrelajación: pasos más prudentes, útiles para amortiguar oscilaciones.
ω=1
Recupera exactamente el método de Gauss-Seidel.
1<ω<2
Sobrerrelajación: puede acelerar ciertos problemas; una mala elección puede empeorar o destruir la convergencia.
Elegir ω
Depende de la matriz. No existe un valor universalmente óptimo.

SOR muestra una idea general de los métodos iterativos: además de la fórmula, importa cómo se controla y precondiciona el proceso.

14 · Exploración interactiva

Laboratorio: comparar la caída del residuo

Elegí un sistema, un valor inicial y la cantidad de iteraciones. El gráfico muestra el residuo relativo de Jacobi y Gauss-Seidel en escala logarítmica.

EXPERIMENTO 17

Dos actualizaciones, dos trayectorias

Sistema diagonal dominante

Los resultados numéricos aparecen debajo.
JacobiCalculando…
Gauss-SeidelCalculando…
Mejor aproximación—
Diagnóstico—

La solución de referencia es [1, 2, −1].

Preguntas para explorar

  1. En el sistema dominante, compará las pendientes de ambas curvas.
  2. Cambiá el valor inicial. ¿Modifica la solución límite o principalmente la trayectoria?
  3. Observá que la dominancia diagonal es suficiente, pero no necesaria, usando el sistema simétrico.
  4. En los casos desfavorable y divergente, buscá crecimiento u oscilación del residuo.

15 · Comprensión

Confusiones frecuentes

«Jacobi y Gauss-Seidel usan los mismos valores en cada fila»

Jacobi usa solo la iteración anterior. Gauss-Seidel incorpora inmediatamente los componentes nuevos ya calculados.

«Si la diagonal no contiene ceros, el método converge»

Eso permite ejecutar la fórmula, pero la convergencia depende de la matriz de iteración y requiere condiciones adicionales.

«La dominancia diagonal es obligatoria»

Es una condición suficiente muy útil, no una condición necesaria. Existen sistemas convergentes que no la cumplen.

«Más iteraciones siempre mejoran la respuesta»

Si el proceso diverge, cada iteración puede empeorarla. Incluso al converger, llega un punto donde el redondeo limita la mejora.

«Un método iterativo devuelve una solución exacta»

Devuelve una aproximación acompañada por tolerancia, residuo, cantidad de iteraciones y diagnóstico de convergencia.

16 · Práctica guiada

Ejercicios

Ejercicio 1: una iteración de Jacobi

Desde (0,0,0), calculá la primera iteración para el sistema del ejemplo.

Ver solución

Al sustituir ceros en los despejes se obtiene x=6/10=0.6, y=22/11=2 y z=−10/10=−1.

Ejercicio 2: Gauss-Seidel

¿Por qué el primer valor de y es aproximadamente 2.054545 y no 2?

Ver solución

Porque Gauss-Seidel usa inmediatamente x⁽¹⁾=0.6: y⁽¹⁾=(22+0.6+0)/11≈2.054545.

Ejercicio 3: dominancia diagonal

¿Es estrictamente dominante la matriz [[4,−1,0],[−1,4,−1],[0,−1,3]]?

Ver solución razonada

Sí. Por filas: 4>1, 4>1+1 y 3>1. Por lo tanto, Jacobi y Gauss-Seidel convergen.

Ejercicio 4: criterio de parada

Si el cambio relativo es 10⁻¹² pero el residuo relativo es 10⁻³, ¿deberíamos aceptar la solución con tolerancia 10⁻⁸?

Ver solución

No. La iteración se ha estabilizado, pero todavía no satisface suficientemente el sistema original. Puede existir estancamiento.

Ejercicio 5: dominancia en código

Implementá una función que compruebe dominancia diagonal estricta por filas.

Ver una posible solución
function esDiagonalDominante(A) {
  return A.every((fila, i) => {
    const fueraDiagonal = fila.reduce((suma, valor, j) =>
      suma + (j === i ? 0 : Math.abs(valor)), 0);
    return Math.abs(fila[i]) > fueraDiagonal;
  });
}

console.log(esDiagonalDominante([
  [4, -1, 0],
  [-1, 4, -1],
  [0, -1, 3]
])); // true

17 · Síntesis

Ideas para recordar

  • Los métodos iterativos generan aproximaciones sucesivas a la solución de Ax=b.
  • Jacobi calcula todos los componentes desde el vector anterior.
  • Gauss-Seidel utiliza inmediatamente los valores nuevos disponibles.
  • La convergencia general está determinada por el radio espectral de la matriz de iteración.
  • La dominancia diagonal estricta garantiza la convergencia de ambos métodos.
  • El residuo y el cambio relativo deben acompañar al máximo de iteraciones.
  • Las estructuras dispersas evitan recorrer y almacenar coeficientes nulos.
  • El orden de las ecuaciones y la relajación pueden modificar el comportamiento.
  • El resultado debe informar si realmente convergió.

En el próximo tema iniciaremos el bloque de interpolación y aproximación de datos: construiremos funciones a partir de muestras y distinguiremos interpolar de ajustar.