blob: 986888b0b9eb06d1397f46d224c3cbf1fb715ebe [file] [log] [blame]
package org.apache.commons.graph.shortestpath;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import static org.apache.commons.graph.utils.Assertions.checkNotNull;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.graph.Graph;
import org.apache.commons.graph.Mapper;
import org.apache.commons.graph.UndirectedGraph;
import org.apache.commons.graph.VertexPair;
import org.apache.commons.graph.WeightedPath;
import org.apache.commons.graph.math.monoid.OrderedMonoid;
import org.apache.commons.graph.model.PredecessorsList;
final class DefaultPathSourceSelector<V, WE, W>
implements PathSourceSelector<V, WE, W>
{
private final Graph<V, WE> graph;
private final Mapper<WE, W> weightedEdges;
public DefaultPathSourceSelector( Graph<V, WE> graph, Mapper<WE, W> weightedEdges )
{
this.graph = graph;
this.weightedEdges = weightedEdges;
}
/**
* {@inheritDoc}
*/
public <WO extends OrderedMonoid<W>> AllVertexPairsShortestPath<V, WE, W> applyingFloydWarshall( WO weightOperations )
{
weightOperations = checkNotNull( weightOperations, "Floyd-Warshall algorithm can not be applied using null weight operations" );
AllVertexPairsShortestPath<V, WE, W> shortestPaths = new AllVertexPairsShortestPath<V, WE, W>( weightOperations );
Map<VertexPair<V>, V> next = new HashMap<VertexPair<V>, V>();
// init
for ( WE we : graph.getEdges() )
{
VertexPair<V> vertexPair = graph.getVertices( we );
shortestPaths.addShortestDistance( vertexPair.getHead(), vertexPair.getTail(), weightedEdges.map( we ) );
if ( graph instanceof UndirectedGraph )
{
shortestPaths.addShortestDistance( vertexPair.getTail(), vertexPair.getHead(), weightedEdges.map( we ) );
}
}
// run the Floyd-Warshall algorithm.
for ( V k : graph.getVertices() )
{
for ( V i : graph.getVertices() )
{
for ( V j : graph.getVertices() )
{
if ( shortestPaths.hasShortestDistance( i, k ) && shortestPaths.hasShortestDistance( k, j ) )
{
W newDistance = weightOperations.append( shortestPaths.getShortestDistance( i, k ), shortestPaths.getShortestDistance( k, j ) );
if ( !shortestPaths.hasShortestDistance( i, j )
|| weightOperations.compare( newDistance, shortestPaths.getShortestDistance( i, j ) ) < 0 )
{
shortestPaths.addShortestDistance( i, j, newDistance );
// store the intermediate vertex
next.put( new VertexPair<V>( i, j ), k );
}
}
}
}
}
// fills all WeightedPaths
for ( V source : graph.getVertices() )
{
for ( V target : graph.getVertices() )
{
if ( !source.equals( target ) )
{
PredecessorsList<V, WE, W> predecessorsList = new PredecessorsList<V, WE, W>( graph, weightOperations, weightedEdges );
pathReconstruction( predecessorsList, source, target, next );
if ( !predecessorsList.isEmpty() )
{
WeightedPath<V, WE, W> weightedPath = predecessorsList.buildPath( source, target );
if ( weightedPath.getOrder() > 0 )
{
shortestPaths.addShortestPath( source, target, weightedPath );
}
}
}
}
}
return shortestPaths;
}
private void pathReconstruction( PredecessorsList<V, WE, W> path,
V source, V target,
Map<VertexPair<V>, V> next )
{
V k = next.get( new VertexPair<V>( source, target ) );
if ( k == null )
{
// there is a direct path between a and b
WE edge = graph.getEdge( source, target );
if ( edge != null )
{
path.addPredecessor( target, source );
}
}
else
{
pathReconstruction( path, source, k, next );
pathReconstruction( path, k, target, next );
}
}
/**
* {@inheritDoc}
*/
public <H extends V> TargetSourceSelector<V, WE, W> from( H source )
{
source = checkNotNull( source, "Shortest path can not be calculated from a null source" );
return new DefaultTargetSourceSelector<V, WE, W>( graph, weightedEdges, source );
}
}