org.jgrapht.alg.RankingPathElementList Maven / Gradle / Ivy
/* ==========================================
* 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-2010, by Barak Naveh and Contributors.
*
* This program and the accompanying materials are dual-licensed under
* either
*
* (a) the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation, or (at your option) any
* later version.
*
* or (per the licensee's choosing)
*
* (b) the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation.
*/
/* -------------------------
* RankingPathElementList.java
* -------------------------
* (C) Copyright 2007-2010, by France Telecom
*
* Original Author: Guillaume Boulmier and Contributors.
* Contributor(s): John V. Sichi
*
* $Id$
*
* Changes
* -------
* 05-Jun-2007 : Initial revision (GB);
* 05-Jul-2007 : Added support for generics (JVS);
* 06-Dec-2010 : Bugfixes (GB);
*
*/
package org.jgrapht.alg;
import java.util.*;
import org.jgrapht.*;
import org.jgrapht.graph.*;
/**
* List of simple paths in increasing order of weight.
*
* @author Guillaume Boulmier
* @since July 5, 2007
*/
final class RankingPathElementList
extends AbstractPathElementList>
{
/**
* Vertex that paths of the list must not disconnect.
*/
private V guardVertexToNotDisconnect = null;
private Map, Boolean> path2disconnect =
new HashMap, Boolean>();
/**
* Creates a list with an empty path. The list size is 1.
*
* @param maxSize max number of paths the list is able to store.
*/
RankingPathElementList(
Graph graph,
int maxSize,
RankingPathElement pathElement)
{
super(graph, maxSize, pathElement);
}
/**
* Creates paths obtained by concatenating the specified edge to the
* specified paths.
*
* @param prevPathElementList paths, list of
* RankingPathElement
.
* @param edge edge reaching the end vertex of the created paths.
* @param maxSize maximum number of paths the list is able to store.
*/
RankingPathElementList(
Graph graph,
int maxSize,
RankingPathElementList elementList,
E edge)
{
this(graph, maxSize, elementList, edge, null);
assert (!this.pathElements.isEmpty());
}
/**
* Creates paths obtained by concatenating the specified edge to the
* specified paths.
*
* @param prevPathElementList paths, list of
* RankingPathElement
.
* @param edge edge reaching the end vertex of the created paths.
* @param maxSize maximum number of paths the list is able to store.
*/
RankingPathElementList(
Graph graph,
int maxSize,
RankingPathElementList elementList,
E edge,
V guardVertexToNotDisconnect)
{
super(graph, maxSize, elementList, edge);
this.guardVertexToNotDisconnect = guardVertexToNotDisconnect;
// loop over the path elements in increasing order of weight.
for (int i = 0; (i < elementList.size()) && (size() < maxSize); i++) {
RankingPathElement prevPathElement = elementList.get(i);
if (isNotValidPath(prevPathElement, edge)) {
// go to the next path element in the loop
continue;
}
double weight = calculatePathWeight(prevPathElement, edge);
RankingPathElement newPathElement =
new RankingPathElement(
this.graph,
prevPathElement,
edge,
weight);
// the new path is inserted at the end of the list.
this.pathElements.add(newPathElement);
}
}
/**
* Creates an empty list. The list size is 0.
*
* @param maxSize max number of paths the list is able to store.
*/
RankingPathElementList(Graph graph, int maxSize, V vertex)
{
super(graph, maxSize, vertex);
}
/**
* Adds paths in the list at vertex y. Candidate paths are obtained by
* concatenating the specified edge (v->y) to the paths
* elementList
at vertex v.
*
* Complexity =
*
*
* - w/o guard-vertex: O(
k*np
) where k
is the
* max size limit of the list and np
is the maximum number of
* vertices in the paths stored in the list
* - with guard-vertex: O(
k*(m+n)
) where k
is
* the max size limit of the list, m
is the number of edges of
* the graph and n
is the number of vertices of the graph,
* O(m+n
) being the complexity of the
* ConnectivityInspector
to check whether a path exists towards the
* guard-vertex
*
*
* @param elementList list of paths at vertex v.
* @param edge edge (v->y).
*
* @return true
if at least one path has been added in the
* list, false
otherwise.
*/
public boolean addPathElements(
RankingPathElementList elementList,
E edge)
{
assert (this.vertex.equals(
Graphs.getOppositeVertex(
this.graph,
edge,
elementList.getVertex())));
boolean pathAdded = false;
// loop over the paths elements of the list at vertex v.
for (
int vIndex = 0, yIndex = 0;
vIndex < elementList.size();
vIndex++)
{
RankingPathElement prevPathElement = elementList.get(vIndex);
if (isNotValidPath(prevPathElement, edge)) {
// checks if path is simple and if guard-vertex is not
// disconnected.
continue;
}
double newPathWeight = calculatePathWeight(prevPathElement, edge);
RankingPathElement newPathElement =
new RankingPathElement(
this.graph,
prevPathElement,
edge,
newPathWeight);
// loop over the paths of the list at vertex y from yIndex to the
// end.
RankingPathElement yPathElement = null;
for (; yIndex < size(); yIndex++) {
yPathElement = get(yIndex);
// case when the new path is shorter than the path Py stored at
// index y
if (newPathWeight < yPathElement.getWeight()) {
this.pathElements.add(yIndex, newPathElement);
pathAdded = true;
// ensures max size limit is not exceeded.
if (size() > this.maxSize) {
this.pathElements.remove(this.maxSize);
}
break;
}
// case when the new path is of the same length as the path Py
// stored at index y
if (newPathWeight == yPathElement.getWeight()) {
this.pathElements.add(yIndex + 1, newPathElement);
pathAdded = true;
// ensures max size limit is not exceeded.
if (size() > this.maxSize) {
this.pathElements.remove(this.maxSize);
}
break;
}
}
// case when the new path is longer than the longest path in the
// list (Py stored at the last index y)
if (newPathWeight > yPathElement.getWeight()) {
// ensures max size limit is not exceeded.
if (size() < this.maxSize) {
// the new path is inserted at the end of the list.
this.pathElements.add(newPathElement);
pathAdded = true;
} else {
// max size limit is reached -> end of the loop over the
// paths elements of the list at vertex v.
break;
}
}
}
return pathAdded;
}
/**
* @return list of RankingPathElement
.
*/
List> getPathElements()
{
return this.pathElements;
}
/**
* Costs taken into account are the weights stored in Edge
* objects.
*
* @param pathElement
* @param edge the edge via which the vertex was encountered.
*
* @return the cost obtained by concatenation.
*
* @see Graph#getEdgeWeight(E)
*/
private double calculatePathWeight(
RankingPathElement pathElement,
E edge)
{
double pathWeight = this.graph.getEdgeWeight(edge);
// otherwise it's the start vertex.
if ((pathElement.getPrevEdge() != null)) {
pathWeight += pathElement.getWeight();
}
return pathWeight;
}
/**
* Ensures that paths of the list do not disconnect the guard-vertex.
*
* @return true
if the specified path element disconnects the
* guard-vertex, false
otherwise.
*/
private boolean isGuardVertexDisconnected(
RankingPathElement prevPathElement)
{
if (this.guardVertexToNotDisconnect == null) {
return false;
}
if (this.path2disconnect.containsKey(prevPathElement)) {
return this.path2disconnect.get(prevPathElement);
}
ConnectivityInspector connectivityInspector;
MaskFunctor connectivityMask;
if (this.graph instanceof DirectedGraph, ?>) {
connectivityMask = new PathMask(prevPathElement);
DirectedMaskSubgraph connectivityGraph =
new DirectedMaskSubgraph(
(DirectedGraph) this.graph,
connectivityMask);
connectivityInspector =
new ConnectivityInspector(
connectivityGraph);
} else {
connectivityMask = new PathMask(prevPathElement);
UndirectedMaskSubgraph connectivityGraph =
new UndirectedMaskSubgraph(
(UndirectedGraph) this.graph,
connectivityMask);
connectivityInspector =
new ConnectivityInspector(
connectivityGraph);
}
if (connectivityMask.isVertexMasked(this.guardVertexToNotDisconnect)) {
// the guard-vertex was already in the path element -> invalid path
this.path2disconnect.put(prevPathElement, true);
return true;
}
if (!connectivityInspector.pathExists(
this.vertex,
this.guardVertexToNotDisconnect))
{
this.path2disconnect.put(prevPathElement, true);
return true;
}
this.path2disconnect.put(prevPathElement, false);
return false;
}
private boolean isNotValidPath(
RankingPathElement prevPathElement,
E edge)
{
return !isSimplePath(prevPathElement, edge)
|| isGuardVertexDisconnected(prevPathElement);
}
/**
* Ensures that paths of the list are simple (check that the vertex was not
* already in the path element).
*
* @param prevPathElement
* @param edge
*
* @return true
if the resulting path (obtained by
* concatenating the specified edge to the specified path) is simple,
* false
otherwise.
*/
private boolean isSimplePath(
RankingPathElement prevPathElement,
E edge)
{
V endVertex =
Graphs.getOppositeVertex(
this.graph,
edge,
prevPathElement.getVertex());
assert (endVertex.equals(this.vertex));
RankingPathElement pathElementToTest = prevPathElement;
do {
if (pathElementToTest.getVertex().equals(endVertex)) {
return false;
} else {
pathElementToTest = pathElementToTest.getPrevPathElement();
}
} while (pathElementToTest != null);
return true;
}
private static class PathMask
implements MaskFunctor
{
private Set maskedEdges;
private Set maskedVertices;
/**
* Creates a mask for all the edges and the vertices of the path
* (including the 2 extremity vertices).
*
* @param pathElement
*/
PathMask(RankingPathElement pathElement)
{
this.maskedEdges = new HashSet();
this.maskedVertices = new HashSet();
while (pathElement.getPrevEdge() != null) {
this.maskedEdges.add(pathElement.getPrevEdge());
this.maskedVertices.add(pathElement.getVertex());
pathElement = pathElement.getPrevPathElement();
}
this.maskedVertices.add(pathElement.getVertex());
}
// implement MaskFunctor
@Override public boolean isEdgeMasked(E edge)
{
return this.maskedEdges.contains(edge);
}
// implement MaskFunctor
@Override public boolean isVertexMasked(V vertex)
{
return this.maskedVertices.contains(vertex);
}
}
}
// End RankingPathElementList.java