/*
* This file or a portion of this file is licensed under the terms of
* the Globus Toolkit Public License, found in file GTPL, or at
* http://www.globus.org/toolkit/download/license.html. This notice must
* appear in redistributions of this file, with or without modification.
*
* Redistributions of this Software, with or without modification, must
* reproduce the GTPL in: (1) the Software, or (2) the Documentation or
* some other similar material which is provided with the Software (if
* any).
*
* Copyright 1999-2004 University of Chicago and The University of
* Southern California. All rights reserved.
*/
package org.griphyn.vdl.planner;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.io.*;
/**
* Class which implements a topological sort of a graph.
*
* @author Jens-S. Vöckler
* @author Yong Zhao
*
* @version $Revision$
* @see Graph
*/
public class Topology
{
/**
* The graph representation.
*/
private Graph m_graph;
/**
* Hashtable to map vertex name to array index.
*/
private Map m_vertexMap;
/**
* Array to keep the name of each vertex.
*/
private String[] m_vertices;
/**
* Array to keep the in-degree of each vertex.
*/
private int[] m_inDeg;
/**
* Queue to keep 0 in-degree vertices.
*/
private List m_inQueue;
/**
* Constructor, given a graph, construct internal objects
* needed for topological sort.
*
* @param graph is a graph representation.
*/
public Topology( Graph graph )
{
m_graph = (Graph) graph.clone();
init();
}
/**
* Initializes in-degree array and the corresponding 0 in-degree
* queue.
*/
public void init()
{
// allocate memory for collections
int n = m_graph.order();
m_vertexMap = new HashMap();
m_vertices = new String[n];
m_inDeg = new int[n];
m_inQueue = new ArrayList();
// map nodes
int i = 0;
for ( Iterator e=m_graph.getVertices(); e.hasNext(); ) {
String v = (String) e.next();
m_vertices[i] = new String(v);
m_vertexMap.put( new String(v), new Integer(i) );
m_inDeg[i] = m_graph.inDegree(v);
++i;
}
// put 0 in-degree vertices in the queue
for ( i=0; i<n; i++ ) {
if ( m_inDeg[i] == 0 ) m_inQueue.add( new Integer(i) );
}
}
/**
* Sorts the graph topologically. It first invokes the {@link #init()}
* method to start the graph over, and initialize data structures.
*
* @return A sorted list of vortex names.
*/
public String[] sort()
{
int n = m_graph.order();
String[] s = new String[n];
int cnt = 0;
int i;
while ( m_inQueue.size() > 0 ) {
i = ((Integer)m_inQueue.remove(0)).intValue();
s[cnt++] = new String(m_vertices[i]);
List neighbors = m_graph.neighbors( m_vertices[i] );
for ( int j=0; j<neighbors.size(); j++ ) {
String w = (String) neighbors.get(j);
int k = ((Integer) m_vertexMap.get(w)).intValue();
m_inDeg[k] -= 1;
if ( m_inDeg[k] == 0 ) m_inQueue.add( new Integer(k) );
}
}
if ( cnt != n )
throw new Error("The graph is not acyclic");
return s;
}
/**
* Sorts the graph topologically, but also with regards to stages. It
* first invokes the {@link #init()} method to start the graph over,
* and initialize data structures.
*
* @return a sorted list of zero in-degree vertices.
*/
public String[] stageSort()
{
int n = m_inQueue.size();
if ( n == 0 ) return null;
String[] s = new String[n];
int cnt = 0;
while ( cnt < n ) {
int i = ((Integer)m_inQueue.remove(0)).intValue();
s[cnt++] = new String(m_vertices[i]);
List neighbors = m_graph.neighbors( m_vertices[i] );
for ( int j=0; j<neighbors.size(); j++ ) {
String w = (String) neighbors.get(j);
int k = ((Integer) m_vertexMap.get(w)).intValue();
m_inDeg[k] -= 1;
if (m_inDeg[k] == 0) m_inQueue.add( new Integer(k) );
}
}
return s;
}
/**
* The main method contains some simple tests for the sorting algorithms.
* The graph to test with is read from stdin.
*
* @param args are commandline arguments.
*/
public static void main(String[] args)
{
Graph g = new Graph(new BufferedReader(new InputStreamReader(System.in)));
Topology t = new Topology(g);
String[] r = t.sort();
System.out.println( "The topological sorting result:" );
for ( int i=0; i < r.length; i++ ) System.out.print(r[i] + " ");
System.out.println();
System.out.println("The stage-by-stage sorting result:");
t.init();
while ( (r=t.stageSort()) != null ) {
for ( int i=0; i < r.length; i++ ) System.out.print( r[i] + " " );
System.out.println();
}
System.out.println( "Let's do it in reverse" );
t = new Topology(g.reverseGraph());
r = t.sort();
System.out.println( "The topological sorting result:" );
for ( int i=0; i < r.length; i++ ) System.out.print( r[i] + " " );
System.out.println();
}
}