64#ifndef OR_TOOLS_GRAPH_SHORTEST_PATHS_H_
65#define OR_TOOLS_GRAPH_SHORTEST_PATHS_H_
73#include "absl/base/attributes.h"
74#include "absl/container/flat_hash_map.h"
75#include "absl/functional/bind_front.h"
76#include "absl/log/check.h"
77#include "absl/types/span.h"
93 std::numeric_limits<uint32_t>::max();
96template <
class NodeIndex, NodeIndex kNilNode>
113template <
class GraphType>
147 std::vector<NodeIndex>* path)
const;
169 Impl* GetImplementation()
const {
return container_.get(); }
173 : container_(
std::move(impl)) {}
175 std::unique_ptr<Impl> container_;
179template <
class GraphType>
180void GetGraphNodes(
const GraphType& graph,
181 std::vector<typename GraphType::NodeIndex>* nodes) {
182 CHECK(nodes !=
nullptr);
184 nodes->reserve(graph.num_nodes());
185 for (
typename GraphType::NodeIterator iterator(graph); iterator.Ok();
187 nodes->push_back(iterator.Index());
191template <
class GraphType>
192void GetGraphNodesFromGraph(
const GraphType& graph,
193 std::vector<typename GraphType::NodeIndex>* nodes) {
194 CHECK(nodes !=
nullptr);
196 nodes->reserve(graph.num_nodes());
197 for (
const typename GraphType::NodeIndex node : graph.AllNodes()) {
198 nodes->push_back(node);
207template <
class GraphType>
208void ComputeOneToAllShortestPaths(
209 const GraphType& graph,
const std::vector<PathDistance>& arc_lengths,
210 typename GraphType::NodeIndex source,
212 std::vector<typename GraphType::NodeIndex> all_nodes;
213 GetGraphNodesFromGraph<GraphType>(graph, &all_nodes);
214 ComputeOneToManyShortestPaths(graph, arc_lengths, source, all_nodes,
221template <
class GraphType>
222void ComputeOneToManyShortestPaths(
223 const GraphType& graph,
const std::vector<PathDistance>& arc_lengths,
224 typename GraphType::NodeIndex source,
225 const std::vector<typename GraphType::NodeIndex>& destinations,
227 std::vector<typename GraphType::NodeIndex> sources(1, source);
229 graph, arc_lengths, sources, destinations, 1, path_container);
240template <
class GraphType>
241std::vector<typename GraphType::NodeIndex> ComputeOneToOneShortestPath(
242 const GraphType& graph,
const std::vector<PathDistance>& arc_lengths,
243 typename GraphType::NodeIndex source,
244 typename GraphType::NodeIndex destination) {
245 std::vector<typename GraphType::NodeIndex> sources(1, source);
246 std::vector<typename GraphType::NodeIndex> destinations(1, destination);
248 auto path_container =
252 graph, arc_lengths, sources, destinations, 1, &path_container);
254 std::vector<typename GraphType::NodeIndex> path;
255 path_container.GetPath(source, destination, &path);
261template <
class GraphType>
262void ComputeManyToAllShortestPathsWithMultipleThreads(
263 const GraphType& graph,
const std::vector<PathDistance>& arc_lengths,
264 const std::vector<typename GraphType::NodeIndex>& sources,
int num_threads,
266 std::vector<typename GraphType::NodeIndex> all_nodes;
267 GetGraphNodesFromGraph<GraphType>(graph, &all_nodes);
269 graph, arc_lengths, sources, all_nodes, num_threads, path_container);
273template <
class GraphType>
274void ComputeAllToAllShortestPathsWithMultipleThreads(
275 const GraphType& graph,
const std::vector<PathDistance>& arc_lengths,
277 std::vector<typename GraphType::NodeIndex> all_nodes;
278 GetGraphNodesFromGraph<GraphType>(graph, &all_nodes);
280 graph, arc_lengths, all_nodes, all_nodes, num_threads, path_container);
292template <
class NodeIndex, NodeIndex kNilNode>
295 PathContainerImpl() =
default;
296 virtual ~PathContainerImpl() =
default;
302 virtual void Initialize(
const std::vector<NodeIndex>& sources,
303 const std::vector<NodeIndex>& destinations,
307 virtual void Finalize() {}
329 std::vector<NodeIndex>* path)
const = 0;
338 virtual void StoreSingleSourcePaths(
339 NodeIndex from,
const std::vector<NodeIndex>& predecessor_in_path_tree,
340 const std::vector<PathDistance>& distance_to_destination) = 0;
354template <
class NodeIndex, NodeIndex kNilNode>
360 absl::Span<const NodeIndex> destinations);
370 std::vector<NodeIndex>* path)
const;
373 std::vector<NodeIndex> nodes_;
374 std::vector<int> parents_;
380template <
class NodeIndex, NodeIndex kNilNode>
382 absl::Span<const NodeIndex> paths,
383 absl::Span<const NodeIndex> destinations) {
384 std::vector<bool> node_explored(paths.size(),
false);
385 const int destination_size = destinations.size();
386 typedef std::pair<NodeIndex, NodeIndex> NodeParent;
387 std::vector<NodeParent> tree;
388 for (
int i = 0; i < destination_size; ++i) {
390 while (!node_explored[destination]) {
391 node_explored[destination] =
true;
392 tree.push_back(std::make_pair(destination, paths[destination]));
393 if (paths[destination] != kNilNode) {
394 destination = paths[destination];
398 std::sort(tree.begin(), tree.end());
399 const int num_nodes = tree.size();
401 absl::flat_hash_map<NodeIndex, int> node_indices;
403 for (
int i = 0; i < num_nodes; ++i) {
404 node_indices[tree[i].first] = i;
406 parents_.resize(num_nodes, -1);
407 for (
int i = 0; i < num_nodes; ++i) {
412 nodes_.resize(num_nodes, kNilNode);
413 for (
int i = 0; i < num_nodes; ++i) {
414 nodes_[i] = tree[i].first;
418template <
class NodeIndex, NodeIndex kNilNode>
420 const auto node_position = absl::c_lower_bound(nodes_, node);
421 if (node_position != nodes_.end() && *node_position == node) {
422 const int parent = parents_[node_position - nodes_.begin()];
423 if (parent != kNilNode) {
424 return nodes_[parent];
430template <
class NodeIndex, NodeIndex kNilNode>
433 DCHECK(path !=
nullptr);
435 const auto to_position = absl::c_lower_bound(nodes_,
to);
436 if (to_position != nodes_.end() && *to_position ==
to) {
437 int current_index = to_position - nodes_.begin();
439 while (current_node != from) {
440 path->push_back(current_node);
441 current_index = parents_[current_index];
443 if (current_index == kNilNode) {
447 current_node = nodes_[current_index];
449 path->push_back(current_node);
450 std::reverse(path->begin(), path->end());
455template <
class NodeIndex, NodeIndex kNilNode>
465 const std::vector<NodeIndex>& destinations,
470 distances_.resize(sources.size());
473 return distances_[reverse_sources_[from]][reverse_destinations_[
to]];
476 LOG(FATAL) <<
"Path not stored.";
480 LOG(FATAL) <<
"Path not stored.";
482 void StoreSingleSourcePaths(
485 const std::vector<NodeIndex>&,
486 const std::vector<PathDistance>& distance_to_destination)
override {
491 std::vector<int> reverse_sources_;
492 std::vector<int> reverse_destinations_;
495 static void ComputeReverse(absl::Span<const NodeIndex> nodes,
497 std::vector<int>* reverse_nodes) {
498 CHECK(reverse_nodes !=
nullptr);
499 const int kUnassignedIndex = -1;
500 reverse_nodes->clear();
501 reverse_nodes->resize(num_nodes, kUnassignedIndex);
502 for (
int i = 0; i < nodes.size(); ++i) {
503 reverse_nodes->at(nodes[i]) = i;
507 std::vector<std::vector<PathDistance>> distances_;
511template <
class NodeIndex, NodeIndex kNilNode>
512class InMemoryCompactPathContainer
513 :
public DistanceContainer<NodeIndex, kNilNode> {
524 void Initialize(
const std::vector<NodeIndex>& sources,
525 const std::vector<NodeIndex>& destinations,
528 destinations_ = destinations;
530 trees_.resize(sources.size());
537 std::vector<NodeIndex>* path)
const override {
538 DCHECK(path !=
nullptr);
541 void StoreSingleSourcePaths(
542 NodeIndex from,
const std::vector<NodeIndex>& predecessor_in_path_tree,
543 const std::vector<PathDistance>& distance_to_destination)
override {
545 distance_to_destination);
551 std::vector<PathTree<NodeIndex, kNilNode>> trees_;
552 std::vector<NodeIndex> destinations_;
556template <
class NodeIndex, NodeIndex kNilNode>
564 is_destination_(false) {}
565 bool operator<(
const NodeEntry& other)
const {
566 return distance_ > other.distance_;
568 void SetHeapIndex(
int h) {
572 int GetHeapIndex()
const {
return heap_index_; }
573 void set_distance(PathDistance distance) { distance_ = distance; }
582 bool is_destination()
const {
return is_destination_; }
589 bool is_destination_;
595template <
class NodeIndex, NodeIndex kNilNode>
603 "node_entry_class_is_not_well_packed");
605 DCHECK(priority_queue !=
nullptr);
606 DCHECK(entry !=
nullptr);
607 if (!priority_queue->Contains(entry)) {
608 entry->set_distance(distance);
609 priority_queue->Add(entry);
611 }
else if (distance < entry->distance()) {
612 entry->set_distance(distance);
613 priority_queue->NoteChangedPriority(entry);
623template <
class GraphType>
625 const GraphType*
const graph,
626 const std::vector<PathDistance>*
const arc_lengths,
627 typename GraphType::NodeIndex source,
628 const std::vector<typename GraphType::NodeIndex>*
const destinations,
630 using NodeIndex =
typename GraphType::NodeIndex;
631 using ArcIndex =
typename GraphType::ArcIndex;
633 CHECK(graph !=
nullptr);
634 CHECK(arc_lengths !=
nullptr);
635 CHECK(destinations !=
nullptr);
636 CHECK(paths !=
nullptr);
637 const int num_nodes = graph->num_nodes();
638 std::vector<NodeIndex> predecessor(num_nodes, GraphType::kNilNode);
640 std::vector<NodeEntryT> entries(num_nodes);
641 for (
const NodeIndex node : graph->AllNodes()) {
642 entries[node].set_node(node);
646 for (
int i = 0; i < destinations->size(); ++i) {
647 entries[(*destinations)[i]].set_is_destination(
true);
653 for (
const ArcIndex arc : graph->OutgoingArcs(source)) {
657 predecessor[next] = source;
660 int destinations_remaining = destinations->size();
661 while (!priority_queue.
IsEmpty()) {
662 NodeEntryT* current = priority_queue.
Top();
663 const NodeIndex current_node = current->node();
664 priority_queue.
Pop();
665 current->set_settled(
true);
666 if (current->is_destination()) {
667 destinations_remaining--;
668 if (destinations_remaining == 0) {
672 const PathDistance current_distance = current->distance();
673 for (
const ArcIndex arc : graph->OutgoingArcs(current_node)) {
675 NodeEntryT*
const entry = &entries[next];
676 if (!entry->settled()) {
677 DCHECK_GE(current_distance, 0);
682 predecessor[next] = current_node;
687 const int destinations_size = destinations->size();
688 std::vector<PathDistance> distances(destinations_size,
690 for (
int i = 0; i < destinations_size; ++i) {
692 if (entries[node].settled()) {
693 distances[i] = entries[node].distance();
696 paths->StoreSingleSourcePaths(source, predecessor, distances);
701template <
class GraphType>
704template <
class GraphType>
707 DCHECK(container_ !=
nullptr);
708 return container_->GetDistance(from,
to);
711template <
class GraphType>
715 DCHECK(container_ !=
nullptr);
716 return container_->GetPenultimateNodeInPath(from,
to);
719template <
class GraphType>
722 DCHECK(container_ !=
nullptr);
723 DCHECK(path !=
nullptr);
724 container_->GetPath(from,
to, path);
727template <
class GraphType>
732 internal::DistanceContainer<NodeIndex, GraphType::kNilNode>>());
735template <
class GraphType>
736GenericPathContainer<GraphType>
737GenericPathContainer<GraphType>::BuildInMemoryCompactPathContainer() {
738 return GenericPathContainer(
739 std::make_unique<internal::InMemoryCompactPathContainer<
743template <
class GraphType>
745 const GraphType& graph,
const std::vector<PathDistance>& arc_lengths,
746 const std::vector<typename GraphType::NodeIndex>& sources,
747 const std::vector<typename GraphType::NodeIndex>& destinations,
748 int num_threads, GenericPathContainer<GraphType>*
const paths) {
749 if (graph.num_nodes() > 0) {
750 CHECK_EQ(graph.num_arcs(), arc_lengths.size())
751 <<
"Number of arcs in graph must match arc length vector size";
754 std::vector<typename GraphType::NodeIndex> unique_sources = sources;
756 std::vector<typename GraphType::NodeIndex> unique_destinations =
761 auto*
const container = paths->GetImplementation();
762 container->Initialize(unique_sources, unique_destinations,
765 std::unique_ptr<ThreadPool> pool(
new ThreadPool(num_threads));
766 pool->StartWorkers();
767 for (
int i = 0; i < unique_sources.size(); ++i) {
768 pool->Schedule(absl::bind_front(
769 &internal::ComputeOneToManyOnGraph<GraphType>, &graph, &arc_lengths,
770 unique_sources[i], &unique_destinations, container));
773 container->Finalize();
774 VLOG(2) <<
"Elapsed time to compute shortest paths: " << timer.
Get() <<
"s";
void Pop()
If there are ties for the top, this returns all of them.
void Start()
When Start() is called multiple times, only the most recent is used.
DistanceContainer & operator=(const DistanceContainer &)=delete
void StoreSingleSourcePaths(NodeIndex from, const std::vector< NodeIndex > &, const std::vector< PathDistance > &distance_to_destination) override
std::vector< int > reverse_sources_
std::vector< int > reverse_destinations_
void Initialize(const std::vector< NodeIndex > &sources, const std::vector< NodeIndex > &destinations, NodeIndex num_nodes) override
typename GraphType::NodeIndex NodeIndex
virtual void GetPath(NodeIndex from, NodeIndex to, std::vector< NodeIndex > *path) const =0
Returns path nodes from node from to node to in a ordered vector.
internal::PathContainerImpl< NodeIndex, GraphType::kNilNode > Impl
GenericPathContainer & operator=(const GenericPathContainer &)=delete
virtual NodeIndex GetPenultimateNodeInPath(NodeIndex from, NodeIndex to) const =0
GenericPathContainer(const GenericPathContainer &)=delete
This type is neither copyable nor movable.
PathDistance GetDistance(NodeIndex from, NodeIndex to) const
InMemoryCompactPathContainer()
DistanceContainer< NodeIndex, kNilNode > Base
InMemoryCompactPathContainer & operator=(const InMemoryCompactPathContainer &)=delete
void Initialize(const std::vector< NodeIndex > &sources, const std::vector< NodeIndex > &destinations, NodeIndex num_nodes) override
Priority queue node entry in the boundary of the Dijkstra algorithm.
bool is_destination() const
void set_settled(bool settled)
void set_is_destination(bool is_destination)
void set_node(NodeIndex node)
PathDistance distance() const
NodeIndex GetParent(NodeIndex node) const
void Initialize(absl::Span< const NodeIndex > paths, absl::Span< const NodeIndex > destinations)
void GetPath(NodeIndex from, NodeIndex to, std::vector< NodeIndex > *path) const
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
const MapUtilMappedT< Collection > & FindWithDefault(const Collection &collection, const KeyType &key, const MapUtilMappedT< Collection > &value)
End of the interface. Below is the implementation.
In SWIG mode, we don't want anything besides these top-level includes.
void ComputeOneToManyOnGraph(const GraphType *const graph, const std::vector< PathDistance > *const arc_lengths, typename GraphType::NodeIndex source, const std::vector< typename GraphType::NodeIndex > *const destinations, typename GenericPathContainer< GraphType >::Impl *const paths)
const PathDistance kDisconnectedPathDistance
bool InsertOrUpdateEntry(PathDistance distance, NodeEntry< NodeIndex, kNilNode > *entry, AdjustablePriorityQueue< NodeEntry< NodeIndex, kNilNode > > *priority_queue)
trees with all degrees equal to
void ComputeManyToManyShortestPathsWithMultipleThreads(const GraphType &graph, const std::vector< PathDistance > &arc_lengths, const std::vector< typename GraphType::NodeIndex > &sources, const std::vector< typename GraphType::NodeIndex > &destinations, int num_threads, GenericPathContainer< GraphType > *const paths)