I have a bunch of boost::property_map
s defining costs of edge traversal in a graph. I'm executing an algorithm with differently weighted combinations of these maps, currently by manually doing totalcost = weight1*weight1_factor + weight2*weight2_factor + ...
. The number of property maps is rising though, and it's becoming a hassle to sum them up like this.
So, I envisioned creating an aggregation class, which contains a collection of some sort of all the maps. However, they are templated differently, as boost::property_map<Graph, PropertyTag>
, where the PropertyTag
differs among the maps. Since they all support operator[](edge_escriptor)
, is there 开发者_C百科some trick I can use, or am I doomed to use boost::any
?
I would advise you to create a boost::tuple with property maps and factors.
Given that in your context, you have (propertymap_i, weight_i) for each i, create an aggregation class which uses this tuple (as a template parameter for the aggregation class) to compute the needed value, when asked.
You may either use operator[] or the get() function provided by property maps.
I probably can be clearer if needed, but it'll have to wait a bit.
EDIT : Is this close to what you need ?
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
#include <boost/shared_ptr.hpp>
namespace property_aggregator
{
template<typename Tuple, typename T>
struct helper
{
double operator()(Tuple const& tuple, T t)
{
return boost::get<0>(tuple)*get(boost::get<1>(tuple), t) +
helper<typename Tuple::tail_type::tail_type, T>()(tuple.get_tail().get_tail(), t);
}
};
template<typename T>
struct helper<boost::tuples::null_type, T>
{
double operator()(boost::tuples::null_type const& tuple, T t)
{
return 0.;
}
};
template<typename T>
class BasePropertyAggregator
{
public:
virtual double compute( T t ) = 0;
};
template <typename PropertyTuple, typename T>
class PropertyAggregator : public BasePropertyAggregator<T>
{
public:
PropertyAggregator(PropertyTuple const& tuple) : m_tuple(tuple){}
virtual ~PropertyAggregator(){}
double compute( T t )
{
return property_aggregator::helper<PropertyTuple, T>()(m_tuple, t);
}
private:
PropertyTuple m_tuple;
};
}
template<typename T>
class PropertyAggregator
{
public:
template<typename Tuple>
PropertyAggregator(Tuple const& tuple) : m_computer(new property_aggregator::PropertyAggregator<Tuple, T>(tuple))
{}
double operator()(T t)
{
return m_computer->compute(t);
}
private:
boost::shared_ptr<property_aggregator::BasePropertyAggregator<T> > m_computer;
};
// Defaut type of a graph
typedef boost::adjacency_list<boost::listS, boost::vecS, boost::directedS,
boost::property<boost::vertex_index_t, unsigned int>,
boost::property<boost::edge_weight_t, double,
boost::property<boost::edge_color_t, double> > > Graph;
int main()
{
typedef boost::property_map<Graph, boost::edge_weight_t>::type PM1;
typedef boost::property_map<Graph, boost::edge_color_t>::type PM2;
typedef boost::graph_traits<Graph>::edge_descriptor EdgeType;
Graph g;
PM1 pm1 = get(boost::edge_weight, g);
PM2 pm2 = get(boost::edge_color, g);
add_vertex(g);
add_vertex(g);
EdgeType edge1 = boost::add_edge(0, 1, g).first;
put(pm1, edge1, 1.);
put(pm2, edge1, 2.);
typedef PropertyAggregator<EdgeType> ComboType;
ComboType combo1(boost::make_tuple(1., pm1));
ComboType combo2(boost::make_tuple(1., pm2));
ComboType combo3(boost::make_tuple(1., pm1, 2., pm2));
std::cout << "-- " << combo1(edge1) << std::endl;
std::cout << "-- " << combo2(edge1) << std::endl;
std::cout << "-- " << combo3(edge1) << std::endl;
return 0;
}
Create an abstract BasePropertyMap class with pure virtual methods for common functionality. Create template class that derives from this base and is templated on your boost_property_map specialization. In your derived template type, hold a property_map by pointer or value, and override base class virtuals with code for your templated property map. Specialize as needed.
Then you may dynamically create derived type objects and hold them in your collection through the base class pointer.
Assuming you e.g. want to sum up weights of all your property maps, and you can write a template function to calculate the weight of a single property map, it would go something like this:
template<typename Graph, typename PropertyTag>
double calc_weight(const boost::property_map<Graph, PropertyTag>& propMap) {
// your body here
}
class BasePropertyMap {
virtual double weight() = 0;
}
template<typename Graph, typename PropertyTag>
class DerivedPropertyMap: public BasePropertyMap {
boost::property_map<Graph, PropertyTag> my_map;
double weight() {
return calc_weight(my_map);
}
}
std::vector<BasePropertyMap*> collection;
[...]
// iterate over collection
totalcost=0;
for(auto it=collection.begin(), endit = collection.end(); it!=endit; ++it) {
totalcost += (*it)->weight();
}
精彩评论