$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [Boost-users] [fusion] named parameter technique with fusion::map
From: alfC (alfredo.correa_at_[hidden])
Date: 2010-11-13 18:41:26
On Nov 9, 12:53 pm, Alfredo Correa <alfredo.cor..._at_[hidden]> wrote:
> On Tue, Nov 9, 2010 at 5:45 AM, Larry Evans <cppljev..._at_[hidden]>wrote:
>
> > On 11/09/10 05:02, Alfredo Correa wrote:
> > [snip]
> > > I hope this helps somebody else, having named derivatives like in
> > > mathematical notation is a blessing for my code.
>
> > You might try repeating the process on a derivative. IOW,
> > take a derivative of a derivative.
>
> yes, yes. Even crossed derivatives,
> partial<q>(partial<p>(h))(make_set(1.,2.))
>
> Last night I tryed this and works with some limitations on the way passing
> parameters to the second derivative.
>
> for the monent I can't use it as partial<q>(partial<p>(h))(uno, dos)
>
> In fact the other threads in the Boost group I opened are to solve this.
> In a few words, for derivative to have the same interface as H (the model
> functor)
> (and automatically generated), I need it to be "fused" and "unfused" at the
> same time.
> Which is problematic.
I achieved concatenated (repeated) derivative notation by using
variadic templates:
given an original functor that can be called as
h(1.,2.);
//or h(make_map<p,q>(1.,2.));
you can define the second derivative by repeatedly calling
partial<p>(partial<q>(h))(1.,2.); //crossed derivative
// or partial<p>(partial<q>(h))(make_map<p,q>(1.,2.))
partial<p>(partial<p>(h))(1.,2.); //second derivative
partial<q>(partial<q>(h))(1.,2.); //another second derivative
Note 1: calculating second derivatives in this way is not efficient or
numerically stable,
there are more efficient ways to calculate second derivatives than.
Note 2: fortunatelly partial<...> can be specialized for certain
function objects, therefore can contain the *explicit* first
derivative of the functor)
below is the implementation, the addition with respect to the old is
using a variadic operator():
---
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{
mutable FusionMap m;
Functor f;
bind_free_at(Functor const& f, FusionMap const& fm) : m(fm), f(f){}
//bind_free_at(bind_free_at const& other) : FusionMap((FusionMap
const&)other), f(other.f){}
double operator()(typename result_of::value_at_key<FusionMap,
FreeArgumentMapKey>::type const& free_value) const{
at_key<FreeArgumentMapKey>(m) = free_value;
return f(m);
}
};
template<class ParameterKey, class Functor, class Args=typename
Functor::mapped_arguments> //, class FusionMap>
struct d_{
Functor f;
d_(Functor const& f) : f(f){}
template <class Seq>
struct result{typedef double type;};
typedef typename Functor::mapped_arguments mapped_arguments;
double operator()(mapped_arguments args) const{
bind_free_at<Args, Functor, ParameterKey> bf(f, args);
double x = at_key<ParameterKey>(args);
return gsl::derivative::central(bf, x);
}
template<class... DomainTypeS>
double operator()(DomainTypeS ... domainS) const{
//BOOST_STATIC_ASSERT((sizeof...(DomainTypeS))>1);
return (*this)(mapped_arguments(domainS ... ));
}
};
template<class ParameterKey, class Functor, class Args=typename
Functor::mapped_arguments>
d_<ParameterKey, Functor, Args> partial(Functor const& f){
return d_<ParameterKey, Functor, Args>(f);
};
still TODO:
improve notation for second derivatives:
partial<p, 2>(h)(1.,2.); //second derivative with respect to p