Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dijkstra Shortest Path with VertexList = ListS in boost graph

I am quite new to Boost graph. I am trying to adapt an example for finding Dijkstra Shortest Path algorithm which used VertexList = vecS. I changed the vertex container to ListS. I learned that we have to provide our own vertex_index for the algorithm to work if we use listS.

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::property<boost::vertex_index_t, int> IndexProperty;

  typedef boost::adjacency_list < boost::listS, boost::listS, boost::directedS,
  NameProperty, WeightProperty > Graph;

  typedef boost::graph_traits < Graph >::vertex_descriptor Vertex;
  typedef boost::graph_traits <Graph>::vertex_iterator Viter;

  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;

  Graph g;


  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);

  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);


  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);
  NameMap name;
  Viter i, iend;
 //Create our own vertex index. This is what I changed in the original code
    int c = 0;
  for (boost::tie(i, iend) = vertices(g); i != iend; ++i, ++c) {
       indexMap[*i] = c; // **Error points to this line**
       name[*i] = 'A' + c;
  }
PredecessorMap predecessorMap(&predecessors[0], indexMap);
DistanceMap distanceMap(&distances[0], indexMap);
boost::dijkstra_shortest_paths(g, v0,   boost::distance_map(distanceMap).predecessor_map(predecessorMap));


  // Extract a shortest path
  std::cout << std::endl;
  typedef std::vector<Graph::edge_descriptor> PathType;
  PathType path;
  Vertex v = v3; 
  for(Vertex u = predecessorMap[v]; 
  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 << name[boost::source(*pathIterator, g)] << " -> " <<     name[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;
}

I get the following error:

/spvec.cpp:62:20: error: no match for ‘operator=’ in ‘index.boost::adj_list_vertex_property_map::operator[] [with Graph = boost::adjacency_list >, boost::property >, ValueType = boost::detail::error_property_not_found, Reference = boost::detail::error_property_not_found&, Tag = boost::vertex_index_t, boost::adj_list_vertex_property_map::key_type = void*](i.std::_List_iterator<_Tp>::operator* with _Tp = void*, _Tp& = void*&) = c’

I am sure I made a mistake in creating my own vertex index. But couldn´t find out exactly what´s the issue. Does anyone have some suggestions on what I am doing wrong..

like image 724
srkrish Avatar asked Aug 23 '11 06:08

srkrish


People also ask

Does Dijkstra work with 0 weights?

Dijkstra itself has no problem with 0 weight, per definition of the algorithm. It only gets problematic with negative weights. Since in every round Dijkstra will settle a node. If you later find a negative weighted edge, this could lead to a shorter path to that settled node.

Does Dijkstra work for graphs with cycles?

Dijkstra's algorithm solves the shortest-path problem for any weighted, directed graph with non-negative weights. It can handle graphs consisting of cycles, but negative weights will cause this algorithm to produce incorrect results.

How can you find the shortest path between two nodes in A graph by Dijkstra's algorithm?

Look at all nodes directly adjacent to the starting node. The values carried by the edges connecting the start and these adjacent nodes are the shortest distances to each respective node.


2 Answers

BGL actually has an example of using dijkstra_shortest_paths with listS/listS, but it's not linked to from the HTML documentation: http://www.boost.org/doc/libs/release/libs/graph/example/dijkstra-example-listS.cpp

What the error message is trying to tell you (error: no match for ‘operator=’ in ‘index.boost::adj_list_vertex_property_map...ValueType = boost::detail::error_property_not_found...) is that there is no per-vertex storage for the vertex_index_t property, which is what adj_list_vertex_property_map needs. To fix the problem you can either change your Graph typedef to include per-vertex storage for the vertex_index_t property or use an "external" property map such as associative_property_map.

The dijkstra-example-listS.cpp example uses the approach of changing the graph typedef. To use this approach in your code, you could define:

typedef boost::adjacency_list <boost::listS, boost::listS, boost::directedS,
  boost::property<boost::vertex_name_t, std::string, boost::property<boost::vertex_index_t, int> >,
  boost::property<boost::edge_weight_t, Weight> > Graph;
like image 191
Daniel Trebbien Avatar answered Oct 18 '22 16:10

Daniel Trebbien


If somebody is interested in the solution, Creating an associative_property_map as suggested in the previous answer solved the issue:

   typedef std::map<vertex_desc, size_t>IndexMap;
   IndexMap mapIndex;
   boost::associative_property_map<IndexMap> propmapIndex(mapIndex);
   //indexing the vertices
     int i=0;
     BGL_FORALL_VERTICES(v, g, pGraph)
     {
        boost::put(propmapIndex, v, i++);
     }

Then pass this Vertex index map to the dijkstra_shortest_paths() call as a named parameter. PS: BGL_FORALL_VERTICES() is defined in < boost/graph/iteration/iteration_macros.hpp >

like image 26
srkrish Avatar answered Oct 18 '22 16:10

srkrish