/* $RCSfile$
* $Author$
* $Date$
* $Revision$
*
* Copyright (C) 2004-2007 Ulrich Bauer <ulrich.bauer@alumni.tum.de>
*
* Contact: cdk-devel@lists.sourceforge.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
* All we ask is that proper credit is given for our work, which includes
* - but is not limited to - adding the above copyright notice to the beginning
* of your source code files, and to any copyright notice that you may distribute
* with programs based on this work.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
package org.openscience.cdk.graph;
import org._3pq.jgrapht.DirectedGraph;
import org._3pq.jgrapht.Edge;
import org._3pq.jgrapht.Graph;
import org._3pq.jgrapht.graph.DefaultDirectedGraph;
import org._3pq.jgrapht.graph.SimpleGraph;
import org._3pq.jgrapht.traverse.BreadthFirstIterator;
import org.openscience.cdk.annotations.TestClass;
import org.openscience.cdk.annotations.TestMethod;
import java.util.*;
/**
* Iterates over all shortest paths between two vertices in an undirected, unweighted graph.
*
* @author Ulrich Bauer <ulrich.bauer@alumni.tum.de>
*
*
* @cdk.module standard
* @cdk.githash
*
* @cdk.builddepends jgrapht-0.5.3.jar
* @cdk.depends jgrapht-0.5.3.jar
*/
@TestClass("org.openscience.cdk.graph.MinimalPathIteratorTest")
public class MinimalPathIterator implements Iterator {
private Object sourceVertex, targetVertex;
private Graph g;
private DirectedGraph shortestPathGraph;
private Stack edgeIteratorStack;
private Stack vertexStack;
private Object next;
/**
* Creates a minimal path iterator for the specified undirected graph.
* @param g the specified graph
* @param sourceVertex the start vertex for the paths
* @param targetVertex the target vertex for the paths
*/
public MinimalPathIterator(SimpleGraph g, Object sourceVertex, Object targetVertex) {
this.g = g;
this.sourceVertex = sourceVertex;
this.targetVertex = targetVertex;
createShortestPathGraph();
}
private void createShortestPathGraph() {
/* shortestPathGraph = new DefaultDirectedGraph();
//shortestPathGraph.addAllVertices(g.vertexSet());
LinkedList queue = new LinkedList();
//encounter target vertex
queue.addLast(targetVertex);
shortestPathGraph.addVertex(targetVertex);
int distance = 0;
Object firstVertexOfNextLevel = targetVertex;
Collection verticesOfNextLevel = new ArrayList();
while (!queue.isEmpty()) {
//provide next vertex
Object vertex = queue.removeFirst();
if (vertex == firstVertexOfNextLevel) {
distance++;
firstVertexOfNextLevel = null;
verticesOfNextLevel.clear();
}
//add unseen children of next vertex
List edges = g.edgesOf(vertex);
for(Iterator i = edges.iterator(); i.hasNext();) {
Edge e = (Edge) i.next( );
Object opposite = e.oppositeVertex(vertex);
if (!shortestPathGraph.containsVertex(opposite)) {
//encounter vertex
queue.addLast(opposite);
shortestPathGraph.addVertex(opposite);
verticesOfNextLevel.add(opposite);
if (firstVertexOfNextLevel == null) {
firstVertexOfNextLevel = opposite;
}
}
if (verticesOfNextLevel.contains(opposite)) {
shortestPathGraph.addEdge(opposite, vertex);
}
}
}
*/
shortestPathGraph = new DefaultDirectedGraph();
shortestPathGraph.addVertex(targetVertex);
// This map gives the distance of a vertex to the target vertex
Map distanceMap = new HashMap();
for (MyBreadthFirstIterator iter = new MyBreadthFirstIterator(g, targetVertex); iter.hasNext(); ) {
Object vertex = iter.next();
shortestPathGraph.addVertex(vertex);
int distance = iter.level;
distanceMap.put(vertex, Integer.valueOf(distance));
for (Iterator edges = g.edgesOf(vertex).iterator(); edges.hasNext();) {
Edge edge = (Edge) edges.next();
Object opposite = edge.oppositeVertex(vertex);
if (distanceMap.get(opposite) != null) {
if (((Integer) distanceMap.get(opposite)).intValue() + 1 == distance) {
shortestPathGraph.addVertex(opposite);
shortestPathGraph.addEdge(vertex, opposite);
}
}
}
if (vertex == sourceVertex) {
break;
}
}
Iterator edgeIterator = shortestPathGraph.outgoingEdgesOf(sourceVertex).iterator();
edgeIteratorStack = new Stack();
edgeIteratorStack.push(edgeIterator);
vertexStack = new Stack();
vertexStack.push(sourceVertex);
}
// private void createShortestPathWeightedGraph() {
// shortestPathGraph = new DefaultDirectedGraph();
// //shortestPathGraph.addAllVertices(g.vertexSet());
// shortestPathGraph.addVertex(targetVertex);
//
// // This map gives the distance of a vertex to the target vertex
// Map distanceMap = new HashMap();
// distanceMap.put(targetVertex, new Integer(0));
//
// for (ClosestFirstIterator iter = new ClosestFirstIterator(g, targetVertex); iter.hasNext(); ) {
// Object vertex = iter.next();
// shortestPathGraph.addVertex(vertex);
//
// Edge treeEdge = iter.getSpanningTreeEdge(vertex);
//
// // in the first iteration, vertex is the target vertex; therefore no tree edge exists
// if (treeEdge != null) {
// Object parent = treeEdge.oppositeVertex(vertex);
// int distance = ((Integer)distanceMap.get(parent)).intValue() + 1;
// distanceMap.put(vertex, new Integer(distance));
//
// for (Iterator edges = g.edgesOf(vertex).iterator(); edges.hasNext();) {
// Edge edge = (Edge) edges.next();
// Object opposite = edge.oppositeVertex(vertex);
// if (distanceMap.get(opposite) != null) {
// if (((Integer) distanceMap.get(opposite)).intValue() + 1 == distance) {
// shortestPathGraph.addVertex(opposite);
// shortestPathGraph.addEdge(vertex, opposite);
// }
// }
// }
// }
// if (vertex == sourceVertex) {
// break;
// }
// }
//
// Iterator edgeIterator = shortestPathGraph.outgoingEdgesOf(sourceVertex).iterator();
//
// edgeIteratorStack = new Stack();
// edgeIteratorStack.push(edgeIterator);
//
// vertexStack = new Stack();
// vertexStack.push(sourceVertex);
//
// }
@TestMethod("testMinimalPathIterator")
public boolean hasNext() {
if (next == null) {
while (next == null && !edgeIteratorStack.isEmpty()) {
Iterator edgeIterator = (Iterator) edgeIteratorStack.peek();
Object currentVertex = vertexStack.peek();
//logger.debug(currentVertex);
if (edgeIterator.hasNext()) {
Edge edge = (Edge)edgeIterator.next();
currentVertex = edge.oppositeVertex(currentVertex);
edgeIterator = shortestPathGraph.outgoingEdgesOf(currentVertex).iterator();
edgeIteratorStack.push(edgeIterator);
vertexStack.push(currentVertex);
} else {
if (currentVertex == targetVertex) {
next = edgeList(g, vertexStack);
}
edgeIteratorStack.pop();
vertexStack.pop();
}
}
}
return (next != null);
}
@TestMethod("testMinimalPathIterator")
public Object next() {
if (hasNext()) {
Object result = next;
next = null;
return result;
}
else {
return null;
}
}
@TestMethod("testRemove")
public void remove() {
throw new UnsupportedOperationException();
}
private List edgeList(Graph g, List vertexList) {
List edgeList = new ArrayList(vertexList.size()-1);
Iterator vertices = vertexList.iterator();
Object currentVertex = vertices.next();
while (vertices.hasNext()) {
Object nextVertex = vertices.next();
edgeList.add(g.getAllEdges(currentVertex, nextVertex).get(0));
currentVertex = nextVertex;
}
return edgeList;
}
private static class MyBreadthFirstIterator extends BreadthFirstIterator {
public MyBreadthFirstIterator(Graph g, Object startVertex) {
super(g, startVertex);
}
int level = -1;
private Object firstVertexOfNextLevel;
protected void encounterVertex( Object vertex, Edge edge ) {
super.encounterVertex(vertex, edge);
if (firstVertexOfNextLevel == null) {
firstVertexOfNextLevel = vertex;
}
}
protected Object provideNextVertex( ) {
Object nextVertex = super.provideNextVertex();
if (firstVertexOfNextLevel == nextVertex) {
firstVertexOfNextLevel = null;
level++;
}
return nextVertex;
}
}
}