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,
219template <
class GraphType>
220void ComputeOneToManyShortestPaths(
221 const GraphType& graph,
const std::vector<PathDistance>& arc_lengths,
222 typename GraphType::NodeIndex source,
223 const std::vector<typename GraphType::NodeIndex>& destinations,
225 std::vector<typename GraphType::NodeIndex> sources(1, source);
227 graph, arc_lengths, sources, destinations, 1, path_container);
238template <
class GraphType>
239std::vector<typename GraphType::NodeIndex> ComputeOneToOneShortestPath(
240 const GraphType& graph,
const std::vector<PathDistance>& arc_lengths,
241 typename GraphType::NodeIndex source,
242 typename GraphType::NodeIndex destination) {
243 std::vector<typename GraphType::NodeIndex> sources(1, source);
244 std::vector<typename GraphType::NodeIndex> destinations(1, destination);
246 auto path_container =
250 graph, arc_lengths, sources, destinations, 1, &path_container);
252 std::vector<typename GraphType::NodeIndex> path;
253 path_container.GetPath(source, destination, &path);
259template <
class GraphType>
260void ComputeManyToAllShortestPathsWithMultipleThreads(
261 const GraphType& graph,
const std::vector<PathDistance>& arc_lengths,
262 const std::vector<typename GraphType::NodeIndex>& sources,
int num_threads,
264 std::vector<typename GraphType::NodeIndex> all_nodes;
265 GetGraphNodesFromGraph<GraphType>(graph, &all_nodes);
267 graph, arc_lengths, sources, all_nodes, num_threads, path_container);
271template <
class GraphType>
272void ComputeAllToAllShortestPathsWithMultipleThreads(
273 const GraphType& graph,
const std::vector<PathDistance>& arc_lengths,
275 std::vector<typename GraphType::NodeIndex> all_nodes;
276 GetGraphNodesFromGraph<GraphType>(graph, &all_nodes);
278 graph, arc_lengths, all_nodes, all_nodes, num_threads, path_container);
290template <
class NodeIndex, NodeIndex kNilNode>
293 PathContainerImpl() =
default;
294 virtual ~PathContainerImpl() =
default;
300 virtual void Initialize(
const std::vector<NodeIndex>& sources,
301 const std::vector<NodeIndex>& destinations,
305 virtual void Finalize() {}
327 std::vector<NodeIndex>* path)
const = 0;
336 virtual void StoreSingleSourcePaths(
337 NodeIndex from,
const std::vector<NodeIndex>& predecessor_in_path_tree,
338 const std::vector<PathDistance>& distance_to_destination) = 0;
352template <
class NodeIndex, NodeIndex kNilNode>
358 absl::Span<const NodeIndex> destinations);
368 std::vector<NodeIndex>* path)
const;
371 std::vector<NodeIndex> nodes_;
372 std::vector<int> parents_;
378template <
class NodeIndex, NodeIndex kNilNode>
380 absl::Span<const NodeIndex> paths,
381 absl::Span<const NodeIndex> destinations) {
382 std::vector<bool> node_explored(paths.size(),
false);
383 const int destination_size = destinations.size();
384 typedef std::pair<NodeIndex, NodeIndex> NodeParent;
385 std::vector<NodeParent> tree;
386 for (
int i = 0; i < destination_size; ++i) {
388 while (!node_explored[destination]) {
389 node_explored[destination] =
true;
390 tree.push_back(std::make_pair(destination, paths[destination]));
391 if (paths[destination] != kNilNode) {
392 destination = paths[destination];
396 std::sort(tree.begin(), tree.end());
397 const int num_nodes = tree.size();
399 absl::flat_hash_map<NodeIndex, int> node_indices;
401 for (
int i = 0; i < num_nodes; ++i) {
402 node_indices[tree[i].first] = i;
404 parents_.resize(num_nodes, -1);
405 for (
int i = 0; i < num_nodes; ++i) {
410 nodes_.resize(num_nodes, kNilNode);
411 for (
int i = 0; i < num_nodes; ++i) {
412 nodes_[i] = tree[i].first;
416template <
class NodeIndex, NodeIndex kNilNode>
418 const auto node_position = absl::c_lower_bound(nodes_, node);
419 if (node_position != nodes_.end() && *node_position == node) {
420 const int parent = parents_[node_position - nodes_.begin()];
421 if (parent != kNilNode) {
422 return nodes_[parent];
428template <
class NodeIndex, NodeIndex kNilNode>
431 DCHECK(path !=
nullptr);
433 const auto to_position = absl::c_lower_bound(nodes_,
to);
434 if (to_position != nodes_.end() && *to_position ==
to) {
435 int current_index = to_position - nodes_.begin();
437 while (current_node != from) {
438 path->push_back(current_node);
439 current_index = parents_[current_index];
441 if (current_index == kNilNode) {
445 current_node = nodes_[current_index];
447 path->push_back(current_node);
448 std::reverse(path->begin(), path->end());
453template <
class NodeIndex, NodeIndex kNilNode>
463 const std::vector<NodeIndex>& destinations,
468 distances_.resize(sources.size());
471 return distances_[reverse_sources_[from]][reverse_destinations_[
to]];
474 LOG(FATAL) <<
"Path not stored.";
478 LOG(FATAL) <<
"Path not stored.";
480 void StoreSingleSourcePaths(
483 const std::vector<NodeIndex>&,
484 const std::vector<PathDistance>& distance_to_destination)
override {
489 std::vector<int> reverse_sources_;
490 std::vector<int> reverse_destinations_;
493 static void ComputeReverse(absl::Span<const NodeIndex> nodes,
495 std::vector<int>* reverse_nodes) {
496 CHECK(reverse_nodes !=
nullptr);
497 const int kUnassignedIndex = -1;
498 reverse_nodes->clear();
499 reverse_nodes->resize(num_nodes, kUnassignedIndex);
500 for (
int i = 0; i < nodes.size(); ++i) {
501 reverse_nodes->at(nodes[i]) = i;
505 std::vector<std::vector<PathDistance>> distances_;
509template <
class NodeIndex, NodeIndex kNilNode>
510class InMemoryCompactPathContainer
511 :
public DistanceContainer<NodeIndex, kNilNode> {
522 void Initialize(
const std::vector<NodeIndex>& sources,
523 const std::vector<NodeIndex>& destinations,
526 destinations_ = destinations;
528 trees_.resize(sources.size());
535 std::vector<NodeIndex>* path)
const override {
536 DCHECK(path !=
nullptr);
539 void StoreSingleSourcePaths(
540 NodeIndex from,
const std::vector<NodeIndex>& predecessor_in_path_tree,
541 const std::vector<PathDistance>& distance_to_destination)
override {
543 distance_to_destination);
549 std::vector<PathTree<NodeIndex, kNilNode>> trees_;
550 std::vector<NodeIndex> destinations_;
554template <
class NodeIndex, NodeIndex kNilNode>
562 is_destination_(false) {}
563 bool operator<(
const NodeEntry& other)
const {
564 return distance_ > other.distance_;
566 void SetHeapIndex(
int h) {
570 int GetHeapIndex()
const {
return heap_index_; }
571 void set_distance(PathDistance distance) { distance_ = distance; }
580 bool is_destination()
const {
return is_destination_; }
587 bool is_destination_;
593template <
class NodeIndex, NodeIndex kNilNode>
601 "node_entry_class_is_not_well_packed");
603 DCHECK(priority_queue !=
nullptr);
604 DCHECK(entry !=
nullptr);
605 if (!priority_queue->Contains(entry)) {
606 entry->set_distance(distance);
607 priority_queue->Add(entry);
609 }
else if (distance < entry->distance()) {
610 entry->set_distance(distance);
611 priority_queue->NoteChangedPriority(entry);
621template <
class GraphType>
623 const GraphType*
const graph,
624 const std::vector<PathDistance>*
const arc_lengths,
625 typename GraphType::NodeIndex source,
626 const std::vector<typename GraphType::NodeIndex>*
const destinations,
628 using NodeIndex =
typename GraphType::NodeIndex;
629 using ArcIndex =
typename GraphType::ArcIndex;
631 CHECK(graph !=
nullptr);
632 CHECK(arc_lengths !=
nullptr);
633 CHECK(destinations !=
nullptr);
634 CHECK(paths !=
nullptr);
635 const int num_nodes = graph->num_nodes();
636 std::vector<NodeIndex> predecessor(num_nodes, GraphType::kNilNode);
638 std::vector<NodeEntryT> entries(num_nodes);
639 for (
const NodeIndex node : graph->AllNodes()) {
640 entries[node].set_node(node);
644 for (
int i = 0; i < destinations->size(); ++i) {
645 entries[(*destinations)[i]].set_is_destination(
true);
651 for (
const ArcIndex arc : graph->OutgoingArcs(source)) {
655 predecessor[next] = source;
658 int destinations_remaining = destinations->size();
659 while (!priority_queue.
IsEmpty()) {
660 NodeEntryT* current = priority_queue.
Top();
661 const NodeIndex current_node = current->node();
662 priority_queue.
Pop();
663 current->set_settled(
true);
664 if (current->is_destination()) {
665 destinations_remaining--;
666 if (destinations_remaining == 0) {
670 const PathDistance current_distance = current->distance();
671 for (
const ArcIndex arc : graph->OutgoingArcs(current_node)) {
673 NodeEntryT*
const entry = &entries[next];
674 if (!entry->settled()) {
675 DCHECK_GE(current_distance, 0);
680 predecessor[next] = current_node;
685 const int destinations_size = destinations->size();
686 std::vector<PathDistance> distances(destinations_size,
688 for (
int i = 0; i < destinations_size; ++i) {
690 if (entries[node].settled()) {
691 distances[i] = entries[node].distance();
694 paths->StoreSingleSourcePaths(source, predecessor, distances);
699template <
class GraphType>
702template <
class GraphType>
705 DCHECK(container_ !=
nullptr);
706 return container_->GetDistance(from,
to);
709template <
class GraphType>
713 DCHECK(container_ !=
nullptr);
714 return container_->GetPenultimateNodeInPath(from,
to);
717template <
class GraphType>
720 DCHECK(container_ !=
nullptr);
721 DCHECK(path !=
nullptr);
722 container_->GetPath(from,
to, path);
725template <
class GraphType>
730 internal::DistanceContainer<NodeIndex, GraphType::kNilNode>>());
733template <
class GraphType>
734GenericPathContainer<GraphType>
735GenericPathContainer<GraphType>::BuildInMemoryCompactPathContainer() {
736 return GenericPathContainer(
737 std::make_unique<internal::InMemoryCompactPathContainer<
741template <
class GraphType>
743 const GraphType& graph,
const std::vector<PathDistance>& arc_lengths,
744 const std::vector<typename GraphType::NodeIndex>& sources,
745 const std::vector<typename GraphType::NodeIndex>& destinations,
746 int num_threads, GenericPathContainer<GraphType>*
const paths) {
747 if (graph.num_nodes() > 0) {
748 CHECK_EQ(graph.num_arcs(), arc_lengths.size())
749 <<
"Number of arcs in graph must match arc length vector size";
752 std::vector<typename GraphType::NodeIndex> unique_sources = sources;
754 std::vector<typename GraphType::NodeIndex> unique_destinations =
759 auto*
const container = paths->GetImplementation();
760 container->Initialize(unique_sources, unique_destinations,
763 std::unique_ptr<ThreadPool> pool(
new ThreadPool(num_threads));
764 pool->StartWorkers();
765 for (
int i = 0; i < unique_sources.size(); ++i) {
766 pool->Schedule(absl::bind_front(
767 &internal::ComputeOneToManyOnGraph<GraphType>, &graph, &arc_lengths,
768 unique_sources[i], &unique_destinations, container));
771 container->Finalize();
772 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
BlossomGraph::NodeIndex NodeIndex
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)