|
Boost Users : |
Subject: Re: [Boost-users] [fusion] named parameter technique with fusion::map
From: Alfredo Correa (alfredo.correa_at_[hidden])
Date: 2010-11-09 06:02:41
On Sun, Nov 7, 2010 at 2:11 PM, Larry Evans <cppljevans_at_[hidden]>wrote:
> On 11/07/10 13:07, Alfredo Correa wrote:
> [snip]
> > template<double(f)(double)>
> > double derivative(double const& x){ ...already defined... }
> >
> > double f(double x){return x*x;}
> >
> > used as
> > derivative<f>(1.);
> >
> > the question is how to define a function "d" that takes a function like
> > H with fusion container arguments, bind it against all arguments except
> > one and calls derivative on that function. For example
> >
> > d<H, q>(1.,2.);
> >
> > internally, the code should bind all the parameters except q to its
> > corresponding values in the argument. in this case it is H binded with
> > p=1. and then *derivative* of H( __, 2.) is called with argument 1.
> >
> [snip]
> What about just creating a fusion::vector for tuple containing
> an initial value, then store that into a templated functor taking the
> free variable index as one of the template arguments, and then the
> operator()(double value) would use value to set the tuple at the
> template index and then call the function. For example:
>
>
Hi Larry,
I used your free_at.hpp to implement numerical derivative on named
parameters of a function object.
This post has the final solution that I was looking for:
1) First the "derivable" functor with named parameters, it has this general
shape:
struct p{};
struct q{};
struct H{
double operator()(double p, double q){
return p*p + q*q;
}
typedef result_of::make_map<
p , q ,
double, double
>::type mapped_arguments;
double operator()(mapped_arguments const& args){
return operator()(at_key<p>(args), at_key<q>(args));
}
};
The operator()( .. map ..) part is not very elegant. I don't know if it can
be improved (suggestions?).
2) Now, how to use the derivative with respect to ONE particular named
parameter, this is the notation I wanted to achieve. I think it is decent
but I accept suggestions. So, the usage:
H h;
double uno = 1., dos = 2.;
clog << h( uno, dos) << endl; // value at 1., 2., prints 5.
clog << d<q>(h)(uno, dos) << endl; // value of derivative at 1.,2. prints
4.
// more specific name should be
// partial<q>(h) where partial stands for partial derivative
Now the internal code that makes the magic in "d", that administers the
derivation parameter and ultimately takes the numerical derivative on that
function:
using namespace boost::fusion;
template<
class FusionMap, // e.g. fusion::map<T1,T2,...Tn>
class Functor, // double(FreeFunction)(FusionMap const&),
class FreeArgumentMapKey
>
struct bind_free_at : Functor, FusionMap{
bind_free_at(Functor const& f, FusionMap const& fm) : Functor(f),
FusionMap(fm){}
double operator()(typename result_of::value_at_key<FusionMap,
FreeArgumentMapKey>::type const& free_value){
at_key<FreeArgumentMapKey>(*this) = free_value;
return Functor::operator()(*this);
}
};
template<class ParameterKey, class Functor, class Args> //, class FusionMap>
struct d_ {
Functor f;
template <class Seq>
struct result{
typedef double type;
};
d_(Functor const& f) : f(f){}
typename result<Args>::type
operator()(Args const& args) const{
bind_free_at<Args, Functor, ParameterKey> bf(f, args);
double x = at_key<ParameterKey>(args);
return gsl::derivative::central(bf, x);
// this ithe magical function that calculates
// the numerical derivative of one-parameter (double->double)
function
}
};
template<class ParameterKey, class Functor, class Args=typename
Functor::mapped_arguments>
unfused<d_<ParameterKey, Functor, Args> > d(Functor const& f){
return unfused<d_<ParameterKey, Functor, Args> >(
d_<ParameterKey, Functor, Args>(f)
);
};
The final code is shorter than what I expected. I think there are some
internal redundancies and unnecessary copying but at least it works. Another
restriction inherited from fusion::fused is that the d<q>(h) object can only
take Lvalues.
I hope this helps somebody else, having named derivatives like in
mathematical notation is a blessing for my code.
Note that I gladly accept suggestions/improvements and that I didn't explore
the possibility of using Boost.Parameter because I don't understand that
library good enough. Another problem left is that in principle I could also
use integer index to define the partial derivative parameter.
clog << d<1>(h)( ... ) << endl; // derivative with respect to second (or
first??) argument, i.e. equal to d<q>(h)(...)
shouldn't be complicated since even if I used named parameters in a fusion
map they can bereferenced by integer indeces.
Cheers and thanks everyone for your help,
Alfredo
>
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net