113 lines
2.6 KiB
C++
113 lines
2.6 KiB
C++
|
|
#ifndef DEF_compile_time_derivative
|
||
|
|
#define DEF_compile_time_derivative
|
||
|
|
|
||
|
|
#include <boost/proto/proto.hpp>
|
||
|
|
|
||
|
|
using namespace boost::proto;
|
||
|
|
|
||
|
|
// Assuming derivative of one variable, the 'unknown'
|
||
|
|
struct unknown {};
|
||
|
|
|
||
|
|
// Boost.Proto calls this the expression wrapper
|
||
|
|
// elements of the EDSL will have this type
|
||
|
|
template<typename Expr>
|
||
|
|
struct expression;
|
||
|
|
|
||
|
|
// Boost.Proto calls this the domain
|
||
|
|
struct derived_domain
|
||
|
|
: domain<generator<expression>> {};
|
||
|
|
|
||
|
|
// We will use a context to evaluate expression templates
|
||
|
|
struct evaluation_context: callable_context<evaluation_context const> {
|
||
|
|
double value;
|
||
|
|
|
||
|
|
explicit evaluation_context(double value)
|
||
|
|
: value(value)
|
||
|
|
{}
|
||
|
|
|
||
|
|
typedef double result_type;
|
||
|
|
|
||
|
|
double operator()(tag::terminal, unknown) const
|
||
|
|
{ return value; }
|
||
|
|
};
|
||
|
|
// And now we can do:
|
||
|
|
// evaluation_context context(42);
|
||
|
|
// eval(expr, context);
|
||
|
|
// to evaluate an expression as though the unknown had value 42
|
||
|
|
|
||
|
|
template<typename Expr>
|
||
|
|
struct expression: extends<Expr, expression<Expr>, derived_domain> {
|
||
|
|
typedef extends<Expr, expression<Expr>, derived_domain> base_type;
|
||
|
|
|
||
|
|
expression(Expr const& expr = Expr())
|
||
|
|
: base_type(expr)
|
||
|
|
{}
|
||
|
|
|
||
|
|
typedef double result_type;
|
||
|
|
|
||
|
|
// We spare ourselves the need to write eval(expr, context)
|
||
|
|
// Instead, expr(42) is available
|
||
|
|
double operator()(double d) const
|
||
|
|
{
|
||
|
|
evaluation_context context(d);
|
||
|
|
return eval(*this, context);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// Boost.Proto calls this a transform -- we use this to operate
|
||
|
|
// on the expression templates
|
||
|
|
struct Derivative
|
||
|
|
: or_<
|
||
|
|
when<
|
||
|
|
terminal<unknown>
|
||
|
|
, boost::mpl::int_<1>()
|
||
|
|
>
|
||
|
|
, when<
|
||
|
|
terminal<_>
|
||
|
|
, boost::mpl::int_<0>()
|
||
|
|
>
|
||
|
|
, when<
|
||
|
|
plus<Derivative, Derivative>
|
||
|
|
, _make_plus(Derivative(_left), Derivative(_right))
|
||
|
|
>
|
||
|
|
, when<
|
||
|
|
minus<Derivative, Derivative>
|
||
|
|
, _make_minus(Derivative(_left), Derivative(_right))
|
||
|
|
>
|
||
|
|
, when<
|
||
|
|
multiplies<Derivative, Derivative>
|
||
|
|
, _make_plus(
|
||
|
|
_make_multiplies(Derivative(_left), _right)
|
||
|
|
, _make_multiplies(_left, Derivative(_right))
|
||
|
|
)
|
||
|
|
>
|
||
|
|
//*
|
||
|
|
, when<
|
||
|
|
divides<Derivative, Derivative>
|
||
|
|
, _make_divides
|
||
|
|
(
|
||
|
|
_make_minus
|
||
|
|
(
|
||
|
|
_make_multiplies
|
||
|
|
(
|
||
|
|
_right,
|
||
|
|
Derivative(_left)
|
||
|
|
),
|
||
|
|
_make_multiplies
|
||
|
|
(
|
||
|
|
_left,
|
||
|
|
Derivative(_right)
|
||
|
|
)
|
||
|
|
),
|
||
|
|
_make_multiplies
|
||
|
|
(
|
||
|
|
_right,
|
||
|
|
_right
|
||
|
|
)
|
||
|
|
)
|
||
|
|
>
|
||
|
|
, otherwise<_>
|
||
|
|
> {};
|
||
|
|
|
||
|
|
#endif
|