7

I'm using boost::graph and its Dijkstra implementation.

When someone is using the Dijkstra algorithm, it may be to know the shortest path between 2 nodes in a graph. But as you need to check all nodes in the graph to find the shortest path, usually (like the boost algorithm) Dijkstra gives you back all the distances between one origin point, and all the other nodes of the graph.

One easy improvement of this algorithm when you only want the path between 2 nodes is to stop it when the algorithm reach the destination node. Then, you are sure that the distance that you have for this final destination node is the shortest one.

How can one tell the boost Dijkstra algorithm to stop when it reaches a specific node ?

Emmanuel Jay
  • 484
  • 3
  • 10

2 Answers2

7

You can throw an exception from the visitor: FAQ

How do I perform an early exit from an algorithm such as BFS?

Create a visitor that throws an exception when you want to cut off the search, then put your call to breadth_first_search inside of an appropriate try/catch block. This strikes many programmers as a misuse of exceptions, however, much thought was put into the decision to have exceptions has the preferred way to exit early. See boost email discussions for more details.

Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Can you do such a thing (try-catch block) in c++ ? I thought that Visitors were the way to go, but as always, it is a bit hard to implement boost concepts. (Are you a god sehe btw, did you code boost ?) EDIT : I'm a morron, it's basic structure in c++ ... ^^" sorry. – Emmanuel Jay Aug 17 '15 at 11:43
  • It's pretty easy to implement BGL visitors. The docs contain samples of that (as do the ... example programs). – sehe Aug 17 '15 at 11:44
6

Thanks to Sehe and his insights, I followed the road of the Dijkstra Visitors to solve my problem. Here is the solution :

I created a visitor class that came from the Dijkstra's visitor types :

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>

// Graph Definitions
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
typedef boost::graph_traits<Graph>::edge_descriptor Edge;

// Visitor that throw an exception when finishing the destination vertex
class my_visitor : boost::default_bfs_visitor{
protected:
  Vertex destination_vertex_m;
public:
  my_visitor(Vertex destination_vertex_l)
    : destination_vertex_m(destination_vertex_l) {};

  void initialize_vertex(const Vertex &s, const Graph &g) const {}
  void discover_vertex(const Vertex &s, const Graph &g) const {}
  void examine_vertex(const Vertex &s, const Graph &g) const {}
  void examine_edge(const Edge &e, const Graph &g) const {}
  void edge_relaxed(const Edge &e, const Graph &g) const {}
  void edge_not_relaxed(const Edge &e, const Graph &g) const {}
  void finish_vertex(const Vertex &s, const Graph &g) const {
    if (destination_vertex_m == s)
      throw(2);
  }
};

And then I launched Boost Dijkstra with a try-catch block to get the exception

// To store predecessor
std::vector<Vertex> predecessor_map_p (boost::num_vertices(graph_m)); 
// To store distances
std::vector<double> distance_map_p (boost::num_vertices(graph_m)); 
// Vertex that will have set to the origin and the destination :
Vertex vertex_origin_num_p,vertex_destination_num_p;

// Visitor to throw an exception when the end is reached
my_visitor vis(vertex_destination_num_p);

try {
  boost::dijkstra_shortest_paths(
    graph_m, 
    vertex_origin_num_p,
    predecessor_map(boost::make_iterator_property_map(predecessor_map_p->data(), vid_l)).
    distance_map(boost::make_iterator_property_map(distance_map_p->data(), vid_l)).
    visitor(vis)
  );
}
catch (int exception) {
  std::cout << "The Dijsktra algorithm stopped" << std::endl;
}
mando
  • 135
  • 1
  • 8
Emmanuel Jay
  • 484
  • 3
  • 10
  • Wow. I'm a bit miffed how you chose to _unaccept_ the answer there. You could have posted this as a comment to the answer. I mean, you didn't even post a single line of code in the question (otherwise I'd have shown the code for you!) – sehe Aug 19 '15 at 17:02
  • @sehe True. I thought an example of how to make the thing work was useful ... my bad, god of Boost Graph ;) I have another question for you : What if you want to make the visitor modify something ? It seems it is a const function... – Emmanuel Jay Aug 20 '15 at 08:56
  • Oh yeah, an example is useful. Let me upvote for that alone :) (it was just a bit strange to post a "better" answer, which is only better because it uses information not present in the question). Thanks – sehe Aug 20 '15 at 09:16
  • On modifying: the usual approach is to keep a reference to the variables to be modified. PropertyMaps have embraced this so fully, that all property maps are - by definition - logically references. A -possible- alternative idiom would be to pass `boost::ref(my_visitor)` (but I'm not sure it works, haven't used it in this context). In any case, this idiom usually works for function objects because `reference_wrapper` forwards the function call operator – sehe Aug 20 '15 at 09:18
  • @sehe Ok, I will be honest, it seems way behond my comprehension of the boost concepts... And as my intership is over today, I won't ask you for more ;) . Thank you for everything you did ! I learned a lot from you ! – Emmanuel Jay Aug 21 '15 at 10:46
  • Cheers for that, appreciated. I hope you had fun learning and I'm sure you did a good job! – sehe Aug 21 '15 at 10:58