/** * Copyright 2007-2008 University Of Southern California * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package edu.isi.pegasus.planner.partitioner.graph; import edu.isi.pegasus.planner.classes.NameValue; import java.util.Iterator; import java.util.Stack; /** * Cycle checker. * * @author Karan Vahi */ public class CycleChecker { /** * Key value pairs identifying the cyclic edges. */ private NameValue mCyclicEdge; private final Graph mDAG; public CycleChecker( Graph dag ){ mCyclicEdge = null; mDAG = dag; } /** * Returns a boolean indicating whether a graph has cyclic edges or not. * * @return boolean */ public boolean hasCycles( ){ mCyclicEdge = null; Stack<GraphNode> stack = new Stack(); //sanity intialization of all nodes to white color for( Iterator it = mDAG.nodeIterator(); it.hasNext(); ){ GraphNode node = ( GraphNode )it.next(); node.setColor( GraphNode.WHITE_COLOR ); } if( mDAG.getRoots().isEmpty() ){ //sanity check if there is a cycle at the whole dag level //roots will return empty return true; } //start the DFS for( Iterator<GraphNode> it = mDAG.getRoots().iterator(); it.hasNext(); ){ GraphNode node = ( GraphNode )it.next(); if( dfsVisitForCycleDetection( node ) ){ return true; } } return false; } public boolean dfsVisitForCycleDetection( GraphNode node ){ node.setColor( GraphNode.GRAY_COLOR ); //System.out.println( "Colored node GREY " + node.getID()); for( Iterator it = node.getChildren().iterator(); it.hasNext(); ){ GraphNode child = (GraphNode)it.next(); int color = child.getColor(); switch( color ){ case GraphNode.GRAY_COLOR: mCyclicEdge = new NameValue( node.getID() , child.getID() ); //System.out.println( "Cycic Edge " + mCyclicEdge.getKey() + "->" + mCyclicEdge.getValue()); return true; case GraphNode.WHITE_COLOR: //System.out.println( "Recursive call for node " + child.getID()); if( dfsVisitForCycleDetection( child ) ){ return true; } default: break; } } //traversed all the children recursively //System.out.println( "Colored node Black " + node.getID()); node.setColor( GraphNode.BLACK_COLOR ); return false; } /** * Returns the detected cyclic edge if , hasCycles returns true * * @return */ public NameValue getCyclicEdge(){ return this.mCyclicEdge; } public static void main(String[] args ){ Graph g = new MapGraph(); g.addNode( new GraphNode("A", "A")); g.addNode( new GraphNode("B", "B")); g.addNode( new GraphNode("C", "C")); g.addNode( new GraphNode("D", "D")); g.addEdge( "A", "B"); g.addEdge( "A", "C"); g.addEdge( "C", "D"); g.addEdge( "B", "D"); g.addEdge( "D", "A"); CycleChecker c = new CycleChecker(g); if ( c.hasCycles() ){ System.err.println( "Graph has cycles with edge " + c.getCyclicEdge() ); } else{ System.out.println( "Graph has no cycles"); } System.out.println( " --------------------------------------- "); g = new MapGraph(); for( int i=1; i<=6;i++){ g.addNode( new GraphNode( "j"+i, "j"+i)); } g.addEdge( "j1", "j2"); g.addEdge( "j1", "j3"); g.addEdge( "j2", "j4"); g.addEdge( "j3", "j4"); g.addEdge( "j4", "j5"); g.addEdge( "j4", "j6"); g.addEdge( "j6", "j2"); c = new CycleChecker(g); if ( c.hasCycles() ){ System.err.println( " C has cycles with edge " + c.getCyclicEdge() ); } else{ System.out.println( "Graph has no cycles"); } System.out.println( " --------------------------------------- "); } }