Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
bounded_dijkstra.h
Go to the documentation of this file.
1// Copyright 2010-2024 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#ifndef OR_TOOLS_GRAPH_BOUNDED_DIJKSTRA_H_
15#define OR_TOOLS_GRAPH_BOUNDED_DIJKSTRA_H_
16
17#include <algorithm>
18#include <functional>
19#include <limits>
20#include <utility>
21#include <vector>
22
23#include "absl/algorithm/container.h"
24#include "absl/base/attributes.h"
25#include "absl/log/check.h"
26#include "absl/types/span.h"
28#include "ortools/base/top_n.h"
29#include "ortools/graph/graph.h"
30
31namespace operations_research {
32
33// Computes a shortest path from source to destination in a weighted directed
34// graph, specified as an arc list.
35//
36// This function also demonstrates how to use the more feature rich
37// BoundedDijkstraWrapper (defined below) in the simple case, see the
38// implementation at the bottom of this file.
39//
40// We take a sparse directed input graph with nodes indexed in [0, num_nodes).
41// Each arcs goes from a tail node to a head node (tail -> head) and must have a
42// NON-NEGATIVE length. Self-arc or duplicate arcs are supported. This is
43// provided as 3 parallel vectors of the same size. Note that we validate the
44// input consistency with checks.
45//
46// If your graph is undirected, you can easily transform it by adding two arcs
47// (a -> b and b -> a) for each edge (a <-> b).
48//
49// This returns a pair (path length, node-path from source to destination)
50// corresponding to a shortest path. Both source and destination will be
51// included in the path.
52//
53// If destination is not reachable from source, or if the shortest path length
54// is >= limit we will return {limit, {}}. As a consequence any arc length >=
55// limit is the same as no arc. The code is also overflow-safe and will behave
56// correctly if the limit is int64max or infinity.
57template <typename DistanceType>
58std::pair<DistanceType, std::vector<int>> SimpleOneToOneShortestPath(
59 int source, int destination, absl::Span<const int> tails,
60 absl::Span<const int> heads, absl::Span<const DistanceType> lengths,
61 DistanceType limit = std::numeric_limits<DistanceType>::max());
62
63template <class T>
65 public:
66 explicit ElementGetter(const std::vector<T>& c) : c_(c) {}
67 const T& operator()(int index) const { return c_[index]; }
68
69 private:
70 const std::vector<T>& c_;
71};
72
73// A wrapper that holds the memory needed to run many bounded shortest path
74// computations on the given graph. The graph must implement the
75// interface described in graph.h (without the need for reverse arcs).
76//
77// We use the length and distance formalism here, but the arc lengths can
78// represent any numeric physical quantity. A shortest path will just be a path
79// minimizing this quantity. Arc length MUST be non-negative though. The code
80// should work with both signed and unsigned integer, or floating point
81// DistanceType.
82//
83// If one do not use source/destination distance offset, this class is
84// integer-overflow safe, and one can safely use distance_limit =
85// std::numeric_limits<int64_t>::max() for instance. Any arcs with a distance >=
86// distance_limit will then be the same as a non-existent arc.
87//
88// With source/destination offsets, the potential integer overflow situation is
89// trickier: one need to make sure that the range (distance_limit -
90// source_offset) do not overflow in case of negative source_offset. And also
91// that (distance_limit + destination_offset) do not overflow. Note that with
92// negative source_offset, arc with a length greater than the distance_limit can
93// still be considered!
94template <class GraphType, class DistanceType,
95 class ArcLengthFunctor = ElementGetter<DistanceType>>
97 public:
98 typedef typename GraphType::NodeIndex node_type;
99 typedef DistanceType distance_type;
100
101 // IMPORTANT: Both arguments must outlive the class. The arc lengths cannot be
102 // negative and the vector must be of the correct size (both preconditions are
103 // CHECKed).
104 //
105 // SUBTLE: The client can modify the graph and the arc length between calls to
106 // RunBoundedDijkstra(). That's fine. Doing so will obviously invalidate the
107 // reader API of the last Dijkstra run, which could return junk, or crash.
108 BoundedDijkstraWrapper(const GraphType* graph,
109 const std::vector<DistanceType>* arc_lengths);
110
111 // Variant that takes a custom arc length functor and copies it locally.
112 BoundedDijkstraWrapper(const GraphType* graph,
113 ArcLengthFunctor arc_length_functor);
114
115 // The typical Dijkstra, from a single source with distance zero, to all nodes
116 // of the graph within the distance limit (exclusive). The first element of
117 // the returned vector will always be the source_node with a distance of zero.
118 // See RunBoundedDijkstraFromMultipleSources() for more information.
119 const std::vector<int>& RunBoundedDijkstra(int source_node,
120 DistanceType distance_limit) {
121 return RunBoundedDijkstraFromMultipleSources({{source_node, 0}},
122 distance_limit);
123 }
124
125 // Finds the shortest path between two nodes, subject to the distance limit.
126 // Returns true iff it exists and its length is < distance_limit.
127 //
128 // If this returns true, you can get the path distance with distances()[to]
129 // and the path with ArcPathTo(to) or NodePathTo(to).
130 bool OneToOneShortestPath(int from, int to, DistanceType distance_limit);
131
132 // Returns the list of all the nodes which are under the given distance limit
133 // (exclusive) from at least one of the given source nodes (which also have
134 // an initial distance offset, to be added to the distance).
135 // The nodes are sorted by increasing distance.
136 // By "distance", we mean the length of the shortest path from any source
137 // plus the source's distance offset, where the length of a path is the
138 // sum of the length of its arcs
139 const std::vector<int>& RunBoundedDijkstraFromMultipleSources(
140 const std::vector<std::pair<int, DistanceType>>&
141 sources_with_distance_offsets,
142 DistanceType distance_limit);
143
144 // Like RunBoundedDijkstraFromMultipleSources(), but this one stops as soon as
145 // it has determined the shortest path from any of the sources to the closest
146 // "num_destinations_to_reach" destinations, and returns those destinations,
147 // sorted by overall distance (also counting the destination offsets).
148 //
149 // If num_destinations_to_reach is non-positive, returns the empty vector, if
150 // it is greater than the number of distinct destination nodes, it has no
151 // effect (it's safe to do so).
152 //
153 // If the limit is reached before, the returned vector may have smaller size,
154 // in particular it may be empty if none of the destinations was reachable.
155 //
156 // Both the sources and the destinations have a "distance offset", which is
157 // added to the path length to determine the distance between them.
158 //
159 // The rest of the reader API below is available; with the caveat that you
160 // should only try to access the nodes that have been reached by the search.
161 // That's true for the returned node index (if not -1) and its ancestors.
162 //
163 // Note that the distances() will take the source offsets into account,
164 // but not the destination offsets.
166 const std::vector<std::pair<int, DistanceType>>&
167 sources_with_distance_offsets,
168 const std::vector<std::pair<int, DistanceType>>&
169 destinations_with_distance_offsets,
170 int num_destinations_to_reach, DistanceType distance_limit);
171
172 // Like RunBoundedDijkstraFromMultipleSources(), but will call a user-provided
173 // callback "settled_node_callback" when settling each node ('settling' a node
174 // happens at most once per node, when popping it from the Dijkstra queue,
175 // meaning that the node has been fully 'processed'). This callback may modify
176 // the distance limit dynamically, thus affecting the stopping criterion.
177 const std::vector<int>& RunBoundedDijkstraWithSettledNodeCallback(
178 const std::vector<std::pair<int, DistanceType>>&
179 sources_with_distance_offsets,
180 std::function<void(node_type settled_node, DistanceType settled_distance,
181 DistanceType* distance_limit)>
182 settled_node_callback,
183 DistanceType distance_limit);
184
185 // Returns true if `node` was reached by the last Run*() call.
186 bool IsReachable(int node) const { return is_reached_[node]; }
187
188 // Returns all the reached nodes form the previous Run*() call.
189 const std::vector<int>& reached_nodes() const { return reached_nodes_; }
190
191 // The following vectors are all indexed by graph node indices.
192 //
193 // IMPORTANT: after each Run*() function, only the positions of the
194 // reached nodes are updated, the others will contain junk.
195
196 // The distance of the nodes from their source.
197 const std::vector<DistanceType>& distances() const { return distances_; }
198
199 // The parent of the nodes in the shortest path from their source.
200 // When a node doesn't have any parent (it has to be a source), its parent
201 // is itself.
202 // Note that a path will never contain the same node twice, even if some
203 // arcs have a length of zero.
204 // Note also that some sources may have parents, because of the initial
205 // distances.
206 const std::vector<int>& parents() const { return parents_; }
207
208 // The arc reaching a given node in the path from their source.
209 // arc_from_source()[x] is undefined (i.e. junk) when parents()[x] == x.
210 const std::vector<int>& arc_from_source() const { return arc_from_source_; }
211
212 // Returns the list of all the arcs in the shortest path from the node's
213 // source to the node.
214 std::vector<int> ArcPathTo(int node) const;
215
216 ABSL_DEPRECATED("Use ArcPathTo() instead.")
217 std::vector<int> ArcPathToNode(int node) const { return ArcPathTo(node); }
218
219 // Returns the list of all the nodes in the shortest path from the node's
220 // source to the node. This always start by the node's source, and end by
221 // the given node. In the case that source == node, returns {node}.
222 std::vector<int> NodePathTo(int node) const;
223
224 // Returns the node's source. This is especially useful when running
225 // Dijkstras from multiple sources.
226 int SourceOfShortestPathToNode(int node) const;
227
228 // Original Source/Destination index extraction, after a call to the
229 // multi-source and/or multi-destination variants:
230 // Retrieves the original index of the source or destination node in the
231 // source/destination lists given in the method calls. Eg. if you called
232 // RunBoundedDijkstraFromMultipleSourcesToMultipleDestinations(srcs, dsts),
233 // then srcs[GetSourceIndex(node)] = (node, ...), for all "node" that appear
234 // in "srcs". Ditto for dsts and GetDestinationIndex().
235 //
236 // If the node was listed several times as a source (or destinations), it'll
237 // pick the listing with the smallest distance offset.
238 // If the node is not a source (or destination), this returns junk: you can't
239 // rely on the value.
240 //
241 // These methods are invalidated by the next RunBoundedDijkstra*() call.
242 int GetSourceIndex(int node) const;
243 int GetDestinationIndex(int node) const;
244
245 // Trivial accessors to the underlying graph and arc lengths.
246 const GraphType& graph() const { return *graph_; }
247 const std::vector<DistanceType>& arc_lengths() const {
248 CHECK(arc_lengths_);
249 return *arc_lengths_;
250 }
251 DistanceType GetArcLength(int arc) const {
252 const DistanceType length = arc_length_functor_(arc);
253 DCHECK_GE(length, 0);
254 return length;
255 }
256
257 private:
258 // The default copy constructor is problematic in a multi-threaded
259 // environment.
261
262 // The Graph and length of each arc.
263 const GraphType* const graph_;
264 ArcLengthFunctor arc_length_functor_;
265 const std::vector<DistanceType>* const arc_lengths_;
266
267 // Data about the last Dijkstra run.
268 std::vector<DistanceType> distances_;
269 std::vector<int> parents_;
270 std::vector<int> arc_from_source_;
271 std::vector<bool> is_reached_;
272 std::vector<int> reached_nodes_;
273
274 // Priority queue of nodes, ordered by their distance to the source.
275 struct NodeDistance {
276 node_type node; // The target node.
277 DistanceType distance; // Its distance from the source.
278
279 bool operator<(const NodeDistance& other) const {
280 // PERFORMANCE(user): Here are some versions of the comparison operator:
281 // 0) distance != other.distance ? distance < other.distance
282 // : node < other.node
283 // 1) Same, with ABSL_PREDICT_TRUE() around the first test.
284 // 2) std::tie(distance, node) < std::tie(other.distance, other.node)
285 // 3) __int128 comparison with *reinterpret_cast<const __int128*>(this).
286 // (note: this only works when the node and distance types are integer
287 // or ieee754 floating-point, when the machine is little endian, and
288 // when the total size of NodeDistance equals 16 bytes).
289 // And here are the speeds of the BM_GridGraph benchmark (in which
290 // DistanceType=int64_t and node_type=int32_t), done with benchy
291 // --runs=20: 0) BM_GridGraph<true> 9.22ms ± 5% BM_GridGraph<false> 3.19ms
292 // ± 6% 1) BM_GridGraph<true> 8.89ms ± 4% BM_GridGraph<false> 3.07ms ±
293 // 3% 2) BM_GridGraph<true> 8.61ms ± 3% BM_GridGraph<false> 3.13ms ± 6%
294 // 3) BM_GridGraph<true> 7.85ms ± 2% BM_GridGraph<false> 3.29ms ± 2%
295 return std::tie(distance, node) < std::tie(other.distance, other.node);
296 }
297 bool operator>(const NodeDistance& other) const { return other < *this; }
298 };
299 std::vector<NodeDistance> queue_;
300
301 // These are used by some of the Run...() variants, and are kept as data
302 // members to avoid reallocation upon multiple calls.
303 // The vectors are only allocated after they are first used.
304 // Between calls, is_destination_ is all false, and the rest is junk.
305 std::vector<bool> is_destination_;
306 std::vector<int> node_to_source_index_;
307 std::vector<int> node_to_destination_index_;
308};
309
310// -----------------------------------------------------------------------------
311// Implementation.
312// -----------------------------------------------------------------------------
313
314template <class GraphType, class DistanceType, class ArcLengthFunctor>
316 BoundedDijkstraWrapper(const GraphType* graph,
317 const std::vector<DistanceType>* arc_lengths)
318 : graph_(graph),
319 arc_length_functor_(*arc_lengths),
320 arc_lengths_(arc_lengths) {
321 CHECK(arc_lengths_ != nullptr);
322 CHECK_EQ(arc_lengths_->size(), graph->num_arcs());
323 for (const DistanceType length : *arc_lengths) {
324 CHECK_GE(length, 0);
325 }
326}
327
328template <class GraphType, class DistanceType, class ArcLengthFunctor>
330 BoundedDijkstraWrapper(const GraphType* graph,
331 ArcLengthFunctor arc_length_functor)
332 : graph_(graph),
333 arc_length_functor_(std::move(arc_length_functor)),
334 arc_lengths_(nullptr) {}
335
336template <class GraphType, class DistanceType, class ArcLengthFunctor>
339 : graph_(other.graph_),
340 arc_length_functor_(other.arc_length_functor_),
341 arc_lengths_(other.arc_lengths_) {}
342
343template <class GraphType, class DistanceType, class ArcLengthFunctor>
344const std::vector<int>&
347 const std::vector<std::pair<int, DistanceType>>&
348 sources_with_distance_offsets,
349 DistanceType distance_limit) {
350 return RunBoundedDijkstraWithSettledNodeCallback(
351 sources_with_distance_offsets, nullptr, distance_limit);
352}
353
354template <class GraphType, class DistanceType, class ArcLengthFunctor>
355std::vector<int>
358 const std::vector<std::pair<int, DistanceType>>&
359 sources_with_distance_offsets,
360 const std::vector<std::pair<int, DistanceType>>&
361 destinations_with_distance_offsets,
362 int num_destinations_to_reach, DistanceType distance_limit) {
363 if (destinations_with_distance_offsets.empty()) return {};
364 if (num_destinations_to_reach <= 0) return {};
365
366 // Initialize the destinations. We'll adapt the distance limit according to
367 // the minimal destination distance offset. This is an optional optimization,
368 // to reduce the search space.
369 DCHECK_GE(num_destinations_to_reach, 0);
370 int num_destinations = 0;
371 is_destination_.resize(graph_->num_nodes(), false);
372 node_to_destination_index_.resize(graph_->num_nodes(), -1);
373 DistanceType min_destination_distance_offset =
374 destinations_with_distance_offsets[0].second;
375 for (int i = 0; i < destinations_with_distance_offsets.size(); ++i) {
376 const int node = destinations_with_distance_offsets[i].first;
377 const DistanceType distance = destinations_with_distance_offsets[i].second;
378 if (!is_destination_[node]) ++num_destinations;
379 // Skip useless repetitions.
380 if (is_destination_[node] &&
381 distance >=
382 destinations_with_distance_offsets[node_to_destination_index_[node]]
383 .second) {
384 continue;
385 }
386 is_destination_[node] = true;
387 node_to_destination_index_[node] = i;
388 min_destination_distance_offset =
389 std::min(min_destination_distance_offset, distance);
390 }
391 distance_limit -= min_destination_distance_offset;
392 if (num_destinations_to_reach > num_destinations) {
393 num_destinations_to_reach = num_destinations;
394 }
396 /*limit=*/num_destinations_to_reach);
397
398 std::function<void(node_type, DistanceType, DistanceType*)>
399 settled_node_callback =
400 [this, num_destinations_to_reach, min_destination_distance_offset,
401 &destinations_with_distance_offsets, &closest_destinations](
402 node_type settled_node, DistanceType settled_distance,
403 DistanceType* distance_limit) {
404 if (!is_destination_[settled_node]) return;
405 const DistanceType distance =
406 settled_distance +
407 destinations_with_distance_offsets
408 [node_to_destination_index_[settled_node]]
409 .second -
410 min_destination_distance_offset;
411 if (distance >= *distance_limit) return;
412 closest_destinations.push(NodeDistance{settled_node, distance});
413 if (closest_destinations.size() == num_destinations_to_reach) {
414 const DistanceType new_distance_limit =
415 closest_destinations.peek_bottom().distance;
416 DCHECK_LE(new_distance_limit, *distance_limit);
417 *distance_limit = new_distance_limit;
418 }
419 };
420
421 RunBoundedDijkstraWithSettledNodeCallback(
422 sources_with_distance_offsets, settled_node_callback, distance_limit);
423
424 // Clean up, sparsely, for the next call.
425 for (const auto& [node, _] : destinations_with_distance_offsets) {
426 is_destination_[node] = false;
427 }
428
429 // Return the closest "num_destinations_to_reach" reached destinations,
430 // sorted by distance.
431 std::vector<int> sorted_destinations;
432 sorted_destinations.reserve(closest_destinations.size());
433 for (const NodeDistance& d : closest_destinations.Take()) {
434 sorted_destinations.push_back(d.node);
435 }
436 return sorted_destinations;
437}
438
439template <class GraphType, class DistanceType, class ArcLengthFunctor>
441 OneToOneShortestPath(int from, int to, DistanceType distance_limit) {
442 bool reached = false;
443 std::function<void(node_type, DistanceType, DistanceType*)>
444 settled_node_callback = [to, &reached](node_type node,
445 DistanceType distance,
446 DistanceType* distance_limit) {
447 if (node != to) return;
448 if (distance >= *distance_limit) return;
449 reached = true;
450 // Stop the search, by setting the distance limit to 0.
451 *distance_limit = 0;
452 };
453 RunBoundedDijkstraWithSettledNodeCallback({{from, 0}}, settled_node_callback,
454 distance_limit);
455 return reached;
456}
457
458template <class GraphType, class DistanceType, class ArcLengthFunctor>
459const std::vector<int>&
462 const std::vector<std::pair<int, DistanceType>>&
463 sources_with_distance_offsets,
464 std::function<void(node_type settled_node,
465 DistanceType settled_distance,
466 DistanceType* distance_limit)>
467 settled_node_callback,
468 DistanceType distance_limit) {
469 // Sparse clear is_reached_ from the last call.
470 for (const int node : reached_nodes_) {
471 is_reached_[node] = false;
472 }
473 reached_nodes_.clear();
474 DCHECK(!absl::c_linear_search(is_reached_, true));
475
476 is_reached_.resize(graph_->num_nodes(), false);
477 distances_.resize(graph_->num_nodes(), distance_limit);
478 parents_.resize(graph_->num_nodes(), std::numeric_limits<int>::min());
479 arc_from_source_.resize(graph_->num_nodes(), -1);
480
481 // Initialize sources.
482 CHECK(queue_.empty());
483 node_to_source_index_.resize(graph_->num_nodes(), -1);
484 for (int i = 0; i < sources_with_distance_offsets.size(); ++i) {
485 const int node = sources_with_distance_offsets[i].first;
486 DCHECK_GE(node, 0);
487 DCHECK_LT(node, graph_->num_nodes());
488 const DistanceType distance = sources_with_distance_offsets[i].second;
489 // Sources with an initial distance ≥ limit are *not* reached.
490 if (distance >= distance_limit) continue;
491 // Skip useless repetitions.
492 if (is_reached_[node] && distance >= distances_[node]) continue;
493 if (!is_reached_[node]) {
494 is_reached_[node] = true;
495 reached_nodes_.push_back(node);
496 parents_[node] = node; // Set the parent to itself.
497 }
498 node_to_source_index_[node] = i;
499 distances_[node] = distance;
500 }
501 for (const int source : reached_nodes_) {
502 queue_.push_back({source, distances_[source]});
503 }
504 std::make_heap(queue_.begin(), queue_.end(), std::greater<NodeDistance>());
505
506 // Dijkstra loop.
507 while (!queue_.empty()) {
508 const NodeDistance top = queue_.front();
509 std::pop_heap(queue_.begin(), queue_.end(), std::greater<NodeDistance>());
510 queue_.pop_back();
511
512 // The queue may contain the same node more than once, skip irrelevant
513 // entries.
514 if (distances_[top.node] < top.distance) continue;
515
516 if (settled_node_callback) {
517 // We usually never enqueue anything >= distance_limit, but if
518 // settled_node_callback is not nullptr, the limit might have been changed
519 // after the enqueue were done. So we re-test it here to make sure we
520 // never call the callback on such node.
521 if (top.distance < distance_limit) {
522 settled_node_callback(top.node, top.distance, &distance_limit);
523 }
524
525 // If we are over the distance, we can empty the queue and abort.
526 if (top.distance >= distance_limit) {
527 queue_.clear();
528 break;
529 }
530 } else {
531 DCHECK_LT(top.distance, distance_limit);
532 }
533
534 // Visit the neighbors.
535 const DistanceType limit = distance_limit - top.distance;
536 for (const int arc : graph_->OutgoingArcs(top.node)) {
537 // Overflow-safe check of top.distance + arc_length >= distance_limit.
538 // This works since we know top.distance < distance_limit, as long as we
539 // don't have negative top.distance (which might happen with negative
540 // source offset). Note that for floating point, it is not exactly the
541 // same as (top_distance + arc_length < distance_limit) though.
542 const DistanceType arc_length = GetArcLength(arc);
543 if (arc_length >= limit) continue;
544 const DistanceType candidate_distance = top.distance + arc_length;
545
546 const int head = graph_->Head(arc);
547 if (is_reached_[head]) {
548 if (candidate_distance >= distances_[head]) continue;
549 } else {
550 is_reached_[head] = true;
551 reached_nodes_.push_back(head);
552 }
553 distances_[head] = candidate_distance;
554 parents_[head] = top.node;
555 arc_from_source_[head] = arc;
556 queue_.push_back({head, candidate_distance});
557 std::push_heap(queue_.begin(), queue_.end(),
558 std::greater<NodeDistance>());
559 }
560 }
561
562 return reached_nodes_;
563}
564
565template <class GraphType, class DistanceType, class ArcLengthFunctor>
566std::vector<int>
568 int node) const {
569 std::vector<int> output;
570 int loop_detector = 0;
571 while (true) {
572 DCHECK_GE(node, 0);
573 DCHECK_LT(node, parents_.size());
574 CHECK_LT(loop_detector++, parents_.size());
575 if (parents_[node] == node) break;
576 output.push_back(arc_from_source_[node]);
577 node = parents_[node];
578 }
579 std::reverse(output.begin(), output.end());
580 return output;
581}
582
583template <class GraphType, class DistanceType, class ArcLengthFunctor>
584std::vector<int>
586 int node) const {
587 std::vector<int> output;
588 int loop_detector = 0;
589 while (true) {
590 DCHECK_GE(node, 0);
591 DCHECK_LT(node, parents_.size());
592 CHECK_LT(loop_detector++, parents_.size());
593 output.push_back(node);
594 if (parents_[node] == node) break;
595 node = parents_[node];
596 }
597 std::reverse(output.begin(), output.end());
598 return output;
599}
600
601template <class GraphType, class DistanceType, class ArcLengthFunctor>
603 SourceOfShortestPathToNode(int node) const {
604 int parent = node;
605 while (parents_[parent] != parent) parent = parents_[parent];
606 return parent;
607}
608
609template <class GraphType, class DistanceType, class ArcLengthFunctor>
610int BoundedDijkstraWrapper<GraphType, DistanceType,
611 ArcLengthFunctor>::GetSourceIndex(int node) const {
612 DCHECK_GE(node, 0);
613 DCHECK_LT(node, node_to_source_index_.size());
614 return node_to_source_index_[node];
615}
616
617template <class GraphType, class DistanceType, class ArcLengthFunctor>
618int BoundedDijkstraWrapper<GraphType, DistanceType,
619 ArcLengthFunctor>::GetDestinationIndex(int node)
620 const {
621 DCHECK_GE(node, 0);
622 DCHECK_LT(node, node_to_destination_index_.size());
623 return node_to_destination_index_[node];
624}
625
626// -----------------------------------------------------------------------------
627// Example usage.
628// -----------------------------------------------------------------------------
629
630template <typename DistanceType>
631std::pair<DistanceType, std::vector<int>> SimpleOneToOneShortestPath(
632 int source, int destination, absl::Span<const int> tails,
633 absl::Span<const int> heads, absl::Span<const DistanceType> lengths,
634 DistanceType limit) {
635 // Compute the number of nodes.
636 //
637 // This is not necessary, but is a good practice to allocate the graph size in
638 // one go. We also do some basic validation.
639 CHECK_GE(source, 0);
640 CHECK_GE(destination, 0);
641 int num_nodes = std::max(source + 1, destination + 1);
642 for (const int tail : tails) {
643 CHECK_GE(tail, 0);
644 num_nodes = std::max(tail + 1, num_nodes);
645 }
646 for (const int head : heads) {
647 CHECK_GE(head, 0);
648 num_nodes = std::max(head + 1, num_nodes);
649 }
650
651 // The number of arcs.
652 const int num_arcs = tails.size();
653 CHECK_EQ(num_arcs, heads.size());
654 CHECK_EQ(num_arcs, lengths.size());
655
656 // Build the graph. Note that this permutes arc indices for speed, but we
657 // don't care here since we will return a node path.
658 util::StaticGraph<> graph(num_nodes, num_arcs);
659 std::vector<DistanceType> arc_lengths(lengths.begin(), lengths.end());
660 for (int a = 0; a < num_arcs; ++a) {
661 // Negative length can cause the algo to loop forever and/or use a lot of
662 // memory. So it should be validated.
663 CHECK_GE(lengths[a], 0);
664 graph.AddArc(tails[a], heads[a]);
665 }
666 std::vector<int> permutation;
667 graph.Build(&permutation);
668 util::Permute(permutation, &arc_lengths);
669
670 // Compute a shortest path.
671 // This should work for both float/double or integer distances.
672 BoundedDijkstraWrapper<util::StaticGraph<>, DistanceType> wrapper(
673 &graph, &arc_lengths);
674 if (!wrapper.OneToOneShortestPath(source, destination, limit)) {
675 // No path exists, or shortest_distance >= limit.
676 return {limit, {}};
677 }
678
679 // A path exist, returns it.
680 return {wrapper.distances()[destination], wrapper.NodePathTo(destination)};
681}
682
683} // namespace operations_research
684
685#endif // OR_TOOLS_GRAPH_BOUNDED_DIJKSTRA_H_
bool IsReachable(int node) const
Returns true if node was reached by the last Run*() call.
const std::vector< int > & RunBoundedDijkstraFromMultipleSources(const std::vector< std::pair< int, DistanceType > > &sources_with_distance_offsets, DistanceType distance_limit)
std::vector< int > ArcPathTo(int node) const
const std::vector< int > & reached_nodes() const
Returns all the reached nodes form the previous Run*() call.
const std::vector< int > & RunBoundedDijkstraWithSettledNodeCallback(const std::vector< std::pair< int, DistanceType > > &sources_with_distance_offsets, std::function< void(node_type settled_node, DistanceType settled_distance, DistanceType *distance_limit)> settled_node_callback, DistanceType distance_limit)
const std::vector< int > & arc_from_source() const
BoundedDijkstraWrapper(const GraphType *graph, const std::vector< DistanceType > *arc_lengths)
const GraphType & graph() const
Trivial accessors to the underlying graph and arc lengths.
std::vector< int > NodePathTo(int node) const
const std::vector< int > & parents() const
const std::vector< DistanceType > & distances() const
The distance of the nodes from their source.
bool OneToOneShortestPath(int from, int to, DistanceType distance_limit)
std::vector< int > RunBoundedDijkstraFromMultipleSourcesToMultipleDestinations(const std::vector< std::pair< int, DistanceType > > &sources_with_distance_offsets, const std::vector< std::pair< int, DistanceType > > &destinations_with_distance_offsets, int num_destinations_to_reach, DistanceType distance_limit)
const std::vector< DistanceType > & arc_lengths() const
const std::vector< int > & RunBoundedDijkstra(int source_node, DistanceType distance_limit)
std::vector< int > ArcPathToNode(int node) const
const T & operator()(int index) const
ElementGetter(const std::vector< T > &c)
int64_t a
Definition table.cc:44
std::vector< double > arc_lengths
GraphType graph
int arc
int index
In SWIG mode, we don't want anything besides these top-level includes.
std::pair< DistanceType, std::vector< int > > SimpleOneToOneShortestPath(int source, int destination, absl::Span< const int > tails, absl::Span< const int > heads, absl::Span< const DistanceType > lengths, DistanceType limit=std::numeric_limits< DistanceType >::max())
STL namespace.
void Permute(const IntVector &permutation, Array *array_to_permute)
Definition graph.h:758
trees with all degrees equal to
int head
int tail
double distance