Clase 9 · DAGs, restricciones de precedencia y algoritmos de ordenamiento topológico

Alcance y fuentes de esta clase

Esta nota integra dos fuentes complementarias del curso:

  1. 03Graphs.pdf (Diapositivas 44–51): Teoría de Gráficas Dirigidas Acíclicas (DAGs), restricciones de precedencia, teorema de equivalencia (), lema del nodo fuente () y demostración inductiva.
  2. Ordenamiento Topológico (Diapositivas 1–8): Análisis formal comparativo impartido en clase entre la versión recursiva, la versión iterativa ingenua () y la versión iterativa mejorada de Kahn () con detección de ciclos cuando .

Material extra

https://www.cs.emory.edu/~cheung/Courses/253/Syllabus/Graph/DAG.html

Pregunta central

¿Cómo podemos ordenar linealmente un conjunto de tareas con dependencias para que ninguna tarea se ejecute antes de que sus prerrequisitos estén listos, cómo demostramos matemáticamente si dicho orden existe, y cómo optimizamos el algoritmo para pasar de a tiempo lineal ?

Idea de la clase

Un ordenamiento topológico es una disposición lineal de los vértices de un digrafo donde todas las aristas van de izquierda a derecha. Dicho orden existe si y solo si el grafo es un DAG (sin ciclos dirigidos). Todo DAG finito contiene al menos un nodo fuente con grado de entrada cero (), lo que permite extraer fuentes sucesivamente. Buscar fuentes de manera ingenua en cada paso cuesta ; el algoritmo de Kahn mantiene un vector de grados de entrada y una cola con los nodos de grado cero, reduciendo el costo a en tiempo y en espacio, detectando además ciclos dirigidos si la lista final tiene menos de vértices.

flowchart TD
  DAG["Problema con dependencias: DAG"] --> TH["Teorema:\nOrden topológico existe ⟺ Es un DAG"]
  TH --> LEM["Lema de la Fuente:\nTodo DAG tiene al menos un nodo con in-degree = 0"]
  LEM --> REC["Versión Recursiva:\nExtraer fuente v y recursar en G ∖ {v}"]
  REC --> IT1["Versión Iterativa Ingenua:\nEscanear G cada ronda buscando in-degree = 0\nT(n,m) = O(n² + nm) | S(n,m) = O(n)"]
  IT1 --> IT2["Versión Iterativa Mejorada (Kahn):\nVector in-degree + Cola S de fuentes\nT(n,m) = O(n + m) | S(n,m) = O(n)"]
  IT2 --> CYC{"¿|L| < n?"}
  CYC -->|SÍ| ERR["Retornar NO-DAG (Ciclo detectado)"]
  CYC -->|NO| OK["Retornar orden lineal válido L"]

1. Gráficas Dirigidas Acíclicas (DAGs) y Precedencia

Diapositivas 44–46 de 03Graphs.pdf.

1.1 Definición formal de DAG

Un grafo dirigido acíclico o DAG (Directed Acyclic Graph) es un grafo dirigido que no contiene ningún ciclo dirigido simple. Es decir, no existe ninguna trayectoria dirigida que comience y termine en el mismo vértice ().

1.2 Restricciones de precedencia

En una red de dependencias, una arista dirigida formaliza una restricción de precedencia: la tarea debe completarse obligatoriamente antes de poder iniciar la tarea .

Ejemplos en computación y vida real:

  1. Malla curricular universitaria: La materia es prerrequisito formal de (ej. Cálculo I Cálculo II). Si existiera un ciclo (), sería imposible graduarse.
  2. Sistemas de compilación de software: En herramientas como make, CMake o Bazel, el archivo o módulo debe compilarse antes de generar el binario o biblioteca .
  3. Pipelines de tareas concurrentes: La salida generada por el proceso es requerida como entrada por el proceso .

2. Definición del Ordenamiento Topológico

Diapositiva 45 de 03Graphs.pdf y Diapositiva 1 de Ordenamiento Topológico.

Dado un grafo dirigido con vértices, un ordenamiento topológico es una permutación lineal de sus nodos:

tal que para toda arista dirigida , el índice de en la secuencia es estrictamente menor que el índice de :

Representación visual: El grafo canónico del hexágono

En la diapositiva 45 de Kleinberg & Tardos (y diapositiva 1 de la clase), se presenta el DAG canónico de 7 vértices:

           v2 ───────> v3
          ^  \        /  \
         /    \      /    \
        /      v    v      v
      v6 <────  v5  ──────> v4
        \      ^    ^      /
         \    /      \    /
          v  /        \  v
           v7 <─────── v1

Al proyectar los vértices sobre una línea horizontal según un orden topológico válido, todas las aristas apuntan estrictamente hacia adelante (de izquierda a derecha). Ningún arco puede apuntar hacia atrás:

(v1) ───> (v2) ───> (v3) ───> (v4) ───> (v5) ───> (v6) ───> (v7)
 └───────────────────────> aristas van siempre i < j

3. Teorema: Relación biunívoca entre DAGs y Orden Topológico

Diapositivas 47–48 de 03Graphs.pdf.

Teorema Fundamental

Un grafo dirigido admite un ordenamiento topológico si y solo si es un DAG (no contiene ciclos dirigidos).

3.1 Demostración de la ida (): Si tiene orden topológico, entonces es un DAG

Demostración por contradicción (Diapositiva 47):

  1. Supongamos que tiene un orden topológico y que, al mismo tiempo, contiene un ciclo dirigido .
  2. Sea el nodo del ciclo que tiene el índice más bajo en el orden topológico (es decir, el que aparece más a la izquierda en la línea).
  3. Sea el nodo inmediatamente anterior a en el ciclo . Por tanto, la arista dirigida pertenece al grafo:
  4. Por haber elegido a como el nodo de índice mínimo en , todos los demás nodos de tienen un índice mayor; en particular:
  5. Sin embargo, dado que y la secuencia es un orden topológico válido, por definición de orden topológico se debe cumplir que el origen precede al destino:
  6. Obtenemos simultáneamente y , lo cual es una contradicción lógica directa ().
  7. Por lo tanto, ningún grafo que admita un orden topológico puede contener un ciclo dirigido. es forzosamente un DAG.

4. Lema fundamental: Existencia de una fuente en todo DAG

Diapositiva 49 de 03Graphs.pdf.

Para demostrar el regreso (), necesitamos garantizar que siempre existe al menos un nodo con el cual podamos comenzar el orden.

Lema de la Fuente (Source Lemma)

Si es un DAG finito con vértices, entonces tiene al menos un vértice sin aristas de entrada ().

Demostración por contradicción (Paseo hacia atrás):

  1. Supongamos que es un DAG pero ningún nodo tiene grado de entrada cero; es decir, todo nodo tiene al menos una arista que entra a él:
  2. Elijamos un vértice inicial cualquiera .
  3. Como , existe una arista . Damos un paso hacia atrás y nos paramos en .
  4. Como , existe una arista . Retrocedemos a .
  5. Repetimos este retroceso paso a paso de forma indefinida:
  6. Como el conjunto de vértices es finito (), tras dar a lo más pasos hacia atrás, por el principio del palomar, forzosamente visitaremos por segunda vez algún vértice ya visitado anteriormente.
  7. La secuencia de nodos visitados entre la primera visita a y la segunda visita a constituye un ciclo dirigido:
  8. Esto contradice la hipótesis de que es un DAG (no tiene ciclos).
  9. Por contradicción, la suposición inicial es falsa: debe existir al menos un nodo con .

5. Existencia de Orden Topológico por Inducción

Diapositiva 50 de 03Graphs.pdf.

Con el lema de la fuente, demostramos que todo DAG tiene un orden topológico mediante inducción matemática en el número de vértices :

  • Caso base (): Un grafo con un solo vértice y sin lazos es un DAG y su único orden topológico es el vértice mismo.
  • Hipótesis de inducción: Supongamos que todo DAG con vértices tiene al menos un orden topológico válido.
  • Paso inductivo (para vértices):
    1. Por el lema de la fuente, existe un nodo tal que .
    2. Consideremos la subgráfica inducida (eliminando el vértice y todas las aristas que salen de él).
    3. tiene vértices y sigue siendo un DAG, pues eliminar vértices y aristas nunca puede crear ciclos nuevos.
    4. Por hipótesis de inducción, posee un ordenamiento topológico: .
    5. Construimos el orden para colocando a en la primera posición:
    6. ¿Es este orden válido para ? Sí, porque como , ninguna arista en entra a ; todas las aristas incidentes a salen de él hacia los nodos de , cumpliendo estrictamente la condición de precedencia .

6. Los tres algoritmos de Ordenamiento Topológico

Presentación Ordenamiento Topológico, Diapositivas 1–8.

La demostración inductiva sugiere directamente algoritmos concretos. En clase se analizaron tres variantes formales.

6.1 Algoritmo 1: Versión Recursiva (Topo-Recursivo)

Diapositiva 2 de Ordenamiento Topológico.

Algoritmo Topo-Recursivo(G):
    If G tiene un único vértice v Then
        Return v
    Else
        v = vértice de G sin aristas de entrada;
        de no haberlo Return NO-DAG
        G' = gráfica G sin v y las aristas que salen de v
        Return v · Topo-Rec(G')
End Topo-Rec
  • Mecánica: Encuentra una fuente , la retira de , llama recursivamente con la subgráfica restante y concatena al frente. Si en alguna llamada no encuentra ninguna fuente, la gráfica no es un DAG.

6.2 Algoritmo 2: Versión Iterativa Ingenua (Topo-Iterativo)

Diapositivas 3–5 de Ordenamiento Topológico.

Elimina la pila de recursión manteniendo una lista acumuladora:

Algoritmo Topo-Iterativo(G):
    L = cadena vacía                                    // O(1)
    While G tiene por lo menos un vértice Do            // (n + 1) veces
        v = vértice de G sin aristas de entrada;        // O(n + m) cada vez
        de no haberlo, Return NO-DAG
        L = L · v                                       // O(1)
        G = gráfica G sin v y las aristas que salen de v // O(1)
    Return L                                            // O(1)
End Topo-Rec

Análisis formal de tiempo de ejecución (Diapositiva 4)

  • La inicialización toma .
  • El bucle While evalúa la condición veces. En cada evaluación, verificar si tiene vértices toma , dando .
  • El cuerpo del bucle se ejecuta exactamente veces:
    • Encontrar un vértice sin aristas de entrada escaneando la representación de la gráfica toma .
    • Al ejecutarse veces, este costo acumulado es:
    • Las operaciones y la eliminación toman .
  • Tiempo total:

Análisis formal de espacio en memoria (Diapositiva 5)

  • La lista o cadena almacena los vértices en secuencia.
  • Espacio total:

6.3 Algoritmo 3: Versión Iterativa Mejorada / Algoritmo de Kahn (Topo-Iterativo-Mejorado)

Diapositivas 6–8 de Ordenamiento Topológico y Diapositiva 51 de 03Graphs.pdf.

El cuello de botella de la versión ingenua radica en reescanear toda la gráfica en cada ronda para buscar qué vértice tiene grado cero. La versión mejorada evita este desperdicio manteniendo:

  1. Un vector dinámico in-neighbourhood(w) (o in-degree[w]) con el número de aristas de entrada pendientes de cada vértice.
  2. Una estructura de datos (cola o pila) que contiene exclusivamente los vértices listos cuyo grado de entrada actual es .
Algoritmo Topo-Iterativo-Mejorado(G):
    S = cola vacía                                      // O(1)
    L = lista vacía                                     // O(1)
    
    For cada vértice v de G Do                          // O(n + m)
        in-neighbourhood(v) = #aristas de entrada de v
        If in-neighbourhood(v) == 0 Then
            Meter v a S
            
    While S != vacío Do                                 // O(n)
        v = tomar el siguiente de S
        L = L · v
        For cada arista (v, w) de G Do                  // O(m) acumulado
            in-neighbourhood(w) = in-neighbourhood(w) - 1
            If in-neighbourhood(w) == 0 Then
                Meter w a S
                
    If |L| < n Then                                     // O(1)
        Return NO-DAG                                   // Detección de ciclo
    Else
        Return L
End Topo-Rec

Análisis formal de tiempo de ejecución (Diapositiva 7)

  1. Inicialización:
    • Crear las estructuras y : .
    • Contar las aristas de entrada de todos los vértices mediante un escaneo de las listas de adyacencia: .
    • Encolar los vértices iniciales de grado cero en : a lo más operaciones .
  2. Bucle While principal:
    • Cada vértice entra a la cola y sale de ella a lo más una vez. El número total de iteraciones del While es , tomando en total.
  3. Bucle interno For cada arista (v, w):
    • Cuando se procesa el nodo , recorremos sus aristas salientes. A lo largo de toda la ejecución del algoritmo, cada arista dirigida es examinada exactamente una sola vez.
    • En cada arista, se realiza un decremento (in-neighbourhood(w) = in-neighbourhood(w) - 1) y una comparación.
    • La suma acumulada del costo de todas las aristas es:
  4. Verificación final:
    • Comparar toma .
  5. Tiempo total de ejecución:

Análisis formal de espacio en memoria (Diapositiva 8)

  • El arreglo in-neighbourhood requiere tamaño .
  • La cola almacena a lo más vértices .
  • La lista de salida almacena a lo más vértices .
  • Espacio total:

7. Detección formal de ciclos dirigidos

¿Qué ocurre si la gráfica contiene un ciclo dirigido (por ejemplo, )?

  1. En un ciclo cerrado, todos los nodos del ciclo tienen al menos una arista de entrada proveniente de su predecesor dentro del ciclo.
  2. Ningún nodo perteneciente al ciclo puede tener jamás in-degree == 0 a menos que se rompa el ciclo desde afuera.
  3. Si el ciclo no tiene dependencias externas (o cuando estas ya se procesaron), ninguno de los nodos del ciclo entrará jamás a la cola .
  4. La cola se vaciará prematuramente antes de que todos los nodos hayan sido procesados.
  5. Al terminar el bucle, la longitud de la lista de salida será estrictamente menor que el número total de vértices:
  6. Esta condición simple certifica formalmente que la gráfica contiene al menos un ciclo y retorna NO-DAG en tiempo .

8. Laboratorio interactivo: Simulador de Ordenamiento Topológico

Ejecuta paso a paso el algoritmo de Kahn sobre el grafo canónico hexagonal de 7 nodos, visualiza la cola , el vector dinámico in-degree y el orden lineal resultante, o inyecta un ciclo para observar la detección de NO-DAG.

Idea central si el laboratorio no carga: El algoritmo inicia calculando el grado de entrada de cada nodo. Los nodos con grado cero ( y ) entran a la cola . En cada paso se extrae un nodo, se añade a la lista y se decrementa el grado de sus vecinos salientes. Cuando el grado de un vecino llega a cero, entra a la cola. Al finalizar, si se procesaron los 7 nodos, la lista representa un ordenamiento topológico válido. Si se inyecta una arista cíclica (), la cola se vacía con , reportando NO-DAG.


9. Comparación sistemática de las tres versiones

CriterioVersión RecursivaVersión Iterativa IngenuaVersión Iterativa Mejorada (Kahn)
EstrategiaInducción matemática directaBúsqueda exhaustiva de fuentes en bucleMantenimiento dinámico con cola
Tiempo (Óptimo)
Espacio (pila de llamadas)
Estructuras auxiliaresPila del sistemaLista Vector in-degree + Cola + Lista
Detección de ciclosAl no encontrar fuente en recursiónAl no encontrar fuente en el bucleCondición $

10. Ejercicios resueltos paso a paso

Ejercicio 1: Traza completa del Algoritmo de Kahn

Problema: Obtener un orden topológico para el DAG con vértices y aristas:

Procedimiento:

  1. Paso 0 (Inicialización):
    • Grados de entrada: in-degree = {A: 0, B: 1, C: 1, D: 2, E: 1}.
    • Vértices con grado 0 entran a : .
    • Lista de salida: .
  2. Paso 1:
    • Desencolar de .
    • Procesar aristas salientes y :
      • in-degree[B] pasa de a meter a .
      • in-degree[C] pasa de a meter a .
    • Estado: .
  3. Paso 2:
    • Desencolar de .
    • Procesar arista saliente :
      • in-degree[D] pasa de a (no es 0, no entra a ).
    • Estado: .
  4. Paso 3:
    • Desencolar de .
    • Procesar arista saliente :
      • in-degree[D] pasa de a meter a .
    • Estado: .
  5. Paso 4:
    • Desencolar de .
    • Procesar arista saliente :
      • in-degree[E] pasa de a meter a .
    • Estado: .
  6. Paso 5:
    • Desencolar de .
    • No tiene aristas salientes.
    • Estado: .
  7. Verificación final: . Resultado: Orden topológico válido: . (Nota: también es válido).

Ejercicio 2: Justificación formal del costo en la versión ingenua

Problema: ¿Por qué la versión iterativa ingenua toma si solo se realizan iteraciones del bucle While?

Procedimiento:

  1. En cada una de las iteraciones, el algoritmo debe seleccionar un vértice tal que .
  2. Sin un arreglo que almacene los grados de entrada precomputados, el algoritmo debe inspeccionar los vértices restantes.
  3. Para cada uno de los vértices restantes en la ronda actual (), debe verificar si alguna de las aristas del grafo entra a él.
  4. Escanear toda la estructura de la gráfica toma tiempo proporcional a sus vértices y aristas actuales: por cada búsqueda.
  5. Al repetirse esta búsqueda en las rondas del bucle:
  6. Sumando la condición de parada del While (), el tiempo global queda dominado por .

11. Errores conceptuales frecuentes

Error conceptualCorrección
Creer que un DAG tiene un único orden topológicoFalso. Salvo que el DAG contenga un camino hamiltoniano estricto, suele haber múltiples órdenes topológicos válidos según el orden en que se extraigan las fuentes independientes de .
Pensar que el orden topológico aplica a grafos no dirigidosNo tiene sentido en grafos no dirigidos, ya que una arista sin dirección implicaría simultáneamente y , lo cual es imposible.
Confundir grado cero con grado de entrada ceroUn nodo con puede tener muchas aristas salientes (). La condición para entrar a la cola es únicamente tener cero aristas de entrada.
Asumir que Kahn solo detecta ciclos pero no los localizaEl algoritmo de Kahn detecta de forma exacta si hay un ciclo ($

12. Preguntas de autoevaluación

  1. ¿Puede un árbol no dirigido tener un ordenamiento topológico?
  2. Si un DAG tiene 3 nodos con grado de entrada 0 al inicio, ¿cuántos nodos tendrá la cola en la primera iteración?
  3. En la versión mejorada de Kahn, ¿cuántas veces se ejecuta la instrucción in-neighbourhood(w) = in-neighbourhood(w) - 1 en total a lo largo de todo el algoritmo?
  4. Si al terminar el algoritmo de Kahn la lista contiene 8 vértices y el grafo original tenía 10 vértices, ¿qué podemos concluir con certeza?
Respuestas explicadas
  1. No. El ordenamiento topológico solo está definido para grafos dirigidos. Un árbol no dirigido no tiene orientación; requeriría orientar sus aristas desde una raíz para convertirse en un DAG.
  2. Tendrá 3 nodos. Todos los vértices que cumplen inicialmente se encolan durante la fase de inicialización.
  3. Exactamente veces (una vez por cada arista dirigida ), cuando su nodo origen es extraído de .
  4. Que el grafo contiene al menos un ciclo dirigido y no es un DAG (retorna NO-DAG), y que 2 vértices quedaron atrapados en dependencias circulares.

13. Recorrido de diapositivas

DiapositivaContenido originalDónde se desarrolla
03Graphs: 44Agenda: DAGs and topological ordering§1
03Graphs: 45Definición de DAG y orden topológico; dibujo de hexágono y orden lineal§1.1 y §2
03Graphs: 46Restricciones de precedencia (cursos, compilación, pipelines)§1.2
03Graphs: 47Demostración por contradicción: Orden topológico DAG§3.1
03Graphs: 48Preguntas centrales de existencia y cálculo§4
03Graphs: 49Lema de la fuente () y demostración por paseo hacia atrás§4
03Graphs: 50Demostración constructiva inductiva de existencia de orden topológico§5
03Graphs: 51Análisis de tiempo mediante count(w) y conjunto §6.3
Topo: 1Portada: Gráfica hexagonal canónica y orden lineal§2
Topo: 2Pseudocódigo formal de Topo-Recursivo(G)§6.1
Topo: 3Pseudocódigo formal de Topo-Iterativo(G)§6.2
Topo: 4Análisis formal de tiempo de Topo-Iterativo: §6.2
Topo: 5Análisis formal de espacio de Topo-Iterativo: §6.2
Topo: 6Pseudocódigo formal de Topo-Iterativo-Mejorado(G) (Kahn)§6.3
Topo: 7Análisis formal de tiempo de Topo-Iterativo-Mejorado: §6.3
Topo: 8Análisis formal de espacio y estructuras de datos: §6.3 y §9

Conexiones