Boost logo

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