/*******************************************************************************
* Copyright (c) 2004, 2007 IBM Corporation and Cambridge Semantics Incorporated.
* 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
*
* File: $Source: /cvsroot/slrp/boca/com.ibm.adtech.boca.jastor/src/com/ibm/adtech/boca/jastor/util/graph/DFS.java,v $
* Created by:
* Created on: 01/23/2007
* Revision: $Id: DFS.java 172 2007-07-31 14:22:23Z mroy $
*
* Contributors:
* IBM Corporation - initial API and implementation
* Cambridge Semantics Incorporated - Fork to Anzo
*******************************************************************************/
package org.openanzo.rdf.jastor.util.graph;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
/**
* Depth First Search
*
* @author Elias Torres ( <a href="mailto:eliast@us.ibm.com">eliast@us.ibm.com </a>)
*
*/
public class DFS extends AlgorithmsBase {
// run data
private HashMap<INode, Integer> discover, color, finish;
private HashMap<INode, INode> prev;
private List<INode> nodesByDiscover, nodesByFinish;
private int time = 0;
protected boolean done = false;
private INode end;
private GraphMem tree = null;
synchronized void executeSubgraph() {
startExecution();
reinit();
for (INode node : graph.nodes()) {
if (isDone())
break;
if (color.get(node).equals(WHITE) && node.getIncomingEdges().size() == 0) {
visit(node);
}
}
endExecution();
}
synchronized void executeSubgraph(INode start) {
startExecution();
reinit();
visit(start);
endExecution();
}
synchronized void execute(INode start) {
startExecution();
reinit();
visit(start);
internalExecute();
endExecution();
}
synchronized void execute(INode start, INode end) {
startExecution();
reinit();
this.end = end;
visit(start);
internalExecute();
endExecution();
}
@Override
public synchronized void execute() {
startExecution();
reinit();
internalExecute();
endExecution();
}
void internalExecute() {
for (INode node : graph.nodes()) {
if (isDone())
break;
if (color.get(node).equals(WHITE) && node.getIncomingEdges().size() == 0) {
visit(node);
}
}
for (INode node : graph.nodes()) {
if (isDone())
break;
if (color.get(node).equals(WHITE)) {
visit(node);
}
}
}
protected void reinit() {
prev = new HashMap<INode, INode>();
color = new HashMap<INode, Integer>();
discover = new HashMap<INode, Integer>();
finish = new HashMap<INode, Integer>();
nodesByDiscover = new LinkedList<INode>();
nodesByFinish = new LinkedList<INode>();
end = null;
time = 0;
for (INode node : graph.nodes()) {
color.put(node, WHITE);
prev.put(node, NILNODE);
}
tree = new GraphMem("dfs-tree");
}
/**
* Print results of depth first search
*
* @param writer
* output writer
*/
public void printResults(PrintWriter writer) {
checkState();
ArrayList<INode> ordered = new ArrayList<INode>(time);
for (int i = 0; i < time; i++) {
ordered.add(NILNODE);
}
for (INode node : graph.nodes()) {
ordered.set(getDiscoverTime(node) - 1, node);
ordered.set(getFinishTime(node) - 1, node);
}
for (int i = 0; i < ordered.size(); i++) {
System.out.print(ordered.get(i) + ",");
}
}
private void visit(INode node) {
color.put(node, GRAY);
time++;
discover.put(node, Integer.valueOf(time));
nodesByDiscover.add(node);
startVisit(node);
for (IEdge edge : node.getOutgoingEdges()) {
if (isDone())
break;
INode adj = edge.getDestination();
if (color.get(adj).equals(WHITE)) {
prev.put(adj, node);
visit(adj);
} else if (color.get(adj).equals(GRAY)) { // back-edge
foundBackEdge(edge);
} else if (color.get(adj).equals(BLACK)) {
if (getDiscoverTime(edge.getSource()) > getDiscoverTime(edge.getDestination())) {
foundCrossEdge(edge);
} else {
foundForwardEdge(edge);
}
}
}
color.put(node, BLACK);
time++;
finish.put(node, Integer.valueOf(time));
nodesByFinish.add(node);
finishVisit(node);
}
INode getParent(INode child) {
checkState();
INode object = prev.get(child);
return (object != NILNODE) ? (INode) object : null;
}
private int getFinishTime(INode node) {
if (!finish.containsKey(node))
return INVALID_TIME;
Integer val = finish.get(node);
return val.intValue();
}
private int getDiscoverTime(INode node) {
if (!discover.containsKey(node))
return INVALID_TIME;
Integer val = discover.get(node);
return val.intValue();
}
/**
* Get nodes by discover time
*
* @return nodes by discover time
*/
public List<INode> getNodesByDiscoverTime() {
checkState();
return Collections.unmodifiableList(nodesByDiscover);
}
/**
* Get nodes by finish time
*
* @return nodes by finish time
*/
public List<INode> getNodesByFinishTime() {
checkState();
return Collections.unmodifiableList(nodesByFinish);
}
@Override
public Object result() {
checkState();
if (tree.getEdgeCount() == 0) {
for (INode node : prev.keySet()) {
tree.addNode(new NodeMem(node.getName()));
}
for (INode node : prev.keySet()) {
if (!prev.get(node).equals(NILNODE)) {
INode prevNode = prev.get(node);
tree.addEdge(new EdgeMem("tree-edge", tree.getNodeByName(prevNode.getName()), tree.getNodeByName(node.getName())));
}
}
}
return tree;
}
/**
* Print results
*/
public void printResult() {
checkState();
}
protected boolean isDone() {
return done;
}
protected void startVisit(INode n) {
if (end != null && end.equals(n))
done = true;
}
protected void finishVisit(INode n) {
}
protected void foundForwardEdge(IEdge edge) {
}
protected void foundBackEdge(IEdge edge) {
}
protected void foundCrossEdge(IEdge edge) {
}
}