|
Boost Users : |
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
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