17. Clausura reflexiva, simétrica y transitiva

La clausura de una relación es la relación más pequeña que la contiene y que cumple una propiedad dada. Permite completar relaciones incompletas de manera controlada y mínima.

17.1 Introducción

En muchas situaciones encontramos relaciones que casi cumplen una propiedad pero les falta algún par. Por ejemplo, una relación que debería ser reflexiva pero tiene algunos elementos sin el par (a, a).

La clausura de una relación con respecto a una propiedad es la forma más económica de extenderla para que sí la cumpla: se agregan solo los pares estrictamente necesarios, sin añadir ninguno de más.

17.2 Definición general de clausura

Dada una relación R sobre un conjunto A y una propiedad P, la clausura de R respecto de P es la relación R' tal que:

  • R ⊆ R': contiene todos los pares de R.
  • R' cumple la propiedad P.
  • No existe ninguna relación que contenga a R, cumpla P y sea más pequeña que R'.
Clausura de R respecto de P = R ∪ {pares mínimos para cumplir P}

17.3 Clausura reflexiva

La clausura reflexiva de una relación R sobre A se obtiene agregando todos los pares (a, a) que no estaban en R.

r(R) = R ∪ {(a, a) | a ∈ A}

Si R ya es reflexiva, su clausura reflexiva coincide con ella misma.

Ejemplo: Si A = {1, 2, 3} y R = {(1, 2), (2, 3)}, entonces:

r(R) = {(1, 1), (1, 2), (2, 2), (2, 3), (3, 3)}

17.4 Clausura reflexiva en JavaScript

Para calcular la clausura reflexiva sumamos todos los pares de la diagonal que aún no existen en la relación.

const A = [1, 2, 3];
const R = [[1, 2], [2, 3]];

function clausuraReflexiva(conjunto, relacion) {
  const resultado = [...relacion];

  for (const a of conjunto) {
    const yaEsta = resultado.some(([x, y]) => x === a && y === a);
    if (!yaEsta) resultado.push([a, a]);
  }

  return resultado;
}

console.log(clausuraReflexiva(A, R));

La función agrega solo los pares reflexivos faltantes, preservando los que ya existen.

17.5 Clausura simétrica

La clausura simétrica de una relación R se obtiene agregando el par inverso (b, a) por cada par (a, b) que ya está en R.

s(R) = R ∪ {(b, a) | (a, b) ∈ R}

Ejemplo: Si R = {(1, 2), (2, 3)}, entonces:

s(R) = {(1, 2), (2, 1), (2, 3), (3, 2)}

17.6 Clausura simétrica en JavaScript

Para cada par existente en la relación, verificamos si el par inverso ya está; si no, lo agregamos.

const R = [[1, 2], [2, 3]];

function clausuraSimetrica(relacion) {
  const resultado = [...relacion];

  for (const [a, b] of relacion) {
    const yaEsta = resultado.some(([x, y]) => x === b && y === a);
    if (!yaEsta) resultado.push([b, a]);
  }

  return resultado;
}

console.log(clausuraSimetrica(R));

La función recorre cada par y añade su inverso si aún no está presente.

17.7 Clausura transitiva

La clausura transitiva es la más compleja. Se obtiene agregando todos los pares que se pueden deducir aplicando la transitividad repetidamente.

t(R) = R ∪ R² ∪ R³ ∪ ...

Donde contiene los pares (a, c) para los que existe b con (a, b) ∈ R y (b, c) ∈ R.

Ejemplo: Si R = {(1, 2), (2, 3)}, la clausura transitiva agrega (1, 3) porque hay un camino 1 → 2 → 3.

t(R) = {(1, 2), (2, 3), (1, 3)}

17.8 Algoritmo de Warshall

El algoritmo de Warshall calcula la clausura transitiva de manera eficiente usando una matriz booleana. Es una de las formas más conocidas de resolver este problema.

El algoritmo recorre todos los posibles intermediarios k y marca que (i, j) pertenece a la clausura si existen los pares (i, k) y (k, j).

function clausuraTransitiva(conjunto, relacion) {
  const n = conjunto.length;
  const indice = Object.fromEntries(conjunto.map((v, i) => [v, i]));

  // Inicializar matriz con los pares de la relación
  const M = Array.from({ length: n }, () => Array(n).fill(false));
  for (const [a, b] of relacion) {
    M[indice[a]][indice[b]] = true;
  }

  // Algoritmo de Warshall
  for (let k = 0; k < n; k++) {
    for (let i = 0; i < n; i++) {
      for (let j = 0; j < n; j++) {
        if (M[i][k] && M[k][j]) M[i][j] = true;
      }
    }
  }

  // Convertir la matriz a pares
  const resultado = [];
  for (let i = 0; i < n; i++) {
    for (let j = 0; j < n; j++) {
      if (M[i][j]) resultado.push([conjunto[i], conjunto[j]]);
    }
  }

  return resultado;
}

const A = [1, 2, 3, 4];
const R = [[1, 2], [2, 3], [3, 4]];
console.log(clausuraTransitiva(A, R));

El resultado incluye todos los pares accesibles por caminos de cualquier longitud: (1,2), (1,3), (1,4), (2,3), (2,4), (3,4).

17.9 Comparación de las tres clausuras

Clausura Propiedad que garantiza Pares que agrega Complejidad
Reflexiva Reflexividad Los pares (a, a) que faltan O(n)
Simétrica Simetría Los pares inversos que faltan O(|R|)
Transitiva Transitividad Todos los pares alcanzables por caminos O(n³) con Warshall

17.10 Clausura de equivalencia

Si se necesita que una relación sea de equivalencia (reflexiva, simétrica y transitiva), se puede construir la clausura aplicando las tres operaciones. El orden importa: primero la reflexiva y la simétrica, luego la transitiva.

Clausura de equivalencia = t(s(r(R)))

Ejemplo: Partiendo de R = {(1, 2)} sobre A = {1, 2, 3}:

r(R) = {(1, 1), (1, 2), (2, 2), (3, 3)} s(r(R)) = {(1, 1), (1, 2), (2, 1), (2, 2), (3, 3)} t(s(r(R))) = {(1, 1), (1, 2), (2, 1), (2, 2), (3, 3)}

El resultado es la relación de equivalencia más pequeña que contiene el par (1, 2). Los elementos 1 y 2 quedan en la misma clase y el elemento 3 forma su propia clase.

17.11 Clausura transitiva como alcanzabilidad

La clausura transitiva tiene una interpretación muy práctica en grafos dirigidos: dos nodos a y b están relacionados en la clausura transitiva si y solo si existe un camino de a a b en el grafo.

Uso en informática Interpretación de la clausura transitiva
Redes y grafos ¿Existe un camino entre dos nodos?
Dependencias de paquetes ¿A depende transitivamente de B?
Jerarquía de clases ¿Una clase hereda transitivamente de otra?
Análisis de código ¿Una función llama transitivamente a otra?
Bases de datos relacionales Consultas transitivas sobre relaciones jerárquicas

17.12 Errores comunes

  • Confundir la clausura con la relación original: la clausura siempre incluye los pares de partida.
  • Aplicar las tres clausuras en orden incorrecto al construir la clausura de equivalencia.
  • Pensar que la clausura transitiva es inmediata: puede requerir varias iteraciones para completarse.
  • Creer que la clausura simétrica siempre produce una relación de equivalencia: también necesita ser reflexiva y transitiva.
  • No verificar que la clausura sea mínima, es decir, que no se hayan agregado pares innecesarios.

17.13 Qué debes recordar de este tema

  • La clausura de una relación es la extensión mínima que cumple una propiedad dada.
  • La clausura reflexiva agrega los pares (a, a) faltantes.
  • La clausura simétrica agrega los pares inversos que faltan.
  • La clausura transitiva agrega todos los pares alcanzables por caminos encadenados.
  • El algoritmo de Warshall calcula la clausura transitiva con matrices en O(n³).
  • La clausura transitiva equivale a determinar la alcanzabilidad en un grafo dirigido.
  • Para obtener la clausura de equivalencia se aplica: t(s(r(R))).

17.14 Conclusión

Las clausuras permiten completar relaciones de manera controlada y mínima para que cumplan propiedades como reflexividad, simetría o transitividad. Son herramientas fundamentales en el análisis de grafos, el diseño de bases de datos y la verificación de propiedades en sistemas.

En el próximo tema estudiaremos la composición de relaciones, una operación que combina dos relaciones para obtener nuevas conexiones entre los elementos de un conjunto.