14#ifndef OR_TOOLS_GRAPH_DAG_CONSTRAINED_SHORTEST_PATH_H_
15#define OR_TOOLS_GRAPH_DAG_CONSTRAINED_SHORTEST_PATH_H_
21#include "absl/algorithm/container.h"
22#include "absl/base/log_severity.h"
23#include "absl/log/check.h"
24#include "absl/strings/str_format.h"
25#include "absl/types/span.h"
65struct ArcWithLengthAndResources {
76 absl::Span<const ArcWithLengthAndResources> arcs_with_length_and_resources,
77 int source,
int destination,
const std::vector<double>& max_resources);
85template <
class GraphType>
86#if __cplusplus >= 202002L
87 requires DagGraphType<GraphType>
91 using NodeIndex =
typename GraphType::NodeIndex;
92 using ArcIndex =
typename GraphType::ArcIndex;
121 const std::vector<std::vector<double>>* arc_resources,
123 absl::Span<const NodeIndex> sources,
124 absl::Span<const NodeIndex> destinations,
125 const std::vector<double>* max_resources,
126 int max_num_created_labels = 1e9);
136 return lengths_from_sources_[FORWARD].size() +
137 lengths_from_sources_[BACKWARD].size();
146 inline static Direction Reverse(Direction d) {
147 return d == FORWARD ? BACKWARD : FORWARD;
158 void RunHalfConstrainedShortestPathOnDag(
159 const GraphType& reverse_graph, absl::Span<const double>
arc_lengths,
160 absl::Span<
const std::vector<double>> arc_resources,
161 absl::Span<
const std::vector<double>> min_arc_resources,
162 absl::Span<const double> max_resources,
int max_num_created_labels,
163 std::vector<double>& lengths_from_sources,
164 std::vector<std::vector<double>>& resources_from_sources,
165 std::vector<ArcIndex>& incoming_arc_indices_from_sources,
166 std::vector<int>& incoming_label_indices_from_sources,
167 std::vector<int>& first_label, std::vector<int>& num_labels);
174 absl::Span<
const std::vector<double>> arc_resources,
175 absl::Span<const double> max_resources,
176 const std::vector<NodeIndex> sub_node_indices[2],
177 const std::vector<double> lengths_from_sources[2],
178 const std::vector<std::vector<double>> resources_from_sources[2],
179 const std::vector<int> first_label[2],
180 const std::vector<int> num_labels[2], LabelPair& best_label_pair);
185 std::vector<ArcIndex> ArcPathTo(
186 int best_label_index,
187 absl::Span<const ArcIndex> incoming_arc_indices_from_sources,
188 absl::Span<const int> incoming_label_indices_from_sources)
const;
191 std::vector<NodeIndex> NodePathImpliedBy(absl::Span<const ArcIndex> arc_path,
192 const GraphType&
graph)
const;
194 static constexpr double kTolerance = 1e-6;
196 const GraphType*
const graph_;
197 const std::vector<double>*
const arc_lengths_;
198 const std::vector<std::vector<double>>*
const arc_resources_;
199 const std::vector<double>*
const max_resources_;
200 absl::Span<const NodeIndex> sources_;
201 absl::Span<const NodeIndex> destinations_;
202 const int num_resources_;
215 GraphType sub_reverse_graph_[2];
216 std::vector<std::vector<double>> sub_arc_resources_[2];
222 std::vector<NodeIndex> sub_full_arc_indices_[2];
228 std::vector<NodeIndex> sub_node_indices_[2];
235 std::vector<bool> sub_is_source_[2][2];
241 std::vector<std::vector<double>> sub_min_arc_resources_[2];
243 int max_num_created_labels_[2];
253 std::vector<double> lengths_from_sources_[2];
254 std::vector<std::vector<double>> resources_from_sources_[2];
255 std::vector<ArcIndex> incoming_arc_indices_from_sources_[2];
256 std::vector<int> incoming_label_indices_from_sources_[2];
257 std::vector<int> node_first_label_[2];
258 std::vector<int> node_num_labels_[2];
267template <
class GraphType>
268#if __cplusplus >= 202002L
269 requires DagGraphType<GraphType>
274 const std::vector<std::vector<double>>* arc_resources,
276 absl::Span<const NodeIndex> sources,
277 absl::Span<const NodeIndex> destinations,
278 const std::vector<double>* max_resources,
int max_num_created_labels)
281 arc_resources_(arc_resources),
282 max_resources_(max_resources),
284 destinations_(destinations),
285 num_resources_(max_resources->
size()) {
286 CHECK(graph_ !=
nullptr);
287 CHECK(arc_lengths_ !=
nullptr);
288 CHECK(arc_resources_ !=
nullptr);
289 CHECK(!sources_.empty());
290 CHECK(!destinations_.empty());
291 CHECK(max_resources_ !=
nullptr);
292 CHECK(!max_resources_->empty())
293 <<
"max_resources cannot be empty. Use "
294 "ortools/graph/dag_shortest_path.h instead";
297 CHECK_EQ(arc_resources->size(), max_resources->size());
298 for (absl::Span<const double> arcs_resource : *arc_resources) {
299 CHECK_EQ(arcs_resource.size(),
graph->num_arcs());
300 for (
const double arc_resource : arcs_resource) {
301 CHECK(arc_resource >= 0 &&
302 arc_resource != std::numeric_limits<double>::infinity() &&
303 !std::isnan(arc_resource))
304 << absl::StrFormat(
"resource cannot be negative nor +inf nor NaN");
308 CHECK(arc_length != -std::numeric_limits<double>::infinity() &&
309 !std::isnan(arc_length))
310 << absl::StrFormat(
"length cannot be -inf nor NaN");
313 <<
"Invalid topological order";
314 for (
const double max_resource : *max_resources) {
315 CHECK(max_resource >= 0 &&
316 max_resource != std::numeric_limits<double>::infinity() &&
317 !std::isnan(max_resource))
319 "max_resource cannot be negative not +inf nor NaN");
321 std::vector<bool> is_source(
graph->num_nodes(),
false);
323 is_source[source] =
true;
325 for (
const NodeIndex destination : destinations) {
326 CHECK(!is_source[destination])
327 <<
"A node cannot be both a source and destination";
332 const GraphType* full_graph[2];
333 const std::vector<std::vector<double>>* full_arc_resources[2];
334 absl::Span<const NodeIndex> full_topological_order[2];
335 absl::Span<const NodeIndex> full_sources[2];
337 const int num_nodes =
graph->num_nodes();
338 const int num_arcs =
graph->num_arcs();
339 full_graph[FORWARD] =
graph;
340 full_arc_resources[FORWARD] = arc_resources;
342 full_sources[FORWARD] = sources;
344 GraphType full_backward_graph(num_nodes, num_arcs);
345 for (
ArcIndex arc_index = 0; arc_index < num_arcs; ++arc_index) {
346 full_backward_graph.AddArc(
graph->Head(arc_index),
graph->Tail(arc_index));
348 std::vector<ArcIndex> full_permutation;
349 full_backward_graph.Build(&full_permutation);
350 const std::vector<ArcIndex> full_inverse_arc_indices =
352 std::vector<std::vector<double>> backward_arc_resources(num_resources_);
353 for (
int r = 0; r < num_resources_; ++r) {
354 backward_arc_resources[r] = (*arc_resources)[r];
357 std::vector<NodeIndex> full_backward_topological_order;
358 full_backward_topological_order.reserve(num_nodes);
359 for (
int i = num_nodes - 1; i >= 0; --i) {
362 full_graph[BACKWARD] = &full_backward_graph;
363 full_arc_resources[BACKWARD] = &backward_arc_resources;
364 full_topological_order[BACKWARD] = full_backward_topological_order;
365 full_sources[BACKWARD] = destinations;
369 std::vector<std::vector<double>> full_min_arc_resources[2];
370 for (
const Direction dir : {FORWARD, BACKWARD}) {
371 full_min_arc_resources[dir].reserve(num_resources_);
372 std::vector<double> full_arc_resource = full_arc_resources[dir]->front();
374 full_graph[dir], &full_arc_resource, full_topological_order[dir]);
375 for (
int r = 0; r < num_resources_; ++r) {
376 full_arc_resource = (*(full_arc_resources[dir]))[r];
378 full_min_arc_resources[dir].push_back(shortest_paths_on_dag.
LengthTo());
383 std::vector<bool> is_reachable(num_nodes,
true);
384 std::vector<NodeIndex> sub_topological_order;
385 sub_topological_order.reserve(num_nodes);
387 for (
int r = 0; r < num_resources_; ++r) {
388 if (full_min_arc_resources[FORWARD][r][node_index] +
389 full_min_arc_resources[BACKWARD][r][node_index] >
390 (*max_resources)[r]) {
391 is_reachable[node_index] =
false;
395 if (is_reachable[node_index]) {
396 sub_topological_order.push_back(node_index);
399 const int reachable_node_count = sub_topological_order.size();
403 max_num_created_labels_[BACKWARD] = max_num_created_labels / 2 + 1;
404 max_num_created_labels_[FORWARD] =
405 max_num_created_labels - max_num_created_labels / 2 + 1;
414 std::vector<double> path_count[2];
415 for (
const Direction dir : {FORWARD, BACKWARD}) {
416 const GraphType& reverse_full_graph = *(full_graph[Reverse(dir)]);
417 path_count[dir].resize(num_nodes);
418 for (
const NodeIndex source : full_sources[dir]) {
419 ++path_count[dir][source];
421 for (
const NodeIndex to : full_topological_order[dir]) {
422 if (!is_reachable[
to])
continue;
423 for (
const ArcIndex arc : reverse_full_graph.OutgoingArcs(
to)) {
425 if (!is_reachable[from])
continue;
426 path_count[dir][
to] += path_count[dir][from];
430 for (
const NodeIndex node_index : sub_topological_order) {
431 if (path_count[FORWARD][node_index] > path_count[BACKWARD][node_index]) {
436 if (mid_index == reachable_node_count) {
437 mid_index = reachable_node_count / 2;
441 for (
const Direction dir : {FORWARD, BACKWARD}) {
442 absl::Span<const NodeIndex>
const sub_nodes =
444 ? absl::MakeSpan(sub_topological_order).subspan(0, mid_index)
445 : absl::MakeSpan(sub_topological_order)
446 .subspan(mid_index, reachable_node_count - mid_index);
447 sub_node_indices_[dir].assign(num_nodes, -1);
448 sub_min_arc_resources_[dir].resize(num_resources_);
449 for (
int r = 0; r < num_resources_; ++r) {
450 sub_min_arc_resources_[dir][r].resize(sub_nodes.size());
452 for (
NodeIndex i = 0; i < sub_nodes.size(); ++i) {
454 dir == FORWARD ? i : sub_nodes.size() - 1 - i;
455 sub_node_indices_[dir][sub_nodes[i]] = sub_node_index;
456 for (
int r = 0; r < num_resources_; ++r) {
457 sub_min_arc_resources_[dir][r][sub_node_index] =
458 full_min_arc_resources[Reverse(dir)][r][sub_nodes[i]];
465 const int sub_arcs_count = num_arcs + full_sources[dir].size();
466 sub_reverse_graph_[dir] = GraphType(sub_nodes.size() + 1, sub_arcs_count);
467 sub_arc_resources_[dir].resize(num_resources_);
468 for (
int r = 0; r < num_resources_; ++r) {
469 sub_arc_resources_[dir][r].reserve(sub_arcs_count);
471 sub_full_arc_indices_[dir].reserve(sub_arcs_count);
472 const GraphType& reverse_full_graph = *(full_graph[Reverse(dir)]);
473 for (
ArcIndex arc_index = 0; arc_index < num_arcs; ++arc_index) {
475 sub_node_indices_[dir][reverse_full_graph.Tail(arc_index)];
477 sub_node_indices_[dir][reverse_full_graph.Head(arc_index)];
478 if (from == -1 ||
to == -1) {
481 sub_reverse_graph_[dir].AddArc(from,
to);
483 if (dir == FORWARD && !full_inverse_arc_indices.empty()) {
484 sub_full_arc_index = full_inverse_arc_indices[arc_index];
486 sub_full_arc_index = arc_index;
488 for (
int r = 0; r < num_resources_; ++r) {
489 sub_arc_resources_[dir][r].push_back(
490 (*arc_resources_)[r][sub_full_arc_index]);
492 sub_full_arc_indices_[dir].push_back(sub_full_arc_index);
494 for (
const NodeIndex source : full_sources[dir]) {
495 const NodeIndex sub_source = sub_node_indices_[dir][source];
496 if (sub_source == -1) {
499 sub_reverse_graph_[dir].AddArc(sub_source, sub_nodes.size());
500 for (
int r = 0; r < num_resources_; ++r) {
501 sub_arc_resources_[dir][r].push_back(0.0);
503 sub_full_arc_indices_[dir].push_back(-1);
505 std::vector<ArcIndex> sub_permutation;
506 sub_reverse_graph_[dir].Build(&sub_permutation);
507 for (
int r = 0; r < num_resources_; ++r) {
516 for (
const Direction dir : {FORWARD, BACKWARD}) {
517 resources_from_sources_[dir].resize(num_resources_);
518 node_first_label_[dir].resize(sub_reverse_graph_[dir].
size());
519 node_num_labels_[dir].resize(sub_reverse_graph_[dir].
size());
523template <
class GraphType>
524#if __cplusplus >= 202002L
525 requires DagGraphType<GraphType>
528 GraphType>::RunConstrainedShortestPathOnDag() {
530 std::vector<double> sub_arc_lengths[2];
531 for (
const Direction dir : {FORWARD, BACKWARD}) {
532 sub_arc_lengths[dir].reserve(sub_reverse_graph_[dir].num_arcs());
534 sub_arc_index < sub_reverse_graph_[dir].num_arcs(); ++sub_arc_index) {
535 const ArcIndex arc_index = sub_full_arc_indices_[dir][sub_arc_index];
536 if (arc_index == -1) {
537 sub_arc_lengths[dir].push_back(0.0);
540 sub_arc_lengths[dir].push_back((*arc_lengths_)[arc_index]);
545 ThreadPool search_threads(2);
546 search_threads.StartWorkers();
547 for (
const Direction dir : {FORWARD, BACKWARD}) {
548 search_threads.Schedule([
this, dir, &sub_arc_lengths]() {
549 RunHalfConstrainedShortestPathOnDag(
550 sub_reverse_graph_[dir],
551 sub_arc_lengths[dir],
552 sub_arc_resources_[dir],
553 sub_min_arc_resources_[dir],
555 max_num_created_labels_[dir],
556 lengths_from_sources_[dir],
557 resources_from_sources_[dir],
559 incoming_arc_indices_from_sources_[dir],
561 incoming_label_indices_from_sources_[dir],
562 node_first_label_[dir],
563 node_num_labels_[dir]);
569 LabelPair best_label_pair = {
570 .length = std::numeric_limits<double>::infinity(),
571 .label_index = {-1, -1}};
572 for (
const Direction dir : {FORWARD, BACKWARD}) {
573 absl::Span<const NodeIndex> destinations =
574 dir == FORWARD ? destinations_ : sources_;
575 for (
const NodeIndex dst : destinations) {
576 const NodeIndex sub_dst = sub_node_indices_[dir][dst];
580 const int num_labels_dst = node_num_labels_[dir][sub_dst];
581 if (num_labels_dst == 0) {
584 const int first_label_dst = node_first_label_[dir][sub_dst];
585 for (
int label_index = first_label_dst;
586 label_index < first_label_dst + num_labels_dst; ++label_index) {
587 const double length_dst = lengths_from_sources_[dir][label_index];
588 if (length_dst < best_label_pair.length) {
589 best_label_pair.length = length_dst;
590 best_label_pair.label_index[dir] = label_index;
596 const ArcIndex merging_arc_index = MergeHalfRuns(
597 *graph_, *arc_lengths_,
601 lengths_from_sources_,
602 resources_from_sources_,
604 node_num_labels_, best_label_pair);
606 std::vector<ArcIndex> arc_path;
607 for (
const Direction dir : {FORWARD, BACKWARD}) {
608 for (
const ArcIndex sub_arc_index : ArcPathTo(
609 best_label_pair.label_index[dir],
611 incoming_arc_indices_from_sources_[dir],
613 incoming_label_indices_from_sources_[dir])) {
614 const ArcIndex arc_index = sub_full_arc_indices_[dir][sub_arc_index];
615 if (arc_index == -1) {
618 arc_path.push_back(arc_index);
620 if (dir == FORWARD && merging_arc_index != -1) {
621 absl::c_reverse(arc_path);
622 arc_path.push_back(merging_arc_index);
627 for (
const Direction dir : {FORWARD, BACKWARD}) {
628 lengths_from_sources_[dir].clear();
629 for (
int r = 0; r < num_resources_; ++r) {
630 resources_from_sources_[dir][r].clear();
632 incoming_arc_indices_from_sources_[dir].clear();
633 incoming_label_indices_from_sources_[dir].clear();
635 return {.length = best_label_pair.length,
636 .arc_path = arc_path,
640template <
class GraphType>
641#if __cplusplus >= 202002L
642 requires DagGraphType<GraphType>
644void ConstrainedShortestPathsOnDagWrapper<GraphType>::
645 RunHalfConstrainedShortestPathOnDag(
646 const GraphType& reverse_graph, absl::Span<const double>
arc_lengths,
647 absl::Span<
const std::vector<double>> arc_resources,
648 absl::Span<
const std::vector<double>> min_arc_resources,
649 absl::Span<const double> max_resources,
650 const int max_num_created_labels,
651 std::vector<double>& lengths_from_sources,
652 std::vector<std::vector<double>>& resources_from_sources,
653 std::vector<ArcIndex>& incoming_arc_indices_from_sources,
654 std::vector<int>& incoming_label_indices_from_sources,
655 std::vector<int>& first_label, std::vector<int>& num_labels) {
657 const NodeIndex source_node = reverse_graph.num_nodes() - 1;
658 first_label[source_node] = 0;
659 num_labels[source_node] = 1;
660 lengths_from_sources.push_back(0);
661 for (
int r = 0; r < num_resources_; ++r) {
662 resources_from_sources[r].push_back(0);
664 incoming_arc_indices_from_sources.push_back(-1);
665 incoming_label_indices_from_sources.push_back(-1);
667 std::vector<double> lengths_to;
668 std::vector<std::vector<double>> resources_to(num_resources_);
669 std::vector<ArcIndex> incoming_arc_indices_to;
670 std::vector<int> incoming_label_indices_to;
671 std::vector<int> label_indices_to;
672 std::vector<double> resources(num_resources_);
675 for (
int r = 0; r < num_resources_; ++r) {
676 resources_to[r].clear();
678 incoming_arc_indices_to.clear();
679 incoming_label_indices_to.clear();
680 for (
const ArcIndex reverse_arc_index : reverse_graph.OutgoingArcs(
to)) {
681 const NodeIndex from = reverse_graph.Head(reverse_arc_index);
682 const double arc_length =
arc_lengths[reverse_arc_index];
683 DCHECK(arc_length != -std::numeric_limits<double>::infinity());
684 if (arc_length == std::numeric_limits<double>::infinity()) {
687 for (
int label_index = first_label[from];
688 label_index < first_label[from] + num_labels[from]; ++label_index) {
689 bool path_is_feasible =
true;
690 for (
int r = 0; r < num_resources_; ++r) {
691 DCHECK_GE(arc_resources[r][reverse_arc_index], 0.0);
692 resources[r] = resources_from_sources[r][label_index] +
693 arc_resources[r][reverse_arc_index];
694 if (resources[r] + min_arc_resources[r][
to] > max_resources[r]) {
695 path_is_feasible =
false;
699 if (!path_is_feasible) {
702 lengths_to.push_back(lengths_from_sources[label_index] + arc_length);
703 for (
int r = 0; r < num_resources_; ++r) {
704 resources_to[r].push_back(resources[r]);
706 incoming_arc_indices_to.push_back(reverse_arc_index);
707 incoming_label_indices_to.push_back(label_index);
711 label_indices_to.clear();
712 label_indices_to.reserve(lengths_to.size());
713 for (
int i = 0;
i < lengths_to.size(); ++
i) {
714 label_indices_to.push_back(i);
716 absl::c_sort(label_indices_to, [&](
const int i,
const int j) {
717 if (lengths_to[i] < lengths_to[j])
return true;
718 if (lengths_to[i] > lengths_to[j])
return false;
719 for (
int r = 0; r < num_resources_; ++r) {
720 if (resources_to[r][i] < resources_to[r][j])
return true;
721 if (resources_to[r][i] > resources_to[r][j])
return false;
726 first_label[
to] = lengths_from_sources.size();
727 int& num_labels_to = num_labels[
to];
731 for (
int i = 0;
i < label_indices_to.size(); ++
i) {
733 const int label_i_index = label_indices_to[
i];
734 bool label_i_is_dominated =
false;
735 for (
int j = 0; j <
i - 1; ++j) {
736 const int label_j_index = label_indices_to[j];
737 if (lengths_to[label_i_index] <= lengths_to[label_j_index])
continue;
738 bool label_j_dominates_label_i =
true;
739 for (
int r = 0; r < num_resources_; ++r) {
740 if (resources_to[r][label_i_index] <=
741 resources_to[r][label_j_index]) {
742 label_j_dominates_label_i =
false;
746 if (label_j_dominates_label_i) {
747 label_i_is_dominated =
true;
751 if (label_i_is_dominated)
continue;
752 lengths_from_sources.push_back(lengths_to[label_i_index]);
753 for (
int r = 0; r < num_resources_; ++r) {
754 resources_from_sources[r].push_back(resources_to[r][label_i_index]);
756 incoming_arc_indices_from_sources.push_back(
757 incoming_arc_indices_to[label_i_index]);
758 incoming_label_indices_from_sources.push_back(
759 incoming_label_indices_to[label_i_index]);
761 if (lengths_from_sources.size() >= max_num_created_labels) {
768template <
class GraphType>
769#if __cplusplus >= 202002L
770 requires DagGraphType<GraphType>
772typename GraphType::ArcIndex
773ConstrainedShortestPathsOnDagWrapper<GraphType>::MergeHalfRuns(
775 absl::Span<
const std::vector<double>> arc_resources,
776 absl::Span<const double> max_resources,
777 const std::vector<NodeIndex> sub_node_indices[2],
778 const std::vector<double> lengths_from_sources[2],
779 const std::vector<std::vector<double>> resources_from_sources[2],
780 const std::vector<int> first_label[2],
const std::vector<int> num_labels[2],
781 LabelPair& best_label_pair) {
782 const std::vector<NodeIndex>& forward_sub_node_indices =
783 sub_node_indices[FORWARD];
784 absl::Span<const double> forward_lengths = lengths_from_sources[FORWARD];
785 const std::vector<std::vector<double>>& forward_resources =
786 resources_from_sources[FORWARD];
787 absl::Span<const int> forward_first_label = first_label[FORWARD];
788 absl::Span<const int> forward_num_labels = num_labels[FORWARD];
789 const std::vector<NodeIndex>& backward_sub_node_indices =
790 sub_node_indices[BACKWARD];
791 absl::Span<const double> backward_lengths = lengths_from_sources[BACKWARD];
792 const std::vector<std::vector<double>>& backward_resources =
793 resources_from_sources[BACKWARD];
794 absl::Span<const int> backward_first_label = first_label[BACKWARD];
795 absl::Span<const int> backward_num_labels = num_labels[BACKWARD];
797 for (
ArcIndex arc_index = 0; arc_index <
graph.num_arcs(); ++arc_index) {
798 const NodeIndex sub_from = forward_sub_node_indices[
graph.Tail(arc_index)];
799 if (sub_from == -1) {
802 const NodeIndex sub_to = backward_sub_node_indices[
graph.Head(arc_index)];
806 const int num_labels_from = forward_num_labels[sub_from];
807 if (num_labels_from == 0) {
810 const int num_labels_to = backward_num_labels[sub_to];
811 if (num_labels_to == 0) {
815 DCHECK(arc_length != -std::numeric_limits<double>::infinity());
816 if (arc_length == std::numeric_limits<double>::infinity()) {
819 const int first_label_from = forward_first_label[sub_from];
820 const int first_label_to = backward_first_label[sub_to];
821 for (
int label_to_index = first_label_to;
822 label_to_index < first_label_to + num_labels_to; ++label_to_index) {
823 const double length_to = backward_lengths[label_to_index];
824 if (arc_length + length_to >= best_label_pair.length) {
827 for (
int label_from_index = first_label_from;
828 label_from_index < first_label_from + num_labels_from;
829 ++label_from_index) {
830 const double length_from = forward_lengths[label_from_index];
831 if (length_from + arc_length + length_to >= best_label_pair.length) {
834 bool path_is_feasible =
true;
835 for (
int r = 0; r < num_resources_; ++r) {
836 DCHECK_GE(arc_resources[r][arc_index], 0.0);
837 if (forward_resources[r][label_from_index] +
838 arc_resources[r][arc_index] +
839 backward_resources[r][label_to_index] >
841 path_is_feasible =
false;
845 if (!path_is_feasible) {
848 best_label_pair.length = length_from + arc_length + length_to;
849 best_label_pair.label_index[FORWARD] = label_from_index;
850 best_label_pair.label_index[BACKWARD] = label_to_index;
851 merging_arc_index = arc_index;
855 return merging_arc_index;
858template <
class GraphType>
859#if __cplusplus >= 202002L
860 requires DagGraphType<GraphType>
862std::vector<typename GraphType::ArcIndex>
863ConstrainedShortestPathsOnDagWrapper<GraphType>::ArcPathTo(
864 const int best_label_index,
865 absl::Span<const ArcIndex> incoming_arc_indices_from_sources,
866 absl::Span<const int> incoming_label_indices_from_sources)
const {
867 int current_label_index = best_label_index;
868 std::vector<ArcIndex> arc_path;
869 for (
int i = 0;
i < graph_->num_nodes(); ++
i) {
870 if (current_label_index == -1) {
873 arc_path.push_back(incoming_arc_indices_from_sources[current_label_index]);
874 current_label_index =
875 incoming_label_indices_from_sources[current_label_index];
880template <
typename GraphType>
881#if __cplusplus >= 202002L
882 requires DagGraphType<GraphType>
884std::vector<typename GraphType::NodeIndex>
885ConstrainedShortestPathsOnDagWrapper<GraphType>::NodePathImpliedBy(
886 absl::Span<const ArcIndex> arc_path,
const GraphType&
graph)
const {
887 if (arc_path.empty()) {
890 std::vector<NodeIndex> node_path;
891 node_path.reserve(arc_path.size() + 1);
892 for (
const ArcIndex arc_index : arc_path) {
893 node_path.push_back(
graph.Tail(arc_index));
895 node_path.push_back(
graph.Head(arc_path.back()));
typename GraphType::NodeIndex NodeIndex
ConstrainedShortestPathsOnDagWrapper(const GraphType *graph, const std::vector< double > *arc_lengths, const std::vector< std::vector< double > > *arc_resources, absl::Span< const NodeIndex > topological_order, absl::Span< const NodeIndex > sources, absl::Span< const NodeIndex > destinations, const std::vector< double > *max_resources, int max_num_created_labels=1e9)
PathWithLength RunConstrainedShortestPathOnDag()
typename GraphType::ArcIndex ArcIndex
double LengthTo(NodeIndex node) const
Returns the length of the shortest path from node's source to node.
void RunShortestPathOnDag(absl::Span< const NodeIndex > sources)
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< typename GraphType::NodeIndex > NodePathImpliedBy(absl::Span< const typename GraphType::ArcIndex > arc_path, const GraphType &graph)
std::vector< int > GetInversePermutation(absl::Span< const int > permutation)
absl::Status TopologicalOrderIsValid(const GraphType &graph, absl::Span< const typename GraphType::NodeIndex > topological_order)
PathWithLength ConstrainedShortestPathsOnDag(const int num_nodes, absl::Span< const ArcWithLengthAndResources > arcs_with_length_and_resources, int source, int destination, const std::vector< double > &max_resources)
void Permute(const IntVector &permutation, Array *array_to_permute)
trees with all degrees equal to
std::vector< double > resources