From 53a90f6346dca5e48bbb1900bff1da987ccba1b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me?= Date: Wed, 27 Mar 2019 21:27:39 +0100 Subject: [PATCH] Static derivative computation test added (boost::proto). --- examples/firstAndSecondDerivative.cpp | 6 +- tests/compile_time_derivative/Makefile | 33 ++++++ .../compile_time_derivative.hpp | 112 ++++++++++++++++++ tests/compile_time_derivative/main.cpp | 39 ++++++ 4 files changed, 187 insertions(+), 3 deletions(-) create mode 100755 tests/compile_time_derivative/Makefile create mode 100755 tests/compile_time_derivative/compile_time_derivative.hpp create mode 100755 tests/compile_time_derivative/main.cpp diff --git a/examples/firstAndSecondDerivative.cpp b/examples/firstAndSecondDerivative.cpp index 29aa8c8..72e27a9 100755 --- a/examples/firstAndSecondDerivative.cpp +++ b/examples/firstAndSecondDerivative.cpp @@ -29,14 +29,14 @@ T ddf(const T & x) int main() { double xdbl = 1.5; - + { cout << "Analytical\n"; cout << "f(x) = " << f(xdbl) << endl; cout << "df(x)/dt = " << df(xdbl) << endl; cout << "d²f(x)/dt = " << ddf(xdbl) << endl; } - + // 1st derivative forward { using Fd = Dual; @@ -47,7 +47,7 @@ int main() cout << "f(x) = " << y.a << endl; cout << "df(x)/dt = " << y.d(0) << endl; } - + // 2nd derivative forward /* { diff --git a/tests/compile_time_derivative/Makefile b/tests/compile_time_derivative/Makefile new file mode 100755 index 0000000..2690a6a --- /dev/null +++ b/tests/compile_time_derivative/Makefile @@ -0,0 +1,33 @@ +# Declaration of variables +C = clang +C_FLAGS = -Wall +CC = clang++ +CC_FLAGS = -Wall -std=c++17 -O0 +LD_FLAGS = +INCLUDES = + +# File names +EXEC = run +CSOURCES = $(wildcard *.c) +COBJECTS = $(CSOURCES:.c=.o) +SOURCES = $(wildcard *.cpp) +OBJECTS = $(SOURCES:.cpp=.o) + +# Main target +$(EXEC): $(COBJECTS) $(OBJECTS) + $(CC) $(LD_FLAGS) $(COBJECTS) $(OBJECTS) -o $(EXEC) + +# To obtain object files +%.o: %.cpp + $(CC) $(INCLUDES) $(CC_FLAGS) -o $@ -c $< + +# To obtain object files +%.o: %.c + $(C) $(INCLUDES) $(C_FLAGS) -o $@ -c $< + +# To remove generated files +clean: + rm -f $(COBJECTS) $(OBJECTS) + +cleaner: + rm -f $(EXEC) $(COBJECTS) $(OBJECTS) diff --git a/tests/compile_time_derivative/compile_time_derivative.hpp b/tests/compile_time_derivative/compile_time_derivative.hpp new file mode 100755 index 0000000..70e978d --- /dev/null +++ b/tests/compile_time_derivative/compile_time_derivative.hpp @@ -0,0 +1,112 @@ +#ifndef DEF_compile_time_derivative +#define DEF_compile_time_derivative + +#include + +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 +struct expression; + +// Boost.Proto calls this the domain +struct derived_domain +: domain> {}; + +// We will use a context to evaluate expression templates +struct evaluation_context: callable_context { + 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 +struct expression: extends, derived_domain> { + typedef extends, 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 + , boost::mpl::int_<1>() + > + , when< + terminal<_> + , boost::mpl::int_<0>() + > + , when< + plus + , _make_plus(Derivative(_left), Derivative(_right)) + > + , when< + minus + , _make_minus(Derivative(_left), Derivative(_right)) + > + , when< + multiplies + , _make_plus( + _make_multiplies(Derivative(_left), _right) + , _make_multiplies(_left, Derivative(_right)) + ) + > + //* + , when< + divides + , _make_divides + ( + _make_minus + ( + _make_multiplies + ( + _right, + Derivative(_left) + ), + _make_multiplies + ( + _left, + Derivative(_right) + ) + ), + _make_multiplies + ( + _right, + _right + ) + ) + > + , otherwise<_> +> {}; + +#endif diff --git a/tests/compile_time_derivative/main.cpp b/tests/compile_time_derivative/main.cpp new file mode 100755 index 0000000..daa535f --- /dev/null +++ b/tests/compile_time_derivative/main.cpp @@ -0,0 +1,39 @@ +#include + +#include "utils.hpp" +#include "compile_time_derivative.hpp" + +using std::cout; +using std::endl; + +// x is the unknown +expression::type> const x; + +// A transform works as a functor +Derivative const derivative; + +template +T fct(const T & x) { + return (3)*x*x + (2)*x - (3) + (1)/x; +} +template +T dfct(const T & x) { + return (6)*x + (2) - (1)/(x*x); +} + +// The file must be compiled with -O0 because with -O2 and up +int main() +{ + auto func = (3*x*x + 2*x - 3 + 1./x); + // auto func = fct(x); + auto dfunc = derivative(func); + + cout.precision(16); + for(double i = 0.1 ; i < 2. ; i+=.1) + std::cout << func(i) << "\t" << fct(i) << '\n'; + + for(double i = 0.1 ; i < 2. ; i+=.1) + std::cout << func(i) << "\t" << fct(i) << "\t" << dfunc(i) << "\t" << dfct(i) << '\n'; + + return 0; +}