I've used BGL before for representing graphs, but this is my first time with
an algorithm. I've been stuck for many hours trying to define a property map
with bundled properties, I'd really appreciate some help. I'm using gcc4.3,
boost 1.34. An example program and the compiler error are:
-------------------------------------------------------------
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/astar_search.hpp>
using namespace std;
class Point {
public:
double p_[2];
};
struct EdgeProp {
double cost;
};
typedef boost::adjacency_list<boost::vecS,
boost::vecS,
boost::undirectedS,
Point*,
EdgeProp> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor VertexRef;
class AStarHeuristic : public boost::astar_heuristic<Graph, double>
{
public:
double operator()( VertexRef vertex ) const {return 0.0;}
};
// exception for termination
struct FoundGoal {};
//
// A* Visitor that terminates when we reach the goal
//
class AStarVisitor : public boost::default_astar_visitor
{
public:
AStarVisitor( const VertexRef &goal )
: goal_(goal) {}
template <class Graph>
void examine_vertex( VertexRef vertex, Graph &g )
{
if( vertex == goal_ )
throw FoundGoal();
}
private:
VertexRef goal_;
};
bool
searchThroughGraph( const Graph &graph,
VertexRef start,
VertexRef goal,
std::vector<VertexRef> &shortestPath )
{
AStarHeuristic aStarHeuristic;
AStarVisitor aStarVisitor( goal );
typedef boost::property_map<Graph, double EdgeProp::*>::type
EdgeWeightMap;
EdgeWeightMap edgeWeightMap = get(&EdgeProp::cost, graph);
std::vector<VertexRef> predecessors(num_vertices(graph));
try {
astar_search( graph,
start,
aStarHeuristic,
boost::weight_map(edgeWeightMap).
predecessor_map(&predecessors[0]).
visitor(aStarVisitor) );
}
catch ( const FoundGoal& )
{
shortestPath.clear();
for ( VertexRef vertex = goal;; vertex = predecessors[vertex] )
{
shortestPath.push_back( vertex );
if ( predecessors[vertex]==vertex ) break;
}
std::reverse( shortestPath.begin(), shortestPath.end() );
return true;
}
// If we get to here, we couldn't reach the goal
return false;
}
int main()
{
Graph graph;
std::vector<VertexRef> path;
searchThroughGraph(graph,0,1,path);
return 0;
}
-------------------------------------------------------------
/home/a.brooks/shh/src/libs/prm/test/stupid.cpp: In function ‘bool
searchThroughGraph(const Graph&, VertexRef, VertexRef, std::vector<unsigned
int, std::allocator<unsigned int> >&)’:
/home/a.brooks/shh/src/libs/prm/test/stupid.cpp:64: error: conversion
from ‘boost::bundle_property_map<const boost::adjacency_list<boost::vecS,
boost::vecS, boost::undirectedS, Point*, EdgeProp, boost::no_property,
boost::listS>, boost::detail::edge_desc_impl<boost::undirected_tag, unsigned
int>, EdgeProp, const double>’ to non-scalar type ‘searchThroughGraph(const
Graph&, VertexRef, VertexRef, std::vector<unsigned int,
std::allocator<unsigned int> >&)::EdgeWeightMap’ requested
-------------------------------------------------------------
Does anyone know what might be wrong?
More generally, I'm a bit mystefied by the "<Graph, double EdgeProp::*>::type"
syntax -- can anyone give me any pointers about what this syntax means, or
where I can look it up? (googling for colon-colon-star doesn't help much).
I also tried pattern-matching from the documentation page about bundled
properties (the weight_map(get(&Highway::miles, map)) example) but couldn't
get this to compile either. Is this example correct?
Thanks very much in advance,
Alex
_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users
typedef boost::property_map<Graph, double EdgeProp::*>::type EdgeWeightMap;
// The following line fails to compile
EdgeWeightMap edgeWeightMap = get(&EdgeProp::cost, graph);
Thanks again,
Does anyone know what might be wrong?
More generally, I'm a bit mystefied by the "<Graph, double EdgeProp::*>::type"
syntax -- can anyone give me any pointers about what this syntax means, or
where I can look it up? (googling for colon-colon-star doesn't help much).
I also tried pattern-matching from the documentation page about bundled
properties (the weight_map(get(&Highway::miles, map)) example) but couldn't
get this to compile either. Is this example correct?
Thanks very much for the help, I've got it working now. I had to use a
non-const reference though. Here are the options I tried:
// Option A:
Graph &nonConstGraph = const_cast<Graph&>(graph);
typedef boost::property_map<Graph, double EdgeProp::*>::type
EdgeWeightMap;
EdgeWeightMap edgeWeightMap = get(&EdgeProp::cost, nonConstGraph);
// Option B:
// typedef boost::property_map<Graph, double const EdgeProp::*>::type
EdgeWeightMap;
// EdgeWeightMap edgeWeightMap = get(&EdgeProp::cost, graph);
Option A works, but is a bit ugly.
Option B is what you suggested, but it gives the following error:
/home/a.brooks/shh/src/libs/prm/test/stupid.cpp:70: error: conversion
from 'boost::bundle_property_map<const boost::adjacency_list<boost::vecS,
boost::vecS, boost::undirectedS, Point*, EdgeProp, boost::no_property,
boost::listS>, boost::detail::edge_desc_impl<boost::undirected_tag, unsigned
int>, EdgeProp, const double>' to non-scalar type 'searchThroughGraph(const
Graph&, VertexRef, VertexRef, std::vector<unsigned int,
std::allocator<unsigned int> >&)::EdgeWeightMap' requested
Do I also need to modify the 'get()' line?
> It's pointer-to-member syntax. Read from right to left You're saying that
> the type is a "pointer to a member of EdgeProp that is of type double." Or
> in this case, a pointer to a const EdgeProp that's a double.
Awesome, thanks for the pointer.
Cheers,
// typedef boost::property_map<Graph, double const EdgeProp::*>::type
EdgeWeightMap;
// EdgeWeightMap edgeWeightMap = get(&EdgeProp::cost, graph);
Option A works, but is a bit ugly.
Option B is what you suggested, but it gives the following error:
This line compiles now, but I get a new compile error from the astar_search
line. The important bits are:
typedef boost::property_map<const Graph, double const EdgeProp::*>::type
EdgeWeightMap;
EdgeWeightMap edgeWeightMap = get(&EdgeProp::cost, graph);
std::vector<VertexRef> predecessors(num_vertices(graph));
astar_search( graph,
start,
aStarHeuristic,
boost::weight_map(edgeWeightMap).
predecessor_map(&predecessors[0]).
visitor(aStarVisitor) );
The error is:
/usr/include/c++/4.3/bits/allocator.h:84: instantiated
from 'std::allocator<const double>'
/usr/include/c++/4.3/bits/stl_vector.h:75: instantiated
from 'std::_Vector_base<const double, std::allocator<const double> >'
/usr/include/c++/4.3/bits/stl_vector.h:176: instantiated
from 'std::vector<const double, std::allocator<const double> >'
/usr/include/boost/graph/astar_search.hpp:360: instantiated from 'void
boost::detail::astar_dispatch1(VertexListGraph&, typename
boost::graph_traits<G>::vertex_descriptor, AStarHeuristic, CostMap,
DistanceMap, WeightMap, IndexMap, ColorMap, const Params&) [with
VertexListGraph = const boost::adjacency_list<boost::vecS, boost::vecS,
boost::undirectedS, Point*, EdgeProp, boost::no_property, boost::listS>,
AStarHeuristic = AStarHeuristic, CostMap =
boost::detail::error_property_not_found, DistanceMap =
boost::detail::error_property_not_found, WeightMap =
boost::bundle_property_map<const boost::adjacency_list<boost::vecS,
boost::vecS, boost::undirectedS, Point*, EdgeProp, boost::no_property,
boost::listS>, boost::detail::edge_desc_impl<boost::undirected_tag, unsigned
int>, EdgeProp, const double>, IndexMap =
boost::vec_adj_list_vertex_id_map<boost::property<boost::vertex_bundle_t,
Point*, boost::no_property>, unsigned int>, ColorMap =
boost::detail::error_property_not_found, Params =
boost::bgl_named_params<AStarVisitor, boost::graph_visitor_t,
boost::bgl_named_params<unsigned int*, boost::vertex_predecessor_t,
boost::bgl_named_params<boost::bundle_property_map<const
boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, Point*,
EdgeProp, boost::no_property, boost::listS>,
boost::detail::edge_desc_impl<boost::undirected_tag, unsigned int>, EdgeProp,
const double>, boost::edge_weight_t, boost::no_property> > >]'
/usr/include/boost/graph/astar_search.hpp:394: instantiated from 'void
boost::astar_search(VertexListGraph&, typename
boost::graph_traits<G>::vertex_descriptor, AStarHeuristic, const
boost::bgl_named_params<P, T, R>&) [with VertexListGraph = const
boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, Point*,
EdgeProp, boost::no_property, boost::listS>, AStarHeuristic = AStarHeuristic,
P = AStarVisitor, T = boost::graph_visitor_t, R =
boost::bgl_named_params<unsigned int*, boost::vertex_predecessor_t,
boost::bgl_named_params<boost::bundle_property_map<const
boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, Point*,
EdgeProp, boost::no_property, boost::listS>,
boost::detail::edge_desc_impl<boost::undirected_tag, unsigned int>, EdgeProp,
const double>, boost::edge_weight_t, boost::no_property> >]'
/home/a.brooks/shh/src/libs/prm/test/stupid.cpp:83: instantiated from here
/usr/include/c++/4.3/ext/new_allocator.h:82: error: 'const _Tp*
__gnu_cxx::new_allocator<_Tp>::address(const _Tp&) const [with _Tp = const
double]' cannot be overloaded
/usr/include/c++/4.3/ext/new_allocator.h:79: error: with '_Tp*
__gnu_cxx::new_allocator<_Tp>::address(_Tp&) const [with _Tp = const double]'
Any other ideas?
Thanks again,
I was able to compile your original code by changing the line
typedef boost::property_map<Graph, double EdgeProp::*>::type EdgeWeightMap;
to
typedef boost::property_map<Graph, double EdgeProp::*>::const_type
EdgeWeightMap;
hope this will help,
Dmitry
Alex Brooks escribió:
>> Gotta a const Graph also:
>>
>> property_map<const Graph, double const EdgeProp::*>
>
>
I was able to compile your original code by changing the line
typedef boost::property_map<Graph, double EdgeProp::*>::type EdgeWeightMap;
to
typedef boost::property_map<Graph, double EdgeProp::*>::const_type EdgeWeightMap;
/usr/include/c++/4.3/ext/new_allocator.h:82: error: 'const _Tp*
__gnu_cxx::new_allocator<_Tp>::address(const _Tp&) const [with _Tp = const
double]' cannot be overloaded
/usr/include/c++/4.3/ext/new_allocator.h:79: error: with '_Tp*
__gnu_cxx::new_allocator<_Tp>::address(_Tp&) const [with _Tp = const double]'
Thanks again for the help. I guess I'll stick with the const-cast.
Cheers,
I'm having the same problem though mine (with MSVC9) says:
error C2678: binary '=': no operator found which takes a left-hand
operand of type 'const Weight' (or there is no acceptable conversion)
c:\program files\boost\boost_1_37_0\boost\property_map.hpp 161
A follow-up would be greatly appreciated.
Thanks,
Geoff
You can try to use
boost::remove_const<Weight>::type
Regards,
Dmitry
I appreciate your suggestion, but the reason I'm getting the error is
because I'm trying to make the code const-correct, until yesterday code
that raised this issue would have the graph parameter be rendered
non-const as a temporary "fix", but that's not good style, I'm looking
to remedy this by making the code const-correct now. :)
If there's no other solution then I'll revert the const-correctedness
changes until there is one, but I have a hard time believing this to be
the case.
Thanks,
Geoff
Just a quick glance at your code would be greatly appreciated,
Regards,
Dmitry
To help things along, here's the code in question:
Note: graph variable is of type const Graph&.
const boost::property_map<Graph,
Weight EdgeProp::*>::const_type eprop =
boost::get(&EdgeProp::weight, graph);
const boost::property_map<Graph,
boost::vertex_index_t>::const_type vindex =
boost::get(boost::vertex_index, graph);
const vertex_descriptor firstVertex = *GetGraphBeginVertexIterator(graph);
PredecessorMap preds = PredecessorMap(numVertices);
DistanceMap dists = DistanceMap(numVertices);
boost::bellman_ford_shortest_paths(graph, numVertices,
weight_map(eprop)
.predecessor_map(boost::make_iterator_property_map(preds.begin(),
vindex))
.distance_map(boost::make_iterator_property_map(dists.begin(), vindex))
.root_vertex(firstVertex)
.distance_combine(Combiner())
.distance_compare(Comparer(currentOffset))
);
Also, my Weight type has an explicit constructor which takes a POD
convertible to 0, a requirement imposed it seems by line 155 of
bellman_ford_shortest_paths.hpp. Why doesn't the algorithm take a weight
of value zero as a parameter and use it instead?
Anyway, because of this explicit constructor I've added a (typical)
assignment operator (not sure if this is relevant, but I'm mentioning it
just in case).
I should also note that out of curiosity I commented out line 103 of
bellman_ford_shortest_paths.hpp which is:
function_requires<ReadablePropertyMapConcept<WeightMap, Edge> >();
Commenting out the above line allows my code as written above to
compile, otherwise it fails with the error written in my original
response (quoted above). Whether the compiled code (with line 103
commented out) functions as expected I don't know, I haven't tested it.
Thanks,
Geoff
It looks like the problem is with
template <class PMap, class Key> struct ReadablePropertyMapConcept;
The following code fails to compile:
#include <boost/graph/graph_concepts.hpp>
#include <boost/graph/adjacency_list.hpp>
using namespace boost;
struct EdgeProp
{
double weight;
};
typedef boost::adjacency_list<vecS, vecS, directedS, no_property,
EdgeProp > graph_t;
int main()
{
typedef boost::property_map<graph_t, double
EdgeProp::*>::const_type WeightMap;
typedef boost::graph_traits<graph_t>::edge_descriptor Edge;
function_requires<ReadablePropertyMapConcept<WeightMap, Edge> >();
}
You may try to change the boost/property_map.hpp as follows:
(in the version 1.37 the line number is 165)
typename typename property_traits<PMap>::value_type val;
to the
typename remove_const<typename property_traits<PMap>::value_type>::type val;
Does it work for you?
Regards,
Dmitry
Thanks Dmitry, it does work! I do wonder though, isn't there a better
fix? What about specializing ReadablePropertyMapConcept specifically for
const properties, or does that not make sense with concept classes? I'm
okay with modifying BGL code, but the remove_const makes me feel dirty.
This sounds like something that should be brought up with BGL maintainers...
Geoff
I believe that something is bad with the const version of
bundled_properties. Andrew, what do you think?
Dmitry
I believe that something is bad with the const version of bundled_properties. Andrew, what do you think?Thanks Dmitry, it does work! I do wonder though, isn't there a better fix? What about specializing ReadablePropertyMapConcept specifically for const properties, or does that not make sense with concept classes? I'm okay with modifying BGL code, but the remove_const makes me feel dirty.
This sounds like something that should be brought up with BGL maintainers...
Geoff
Merry Christmas, Happy New Year and all that!
Any progress?
Thanks,
Geoff
Hi Andrew, apologies for writing directly to you, I just thought I'd try to get your attention this way since you hadn't yet replied to my last post on the above topic in the mailing list.
Sorry about that, I've been swamped since new years. I'm going to bounce this back to the list
I would avoid declaring property maps as const. Somewhere in your posted code you have:
const property_map<...>::const_type map; // or something similar.
For all property maps, map = get(...) is a valid expression, regardless of whether your map is a ::type or ::const_type. By declaring it const, and then instantiating a template with the const pmap, you're going to run into problems - probably the problem you reported earlier.
Okay, so if I understand correctly I shouldn't use const prop maps with
const_type at all?
It seems to me like a line such as the above should still theoretically
compile. At least from the perspective of a concept check for
Readability; this is by definition what const is meant to restrict
objects to so in theory in should be allowable no? If I'm right it would
be a compilation error caused by the underlying implementation. Either
that or a debatable foible that should be documented? *shrug*.
const property_map<...>::const_type map; // or something similar.
For all property maps, map = get(...) is a valid expression,
regardless of whether your map is a ::type or ::const_type. By
declaring it const, and then instantiating a template with the const
pmap, you're going to run into problems - probably the problem you
reported earlier.
Okay, so if I understand correctly I shouldn't use const prop maps with const_type at all?
It seems to me like a line such as the above should still theoretically compile. At least from the perspective of a concept check for Readability; this is by definition what const is meant to restrict objects to so in theory in should be allowable no? If I'm right it would be a compilation error caused by the underlying implementation. Either that or a debatable foible that should be documented? *shrug*.
Okay.
>
> /* 1 */ property_map<...>::const_type p; // Good
> /* 2 */ const property_map<...>::const_type p; // Bad
>
> The const_type in 1 forces the p to operate on its underlying reference
> in a const way. Returing const references, no put() operation, etc. The
> leading const in 2 means that you can't write:
>
> p = q; // Assuming q is type property_map<...>::type
>
> It's a compiler error since p is not modifiable.
I agree, both situations are perfectly reasonable.
>
> If you look at the concept definition in boost/property_map.hpp for
> ReadablePropertyMapConcept, you'll find, in the constraints() member,
> this line:
>
> val = get(pmap, k)
>
> So apparently, the concept definition actually requires that property
> maps are never const - which is admittedly a little weird.
It sounds like we're now on the same page! The above essentially means
that it becomes literally impossible to write perfectly const-correct
code (from a user standpoint). While const-incorrect code is bad enough,
it also means that I may be missing out on potential compiler
optimizations, that bugs me quite a bit more.
What may be done to remedy this?
>
> Andrew Sutton
> andrew....@gmail.com
It sounds like we're now on the same page! The above essentially means that it becomes literally impossible to write perfectly const-correct code (from a user standpoint). While const-incorrect code is bad enough, it also means that I may be missing out on potential compiler optimizations, that bugs me quite a bit more.val = get(pmap, k)
So apparently, the concept definition actually requires that property maps are never const - which is admittedly a little weird.
What may be done to remedy this?
Can this be fixed for 1.38?
Can this be fixed for 1.38?
Darn.
> and I'm not entirely sure it should be fixed.
Really? It sounds like the fix is very reasonable.
>
> Andrew Sutton
> andrew....@gmail.com
Oh and about the compiler optimizations in your previous message; good. :)
Really? It sounds like the fix is very reasonable.
Good enough! I hope it does. :)
Thanks,