edge_descriptor mapping in bgl - c++

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.

Related

How to access edge information in Boost Graph?

The main question:
I am able to create a graph implementation with information structs assigned to the vertices and edges:
struct vertex_info {std::string name;};
struct edge_info {std::string name;};
typedef boost::adjacency_list<
boost::vecS,
boost::vecS,
boost::undirectedS,
vertex_info,
edge_info> UndirectedGraph;
And for an instance of UndirectedGraph, g, I can easily iterate over the vertices, and access their information:
for(size_t i=0; i<boost::num_vertices(g); i++){
std::cout << g[i].name << std::endl;
}
but I am unable to figure out how to do the same for the edges. I have come across some iterators to loop over all the edges, but I cannot access these edges as some kind of object or something with properties. How can I access the edge information of g?
A minimal working demonstration:
#include <iostream>
#include <utility>
#include <vector>
#include <string>
#include "boost/graph/graph_traits.hpp"
#include "boost/graph/adjacency_list.hpp"
int main(int argc, char *argv[])
{
//Add vertex information struct
struct vertex_info {
std::string name;
};
//Add edge information struct
struct edge_info {
std::string name;
};
//Typedef my graph implimentation
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, vertex_info, edge_info> UndirectedGraph;
//Our set of edges, and count N: (0-7) and 8
enum {C, D, G, I, S, J, L, H, N};
const char *name = "CDGISJLH";
//Create a vector of edges
typedef std::pair<int, int> Edge;
std::vector<Edge> edgeVec;
edgeVec.push_back(Edge(C,D));
edgeVec.push_back(Edge(D,G));
edgeVec.push_back(Edge(I,G));
edgeVec.push_back(Edge(G,L));
edgeVec.push_back(Edge(H,G));
edgeVec.push_back(Edge(I,S));
edgeVec.push_back(Edge(S,J));
edgeVec.push_back(Edge(L,J));
edgeVec.push_back(Edge(H,J));
//Now we can initialize our graph using iterators from our above vector
UndirectedGraph g(edgeVec.begin(), edgeVec.end(), N);
std::cout << num_edges(g) << "\n"; //Outputs: 9
//loop over vertices, access "name" property
for(size_t i=0; i<boost::num_vertices(g); i++){
//And add information to the edges
g[i].name = "foo";
}
//We can access the first vertice and print the property
std::cout << g[0].name << std::endl; //Outputs: foo
//Edge iterator for or graph
typedef boost::graph_traits<UndirectedGraph>::edge_iterator edge_iterator;
//Iterate through all the edges
std::pair<edge_iterator, edge_iterator> ei = boost::edges(g);
for(edge_iterator edge_iter = ei.first; edge_iter != ei.second; ++edge_iter) {
//How can I access the edge property???
}
}
I have figure out the problem by walking through this example: https://www.boost.org/doc/libs/1_71_0/libs/graph/doc/bundles.html
The fix:
Although I still don't exactly understand how it all works. It seems like you have to use edge_iter as some kind of index into g:
//Edge iterator for or graph
typedef boost::graph_traits<MRFGraph>::edge_iterator edge_iterator;
//Iterate through all the edges
std::pair<edge_iterator, edge_iterator> ei = boost::edges(g);
for(edge_iterator edge_iter = ei.first; edge_iter != ei.second; ++edge_iter) {
g[*edge_iter].name = "bar";
std::cout << *edge_iter << ": " << g[*edge_iter].name << std::endl;
}
Output:
If I add this to the minimal working demonstration, it produces the following output:
9
foo
(0,1): bar
(1,2): bar
(3,2): bar
(2,6): bar
(7,2): bar
(3,4): bar
(4,5): bar
(6,5): bar
(7,5): bar
May not be exactly what you are looking for but does achieve what you are after
#include <iostream>
#include <utility>
#include <vector>
#include <string>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
namespace boost {
enum edge_myname_t { edge_myname };
BOOST_INSTALL_PROPERTY(boost::edge, myname);
}
int main(int argc, char* argv[]) {
// Add vertex information struct
struct vertex_info {
std::string name;
};
// Add edge information struct
//struct edge_info {
//std::string name;
//};
using EdgeName = boost::property<boost::edge_myname_t, std::string>;
// Typedef my graph implimentation
using UndirectedGraph =
boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS,
vertex_info, EdgeName>;
// Our set of edges, and count N: (0-7) and 8
enum { C, D, G, I, S, J, L, H, N };
const char* name = "CDGISJLH";
// Create a vector of edges
//using Edge = std::pair<int, int>;
//std::vector<Edge> edgeVec;
//edgeVec.push_back(Edge(C, D));
//edgeVec.push_back(Edge(D, G));
//edgeVec.push_back(Edge(I, G));
//edgeVec.push_back(Edge(G, L));
//edgeVec.push_back(Edge(H, G));
//edgeVec.push_back(Edge(I, S));
//edgeVec.push_back(Edge(S, J));
//edgeVec.push_back(Edge(L, J));
//edgeVec.push_back(Edge(H, J));
// Now we can initialize our graph using iterators from our above vector
UndirectedGraph g(N);
//UndirectedGraph g(edgeVec.begin(), edgeVec.end(), N);
boost::add_edge(C, D, EdgeName("#1"), g);
boost::add_edge(D, G, EdgeName("#2"), g);
boost::add_edge(I, G, EdgeName("#3"), g);
boost::add_edge(G, L, EdgeName("#4"), g);
boost::add_edge(H, G, EdgeName("#5"), g);
boost::add_edge(I, S, EdgeName("#6"), g);
boost::add_edge(S, J, EdgeName("#7"), g);
boost::add_edge(L, J, EdgeName("#8"), g);
boost::add_edge(H, J, EdgeName("#9"), g);
boost::property_map<UndirectedGraph, boost::edge_myname_t>::type get_name =
boost::get(boost::edge_myname, g);
std::cout << num_edges(g) << "\n"; // Outputs: 9
// loop over vertices, access "name" property
for (size_t i = 0; i < boost::num_vertices(g); i++) {
// And add information to the edges
g[i].name = "foo";
}
// We can access the first vertice and print the property
std::cout << g[0].name << std::endl; // Outputs: foo
// Edge iterator for or graph
using EdgeIterator = boost::graph_traits<UndirectedGraph>::edge_iterator;
// Iterate through all the edges
std::pair<EdgeIterator, EdgeIterator> ei = boost::edges(g);
for (EdgeIterator edge_iter = ei.first; edge_iter != ei.second; ++edge_iter) {
// How can I access the edge property???
std::cout << get_name[*edge_iter] << "\n";
}
}
I just slightly modified some of the code for my own readability issues.
For reference, check this out.

Boost prim_minimum_spanning_tree from a particular start vertex

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

copy_graph - adjacency_list with bundled properties

Here is a complete snippet to copy a graph with bundled properties, but results in bunch of compiler errors. What is needed to fix the problems?
struct NodeInfo1 {};
struct EdgeInfo1 {};
typedef boost::labeled_graph< boost::adjacency_list<
boost::vecS, boost::vecS, boost::undirectedS, NodeInfo1, EdgeInfo1>,
std::string> Graph1;
typedef std::pair<boost::graph_traits<Graph>::edge_descriptor, bool> Edge;
void TestCases::TestCopyGraph()
{
Graph1 grid, g1;
EdgeInfo1 ei;
Edge e = add_edge_by_label("A", "B", ei, grid);
copy_graph(grid, g1);
}
That's slightly misrepresenting the question. You're not actually copying the adjacency list, you're copying the labeled_graph adaptor, which happens to not satisfy the concepts required by copy_graph:
/** #name Labeled Mutable Graph
* The labeled mutable graph hides the add_ and remove_ vertex functions from
* the mutable graph concept. Note that the remove_vertex is hidden because
* removing the vertex without its key could leave a dangling reference in
* the map.
*/
Here's copying the adjacency_list: ¹
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, NodeInfo1, EdgeInfo1> AList;
typedef boost::labeled_graph<AList, std::string> Graph;
void TestCopyGraph()
{
std::string names[3] = { "A", "B", "C" };
Graph grid(3, names);
EdgeInfo1 ei;
/*auto e =*/ add_edge_by_label("C", "B", ei, grid);
AList g1;
copy_graph(grid, g1);
}
Copying the Labeled adaptor
Is much easier. No copy_graph required, just copy-construct the object:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/copy.hpp>
#include <boost/graph/labeled_graph.hpp>
#include <boost/graph/graph_utility.hpp>
struct NodeInfo1 { int i; };
struct EdgeInfo1 { int j; };
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, NodeInfo1, EdgeInfo1> AList;
typedef boost::labeled_graph<AList, std::string> Graph;
auto TestCopyGraph()
{
std::string names[3] = { "A", "B", "C" };
NodeInfo1 props[3] = { {11}, {22}, {33} };
Graph grid(3, names, props);
/*auto e =*/ add_edge_by_label("C", "B", EdgeInfo1{17}, grid);
Graph g1 = grid; // just copy-construct
return g1;
}
int main() {
auto copied = TestCopyGraph();
print_graph(copied);
// check that properties were copied: vertex B has NodeInfo1 22
{
auto pmap = boost::get(&NodeInfo1::i, copied);
std::cout << "Vertex B NodeInfo1.i after copy: " << pmap[copied.vertex("B")] << "\n";
}
// edge properties too:
for (auto e : boost::make_iterator_range(edges(copied)))
std::cout << "Edge has property EdgeInfo1 " << copied[e].j << "\n";
std::cout << "Removed A:\n";
copied.remove_vertex("A");
print_graph(copied);
}
Prints
0 <-->
1 <--> 2
2 <--> 1
Vertex B NodeInfo1.i after copy: 22
Edge has property EdgeInfo1 17
Removed A:
0 <--> 1
1 <--> 0
¹ Note that you need this patch because of bugs in labeled_graph: https://github.com/boostorg/graph/pull/58

Same weights for different boost graphs

I have just realized that I have not yet understood how to use boost graph library. I have this code:
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
using namespace std;
using namespace boost;
typedef unsigned int WeightType;
typedef adjacency_list<listS, vecS, bidirectionalS,
no_property, property<edge_weight_t, WeightType>> Graph;
typedef graph_traits<Graph>::vertex_descriptor Vertex;
typedef graph_traits<Graph>::edge_descriptor Edge;
typedef property_map<Graph, edge_weight_t>::type WeightMap;
typedef property_map<Graph, edge_weight_t>::const_type ConstWeightMap;
const WeightType infinity = numeric_limits<WeightType>::max();
int main() {
Graph g(4);
Graph g2(4);
for (uint i = 0; i < 3; ++i) {
add_edge(i, i+1, i, g);
add_edge(i, i+1, i*10, g2);
}
WeightMap m = get(edge_weight, g);
WeightMap m2 = get(edge_weight, g2);
for (auto e : make_iterator_range(edges(g))) {
cout << m[e] << endl;
}
cout << endl;
for (auto e : make_iterator_range(edges(g))) {
cout << m2[e] << endl;
}
}
I would expect an output like: "0 1 2 , 0 10 20". But the output is "0 1 2, 0 1 2". Every graph have its weight property map, doesn't it? Where is my mistake?
You made a typo in the second for loop:
for (auto e : make_iterator_range(edges(g))) {
Should be:
for (auto e : make_iterator_range(edges(g2))) {
So you were printing the content of the first graph twice, instead of the first then the second.

How do I attach objects to the nodes and edges of a graph using the Boost Graph Library?

I would like to use the Boost Graph Library more effectively by attaching properly encapsulated classes to graph nodes & edges. I am not interested in attaching int's or POD struct's. Following suggestions on other StackOverFlow articles, I have developed the following sample app. Can anybody tell me the magic I need to sprinkle onto the EdgeInfo class to make this thing compile?
I am using Visual Studio 2010 with Boost 1.54.0.
//------------------------------------------------------------------------
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <iostream>
//------------------------------------------------------------------------
struct VertexInfo
{
struct Tag
{
typedef boost::vertex_property_tag kind;
static std::size_t const num; // ???
};
typedef boost::property<Tag, VertexInfo> Property;
};
std::size_t const VertexInfo::Tag::num = reinterpret_cast<std::size_t> (&VertexInfo::Tag::num);
//------------------------------------------------------------------------
class EdgeInfo
{
int _nWeight;
public:
int getWeight () const {return _nWeight;}
struct Tag
{
typedef boost::edge_property_tag kind;
static std::size_t const num; // ???
};
typedef boost::property<boost::edge_weight_t, int> Weight;
typedef boost::property<Tag, EdgeInfo> Property;
EdgeInfo (int nWeight = 9999) : _nWeight (nWeight) {}
};
std::size_t const EdgeInfo::Tag::num = reinterpret_cast<std::size_t> (&EdgeInfo::Tag::num);
//------------------------------------------------------------------------
typedef boost::property<boost::edge_weight_t, int> EdgeProperty;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexInfo::Property, EdgeProperty> GraphWorking;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexInfo::Property, EdgeInfo::Property> GraphBroken;
//------------------------------------------------------------------------
template<typename GraphType, typename EdgeType> void
dijkstra (GraphType g, EdgeType e)
{
typedef boost::graph_traits<GraphType>::vertex_descriptor VertexDesc;
typedef boost::graph_traits<GraphType>::edge_descriptor EdgeDesc;
VertexDesc u = add_vertex (g);
VertexDesc v = add_vertex (g);
std::pair<EdgeDesc, bool> result = add_edge (u, v, e, g);
std::vector<VertexDesc> vecParent (num_vertices (g), 0);
dijkstra_shortest_paths (g, u, boost::predecessor_map (&vecParent[0]));
}
//------------------------------------------------------------------------
int
main (int argc, char** argv)
{
#if defined(BOOST_MSVC) && BOOST_MSVC <= 1300
std::cout << "Buy a new compiler\n";
#else
std::cout << "Your compiler is fine\n";
#endif
GraphWorking gWorking;
GraphBroken gBroken;
dijkstra (gWorking, 3);
dijkstra (gBroken, EdgeInfo (4));
}
//------------------------------------------------------------------------
When I run your code i get an error in numeric_limits that results from a distance map in dijkstra.
"
Error 1 error C2440: '' : cannot convert from 'int' to 'D' c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\limits 92
"
probably from this part of http://www.boost.org/doc/libs/1_55_0/boost/graph/dijkstra_shortest_paths.hpp
typedef typename property_traits<DistanceMap>::value_type D;
D inf = choose_param(get_param(params, distance_inf_t()),
(std::numeric_limits<D>::max)());
I think there may be an easier way to tie a real class for your nodes and edges. Its more trouble than its worth to create vertex and edge property classes that will provide all the needed tagged properties (index, weight, color, etc) needed for most boost algorihtms.
Don't forget Edge class != Edge property.
The edge class is really the graph_traits::edge_discriptor.
Properties are the data associated with each edge. Same for vertex.
I would use bundled properties and add a pointer to your class in each one.
Here is an example
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/properties.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/property_map/property_map.hpp>
#include <iostream>
//Fancy Edge class
class EdgeData
{
int _data;
public:
EdgeData(){
_data=0;
}
EdgeData(int data){
_data= data;
}
void printHello(){
std::cout << "hello " << _data << std::endl;
}
};
//Fancy Vert class
class VertexData
{
int _data;
public:
VertexData(){
_data=0;
}
VertexData(int data){
_data= data;
}
void printHello(){
std::cout << "hello " << _data << std::endl;
}
};
//bundled properties
struct VertexProps
{
VertexData* data;
};
struct EdgeProps
{
size_t weight;
EdgeData* data;
};
//Graph
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
VertexProps,EdgeProps> Graph;
//helpers
//Vertex
typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
//Edge
typedef boost::graph_traits<Graph>::edge_descriptor Edge;
//------------------------------------------------------------------------
template<typename GraphType> void
templateFunction (GraphType g)
{
typedef boost::graph_traits<GraphType>::edge_iterator edge_iter;
std::pair<edge_iter, edge_iter> ep;
edge_iter ei, ei_end;
ep = edges(g);
ei_end = ep.second;
for (ei = ep.first; ei != ei_end; ++ei){
g[*ei].data->printHello();
}
}
//if you want to alter the graph use referenced &graph
template<typename GraphType,typename EdgePropType> void
templateFuctionProps(GraphType &g, EdgePropType e)
{
typedef boost::graph_traits<GraphType>::vertex_descriptor VertexDesc;
VertexDesc v = add_vertex(g);
VertexDesc u = add_vertex(g);
//add an edge with the Edge property
add_edge(v,u,e,g);
}
//------------------------------------------------------------------------
int
main (int argc, char** argv)
{
Graph g;
//vertex holder
std::vector<Vertex> verts;
//add some verts
for(size_t i = 0; i < 5; ++i){
Vertex v = add_vertex(g);
g[v].data = new VertexData(i%2);
verts.push_back(v);
}
//add some edges
for(size_t i = 0; i < 4; ++i){
std::pair<Edge,bool> p = add_edge(verts.at(i),verts.at(i+1),g);
Edge e = p.first;
g[e].data = new EdgeData(i%3);
g[e].weight = 5;
}
//iterate edges and call a class function
typedef boost::graph_traits<Graph>::edge_iterator edge_iter;
std::pair<edge_iter, edge_iter> ep;
edge_iter ei, ei_end;
ep = edges(g);
ei_end = ep.second;
for (ei = ep.first; ei != ei_end; ++ei){
g[*ei].data->printHello();
}
std::cout << "Iterate with template with template " << std::endl;
templateFunction(g);
//Use an edge property in a function
EdgeProps edgeProp;
edgeProp.weight = 5;
edgeProp.data = new EdgeData(150);
std::cout << "Modity graph with template function " << std::endl;
templateFuctionProps(g,edgeProp);
std::cout << "Iterate again with template" << std::endl;
templateFunction(g);
//getting the weight property
boost::property_map<Graph,size_t EdgeProps::*>::type w
= get(&EdgeProps::weight, g);
std::cout << "Print weights" << std::endl;
ep = edges(g);
ei_end = ep.second;
for (ei = ep.first; ei != ei_end; ++ei){
std::cout << w[*ei] << std::endl;
}
std::cin.get();
}
//------------------------------------------------------------------------
Also I see you are using vecS, meaning that both vectors and edges are stored as vectors with a fixed ordering.
You could just have a class that stores your Edge and Vertex classes with a pointer to the vertex map or edge map for the graph.
I don't know your goals for this project, but I would definitely have higher level classes than manage all of this boost stuff behind the scenes. Meaning storing classes in a vector with an index look up would be hidden and encapsulated from applications that want to use your nice graph class.