14#ifndef OR_TOOLS_GRAPH_BIDIRECTIONAL_DIJKSTRA_H_ 
   15#define OR_TOOLS_GRAPH_BIDIRECTIONAL_DIJKSTRA_H_ 
   23#include "absl/base/thread_annotations.h" 
   24#include "absl/log/log.h" 
   25#include "absl/log/vlog_is_on.h" 
   26#include "absl/strings/str_cat.h" 
   27#include "absl/synchronization/mutex.h" 
   28#include "absl/synchronization/notification.h" 
   43template <
typename GraphType, 
typename DistanceType>
 
   57                        const std::vector<DistanceType>* forward_arc_lengths,
 
   58                        const GraphType* backward_graph,
 
   59                        const std::vector<DistanceType>* backward_arc_lengths);
 
  118                            const std::vector<NodeDistance>& destinations);
 
  132  inline static Direction Reverse(Direction d) {
 
  133    return d == FORWARD ? BACKWARD : FORWARD;
 
  136  inline static DistanceType infinity() {
 
  137    return std::numeric_limits<DistanceType>::infinity();
 
  140  template <Direction dir>
 
  141  void PerformHalfSearch(absl::Notification* search_has_ended);
 
  144  const GraphType* graph_[2];
 
  145  const std::vector<DistanceType>* arc_lengths_[2];
 
  148  std::priority_queue<NodeDistance> queue_[2];
 
  150  std::vector<bool> is_source_[2];
 
  151  std::vector<bool> is_reached_[2];
 
  155  std::vector<char> is_settled_[2];
 
  157  std::vector<DistanceType> distances_[2];
 
  158  std::vector<ArcIndex> parent_arc_[2];
 
  159  std::vector<NodeIndex> reached_nodes_[2];
 
  174  std::vector<absl::Mutex> node_mutex_;
 
  176  absl::Mutex search_mutex_;
 
  177  NodeDistance best_meeting_point_ ABSL_GUARDED_BY(search_mutex_);
 
  178  DistanceType current_search_radius_[2] ABSL_GUARDED_BY(search_mutex_);
 
  180  ThreadPool search_threads_;
 
 
  183template <
typename GraphType, 
typename DistanceType>
 
  185    const GraphType* forward_graph,
 
  186    const std::vector<DistanceType>* forward_arc_lengths,
 
  187    const GraphType* backward_graph,
 
  188    const std::vector<DistanceType>* backward_arc_lengths)
 
  189    : node_mutex_(forward_graph->num_nodes()), search_threads_(2) {
 
  190  CHECK_EQ(forward_graph->num_nodes(), backward_graph->num_nodes());
 
  191  const int num_nodes = forward_graph->num_nodes();
 
  193  for (
int i = 0; i < num_nodes; ++i) {
 
  194    CHECK_GE((*forward_arc_lengths)[i], 0) << i;
 
  195    CHECK_GE((*backward_arc_lengths)[i], 0) << i;
 
  197  graph_[FORWARD] = forward_graph;
 
  198  graph_[BACKWARD] = backward_graph;
 
  199  arc_lengths_[FORWARD] = forward_arc_lengths;
 
  200  arc_lengths_[BACKWARD] = backward_arc_lengths;
 
  201  for (
const Direction dir : {FORWARD, BACKWARD}) {
 
  202    current_search_radius_[dir] = -infinity();
 
  203    is_source_[dir].assign(num_nodes, 
false);
 
  204    is_reached_[dir].assign(num_nodes, 
false);
 
  205    is_settled_[dir].assign(num_nodes, 
false);
 
  206    distances_[dir].assign(num_nodes, infinity());
 
  207    parent_arc_[dir].assign(num_nodes, -1);
 
  209  search_threads_.StartWorkers();
 
 
  212template <
typename GraphType, 
typename DistanceType>
 
  214    const Path& path)
 const {
 
  218    absl::StrAppend(&out, graph_[FORWARD]->Tail(arc), 
" --(#", arc, 
":",
 
  219                    ((*arc_lengths_[FORWARD])[arc]), 
")--> ");
 
  223    absl::StrAppend(&out, 
" <--(#", arc, 
":", ((*arc_lengths_[BACKWARD])[arc]),
 
  224                    ")-- ", graph_[BACKWARD]->Tail(arc));
 
 
  229template <
typename GraphType, 
typename DistanceType>
 
  230std::vector<typename GraphType::NodeIndex>
 
  235  std::vector<int> nodes;
 
  237    nodes.push_back(graph_[FORWARD]->Tail(arc));
 
  241    nodes.push_back(graph_[BACKWARD]->Tail(arc));
 
 
  246template <
typename GraphType, 
typename DistanceType>
 
  249    const std::vector<NodeDistance>& sources,
 
  250    const std::vector<NodeDistance>& destinations)
 
  254    ABSL_NO_THREAD_SAFETY_ANALYSIS {
 
  256    VLOG(2) << 
"Starting search with " << sources.size() << 
" sources and " 
  257            << destinations.size() << 
" destinations. Sources:";
 
  258    for (
const NodeDistance& src : sources) VLOG(2) << src.DebugString();
 
  259    VLOG(2) << 
"Destinations:";
 
  260    for (
const NodeDistance& dst : destinations) VLOG(2) << dst.DebugString();
 
  262  if (sources.empty() || destinations.empty()) 
return {-1, {}, {}};
 
  264  for (
const Direction dir : {FORWARD, BACKWARD}) {
 
  265    const std::vector<NodeDistance>& srcs =
 
  266        dir == FORWARD ? sources : destinations;
 
  267    CHECK(queue_[dir].empty());
 
  268    QCHECK_EQ(reached_nodes_[dir].size(), 0);
 
  270      for (
bool b : is_reached_[dir]) QCHECK(!b);
 
  271      for (
bool b : is_settled_[dir]) QCHECK(!b);
 
  274      CHECK_GE(src.node, 0);
 
  275      CHECK_LT(src.node, graph_[dir]->num_nodes());
 
  276      is_source_[dir][src.node] = 
true;
 
  277      if (!is_reached_[dir][src.node]) {
 
  278        is_reached_[dir][src.node] = 
true;
 
  279        reached_nodes_[dir].push_back(src.node);
 
  280        parent_arc_[dir][src.node] = -1;
 
  281      } 
else if (src.distance >= distances_[dir][src.node]) {
 
  286      distances_[dir][src.node] = src.distance;
 
  287      queue_[dir].push(src);
 
  292  best_meeting_point_ = {-1, infinity()};
 
  293  absl::Notification search_has_ended[2];
 
  294  search_threads_.Schedule([
this, &search_has_ended, &sources]() {
 
  295    PerformHalfSearch<FORWARD>(&search_has_ended[FORWARD]);
 
  297  search_threads_.Schedule([
this, &search_has_ended, &destinations]() {
 
  298    PerformHalfSearch<BACKWARD>(&search_has_ended[BACKWARD]);
 
  302  search_has_ended[FORWARD].WaitForNotification();
 
  303  search_has_ended[BACKWARD].WaitForNotification();
 
  312  for (
const Direction dir : {FORWARD, BACKWARD}) {
 
  313    current_search_radius_[dir] = -infinity();
 
  314    for (
const int node : reached_nodes_[dir]) {
 
  315      is_reached_[dir][node] = 
false;
 
  316      is_settled_[dir][node] = 
false;
 
  318    reached_nodes_[dir].clear();
 
  321    is_source_[FORWARD][src.node] = 
false;
 
  324    is_source_[BACKWARD][dst.node] = 
false;
 
  328  Path path = {best_meeting_point_.node, {}, {}};
 
  331  for (
const Direction dir : {FORWARD, BACKWARD}) {
 
  333    std::vector<int>* arc_path =
 
  336      const int arc = parent_arc_[dir][node];
 
  338      arc_path->push_back(arc);
 
  339      node = graph_[dir]->Tail(arc);
 
  341    std::reverse(arc_path->begin(), arc_path->end());
 
 
  346template <
typename GraphType, 
typename DistanceType>
 
  348    typename BidirectionalDijkstra<GraphType, DistanceType>::Direction dir>
 
  349void BidirectionalDijkstra<GraphType, DistanceType>::PerformHalfSearch(
 
  350    absl::Notification* search_has_ended) {
 
  351  while (!queue_[dir].empty()) {
 
  352    const NodeDistance top = queue_[dir].top();
 
  357    if (is_settled_[dir][top.node]) 
continue;
 
  358    DVLOG(2) << (dir ? 
"BACKWARD" : 
"FORWARD") << 
": Popped " 
  359             << top.DebugString();
 
  365      node_mutex_[top.node].Lock();
 
  366      is_settled_[dir][top.node] = 
true;  
 
  370      if (is_source_[Reverse(dir)][top.node]) {
 
  371        const DistanceType meeting_distance =
 
  372            top.distance + distances_[Reverse(dir)][top.node];
 
  375        node_mutex_[top.node].Unlock();
 
  376        absl::MutexLock search_lock(&search_mutex_);
 
  377        if (meeting_distance < best_meeting_point_.distance) {
 
  378          best_meeting_point_ = {top.node, meeting_distance};
 
  379          DVLOG(2) << (dir ? 
"BACKWARD" : 
"FORWARD")
 
  380                   << 
": New best: " << best_meeting_point_.DebugString();
 
  383        node_mutex_[top.node].Unlock();
 
  389    DistanceType potentially_interesting_distance_upper_bound;
 
  391      absl::MutexLock lock(&search_mutex_);
 
  392      current_search_radius_[dir] = top.distance;
 
  393      potentially_interesting_distance_upper_bound =
 
  394          best_meeting_point_.distance - current_search_radius_[
Reverse(dir)];
 
  396    if (top.distance >= potentially_interesting_distance_upper_bound) {
 
  397      DVLOG(2) << (dir ? 
"BACKWARD" : 
"FORWARD") << 
": Stopping.";
 
  402    for (
const int arc : graph_[dir]->OutgoingArcs(top.node)) {
 
  403      const DistanceType candidate_distance =
 
  404          top.distance + (*arc_lengths_[dir])[arc];
 
  405      const int head = graph_[dir]->Head(arc);
 
  406      if (!is_reached_[dir][head] ||
 
  407          candidate_distance < distances_[dir][head]) {
 
  408        DVLOG(2) << (dir ? 
"BACKWARD" : 
"FORWARD") << 
": Pushing: " 
  409                 << NodeDistance({head, candidate_distance}).DebugString();
 
  410        if (!is_reached_[dir][head]) {
 
  411          is_reached_[dir][head] = 
true;
 
  412          reached_nodes_[dir].push_back(head);
 
  414        parent_arc_[dir][head] = arc;
 
  422        if (candidate_distance < potentially_interesting_distance_upper_bound) {
 
  423          queue_[dir].push({head, candidate_distance});
 
  428        DistanceType meeting_distance = infinity();
 
  430          absl::MutexLock node_lock(&node_mutex_[head]);
 
  431          distances_[dir][head] = candidate_distance;
 
  433          if (is_settled_[
Reverse(dir)][head]) {
 
  435                candidate_distance + distances_[
Reverse(dir)][head];
 
  436            DVLOG(2) << (dir ? 
"BACKWARD" : 
"FORWARD")
 
  437                     << 
": Found meeting point!";
 
  443        if (meeting_distance != infinity()) {
 
  444          absl::MutexLock search_lock(&search_mutex_);
 
  445          if (meeting_distance < best_meeting_point_.distance) {
 
  446            best_meeting_point_ = {head, meeting_distance};
 
  447            DVLOG(2) << (dir ? 
"BACKWARD" : 
"FORWARD")
 
  448                     << 
": New best: " << best_meeting_point_.DebugString();
 
  454  DVLOG(2) << (dir ? 
"BACKWARD" : 
"FORWARD") << 
": Done. Cleaning up...";
 
  457  while (!queue_[dir].empty()) queue_[dir].pop();
 
  460  search_has_ended->Notify();
 
GraphType::NodeIndex NodeIndex
 
GraphType::ArcIndex ArcIndex
 
std::string PathDebugString(const Path &path) const
 
Path SetToSetShortestPath(const std::vector< NodeDistance > &sources, const std::vector< NodeDistance > &destinations)
 
std::vector< NodeIndex > PathToNodePath(const Path &path) const
 
Path OneToOneShortestPath(NodeIndex from, NodeIndex to)
 
BidirectionalDijkstra(const GraphType *forward_graph, const std::vector< DistanceType > *forward_arc_lengths, const GraphType *backward_graph, const std::vector< DistanceType > *backward_arc_lengths)
 
ReverseView< Container > reversed_view(const Container &c)
 
In SWIG mode, we don't want anything besides these top-level includes.
 
BeginEndReverseIteratorWrapper< Container > Reverse(const Container &c)
 
trees with all degrees equal to
 
bool operator<(const NodeDistance &other) const
 
std::string DebugString() const
 
std::vector< ArcIndex > backward_arc_path
 
std::vector< ArcIndex > forward_arc_path
 
NodeIndex meeting_point
The node where the two half-paths meet. -1 if no path exists.