Difference between revisions of "Boost/BGL/DijkstraComputePath"

From ProgrammingExamples
< Boost‎ | BGL
Jump to: navigation, search
(Created page with 'The Dijkstra algorithm in Boost computes the shortest path from a specified vertex to ALL other vertices in the graph. Many times we are interested in the path to one specific ve…')
 
 
(3 intermediate revisions by the same user not shown)
Line 4: Line 4:
 
<source lang="cpp">
 
<source lang="cpp">
 
#include <boost/config.hpp>
 
#include <boost/config.hpp>
#include <iostream>
 
#include <fstream>
 
  
#include <boost/graph/dijkstra_shortest_paths.hpp>
 
 
#include <boost/graph/adjacency_list.hpp>
 
#include <boost/graph/adjacency_list.hpp>
 +
#include <boost/graph/dijkstra_shortest_paths.hpp>
 +
#include <boost/graph/graph_traits.hpp>
 +
#include <boost/graph/iteration_macros.hpp>
 +
#include <boost/graph/properties.hpp>
  
typedef boost::property<boost::edge_weight_t, float> EdgeWeightProperty;
+
#include <boost/property_map/property_map.hpp>
  
typedef boost::adjacency_list < boost::listS, boost::vecS, boost::directedS,
+
#include <iostream>
  boost::no_property, EdgeWeightProperty > Graph;
+
#include <utility>
 
+
#include <vector>
typedef Graph::vertex_descriptor vertex_descriptor;
+
 
+
std::vector<unsigned int> GetShortestPath(Graph& g, vertex_descriptor start, vertex_descriptor end);
+
std::vector<unsigned int> ReverseVector(std::vector<unsigned int> &v);
+
  
 
int main(int, char *[])
 
int main(int, char *[])
 
{
 
{
 +
  typedef float Weight;
 +
  typedef boost::property<boost::edge_weight_t, Weight> WeightProperty;
 +
  typedef boost::property<boost::vertex_name_t, std::string> NameProperty;
 +
 +
  typedef boost::adjacency_list < boost::listS, boost::vecS, boost::directedS,
 +
    NameProperty, WeightProperty > Graph;
 +
 +
  typedef boost::graph_traits < Graph >::vertex_descriptor Vertex;
 +
 +
  typedef boost::property_map < Graph, boost::vertex_index_t >::type IndexMap;
 +
  typedef boost::property_map < Graph, boost::vertex_name_t >::type NameMap;
 +
 +
  typedef boost::iterator_property_map < Vertex*, IndexMap, Vertex, Vertex& > PredecessorMap;
 +
  typedef boost::iterator_property_map < Weight*, IndexMap, Weight, Weight& > DistanceMap;
 +
 +
 
   // Create a graph
 
   // Create a graph
 
   Graph g;
 
   Graph g;
    
+
 
   vertex_descriptor v0 = boost::add_vertex(g);
+
   // Add named vertices
   vertex_descriptor v1 = boost::add_vertex(g);
+
   Vertex v0 = boost::add_vertex(std::string("v0"), g);
   vertex_descriptor v2 = boost::add_vertex(g);
+
   Vertex v1 = boost::add_vertex(std::string("v1"), g);
   vertex_descriptor v3 = boost::add_vertex(g);
+
   Vertex v2 = boost::add_vertex(std::string("v2"), g);
 +
   Vertex v3 = boost::add_vertex(std::string("v3"), g);
  
 
   // Add weighted edges
 
   // Add weighted edges
   EdgeWeightProperty weight0(5);
+
   Weight weight0 = 5;
   boost::add_edge(v0, v1, weight0, g);
+
   Weight weight1 = 3;
 +
  Weight weight2 = 2;
 +
  Weight weight3 = 4;
  
   EdgeWeightProperty weight1(3);
+
   boost::add_edge(v0, v1, weight0, g);
 
   boost::add_edge(v1, v3, weight1, g);
 
   boost::add_edge(v1, v3, weight1, g);
 
 
  EdgeWeightProperty weight2(2);
 
 
   boost::add_edge(v0, v2, weight2, g);
 
   boost::add_edge(v0, v2, weight2, g);
 
 
  EdgeWeightProperty weight3(4);
 
 
   boost::add_edge(v2, v3, weight3, g);
 
   boost::add_edge(v2, v3, weight3, g);
 
+
 
 
   // At this point the graph is
 
   // At this point the graph is
   /*   v0
+
   /*   v0
      .
+
        .
      / \ 2
+
        / \ 2
    /  \
+
      /  \
    /    . v2
+
      /    . v2
  5/     \
+
    5/       \
  /       \ 4
+
    /         \ 4
/         \
+
  /           \
v1---------- v3
+
  v1----------- v3
 
       3
 
       3
 
   */
 
   */
  
 
   // Create things for Dijkstra
 
   // Create things for Dijkstra
   std::vector<vertex_descriptor> parents(boost::num_vertices(g)); // To store parents
+
   std::vector<Vertex> predecessors(boost::num_vertices(g)); // To store parents
   std::vector<int> distances(boost::num_vertices(g)); // To store distances
+
   std::vector<Weight> distances(boost::num_vertices(g)); // To store distances
  
   // Compute shortest paths from v0 to all vertices, and store the output in parents and distances
+
  IndexMap indexMap = boost::get(boost::vertex_index, g);
   boost::dijkstra_shortest_paths(g, v0, boost::predecessor_map(&parents[0]).distance_map(&distances[0]));
+
  PredecessorMap predecessorMap(&predecessors[0], indexMap);
 +
  DistanceMap distanceMap(&distances[0], indexMap);
 +
 
 +
   // Compute shortest paths from v0 to all vertices, and store the output in predecessors and distances
 +
   // boost::dijkstra_shortest_paths(g, v0, boost::predecessor_map(predecessorMap).distance_map(distanceMap));
 +
  // This is exactly the same as the above line - it is the idea of "named parameters" - you can pass the
 +
  // prdecessor map and the distance map in any order.
 +
  boost::dijkstra_shortest_paths(g, v0, boost::distance_map(distanceMap).predecessor_map(predecessorMap));
  
 
   // Output results
 
   // Output results
 
   std::cout << "distances and parents:" << std::endl;
 
   std::cout << "distances and parents:" << std::endl;
   boost::graph_traits < Graph >::vertex_iterator vertexIterator, vend;
+
   NameMap nameMap = boost::get(boost::vertex_name, g);
   for (boost::tie(vertexIterator, vend) = boost::vertices(g); vertexIterator != vend; ++vertexIterator)  
+
 
 +
   BGL_FORALL_VERTICES(v, g, Graph)
 
   {
 
   {
     std::cout << "distance(" << *vertexIterator << ") = " << distances[*vertexIterator] << ", ";
+
     std::cout << "distance(" << nameMap[v0] << ", " << nameMap[v] << ") = " << distanceMap[v] << ", ";
     std::cout << "parent(" << *vertexIterator << ") = " << parents[*vertexIterator] << std::endl;
+
     std::cout << "predecessor(" << nameMap[v] << ") = " << nameMap[predecessorMap[v]] << std::endl;
 
   }
 
   }
 +
 +
  // Extract a shortest path
 
   std::cout << std::endl;
 
   std::cout << std::endl;
 
 
  /*
 
  The output is:
 
  distance(0) = 0, parent(0) = 0
 
  distance(1) = 5, parent(1) = 0
 
  distance(2) = 2, parent(2) = 0
 
  distance(3) = 6, parent(3) = 2
 
 
 
  which means:
 
  the distance from v0 to v0 is 0 and it is reached directly
 
  the distance from v0 to v1 is 5 and it is reached directly
 
  the distance from v0 to v2 is 2 and it is reached directly
 
  the distance from v0 to v3 is 6 and it is reached via v2
 
  */
 
 
 
  std::vector<unsigned int> shortestPath = GetShortestPath(g, v0, v3);
 
 
 
  for(unsigned int i = 0; i < shortestPath.size(); ++i)
 
  {
 
    std::cout << shortestPath[i] << " ";
 
  }
 
  std::cout << std::endl;
 
 
 
  return EXIT_SUCCESS;
 
}
 
  
std::vector<unsigned int> GetShortestPath(Graph& g, Graph::vertex_descriptor start, Graph::vertex_descriptor end)
+
  typedef std::vector<Graph::edge_descriptor> PathType;
{
+
  // Create things for Dijkstra
+
  std::vector<vertex_descriptor> parents(boost::num_vertices(g)); // To store parents
+
  std::vector<int> distances(boost::num_vertices(g)); // To store distances
+
  
   // Compute shortest paths from 'start' to all vertices, and store the output in parents and distances
+
   PathType path;
  boost::dijkstra_shortest_paths(g, start, boost::predecessor_map(&parents[0]).distance_map(&distances[0]));
+
  
   // Create a vector in which to store the path
+
   Vertex v = v3; // We want to start at the destination and work our way back to the source
  std::vector<unsigned int> shortestPath;
+
   for(Vertex u = predecessorMap[v]; // Start by setting 'u' to the destintaion node's predecessor
 
+
      u != v; // Keep tracking the path until we get to the source
  // Start at the end and work back to the beginning (aka Backtracking algorithm)
+
      v = u, u = predecessorMap[v]) // Set the current vertex to the current predecessor, and the predecessor to one level up
   vertex_descriptor currentVertex = end;
+
 
+
  std::cout << "Starting at " << currentVertex << " and looking for " << start << std::endl;
+
 
+
  while(parents[currentVertex] != start)
+
 
   {
 
   {
     std::cout << "currentVertex: " << currentVertex << std::endl;
+
     std::pair<Graph::edge_descriptor, bool> edgePair = boost::edge(u, v, g);
     std::cout << "current parent: " << parents[currentVertex] << std::endl;
+
     Graph::edge_descriptor edge = edgePair.first;
     shortestPath.push_back(currentVertex);
+
 
    currentVertex = parents[currentVertex];
+
     path.push_back( edge );
 
   }
 
   }
 
 
  // The next to last vertex will not be added (one after 'start'), so add it manually
 
  shortestPath.push_back(currentVertex);
 
 
 
  // Add the 'start' vertex to the path
 
  shortestPath.push_back(start);
 
 
 
  return ReverseVector(shortestPath);
 
}
 
  
std::vector<unsigned int> ReverseVector(std::vector<unsigned int> &v)
+
  // Write shortest path
{
+
  std::cout << "Shortest path from v0 to v3:" << std::endl;
  std::vector<unsigned int> result;
+
   float totalDistance = 0;
    
+
   for(PathType::reverse_iterator pathIterator = path.rbegin(); pathIterator != path.rend(); ++pathIterator)
   for(int i = v.size() - 1; i >= 0; --i) // this is not unsigned because I'm not sure about the behavior of the comparison when it gets near zero
+
 
   {
 
   {
     result.push_back(v[i]);
+
     std::cout << nameMap[boost::source(*pathIterator, g)] << " -> " << nameMap[boost::target(*pathIterator, g)]
 +
              << " = " << boost::get( boost::edge_weight, g, *pathIterator ) << std::endl;
 +
 
 
   }
 
   }
    
+
 
   return result;
+
   std::cout << std::endl;
 +
 
 +
  std::cout << "Distance: " << distanceMap[v3] << std::endl;
 +
 
 +
   return EXIT_SUCCESS;
 
}
 
}
 +
 +
/*
 +
* Output:
 +
distances and parents:
 +
distance(v0, v0) = 0, predecessor(v0) = v0
 +
distance(v0, v1) = 5, predecessor(v1) = v0
 +
distance(v0, v2) = 2, predecessor(v2) = v0
 +
distance(v0, v3) = 6, predecessor(v3) = v2
 +
 +
Shortest path from v0 to v3:
 +
v0 -> v2 = 2
 +
v2 -> v3 = 4
 +
 +
Total distance: 6
 +
 +
*/
 
</source>
 
</source>
  

Latest revision as of 08:52, 16 November 2011

The Dijkstra algorithm in Boost computes the shortest path from a specified vertex to ALL other vertices in the graph. Many times we are interested in the path to one specific vertex. The custom function GetShortestPath follows the 'parents' in the data returned by the Dijkstra algorithm to get the path of interest.

DijkstraComputePath.cpp

#include <boost/config.hpp>
 
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/graph/properties.hpp>
 
#include <boost/property_map/property_map.hpp>
 
#include <iostream>
#include <utility>
#include <vector>
 
int main(int, char *[])
{
  typedef float Weight;
  typedef boost::property<boost::edge_weight_t, Weight> WeightProperty;
  typedef boost::property<boost::vertex_name_t, std::string> NameProperty;
 
  typedef boost::adjacency_list < boost::listS, boost::vecS, boost::directedS,
    NameProperty, WeightProperty > Graph;
 
  typedef boost::graph_traits < Graph >::vertex_descriptor Vertex;
 
  typedef boost::property_map < Graph, boost::vertex_index_t >::type IndexMap;
  typedef boost::property_map < Graph, boost::vertex_name_t >::type NameMap;
 
  typedef boost::iterator_property_map < Vertex*, IndexMap, Vertex, Vertex& > PredecessorMap;
  typedef boost::iterator_property_map < Weight*, IndexMap, Weight, Weight& > DistanceMap;
 
 
  // Create a graph
  Graph g;
 
  // Add named vertices
  Vertex v0 = boost::add_vertex(std::string("v0"), g);
  Vertex v1 = boost::add_vertex(std::string("v1"), g);
  Vertex v2 = boost::add_vertex(std::string("v2"), g);
  Vertex v3 = boost::add_vertex(std::string("v3"), g);
 
  // Add weighted edges
  Weight weight0 = 5;
  Weight weight1 = 3;
  Weight weight2 = 2;
  Weight weight3 = 4;
 
  boost::add_edge(v0, v1, weight0, g);
  boost::add_edge(v1, v3, weight1, g);
  boost::add_edge(v0, v2, weight2, g);
  boost::add_edge(v2, v3, weight3, g);
 
  // At this point the graph is
  /*    v0
         .
        / \ 2
       /   \
      /     . v2
    5/       \
    /         \ 4
   /           \
  v1----------- v3
      3
  */
 
  // Create things for Dijkstra
  std::vector<Vertex> predecessors(boost::num_vertices(g)); // To store parents
  std::vector<Weight> distances(boost::num_vertices(g)); // To store distances
 
  IndexMap indexMap = boost::get(boost::vertex_index, g);
  PredecessorMap predecessorMap(&predecessors[0], indexMap);
  DistanceMap distanceMap(&distances[0], indexMap);
 
  // Compute shortest paths from v0 to all vertices, and store the output in predecessors and distances
  // boost::dijkstra_shortest_paths(g, v0, boost::predecessor_map(predecessorMap).distance_map(distanceMap));
  // This is exactly the same as the above line - it is the idea of "named parameters" - you can pass the
  // prdecessor map and the distance map in any order.
  boost::dijkstra_shortest_paths(g, v0, boost::distance_map(distanceMap).predecessor_map(predecessorMap));
 
  // Output results
  std::cout << "distances and parents:" << std::endl;
  NameMap nameMap = boost::get(boost::vertex_name, g);
 
  BGL_FORALL_VERTICES(v, g, Graph)
  {
    std::cout << "distance(" << nameMap[v0] << ", " << nameMap[v] << ") = " << distanceMap[v] << ", ";
    std::cout << "predecessor(" << nameMap[v] << ") = " << nameMap[predecessorMap[v]] << std::endl;
  }
 
  // Extract a shortest path
  std::cout << std::endl;
 
  typedef std::vector<Graph::edge_descriptor> PathType;
 
  PathType path;
 
  Vertex v = v3; // We want to start at the destination and work our way back to the source
  for(Vertex u = predecessorMap[v]; // Start by setting 'u' to the destintaion node's predecessor
      u != v; // Keep tracking the path until we get to the source
      v = u, u = predecessorMap[v]) // Set the current vertex to the current predecessor, and the predecessor to one level up
  {
    std::pair<Graph::edge_descriptor, bool> edgePair = boost::edge(u, v, g);
    Graph::edge_descriptor edge = edgePair.first;
 
    path.push_back( edge );
  }
 
  // Write shortest path
  std::cout << "Shortest path from v0 to v3:" << std::endl;
  float totalDistance = 0;
  for(PathType::reverse_iterator pathIterator = path.rbegin(); pathIterator != path.rend(); ++pathIterator)
  {
    std::cout << nameMap[boost::source(*pathIterator, g)] << " -> " << nameMap[boost::target(*pathIterator, g)]
              << " = " << boost::get( boost::edge_weight, g, *pathIterator ) << std::endl;
 
  }
 
  std::cout << std::endl;
 
  std::cout << "Distance: " << distanceMap[v3] << std::endl;
 
  return EXIT_SUCCESS;
}
 
/*
 * Output:
distances and parents:
distance(v0, v0) = 0, predecessor(v0) = v0
distance(v0, v1) = 5, predecessor(v1) = v0
distance(v0, v2) = 2, predecessor(v2) = v0
distance(v0, v3) = 6, predecessor(v3) = v2
 
Shortest path from v0 to v3:
v0 -> v2 = 2
v2 -> v3 = 4
 
Total distance: 6
 
*/

CMakeLists.txt

cmake_minimum_required(VERSION 2.6)
 
Project(DijkstraComputePath)
 
set(Boost_USE_MULTITHREADED ON)
FIND_PACKAGE(Boost 1.38 COMPONENTS program_options required)
 
INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES} ${Boost_INCLUDE_DIRS})
LINK_DIRECTORIES(${LINK_DIRECTORIES} ${Boost_LIBRARY_DIRS})
 
ADD_EXECUTABLE(DijkstraComputePath DijkstraComputePath.cpp)