Attach an external property map to a graph - c++

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

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

How to add colored edge in boost graph?

int main()
{
using namespace std;
using namespace boost;
typedef adjacency_list< listS, vecS, directedS > digraph;
// instantiate a digraph object with 8 vertices
digraph g;
// add some edges
add_edge(0, 1, g);
add_edge(1, 5, g);
add_edge(5, 6, g);``
add_edge(2, 3, g);
add_edge(2, 4, g);
// represent graph in DOT format and send to cout
write_graphviz(cout, g);
return 0;
}
Please tell me how to add coloured edge not coloured vertex.
for example edge between vertex 0 and 1 I want it to give some colour to it for example red
so all other edges should be of different colour and edge between vertex 0 and 1 should be red colour, how can I set that property.
You can do this with a property writer.
Something along these lines will do the job:
#include <iostream>
#include <boost/graph/graphviz.hpp>
using namespace std;
using namespace boost;
typedef adjacency_list< listS, vecS, directedS > digraph;
// define a property writer to color the edges as required
class color_writer {
public:
// constructor - needs reference to graph we are coloring
color_writer( digraph& g ) : myGraph( g ) {}
// functor that does the coloring
template <class VertexOrEdge>
void operator()(std::ostream& out, const VertexOrEdge& e) const {
// check if this is the edge we want to color red
if( source( e, myGraph ) == 0 &&
target( e, myGraph ) == 1 )
out << "[color=red]";
}
private:
digraph& myGraph;
};
int main()
{
using namespace std;
// instantiate a digraph object with 8 vertices
digraph g;
// add some edges
add_edge(0, 1, g);
add_edge(1, 5, g);
add_edge(5, 6, g);
add_edge(2, 3, g);
add_edge(2, 4, g);
// represent graph in DOT format and send to cout
write_graphviz(cout, g,
default_writer(), // default ( do nothing ) vertex property writer
color_writer( g ) ); // edge color property writer
return 0;
}
Running this produces
digraph G {
0;
1;
2;
3;
4;
5;
6;
0->1 [color=red];
1->5 ;
2->3 ;
2->4 ;
5->6 ;
}
which when input to the dot program gives:
The manual says this should work with a PropertyWriter.
I use below mentioned code to make colour edges using boost graph api:
#include <iostream>
#include <string>
#include <boost/graph/directed_graph.hpp>
#include <boost/graph/labeled_graph.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/config.hpp>
#include <boost/graph/adjacency_list.hpp>
using namespace boost;
using namespace std;
template < typename Graph, typename VertexNameMap, typename EdgeNameMap > void
print_dependencies(std::ostream & out, const Graph & g,
VertexNameMap name_map,EdgeNameMap edge_map)
{
//property_map<Graph, edge_name_t>::type name = get(edge_map, g);
typename graph_traits < Graph >::edge_iterator ei, ei_end;
cout<<"digraph G {"<<"\n";
//for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
// out << get(name_map, source(*ei, g)) <<" ;" <<std::endl;
for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
out << get(name_map, source(*ei, g)) << "->"
<< get(name_map, target(*ei, g)) << " [color= "<<edge_map[*ei] <<"]"<<" ;" <<std::endl;
cout<<"}"<<"\n";
}
int main() {
using namespace boost;
typedef boost::adjacency_list
<
//Store all edges as a std::vector
boost::vecS,
//Store all vertices in a std::vector
boost::vecS,
//Relations are both ways (in this example)
//(note: but you can freely change it to boost::directedS)
boost::directedS,
//All vertices are person names of type std::string
boost::property<boost::vertex_name_t,std::string>,
//All edges are weights equal to the encounter frequencies
// boost::property<boost::edge_weight_t,double>,
boost::property<boost::edge_name_t,std::string>,
//Graph itself has a std::string name
// boost::property< vertex_color_t, default_color_type >,
boost::property<boost::graph_name_t,std::string>
> Graph;
Graph g;
typedef boost::graph_traits<Graph>::edge_descriptor ed;
typedef std::pair<ed, bool> edgeName;
typedef property<edge_name_t, string> EdgeProperty;
string ab = "test";
string cd = "hello";
//All vertex names
//Note: cannot use spaces
std::vector<std::string> names;
names.push_back("MrA");
names.push_back("Mrs_B");
names.push_back("Dr_C");
names.push_back("Prof_D");
// Graph::vertex_descriptor
const Graph::vertex_descriptor v0 = boost::add_vertex(names[0],g);
const Graph::vertex_descriptor v1 = boost::add_vertex(names[1],g);
const Graph::vertex_descriptor v2 = boost::add_vertex(names[2],g);
const Graph::vertex_descriptor v3 = boost::add_vertex(names[3],g);
const Graph::vertex_descriptor v4 = boost::add_vertex(ab,g);
boost::add_vertex(cd,g);
boost::add_edge(v0, v1,EdgeProperty("red"), g);
boost::add_edge(v1,v2,EdgeProperty("yellow"),g);
boost::add_edge(v2,v3,EdgeProperty("red"),g);
boost::add_edge(v3,v4,EdgeProperty("green"),g);
boost::add_edge(0,5,EdgeProperty("blue"),g);
//write_graphviz(cout, g);
print_dependencies(std::cout, g, get(vertex_name, g), get(edge_name, g) );
}

boost graph that doesn't allow circular references

I'm new to boost graphs and are researching the graph that best fits my need. I need to create a dependency graph and given a vertex, I need access to in and out edges. An adjacency_list with Directed=bidirectionalS is what I'm thinking.
But I need to make sure when I call add_edge and that causes a circular reference then it has to error out. I can't seem to find how to do this.
In general, there's only one way to discover whether a graph is a-cyclic: traverse all nodes.
So you'd just need to check whether the graph is still a-cyclic after adding each edge.
However, depending on how you are adding the nodes, you can optimize. If, e.g. you add edges by traversing nodes from a source in DFS order, you can just keep track of nodes "seen" in the current path and refuse to add an out edge to those.
Simplistic example based on topological_sort Live On Coliru:
#include <iostream> // for std::cout
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/function_output_iterator.hpp>
using namespace boost;
int main()
{
srand(time(0));
typedef adjacency_list<vecS, vecS, bidirectionalS> Graph;
const int num_vertices = 10;
Graph g(num_vertices);
// add random edges to the graph object
for (size_t i = 0; i < 10; ++i)
{
auto f = rand()%num_vertices,
s = rand()%num_vertices;
add_edge(f, s, g);
try {
topological_sort(g, boost::make_function_output_iterator([](int){}));
} catch(not_a_dag const& e)
{
remove_edge(f, s, g);
std::cerr << "dropped edge: " << e.what() << "\n";
}
}
write_graphviz(std::cout, g);
}
Creates random DAGs like
In boost graph BidirectinalS indicates that the edge will be having soruce and target vertices both.
Here is the example for it:
#include <QtCore/QCoreApplication>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/subgraph.hpp>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
using namespace std;
using namespace boost;
typedef boost::subgraph<boost::adjacency_list< boost::listS,
boost::vecS,
boost::bidirectionalS,
boost::property<boost::vertex_index_t, int , property<boost::vertex_color_t, boost::default_color_type > > ,
boost::property<boost::edge_index_t,int, property<boost::edge_color_t , default_color_type> > > >
Graph;
const int num_vertices = 5;
Graph g(num_vertices);
add_edge(0, 1, g);
add_edge(1, 2, g);
add_edge(1, 3, g);
add_edge(2, 4, g);
add_edge(3, 4, g);
boost::graph_traits<Graph>::vertex_iterator VertexItr, VertexItr_end;
boost::graph_traits<Graph>::in_edge_iterator in, in_end;
boost::graph_traits<Graph>::out_edge_iterator out,out_end;
typedef boost::graph_traits < Graph >::adjacency_iterator adjacency_iterator;
// This loop is for getting in edges at vertex
cout<<"In Edge :- "<<endl;
for(boost::tie(VertexItr,VertexItr_end) = vertices(g); VertexItr != VertexItr_end; ++VertexItr) {
cout << *VertexItr << " <-- ";
for (boost::tie(in,in_end) = in_edges(*VertexItr, g); in != in_end; ++in)
cout << source(*in, g) << " ";
cout << endl;
}
// This loop is for getting out edges from vertex
cout<<endl<<"Out Edge :- "<<endl;
for(boost::tie(VertexItr,VertexItr_end) = vertices(g); VertexItr != VertexItr_end; ++VertexItr) {
cout<<*VertexItr<<"--->";
for (boost::tie(out,out_end) = out_edges(*VertexItr, g); out != out_end; ++out)
cout << target(*out, g) << " ";
cout << endl;
}
// This loop is for getting the neighbour vertices of vertex
typedef boost::property_map<Graph, boost::vertex_index_t>::type IndexMap;
IndexMap index = get(boost::vertex_index, g);
cout<<"Adjacent vertices"<<endl;
for(boost::tie(VertexItr,VertexItr_end) = vertices(g); VertexItr != VertexItr_end; ++VertexItr) {
cout<<*VertexItr<<"--->";
std::pair<adjacency_iterator, adjacency_iterator> neighbors =
boost::adjacent_vertices(vertex(*VertexItr,g), g);
for(; neighbors.first != neighbors.second; ++neighbors.first)
{
std::cout << index[*neighbors.first] << " ";
}
cout<<endl;
}
return a.exec();
}
I found this section on the boost documentation discussing how to detect dependencies:
http://www.boost.org/doc/libs/1_55_0/libs/graph/doc/file_dependency_example.html#sec:cycles
But for the adjacency_list the VertexList and EdgeList have to be of type vecS. There's discussion about this here:
How to print a boost graph in graphviz with one of the properties displayed?

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.