My goal is to detect cycles in an undirected graph.
I try to adapt the djiskra shortest path with predecessor_recorder and predecessor map to the undirected_dfs.
I use the code available here :http://www.boost.org/doc/libs/1_46_1/libs/graph/doc/quick_tour.html
Cut & paste of :
Part 1:
template <class PredecessorMap>
class record_predecessors : public dijkstra_visitor<>
{
public:
record_predecessors(PredecessorMap p)
: m_predecessor(p) { }
template <class Edge, class Graph>
void edge_relaxed(Edge e, Graph& g) {
// set the parent of the target(e) to source(e)
put(m_predecessor, target(e, g), source(e, g));
}
protected:
PredecessorMap m_predecessor;
};
Part 2:
template <class PredecessorMap>
record_predecessors<PredecessorMap>
make_predecessor_recorder(PredecessorMap p) {
return record_predecessors<PredecessorMap>(p);
}
the call to undirected_dfs is:
boost::undirected_dfs(g, boost::make_dfs_visitor(make_predecessor_recorder(&p[0])), vertex_color_map, edge_color_map);
The compilation error on Visual studio is :
visitors.hpp(124): error : class "record_predecessors<Vertex={size_t={unsigned __int64}} *>" has no member "event_filter"
Do you have an idea on how to solve this issue ?
Thank you
Here is the code
#include <string>
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/undirected_dfs.hpp>
#include<boost/graph/properties.hpp>
#include <boost/graph/named_function_params.hpp> //for named parameter http://www.boost.org/doc/libs/1_58_0/libs/graph/doc/bgl_named_params.html
#include <boost/cstdlib.hpp> // for exit_success;
//#include <boost/utility.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/graph/graph_utility.hpp> //pring_graph
#include <boost/graph/dijkstra_shortest_paths.hpp> //dijkstra_visitor
//template du graph http://www.boost.org/doc/libs/1_55_0/libs/graph/doc/adjacency_list.html
typedef boost::adjacency_list<
boost::vecS, //OutEdgeList
boost::vecS, //VertexList
boost::undirectedS //Directednes
// boost::no_property, //VertexProperties
// boost::no_property, //EdgeProperties
// boost::no_property, //GraphProperties
// boost::listS //EdgeList
> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
template <class PredecessorMap>
class record_predecessors : public boost::dijkstra_visitor<>
{
public:
record_predecessors(PredecessorMap p)
: m_predecessor(p) { }
template <class Edge, class Graph>
void tree_edge(Edge e, Graph& g) {
// set the parent of the target(e) to source(e)
put(m_predecessor, target(e, g), source(e, g));
};
protected:
PredecessorMap m_predecessor;
};
template <class PredecessorMap>
record_predecessors<PredecessorMap>
make_predecessor_recorder(PredecessorMap p) {
return record_predecessors<PredecessorMap>(p);
}
template <typename event_type>
struct test_visitor : public boost::default_bfs_visitor {
using event_filter = event_type;
void operator()(Vertex, Graph const&) const {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
void tree_edge{};
void back_edge{};
void examine_edge{};
void discover_vertex{};
void finish_vertex{};
void initialize_vertex{};
void tree_vertex{};
void start_vertex{};
void forwared_or_cross_edge{};
};
struct detect_loops : public boost::dfs_visitor<>
{
//source:https://github.com/orocos-toolchain/utilmm/blob/master/test/test_undirected_graph.cc
using colormap = std::map<Graph::vertex_descriptor, boost::default_color_type>;
colormap vertex_coloring;
//source:https://github.com/orocos-toolchain/utilmm/blob/master/test/test_undirected_graph.cc
using edgeColorMap = std::map<Graph::edge_descriptor, boost::default_color_type>;
edgeColorMap edge_coloring;
template <class Edge, class Graph>
void tree_edge(Edge e, const Graph& g) {
boost::record_predecessors()
std::cout << "tree_edge: " << boost::source(e, g) << " --> " << boost::target(e, g) << std::endl;
std::cout << " tree_edge ";
}
template <class Edge, class Graph>
void back_edge(Edge e, const Graph& g) {
std::cout << "back_edge: " << boost::source(e, g) << " --> " << boost::target(e, g) << std::endl;
}
};
//---------------------------------------------------------
//---------------------------------------------------------
Graph make(Graph &g)
{
boost::add_vertex(g);
boost::add_vertex(g);
boost::add_vertex(g);
boost::add_vertex(g);
boost::add_vertex(g);
boost::add_edge(0, 1, g);
boost::add_edge(0, 2, g);
boost::add_edge(1, 0, g);
boost::add_edge(2, 4, g);
boost::add_edge(4, 3, g);
boost::add_edge(3, 1, g);
return g;
}
//---------------------------------------------------------
//---------------------------------------------------------
int main()
{
Graph g;
detect_loops vis;
make(g);
typedef std::map<boost::graph_traits<Graph>::vertex_descriptor, boost::graph_traits<Graph>::edge_descriptor> EdgeMap;
typedef boost::associative_property_map<EdgeMap> PredecessorMap;
typedef boost::edge_predecessor_recorder<PredecessorMap, boost::on_tree_edge> PredecessorVisitor;
std::vector< int > predecessorMap(boost::num_vertices(g));
typedef boost::associative_property_map< std::map<Graph::edge_descriptor, boost::default_color_type> >EdgeColorMap;
EdgeColorMap edge_color_map;
typedef boost::associative_property_map< std::map<Graph::vertex_descriptor, boost::default_color_type> >VertexColorMap;
VertexColorMap vertex_color_map;
//source 1: http://www.boost.org/doc/libs/1_38_0/libs/graph/doc/undirected_dfs.html
//source 2: https://github.com/orocos-toolchain/utilmm/blob/master/test/test_undirected_graph.cc
// named parameter version: template <typename Graph, typename P, typename T, typename R>
//boost::undirected_dfs(g, vis, vertex_color_map, edge_color_map);
std::vector<Vertex> p(boost::num_vertices(g), boost::graph_traits<Graph>::null_vertex()); //the predecessor array
// The source vertex
Graph::vertex_descriptor s = *(boost::vertices(g).first);
p[s] = s;
std::cout << "num vertices= " << boost::num_vertices(g) << std::endl;
std::cout << "num vertices= " << boost::num_vertices(g), boost::graph_traits<Graph>::null_vertex();
boost::print_graph(g);
//undirected_dfs(const Graph& g, DFSVisitor vis,VertexColorMap vertex_color, EdgeColorMap edge_color)
/*
boost::undirected_dfs( g,
//boost::visitor( boost::make_dfs_visitor(boost::record_predecessors(p.begin() , boost::on_tree_edge )) ),
boost::make_dfs_visitor( make_predecessor_recorder( &p[0] ) ),
vertex_color_map,
edge_color_map);
*/
boost::undirected_dfs( g,
boost::visitor( boost::make_dfs_visitor( std::make_pair( make_predecessor_recorder(&p[0]), test_visitor<boost::on_discover_vertex>() ) ) ),
vertex_color_map, edge_color_map);
/*
/// Declare predecessor map
typedef std::vector <Vertex> predecessors_t;
typedef boost::iterator_property_map <typename predecessors_t::iterator, IndexMap> predecessor_map_t;
predecessors_t predecessors(boost::num_vertices(g), boost::graph_traits<Graph>::null_vertex();;
predecessor_map_t predecessor_map(predecessors.begin(), index_map);
boost::depth_first_visit(g, s, boost::make_dfs_visitor(boost::record_predecessors(predecessor_map, boost::on_tree_edge())), vertex_color_map);
*/
return boost::exit_success;
}
Related
I am working on a project where I need to implement Dijkstra's, Prim's and A* algorithms on an input file my professor will provide. I have successfully written working code for Dijkstra's but I am hitting a wall trying to get my same graph to work for Prim's as well. I feel like my problem is not properly having a min spanning tree map to pull my info from but I cant really wrap my head around what the problem is, any help would be greatly appreciated.
structs and graph traits for edges and verts:
typedef boost::adjacency_list_traits<vecS, vecS, undirectedS, listS> GraphTraits;
// type 'Vertex' identifies each vertex uniquely:
typedef GraphTraits::vertex_descriptor Vertex;
// Property type associated to each vertex:
struct VertexProperty {
string name; // Name of vertex (i.e., "location")
Vertex predecessor; // Predecessor along optimal path.
double distance; // Distance to the goal, along shortest path.
default_color_type color; // for use by dijkstra.
VertexProperty(const string& aName = "") : name(aName) { };
};
// Property type associated to each edge:
struct EdgeProperty {
double weight; // distance to travel along this edge.
EdgeProperty(double aWeight = 0.0) : weight(aWeight) { };
};
// Type of the graph used:
typedef adjacency_list<vecS, vecS, undirectedS, VertexProperty, EdgeProperty> Graph;
// Create a global graph object 'g'
Graph g;
// This is a visitor for the dijkstra algorithm. This visitor does nothing special.
struct do_nothing_dijkstra_visitor {
template <typename Vertex, typename Graph>
void initialize_vertex(Vertex u, const Graph& g) const { };
template <typename Vertex, typename Graph>
void examine_vertex(Vertex u, const Graph& g) const { };
template <typename Edge, typename Graph>
void examine_edge(Edge e, const Graph& g) const { };
template <typename Vertex, typename Graph>
void discover_vertex(Vertex u, const Graph& g) const { };
template <typename Edge, typename Graph>
void edge_relaxed(Edge e, const Graph& g) const { };
template <typename Edge, typename Graph>
void edge_not_relaxed(Edge e, const Graph& g) const { };
template <typename Vertex, typename Graph>
void finish_vertex(Vertex u, const Graph& g) const { };
};
Variables:
string tempName1, tempName2, tempString, data2;
int weight;
string inputFile;
int choice;
Vertex cur_v, start_v, goal_v;
map<string, Vertex> name2v, name1v;
double totalDist, tempDist;
int numVert = 0;
Graph constructions based on file uploaded:
//build graph based on file loaded
getline(fin, tempString);
getline(fin, tempString);
stringstream tempSS(tempString);
while (getline(tempSS, tempName1, ',')) {
name2v[tempName1] = add_vertex(VertexProperty(tempName1), g);
numVert++;
}
getline(fin, tempString);
while (getline(fin, tempString)) {
tempString.erase(tempString.begin(), tempString.begin() + tempString.find('(') + 1);
tempString.erase(tempString.begin() + tempString.find(')'), tempString.end());
stringstream temp_ss(tempString);
getline(temp_ss, tempName1, ',');
getline(temp_ss, tempName2, ',');
temp_ss >> weight;
add_edge(name2v[tempName1], name2v[tempName2], EdgeProperty(weight), g);
}
name1v = name2v;
Prim's call:
cout << "Please enter the Vertex you would like to start at: ";
cin >> tempName1;
transform(tempName1.begin(), tempName1.end(), tempName1.begin(), ::toupper);
start_v = name1v[tempName1];
prim_minimum_spanning_tree(g, start_v,
get(&VertexProperty::predecessor, g),
get(&VertexProperty::distance, g),
get(&EdgeProperty::weight, g),
identity_property_map(),
do_nothing_dijkstra_visitor());
I tried to just include the code that matters. Like I said this code will work for Dijkstra but I am not sure how to make it work for Prim's. I am thinking I need to add more to the struct for the VertexProperty or have a map to store the min spannning tree. Thanks in advance.
I don't see what exactly you are asking (aside from code style and quality issues).
Here it is, note
the reduced visitor
removed confusing comments
and of course that I'm generating a random graph here because we don't have your input
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/graph/prim_minimum_spanning_tree.hpp>
#include <boost/graph/random.hpp>
#include <fstream>
#include <map>
#include <random>
#include <sstream>
typedef boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::undirectedS> GraphTraits;
typedef GraphTraits::vertex_descriptor Vertex;
struct DijkstraStuff {
Vertex predecessor;
double distance;
boost::default_color_type color; // for use by dijkstra.
};
struct VertexProperty : DijkstraStuff {
std::string name;
VertexProperty(const std::string &aName = "") : name(aName){};
};
struct EdgeProperty {
double weight; // distance to travel along this edge.
EdgeProperty(double aWeight = 0.0) : weight(aWeight){};
};
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, VertexProperty, EdgeProperty> Graph;
struct do_nothing_dijkstra_visitor : boost::default_dijkstra_visitor {};
int main() {
Graph g;
std::map<std::string, Vertex> name_map;
// read graph (random for now)
{
std::mt19937 prng{ 42 };
generate_random_graph(g, 10, 20, prng);
for (auto vd : boost::make_iterator_range(vertices(g))) {
name_map[g[vd].name = "NAME" + std::to_string(vd)] = vd;
}
std::uniform_real_distribution<double> weight_dist(0, 1);
for (auto ed : boost::make_iterator_range(edges(g))) {
g[ed].weight = weight_dist(prng);
}
}
print_graph(g, get(&VertexProperty::name, g));
Graph::vertex_descriptor start_v;
std::cout << "Please enter the Vertex you would like to start at: ";
{
std::string startName;
std::cin >> startName;
std::transform(startName.begin(), startName.end(), startName.begin(),
[](uint8_t ch) { return std::toupper(ch); });
start_v = name_map.at(startName);
}
boost::prim_minimum_spanning_tree(g, start_v, get(&VertexProperty::predecessor, g),
get(&VertexProperty::distance, g), get(&EdgeProperty::weight, g),
boost::identity_property_map(), do_nothing_dijkstra_visitor());
}
Printing the result
The resulting MST is encoded as the predecessor map. Print it as follows:
for (auto vd : boost::make_iterator_range(vertices(g))) {
auto p = g[vd].predecessor;
std::cout << "Pred of " << g[vd].name << " is " << g[p].name << "\n";
}
(This assumes all vertices are in the MST, for simplicity. This is the same as assuming you didn't have unconnected vertices in the input)
Prints (for the given random seed and starting vertex):
Pred of NAME1 is NAME9
Pred of NAME2 is NAME2
Pred of NAME3 is NAME6
Pred of NAME4 is NAME1
Pred of NAME5 is NAME6
Pred of NAME6 is NAME1
Pred of NAME7 is NAME3
Pred of NAME8 is NAME7
Pred of NAME9 is NAME0
I am new in Boost and I'm trying to write a program to Dijkstra-SP and Dijkstra with A*. The graph take random edge weight between [0,100]. I have many problems as we can see and I need some suggestions in order to solve it.
#include <boost/graph/grid_graph.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
typedef boost::grid_graph<2> grid;
typedef boost::graph_traits<grid>::vertices_size_type vertices_size_type;
typedef boost::property_map<grid, boost::vertex_index_t>::const_type GridIndexMapType;
GridIndexMapType gridIndexMap(get(boost::vertex_index, graph));
shared_array_property_map < vertex_descriptor, property_map<graph_t, vertex_index_t>::const_type>
p_map(num_vertices(graph), get(vertex_index, graph));
shared_array_property_map<double, property_map<graph_t, vertex_index_t>::const_type>
d_map(num_vertices(graph), get(vertex_index, graph));
struct edge_weight_map;
namespace boost
{
template<>
struct property_map< graph_t, edge_weight_t > {
typedef edge_weight_map type;
typedef edge_weight_map const_type;
};
}
/*
Map from edges to weight values
*/
struct edge_weight_map
{
typedef double value_type;
typedef value_type reference;
typedef edge_descriptor key_type;
typedef boost::readable_property_map_tag category;
const graph_t& m_graph;
edge_weight_map(const graph_t& g)
:m_graph(g) { }
reference operator[](key_type e) const; // implemented below
};
typedef boost::property_map<graph_t, boost::edge_weight_t>::const_type
const_edge_weight_map;
typedef boost::property_traits<const_edge_weight_map>::reference
edge_weight_map_value_type;
typedef boost::property_traits<const_edge_weight_map>::key_type
edge_weight_map_key;
namespace boost{
// PropertyMap valid expressions
edge_weight_map_value_type get(const_edge_weight_map pmap,
edge_weight_map_key e) {
return pmap[e]; }
// ReadablePropertyGraph valid expressions
const_edge_weight_map get(boost::edge_weight_t, const graph_t&g) {
return const_edge_weight_map(g); }
edge_weight_map_value_type get(boost::edge_weight_t tag, const graph_t& g,
edge_weight_map_key e)
{ return get(tag, g)[e]; }
}
edge_weight_map::reference
edge_weight_map::operator[](key_type e) const {
vertex_descriptor t = target(e,m_graph);
vertex_descriptor s = source(e,m_graph);
// f = f(t,s)
return f;
}
class grid_graph {
public:
friend std::ostream& operator<<(std::ostream&, const grid_graph&);
//friend grid_graph random_maze(std::size_t, std::size_t);
grid_graph():m_grid(create_grid(0, 0)) {};
grid_graph(std::size_t x, std::size_t y):m_grid(create_grid(x, y)){};
// The length of the grid_graph along the specified dimension.
vertices_size_type length(std::size_t d) const {return m_grid.length(d);}
private:
// Create the underlying rank-2 grid with the specified dimensions.
grid create_grid(std::size_t x, std::size_t y) {
boost::array<std::size_t, 2> lengths = { {x, y} };
return grid(lengths);
}
// The grid underlying the grid_graph
grid m_grid;
};
// Euclidean heuristic for a grid
//
// This calculates the Euclidean distance between a vertex and a goal
// vertex.
class euclidean_heuristic {
// public boost::astar_heuristic<filtered_grid, double>
public:
euclidean_heuristic(vertex_descriptor goal):m_goal(goal) {};
double operator()(vertex_descriptor v) {
return sqrt(pow(m_goal[0] - v[0], 2) + pow(m_goal[1] - v[1], 2));
}
private:
vertex_descriptor m_goal;
};
// Exception thrown when the goal vertex is found
struct found_goal {};
// Visitor that terminates when we find the goal vertex
struct astar_goal_visitor:public boost::default_astar_visitor
{
astar_goal_visitor(vertex_descriptor goal):m_goal(goal) {};
void examine_vertex(vertex_descriptor u, const filtered_grid&) {
if (u == m_goal)
throw found_goal();
}
private:
vertex_descriptor m_goal;
};
void find_shortest(int start, int end, std::vector<std::map<ulong,unlong>>&
graph)
{
std::set<unlong> searchedList;
std::priority_queue<std::pair<ulong, ulong>> frontierList;
frontierList.push(std::make_pair(0, start));
while(!frontierList.empty())
{
std::pair<ulong, ulong> next = frontierList.top();
frontierList.pop();
if (next.second == end) {
std::cout << "Min Cost: " << next.first << "\n";
return;
}
if (searchedList.find(next.second) != searchedList.end()) {
continue;
}
searchedList.insert(next.second);
for(std::map<ulong,unlong>::const_iterator loop = graph[next.second].begin(); loop != graph[next.second].end(); ++loop)
{
frontierList.push(std::make_pair(next.first + loop->second, loop->first));
}
}
boolgrid_graph::solve() {
// The predecessor map is a vertex-to-vertex mapping.
typedef boost::unordered_map<vertex_descriptor,
vertex_descriptor,
vertex_hash> pred_map;
pred_map predecessor;
boost::associative_property_map<pred_map> pred_pmap(predecessor);
// The distance map is a vertex-to-distance mapping.
typedef boost::unordered_map<vertex_descriptor,
distance,
vertex_hash> dist_map;
dist_map distance;
boost::associative_property_map<dist_map> dist_pmap(distance);
vertex_descriptor s = source();
vertex_descriptor g = goal();
euclidean_heuristic heuristic(g);
astar_goal_visitor visitor(g);
try {
astar_search(m_barrier_grid, s, heuristic,
boost::weight_map(weight).
predecessor_map(pred_pmap).
distance_map(dist_pmap).
visitor(visitor) );
} catch(found_goal fg) {
// Walk backwards from the goal through the predecessor chain adding
// vertices to the solution path.
for (vertex_descriptor u = g; u != s; u = predecessor[u])
m_solution.insert(u);
m_solution.insert(s);
m_solution_length = distance[g];
return true;
}
return false;
}
int main(int,char*[]){
boost::array<std::size_t, 2> lengths = { { 30,50 } };
GraphType grid(lengths);
if (grid_graph.solve())
output << std::endl << "Solution length " << m.m_solution_length;
}
I am using Boost C++ Library to build a adjacency list to represent an undirected graph. Each edge on the graph is associated with respective weights and I want to check if the weight is greater than some threshold than I merge the 2 vertices together.
How I merge:
For the vertex to merge, gather all the edges to and from this vertex and direct the edges to the new vertex
Clear the merging vertex
Remove the vertex
My Problem:
I use a simple program to first construct the algorithm before I use it for purpose. In this program I am using simple family tree method to perform the above steps. When I remove the vertex using the function remove_vertex(vertex, Graph) I get a segmentation fault.
I cannot figure out if once the vertex is removed, does the graph automatically updates its structure?
My C++ code is as follows:
#include <boost/graph/adjacency_list.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/config.hpp>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef boost::property<boost::vertex_index_t, int> vertex_property;
typedef boost::property<boost::edge_weight_t, float> edge_property;
typedef typename boost::adjacency_list <boost::vecS,
boost::vecS,
boost::undirectedS,
vertex_property,
edge_property> Graph;
void boostSampleGraph() {
enum family {
Jeanie, Debbie, Rick, John, Amanda, Margaret, Benjamin, N };
const char *name[] = { "Jeanie", "Debbie", "Rick", "John", "Amanda",
"Margaret", "Benjamin", "N"
};
/* actual graph structure */
Graph graph;
/* add vertices to the graph */
add_vertex(Jeanie, graph);
add_vertex(Debbie, graph);
add_vertex(Rick, graph);
add_vertex(John, graph);
add_vertex(Amanda, graph);
add_vertex(Margaret, graph);
add_vertex(Benjamin, graph);
// add_vertex(N, graph);
/* add edges to the vertices in the graph*/
add_edge(Jeanie, Debbie, edge_property(0.5f), graph);
add_edge(Jeanie, Rick, edge_property(0.2f), graph);
add_edge(Jeanie, John, edge_property(0.1f), graph);
add_edge(Debbie, Amanda, edge_property(0.3f), graph);
add_edge(Rick, Margaret, edge_property(0.4f), graph);
add_edge(John, Benjamin, edge_property(0.6f), graph);
// add_edge(Benjamin, Benjamin, edge_property(0.7f), graph);
/* vertex iterator */
boost::graph_traits<Graph>::vertex_iterator i, end;
typedef typename boost::graph_traits<
Graph>::adjacency_iterator AdjacencyIterator;
/* gets the graph vertex index */
typedef typename boost::property_map
<Graph, boost::vertex_index_t >::type IndexMap;
IndexMap index_map = get(boost::vertex_index, graph);
/* container to hold the edge descriptor info */
typedef typename boost::graph_traits<
Graph>::edge_descriptor EdgeDescriptor;
EdgeDescriptor e_descriptor;
typedef typename boost::property_map<Graph, boost::edge_weight_t
>::type EdgePropertyAccess;
EdgePropertyAccess edge_weights = get(boost::edge_weight, graph);
typedef typename boost::property_traits<boost::property_map<
Graph, boost::edge_weight_t>::const_type>::value_type EdgeValue;
float edge_size = num_vertices(graph);
std::cout << "# of Edges: " << edge_size << std::endl;
/* iterator throught the graph */
for (tie(i, end) = vertices(graph); i != end; ++i) {
std::cout << name[get(index_map, *i)];
AdjacencyIterator ai, a_end;
tie(ai, a_end) = adjacent_vertices(*i, graph);
if (ai == a_end) {
std::cout << " has no children";
} else {
std::cout << " is the parent of ";
}
for (; ai != a_end; ++ai) {
AdjacencyIterator tmp;
bool found;
tie(e_descriptor, found) = edge(*i, *ai, graph);
float weights_ = 0.0f;
if (found) {
EdgeValue edge_val = boost::get(
boost::edge_weight, graph, e_descriptor);
weights_ = edge_val;
if (weights_ > 0.3f) {
// - remove and merge
AdjacencyIterator aI, aEnd;
tie(aI, aEnd) = adjacent_vertices(*ai, graph);
for (; aI != aEnd; aI++) {
EdgeDescriptor ed;
bool located;
tie(ed, located) = edge(*aI, *ai, graph);
if (located && *aI != *i) {
add_edge(
get(index_map, *i), get(index_map, *aI), graph);
}
std::cout << "\n DEBUG: " << *i << " "
<< *ai << " "
<< *aI << " ";
}
std::cout << std::endl;
clear_vertex(*ai, graph);
remove_vertex(*ai, graph);
// std::cout << "\nGraph Size: " <<
// num_vertices(graph) << std::endl;
}
}
// ai = tmp;
std::cout << name[get(index_map, *ai)];
if (boost::next(ai) != a_end) {
std::cout << ", ";
}
}
std::cout << std::endl << std::endl;
}
std::cout << "\nGraph Size: " << num_vertices(graph) << std::endl;
}
int main(int argc, const char *argv[]) {
boostSampleGraph();
return 0;
}
Could I get some help and ideas on where did I got this wrong.
I don't know what you're actually trying to achieve with the algorithm shown in the OP.
Here's, however, one that simplifies the code considerably, so that at least it works safely:
uses Vertex bundled property type for vertex (id, name)
uses ranged for loops where possible (see mir, shorthand to create a boost::iterator_range from a std::pair of iterators)
the code is written in container-selection independent way (so it works just the same when you replace vecS by listS in the Graph type declaration)
it uses out_edges instead of adjacent_vertices to benefit more from the AdjacencyGraph concept, and avoid reverse-lookup of edge-descriptors by (source, target) vertices
most importantly, it uses a std::set<vertex_descriptor> of vertices that have been "removed". The actual removal happens later so we don't get undefined behaviour while iterating a changing container
runs cleanly under valgrind
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
struct Vertex {
int id;
const char* name;
Vertex(int i = -1, const char* name = "default") : id(i), name(name) {}
};
template <typename It> boost::iterator_range<It> mir(std::pair<It, It> const& p) {
return boost::make_iterator_range(p.first, p.second);
}
template <typename It> boost::iterator_range<It> mir(It b, It e) {
return boost::make_iterator_range(b, e);
}
typedef typename boost::adjacency_list<
boost::vecS, boost::vecS,
boost::undirectedS,
Vertex, // bundled properties (id, name)
boost::property<boost::edge_weight_t, float> // interior property
> Graph;
Graph make() {
Graph graph;
auto Jeanie = add_vertex(Vertex { 0, "Jeanie" }, graph);
auto Debbie = add_vertex(Vertex { 1, "Debbie" }, graph);
auto Rick = add_vertex(Vertex { 2, "Rick" }, graph);
auto John = add_vertex(Vertex { 3, "John" }, graph);
auto Amanda = add_vertex(Vertex { 4, "Amanda" }, graph);
auto Margaret = add_vertex(Vertex { 5, "Margaret" }, graph);
auto Benjamin = add_vertex(Vertex { 6, "Benjamin" }, graph);
add_edge(Jeanie, Debbie, 0.5f, graph);
add_edge(Jeanie, Rick, 0.2f, graph);
add_edge(Jeanie, John, 0.1f, graph);
add_edge(Debbie, Amanda, 0.3f, graph);
add_edge(Rick, Margaret, 0.4f, graph);
add_edge(John, Benjamin, 0.6f, graph);
return graph;
}
Graph reduce(Graph graph) {
/* vertex iterator */
using vertex_descriptor = boost::graph_traits<Graph>::vertex_descriptor;
std::cout << "# of vertices: " << num_vertices(graph) << "\n";
std::cout << "# of edges: " << num_edges(graph) << "\n";
std::set<vertex_descriptor> to_remove;
/* iterator throught the graph */
for (auto self : mir(vertices(graph)))
{
std::cout << graph[self].name << (boost::empty(mir(out_edges(self, graph)))? " has no children " : " is the parent of ");
for(auto edge : mir(out_edges(self, graph))) {
auto weight = boost::get(boost::edge_weight, graph, edge);
auto mid_point = target(edge, graph);
if (to_remove.count(mid_point)) // already elided
break;
if (weight > 0.3f) {
std::set<vertex_descriptor> traversed;
for (auto hop : mir(out_edges(mid_point, graph))) {
auto hop_target = target(hop, graph);
if (hop_target != self)
add_edge(self, hop_target, graph);
std::cout << "\n DEBUG: " << graph[self].name << " " << graph[mid_point].name << " " << graph[hop_target].name << " ";
}
std::cout << "\n";
clear_vertex(mid_point, graph);
to_remove.insert(mid_point);
}
std::cout << graph[mid_point].name;
}
std::cout << "\n\n";
}
for(auto vd : to_remove)
{
clear_vertex(vd, graph);
remove_vertex(vd, graph);
}
std::cout << "# of vertices: " << num_vertices(graph) << "\n";
std::cout << "# of edges: " << num_edges(graph) << "\n";
return graph;
}
void save(Graph const& g, const char* fname);
int main() {
auto const g = make();
auto const h = reduce(g);
save(g, "before.dot");
save(h, "after.dot");
}
#include <boost/graph/graphviz.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/property_map/function_property_map.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <boost/format.hpp>
#include <fstream>
void save(Graph const& g, const char* fname) {
std::ofstream ofs(fname);
using namespace boost;
write_graphviz(
ofs,
g,
make_label_writer(make_function_property_map<Graph::vertex_descriptor, std::string>([&] (Graph::vertex_descriptor v){ return g[v].name; })),
make_label_writer(make_transform_value_property_map([](float v){return boost::format("%1.1f") % v;}, boost::get(edge_weight, g)))
);
}
Prints
# of vertices: 7
# of edges: 6
Jeanie is the parent of
DEBUG: Jeanie Debbie Jeanie
DEBUG: Jeanie Debbie Amanda
DebbieJohnAmanda
Debbie has no children
Rick is the parent of Jeanie
DEBUG: Rick Margaret Rick
Margaret
John is the parent of Jeanie
DEBUG: John Benjamin John
Benjamin
Amanda is the parent of Jeanie
Margaret has no children
Benjamin has no children
# of vertices: 4
# of edges: 3
Graph before:
Graph after:
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.
I have problems getting to compile the BFS of a very simple graph. Whatever I do I get various compiler messages about unmatched method calls (I've tried boost::visitor and extending boost::default_bfs_visitor etc.)
#include <stdint.h>
#include <iostream>
#include <vector>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
int main() {
typedef boost::adjacency_list<boost::vecS, boost::hash_setS, boost::undirectedS, uint32_t, uint32_t, boost::no_property> graph_t;
graph_t graph(4);
graph_t::vertex_descriptor a = boost::vertex(0, graph);
graph_t::vertex_descriptor b = boost::vertex(1, graph);
graph_t::vertex_descriptor c = boost::vertex(2, graph);
graph_t::vertex_descriptor d = boost::vertex(3, graph);
graph[a] = 0;
graph[b] = 1;
graph[c] = 2;
graph[d] = 3;
std::pair<graph_t::edge_descriptor, bool> result = boost::add_edge(a, b, 0, graph);
result = boost::add_edge(a, c, 1, graph);
result = boost::add_edge(c, b, 2, graph);
class {
public:
void initialize_vertex(const graph_t::vertex_descriptor &s, graph_t &g) {
std::cout << "Initialize: " << g[s] << std::endl;
}
void discover_vertex(const graph_t::vertex_descriptor &s, graph_t &g) {
std::cout << "Discover: " << g[s] << std::endl;
}
void examine_vertex(const graph_t::vertex_descriptor &s, graph_t &g) {
std::cout << "Examine vertex: " << g[s] << std::endl;
}
void examine_edge(const graph_t::edge_descriptor &e, graph_t &g) {
std::cout << "Examine edge: " << g[e] << std::endl;
}
void tree_edge(const graph_t::edge_descriptor &e, graph_t &g) {
std::cout << "Tree edge: " << g[e] << std::endl;
}
void non_tree_edge(const graph_t::edge_descriptor &e, graph_t &g) {
std::cout << "Non-Tree edge: " << g[e] << std::endl;
}
void gray_target(const graph_t::edge_descriptor &e, graph_t &g) {
std::cout << "Gray target: " << g[e] << std::endl;
}
void black_target(const graph_t::edge_descriptor &e, graph_t &g) {
std::cout << "Black target: " << g[e] << std::endl;
}
void finish_vertex(const graph_t::vertex_descriptor &s, graph_t &g) {
std::cout << "Finish vertex: " << g[s] << std::endl;
}
} bfs_visitor;
boost::breadth_first_search(graph, a, bfs_visitor);
return 0;
}
How to visit the graph using bfs_visitor?
PS. I've seen and compiled "How to create a C++ Boost undirected graph and traverse it in depth first search (DFS) order?" but it didn't help.
You can see here a list of the overloads of breadth_first_search. If you don't want to specify every one of the parameters you need to use the named-parameter version. It would look like this:
breadth_first_search(graph, a, boost::visitor(bfs_visitor));
This would work as is if you had used vecS as your VertexList storage in your graph definition or if you had constructed and initialized an internal vertex_index property map. Since you are using hash_setS you need to change the invocation to:
breath_first_search(graph, a, boost::visitor(bfs_visitor).vertex_index_map(my_index_map));
You are already using an index map in your uint32_t bundled property. You can use get(boost::vertex_bundle, graph) to access it.
There was also a problem with your visitor. You should derive it from boost::default_bfs_visitor and the graph_t parameter of your member functions needs to be const qualified.
Full code:
#include <stdint.h>
#include <iostream>
#include <vector>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
typedef boost::adjacency_list<boost::vecS, boost::hash_setS, boost::undirectedS, uint32_t, uint32_t, boost::no_property> graph_t;
struct my_visitor : boost::default_bfs_visitor{
void initialize_vertex(const graph_t::vertex_descriptor &s, const graph_t &g) const {
std::cout << "Initialize: " << g[s] << std::endl;
}
void discover_vertex(const graph_t::vertex_descriptor &s, const graph_t &g) const {
std::cout << "Discover: " << g[s] << std::endl;
}
void examine_vertex(const graph_t::vertex_descriptor &s, const graph_t &g) const {
std::cout << "Examine vertex: " << g[s] << std::endl;
}
void examine_edge(const graph_t::edge_descriptor &e, const graph_t &g) const {
std::cout << "Examine edge: " << g[e] << std::endl;
}
void tree_edge(const graph_t::edge_descriptor &e, const graph_t &g) const {
std::cout << "Tree edge: " << g[e] << std::endl;
}
void non_tree_edge(const graph_t::edge_descriptor &e, const graph_t &g) const {
std::cout << "Non-Tree edge: " << g[e] << std::endl;
}
void gray_target(const graph_t::edge_descriptor &e, const graph_t &g) const {
std::cout << "Gray target: " << g[e] << std::endl;
}
void black_target(const graph_t::edge_descriptor &e, const graph_t &g) const {
std::cout << "Black target: " << g[e] << std::endl;
}
void finish_vertex(const graph_t::vertex_descriptor &s, const graph_t &g) const {
std::cout << "Finish vertex: " << g[s] << std::endl;
}
};
int main() {
graph_t graph(4);
graph_t::vertex_descriptor a = boost::vertex(0, graph);
graph_t::vertex_descriptor b = boost::vertex(1, graph);
graph_t::vertex_descriptor c = boost::vertex(2, graph);
graph_t::vertex_descriptor d = boost::vertex(3, graph);
graph[a] = 0;
graph[b] = 1;
graph[c] = 2;
graph[d] = 3;
std::pair<graph_t::edge_descriptor, bool> result = boost::add_edge(a, b, 0, graph);
result = boost::add_edge(a, c, 1, graph);
result = boost::add_edge(c, b, 2, graph);
my_visitor vis;
breadth_first_search(graph, a, boost::visitor(vis).vertex_index_map(get(boost::vertex_bundle,graph)));
return 0;
}
I faced the same problem, but compared to the answer provided by user1252091 my vertex type is a struct that doesn't include an integer that can be used to create a vertex_index_map, therefore the line
breadth_first_search(graph, a, boost::visitor(vis).vertex_index_map(get(boost::vertex_bundle,graph)));
wouldn't work in my case. Eventually I figured out how to create an external vertex_index_map (thanks also to this answer) and pass it to the breadth_first_search function. Here is a working example in case it helps others:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <iostream>
struct Person
{
std::string Name;
unsigned int YearBorn;
};
typedef boost::adjacency_list <boost::vecS, boost::hash_setS, boost::bidirectionalS, Person, boost::no_property > FamilyTree;
typedef boost::graph_traits<FamilyTree>::vertex_descriptor Vertex;
typedef boost::graph_traits<FamilyTree>::edge_descriptor Edge;
template <class Graph>
class BfsVisitor : public boost::default_bfs_visitor
{
public:
typedef typename boost::graph_traits<Graph>::vertex_descriptor VertexDescriptor;
typedef typename boost::graph_traits<Graph>::edge_descriptor EdgeDescriptor;
BfsVisitor(std::vector<VertexDescriptor>& nodesVisited)
: m_nodesVisited(nodesVisited){}
void tree_edge(EdgeDescriptor e, const Graph& g) const
{
VertexDescriptor u = source(e, g);
VertexDescriptor v = target(e, g);
m_nodesVisited.push_back(v);
}
private:
std::vector<VertexDescriptor>& m_nodesVisited;
};
const Person Abe_Simpson {"Abe_Simpson", 0};
const Person Mona_Simpson { "Mona_Simpson", 0};
const Person Herb_Simpson { "Herb_Simpson", 0};
const Person Homer_Simpson { "Homer_Simpson", 0};
const Person Clancy_Bouvier { "Clancy_Bouvier", 0};
const Person Jacqueline_Bouvier { "Jacqueline_Bouvier", 0};
const Person Marge_Bouvier { "Marge_Bouvier", 0};
const Person Patty_Bouvier { "Patty_Bouvier", 0};
const Person Selma_Bouvier { "Selma_Bouvier", 0};
const Person Bart_Simpson { "Bart_Simpson", 0};
const Person Lisa_Simpson { "Lisa_Simpson", 0};
const Person Maggie_Simpson { "Maggie_Simpson", 0};
const Person Ling_Bouvier { "Ling_Bouvier", 0};
int main(void)
{
std::cout << __FUNCTION__ << "\n";
FamilyTree g;
// nodes
auto v_Abe_Simpson = boost::add_vertex(Abe_Simpson,g);
auto v_Mona_Simpson = boost::add_vertex(Mona_Simpson,g);
auto v_Herb_Simpson = boost::add_vertex(Herb_Simpson,g);
auto v_Homer_Simpson = boost::add_vertex(Homer_Simpson,g);
auto v_Clancy_Bouvier = boost::add_vertex(Clancy_Bouvier,g);
auto v_Jacqueline_Bouvier = boost::add_vertex(Jacqueline_Bouvier,g);
auto v_Marge_Bouvier = boost::add_vertex(Marge_Bouvier,g);
auto v_Patty_Bouvier = boost::add_vertex(Patty_Bouvier,g);
auto v_Selma_Bouvier = boost::add_vertex(Selma_Bouvier,g);
auto v_Bart_Simpson = boost::add_vertex(Bart_Simpson,g);
auto v_Lisa_Simpson = boost::add_vertex(Lisa_Simpson,g);
auto v_Maggie_Simpson = boost::add_vertex(Maggie_Simpson,g);
auto v_Ling_Bouvier = boost::add_vertex(Ling_Bouvier,g);
// connections
boost::add_edge(v_Abe_Simpson, v_Herb_Simpson, g);
boost::add_edge(v_Abe_Simpson, v_Homer_Simpson, g);
boost::add_edge(v_Mona_Simpson, v_Herb_Simpson, g);
boost::add_edge(v_Mona_Simpson, v_Homer_Simpson, g);
boost::add_edge(v_Clancy_Bouvier, v_Marge_Bouvier, g);
boost::add_edge(v_Clancy_Bouvier, v_Patty_Bouvier, g);
boost::add_edge(v_Clancy_Bouvier, v_Selma_Bouvier, g);
boost::add_edge(v_Jacqueline_Bouvier, v_Marge_Bouvier, g);
boost::add_edge(v_Jacqueline_Bouvier, v_Patty_Bouvier, g);
boost::add_edge(v_Jacqueline_Bouvier, v_Selma_Bouvier, g);
boost::add_edge(v_Homer_Simpson, v_Bart_Simpson, g);
boost::add_edge(v_Homer_Simpson, v_Lisa_Simpson, g);
boost::add_edge(v_Homer_Simpson, v_Maggie_Simpson, g);
boost::add_edge(v_Marge_Bouvier, v_Bart_Simpson, g);
boost::add_edge(v_Marge_Bouvier, v_Lisa_Simpson, g);
boost::add_edge(v_Marge_Bouvier, v_Maggie_Simpson, g);
boost::add_edge(v_Selma_Bouvier, v_Ling_Bouvier, g);
typedef std::map<Vertex, size_t>IndexMap;
IndexMap mapIndex;
boost::associative_property_map<IndexMap> propmapIndex(mapIndex);
size_t i=0;
FamilyTree::vertex_iterator vi, vi_end;
for (boost::tie(vi, vi_end) = boost::vertices(g); vi != vi_end; ++vi)
{
boost::put(propmapIndex, *vi, i++);
}
for (boost::tie(vi, vi_end) = boost::vertices(g); vi != vi_end; ++vi)
{
Vertex vParent = *vi;
std::vector<Vertex> vertexDescriptors;
BfsVisitor<FamilyTree> bfsVisitor(vertexDescriptors);
breadth_first_search(g, vParent, visitor(bfsVisitor).vertex_index_map(propmapIndex));
std::cout << "\nDecendants of " << g[vParent].Name << ":\n";
for (auto v : vertexDescriptors)
{
Person p = g[v];
std::cout << p.Name << "\n";
}
}
getchar();
return 0;
}