El rango mide cuántas filas o columnas aportan información linealmente independiente. Permite reconocer transformaciones que pierden dimensiones y anticipar el comportamiento de los sistemas lineales.
Una matriz puede contener filas o columnas repetidas, proporcionales o formadas a partir de otras. Esos datos no agregan nuevas direcciones de información.
El rango resume cuántas direcciones independientes conserva la matriz. Se escribe rango(A), rg(A) o rank(A).
Considere A = [[1, 2], [2, 4]]. La segunda fila es el doble de la primera, por lo que no aporta una dirección nueva. Aunque la matriz tiene dos filas, su rango es 1.
const A = [[1, 2], [2, 4]];
const primera = A[0];
const segundaEsperada = primera.map(valor => 2 * valor);
console.log(A[1]); // [2, 4]
console.log(segundaEsperada); // [2, 4]
En cambio, [[1, 2], [2, 5]] tiene dos filas independientes: ninguna es múltiplo de la otra. Su rango es 2.
Si A tiene m filas y n columnas, su rango siempre satisface:
| Matriz | Rango máximo | Motivo |
|---|---|---|
| 2 × 5 | 2 | Solo dispone de 2 filas |
| 4 × 3 | 3 | Solo dispone de 3 columnas |
| 3 × 3 | 3 | Puede tener 3 pivotes |
| Matriz nula | 0 | No contiene ninguna dirección no nula |
El rango por filas es la dimensión del espacio generado por las filas. El rango por columnas se define de forma análoga con las columnas.
Un resultado fundamental establece que ambos números siempre coinciden. Por eso hablamos simplemente del rango de la matriz.
const matriz = [[1, 0, 1], [0, 1, 1]];
const filas = matriz.length;
const columnas = matriz[0].length;
console.log({ filas, columnas, rangoMaximo: Math.min(filas, columnas) });
Una matriz está en forma escalonada cuando cada fila no nula comienza más a la derecha que la anterior y las filas nulas quedan al final.
El primer elemento no nulo de cada fila se denomina pivote. La matriz del ejemplo tiene dos pivotes y, por tanto, rango 2.
const escalonada = [[1, 2, 0], [0, 3, 4], [0, 0, 0]];
const tolerancia = 1e-12;
const filasNoNulas = escalonada.filter(fila =>
fila.some(valor => Math.abs(valor) > tolerancia)
);
console.log(filasNoNulas.length); // 2
Las operaciones elementales por fila no cambian el rango:
Estas operaciones permiten simplificar la matriz hasta una forma escalonada sin perder la información necesaria para medir su rango.
const A = [[1, 2], [2, 4]];
// F2 recibe F2 - 2F1.
const reducida = [A[0], A[1].map((valor, j) => valor - 2 * A[0][j])];
console.log(reducida); // [[1, 2], [0, 0]]
El procedimiento más práctico consiste en escalonar la matriz y contar sus filas no nulas:
Sea A = [[1, 2, 3], [2, 4, 6], [1, 1, 1]]. Aplicamos F2 − 2F1 y F3 − F1:
Al ordenar las filas quedan dos filas no nulas. Por lo tanto, rango(A) = 2.
const A = [[1, 2, 3], [2, 4, 6], [1, 1, 1]];
const F1 = A[0];
const F2 = A[1].map((valor, j) => valor - 2 * F1[j]);
const F3 = A[2].map((valor, j) => valor - F1[j]);
console.log([F1, F3, F2]); // dos filas no nulas
El algoritmo siguiente emplea eliminación de Gauss con pivoteo parcial. Trabaja sobre una copia para conservar intacta la matriz recibida.
function rango(matriz, tolerancia = 1e-10) {
if (matriz.length === 0) return 0;
const columnas = matriz[0].length;
if (matriz.some(fila => fila.length !== columnas)) {
throw new Error("Todas las filas deben tener igual longitud");
}
const m = matriz.map(fila => fila.map(Number));
let filaPivote = 0;
for (let columna = 0; columna < columnas && filaPivote < m.length; columna++) {
let mejorFila = filaPivote;
for (let fila = filaPivote + 1; fila < m.length; fila++) {
if (Math.abs(m[fila][columna]) > Math.abs(m[mejorFila][columna])) {
mejorFila = fila;
}
}
if (Math.abs(m[mejorFila][columna]) <= tolerancia) continue;
[m[filaPivote], m[mejorFila]] = [m[mejorFila], m[filaPivote]];
for (let fila = filaPivote + 1; fila < m.length; fila++) {
const factor = m[fila][columna] / m[filaPivote][columna];
for (let j = columna; j < columnas; j++) {
m[fila][j] -= factor * m[filaPivote][j];
}
}
filaPivote++;
}
return filaPivote;
}
console.log(rango([[1, 2, 3], [2, 4, 6], [1, 1, 1]])); // 2
El pivoteo parcial selecciona el valor de mayor magnitud disponible en una columna. Esto evita dividir por cero y reduce la amplificación de errores.
Con números decimales, un valor calculado como 0 puede quedar representado por una cantidad diminuta. La tolerancia permite tratarlo como cero.
const valores = [1, 1e-13, -4e-11, 0];
const tolerancia = 1e-10;
const normalizados = valores.map(valor =>
Math.abs(valor) <= tolerancia ? 0 : valor
);
console.log(normalizados); // [1, 0, 0, 0]
Una tolerancia demasiado grande puede ocultar información válida; una demasiado pequeña puede contar ruido numérico como un pivote.
También puede buscarse el determinante no nulo de mayor orden contenido en A. Si existe un menor de orden r distinto de cero y todos los de orden superior son cero, entonces rango(A) = r.
Para matrices pequeñas este criterio es útil:
function determinante2x2(a, b, c, d) {
return a * d - b * c;
}
const menor = determinante2x2(1, 2, 1, 1);
console.log(menor); // -1: existe un menor de orden 2 no nulo
| Matriz | Rango |
|---|---|
| Nula de tamaño m × n | 0 |
| Identidad In | n |
| Diagonal | Cantidad de elementos diagonales no nulos |
| Cuadrada invertible de orden n | n |
| Una fila no nula | 1 |
const diagonal = [[5, 0, 0], [0, 0, 0], [0, 0, -2]];
const rangoDiagonal = diagonal.reduce(
(cantidad, fila, i) => cantidad + Number(fila[i] !== 0),
0
);
console.log(rangoDiagonal); // 2
Una matriz tiene rango completo cuando alcanza min(m, n).
Si una matriz representa una transformación lineal, su rango es la dimensión de la imagen: la cantidad de dimensiones que pueden aparecer en la salida.
const proyectarSobrePlanoXY = ([x, y, z]) => [x, y, 0];
console.log(proyectarSobrePlanoXY([3, 4, 5])); // [3, 4, 0]
// La transformación conserva dos direcciones: su rango es 2.
En el sistema Ax = b se comparan el rango de la matriz de coeficientes A y el de la matriz aumentada [A | b].
| Condición | Resultado |
|---|---|
| rango(A) ≠ rango([A | b]) | No existe solución |
| rango(A) = rango([A | b]) = número de incógnitas | Solución única |
| rango(A) = rango([A | b]) < número de incógnitas | Infinitas soluciones |
Estas condiciones se estudiarán con más detalle al trabajar con sistemas de ecuaciones lineales.
La matriz aumentada se obtiene agregando el vector de términos independientes como una columna adicional.
function aumentar(A, b) {
if (A.length !== b.length) throw new Error("Dimensiones incompatibles");
return A.map((fila, i) => [...fila, b[i]]);
}
const A = [[1, 1], [2, 2]];
const b = [3, 7];
console.log(aumentar(A, b)); // [[1, 1, 3], [2, 2, 7]]
En el ejemplo, rango(A) = 1 pero rango([A | b]) = 2. Las ecuaciones representan condiciones incompatibles y el sistema no tiene solución.
El rango aparece en numerosos contextos computacionales:
const original = [[1, 2], [3, 4]];
const copia = original.map(fila => [...fila]);
copia[0][0] = 99;
console.log(original[0][0]); // 1: la original no fue modificada
El rango revela cuánta información independiente contiene una matriz. La eliminación de Gauss proporciona una forma sistemática de calcularlo, mientras que los menores y determinantes explican su relación con la invertibilidad.
En el próximo tema introduciremos los sistemas de ecuaciones lineales y utilizaremos matrices para representar varias ecuaciones de manera compacta.