Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
dag_shortest_path.cc
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
15
16#include <limits>
17#include <utility>
18#include <vector>
19
20#include "absl/log/check.h"
21#include "absl/types/span.h"
23#include "ortools/graph/graph.h"
25
26namespace operations_research {
27
28namespace {
29
30using GraphType = util::StaticGraph<>;
31using NodeIndex = GraphType::NodeIndex;
32using ArcIndex = GraphType::ArcIndex;
33
34struct ShortestPathOnDagProblem {
35 GraphType graph;
36 std::vector<double> arc_lengths;
37 std::vector<ArcIndex> original_arc_indices;
38 std::vector<NodeIndex> topological_order;
39};
40
41ShortestPathOnDagProblem ReadProblem(
42 const int num_nodes, absl::Span<const ArcWithLength> arcs_with_length) {
43 GraphType graph(num_nodes, arcs_with_length.size());
44 std::vector<double> arc_lengths;
45 arc_lengths.reserve(arcs_with_length.size());
46 for (const auto& arc : arcs_with_length) {
47 graph.AddArc(arc.from, arc.to);
48 arc_lengths.push_back(arc.length);
49 }
50 std::vector<ArcIndex> permutation;
51 graph.Build(&permutation);
52 util::Permute(permutation, &arc_lengths);
53
54 std::vector<ArcIndex> original_arc_indices(permutation.size());
55 if (!permutation.empty()) {
56 for (ArcIndex i = 0; i < permutation.size(); ++i) {
57 original_arc_indices[permutation[i]] = i;
58 }
59 }
60
61 absl::StatusOr<std::vector<NodeIndex>> topological_order =
63 CHECK_OK(topological_order) << "arcs_with_length form a cycle.";
64
65 return ShortestPathOnDagProblem{
66 .graph = std::move(graph),
67 .arc_lengths = std::move(arc_lengths),
68 .original_arc_indices = std::move(original_arc_indices),
69 .topological_order = std::move(topological_order).value()};
70}
71
72void GetOriginalArcPath(absl::Span<const ArcIndex> original_arc_indices,
73 std::vector<ArcIndex>& arc_path) {
74 if (original_arc_indices.empty()) {
75 return;
76 }
77 for (int i = 0; i < arc_path.size(); ++i) {
78 arc_path[i] = original_arc_indices[arc_path[i]];
79 }
80}
81
82} // namespace
83
85 const int num_nodes, absl::Span<const ArcWithLength> arcs_with_length,
86 const int source, const int destination) {
87 const ShortestPathOnDagProblem problem =
88 ReadProblem(num_nodes, arcs_with_length);
89
91 &problem.graph, &problem.arc_lengths, problem.topological_order);
92 shortest_path_on_dag.RunShortestPathOnDag({source});
93
94 if (!shortest_path_on_dag.IsReachable(destination)) {
95 return PathWithLength{.length = std::numeric_limits<double>::infinity()};
96 }
97
98 std::vector<int> arc_path = shortest_path_on_dag.ArcPathTo(destination);
99 GetOriginalArcPath(problem.original_arc_indices, arc_path);
100 return PathWithLength{
101 .length = shortest_path_on_dag.LengthTo(destination),
102 .arc_path = std::move(arc_path),
103 .node_path = shortest_path_on_dag.NodePathTo(destination)};
104}
105
106std::vector<PathWithLength> KShortestPathsOnDag(
107 const int num_nodes, absl::Span<const ArcWithLength> arcs_with_length,
108 const int source, const int destination, const int path_count) {
109 const ShortestPathOnDagProblem problem =
110 ReadProblem(num_nodes, arcs_with_length);
111
113 &problem.graph, &problem.arc_lengths, problem.topological_order,
114 path_count);
115 shortest_paths_on_dag.RunKShortestPathOnDag({source});
116
117 if (!shortest_paths_on_dag.IsReachable(destination)) {
118 return {PathWithLength{.length = std::numeric_limits<double>::infinity()}};
119 }
120
121 std::vector<double> lengths = shortest_paths_on_dag.LengthsTo(destination);
122 std::vector<std::vector<ArcIndex>> arc_paths =
123 shortest_paths_on_dag.ArcPathsTo(destination);
124 std::vector<std::vector<NodeIndex>> node_paths =
125 shortest_paths_on_dag.NodePathsTo(destination);
126 std::vector<PathWithLength> paths;
127 paths.reserve(lengths.size());
128 for (int k = 0; k < lengths.size(); ++k) {
129 GetOriginalArcPath(problem.original_arc_indices, arc_paths[k]);
130 paths.push_back(PathWithLength{.length = lengths[k],
131 .arc_path = std::move(arc_paths[k]),
132 .node_path = std::move(node_paths[k])});
133 }
134 return paths;
135}
136
137} // namespace operations_research
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
std::vector< double > LengthsTo(NodeIndex node) const
double LengthTo(NodeIndex node) const
Returns the length of the shortest path from node's source to node.
std::vector< ArcIndex > ArcPathTo(NodeIndex node) const
void RunShortestPathOnDag(absl::Span< const NodeIndex > sources)
std::vector< NodeIndex > NodePathTo(NodeIndex node) const
std::vector< ArcIndex > original_arc_indices
std::vector< NodeIndex > topological_order
std::vector< double > arc_lengths
GraphType graph
int arc
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)
PathWithLength ShortestPathsOnDag(const int num_nodes, absl::Span< const ArcWithLength > arcs_with_length, const int source, const int destination)
absl::StatusOr< std::vector< int > > FastTopologicalSort(const AdjacencyLists &adj)
void Permute(const IntVector &permutation, Array *array_to_permute)
Definition graph.h:758