21#include "absl/container/flat_hash_map.h"
22#include "absl/functional/bind_front.h"
23#include "absl/log/check.h"
24#include "absl/types/span.h"
51 virtual void Initialize(
const std::vector<NodeIndex>& sources,
52 const std::vector<NodeIndex>& destinations,
78 std::vector<NodeIndex>* path)
const = 0;
88 NodeIndex from,
const std::vector<NodeIndex>& predecessor_in_path_tree,
89 const std::vector<PathDistance>& distance_to_destination) = 0;
107 PathTree() : nodes_(), parents_() {}
109 void Initialize(absl::Span<const NodeIndex> paths,
110 absl::Span<const NodeIndex> destinations);
120 std::vector<NodeIndex>* path)
const;
123 std::vector<NodeIndex> nodes_;
124 std::vector<int> parents_;
130void PathTree::Initialize(absl::Span<const NodeIndex> paths,
131 absl::Span<const NodeIndex> destinations) {
132 const NodeIndex kNilNode = StarGraph::kNilNode;
133 std::vector<bool> node_explored(paths.size(),
false);
134 const int destination_size = destinations.size();
135 typedef std::pair<NodeIndex, NodeIndex> NodeParent;
136 std::vector<NodeParent> tree;
137 for (
int i = 0; i < destination_size; ++i) {
138 NodeIndex destination = destinations[i];
139 while (!node_explored[destination]) {
140 node_explored[destination] =
true;
141 tree.push_back(std::make_pair(destination, paths[destination]));
142 if (paths[destination] != kNilNode) {
143 destination = paths[destination];
147 std::sort(tree.begin(), tree.end());
148 const int num_nodes = tree.size();
152 absl::flat_hash_map<NodeIndex, int> node_indices;
154 for (
int i = 0;
i < num_nodes; ++
i) {
155 node_indices[tree[
i].first] =
i;
157 parents_.resize(num_nodes, -1);
158 for (
int i = 0;
i < num_nodes; ++
i) {
159 if (tree[i].second == kNilNode) {
161 parents_[
i] = kNilNode;
168 nodes_.resize(num_nodes, kNilNode);
169 for (
int i = 0;
i < num_nodes; ++
i) {
170 nodes_[
i] = tree[
i].first;
175 std::vector<NodeIndex>::const_iterator node_position =
176 std::lower_bound(nodes_.begin(), nodes_.end(), node);
177 if (node_position != nodes_.end() && *node_position == node) {
178 const int parent = parents_[node_position - nodes_.begin()];
179 if (parent != StarGraph::kNilNode) {
180 return nodes_[parent];
183 return StarGraph::kNilNode;
187 std::vector<NodeIndex>* path)
const {
188 DCHECK(path !=
nullptr);
190 std::vector<NodeIndex>::const_iterator to_position =
191 std::lower_bound(nodes_.begin(), nodes_.end(),
to);
192 if (to_position != nodes_.end() && *to_position ==
to) {
193 int current_index = to_position - nodes_.begin();
195 while (current_node != from) {
196 path->push_back(current_node);
197 current_index = parents_[current_index];
199 if (current_index == StarGraph::kNilNode) {
203 current_node = nodes_[current_index];
205 path->push_back(current_node);
206 std::reverse(path->begin(), path->end());
211class DistanceContainer :
public PathContainerImpl {
216 DistanceContainer(
const DistanceContainer&) =
delete;
217 DistanceContainer& operator=(
const DistanceContainer&) =
delete;
218 ~DistanceContainer()
override {}
219 void Initialize(
const std::vector<NodeIndex>& sources,
220 const std::vector<NodeIndex>& destinations,
221 NodeIndex num_nodes)
override {
225 distances_.resize(sources.size());
227 PathDistance GetDistance(NodeIndex from, NodeIndex
to)
const override {
230 NodeIndex GetPenultimateNodeInPath(NodeIndex from,
231 NodeIndex
to)
const override {
235 LOG(FATAL) <<
"Path not stored.";
236 return StarGraph::kNilNode;
238 void GetPath(NodeIndex from, NodeIndex
to,
239 std::vector<NodeIndex>* path)
const override {
244 LOG(FATAL) <<
"Path not stored.";
246 void StoreSingleSourcePaths(
247 NodeIndex from,
const std::vector<NodeIndex>& predecessor_in_path_tree,
248 const std::vector<PathDistance>& distance_to_destination)
override {
250 (void)predecessor_in_path_tree;
260 static void ComputeReverse(absl::Span<const NodeIndex>
nodes,
262 std::vector<int>* reverse_nodes) {
263 CHECK(reverse_nodes !=
nullptr);
264 const int kUnassignedIndex = -1;
265 reverse_nodes->clear();
266 reverse_nodes->resize(num_nodes, kUnassignedIndex);
267 for (
int i = 0; i <
nodes.size(); ++i) {
268 reverse_nodes->at(
nodes[i]) = i;
272 std::vector<std::vector<PathDistance> > distances_;
276class InMemoryCompactPathContainer :
public DistanceContainer {
278 InMemoryCompactPathContainer() : trees_(), destinations_() {}
281 InMemoryCompactPathContainer(
const InMemoryCompactPathContainer&) =
delete;
282 InMemoryCompactPathContainer& operator=(
const InMemoryCompactPathContainer&) =
284 ~InMemoryCompactPathContainer()
override {}
285 void Initialize(
const std::vector<NodeIndex>& sources,
286 const std::vector<NodeIndex>& destinations,
287 NodeIndex num_nodes)
override {
288 DistanceContainer::Initialize(sources, destinations, num_nodes);
289 destinations_ = destinations;
291 trees_.resize(sources.size());
293 NodeIndex GetPenultimateNodeInPath(NodeIndex from,
294 NodeIndex
to)
const override {
297 void GetPath(NodeIndex from, NodeIndex
to,
298 std::vector<NodeIndex>* path)
const override {
299 DCHECK(path !=
nullptr);
302 void StoreSingleSourcePaths(
303 NodeIndex from,
const std::vector<NodeIndex>& predecessor_in_path_tree,
304 const std::vector<PathDistance>& distance_to_destination)
override {
305 DistanceContainer::StoreSingleSourcePaths(from, predecessor_in_path_tree,
306 distance_to_destination);
312 std::vector<PathTree> trees_;
313 std::vector<NodeIndex> destinations_;
324 is_destination_(
false) {}
325 bool operator<(
const NodeEntry& other)
const {
326 return distance_ > other.distance_;
328 void SetHeapIndex(
int h) { heap_index_ = h; }
329 int GetHeapIndex()
const {
return heap_index_; }
332 void set_node(NodeIndex node) { node_ = node; }
334 void set_settled(
bool settled) { settled_ = settled; }
335 bool settled()
const {
return settled_; }
336 void set_is_destination(
bool is_destination) {
337 is_destination_ = is_destination;
339 bool is_destination()
const {
return is_destination_; }
346 bool is_destination_;
354 DCHECK(priority_queue !=
nullptr);
355 DCHECK(entry !=
nullptr);
356 if (!priority_queue->
Contains(entry)) {
358 priority_queue->
Add(entry);
371static_assert(
sizeof(NodeEntry) == 16,
"node_entry_class_is_not_well_packed");
377template <
class GraphType>
378void ComputeOneToManyInternalOnGraph(
379 const GraphType*
const graph,
380 const std::vector<PathDistance>*
const arc_lengths,
381 typename GraphType::NodeIndex source,
382 const std::vector<typename GraphType::NodeIndex>*
const destinations,
383 PathContainerImpl*
const paths) {
384 CHECK(
graph !=
nullptr);
386 CHECK(destinations !=
nullptr);
387 CHECK(paths !=
nullptr);
388 const int num_nodes =
graph->num_nodes();
389 std::vector<typename GraphType::NodeIndex> predecessor(num_nodes, -1);
391 std::vector<NodeEntry> entries(num_nodes);
392 for (
const typename GraphType::NodeIndex node :
graph->AllNodes()) {
393 entries[node].set_node(node);
397 for (
int i = 0;
i < destinations->size(); ++
i) {
398 entries[(*destinations)[
i]].set_is_destination(
true);
404 for (
const typename GraphType::ArcIndex
arc :
graph->OutgoingArcs(source)) {
405 const typename GraphType::NodeIndex
next =
graph->Head(
arc);
408 predecessor[
next] = source;
411 int destinations_remaining = destinations->size();
412 while (!priority_queue.
IsEmpty()) {
413 NodeEntry* current = priority_queue.
Top();
414 const typename GraphType::NodeIndex current_node = current->node();
415 priority_queue.
Pop();
416 current->set_settled(
true);
417 if (current->is_destination()) {
418 destinations_remaining--;
419 if (destinations_remaining == 0) {
423 const PathDistance current_distance = current->distance();
424 for (
const typename GraphType::ArcIndex
arc :
425 graph->OutgoingArcs(current_node)) {
426 const typename GraphType::NodeIndex
next =
graph->Head(
arc);
427 NodeEntry*
const entry = &entries[
next];
428 if (!entry->settled()) {
429 DCHECK_GE(current_distance, 0);
432 if (InsertOrUpdateEntry(current_distance + arc_length, entry,
434 predecessor[
next] = current_node;
439 const int destinations_size = destinations->size();
440 std::vector<PathDistance> distances(destinations_size,
442 for (
int i = 0;
i < destinations_size; ++
i) {
444 if (entries[node].settled()) {
445 distances[
i] = entries[node].distance();
448 paths->StoreSingleSourcePaths(source, predecessor, distances);
457 DCHECK(container_ !=
nullptr);
458 return container_->GetDistance(from,
to);
463 DCHECK(container_ !=
nullptr);
464 return container_->GetPenultimateNodeInPath(from,
to);
468 std::vector<NodeIndex>* path)
const {
469 DCHECK(container_ !=
nullptr);
470 DCHECK(path !=
nullptr);
471 container_->GetPath(from,
to, path);
475 return container_.get();
480 CHECK(path_container !=
nullptr);
481 path_container->container_ = std::make_unique<DistanceContainer>();
486 CHECK(path_container !=
nullptr);
487 path_container->container_ = std::make_unique<InMemoryCompactPathContainer>();
490template <
class GraphType>
493 const std::vector<typename GraphType::NodeIndex>& sources,
494 const std::vector<typename GraphType::NodeIndex>& destinations,
496 if (
graph.num_nodes() > 0) {
498 <<
"Number of arcs in graph must match arc length vector size";
501 std::vector<typename GraphType::NodeIndex> unique_sources = sources;
503 std::vector<typename GraphType::NodeIndex> unique_destinations =
509 container->
Initialize(unique_sources, unique_destinations,
512 std::unique_ptr<ThreadPool> pool(
514 pool->StartWorkers();
515 for (
int i = 0; i < unique_sources.size(); ++i) {
516 pool->Schedule(absl::bind_front(
518 unique_sources[i], &unique_destinations, container));
522 VLOG(2) <<
"Elapsed time to compute shortest paths: " << timer.
Get() <<
"s";
529 const std::vector<ListGraph<>::NodeIndex>& sources,
530 const std::vector<ListGraph<>::NodeIndex>& destinations,
int num_threads,
539 const std::vector<StaticGraph<>::NodeIndex>& sources,
540 const std::vector<StaticGraph<>::NodeIndex>& destinations,
int num_threads,
548 const ReverseArcListGraph<>&
graph,
550 const std::vector<ReverseArcListGraph<>::NodeIndex>& sources,
551 const std::vector<ReverseArcListGraph<>::NodeIndex>& destinations,
559 const ReverseArcStaticGraph<>&
graph,
561 const std::vector<ReverseArcStaticGraph<>::NodeIndex>& sources,
562 const std::vector<ReverseArcStaticGraph<>::NodeIndex>& destinations,
570 const ReverseArcMixedGraph<>&
graph,
572 const std::vector<ReverseArcMixedGraph<>::NodeIndex>& sources,
573 const std::vector<ReverseArcMixedGraph<>::NodeIndex>& destinations,
bool Contains(const T *val) const
void Pop()
If there are ties for the top, this returns all of them.
void NoteChangedPriority(T *val)
void Start()
When Start() is called multiple times, only the most recent is used.
virtual void Finalize()
Called when no more path will be added to the container.
virtual void StoreSingleSourcePaths(NodeIndex from, const std::vector< NodeIndex > &predecessor_in_path_tree, const std::vector< PathDistance > &distance_to_destination)=0
virtual void Initialize(const std::vector< NodeIndex > &sources, const std::vector< NodeIndex > &destinations, NodeIndex num_nodes)=0
virtual void GetPath(NodeIndex from, NodeIndex to, std::vector< NodeIndex > *path) const =0
Returns path nodes from node "from" to node "to" in a ordered vector.
virtual PathDistance GetDistance(NodeIndex from, NodeIndex to) const =0
virtual ~PathContainerImpl()
virtual NodeIndex GetPenultimateNodeInPath(NodeIndex from, NodeIndex to) const =0
static void BuildInMemoryCompactPathContainer(PathContainer *path_container)
NodeIndex GetPenultimateNodeInPath(NodeIndex from, NodeIndex to) const
void GetPath(NodeIndex from, NodeIndex to, std::vector< NodeIndex > *path) const
PathDistance GetDistance(NodeIndex from, NodeIndex to) const
static void BuildPathDistanceContainer(PathContainer *path_container)
Builds a path container which only stores distances between path nodes.
PathContainerImpl * GetImplementation() const
For internal use only. Returns the internal container implementation.
std::vector< double > arc_lengths
void STLSortAndRemoveDuplicates(T *v, const LessFunc &less_func)
const MapUtilMappedT< Collection > & FindWithDefault(const Collection &collection, const KeyType &key, const MapUtilMappedT< Collection > &value)
For infeasible and unbounded see Not checked if options check_solutions_if_inf_or_unbounded and the If options first_solution_only is false
problem is infeasible or unbounded (default).
In SWIG mode, we don't want anything besides these top-level includes.
const PathDistance kDisconnectedPathDistance
void ComputeManyToManyShortestPathsWithMultipleThreadsInternal(const GraphType &graph, const std::vector< PathDistance > &arc_lengths, const std::vector< typename GraphType::NodeIndex > &sources, const std::vector< typename GraphType::NodeIndex > &destinations, int num_threads, PathContainer *const paths)
void ComputeManyToManyShortestPathsWithMultipleThreads(const ListGraph<> &graph, const std::vector< PathDistance > &arc_lengths, const std::vector< ListGraph<>::NodeIndex > &sources, const std::vector< ListGraph<>::NodeIndex > &destinations, int num_threads, PathContainer *const path_container)
EbertGraph< NodeIndex, ArcIndex > StarGraph
trees with all degrees equal to
std::vector< int > reverse_destinations_
std::vector< int > reverse_sources_