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
Related
I'm using the Boost graph library exploiting the following definitions
template <typename Vertex>
using graph = boost::adjacency_list<boost::listS,
boost::vecS,
boost::bidirectionalS,
Vertex>
template <typename Vertex>
using vertex = typename graph<Vertex>::vertex_descriptor;
where the template parameter Vertex is employed to use the BGL with bundled properties.
I'm not that confident with boost at the moment and I'd like to understand if is there a way to get the begin() and end() iterators of the "bundled property list".
In other words, let's assume I have this struct
struct City
{
string name;
int population;
vector<int> zipcodes;
};
and I want to use it as template parameter for my graph. I know I can iterate over vertexes like this
(assuming g is my adjacency list)
for(auto vd : boost::make_iterator_range(vertices(g))
{
auto v = g[*vd];
// do something with v
}
yet I'd like to do this
for(auto & v : some_iterator)
// v is a city ...
is there any way to do this ?
I've adapted my code from your now-deleted question to the more specific example. By now you already realize you are NOT in fact iterating vertices, but their bundles.
I suggest you use a transforming/indirected iterator adaptor. The easiest way I can think of is to use Boost Range Adaptors, specifically using transformed:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/range/adaptors.hpp>
using boost::adaptors::transformed;
template <typename Vertex> struct Wrapper {
using graph = boost::adjacency_list<boost::listS, boost::vecS,
boost::bidirectionalS, Vertex>;
using vertex = typename graph::vertex_descriptor;
auto bundles() {
auto accessor = [map = get(boost::vertex_bundle, _g)](vertex v) -> auto& {
return map[v];
};
return vertices(_g) | transformed(accessor);
}
auto bundles() const {
auto accessor = [map = get(boost::vertex_bundle, _g)](vertex v) -> auto& {
return map[v];
};
return vertices(_g) | transformed(accessor);
}
private:
graph _g {5};
};
struct City {
std::string name;
int population;
std::vector<int> zipcodes;
};
static int id_gen = 0;
struct Sample2 { int id = ++id_gen; };
#include <iostream>
#include <iomanip>
int main() {
Wrapper<City> demo;
for (City& c : demo.bundles()) {
c.name = "name " + std::to_string(rand() % 100);
c.population = rand() % 128 * 190'000;
c.zipcodes = {1234, 2345};
}
auto const& const_ref = demo;
for (City const& c : const_ref.bundles()) {
std::cout << std::quoted(c.name) << ", population " << c.population << "\n";
}
}
Prints
"name 83", population 13300000
"name 77", population 21850000
"name 93", population 24130000
"name 86", population 20520000
"name 49", population 14630000
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.
I need to run A* on a graph with some of the edges removed. To do so I construct a filtered graph with blacklisted edges and I want to run A* on the filtered graph. The blacklisted edges are embedded in the class BlackListEdgeConstraint, that I initialize by passing to its constructor the list of the forbidden edges. This BlackListEdgeConstraint is correctly constructed, and I construct the filtered graph with these constrain. The problem is that when I run A* on the filtered graph, another BlackListEdgeConstraint object is mysteriously constructed with an empty constructor, and no edge is in effect blacklisted. Why is it happening?
This is my complete code:
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/graph/astar_search.hpp>
using namespace std;
typedef std::pair<int, int> Edge;
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS, boost::no_property, boost::property<boost::edge_weight_t, int> > graph_t;
typedef boost::graph_traits<graph_t>::vertex_descriptor vertex_descriptor;
struct BlackListEdgeConstraint
{
private:
std::set<Edge> blackList;
graph_t* g;
public:
BlackListEdgeConstraint():blackList(std::set<Edge>() ),g(NULL){throw std::runtime_error("This should not be called");};
BlackListEdgeConstraint(std::set<Edge>& list, graph_t* g_) : blackList(list), g(g_)
{
Edge edge = *blackList.begin();
std::cout<<"The black list contains "<< edge.first<<"-"<<edge.second<<std::endl;
}
/**
* This is the "predicate function" used by boost::filtered_graph (
* see http://www.boost.org/doc/libs/1_64_0/libs/graph/doc/filtered_graph.html )
* It it returns true, the edge is included in the filtered graph, otherwise it is excluded.
*/
bool operator()(const boost::graph_traits<graph_t>::edge_descriptor& e) const
{
Edge edge(source(e,*g), target(e,*g) );
std::cout<<"Should we include edge "<<source(e,*g)<<" ->"<< target(e,*g)<<" represented by a descriptor "<<e<<"? ";
//Include the edge if it's not in the blacklist.
bool include = (blackList.find( edge ) == blackList.end() );
std::cout<<include<<std::endl;
return include;
}
};
template<class GraphType>
class MyHeuristic : public boost::astar_heuristic<GraphType, double>
{
private:
const GraphType* g;
public:
MyHeuristic(const GraphType* g_): g(g_) {};
double operator()(vertex_descriptor v)
{
return 0;
}
};
//Used to terminate our search
struct GoalsReached{};
class MyVisitor : public boost::default_astar_visitor
{
private:
vertex_descriptor goal;
public:
MyVisitor(vertex_descriptor goal_): goal(goal_){};
template<class GraphType>
void examine_vertex(vertex_descriptor u, const GraphType& g)
{ if (u==goal) throw GoalsReached(); }
};
int main()
{
Edge edge_array[] = {Edge(0,1), Edge(1,2), Edge(2,3), Edge(3,0), Edge(1,3) };
int weights[] = {1,1,1,1,1};
int num_arcs = sizeof(edge_array) / sizeof(Edge);
int num_nodes = 4;
// Graph created from the list of edges
graph_t g(edge_array, edge_array + num_arcs, weights, num_nodes);
// Create descriptor for the source node
vertex_descriptor s = vertex(0, g);
vertex_descriptor goal = vertex(3,g) ;
std::set<Edge> blacklist; blacklist.insert( Edge(1,3) );
BlackListEdgeConstraint filter(blacklist, &g);
boost::filtered_graph<graph_t, BlackListEdgeConstraint> filtered(g, filter);
cout<<"filtered constructed"<<endl;
// Create vectors to store the predecessors (p) and the distances from the root (d)
std::vector<vertex_descriptor> p(num_vertices(filtered));
std::vector<int> d(num_vertices(filtered));
try{
cout<<"Launching astar_search"<<endl;
boost::astar_search(filtered, s,
MyHeuristic<boost::filtered_graph<graph_t, BlackListEdgeConstraint>>(&filtered),
boost::predecessor_map(&p[0]).
distance_map(&d[0]).
visitor(MyVisitor(goal) )
);
cout<<"astar_search launched"<<endl;
}catch(const GoalsReached& )
{ // Print the path
std::vector<boost::graph_traits<graph_t>::vertex_descriptor > path;
boost::graph_traits<graph_t>::vertex_descriptor current = goal;
while(current!=s)
{
path.push_back(current);
current = p[current];
}
path.push_back(s);
// Prints the path obtained in reverse
std::vector<boost::graph_traits<graph_t>::vertex_descriptor >::reverse_iterator it;
for (it = path.rbegin(); it != path.rend(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
}
return EXIT_SUCCESS;
}
And this is the output:
The black list contains 1-3
filtered constructed
Launching astar_search
terminate called after throwing an instance of 'std::runtime_error'
what(): This should not be called
My boost version is 1.54
The problem is that, when boost::astar_search(..) is invoked, the empty constructor BlackListEdgeConstraint() is called.
I don't know how you reach the conclusion. I cannot reproduce that:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/graph/astar_search.hpp>
struct VertexProperties {
};
struct EdgeProperties {
double weight = 1;
};
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexProperties, EdgeProperties> MyGraph;
struct StreetDirectory {
using Graph = MyGraph;
using Edge = Graph::edge_descriptor;
using Vertex = Graph::vertex_descriptor;
};
struct BlackListEdgeConstraint : StreetDirectory
{
private:
std::set<StreetDirectory::Edge> blackList;
public:
BlackListEdgeConstraint(const std::set<Edge>& list) : blackList(list) {};
BlackListEdgeConstraint()
{
throw std::runtime_error("This should not be called");
};
bool operator()(const Edge& e) const
{
//Include the edge if it's not in the blacklist.
return blackList.find(e) == blackList.end();
}
};
int main() {
MyGraph graph;
const std::set<StreetDirectory::Edge> blacklistEdges {
add_edge(1,2,graph).first,
add_edge(1,3,graph).first,
add_edge(2,4,graph).first,
};
add_edge(4,2,graph);
BlackListEdgeConstraint filter(blacklistEdges);
boost::filtered_graph<MyGraph, BlackListEdgeConstraint> filtered(graph, filter);
std::vector<StreetDirectory::Vertex> p(boost::num_vertices(filtered)); //Output variable
std::vector<double> d(boost::num_vertices(filtered)); //Output variable
boost::default_astar_visitor vis;
boost::astar_search(
filtered,
1,
[](auto /*vd*/) { return 1; },
boost::predecessor_map(&p[0]).
weight_map(boost::get(&EdgeProperties::weight, filtered)).
distance_map(&d[0]).
visitor(vis)
);
}
Notes
in general functors are passed by value in (standard) library algorithms. So you'd use std::reference_wrapper<BlackListEdgeConstraint> if you wanted to use the same instance. But like I said, I don't see it happening, so it's not a problem AFAICT
in your sample there seemed to be no edge-weight map indicated. I don't see how that should have compiled
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;
}
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;
}