blob: b1cffbed601cc1533c27d151cba36f76d08f2d09 [file] [log] [blame]
/*******************************************************************************
* Copyright 2005, CHISEL Group, University of Victoria, Victoria, BC, Canada.
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors: The Chisel Group, University of Victoria
*******************************************************************************/
package org.eclipse.zest.layouts.algorithms.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import org.eclipse.zest.layouts.LayoutEntity;
import org.eclipse.zest.layouts.LayoutRelationship;
import org.eclipse.zest.layouts.algorithms.AbstractLayoutAlgorithm;
import org.eclipse.zest.layouts.exampleStructures.SimpleRelationship;
/**
* Checks for cycles in the given graph.
*
* @author Casey Best
*/
public class CycleChecker {
/**
* Tests if there is a directed cirlce in the graph formed by the given entities and relationships.
* @param entities The entities in the graph to check
* @param relationships The relationships in the graph to check
* @param cycle Populated with the cycle encountered, if there is one.
* @throws RuntimeException Thrown if entities doesn't contain all of the endpoints for each relationship in relationships
* @return <code>true</code> if there is a directed circle.
* Otherwise, <code>false</code>.
*/
public static boolean hasDirectedCircles(LayoutEntity[] entities, LayoutRelationship[] relationships, List cycle) {
if (!AbstractLayoutAlgorithm.verifyInput(entities, relationships)) {
throw new RuntimeException("The endpoints of the relationships aren't contained in the entities list.");
}
//Enumeration enum;
//Iterator iterator;
Hashtable endPoints = new Hashtable();
// Initialize the relation(transitive) vector.
for (int i = 0; i < relationships.length; i++) {
LayoutRelationship rel = relationships[i];
//Add the relationship to the source endpoint
Object subject = rel.getSourceInLayout();
List rels = (List) endPoints.get(subject);
if (rels == null) {
rels = new ArrayList();
endPoints.put(subject, rels);
}
if (!rels.contains(rel))
rels.add(rel);
}
boolean hasCyle = hasCycle(new ArrayList(Arrays.asList(entities)), endPoints, cycle);
return hasCyle;
}
/**
* Check passed in nodes for a cycle
*/
private static boolean hasCycle(List nodesToCheck, Hashtable endPoints, List cycle) {
while (nodesToCheck.size() > 0) {
Object checkNode = nodesToCheck.get(0);
List checkedNodes = new ArrayList();
if (hasCycle(checkNode, new ArrayList(), null, endPoints, checkedNodes, cycle)) {
return true;
}
nodesToCheck.removeAll(checkedNodes);
}
return false;
}
/**
* Checks all the nodes attached to the nodeToCheck node for a cycle. All nodes
* checked are placed in nodePathSoFar.
*
* @returns true if there is a cycle
*/
private static boolean hasCycle(Object nodeToCheck, List nodePathSoFar, SimpleRelationship cameFrom, Hashtable endPoints, List nodesChecked, List cycle) {
if (nodePathSoFar.contains(nodeToCheck)) {
cycle.addAll(nodePathSoFar);
cycle.add(nodeToCheck);
return true;
}
nodePathSoFar.add(nodeToCheck);
nodesChecked.add(nodeToCheck);
List relations = (List) endPoints.get(nodeToCheck);
if (relations != null) {
for (Iterator iter = relations.iterator(); iter.hasNext();) {
SimpleRelationship rel = (SimpleRelationship) iter.next();
if (cameFrom == null || !rel.equals(cameFrom)) {
Object currentNode = null;
currentNode = rel.getDestinationInLayout();
if (hasCycle(currentNode, nodePathSoFar, rel, endPoints, nodesChecked, cycle)) {
return true;
}
}
}
}
nodePathSoFar.remove(nodeToCheck);
return false;
}
}