Google OR-Tools v9.12
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`.
219// TODO(b/385094969): Remove second template parameter when all clients are
220// migrated.
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,
226 GenericPathContainer<GraphType>* const path_container) {
227 std::vector<typename GraphType::NodeIndex> sources(1, source);
229 graph, arc_lengths, sources, destinations, 1, path_container);
230}
231
232// Computes the shortest path from the node `source` to the node `destination`
233// and returns that path as a vector of nodes. If there is no path from `source`
234// to `destination`, the returned vector is empty.
235//
236// To get distance information, use `ComputeOneToManyShortestPaths` with a
237// single destination and a `PathContainer` built with
238// `BuildPathDistanceContainer` (if you just need the distance) or
239// `BuildInMemoryCompactPathContainer` (otherwise).
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);
247
248 auto path_container =
250
252 graph, arc_lengths, sources, destinations, 1, &path_container);
253
254 std::vector<typename GraphType::NodeIndex> path;
255 path_container.GetPath(source, destination, &path);
256 return path;
257}
258
259// Computes shortest paths from the nodes in `sources` to all nodes in the
260// graph.
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,
265 GenericPathContainer<GraphType>* const path_container) {
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);
270}
271
272// Computes shortest paths between all nodes of the graph.
273template <class GraphType>
274void ComputeAllToAllShortestPathsWithMultipleThreads(
275 const GraphType& graph, const std::vector<PathDistance>& arc_lengths,
276 int num_threads, GenericPathContainer<GraphType>* const path_container) {
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);
281}
282
283// =============================================================================
284// Implementation.
285// =============================================================================
286
287namespace internal {
288
289// Base path container implementation class. Defines virtual functions used to
290// fill the container (in particular from the shortest path computation
291// function).
292template <class NodeIndex, NodeIndex kNilNode>
293class PathContainerImpl {
294 public:
295 PathContainerImpl() = default;
296 virtual ~PathContainerImpl() = default;
297
298 // Initializes the container on source and destination node vectors
299 // (`num_nodes` is the total number of nodes in the graph containing source
300 // and destination nodes).
301 // Called before adding any paths to the container.
302 virtual void Initialize(const std::vector<NodeIndex>& sources,
303 const std::vector<NodeIndex>& destinations,
304 NodeIndex num_nodes) = 0;
305
306 // Called when no more path will be added to the container.
307 virtual void Finalize() {}
308
309 // Returns the distance between node `from` and node `to` following the path
310 // out of `from` and into `to`. Note that if `from` == `to`, the distance is
311 // not necessarily 0 if the path out of `to` and back into `to` has a distance
312 // greater than 0. If you do require the distance to be 0 in this case, add to
313 // the graph an arc from `to` to itself with a length of 0.
314 // If nodes are not connected, returns `kDisconnectedPathDistance`.
315 virtual PathDistance GetDistance(NodeIndex from, NodeIndex to) const = 0;
316
317 // Returns the penultimate node on the path out of node `from` into node `to`
318 // (the direct predecessor of node `to` on the path).
319 // If `from` == `to`, the penultimate node is `to` only if the shortest path
320 // from `to` to itself is composed of the arc (`to, `to`), which might not be
321 // the case if either this arc doesn't exist or if the length of this arc is
322 // greater than the distance of an alternate path.
323 // If nodes are not connected, returns `kNilNode`.
324 virtual NodeIndex GetPenultimateNodeInPath(NodeIndex from,
325 NodeIndex to) const = 0;
326
327 // Returns path nodes from node `from` to node `to` in a ordered vector.
328 virtual void GetPath(NodeIndex from, NodeIndex to,
329 std::vector<NodeIndex>* path) const = 0;
330
331 // Adds a path tree rooted at node `from`, and to a set of implicit
332 // destinations:
333 // - `predecessor_in_path_tree[node]` is the predecessor of node `node` in the
334 // path from `from` to `node`, or `kNilNode` if there is no
335 // predecessor (i.e. if `node` is not in the path tree);
336 // - `distance_to_destination[i]` is the distance from `from` to the i-th
337 // destination (see `Initialize()`).
338 virtual void StoreSingleSourcePaths(
339 NodeIndex from, const std::vector<NodeIndex>& predecessor_in_path_tree,
340 const std::vector<PathDistance>& distance_to_destination) = 0;
341};
342
343// Class designed to store the tree of paths from a root node to a set of nodes
344// in a very compact way (over performance).
345// Memory consumption is in `O(n)` (`n` being the size of the tree) where node
346// indices are "very" non-contiguous (extremely sparse node indices). It keeps
347// node-sorted arrays of node and parent pairs, which can be accessed in
348// `O(log(n))` with a binary search.
349// The creation of the tree is done in `O(n*log(n))` time.
350// Note that this class uses temporary memory for each call to `Initialize`
351// which is only an issue for massive parallel calls; in practice for shortest
352// paths computation, the number of threads calling `Initialize` is very small
353// compared to the total number of trees created.
354template <class NodeIndex, NodeIndex kNilNode>
355class PathTree {
356 public:
357 PathTree() : nodes_(), parents_() {}
358
359 void Initialize(absl::Span<const NodeIndex> paths,
360 absl::Span<const NodeIndex> destinations);
361
362 // Returns the parent (predecessor) of `node` in the tree in
363 // `O(log(path_tree_size))`, where `path_tree_size` is the size of `nodes_`.
364 NodeIndex GetParent(NodeIndex node) const;
365
366 // Returns the path from node `from` to node `to` in the tree in
367 // `O(log(path_tree_size) + path_size)`, where `path_tree_size` is the size of
368 // `nodes_` and `path_size` is the size of the resulting path.
369 void GetPath(NodeIndex from, NodeIndex to,
370 std::vector<NodeIndex>* path) const;
371
372 private:
373 std::vector<NodeIndex> nodes_;
374 std::vector<int> parents_;
375};
376
377// Initializes the tree from a non-sparse representation of the path tree
378// represented by `paths`. The tree is reduced to the subtree in which nodes in
379// `destinations` are the leafs.
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) {
389 NodeIndex destination = destinations[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];
395 }
396 }
397 }
398 std::sort(tree.begin(), tree.end());
399 const int num_nodes = tree.size();
400 {
401 absl::flat_hash_map<NodeIndex, int> node_indices;
402
403 for (int i = 0; i < num_nodes; ++i) {
404 node_indices[tree[i].first] = i;
405 }
406 parents_.resize(num_nodes, -1);
407 for (int i = 0; i < num_nodes; ++i) {
408 parents_[i] =
409 ::gtl::FindWithDefault(node_indices, tree[i].second, kNilNode);
410 }
411 }
412 nodes_.resize(num_nodes, kNilNode);
413 for (int i = 0; i < num_nodes; ++i) {
414 nodes_[i] = tree[i].first;
415 }
416}
417
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];
425 }
426 }
427 return kNilNode;
428}
429
430template <class NodeIndex, NodeIndex kNilNode>
432 NodeIndex from, NodeIndex to, std::vector<NodeIndex>* path) const {
433 DCHECK(path != nullptr);
434 path->clear();
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();
438 NodeIndex current_node = to;
439 while (current_node != from) {
440 path->push_back(current_node);
441 current_index = parents_[current_index];
442 // `from` and `to` are not connected.
443 if (current_index == kNilNode) {
444 path->clear();
445 return;
446 }
447 current_node = nodes_[current_index];
448 }
449 path->push_back(current_node);
450 std::reverse(path->begin(), path->end());
451 }
452}
453
454// Path container which only stores distances between path nodes.
455template <class NodeIndex, NodeIndex kNilNode>
456class DistanceContainer : public PathContainerImpl<NodeIndex, kNilNode> {
457 public:
458 DistanceContainer() : reverse_sources_(), distances_() {}
459
460 // This type is neither copyable nor movable.
461 DistanceContainer(const DistanceContainer&) = delete;
463 ~DistanceContainer() override = default;
464 void Initialize(const std::vector<NodeIndex>& sources,
465 const std::vector<NodeIndex>& destinations,
466 NodeIndex num_nodes) override {
467 ComputeReverse(sources, num_nodes, &reverse_sources_);
468 ComputeReverse(destinations, num_nodes, &reverse_destinations_);
469 distances_.clear();
470 distances_.resize(sources.size());
471 }
472 PathDistance GetDistance(NodeIndex from, NodeIndex to) const override {
473 return distances_[reverse_sources_[from]][reverse_destinations_[to]];
475 NodeIndex GetPenultimateNodeInPath(NodeIndex, NodeIndex) const override {
476 LOG(FATAL) << "Path not stored.";
477 return kNilNode;
478 }
479 void GetPath(NodeIndex, NodeIndex, std::vector<NodeIndex>*) const override {
480 LOG(FATAL) << "Path not stored.";
482 void StoreSingleSourcePaths(
483 NodeIndex from,
484 // `DistanceContainer` only stores distances and not predecessors.
485 const std::vector<NodeIndex>&,
486 const std::vector<PathDistance>& distance_to_destination) override {
487 distances_[reverse_sources_[from]] = distance_to_destination;
488 }
489
490 protected:
491 std::vector<int> reverse_sources_;
492 std::vector<int> reverse_destinations_;
494 private:
495 static void ComputeReverse(absl::Span<const NodeIndex> nodes,
496 NodeIndex num_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;
504 }
505 }
506
507 std::vector<std::vector<PathDistance>> distances_;
508};
509
510// Path container which stores explicit paths and distances between path nodes.
511template <class NodeIndex, NodeIndex kNilNode>
512class InMemoryCompactPathContainer
513 : public DistanceContainer<NodeIndex, kNilNode> {
514 public:
516
517 InMemoryCompactPathContainer() : trees_(), destinations_() {}
518
519 // This type is neither copyable nor movable.
522 delete;
523 ~InMemoryCompactPathContainer() override = default;
524 void Initialize(const std::vector<NodeIndex>& sources,
525 const std::vector<NodeIndex>& destinations,
526 NodeIndex num_nodes) override {
527 Base::Initialize(sources, destinations, num_nodes);
528 destinations_ = destinations;
529 trees_.clear();
530 trees_.resize(sources.size());
531 }
532 NodeIndex GetPenultimateNodeInPath(NodeIndex from,
533 NodeIndex to) const override {
534 return trees_[Base::reverse_sources_[from]].GetParent(to);
535 }
536 void GetPath(NodeIndex from, NodeIndex to,
537 std::vector<NodeIndex>* path) const override {
538 DCHECK(path != nullptr);
539 trees_[Base::reverse_sources_[from]].GetPath(from, to, path);
540 }
541 void StoreSingleSourcePaths(
542 NodeIndex from, const std::vector<NodeIndex>& predecessor_in_path_tree,
543 const std::vector<PathDistance>& distance_to_destination) override {
544 Base::StoreSingleSourcePaths(from, predecessor_in_path_tree,
545 distance_to_destination);
546 trees_[Base::reverse_sources_[from]].Initialize(predecessor_in_path_tree,
547 destinations_);
548 }
549
550 private:
551 std::vector<PathTree<NodeIndex, kNilNode>> trees_;
552 std::vector<NodeIndex> destinations_;
553};
554
555// Priority queue node entry in the boundary of the Dijkstra algorithm.
556template <class NodeIndex, NodeIndex kNilNode>
557class NodeEntry {
558 public:
560 : heap_index_(-1),
561 distance_(0),
562 node_(kNilNode),
563 settled_(false),
564 is_destination_(false) {}
565 bool operator<(const NodeEntry& other) const {
566 return distance_ > other.distance_;
568 void SetHeapIndex(int h) {
569 DCHECK_GE(h, 0);
570 heap_index_ = h;
571 }
572 int GetHeapIndex() const { return heap_index_; }
573 void set_distance(PathDistance distance) { distance_ = distance; }
574 PathDistance distance() const { return distance_; }
575 void set_node(NodeIndex node) { node_ = node; }
576 NodeIndex node() const { return node_; }
577 void set_settled(bool settled) { settled_ = settled; }
578 bool settled() const { return settled_; }
580 is_destination_ = is_destination;
582 bool is_destination() const { return is_destination_; }
583
584 private:
585 int heap_index_;
586 PathDistance distance_;
587 NodeIndex node_;
588 bool settled_;
589 bool is_destination_;
590};
591
592// Updates an entry with the given distance if it's shorter, and then inserts it
593// in the priority queue (or updates it if it's there already), if needed.
594// Returns true if the entry was modified, false otherwise.
595template <class NodeIndex, NodeIndex kNilNode>
599 // If one wants to use int64_t for either priority or NodeIndex, one should
600 // consider using packed ints (putting the two bools with heap_index, for
601 // example) in order to stay at 16 bytes instead of 24.
602 static_assert(sizeof(NodeEntry<NodeIndex, kNilNode>) == 16,
603 "node_entry_class_is_not_well_packed");
604
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);
610 return true;
611 } else if (distance < entry->distance()) {
612 entry->set_distance(distance);
613 priority_queue->NoteChangedPriority(entry);
614 return true;
615 }
616 return false;
617}
618
619// Computes shortest paths from node `source` to nodes in `destinations`
620// using a binary heap-based Dijkstra algorithm.
621// TODO(user): Investigate alternate implementation which wouldn't use
622// AdjustablePriorityQueue.
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,
629 typename GenericPathContainer<GraphType>::Impl* const paths) {
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);
643 }
644 // Marking destination node. This is an optimization stopping the search
645 // when all destinations have been reached.
646 for (int i = 0; i < destinations->size(); ++i) {
647 entries[(*destinations)[i]].set_is_destination(true);
648 }
649 // In this implementation the distance of a node to itself isn't necessarily
650 // 0.
651 // So we push successors of source in the queue instead of the source
652 // directly which will avoid marking the source.
653 for (const ArcIndex arc : graph->OutgoingArcs(source)) {
654 const NodeIndex next = graph->Head(arc);
655 if (InsertOrUpdateEntry(arc_lengths->at(arc), &entries[next],
656 &priority_queue)) {
657 predecessor[next] = source;
658 }
659 }
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) {
669 break;
670 }
671 }
672 const PathDistance current_distance = current->distance();
673 for (const ArcIndex arc : graph->OutgoingArcs(current_node)) {
674 const NodeIndex next = graph->Head(arc);
675 NodeEntryT* const entry = &entries[next];
676 if (!entry->settled()) {
677 DCHECK_GE(current_distance, 0);
678 const PathDistance arc_length = arc_lengths->at(arc);
679 DCHECK_LE(current_distance, kDisconnectedPathDistance - arc_length);
680 if (InsertOrUpdateEntry(current_distance + arc_length, entry,
681 &priority_queue)) {
682 predecessor[next] = current_node;
683 }
684 }
685 }
686 }
687 const int destinations_size = destinations->size();
688 std::vector<PathDistance> distances(destinations_size,
690 for (int i = 0; i < destinations_size; ++i) {
691 NodeIndex node = destinations->at(i);
692 if (entries[node].settled()) {
693 distances[i] = entries[node].distance();
694 }
695 }
696 paths->StoreSingleSourcePaths(source, predecessor, distances);
697}
698
699} // namespace internal
700
701template <class GraphType>
703
704template <class GraphType>
706 NodeIndex to) const {
707 DCHECK(container_ != nullptr);
708 return container_->GetDistance(from, to);
709}
710
711template <class GraphType>
714 NodeIndex to) const {
715 DCHECK(container_ != nullptr);
716 return container_->GetPenultimateNodeInPath(from, to);
717}
718
719template <class GraphType>
721 NodeIndex from, NodeIndex to, std::vector<NodeIndex>* path) const {
722 DCHECK(container_ != nullptr);
723 DCHECK(path != nullptr);
724 container_->GetPath(from, to, path);
725}
726
727template <class GraphType>
731 std::make_unique<
732 internal::DistanceContainer<NodeIndex, GraphType::kNilNode>>());
733}
734
735template <class GraphType>
736GenericPathContainer<GraphType>
737GenericPathContainer<GraphType>::BuildInMemoryCompactPathContainer() {
738 return GenericPathContainer(
739 std::make_unique<internal::InMemoryCompactPathContainer<
740 NodeIndex, GraphType::kNilNode>>());
741}
742
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";
752 // Removing duplicate sources to allow mutex-free implementation (and it's
753 // more efficient); same with destinations for efficiency reasons.
754 std::vector<typename GraphType::NodeIndex> unique_sources = sources;
755 ::gtl::STLSortAndRemoveDuplicates(&unique_sources);
756 std::vector<typename GraphType::NodeIndex> unique_destinations =
757 destinations;
758 ::gtl::STLSortAndRemoveDuplicates(&unique_destinations);
759 WallTimer timer;
760 timer.Start();
761 auto* const container = paths->GetImplementation();
762 container->Initialize(unique_sources, unique_destinations,
763 graph.num_nodes());
764 {
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));
771 }
772 }
773 container->Finalize();
774 VLOG(2) << "Elapsed time to compute shortest paths: " << timer.Get() << "s";
775 }
776}
777
778} // namespace operations_research
779
780#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:46
void Start()
When Start() is called multiple times, only the most recent is used.
Definition timer.h:32
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:58
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
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)