23. Método de eliminación de Gauss

La eliminación de Gauss transforma un sistema lineal en una forma escalonada equivalente. Después, una sustitución hacia atrás permite calcular las incógnitas desde la última ecuación hasta la primera.

23.1 Introducción

Resolver un sistema por sustitución directa se vuelve difícil cuando aumenta la cantidad de ecuaciones. La eliminación de Gauss organiza el trabajo mediante operaciones sistemáticas sobre las filas.

El método tiene dos fases:

  1. Eliminación hacia adelante: obtener una matriz escalonada.
  2. Sustitución hacia atrás: calcular las incógnitas desde la última fila.
Sistema original ⟶ forma escalonada ⟶ sustitución hacia atrás ⟶ solución

23.2 Matriz aumentada

El sistema se representa mediante [A | b]. Cada fila contiene los coeficientes de una ecuación y su término independiente.

x + y = 5
2x − y = 1

[A | b] = [[1, 1 | 5], [2, −1 | 1]]
function aumentar(A, b) {
  if (A.length !== b.length) throw new Error("Dimensiones incompatibles");
  return A.map((fila, i) => [...fila, b[i]]);
}

console.log(aumentar([[1, 1], [2, -1]], [5, 1]));

23.3 Operaciones elementales por fila

Las siguientes operaciones producen sistemas equivalentes, es decir, conservan el conjunto de soluciones:

  • Intercambiar dos filas: Fi ↔ Fj.
  • Multiplicar una fila por un número no nulo: Fi ← kFi.
  • Sumar a una fila un múltiplo de otra: Fi ← Fi + kFj.
const matriz = [[1, 1, 5], [2, -1, 1]];

// F2 recibe F2 - 2F1.
matriz[1] = matriz[1].map(
  (valor, j) => valor - 2 * matriz[0][j]
);
console.log(matriz); // [[1, 1, 5], [0, -3, -9]]

23.4 Forma escalonada

Una matriz se encuentra en forma escalonada cuando:

  • Las filas completamente nulas están debajo de las no nulas.
  • El pivote de cada fila aparece a la derecha del pivote anterior.
  • Todos los valores debajo de cada pivote son cero.
[[2, 1, −1 | 8], [0, 3, 2 | 5], [0, 0, 4 | 12]]

Esta forma representa un sistema triangular, fácil de resolver comenzando por la última ecuación.

23.5 Selección del pivote

El pivote es el coeficiente utilizado para eliminar los valores que están debajo de él. Si el candidato es cero, debe intercambiarse la fila con otra que tenga un valor no nulo en esa columna.

En cálculo numérico se aplica pivoteo parcial: se selecciona el elemento de mayor valor absoluto entre las filas disponibles.

const matriz = [[0.001, 2, 3], [4, 5, 6], [-2, 1, 0]];
const columna = 0;
let filaPivote = 0;

for (let fila = 1; fila < matriz.length; fila++) {
  if (Math.abs(matriz[fila][columna]) > Math.abs(matriz[filaPivote][columna])) {
    filaPivote = fila;
  }
}
console.log(filaPivote); // 1, porque |4| es el mayor

23.6 Eliminación debajo del pivote

Para anular el elemento aik situado debajo del pivote akk, se calcula el factor:

factor = aik / akk
Fi ← Fi − factor · Fk
const pivote = [2, 1, 5];
const fila = [6, 4, 17];
const factor = fila[0] / pivote[0];
const nuevaFila = fila.map((valor, j) => valor - factor * pivote[j]);

console.log(factor);    // 3
console.log(nuevaFila); // [0, 1, 2]

23.7 Ejemplo completo de orden 2

Partimos del sistema x + y = 5, 2x − y = 1:

[[1, 1 | 5], [2, −1 | 1]]
F2 ← F2 − 2F1
[[1, 1 | 5], [0, −3 | −9]]

La segunda fila indica −3y = −9, entonces y = 3. La primera ecuación produce x = 5 − 3 = 2.

const fila1 = [1, 1, 5];
const fila2 = [0, -3, -9];

const y = fila2[2] / fila2[1];
const x = (fila1[2] - fila1[1] * y) / fila1[0];
console.log({ x, y }); // { x: 2, y: 3 }

23.8 Ejemplo de orden 3

Consideremos:

x + y + z = 6
2x − y + z = 3
x + 2y − z = 2

La matriz aumentada inicial es [[1, 1, 1 | 6], [2, −1, 1 | 3], [1, 2, −1 | 2]]. Primero aplicamos F2 − 2F1 y F3 − F1.

const F1 = [1, 1, 1, 6];
const F2 = [2, -1, 1, 3].map((v, j) => v - 2 * F1[j]);
const F3 = [1, 2, -1, 2].map((v, j) => v - F1[j]);

console.log(F2); // [0, -3, -1, -9]
console.log(F3); // [0, 1, -2, -4]

23.9 Continuación del ejemplo de orden 3

Conviene intercambiar las filas segunda y tercera para utilizar el pivote 1. Después se aplica F3 ← F3 + 3F2:

[[1, 1, 1 | 6], [0, 1, −2 | −4], [0, 0, −7 | −21]]

Ahora el sistema está escalonado y listo para la sustitución hacia atrás.

const fila2 = [0, 1, -2, -4];
const fila3Original = [0, -3, -1, -9];
const fila3 = fila3Original.map((v, j) => v + 3 * fila2[j]);

console.log(fila3); // [0, 0, -7, -21]

23.10 Sustitución hacia atrás

Se resuelve desde la última fila hacia la primera:

  1. −7z = −21, entonces z = 3.
  2. y − 2z = −4, entonces y = 2.
  3. x + y + z = 6, entonces x = 1.
const z = -21 / -7;
const y = -4 + 2 * z;
const x = 6 - y - z;

console.log({ x, y, z }); // { x: 1, y: 2, z: 3 }

23.11 Sustitución hacia atrás general

Para una matriz aumentada triangular de n filas, cada incógnita se calcula restando los términos ya conocidos y dividiendo por el coeficiente diagonal.

function sustitucionAtras(matriz, tolerancia = 1e-12) {
  const n = matriz.length;
  const x = Array(n).fill(0);

  for (let i = n - 1; i >= 0; i--) {
    if (Math.abs(matriz[i][i]) <= tolerancia) return null;
    let restante = matriz[i][n];
    for (let j = i + 1; j < n; j++) {
      restante -= matriz[i][j] * x[j];
    }
    x[i] = restante / matriz[i][i];
  }
  return x;
}

const triangular = [[1, 1, 1, 6], [0, 1, -2, -4], [0, 0, -7, -21]];
console.log(sustitucionAtras(triangular)); // [1, 2, 3]

23.12 Implementación de la eliminación

Esta función escalona una matriz aumentada cuadrada. El pivoteo parcial se realiza antes de eliminar cada columna.

function escalonar(aumentada, tolerancia = 1e-12) {
  const m = aumentada.map(fila => fila.map(Number));
  const n = m.length;

  for (let k = 0; k < n; k++) {
    let mejor = k;
    for (let i = k + 1; i < n; i++) {
      if (Math.abs(m[i][k]) > Math.abs(m[mejor][k])) mejor = i;
    }
    if (Math.abs(m[mejor][k]) <= tolerancia) return null;
    [m[k], m[mejor]] = [m[mejor], m[k]];

    for (let i = k + 1; i < n; i++) {
      const factor = m[i][k] / m[k][k];
      for (let j = k; j <= n; j++) {
        m[i][j] -= factor * m[k][j];
      }
    }
  }
  return m;
}

const sistema = [[1, 1, 1, 6], [2, -1, 1, 3], [1, 2, -1, 2]];
console.log(escalonar(sistema));

23.13 Solucionador completo en JavaScript

Podemos reunir la eliminación y la sustitución hacia atrás en una sola función. Esta versión resuelve sistemas cuadrados con solución única.

function resolverGauss(A, b, tolerancia = 1e-12) {
  const n = A.length;
  if (n === 0 || b.length !== n || A.some(fila => fila.length !== n)) {
    throw new Error("Se requiere un sistema cuadrado");
  }
  const m = A.map((fila, i) => [...fila.map(Number), Number(b[i])]);

  for (let k = 0; k < n; k++) {
    let mejor = k;
    for (let i = k + 1; i < n; i++) {
      if (Math.abs(m[i][k]) > Math.abs(m[mejor][k])) mejor = i;
    }
    if (Math.abs(m[mejor][k]) <= tolerancia) return null;
    [m[k], m[mejor]] = [m[mejor], m[k]];

    for (let i = k + 1; i < n; i++) {
      const factor = m[i][k] / m[k][k];
      for (let j = k; j <= n; j++) m[i][j] -= factor * m[k][j];
    }
  }

  const x = Array(n).fill(0);
  for (let i = n - 1; i >= 0; i--) {
    let valor = m[i][n];
    for (let j = i + 1; j < n; j++) valor -= m[i][j] * x[j];
    x[i] = valor / m[i][i];
  }
  return x;
}

const A = [[1, 1, 1], [2, -1, 1], [1, 2, -1]];
console.log(resolverGauss(A, [6, 3, 2])); // [1, 2, 3]

23.14 Verificación del resultado

Un algoritmo debe comprobarse sustituyendo la solución obtenida en Ax = b. Por los errores decimales, se comparan los valores con una tolerancia.

function verificar(A, x, b, tolerancia = 1e-10) {
  return A.every((fila, i) => {
    const valor = fila.reduce((suma, a, j) => suma + a * x[j], 0);
    return Math.abs(valor - b[i]) < tolerancia;
  });
}

const A = [[1, 1, 1], [2, -1, 1], [1, 2, -1]];
console.log(verificar(A, [1, 2, 3], [6, 3, 2])); // true

23.15 Filas especiales y clasificación

Durante la eliminación pueden aparecer filas que revelan el tipo de sistema:

Fila escalonadaInterpretación
[0, 0, ..., 0 | 0]Ecuación redundante; puede haber variables libres
[0, 0, ..., 0 | c], c ≠ 0Contradicción; el sistema no tiene solución
Un pivote por cada incógnitaSolución única
function tipoFila(fila, tolerancia = 1e-12) {
  const coeficientes = fila.slice(0, -1);
  const termino = fila.at(-1);
  const todosCero = coeficientes.every(v => Math.abs(v) <= tolerancia);
  if (!todosCero) return "fila con pivote";
  return Math.abs(termino) <= tolerancia ? "redundante" : "contradicción";
}

console.log(tipoFila([0, 0, 5])); // contradicción

23.16 Gauss y el rango

Cada pivote obtenido durante la eliminación corresponde a una fila independiente. Por eso el número de pivotes de A es rango(A).

Comparar los pivotes de A con los de [A | b] permite distinguir:

  • Solución única: un pivote por incógnita.
  • Infinitas soluciones: faltan pivotes, pero no hay contradicción.
  • Sin solución: aparece una fila contradictoria.
El mismo proceso sirve para resolver el sistema y para analizar su compatibilidad.

23.17 Costo computacional

Para una matriz cuadrada de orden n, la eliminación requiere una cantidad de operaciones proporcional a n3. La sustitución hacia atrás cuesta aproximadamente n2.

El costo cúbico explica por qué las matrices muy grandes requieren implementaciones optimizadas, estructuras dispersas o métodos especializados.

function crecimientoAproximado(n) {
  return n ** 3;
}

console.log(crecimientoAproximado(10));  // 1000
console.log(crecimientoAproximado(100)); // 1000000

23.18 Estabilidad y errores frecuentes

El pivoteo parcial ayuda a controlar el error numérico, pero una matriz mal condicionada aún puede producir soluciones sensibles a pequeñas variaciones.

Errores habituales:

  • Aplicar una operación solo a los coeficientes y olvidar el término independiente.
  • Dividir por un pivote cero sin intercambiar filas.
  • Modificar la matriz original cuando debe conservarse.
  • Detener la eliminación antes de anular toda la columna inferior.
  • Confundir forma escalonada con forma escalonada reducida.
  • No verificar la solución obtenida.

23.19 Qué debes recordar de este tema

  • Gauss transforma [A | b] en una matriz escalonada equivalente.
  • Las operaciones elementales por fila conservan las soluciones.
  • El pivote se usa para anular los coeficientes situados debajo.
  • El pivoteo parcial elige el mayor valor absoluto disponible.
  • La sustitución hacia atrás comienza en la última ecuación.
  • Una fila [0 ... 0 | c], con c distinto de cero, indica contradicción.
  • El número de pivotes coincide con el rango.
  • El resultado debe verificarse mediante Ax ≈ b.

23.20 Conclusión

La eliminación de Gauss convierte un sistema en una estructura triangular mediante operaciones sencillas y repetibles. Su combinación con la sustitución hacia atrás forma un algoritmo general para sistemas con solución única.

En el próximo tema estudiaremos Gauss-Jordan, que continúa la reducción hasta eliminar también los valores situados sobre cada pivote.