Google OR-Tools v9.14
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
shortest_paths.h
Go to the documentation of this file.
1// Copyright 2010-2025 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14// This file contains functions to compute shortest paths on graphs using
15// Dijkstra's algorithm,
16// E.W. Dijkstra, "A note on two problems in connexion with graphs". Numerische
17// Mathematik 1:269–271, 1959. See for example:
18// http://www.springerlink.com/content/uu8608u0u27k7256/fulltext.pdf.
19// More information can also be found on Wikipedia:
20// http://en.wikipedia.org/wiki/Dijkstra's_algorithm
21//
22// This is a unidirectional implementation of Dijkstra's algorithm. A
23// bidirectional is available in bidirectional_dijkstra.h for specific use
24// cases.
25//
26// Each 1-to-many shortest path computation is run in a separate thread. Users
27// should select the number of threads to use according to the number of cores
28// available (each thread will use up one core). However, increasing the number
29// of threads also increases temporary memory used by each 1-to-many
30// computation.
31//
32// Also included are classes to store path data resulting from shortest path
33// computations (cf. GenericPathContainer).
34//
35// Usage example computing all-pair shortest paths on a graph:
36// StaticGraph<> graph(...,...);
37// std::vector<uint32_t> arc_lengths(...,...);
38// ... populate graph and arc lengths ...
39// GenericPathContainer<StaticGraph<>> container =
40// GenericPathContainer<
41// StaticGraph<>>::BuildInMemoryCompactPathContainer();
42// ComputeAllToAllShortestPathsWithMultipleThreads(graph,
43// arc_lengths,
44// /*num_threads=*/4,
45// &container);
46//
47// Usage example computing shortest paths between a subset of graph nodes:
48// StaticGraph<> graph(...,...);
49// std::vector<uint32_t> arc_lengths(...,...);
50// ... populate graph and arc lengths ...
51// vector<NodeIndex> sources;
52// vector<NodeIndex> sinks;
53// ... fill sources and sinks ...
54// GenericPathContainer<StaticGraph<>> container =
55// GenericPathContainer<
56// StaticGraph<>>::BuildInMemoryCompactPathContainer();
57// ComputeManyToManyShortestPathsWithMultipleThreads(graph,
58// arc_lengths,
59// sources,
60// sinks,
61// /*num_threads=*/4,
62// &container);
63
64#ifndef OR_TOOLS_GRAPH_SHORTEST_PATHS_H_
65#define OR_TOOLS_GRAPH_SHORTEST_PATHS_H_
66
67#include <cstdint>
68#include <limits>
69#include <memory>
70#include <utility>
71#include <vector>
72
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"
84#include "ortools/base/timer.h"
85namespace operations_research {
86
87// Storing distances on 32 bits to limit memory consumption of distance
88// matrices. If distances don't fit on 32 bits, scaling and losing a bit of
89// precision should be acceptable in practice.
90typedef uint32_t PathDistance;
91
93 std::numeric_limits<uint32_t>::max();
94
95namespace internal {
96template <class NodeIndex, NodeIndex kNilNode>
98} // namespace internal
99
100// Container class storing paths and distances along the paths. It is used in
101// shortest path computation functions to store resulting shortest paths.
102// Usage example iterating on the path between nodes `from` and `to`:
103// GenericPathContainer<StaticGraph<>> container =
104// GenericPathContainer<
105// StaticGraph<>>::BuildInMemoryCompactPathContainer();
106// // ... fill up container ...
107// const GenericPathContainer::NodeIndex from =...;
108// GenericPathContainer::NodeIndex to =...;
109// while (to != from) {
110// LOG(INFO) << to;
111// to = container.GetPenultimateNodeInPath(from, to);
112// }
113template <class GraphType>
115 public:
116 using NodeIndex = typename GraphType::NodeIndex;
118
119 // This type is neither copyable nor movable.
122
124
125 // Returns the distance between node `from` and node `to` following the path
126 // out of `from` and into `to`. Note that if `from` == `to`, the distance is
127 // not necessarily 0 if the path out of `to` and back into `to` has a distance
128 // greater than 0. If you do require the distance to be 0 in this case, add to
129 // the graph an arc from `to` to itself with a length of 0.
130 // If nodes are not connected, returns `kDisconnectedPathDistance`.
132
133 // Returns the penultimate node on the path out of node `from` into node `to`
134 // (the direct predecessor of node `to` on the path).
135 // If `from` == `to`, the penultimate node is `to` only if the shortest path
136 // from `to` to itself is composed of the arc (`to, `to`), which might not be
137 // the case if either this arc doesn't exist or if the length of this arc is
138 // greater than the distance of an alternate path.
139 // If nodes are not connected, returns `GraphType::kNilNode`.
141
142 // Returns path nodes from node `from` to node `to` in the order in which they
143 // appear along the path.
144 // The vector starts with `from` and ends with `to`, if both nodes are
145 // connected (otherwise an empty vector is returned).
146 void GetPath(NodeIndex from, NodeIndex to,
147 std::vector<NodeIndex>* path) const;
148
149 // Builds a path container which only stores distances between path nodes.
150 static GenericPathContainer BuildPathDistanceContainer();
151
152 // Builds a path container which stores explicit paths and distances between
153 // path nodes in a memory-compact representation.
154 // In this case `GetPenultimateNodeInPath()` is `O(log(path_tree_size))`,
155 // `path_tree_size` being the size of a tree of paths from a source node (in
156 // practice it is equal to the number of nodes in the graph if all nodes
157 // are strongly connected).
158 // `GetPath` is `O(log(path_tree_size) + path_size)`, where `path_size` is the
159 // size of the resulting path; note this is faster than successive calls
160 // to `GetPenultimateNodeInPath()` which would result in
161 // `O(log(path_tree_size) * path_size)`.
162 static GenericPathContainer BuildInMemoryCompactPathContainer();
163
164 // TODO(user): Add save-to-disk container.
165 // TODO(user): Add `BuildInMemoryFastPathContainer()`, which does
166 // `GetPenultimateNodeInPath()` in `O(1)`.
167
168 // For internal use only. Returns the internal container implementation.
169 Impl* GetImplementation() const { return container_.get(); }
170
171 private:
172 explicit GenericPathContainer(std::unique_ptr<Impl> impl)
173 : container_(std::move(impl)) {}
174
175 std::unique_ptr<Impl> container_;
176};
177
178// Utility function which returns a vector containing all nodes of a graph.
179template <class GraphType>
180void GetGraphNodes(const GraphType& graph,
181 std::vector<typename GraphType::NodeIndex>* nodes) {
182 CHECK(nodes != nullptr);
183 nodes->clear();
184 nodes->reserve(graph.num_nodes());
185 for (typename GraphType::NodeIterator iterator(graph); iterator.Ok();
186 iterator.Next()) {
187 nodes->push_back(iterator.Index());
188 }
189}
190
191template <class GraphType>
192void GetGraphNodesFromGraph(const GraphType& graph,
193 std::vector<typename GraphType::NodeIndex>* nodes) {
194 CHECK(nodes != nullptr);
195 nodes->clear();
196 nodes->reserve(graph.num_nodes());
197 for (const typename GraphType::NodeIndex node : graph.AllNodes()) {
198 nodes->push_back(node);
199 }
200}
201
202// In all the functions below the arc_lengths vector represents the lengths of
203// the arcs of the graph (`arc_lengths[arc]` is the length of `arc`).
204// Resulting shortest paths are stored in a path container `path_container`.
205
206// Computes shortest paths from the node `source` to all nodes in the graph.
207template <class GraphType>
208void ComputeOneToAllShortestPaths(
209 const GraphType& graph, const std::vector<PathDistance>& arc_lengths,
210 typename GraphType::NodeIndex source,
211 GenericPathContainer<GraphType>* const path_container) {
212 std::vector<typename GraphType::NodeIndex> all_nodes;
213 GetGraphNodesFromGraph<GraphType>(graph, &all_nodes);
214 ComputeOneToManyShortestPaths(graph, arc_lengths, source, all_nodes,
215 path_container);
216}
217
218// Computes shortest paths from the node `source` to nodes in `destinations`.
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,
224 GenericPathContainer<GraphType>* const path_container) {
225 std::vector<typename GraphType::NodeIndex> sources(1, source);
227 graph, arc_lengths, sources, destinations, 1, path_container);
228}
229
230// Computes the shortest path from the node `source` to the node `destination`
231// and returns that path as a vector of nodes. If there is no path from `source`
232// to `destination`, the returned vector is empty.
233//
234// To get distance information, use `ComputeOneToManyShortestPaths` with a
235// single destination and a `PathContainer` built with
236// `BuildPathDistanceContainer` (if you just need the distance) or
237// `BuildInMemoryCompactPathContainer` (otherwise).
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);
245
246 auto path_container =
248
250 graph, arc_lengths, sources, destinations, 1, &path_container);
251
252 std::vector<typename GraphType::NodeIndex> path;
253 path_container.GetPath(source, destination, &path);
254 return path;
255}
256
257// Computes shortest paths from the nodes in `sources` to all nodes in the
258// graph.
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,
263 GenericPathContainer<GraphType>* const path_container) {
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);
268}
269
270// Computes shortest paths between all nodes of the graph.
271template <class GraphType>
272void ComputeAllToAllShortestPathsWithMultipleThreads(
273 const GraphType& graph, const std::vector<PathDistance>& arc_lengths,
274 int num_threads, GenericPathContainer<GraphType>* const path_container) {
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);
279}
280
281// =============================================================================
282// Implementation.
283// =============================================================================
284
285namespace internal {
286
287// Base path container implementation class. Defines virtual functions used to
288// fill the container (in particular from the shortest path computation
289// function).
290template <class NodeIndex, NodeIndex kNilNode>
291class PathContainerImpl {
292 public:
293 PathContainerImpl() = default;
294 virtual ~PathContainerImpl() = default;
295
296 // Initializes the container on source and destination node vectors
297 // (`num_nodes` is the total number of nodes in the graph containing source
298 // and destination nodes).
299 // Called before adding any paths to the container.
300 virtual void Initialize(const std::vector<NodeIndex>& sources,
301 const std::vector<NodeIndex>& destinations,
302 NodeIndex num_nodes) = 0;
303
304 // Called when no more path will be added to the container.
305 virtual void Finalize() {}
306
307 // Returns the distance between node `from` and node `to` following the path
308 // out of `from` and into `to`. Note that if `from` == `to`, the distance is
309 // not necessarily 0 if the path out of `to` and back into `to` has a distance
310 // greater than 0. If you do require the distance to be 0 in this case, add to
311 // the graph an arc from `to` to itself with a length of 0.
312 // If nodes are not connected, returns `kDisconnectedPathDistance`.
313 virtual PathDistance GetDistance(NodeIndex from, NodeIndex to) const = 0;
314
315 // Returns the penultimate node on the path out of node `from` into node `to`
316 // (the direct predecessor of node `to` on the path).
317 // If `from` == `to`, the penultimate node is `to` only if the shortest path
318 // from `to` to itself is composed of the arc (`to, `to`), which might not be
319 // the case if either this arc doesn't exist or if the length of this arc is
320 // greater than the distance of an alternate path.
321 // If nodes are not connected, returns `kNilNode`.
322 virtual NodeIndex GetPenultimateNodeInPath(NodeIndex from,
323 NodeIndex to) const = 0;
324
325 // Returns path nodes from node `from` to node `to` in a ordered vector.
326 virtual void GetPath(NodeIndex from, NodeIndex to,
327 std::vector<NodeIndex>* path) const = 0;
328
329 // Adds a path tree rooted at node `from`, and to a set of implicit
330 // destinations:
331 // - `predecessor_in_path_tree[node]` is the predecessor of node `node` in the
332 // path from `from` to `node`, or `kNilNode` if there is no
333 // predecessor (i.e. if `node` is not in the path tree);
334 // - `distance_to_destination[i]` is the distance from `from` to the i-th
335 // destination (see `Initialize()`).
336 virtual void StoreSingleSourcePaths(
337 NodeIndex from, const std::vector<NodeIndex>& predecessor_in_path_tree,
338 const std::vector<PathDistance>& distance_to_destination) = 0;
339};
340
341// Class designed to store the tree of paths from a root node to a set of nodes
342// in a very compact way (over performance).
343// Memory consumption is in `O(n)` (`n` being the size of the tree) where node
344// indices are "very" non-contiguous (extremely sparse node indices). It keeps
345// node-sorted arrays of node and parent pairs, which can be accessed in
346// `O(log(n))` with a binary search.
347// The creation of the tree is done in `O(n*log(n))` time.
348// Note that this class uses temporary memory for each call to `Initialize`
349// which is only an issue for massive parallel calls; in practice for shortest
350// paths computation, the number of threads calling `Initialize` is very small
351// compared to the total number of trees created.
352template <class NodeIndex, NodeIndex kNilNode>
353class PathTree {
354 public:
355 PathTree() : nodes_(), parents_() {}
356
357 void Initialize(absl::Span<const NodeIndex> paths,
358 absl::Span<const NodeIndex> destinations);
359
360 // Returns the parent (predecessor) of `node` in the tree in
361 // `O(log(path_tree_size))`, where `path_tree_size` is the size of `nodes_`.
362 NodeIndex GetParent(NodeIndex node) const;
363
364 // Returns the path from node `from` to node `to` in the tree in
365 // `O(log(path_tree_size) + path_size)`, where `path_tree_size` is the size of
366 // `nodes_` and `path_size` is the size of the resulting path.
367 void GetPath(NodeIndex from, NodeIndex to,
368 std::vector<NodeIndex>* path) const;
369
370 private:
371 std::vector<NodeIndex> nodes_;
372 std::vector<int> parents_;
373};
374
375// Initializes the tree from a non-sparse representation of the path tree
376// represented by `paths`. The tree is reduced to the subtree in which nodes in
377// `destinations` are the leafs.
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) {
387 NodeIndex destination = destinations[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];
393 }
394 }
395 }
396 std::sort(tree.begin(), tree.end());
397 const int num_nodes = tree.size();
398 {
399 absl::flat_hash_map<NodeIndex, int> node_indices;
400
401 for (int i = 0; i < num_nodes; ++i) {
402 node_indices[tree[i].first] = i;
403 }
404 parents_.resize(num_nodes, -1);
405 for (int i = 0; i < num_nodes; ++i) {
406 parents_[i] =
407 ::gtl::FindWithDefault(node_indices, tree[i].second, kNilNode);
408 }
409 }
410 nodes_.resize(num_nodes, kNilNode);
411 for (int i = 0; i < num_nodes; ++i) {
412 nodes_[i] = tree[i].first;
413 }
414}
415
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];
423 }
424 }
425 return kNilNode;
426}
427
428template <class NodeIndex, NodeIndex kNilNode>
430 NodeIndex from, NodeIndex to, std::vector<NodeIndex>* path) const {
431 DCHECK(path != nullptr);
432 path->clear();
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();
436 NodeIndex current_node = to;
437 while (current_node != from) {
438 path->push_back(current_node);
439 current_index = parents_[current_index];
440 // `from` and `to` are not connected.
441 if (current_index == kNilNode) {
442 path->clear();
443 return;
444 }
445 current_node = nodes_[current_index];
446 }
447 path->push_back(current_node);
448 std::reverse(path->begin(), path->end());
449 }
450}
451
452// Path container which only stores distances between path nodes.
453template <class NodeIndex, NodeIndex kNilNode>
454class DistanceContainer : public PathContainerImpl<NodeIndex, kNilNode> {
455 public:
456 DistanceContainer() : reverse_sources_(), distances_() {}
457
458 // This type is neither copyable nor movable.
459 DistanceContainer(const DistanceContainer&) = delete;
461 ~DistanceContainer() override = default;
462 void Initialize(const std::vector<NodeIndex>& sources,
463 const std::vector<NodeIndex>& destinations,
464 NodeIndex num_nodes) override {
465 ComputeReverse(sources, num_nodes, &reverse_sources_);
466 ComputeReverse(destinations, num_nodes, &reverse_destinations_);
467 distances_.clear();
468 distances_.resize(sources.size());
469 }
470 PathDistance GetDistance(NodeIndex from, NodeIndex to) const override {
471 return distances_[reverse_sources_[from]][reverse_destinations_[to]];
473 NodeIndex GetPenultimateNodeInPath(NodeIndex, NodeIndex) const override {
474 LOG(FATAL) << "Path not stored.";
475 return kNilNode;
476 }
477 void GetPath(NodeIndex, NodeIndex, std::vector<NodeIndex>*) const override {
478 LOG(FATAL) << "Path not stored.";
480 void StoreSingleSourcePaths(
481 NodeIndex from,
482 // `DistanceContainer` only stores distances and not predecessors.
483 const std::vector<NodeIndex>&,
484 const std::vector<PathDistance>& distance_to_destination) override {
485 distances_[reverse_sources_[from]] = distance_to_destination;
486 }
487
488 protected:
489 std::vector<int> reverse_sources_;
490 std::vector<int> reverse_destinations_;
492 private:
493 static void ComputeReverse(absl::Span<const NodeIndex> nodes,
494 NodeIndex num_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;
502 }
503 }
504
505 std::vector<std::vector<PathDistance>> distances_;
506};
507
508// Path container which stores explicit paths and distances between path nodes.
509template <class NodeIndex, NodeIndex kNilNode>
510class InMemoryCompactPathContainer
511 : public DistanceContainer<NodeIndex, kNilNode> {
512 public:
514
515 InMemoryCompactPathContainer() : trees_(), destinations_() {}
516
517 // This type is neither copyable nor movable.
520 delete;
521 ~InMemoryCompactPathContainer() override = default;
522 void Initialize(const std::vector<NodeIndex>& sources,
523 const std::vector<NodeIndex>& destinations,
524 NodeIndex num_nodes) override {
525 Base::Initialize(sources, destinations, num_nodes);
526 destinations_ = destinations;
527 trees_.clear();
528 trees_.resize(sources.size());
529 }
530 NodeIndex GetPenultimateNodeInPath(NodeIndex from,
531 NodeIndex to) const override {
532 return trees_[Base::reverse_sources_[from]].GetParent(to);
533 }
534 void GetPath(NodeIndex from, NodeIndex to,
535 std::vector<NodeIndex>* path) const override {
536 DCHECK(path != nullptr);
537 trees_[Base::reverse_sources_[from]].GetPath(from, to, path);
538 }
539 void StoreSingleSourcePaths(
540 NodeIndex from, const std::vector<NodeIndex>& predecessor_in_path_tree,
541 const std::vector<PathDistance>& distance_to_destination) override {
542 Base::StoreSingleSourcePaths(from, predecessor_in_path_tree,
543 distance_to_destination);
544 trees_[Base::reverse_sources_[from]].Initialize(predecessor_in_path_tree,
545 destinations_);
546 }
547
548 private:
549 std::vector<PathTree<NodeIndex, kNilNode>> trees_;
550 std::vector<NodeIndex> destinations_;
551};
552
553// Priority queue node entry in the boundary of the Dijkstra algorithm.
554template <class NodeIndex, NodeIndex kNilNode>
555class NodeEntry {
556 public:
558 : heap_index_(-1),
559 distance_(0),
560 node_(kNilNode),
561 settled_(false),
562 is_destination_(false) {}
563 bool operator<(const NodeEntry& other) const {
564 return distance_ > other.distance_;
566 void SetHeapIndex(int h) {
567 DCHECK_GE(h, 0);
568 heap_index_ = h;
569 }
570 int GetHeapIndex() const { return heap_index_; }
571 void set_distance(PathDistance distance) { distance_ = distance; }
572 PathDistance distance() const { return distance_; }
573 void set_node(NodeIndex node) { node_ = node; }
574 NodeIndex node() const { return node_; }
575 void set_settled(bool settled) { settled_ = settled; }
576 bool settled() const { return settled_; }
578 is_destination_ = is_destination;
580 bool is_destination() const { return is_destination_; }
581
582 private:
583 int heap_index_;
584 PathDistance distance_;
585 NodeIndex node_;
586 bool settled_;
587 bool is_destination_;
588};
589
590// Updates an entry with the given distance if it's shorter, and then inserts it
591// in the priority queue (or updates it if it's there already), if needed.
592// Returns true if the entry was modified, false otherwise.
593template <class NodeIndex, NodeIndex kNilNode>
597 // If one wants to use int64_t for either priority or NodeIndex, one should
598 // consider using packed ints (putting the two bools with heap_index, for
599 // example) in order to stay at 16 bytes instead of 24.
600 static_assert(sizeof(NodeEntry<NodeIndex, kNilNode>) == 16,
601 "node_entry_class_is_not_well_packed");
602
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);
608 return true;
609 } else if (distance < entry->distance()) {
610 entry->set_distance(distance);
611 priority_queue->NoteChangedPriority(entry);
612 return true;
613 }
614 return false;
615}
616
617// Computes shortest paths from node `source` to nodes in `destinations`
618// using a binary heap-based Dijkstra algorithm.
619// TODO(user): Investigate alternate implementation which wouldn't use
620// AdjustablePriorityQueue.
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,
627 typename GenericPathContainer<GraphType>::Impl* const paths) {
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);
641 }
642 // Marking destination node. This is an optimization stopping the search
643 // when all destinations have been reached.
644 for (int i = 0; i < destinations->size(); ++i) {
645 entries[(*destinations)[i]].set_is_destination(true);
646 }
647 // In this implementation the distance of a node to itself isn't necessarily
648 // 0.
649 // So we push successors of source in the queue instead of the source
650 // directly which will avoid marking the source.
651 for (const ArcIndex arc : graph->OutgoingArcs(source)) {
652 const NodeIndex next = graph->Head(arc);
653 if (InsertOrUpdateEntry(arc_lengths->at(arc), &entries[next],
654 &priority_queue)) {
655 predecessor[next] = source;
656 }
657 }
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) {
667 break;
668 }
669 }
670 const PathDistance current_distance = current->distance();
671 for (const ArcIndex arc : graph->OutgoingArcs(current_node)) {
672 const NodeIndex next = graph->Head(arc);
673 NodeEntryT* const entry = &entries[next];
674 if (!entry->settled()) {
675 DCHECK_GE(current_distance, 0);
676 const PathDistance arc_length = arc_lengths->at(arc);
677 DCHECK_LE(current_distance, kDisconnectedPathDistance - arc_length);
678 if (InsertOrUpdateEntry(current_distance + arc_length, entry,
679 &priority_queue)) {
680 predecessor[next] = current_node;
681 }
682 }
683 }
684 }
685 const int destinations_size = destinations->size();
686 std::vector<PathDistance> distances(destinations_size,
688 for (int i = 0; i < destinations_size; ++i) {
689 NodeIndex node = destinations->at(i);
690 if (entries[node].settled()) {
691 distances[i] = entries[node].distance();
692 }
693 }
694 paths->StoreSingleSourcePaths(source, predecessor, distances);
695}
696
697} // namespace internal
698
699template <class GraphType>
701
702template <class GraphType>
704 NodeIndex to) const {
705 DCHECK(container_ != nullptr);
706 return container_->GetDistance(from, to);
707}
708
709template <class GraphType>
712 NodeIndex to) const {
713 DCHECK(container_ != nullptr);
714 return container_->GetPenultimateNodeInPath(from, to);
715}
716
717template <class GraphType>
719 NodeIndex from, NodeIndex to, std::vector<NodeIndex>* path) const {
720 DCHECK(container_ != nullptr);
721 DCHECK(path != nullptr);
722 container_->GetPath(from, to, path);
723}
724
725template <class GraphType>
729 std::make_unique<
730 internal::DistanceContainer<NodeIndex, GraphType::kNilNode>>());
731}
732
733template <class GraphType>
734GenericPathContainer<GraphType>
735GenericPathContainer<GraphType>::BuildInMemoryCompactPathContainer() {
736 return GenericPathContainer(
737 std::make_unique<internal::InMemoryCompactPathContainer<
738 NodeIndex, GraphType::kNilNode>>());
739}
740
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";
750 // Removing duplicate sources to allow mutex-free implementation (and it's
751 // more efficient); same with destinations for efficiency reasons.
752 std::vector<typename GraphType::NodeIndex> unique_sources = sources;
753 ::gtl::STLSortAndRemoveDuplicates(&unique_sources);
754 std::vector<typename GraphType::NodeIndex> unique_destinations =
755 destinations;
756 ::gtl::STLSortAndRemoveDuplicates(&unique_destinations);
757 WallTimer timer;
758 timer.Start();
759 auto* const container = paths->GetImplementation();
760 container->Initialize(unique_sources, unique_destinations,
761 graph.num_nodes());
762 {
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));
769 }
770 }
771 container->Finalize();
772 VLOG(2) << "Elapsed time to compute shortest paths: " << timer.Get() << "s";
773 }
774}
775
776} // namespace operations_research
777
778#endif // OR_TOOLS_GRAPH_SHORTEST_PATHS_H_
void Pop()
If there are ties for the top, this returns all of them.
double Get() const
Definition timer.h:44
void Start()
When Start() is called multiple times, only the most recent is used.
Definition timer.h:30
DistanceContainer & operator=(const DistanceContainer &)=delete
void StoreSingleSourcePaths(NodeIndex from, const std::vector< NodeIndex > &, const std::vector< PathDistance > &distance_to_destination) override
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
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.
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)
Definition stl_util.h:55
const MapUtilMappedT< Collection > & FindWithDefault(const Collection &collection, const KeyType &key, const MapUtilMappedT< Collection > &value)
Definition map_util.h:36
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)
STL namespace.
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)