All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrapht.traverse.ClosestFirstIterator Maven / Gradle / Ivy

Go to download

JGraphT is a free Java graph library that provides mathematical graph-theory objects and algorithms

The newest version!
/* ==========================================
 * JGraphT : a free Java graph-theory library
 * ==========================================
 *
 * Project Info:  http://jgrapht.sourceforge.net/
 * Project Creator:  Barak Naveh (http://sourceforge.net/users/barak_naveh)
 *
 * (C) Copyright 2003-2007, by Barak Naveh and Contributors.
 *
 * This library 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.
 *
 * This library 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 library; if not, write to the Free Software Foundation,
 * Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */
/* -------------------------
 * ClosestFirstIterator.java
 * -------------------------
 * (C) Copyright 2003-2007, by John V. Sichi and Contributors.
 *
 * Original Author:  John V. Sichi
 * Contributor(s):   Barak Naveh
 *
 * $Id: ClosestFirstIterator.java 568 2007-09-30 00:12:18Z perfecthash $
 *
 * Changes
 * -------
 * 02-Sep-2003 : Initial revision (JVS);
 * 31-Jan-2004 : Reparented and changed interface to parent class (BN);
 * 29-May-2005 : Added radius support (JVS);
 * 06-Jun-2005 : Made generic (CH);
 *
 */
package org.jgrapht.traverse;

import org.jgrapht.*;
import org.jgrapht.util.*;


/**
 * A closest-first iterator for a directed or undirected graph. For this
 * iterator to work correctly the graph must not be modified during iteration.
 * Currently there are no means to ensure that, nor to fail-fast. The results of
 * such modifications are undefined.
 *
 * 

The metric for closest here is the path length from a start vertex. * Graph.getEdgeWeight(Edge) is summed to calculate path length. Negative edge * weights will result in an IllegalArgumentException. Optionally, path length * may be bounded by a finite radius.

* * @author John V. Sichi * @since Sep 2, 2003 */ public class ClosestFirstIterator extends CrossComponentIterator>> { //~ Instance fields -------------------------------------------------------- /** * Priority queue of fringe vertices. */ private FibonacciHeap> heap = new FibonacciHeap>(); /** * Maximum distance to search. */ private double radius = Double.POSITIVE_INFINITY; private boolean initialized = false; //~ Constructors ----------------------------------------------------------- /** * Creates a new closest-first iterator for the specified graph. * * @param g the graph to be iterated. */ public ClosestFirstIterator(Graph g) { this(g, null); } /** * Creates a new closest-first iterator for the specified graph. Iteration * will start at the specified start vertex and will be limited to the * connected component that includes that vertex. If the specified start * vertex is null, iteration will start at an arbitrary vertex * and will not be limited, that is, will be able to traverse all the graph. * * @param g the graph to be iterated. * @param startVertex the vertex iteration to be started. */ public ClosestFirstIterator(Graph g, V startVertex) { this(g, startVertex, Double.POSITIVE_INFINITY); } /** * Creates a new radius-bounded closest-first iterator for the specified * graph. Iteration will start at the specified start vertex and will be * limited to the subset of the connected component which includes that * vertex and is reachable via paths of length less than or equal to the * specified radius. The specified start vertex may not be * null. * * @param g the graph to be iterated. * @param startVertex the vertex iteration to be started. * @param radius limit on path length, or Double.POSITIVE_INFINITY for * unbounded search. */ public ClosestFirstIterator(Graph g, V startVertex, double radius) { super(g, startVertex); this.radius = radius; checkRadiusTraversal(isCrossComponentTraversal()); initialized = true; } //~ Methods ---------------------------------------------------------------- // override AbstractGraphIterator public void setCrossComponentTraversal(boolean crossComponentTraversal) { if (initialized) { checkRadiusTraversal(crossComponentTraversal); } super.setCrossComponentTraversal(crossComponentTraversal); } /** * Get the length of the shortest path known to the given vertex. If the * vertex has already been visited, then it is truly the shortest path * length; otherwise, it is the best known upper bound. * * @param vertex vertex being sought from start vertex * * @return length of shortest path known, or Double.POSITIVE_INFINITY if no * path found yet */ public double getShortestPathLength(V vertex) { FibonacciHeapNode> node = getSeenData(vertex); if (node == null) { return Double.POSITIVE_INFINITY; } return node.getKey(); } /** * Get the spanning tree edge reaching a vertex which has been seen already * in this traversal. This edge is the last link in the shortest known path * between the start vertex and the requested vertex. If the vertex has * already been visited, then it is truly the minimum spanning tree edge; * otherwise, it is the best candidate seen so far. * * @param vertex the spanned vertex. * * @return the spanning tree edge, or null if the vertex either has not been * seen yet or is the start vertex. */ public E getSpanningTreeEdge(V vertex) { FibonacciHeapNode> node = getSeenData(vertex); if (node == null) { return null; } return node.getData().spanningTreeEdge; } /** * @see CrossComponentIterator#isConnectedComponentExhausted() */ protected boolean isConnectedComponentExhausted() { if (heap.size() == 0) { return true; } else { if (heap.min().getKey() > radius) { heap.clear(); return true; } else { return false; } } } /** * @see CrossComponentIterator#encounterVertex(Object, Object) */ protected void encounterVertex(V vertex, E edge) { FibonacciHeapNode> node = createSeenData(vertex, edge); putSeenData(vertex, node); heap.insert(node, node.getKey()); } /** * Override superclass. When we see a vertex again, we need to see if the * new edge provides a shorter path than the old edge. * * @param vertex the vertex re-encountered * @param edge the edge via which the vertex was re-encountered */ protected void encounterVertexAgain(V vertex, E edge) { FibonacciHeapNode> node = getSeenData(vertex); if (node.getData().frozen) { // no improvement for this vertex possible return; } double candidatePathLength = calculatePathLength(vertex, edge); if (candidatePathLength < node.getKey()) { node.getData().spanningTreeEdge = edge; heap.decreaseKey(node, candidatePathLength); } } /** * @see CrossComponentIterator#provideNextVertex() */ protected V provideNextVertex() { FibonacciHeapNode> node = heap.removeMin(); node.getData().frozen = true; return node.getData().vertex; } private void assertNonNegativeEdge(E edge) { if (getGraph().getEdgeWeight(edge) < 0) { throw new IllegalArgumentException( "negative edge weights not allowed"); } } /** * Determine path length to a vertex via an edge, using the path length for * the opposite vertex. * * @param vertex the vertex for which to calculate the path length. * @param edge the edge via which the path is being extended. * * @return calculated path length. */ private double calculatePathLength(V vertex, E edge) { assertNonNegativeEdge(edge); V otherVertex = Graphs.getOppositeVertex(getGraph(), edge, vertex); FibonacciHeapNode> otherEntry = getSeenData(otherVertex); return otherEntry.getKey() + getGraph().getEdgeWeight(edge); } private void checkRadiusTraversal(boolean crossComponentTraversal) { if (crossComponentTraversal && (radius != Double.POSITIVE_INFINITY)) { throw new IllegalArgumentException( "radius may not be specified for cross-component traversal"); } } /** * The first time we see a vertex, make up a new heap node for it. * * @param vertex a vertex which has just been encountered. * @param edge the edge via which the vertex was encountered. * * @return the new heap node. */ private FibonacciHeapNode> createSeenData( V vertex, E edge) { double shortestPathLength; if (edge == null) { shortestPathLength = 0; } else { shortestPathLength = calculatePathLength(vertex, edge); } QueueEntry entry = new QueueEntry(); entry.vertex = vertex; entry.spanningTreeEdge = edge; return new FibonacciHeapNode>( entry, shortestPathLength); } //~ Inner Classes ---------------------------------------------------------- /** * Private data to associate with each entry in the priority queue. */ static class QueueEntry { /** * Best spanning tree edge to vertex seen so far. */ E spanningTreeEdge; /** * The vertex reached. */ V vertex; /** * True once spanningTreeEdge is guaranteed to be the true minimum. */ boolean frozen; QueueEntry() { } } } // End ClosestFirstIterator.java




© 2015 - 2024 Weber Informatics LLC | Privacy Policy