7070#include " absl/types/span.h"
7171#include " ortools/base/logging.h"
7272#include " ortools/graph/bounded_dijkstra.h"
73- #include " ortools/graph/ebert_graph.h"
7473#include " ortools/graph/shortest_paths.h"
7574
7675namespace operations_research {
@@ -82,14 +81,15 @@ namespace operations_research {
8281// The paths in `paths` start with `origin` and end at `destination`.
8382//
8483// If the computations are unsuccessful for any reason, the vectors are empty.
84+ template <class GraphType >
8585struct KShortestPaths {
8686 // The paths are stored as vectors of nodes, like the other graph algorithms.
8787 // TODO(user): what about vectors of arcs? That might be faster
8888 // (potentially, add a function to transform it into a vector of nodes if the
8989 // user really needs it). It would also have the nice benefit of removing the
9090 // need for `distances` (compute it on the fly), with a reference to the graph
9191 // and the costs.
92- std::vector<std::vector<NodeIndex>> paths;
92+ std::vector<std::vector<typename GraphType:: NodeIndex>> paths;
9393 std::vector<PathDistance> distances;
9494};
9595
@@ -113,10 +113,10 @@ struct KShortestPaths {
113113// Science. 17 (11): 712–716, 1971.
114114// https://doi.org/10.1287%2Fmnsc.17.11.712
115115template <class GraphType >
116- KShortestPaths YenKShortestPaths (const GraphType& graph,
117- const std::vector<PathDistance>& arc_lengths,
118- NodeIndex source, NodeIndex destination ,
119- unsigned k);
116+ KShortestPaths<GraphType> YenKShortestPaths (
117+ const GraphType& graph, const std::vector<PathDistance>& arc_lengths,
118+ typename GraphType:: NodeIndex source,
119+ typename GraphType::NodeIndex destination, unsigned k);
120120
121121// End of the interface. Below is the implementation.
122122
@@ -137,23 +137,26 @@ const PathDistance kDisconnectedDistance =
137137// In a multigraph, this function returns an index for one of the edges between
138138// the source and the destination.
139139template <class GraphType >
140- ArcIndex FindArcIndex (const GraphType& graph, const NodeIndex source,
141- const NodeIndex destination) {
140+ typename GraphType::ArcIndex FindArcIndex (
141+ const GraphType& graph, const typename GraphType::NodeIndex source,
142+ const typename GraphType::NodeIndex destination) {
142143 const auto outgoing_arcs_iter = graph.OutgoingArcs (source);
143- const auto arc =
144- std::find_if ( outgoing_arcs_iter.begin (), outgoing_arcs_iter.end (),
145- [&graph, destination](const ArcIndex arc) {
146- return graph.Head (arc) == destination;
147- });
144+ const auto arc = std::find_if (
145+ outgoing_arcs_iter.begin (), outgoing_arcs_iter.end (),
146+ [&graph, destination](const typename GraphType:: ArcIndex arc) {
147+ return graph.Head (arc) == destination;
148+ });
148149 return (arc != outgoing_arcs_iter.end ()) ? *arc : GraphType::kNilArc ;
149150}
150151
151152// Determines the shortest path from the given source and destination, returns a
152153// tuple with the path (as a vector of node indices) and its cost.
153154template <class GraphType >
154- std::tuple<std::vector<NodeIndex>, PathDistance> ComputeShortestPath (
155- const GraphType& graph, const std::vector<PathDistance>& arc_lengths,
156- const NodeIndex source, const NodeIndex destination) {
155+ std::tuple<std::vector<typename GraphType::NodeIndex>, PathDistance>
156+ ComputeShortestPath (const GraphType& graph,
157+ const std::vector<PathDistance>& arc_lengths,
158+ const typename GraphType::NodeIndex source,
159+ const typename GraphType::NodeIndex destination) {
157160 BoundedDijkstraWrapper<GraphType, PathDistance> dijkstra (&graph,
158161 &arc_lengths);
159162 dijkstra.RunBoundedDijkstra (source, kMaxDistance );
@@ -165,25 +168,29 @@ std::tuple<std::vector<NodeIndex>, PathDistance> ComputeShortestPath(
165168 // This case only happens when some arcs have an infinite length (i.e.
166169 // larger than `kMaxDistance`): `BoundedDijkstraWrapper::NodePathTo` fails
167170 // to return a path, even empty.
168- return {std::vector<NodeIndex>{}, kDisconnectedDistance };
171+ return {std::vector<typename GraphType::NodeIndex>{},
172+ kDisconnectedDistance };
169173 }
170174
171- if (std::vector<NodeIndex> path = std::move (dijkstra.NodePathTo (destination));
175+ if (std::vector<typename GraphType::NodeIndex> path =
176+ std::move (dijkstra.NodePathTo (destination));
172177 !path.empty ()) {
173178 return {std::move (path), path_length};
174179 } else {
175- return {std::vector<NodeIndex>{}, kDisconnectedDistance };
180+ return {std::vector<typename GraphType::NodeIndex>{},
181+ kDisconnectedDistance };
176182 }
177183}
178184
179185// Computes the total length of a path.
180186template <class GraphType >
181- PathDistance ComputePathLength (const GraphType& graph,
182- const absl::Span<const PathDistance> arc_lengths,
183- const absl::Span<const NodeIndex> path) {
187+ PathDistance ComputePathLength (
188+ const GraphType& graph, const absl::Span<const PathDistance> arc_lengths,
189+ const absl::Span<const typename GraphType:: NodeIndex> path) {
184190 PathDistance distance = 0 ;
185- for (NodeIndex i = 0 ; i < path.size () - 1 ; ++i) {
186- const ArcIndex arc = internal::FindArcIndex (graph, path[i], path[i + 1 ]);
191+ for (typename GraphType::NodeIndex i = 0 ; i < path.size () - 1 ; ++i) {
192+ const typename GraphType::ArcIndex arc =
193+ internal::FindArcIndex (graph, path[i], path[i + 1 ]);
187194 DCHECK_NE (arc, GraphType::kNilArc );
188195 distance += arc_lengths[arc];
189196 }
@@ -192,8 +199,11 @@ PathDistance ComputePathLength(const GraphType& graph,
192199
193200// Stores a path with a priority (typically, the distance), with a comparison
194201// operator that operates on the priority.
202+ template <class GraphType >
195203class PathWithPriority {
196204 public:
205+ using NodeIndex = typename GraphType::NodeIndex;
206+
197207 PathWithPriority (PathDistance priority, std::vector<NodeIndex> path)
198208 : path_(std::move(path)), priority_(priority) {}
199209 bool operator <(const PathWithPriority& other) const {
@@ -265,10 +275,12 @@ class UnderlyingContainerAdapter : public Container {
265275// spur paths, the cheapest being:
266276// S_1^2 = B - E - F - G - H
267277template <class GraphType >
268- KShortestPaths YenKShortestPaths (const GraphType& graph,
269- const std::vector<PathDistance>& arc_lengths,
270- NodeIndex source, NodeIndex destination,
271- unsigned k) {
278+ KShortestPaths<GraphType> YenKShortestPaths (
279+ const GraphType& graph, const std::vector<PathDistance>& arc_lengths,
280+ typename GraphType::NodeIndex source,
281+ typename GraphType::NodeIndex destination, unsigned k) {
282+ using NodeIndex = typename GraphType::NodeIndex;
283+
272284 CHECK_GT (internal::kDisconnectedDistance , internal::kMaxDistance );
273285
274286 CHECK_GE (k, 0 ) << " k must be nonnegative. Input value: " << k;
@@ -289,7 +301,7 @@ KShortestPaths YenKShortestPaths(const GraphType& graph,
289301 << destination
290302 << " . Number of nodes in the input graph: " << graph.num_nodes ();
291303
292- KShortestPaths paths;
304+ KShortestPaths<GraphType> paths;
293305
294306 // First step: compute the shortest path.
295307 {
@@ -306,7 +318,7 @@ KShortestPaths YenKShortestPaths(const GraphType& graph,
306318
307319 // Generate variant paths.
308320 internal::UnderlyingContainerAdapter<
309- std::priority_queue<internal::PathWithPriority>>
321+ std::priority_queue<internal::PathWithPriority<GraphType> >>
310322 variant_path_queue;
311323
312324 // One path has already been generated (the shortest one). Only k-1 more
@@ -364,7 +376,7 @@ KShortestPaths YenKShortestPaths(const GraphType& graph,
364376 previous_path.begin () + root_path.length ());
365377 if (!has_same_prefix_as_root_path) continue ;
366378
367- const ArcIndex after_spur_node_arc =
379+ const typename GraphType:: ArcIndex after_spur_node_arc =
368380 internal::FindArcIndex (graph, previous_path[spur_node_position],
369381 previous_path[spur_node_position + 1 ]);
370382 VLOG (4 ) << " after_spur_node_arc: " << graph.Tail (after_spur_node_arc)
@@ -417,8 +429,8 @@ KShortestPaths YenKShortestPaths(const GraphType& graph,
417429 // coincide at the spur node).
418430 const bool root_path_leads_to_spur_path = absl::c_any_of (
419431 graph.OutgoingArcs (root_path.back ()),
420- [&graph, node_after_spur_in_spur_path =
421- *(spur_path. begin () + 1 )]( const ArcIndex arc_index) {
432+ [&graph, node_after_spur_in_spur_path = *(spur_path. begin () + 1 )](
433+ const typename GraphType:: ArcIndex arc_index) {
422434 return graph.Head (arc_index) == node_after_spur_in_spur_path;
423435 });
424436 CHECK (root_path_leads_to_spur_path);
@@ -471,12 +483,12 @@ KShortestPaths YenKShortestPaths(const GraphType& graph,
471483 // filter by fingerprints? Due to the probability of error with
472484 // fingerprints, still use this slow-but-exact code, but after
473485 // filtering.
474- const bool is_new_path_already_known =
475- std::any_of ( variant_path_queue.container ().cbegin (),
476- variant_path_queue.container ().cend (),
477- [&new_path](const internal::PathWithPriority& element) {
478- return element.path () == new_path;
479- });
486+ const bool is_new_path_already_known = std::any_of (
487+ variant_path_queue.container ().cbegin (),
488+ variant_path_queue.container ().cend (),
489+ [&new_path](const internal::PathWithPriority<GraphType> & element) {
490+ return element.path () == new_path;
491+ });
480492 if (is_new_path_already_known) continue ;
481493
482494 const PathDistance path_length =
@@ -498,7 +510,7 @@ KShortestPaths YenKShortestPaths(const GraphType& graph,
498510 // this iteration found no shorter one.
499511 if (variant_path_queue.empty ()) break ;
500512
501- const internal::PathWithPriority& next_shortest_path =
513+ const internal::PathWithPriority<GraphType> & next_shortest_path =
502514 variant_path_queue.top ();
503515 VLOG (5 ) << " > New path generated: "
504516 << absl::StrJoin (next_shortest_path.path (), " - " ) << " ("
0 commit comments