### Directed Acyclic Graph (DAG): topological ordering

• Directed Acyclic Graph

• Directed graphs with and without cycles:

• Directed graph with cycles:

• Directed graph without cycles:

• Directed graphs without cycles are called Directed Accylic Graphs (DAGs)

• Inheritance hierarchy and DAGs

• We find DAGs in the inheritance/interface hierarchy of programming languages such as Java

• Example:

 A job consists of a number of tasks Some tasks can only be performed after some other task(s) have been completed

• Example:

• Job: building a house

 Pour the foundation        Build the frame

• You cannot start the task "build the frame" before completing the task "pour the foundation"

Notice:

 Job schedules must be acyclic Because if you have a cycle in the job dependency, then you can never start any job in that cycle....

• Definition: topological ordering

• Definition:

• Topological ordering of nodes = an ordering (label) of the nodes/vertices such that:

 For every edge (vi , vj) ∈ G:    i < j

• Example:

Every edge in the graph goes from a vertex with a smaller index to one with a larger index

• Note:

 There may be more than 1 possible topological ordering for the vertices

• DAG and Topological Ordering

• Proposition 13.21 (Goodrich)

 A directed graph G has a topological ordering if and only if G   is acyclic

• Proof:

1. If a directed graph G has a topological ordering then:   G   is acyclic

• Assume that G  is not acyclic

• I.e., there is a cycle C in G

Let the edges in the cycle C be:

(vi0 , vi1 )   (vi1 , vi2 )   ... (vik , vi0 )

• According to the given fact that G   has a topological ordering, we have from the edges in the cycle C that:

 vi0   < vi1   <   vi2   ...   < vik   <   vi0

• This inequality is impossible --- contradiction

Therefore, the assumption that "G  is not acyclic" is false:

 G  is acyclic

2. If directed graph G   is acyclic then:   G has a topological ordering

Proof:

• Since G  is acyclic, there is some vertex that does not have any incoming edges

• Let x be a vertex in G   that does not have any incoming edges

We label the vertex x as v1

• We now remove the vertex v1 from graph G:

 G1 = G - {v1}

• The graph G1  is also acyclic (we cannot add cycles to a graph by removing edges), and there is some vertex that does not have any incoming edges

• Let y be a vertex in G1   that does not have any incoming edges

We label the vertex y as v2

• We now remove the vertex v2 from graph G1:

 G2 = G - {v1,v2}

• And so on

Eventually, every vertex in G2 will be removed

(And we will stop)

• The resulting numbering of nodes is a topological order because:

• An edge (vi , vj ) must be deleted before the deletion of vertex vj

• Therefore, the vertex vi must be deleted before the vertex vj

• Therefore:

 i   <   j   holds for every edge (vi , vj )

• This is the definition of topological ordering.

• An efficient algorithm to find a topological ordering in a DAG

• The proof above provides an algorithm for finding a topological ordering on the vertices of a DAG

• Psuedo code:

 ``` i = 1; while ( G ≠ &empty ) { Let x = vertex in G with indeg(x) = 0; Label x with "i"; i++; Delete all edges (x, z) from G; } ```

• Refined psuedo code:

 ``` Stack S = contains vertices with indeg = 0 (these vertices are ready to be labeled) ============================================================== S = ∅ ; // Initialize the stack /* --------------------------------------- Compute the "indegree" for each vertex --------------------------------------- */ for ( each vertex x ∈ G ) { incounter[x] = incoming degree of x; } /* --------------------------------------- Find vertices with indeg = 0 --------------------------------------- */ for ( each vertex x ∈ G ) { if ( incounter[x] == 0 ) push(x); } i = 1; // Initial label /* --------------------------------------- Label the next vertex in S --------------------------------------- */ while ( S ≠ &empty ) { u = S.pop(); Label u with "i"; i++; /* ------------------------------------ Update indegree of affected nodes ------------------------------------ */ for ( each edge (u, z) ) do { incounter[z]--; if ( incounter[z] == 0 ) S.push(z); // z is ready to be numbered } } ```

• Worked out example

• Directed graph

• Initialization:

 incounter[a] = 0 incounter[b] = 1 incounter[c] = 1 incounter[d] = 1 incounter[e] = 2 incounter[f] = 2            stack = a

• Process top element from stack (a):

 incounter[a] = 0 incounter[b] = 0 incounter[c] = 0 incounter[d] = 1 incounter[e] = 2 incounter[f] = 2            stack = b c

• Process top element from stack (c):

 incounter[a] = 0 incounter[b] = 0 incounter[c] = 0 incounter[d] = 0 incounter[e] = 1 incounter[f] = 2            stack = b d

• Process top element from stack (d):

 incounter[a] = 0 incounter[b] = 0 incounter[c] = 0 incounter[d] = 0 incounter[e] = 1 incounter[f] = 1            stack = b

• Process top element from stack (b):

 incounter[a] = 0 incounter[b] = 0 incounter[c] = 0 incounter[d] = 0 incounter[e] = 0 incounter[f] = 1            stack = e

• Process top element from stack (e):

 incounter[a] = 0 incounter[b] = 0 incounter[c] = 0 incounter[d] = 0 incounter[e] = 0 incounter[f] = 0            stack = f

• Process top element from stack (f):

 incounter[a] = 0 incounter[b] = 0 incounter[c] = 0 incounter[d] = 0 incounter[e] = 0 incounter[f] = 0            stack = empty

• Done