org.jgrapht.alg.shortestpath.DijkstraManyToManyShortestPaths Maven / Gradle / Ivy
/*
* (C) Copyright 2019-2023, by Semen Chudakov and Contributors.
*
* JGraphT : a free Java graph-theory library
*
* See the CONTRIBUTORS.md file distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the
* GNU Lesser General Public License v2.1 or later
* which is available at
* http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html.
*
* SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later
*/
package org.jgrapht.alg.shortestpath;
import org.jgrapht.*;
import org.jgrapht.alg.interfaces.*;
import org.jgrapht.graph.*;
import java.util.*;
/**
* Naive algorithm for many-to-many shortest paths problem using
* {@link DijkstraClosestFirstIterator}.
*
*
* Complexity of the algorithm is $O(min(|S|,|T|)*(V\log V + E))$, where $S$ is the set of source
* vertices, $T$ is the set of target vertices, $V$ is the set of graph vertices and $E$ is the set
* of graph edges of the graph.
*
*
* For each source vertex a single source shortest paths search is performed, which is stopped as
* soon as all target vertices are reached. Shortest paths trees are constructed using
* {@link DijkstraClosestFirstIterator}. In case $|T| > |S|$ the searches are performed on the
* reversed graph using $|T|$ as source vertices and $|S|$ as target vertices. This allows to reduce
* the total number of searches from $|S|$ to $min(|S|,|T|)$.
*
*
* The main bottleneck of this algorithm is the memory usage to store individual shortest paths
* trees for every source vertex, as they may take a lot of space. Considering this, the typical use
* case of this algorithm are small graphs or large graphs with small total number of source and
* target vertices.
*
* @param the graph vertex type
* @param the graph edge type
* @author Semen Chudakov
* @see DefaultManyToManyShortestPaths
* @see CHManyToManyShortestPaths
*/
public class DijkstraManyToManyShortestPaths
extends BaseManyToManyShortestPaths
{
/**
* Constructs an instance of the algorithm for a given {@code graph}.
*
* @param graph underlying graph
*/
public DijkstraManyToManyShortestPaths(Graph graph)
{
super(graph);
}
/**
* {@inheritDoc}
*/
@Override
public ManyToManyShortestPaths getManyToManyPaths(Set sources, Set targets)
{
Objects.requireNonNull(sources, "sources cannot be null!");
Objects.requireNonNull(targets, "targets cannot be null!");
Map> searchSpaces = new HashMap<>();
if (sources.size() >= targets.size()) {
for (V source : sources) {
searchSpaces.put(source, getShortestPathsTree(graph, source, targets));
}
return new DijkstraManyToManyShortestPathsImpl(sources, targets, false, searchSpaces);
} else {
Graph edgeReversedGraph = new EdgeReversedGraph<>(graph);
for (V target : targets) {
searchSpaces.put(target, getShortestPathsTree(edgeReversedGraph, target, sources));
}
return new DijkstraManyToManyShortestPathsImpl(sources, targets, true, searchSpaces);
}
}
/**
* Implementation of the
* {@link org.jgrapht.alg.interfaces.ManyToManyShortestPathsAlgorithm.ManyToManyShortestPaths}.
* For each source vertex a single source shortest paths tree is stored. It is used to retrieve
* both actual paths and theirs weights.
*/
private class DijkstraManyToManyShortestPathsImpl
extends BaseManyToManyShortestPathsImpl
{
/**
* Indicates is the search spaces were computed on the edge reversed graph.
*/
private boolean reversed;
/**
* Map from source vertices to corresponding single source shortest path trees.
*/
private final Map> searchSpaces;
/**
* Constructs an instance of the algorithm for the given {@code sources}, {@code targets},
* {@code reversed} and {@code searchSpaces}.
*
* @param sources source vertices
* @param targets target vertices
* @param reversed if search spaces are reversed
* @param searchSpaces single source shortest paths trees map
*/
DijkstraManyToManyShortestPathsImpl(
Set sources, Set targets, boolean reversed,
Map> searchSpaces)
{
super(sources, targets);
this.reversed = reversed;
this.searchSpaces = searchSpaces;
}
/**
* {@inheritDoc}
*/
@Override
public GraphPath getPath(V source, V target)
{
assertCorrectSourceAndTarget(source, target);
if (reversed) {
GraphPath reversedPath = searchSpaces.get(target).getPath(source);
if (reversedPath == null) {
return null;
}
List vertices = reversedPath.getVertexList();
List edges = reversedPath.getEdgeList();
Collections.reverse(vertices);
Collections.reverse(edges);
return new GraphWalk<>(
graph, source, target, vertices, edges, reversedPath.getWeight());
} else {
return searchSpaces.get(source).getPath(target);
}
}
/**
* {@inheritDoc}
*/
@Override
public double getWeight(V source, V target)
{
assertCorrectSourceAndTarget(source, target);
if (reversed) {
return searchSpaces.get(target).getWeight(source);
}
return searchSpaces.get(source).getWeight(target);
}
}
}