14#ifndef OR_TOOLS_GRAPH_DAG_SHORTEST_PATH_H_
15#define OR_TOOLS_GRAPH_DAG_SHORTEST_PATH_H_
18#if __cplusplus >= 202002L
25#include "absl/algorithm/container.h"
26#include "absl/log/check.h"
27#include "absl/status/status.h"
28#include "absl/strings/str_format.h"
29#include "absl/types/span.h"
71 int num_nodes, absl::Span<const ArcWithLength> arcs_with_length,
int source,
79 int num_nodes, absl::Span<const ArcWithLength> arcs_with_length,
int source,
80 int destination,
int path_count);
88#if __cplusplus >= 202002L
89template <
class GraphType>
90concept DagGraphType =
requires(GraphType
graph) {
91 {
typename GraphType::NodeIndex{} };
92 {
typename GraphType::ArcIndex{} };
93 {
graph.num_nodes() } -> std::same_as<typename GraphType::NodeIndex>;
94 {
graph.num_arcs() } -> std::same_as<typename GraphType::ArcIndex>;
95 {
graph.OutgoingArcs(
typename GraphType::NodeIndex{}) };
97 graph.Tail(
typename GraphType::ArcIndex{})
98 } -> std::same_as<typename GraphType::NodeIndex>;
100 graph.Head(
typename GraphType::ArcIndex{})
101 } -> std::same_as<typename GraphType::NodeIndex>;
110template <
class GraphType>
111#if __cplusplus >= 202002L
112 requires DagGraphType<GraphType>
114class ShortestPathsOnDagWrapper {
116 using NodeIndex =
typename GraphType::NodeIndex;
117 using ArcIndex =
typename GraphType::ArcIndex;
151 const std::vector<NodeIndex>&
reached_nodes()
const {
return reached_nodes_; }
155 std::vector<double>
LengthTo()
const {
return length_from_sources_; }
166 const GraphType&
graph()
const {
return *graph_; }
167 const std::vector<double>&
arc_lengths()
const {
return *arc_lengths_; }
170 static constexpr double kInf = std::numeric_limits<double>::infinity();
171 const GraphType*
const graph_;
172 const std::vector<double>*
const arc_lengths_;
173 absl::Span<const NodeIndex>
const topological_order_;
176 std::vector<double> length_from_sources_;
177 std::vector<ArcIndex> incoming_shortest_path_arc_;
178 std::vector<NodeIndex> reached_nodes_;
188template <
class GraphType>
189#if __cplusplus >= 202002L
190 requires DagGraphType<GraphType>
194 using NodeIndex =
typename GraphType::NodeIndex;
195 using ArcIndex =
typename GraphType::ArcIndex;
230 const std::vector<NodeIndex>&
reached_nodes()
const {
return reached_nodes_; }
246 const GraphType&
graph()
const {
return *graph_; }
247 const std::vector<double>&
arc_lengths()
const {
return *arc_lengths_; }
248 int path_count()
const {
return path_count_; }
251 static constexpr double kInf = std::numeric_limits<double>::infinity();
253 const GraphType*
const graph_;
254 const std::vector<double>*
const arc_lengths_;
255 absl::Span<const NodeIndex>
const topological_order_;
256 const int path_count_;
258 GraphType reverse_graph_;
260 std::vector<ArcIndex> arc_indices_;
265 std::vector<std::vector<double>> lengths_from_sources_;
266 std::vector<std::vector<ArcIndex>> incoming_shortest_paths_arc_;
267 std::vector<std::vector<int>> incoming_shortest_paths_index_;
268 std::vector<bool> is_source_;
269 std::vector<NodeIndex> reached_nodes_;
272template <
class GraphType>
273#if __cplusplus >= 202002L
274 requires DagGraphType<GraphType>
277 const GraphType&
graph,
288template <
typename GraphType>
289#if __cplusplus >= 202002L
290 requires DagGraphType<GraphType>
293 absl::Span<const typename GraphType::ArcIndex> arc_path,
294 const GraphType&
graph) {
295 CHECK(!arc_path.empty());
296 std::vector<typename GraphType::NodeIndex> node_path;
297 node_path.reserve(arc_path.size() + 1);
298 for (
const typename GraphType::ArcIndex arc_index : arc_path) {
299 node_path.push_back(
graph.Tail(arc_index));
301 node_path.push_back(
graph.Head(arc_path.back()));
305template <
class GraphType>
306#if __cplusplus >= 202002L
307 requires DagGraphType<GraphType>
310 const GraphType&
graph) {
311 CHECK_GE(node, 0) <<
"Node must be nonnegative. Input value: " << node;
312 CHECK_LT(node,
graph.num_nodes())
313 <<
"Node must be a valid node. Input value: " << node
314 <<
". Number of nodes in the input graph: " <<
graph.num_nodes();
317template <
class GraphType>
318#if __cplusplus >= 202002L
319 requires DagGraphType<GraphType>
322 const GraphType&
graph,
324 using NodeIndex =
typename GraphType::NodeIndex;
325 using ArcIndex =
typename GraphType::ArcIndex;
328 return absl::InvalidArgumentError(absl::StrFormat(
329 "topological_order.size() = %i, != graph.num_nodes() = %i",
332 std::vector<NodeIndex> inverse_topology(num_nodes, -1);
335 return absl::InvalidArgumentError(
336 absl::StrFormat(
"node % i appears twice in topological order",
344 if (inverse_topology[
tail] >= inverse_topology[
head]) {
345 return absl::InvalidArgumentError(absl::StrFormat(
346 "arc (%i, %i) is inconsistent with topological order",
tail,
head));
350 return absl::OkStatus();
356template <
class GraphType>
357#if __cplusplus >= 202002L
358 requires DagGraphType<GraphType>
366 CHECK(graph_ !=
nullptr);
367 CHECK(arc_lengths_ !=
nullptr);
368 CHECK_GT(graph_->num_nodes(), 0) <<
"The graph is empty: it has no nodes";
369 CHECK_GT(graph_->num_arcs(), 0) <<
"The graph is empty: it has no arcs";
371 CHECK_EQ(arc_lengths_->size(), graph_->num_arcs());
372 for (
const double arc_length : *arc_lengths_) {
373 CHECK(arc_length != -kInf && !std::isnan(arc_length))
374 << absl::StrFormat(
"length cannot be -inf nor NaN");
377 <<
"Invalid topological order";
382 length_from_sources_.resize(graph_->num_nodes(), kInf);
383 incoming_shortest_path_arc_.resize(graph_->num_nodes(), -1);
384 reached_nodes_.reserve(graph_->num_nodes());
387template <
class GraphType>
388#if __cplusplus >= 202002L
389 requires DagGraphType<GraphType>
391void ShortestPathsOnDagWrapper<GraphType>::RunShortestPathOnDag(
392 absl::Span<const NodeIndex> sources) {
394 const absl::Span<double> length_from_sources =
395 absl::MakeSpan(length_from_sources_);
396 const absl::Span<const double>
arc_lengths = *arc_lengths_;
401 for (
const NodeIndex node : reached_nodes_) {
402 length_from_sources[node] = kInf;
404 DCHECK(std::all_of(length_from_sources.begin(), length_from_sources.end(),
405 [](
double l) { return l == kInf; }));
406 reached_nodes_.clear();
410 length_from_sources[source] = 0.0;
413 for (
const NodeIndex
tail : topological_order_) {
414 const double length_to_tail = length_from_sources[
tail];
416 if (length_to_tail == kInf) {
419 reached_nodes_.push_back(
tail);
420 for (
const ArcIndex
arc : graph_->OutgoingArcs(
tail)) {
424 if (length_to_head < length_from_sources[
head]) {
425 length_from_sources[
head] = length_to_head;
426 incoming_shortest_path_arc_[
head] =
arc;
432template <
class GraphType>
433#if __cplusplus >= 202002L
434 requires DagGraphType<GraphType>
436bool ShortestPathsOnDagWrapper<GraphType>::IsReachable(NodeIndex node)
const {
438 return length_from_sources_[node] <
kInf;
441template <
class GraphType>
442#if __cplusplus >= 202002L
443 requires DagGraphType<GraphType>
445std::vector<typename GraphType::ArcIndex>
447 CHECK(IsReachable(node));
448 std::vector<ArcIndex> arc_path;
450 for (
int i = 0; i < graph_->num_nodes(); ++i) {
451 ArcIndex current_arc = incoming_shortest_path_arc_[current_node];
452 if (current_arc == -1) {
455 arc_path.push_back(current_arc);
456 current_node = graph_->Tail(current_arc);
458 absl::c_reverse(arc_path);
462template <
class GraphType>
463#if __cplusplus >= 202002L
464 requires DagGraphType<GraphType>
466std::vector<typename GraphType::NodeIndex>
467ShortestPathsOnDagWrapper<GraphType>::NodePathTo(NodeIndex node)
const {
468 const std::vector<typename GraphType::ArcIndex> arc_path = ArcPathTo(node);
469 if (arc_path.empty()) {
478template <
class GraphType>
479#if __cplusplus >= 202002L
480 requires DagGraphType<GraphType>
488 path_count_(path_count) {
489 CHECK(graph_ !=
nullptr);
490 CHECK(arc_lengths_ !=
nullptr);
491 CHECK_GT(graph_->num_nodes(), 0) <<
"The graph is empty: it has no nodes";
492 CHECK_GT(graph_->num_arcs(), 0) <<
"The graph is empty: it has no arcs";
493 CHECK_GT(path_count_, 0) <<
"path_count must be greater than 0";
495 CHECK_EQ(arc_lengths_->size(), graph_->num_arcs());
496 for (
const double arc_length : *arc_lengths_) {
497 CHECK(arc_length != -kInf && !std::isnan(arc_length))
498 << absl::StrFormat(
"length cannot be -inf nor NaN");
501 <<
"Invalid topological order";
506 const int num_arcs = graph_->num_arcs();
507 reverse_graph_ = GraphType(graph_->num_nodes(), num_arcs);
508 for (
ArcIndex arc_index = 0; arc_index < num_arcs; ++arc_index) {
509 reverse_graph_.AddArc(
graph->Head(arc_index),
graph->Tail(arc_index));
511 std::vector<ArcIndex> permutation;
512 reverse_graph_.Build(&permutation);
513 arc_indices_.resize(permutation.size());
514 if (!permutation.empty()) {
515 for (
int i = 0; i < permutation.size(); ++i) {
516 arc_indices_[permutation[i]] = i;
522 lengths_from_sources_.resize(path_count_);
523 incoming_shortest_paths_arc_.resize(path_count_);
524 incoming_shortest_paths_index_.resize(path_count_);
525 for (
int k = 0; k < path_count_; ++k) {
526 lengths_from_sources_[k].resize(graph_->num_nodes(), kInf);
527 incoming_shortest_paths_arc_[k].resize(graph_->num_nodes(), -1);
528 incoming_shortest_paths_index_[k].resize(graph_->num_nodes(), -1);
530 is_source_.resize(graph_->num_nodes(),
false);
531 reached_nodes_.reserve(graph_->num_nodes());
534template <
class GraphType>
535#if __cplusplus >= 202002L
536 requires DagGraphType<GraphType>
539 absl::Span<const NodeIndex> sources) {
541 const absl::Span<const double>
arc_lengths = *arc_lengths_;
542 const absl::Span<const ArcIndex> arc_indices = arc_indices_;
549 is_source_[node] =
false;
550 for (
int k = 0; k < path_count_; ++k) {
551 lengths_from_sources_[k][node] = kInf;
554 reached_nodes_.clear();
556 for (
int k = 0; k < path_count_; ++k) {
557 CHECK(std::all_of(lengths_from_sources_[k].begin(),
558 lengths_from_sources_[k].
end(),
559 [](
double l) {
return l == kInf; }));
565 is_source_[source] =
true;
568 struct IncomingArcPath {
569 double path_length = 0.0;
571 double arc_length = 0.0;
575 bool operator<(
const IncomingArcPath& other)
const {
576 return std::tie(path_length, from) <
577 std::tie(other.path_length, other.from);
579 bool operator>(
const IncomingArcPath& other)
const {
return other < *
this; }
581 std::vector<IncomingArcPath> min_heap;
582 auto comp = std::greater<IncomingArcPath>();
585 if (is_source_[
to]) {
586 min_heap.push_back({.arc_index = -1});
588 for (
const ArcIndex reverse_arc_index : reverse_graph_.OutgoingArcs(
to)) {
589 const ArcIndex arc_index = arc_indices.empty()
591 : arc_indices[reverse_arc_index];
592 const NodeIndex from = graph_->Tail(arc_index);
594 DCHECK(arc_length != -kInf);
595 const double path_length =
596 lengths_from_sources_.front()[from] + arc_length;
597 if (path_length == kInf) {
600 min_heap.push_back({.path_length = path_length,
601 .arc_index = arc_index,
602 .arc_length = arc_length,
604 std::push_heap(min_heap.begin(), min_heap.end(), comp);
606 if (min_heap.empty()) {
609 reached_nodes_.push_back(
to);
610 for (
int k = 0; k < path_count_; ++k) {
611 std::pop_heap(min_heap.begin(), min_heap.end(), comp);
612 IncomingArcPath& incoming_arc_path = min_heap.back();
613 lengths_from_sources_[k][
to] = incoming_arc_path.path_length;
614 incoming_shortest_paths_arc_[k][
to] = incoming_arc_path.arc_index;
615 incoming_shortest_paths_index_[k][
to] = incoming_arc_path.path_index;
616 if (incoming_arc_path.arc_index != -1 &&
617 incoming_arc_path.path_index < path_count_ - 1 &&
618 lengths_from_sources_[incoming_arc_path.path_index + 1]
619 [incoming_arc_path.from] < kInf) {
620 ++incoming_arc_path.path_index;
621 incoming_arc_path.path_length =
622 lengths_from_sources_[incoming_arc_path.path_index]
623 [incoming_arc_path.from] +
624 incoming_arc_path.arc_length;
625 std::push_heap(min_heap.begin(), min_heap.end(), comp);
628 if (min_heap.empty()) {
636template <
class GraphType>
637#if __cplusplus >= 202002L
638 requires DagGraphType<GraphType>
642 return lengths_from_sources_.front()[node] <
kInf;
645template <
class GraphType>
646#if __cplusplus >= 202002L
647 requires DagGraphType<GraphType>
651 std::vector<double> lengths_to;
652 lengths_to.reserve(path_count_);
653 for (
int k = 0; k < path_count_; ++k) {
654 const double length_to = lengths_from_sources_[k][node];
655 if (length_to == kInf) {
658 lengths_to.push_back(length_to);
663template <
class GraphType>
664#if __cplusplus >= 202002L
665 requires DagGraphType<GraphType>
667std::vector<std::vector<typename GraphType::ArcIndex>>
669 std::vector<std::vector<ArcIndex>> arc_paths;
670 arc_paths.reserve(path_count_);
671 for (
int k = 0; k < path_count_; ++k) {
672 if (lengths_from_sources_[k][node] == kInf) {
675 std::vector<ArcIndex> arc_path;
676 int current_path_index = k;
678 for (
int i = 0; i < graph_->num_nodes(); ++i) {
680 incoming_shortest_paths_arc_[current_path_index][current_node];
681 if (current_arc == -1) {
684 arc_path.push_back(current_arc);
686 incoming_shortest_paths_index_[current_path_index][current_node];
687 current_node = graph_->Tail(current_arc);
689 absl::c_reverse(arc_path);
690 arc_paths.push_back(arc_path);
695template <
class GraphType>
696#if __cplusplus >= 202002L
697 requires DagGraphType<GraphType>
699std::vector<std::vector<typename GraphType::NodeIndex>>
701 const std::vector<std::vector<ArcIndex>> arc_paths = ArcPathsTo(node);
702 std::vector<std::vector<NodeIndex>> node_paths(arc_paths.size());
703 for (
int k = 0; k < arc_paths.size(); ++k) {
704 if (arc_paths[k].empty()) {
705 node_paths[k] = {node};
bool IsReachable(NodeIndex node) const
KShortestPathsOnDagWrapper(const GraphType *graph, const std::vector< double > *arc_lengths, absl::Span< const NodeIndex > topological_order, int path_count)
const GraphType & graph() const
Accessors to the underlying graph and arc lengths.
typename GraphType::ArcIndex ArcIndex
void RunKShortestPathOnDag(absl::Span< const NodeIndex > sources)
std::vector< std::vector< ArcIndex > > ArcPathsTo(NodeIndex node) const
std::vector< std::vector< NodeIndex > > NodePathsTo(NodeIndex node) const
typename GraphType::NodeIndex NodeIndex
const std::vector< NodeIndex > & reached_nodes() const
const std::vector< double > & arc_lengths() const
std::vector< double > LengthsTo(NodeIndex node) const
ShortestPathsOnDagWrapper(const GraphType *graph, const std::vector< double > *arc_lengths, absl::Span< const NodeIndex > topological_order)
typename GraphType::NodeIndex NodeIndex
bool IsReachable(NodeIndex node) const
const GraphType & graph() const
Accessors to the underlying graph and arc lengths.
std::vector< ArcIndex > ArcPathTo(NodeIndex node) const
void RunShortestPathOnDag(absl::Span< const NodeIndex > sources)
std::vector< double > LengthTo() const
const std::vector< double > & arc_lengths() const
typename GraphType::ArcIndex ArcIndex
std::vector< NodeIndex > NodePathTo(NodeIndex node) const
const std::vector< NodeIndex > & reached_nodes() const
std::vector< NodeIndex > topological_order
std::vector< double > arc_lengths
In SWIG mode, we don't want anything besides these top-level includes.
std::vector< PathWithLength > KShortestPathsOnDag(const int num_nodes, absl::Span< const ArcWithLength > arcs_with_length, const int source, const int destination, const int path_count)
void CheckNodeIsValid(typename GraphType::NodeIndex node, const GraphType &graph)
std::vector< typename GraphType::NodeIndex > NodePathImpliedBy(absl::Span< const typename GraphType::ArcIndex > arc_path, const GraphType &graph)
absl::Status TopologicalOrderIsValid(const GraphType &graph, absl::Span< const typename GraphType::NodeIndex > topological_order)
PathWithLength ShortestPathsOnDag(const int num_nodes, absl::Span< const ArcWithLength > arcs_with_length, const int source, const int destination)
trees with all degrees equal to
std::optional< int64_t > end
std::vector< int > node_path
std::vector< int > arc_path