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..
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;
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 >
Related
It is straight forward to add edge weights to a graph as internal properties:
void InternalProperties()
{
std::cout << "InternalProperties()" << std::endl;
// Graph with internal edge weights
using EdgeWeightProperty = boost::property<boost::edge_weight_t, double>; // <tag, type>
using GraphWithInternalEdgeWeightsType = boost::adjacency_list<boost::setS, // out edge container
boost::vecS, // vertex container
boost::undirectedS, // directed or undirected
boost::no_property, // vertex properites
EdgeWeightProperty> // edge properties
;
// Create a graph object
GraphWithInternalEdgeWeightsType g(3);
// add two edges with edge weights
EdgeWeightProperty e1 = 5;
add_edge(0, 1, e1, g);
EdgeWeightProperty e2 = 3;
add_edge(1, 2, e2, g);
boost::property_map<GraphWithInternalEdgeWeightsType, boost::edge_weight_t>::type edgeWeightMap = get(boost::edge_weight_t(), g);
using edge_iter = boost::graph_traits<GraphWithInternalEdgeWeightsType>::edge_iterator;
std::pair<edge_iter, edge_iter> edgePair;
for(edgePair = edges(g); edgePair.first != edgePair.second; ++edgePair.first) {
std::cout << edgeWeightMap[*edgePair.first] << " ";
}
}
Now if I want to do the same thing and demonstrate using "external properties", I came up with this, but there is really no link at all back to the original graph:
void ExternalProperties()
{
std::cout << std::endl << "ExternalProperties()" << std::endl;
// Graph with external edge weights
using GraphWithExternalEdgeWeightsType = boost::adjacency_list<boost::setS, // out edge container
boost::vecS, // vertex container
boost::undirectedS> // directed or undirected
;
// Create a graph object
GraphWithExternalEdgeWeightsType g(3);
// add edges (without edge weights)
add_edge(0, 1, g);
add_edge(1, 2, g);
// create a map from edge_descriptors to weights and populate it
std::map<GraphWithExternalEdgeWeightsType::edge_descriptor, double> edgeWeightMap;
edgeWeightMap[boost::edge(0,1,g).first] = 5;
edgeWeightMap[boost::edge(1,2,g).first] = 3;
using edge_iter = boost::graph_traits<GraphWithExternalEdgeWeightsType>::edge_iterator;
std::pair<edge_iter, edge_iter> edgePair;
for(edgePair = edges(g); edgePair.first != edgePair.second; ++edgePair.first) {
std::cout << edgeWeightMap[*edgePair.first] << " ";
}
}
Is there any way to make something like get(boost::edge_weight_t(), g); (from the internal example) return this map? Like to say g.setPropertyMap(boost::edge_weight_t, edgeWeightMap) in this external example?
I'm not sure what the gain is, but perhaps this helps for inspiration:
#include <boost/graph/adjacency_list.hpp>
#include <boost/property_map/property_map.hpp>
#include <map>
#include <iostream>
namespace MyLib {
struct MyGraph : boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS> {
using base_type = boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS>;
using base_type::adjacency_list;
std::map<edge_descriptor, double> m_weights;
};
auto get(boost::edge_weight_t, MyGraph& g) { return boost::make_assoc_property_map(g.m_weights); }
auto get(boost::edge_weight_t, MyGraph const& g) { return boost::make_assoc_property_map(g.m_weights); }
}
namespace boost {
template <> struct graph_traits<MyLib::MyGraph> : graph_traits<adjacency_list<setS, vecS, undirectedS> > {};
template <> struct property_map<MyLib::MyGraph, edge_weight_t, void> {
using Traits = graph_traits<MyLib::MyGraph>;
using Edge = Traits::edge_descriptor;
using type = boost::associative_property_map<std::map<Edge, double> >;
using const_type = boost::associative_property_map<std::map<Edge, double> > const;
};
}
void ExternalProperties() {
std::cout << "ExternalProperties()" << std::endl;
// Graph with external edge weights
// Create a graph object
using Graph = MyLib::MyGraph;
Graph g(3);
// add edges (without edge weights)
add_edge(0, 1, g);
add_edge(1, 2, g);
// create a map from edge_descriptors to weights and populate it
auto edgeWeightMap = MyLib::get(boost::edge_weight, g);
edgeWeightMap[boost::edge(0, 1, g).first] = 5;
edgeWeightMap[boost::edge(1, 2, g).first] = 3;
using edge_iter = boost::graph_traits<Graph>::edge_iterator;
std::pair<edge_iter, edge_iter> edgePair;
for (edgePair = edges(g); edgePair.first != edgePair.second; ++edgePair.first) {
std::cout << edgeWeightMap[*edgePair.first] << " ";
}
}
int main() {
ExternalProperties();
}
I've not been able to avoid ambiguity with boost::get in such a way that you can trust ADL to pick the "best" overload without namespace qualification.
Live On Coliur
With a simple graph, it is straight forward to call prim_minimum_spanning_tree to get the result starting at vertex 0:
#include <iostream>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/prim_minimum_spanning_tree.hpp>
typedef boost::property<boost::edge_weight_t, double> EdgeWeightProperty;
typedef boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS, boost::no_property, EdgeWeightProperty> Graph;
int main(int,char*[])
{
// Create a graph object
Graph g(3);
EdgeWeightProperty e1 = 5;
add_edge(0, 1, e1, g);
EdgeWeightProperty e2 = 3;
add_edge(1, 2, e2, g);
std::vector < boost::graph_traits < Graph >::vertex_descriptor > parents(num_vertices(g));
prim_minimum_spanning_tree(g, &parents[0]);
for (std::size_t i = 0; i != parents.size(); ++i) {
if (parents[i] != i) {
std::cout << "parent[" << i << "] = " << parents[i] << std::endl;
}
else {
std::cout << "parent[" << i << "] = no parent" << std::endl;
}
}
return 0;
}
But I can't seem to decrypt the signature for specifying a different start vertex? It looks like this one is the only one that takes a vertex_descriptor (which I'm assuming is the start vertex?):
prim_minimum_spanning_tree
(const VertexListGraph& g,
typename graph_traits<VertexListGraph>::vertex_descriptor s,
PredecessorMap predecessor, DistanceMap distance, WeightMap weight,
IndexMap index_map,
DijkstraVisitor vis)
any suggestions on how to call it?
This requires the "named parameter" signature:
prim_minimum_spanning_tree(g, &parents[0], boost::root_vertex(1));
You can find the available named parameters under "Named Parameters" on the documentation page: http://www.boost.org/doc/libs/1_61_0/libs/graph/doc/prim_minimum_spanning_tree.html
I'm trying to update the value of an edge in my Graph, however, when i update the value using the following property map:
property_map<Graph, edge_weight_t>::type weight = get(edge_weight, g);
weight[*edgeIndex] = new_value;
Its update the value, however when i try to get the shortest path using dijkstra algorithm, the algorithm get the old_value of the weight. But when i list all edges and weight in the Graph, the updated weight is with the new_value.
i tried to use the boost::put(); however occurs the same problem. It only works when the new_value is smaller than the old_value
Could somebody help me?
in other words, i just want to set name and weight to the edges and update this weights on the fly.
this is my code:
#include <iostream> // for std::cout
#include <utility> // for std::pair
#include <algorithm> // for std::for_each
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/config.hpp>
#include <string>
#include <string.h>
#include <list>
#include <fstream>
using namespace boost;
//define de Edges and Vertex property
typedef property<edge_weight_t, float, property<edge_name_t, std::string> > EdgeWeightProperty;
typedef property<vertex_name_t, std::string> VertexProperty;
//define the type of the Graph
typedef adjacency_list<vecS, vecS, undirectedS, VertexProperty, EdgeWeightProperty> Graph;
int main(){
typedef float Weight;
//Graph instance
Graph g;
//property accessors
property_map<Graph, vertex_name_t>::type node = get(vertex_name, g);
property_map<Graph, edge_weight_t>::type weight = get(edge_weight, g);
property_map<Graph, edge_name_t>::type edge = get(edge_name, g);
// Create the vertices
typedef graph_traits<Graph>::vertex_descriptor Vertex;
std::vector<Vertex> vertex_list;
typedef graph_traits<Graph>::edge_descriptor Edge;
std::vector<Edge> edges_list;
typedef boost::property_map <Graph, vertex_index_t >::type IndexMap;
typedef boost::property_map <Graph, 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;
std::string vertex_name;
std::ifstream vertex_file;
vertex_file.open("vertex_file.txt");
if (vertex_file.is_open()){
for(int index = 0; vertex_file.peek() != EOF; index++){
vertex_file >> vertex_name;
vertex_list.push_back(add_vertex(g));
node[vertex_list.at(index)] = vertex_name;
}
vertex_file.close();
}
std::string edge_name, from, to;
std::ifstream edges_file;
edges_file.open("edge.txt");
int index_from, index_to;
if(edges_file.is_open()){
for(int index=0; edges_file.peek() != EOF; index++){
edges_file >> edge_name;
edges_file >> from;
edges_file >> to;
for(index_from=0; index_from < vertex_list.size(); index_from++){
if(strcmp(from.c_str(), node[vertex_list.at(index_from)].c_str()) == 0){
break;
}
}
for(index_to=0; index_to < vertex_list.size(); index_to++){
if(strcmp(to.c_str(), node[vertex_list.at(index_to)].c_str()) == 0){
break;
}
}
edges_list.push_back((add_edge(vertex_list.at(index_from), vertex_list.at(index_to), g)).first);
edge[edges_list.at(index)] = edge_name;
//std::cout << edges_list.at(index) << std::endl;
weight[edges_list.at(index)] = 10;
}
}
typedef graph_traits<Graph>::edge_iterator edge_iter;
std::pair<edge_iter, edge_iter> ep;
edge_iter ei, ei_end;
std::string teste = "0/0to0/1";
for (tie(ei, ei_end) = edges(g); ei != ei_end; ++ei){
//std::cout << edge[*ei] << std::endl;
if(strcmp(edge[*ei].c_str(), teste.c_str()) == 0){
weight[*ei] = 700;
}
}
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);
boost::dijkstra_shortest_paths(g, vertex_list.at(0), boost::distance_map(distanceMap).predecessor_map(predecessorMap));
std::cout << "distances and parents:" << std::endl;
NameMap nameMap = boost::get(boost::vertex_name, g);
std::cout << std::endl;
typedef std::vector<Graph::edge_descriptor> PathType;
PathType path;
Vertex v = vertex_list.at(1); // 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)] << " to " << nameMap[boost::target(*pathIterator, g)]
<< " = " << boost::get( boost::edge_weight, g, *pathIterator ) << std::endl;
}
std::cout << std::endl;
std::cout << "Distance: " << distanceMap[vertex_list.at(1)] << std::endl;
return 0;
}
I have defined a Graph using the Boost graph library,
typedef boost::property<boost::edge_weight_t, int> EdgeWeightProperty;
typedef boost::adjacency_list<boost::listS, boost::vecS,boost::undirectedS,boost::no_property,EdgeWeightProperty> Graph;
It is fairly straightforward to add edges using
boost::add_edge(vertice1, vertice2, weight, graph);
I have yet to figure out how to change the edge weight once it has been set. One possible solution would be to delete the edge and re-add it with the updated the weight value, however, that seems a bit excessive.
One solution is to do the following
typedef boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS,boost::no_property,EdgeWeightProperty> Graph;
typedef Graph::edge_descriptor Edge;
Graph g;
std::pair<Edge, bool> ed = boost::edge(v1,v2,g);
int weight = get(boost::edge_weight_t(), g, ed.first);
int weightToAdd = 10;
boost::put(boost::edge_weight_t(), g, ed.first, weight+weightToAdd);
An alternate solution would be to use property maps. Here's an example.
// Edge weight.
typedef boost::property<boost::edge_weight_t, int> EdgeWeightProperty;
// Graph.
typedef boost::adjacency_list< boost::listS,
boost::vecS,
boost::undirectedS,
boost::no_property,
EdgeWeightProperty > Graph;
// Vertex descriptor.
typedef typename boost::graph_traits<Graph>::vertex_descriptor Vertex;
// The Graph object
Graph g;
// Populates the graph.
Vertex v1 = boost::add_vertex(g);
Vertex v2 = boost::add_vertex(g);
Vertex v3 = boost::add_vertex(g);
boost::add_edge(v1, v2, EdgeWeightProperty(2), g);
boost::add_edge(v1, v3, EdgeWeightProperty(4), g);
boost::add_edge(v2, v3, EdgeWeightProperty(5), g);
// The property map associated with the weights.
boost::property_map < Graph,
boost::edge_weight_t >::type EdgeWeightMap = get(boost::edge_weight, g);
// Loops over all edges and add 10 to their weight.
boost::graph_traits< Graph >::edge_iterator e_it, e_end;
for(std::tie(e_it, e_end) = boost::edges(g); e_it != e_end; ++e_it)
{
EdgeWeightMap[*e_it] += 10;
}
// Prints the weighted edgelist.
for(std::tie(e_it, e_end) = boost::edges(g); e_it != e_end; ++e_it)
{
std::cout << boost::source(*e_it, g) << " "
<< boost::target(*e_it, g) << " "
<< EdgeWeightMap[*e_it] << std::endl;
}
I'm new to BGL and I have a problem with making own property maps which key is edge_property
can you tell me what I'm doing wrong that following code prints not :
(0,1) == (0,1) ? 1
but
(0,1) == (0,1) ? 0
Here is the code
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
#include <map>
using namespace std;
class A {};
class B {};
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::bidirectionalS,
A, B > Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<Graph>::edge_descriptor edge_descriptor;
typedef boost::graph_traits<Graph>::edge_iterator edge_iterator;
typedef boost::graph_traits<Graph>::in_edge_iterator in_edge_iterator;
typedef boost::graph_traits<Graph>::out_edge_iterator out_edge_iterator;
map<edge_descriptor, int> fun(Graph g){
map<edge_descriptor, int> m;
m[*(edges(g).first)] = 5;
return m;
}
int main(){
Graph g;
vertex_descriptor a = add_vertex(g);
vertex_descriptor b = add_vertex(g);
add_edge(a, b, g);
map<edge_descriptor, int> m = fun(g);
edge_iterator ei, ei_end;
for(tie(ei, ei_end) = edges(g) ; ei !=ei_end ; ++ei){
cout << m.begin()->first << " == " << *ei << " ? " << (m.begin()->first == *ei) << endl;
}
}
thank you very much!
EDIT:
maybe there is a better way to map edge than by edge_property value?
Your edge descriptor has 3 members: source node, target node and a pointer to your B property. In your fun you make a copy of your graph, and the copied edge in your new graph points to a different B. If you declare your fun as map<edge_descriptor, int> fun(const Graph& g) (and you probably should since a copy of a bigger graph can be expensive) you obtain the result you expect.