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.
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.
Una matriz cuadrada A es diagonalizable si existe una matriz invertible P y una matriz diagonal D tales que:
Equivalentemente:
A y D son matrices semejantes: representan la misma transformación en bases distintas.
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.
Si se cambia el orden de las columnas de P, debe cambiarse de igual modo el orden de la diagonal de D.
Una matriz n × n es diagonalizable si y solo si posee n vectores propios linealmente independientes.
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
Los vectores propios asociados a valores propios distintos son independientes. Por eso:
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
Cuando λ tiene multiplicidad algebraica mayor que uno, deben existir suficientes vectores propios independientes en Eλ.
| Matriz | Direcciones propias para λ = 2 | ¿Diagonalizable? |
|---|---|---|
| [[2, 0], [0, 2]] | Dos independientes; todo ℝ2 | Sí |
| [[2, 1], [0, 2]] | Solo una dirección independiente | No |
Sea A = [[2, 1], [1, 2]]. Sus valores propios y direcciones son:
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));
}
Colocando los pares en el mismo orden:
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 });
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]]
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]]
P-1 convierte coordenadas canónicas a coordenadas en la base propia. D escala cada coordenada y P regresa a la base original.
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]
Los factores intermedios se cancelan al multiplicar:
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]]
Para A = [[2, 1], [1, 2]], la diagonalización produce:
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]]
Para una función adecuada f puede definirse:
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);
Si A es real y simétrica, existe una matriz ortogonal Q formada por vectores propios unitarios tal que:
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
La matriz A = [[2, 1], [0, 2]] tiene el único valor propio 2 con multiplicidad algebraica 2:
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].
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.
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.