Boost logo

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