40. Diagonalización de matrices

Diagonalizar una matriz consiste en describir su transformación desde una base de vectores propios. En esas coordenadas, aplicar la matriz equivale a escalar cada componente de forma independiente.

40.1 Introducción

Las matrices diagonales son especialmente fáciles de interpretar y calcular: cada componente se multiplica por un elemento diagonal, sin mezclarse con las demás.

Algunas matrices no diagonales representan una transformación diagonal cuando elegimos una base apropiada de vectores propios. Encontrar esa base es el objetivo de la diagonalización.

Diagonalizar es simplificar una transformación mediante un cambio de coordenadas.

40.2 Definición

Una matriz cuadrada A es diagonalizable si existe una matriz invertible P y una matriz diagonal D tales que:

A = PDP-1

Equivalentemente:

D = P-1AP

A y D son matrices semejantes: representan la misma transformación en bases distintas.

40.3 Significado de P y D

Las columnas de P son vectores propios independientes de A. Los elementos diagonales de D son sus valores propios asociados, colocados en el mismo orden.

P = [v1 ... vn]
D = diag(λ1, ..., λn)
Avi = λivi

Si se cambia el orden de las columnas de P, debe cambiarse de igual modo el orden de la diagonal de D.

40.4 Condición de diagonalización

Una matriz n × n es diagonalizable si y solo si posee n vectores propios linealmente independientes.

A diagonalizable ⇔ existe una base completa de vectores propios.

La independencia hace que P sea invertible. Si faltan direcciones propias, no puede construirse el cambio de base.

const v1 = [1, 1];
const v2 = [1, -1];
const P = [[v1[0], v2[0]], [v1[1], v2[1]]];
const detP = P[0][0] * P[1][1] - P[0][1] * P[1][0];

console.log(P);    // [[1, 1], [1, -1]]
console.log(detP); // -2: P es invertible

40.5 Valores propios distintos

Los vectores propios asociados a valores propios distintos son independientes. Por eso:

Una matriz n × n con n valores propios distintos es diagonalizable.

Esta condición es suficiente, pero no necesaria: una matriz con valores repetidos también puede ser diagonalizable.

function tieneDosValoresDistintos(A, tolerancia = 1e-10) {
  const traza = A[0][0] + A[1][1];
  const det = A[0][0] * A[1][1] - A[0][1] * A[1][0];
  return traza ** 2 - 4 * det > tolerancia;
}

console.log(tieneDosValoresDistintos([[2, 1], [1, 2]])); // true

40.6 Valores propios repetidos

Cuando λ tiene multiplicidad algebraica mayor que uno, deben existir suficientes vectores propios independientes en Eλ.

MatrizDirecciones propias para λ = 2¿Diagonalizable?
[[2, 0], [0, 2]]Dos independientes; todo ℝ2
[[2, 1], [0, 2]]Solo una dirección independienteNo
Para cada λ: multiplicidad geométrica debe igualar su multiplicidad algebraica.

40.7 Procedimiento para diagonalizar

  1. Calcular los valores propios de A.
  2. Encontrar una base de cada espacio propio ker(A − λI).
  3. Comprobar que en total haya n vectores propios independientes.
  4. Colocarlos como columnas de P.
  5. Construir D con los valores propios en el orden correspondiente.
  6. Verificar AP = PD o A = PDP-1.

40.8 Ejemplo: valores y vectores propios

Sea A = [[2, 1], [1, 2]]. Sus valores propios y direcciones son:

λ1 = 3,   v1 = (1, 1)
λ2 = 1,   v2 = (1, −1)

Como los vectores son independientes, A es diagonalizable.

const A = [[2, 1], [1, 2]];
const pares = [
  { lambda: 3, vector: [1, 1] },
  { lambda: 1, vector: [1, -1] }
];

for (const { lambda, vector } of pares) {
  const Av = A.map(fila => fila.reduce((s, valor, i) => s + valor * vector[i], 0));
  console.log(Av, vector.map(valor => lambda * valor));
}

40.9 Construcción de P y D

Colocando los pares en el mismo orden:

P = [[1, 1], [1, −1]]
D = [[3, 0], [0, 1]]
P-1 = [[1/2, 1/2], [1/2, −1/2]]
const P = [[1, 1], [1, -1]];
const D = [[3, 0], [0, 1]];
const inversaP = [[0.5, 0.5], [0.5, -0.5]];

console.log({ P, D, inversaP });

40.10 Verificación mediante AP = PD

La igualdad AP = PD expresa simultáneamente Avi = λivi para todas las columnas.

function multiplicar(A, B) {
  return A.map(fila => B[0].map((_, j) =>
    fila.reduce((suma, valor, k) => suma + valor * B[k][j], 0)
  ));
}

const A = [[2, 1], [1, 2]];
const P = [[1, 1], [1, -1]];
const D = [[3, 0], [0, 1]];
console.log(multiplicar(A, P)); // [[3,1], [3,-1]]
console.log(multiplicar(P, D)); // [[3,1], [3,-1]]

40.11 Reconstrucción de A

Al calcular PDP-1 debe recuperarse la matriz original.

const multiplicar = (A, B) => A.map(fila => B[0].map((_, j) =>
  fila.reduce((suma, valor, k) => suma + valor * B[k][j], 0)
));

const P = [[1, 1], [1, -1]];
const D = [[3, 0], [0, 1]];
const inversaP = [[0.5, 0.5], [0.5, -0.5]];
const A = multiplicar(multiplicar(P, D), inversaP);

console.log(A); // [[2, 1], [1, 2]]

40.12 Coordenadas en la base propia

P-1 convierte coordenadas canónicas a coordenadas en la base propia. D escala cada coordenada y P regresa a la base original.

v  —P-1→  [v]B  —D→  [Av]B  —P→  Av
const aplicar = (A, v) => A.map(fila =>
  fila.reduce((suma, valor, i) => suma + valor * v[i], 0)
);
const P = [[1, 1], [1, -1]];
const inversaP = [[0.5, 0.5], [0.5, -0.5]];
const D = [[3, 0], [0, 1]];
const v = [4, 2];

const coordenadas = aplicar(inversaP, v); // [3, 1]
const escaladas = aplicar(D, coordenadas); // [9, 1]
console.log(aplicar(P, escaladas));        // [10, 8]

40.13 Potencias de una matriz diagonalizable

Los factores intermedios se cancelan al multiplicar:

A2 = PDP-1PDP-1 = PD2P-1
Ak = PDkP-1

Elevar D es inmediato: cada elemento diagonal se eleva a k.

function potenciaDiagonal(D, k) {
  return D.map((fila, i) =>
    fila.map((_, j) => i === j ? fila[i] ** k : 0)
  );
}

console.log(potenciaDiagonal([[3, 0], [0, 1]], 5)); // [[243,0], [0,1]]

40.14 Ejemplo de potencia

Para A = [[2, 1], [1, 2]], la diagonalización produce:

Ak = 1/2 [[3k + 1, 3k − 1], [3k − 1, 3k + 1]]
function potenciaA(k) {
  const p = 3 ** k;
  return [
    [(p + 1) / 2, (p - 1) / 2],
    [(p - 1) / 2, (p + 1) / 2]
  ];
}

console.log(potenciaA(3)); // [[14, 13], [13, 14]]

40.15 Funciones de matrices y aplicaciones

Para una función adecuada f puede definirse:

f(A) = Pf(D)P-1
f(D) = diag(f(λ1), ..., f(λn))

Esto simplifica exponenciales matriciales, recurrencias, sistemas dinámicos, ecuaciones diferenciales y cadenas de Markov.

const e3 = Math.exp(3);
const e1 = Math.exp(1);
const exponencialA = [
  [(e3 + e1) / 2, (e3 - e1) / 2],
  [(e3 - e1) / 2, (e3 + e1) / 2]
];

console.log(exponencialA);

40.16 Diagonalización ortogonal

Si A es real y simétrica, existe una matriz ortogonal Q formada por vectores propios unitarios tal que:

A = QDQT,   Q-1 = QT

Este resultado, conocido como teorema espectral, mejora la estabilidad y simplifica la inversión.

const s = 1 / Math.sqrt(2);
const Q = [[s, s], [s, -s]];
const transpuesta = Q[0].map((_, j) => Q.map(fila => fila[j]));
const multiplicar = (A, B) => A.map(fila => B[0].map((_, j) =>
  fila.reduce((suma, valor, k) => suma + valor * B[k][j], 0)
));

console.log(multiplicar(transpuesta, Q)); // aproximadamente la identidad

40.17 Matrices no diagonalizables

La matriz A = [[2, 1], [0, 2]] tiene el único valor propio 2 con multiplicidad algebraica 2:

A − 2I = [[0, 1], [0, 0]]
y = 0, x libre
E2 = gen{(1, 0)}

Solo existe una dirección propia independiente. No puede formarse una matriz P invertible con dos columnas propias, así que A no es diagonalizable.

const A = [[2, 1], [0, 2]];
const v = [1, 0];
const Av = A.map(fila => fila.reduce((s, valor, i) => s + valor * v[i], 0));

console.log(Av); // [2, 0]
// El espacio propio solo aporta múltiplos de [1, 0].

40.18 Implementación 2 × 2 y precauciones

Esta función diagonaliza matrices reales 2 × 2 con dos valores propios distintos y reconoce matrices escalares.

function diagonalizar2x2(A, tolerancia = 1e-10) {
  const [[a, b], [c, d]] = A;
  const traza = a + d;
  const det = a * d - b * c;
  const delta = traza ** 2 - 4 * det;

  if (delta < -tolerancia) return null; // no diagonaliza sobre los reales con este método
  if (Math.abs(delta) <= tolerancia) {
    const lambda = traza / 2;
    const escalar = Math.abs(a - lambda) <= tolerancia &&
      Math.abs(d - lambda) <= tolerancia &&
      Math.abs(b) <= tolerancia && Math.abs(c) <= tolerancia;
    return escalar
      ? { P: [[1, 0], [0, 1]], D: [[lambda, 0], [0, lambda]], inversaP: [[1, 0], [0, 1]] }
      : null;
  }

  const raiz = Math.sqrt(delta);
  const lambdas = [(traza + raiz) / 2, (traza - raiz) / 2];
  const vector = lambda => {
    const filas = [[a - lambda, b], [c, d - lambda]];
    const fila = Math.hypot(...filas[1]) > Math.hypot(...filas[0]) ? filas[1] : filas[0];
    const v = [-fila[1], fila[0]];
    const norma = Math.hypot(...v);
    return v.map(valor => valor / norma);
  };
  const [v1, v2] = lambdas.map(vector);
  const P = [[v1[0], v2[0]], [v1[1], v2[1]]];
  const detP = P[0][0] * P[1][1] - P[0][1] * P[1][0];
  const inversaP = [[P[1][1] / detP, -P[0][1] / detP], [-P[1][0] / detP, P[0][0] / detP]];
  return { P, D: [[lambdas[0], 0], [0, lambdas[1]]], inversaP };
}

console.log(diagonalizar2x2([[2, 1], [1, 2]]));

En cálculo numérico, valores muy cercanos y matrices mal condicionadas pueden volver inestable P-1. Las bibliotecas especializadas prefieren descomposiciones robustas y no forman la inversa sin necesidad.

40.19 Qué debes recordar de este tema

  • A es diagonalizable si A = PDP-1 para alguna P invertible y D diagonal.
  • Las columnas de P son vectores propios independientes.
  • La diagonal de D contiene los valores propios en el mismo orden.
  • Una matriz n × n necesita n vectores propios independientes.
  • n valores propios distintos garantizan diagonalización.
  • Un valor repetido requiere suficientes direcciones propias.
  • Ak = PDkP-1 simplifica el cálculo de potencias.
  • Las matrices reales simétricas admiten diagonalización ortogonal.

40.20 Conclusión

La diagonalización encuentra coordenadas en las que una transformación actúa mediante escalados independientes. Esta representación simplifica potencias, funciones matriciales y el análisis de procesos repetidos.

En el próximo tema estudiaremos transformaciones geométricas como traslación, rotación y escalado, y su implementación en programación.