Added Function object for computing the grad and macros to create them.
This commit is contained in:
parent
592f6976ad
commit
5c57aa0afd
6 changed files with 2787 additions and 60 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,6 +1,9 @@
|
|||
# executables
|
||||
run
|
||||
|
||||
# documentation
|
||||
html/
|
||||
|
||||
# catch2 generated files
|
||||
*.gcda
|
||||
*.gcno
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class Dual
|
|||
{
|
||||
public:
|
||||
using VectorT = std::valarray<Scalar>;
|
||||
|
||||
|
||||
static VectorT __create_VectorT_zeros(int N = 1)
|
||||
{
|
||||
assert(N >= 0);
|
||||
|
|
@ -38,7 +38,7 @@ class Dual
|
|||
: a(_a),
|
||||
b(_b)
|
||||
{}
|
||||
|
||||
|
||||
Dual const& operator=(Scalar const& _a)
|
||||
{
|
||||
*this = Dual(_a);
|
||||
|
|
@ -70,7 +70,7 @@ class Dual
|
|||
b[i] = Scalar(1.);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/// Returns the value
|
||||
Scalar const& x() const
|
||||
{
|
||||
|
|
@ -105,124 +105,125 @@ class Dual
|
|||
b += x.b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Dual & operator-=(const Dual & x)
|
||||
{
|
||||
a -= x.a;
|
||||
b -= x.b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Dual & operator*=(const Dual & x)
|
||||
{
|
||||
b = a*x.b + b*x.a;
|
||||
a *= x.a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Dual & operator/=(const Dual & x)
|
||||
{
|
||||
b = (x.a*b - a*x.b)/(x.a*x.a);
|
||||
a /= x.a;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Dual & operator++() { // ++x
|
||||
return ((*this) += Scalar(1.));
|
||||
}
|
||||
|
||||
|
||||
Dual & operator--() { // --x
|
||||
return ((*this) -= Scalar(1.));
|
||||
}
|
||||
|
||||
|
||||
Dual operator++(int) { // x++
|
||||
Dual copy = *this;
|
||||
(*this) += Scalar(1.);
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
Dual operator--(int) { // x--
|
||||
Dual copy = *this;
|
||||
(*this) -= Scalar(1.);
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
Dual operator+(const Dual & x) const {
|
||||
Dual res(*this);
|
||||
return (res += x);
|
||||
}
|
||||
|
||||
|
||||
Dual operator+(void) const // +x
|
||||
{
|
||||
return (*this);
|
||||
}
|
||||
|
||||
|
||||
Dual operator-(const Dual & x) const {
|
||||
Dual res(*this);
|
||||
return (res -= x);
|
||||
}
|
||||
|
||||
|
||||
Dual operator-(void) const // -x
|
||||
{
|
||||
return Dual(-a, -b);
|
||||
}
|
||||
|
||||
|
||||
Dual operator*(const Dual & x) const
|
||||
{
|
||||
Dual res(*this);
|
||||
return (res *= x);
|
||||
}
|
||||
|
||||
|
||||
Dual operator/(const Dual & x) const
|
||||
{
|
||||
Dual res(*this);
|
||||
return (res /= x);
|
||||
}
|
||||
|
||||
|
||||
bool operator==(const Dual & x) const {
|
||||
return (a == x.a);
|
||||
}
|
||||
|
||||
|
||||
bool operator!=(const Dual & x) const {
|
||||
return (a != x.a);
|
||||
}
|
||||
|
||||
|
||||
bool operator<(const Dual & x) const {
|
||||
return (a < x.a);
|
||||
}
|
||||
|
||||
|
||||
bool operator<=(const Dual & x) const {
|
||||
return (a <= x.a);
|
||||
}
|
||||
|
||||
|
||||
bool operator>(const Dual & x) const {
|
||||
return (a > x.a);
|
||||
}
|
||||
|
||||
|
||||
bool operator>=(const Dual & x) const {
|
||||
return (a >= x.a);
|
||||
}
|
||||
|
||||
|
||||
Scalar a; /// Real part
|
||||
VectorT b; /// Infinitesimal parts
|
||||
};
|
||||
|
||||
//*
|
||||
template<typename A, typename B>
|
||||
Dual<B> operator+(A const& v, Dual<B> const& x) {
|
||||
return (Dual<B>(v) + x);
|
||||
return (Dual<B>(static_cast<B>(v)) + x);
|
||||
}
|
||||
template<typename A, typename B>
|
||||
Dual<B> operator-(A const& v, Dual<B> const& x) {
|
||||
return (Dual<B>(v) - x);
|
||||
return (Dual<B>(static_cast<B>(v)) - x);
|
||||
}
|
||||
template<typename A, typename B>
|
||||
Dual<B> operator*(A const& v, Dual<B> const& x) {
|
||||
return (Dual<B>(v) * x);
|
||||
return (Dual<B>(static_cast<B>(v)) * x);
|
||||
}
|
||||
template<typename A, typename B>
|
||||
Dual<B> operator/(A const& v, Dual<B> const& x) {
|
||||
return (Dual<B>(v) / x);
|
||||
}
|
||||
return (Dual<B>(static_cast<B>(v)) / x);
|
||||
}//*/
|
||||
|
||||
// Basic mathematical functions for Scalar numbers
|
||||
|
||||
|
|
@ -464,35 +465,82 @@ template<typename Scalar> std::ostream & operator<<(std::ostream & s, const Dual
|
|||
return (s << x.a);
|
||||
}
|
||||
|
||||
/// Function object to evaluate the derivative of a function anywhere without explicitely using the Dual numbers.
|
||||
//*
|
||||
template<typename Func, typename Scalar>
|
||||
struct GradFunc
|
||||
{
|
||||
Func f;
|
||||
|
||||
GradFunc(Func f_, Scalar) : f(f_) {}
|
||||
|
||||
// Function that returns the 1st derivative of the function f at x.
|
||||
Scalar operator()(Scalar const& x)
|
||||
{
|
||||
// differentiate using the Dual number and return the .b component.
|
||||
Dual<Scalar> X(x);
|
||||
X.diff(0,1);
|
||||
Dual<Scalar> Y = f(X);
|
||||
return Y.d(0);
|
||||
}
|
||||
|
||||
/// Function that returns both the function value and the gradient of f at x. Use this preferably over separate calls to f and to gradf.
|
||||
void get_f_grad(Scalar const& x, Scalar & fx, Scalar & gradfx)
|
||||
{
|
||||
// differentiate using the Dual number and return the .b component.
|
||||
Dual<Scalar> X(x);
|
||||
X.diff(0,1);
|
||||
Dual<Scalar> Y = f(X);
|
||||
fx = Y.x();
|
||||
gradfx = Y.d(0);
|
||||
}
|
||||
};//*/
|
||||
|
||||
//*
|
||||
/// Macro to create a function object that returns the gradient of the function at X.
|
||||
/// Designed to work with functions, lambdas, etc.
|
||||
#define CREATE_GRAD_FUNCTION_OBJECT(Func, GradFuncName) \
|
||||
struct GradFuncName { \
|
||||
template<typename Scalar> \
|
||||
Scalar operator()(Scalar const& x) { \
|
||||
Dual<Scalar> X(x); \
|
||||
X.diff(0,1); \
|
||||
Dual<Scalar> Y = Func<Dual<Scalar>>(X); \
|
||||
return Y.d(0); \
|
||||
} \
|
||||
template<typename Scalar> \
|
||||
void get_f_grad(Scalar const& x, Scalar & fx, Scalar & gradfx) { \
|
||||
Dual<Scalar> X(x); \
|
||||
X.diff(0,1); \
|
||||
Dual<Scalar> Y = Func<Dual<Scalar>>(X); \
|
||||
fx = Y.x(); \
|
||||
gradfx = Y.d(0); \
|
||||
} \
|
||||
}
|
||||
//*/
|
||||
//*
|
||||
/// Macro to create a function object that returns the gradient of the function at X.
|
||||
/// Designed to work with function objects.
|
||||
#define CREATE_GRAD_FUNCTION_OBJECT_FUNCTOR(Func, GradFuncName) \
|
||||
struct GradFuncName { \
|
||||
template<typename Scalar> \
|
||||
Scalar operator()(Scalar const& x) { \
|
||||
Dual<Scalar> X(x); \
|
||||
X.diff(0,1); \
|
||||
Func f; \
|
||||
Dual<Scalar> Y = f(X); \
|
||||
return Y.d(0); \
|
||||
} \
|
||||
template<typename Scalar> \
|
||||
void get_f_grad(Scalar const& x, Scalar & fx, Scalar & gradfx) { \
|
||||
Dual<Scalar> X(x); \
|
||||
X.diff(0,1); \
|
||||
Func f; \
|
||||
Dual<Scalar> Y = f(X); \
|
||||
fx = Y.x(); \
|
||||
gradfx = Y.d(0); \
|
||||
} \
|
||||
}
|
||||
//*/
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -1,6 +1,6 @@
|
|||
CXX = clang++
|
||||
INCLUDE = -I../Catch2-master/single_include
|
||||
CFLAGS = -Wall -std=c++11 -O0 -fprofile-arcs -ftest-coverage $(INCLUDE)
|
||||
CFLAGS = -Wall -std=c++17 -O0 -fprofile-arcs -ftest-coverage $(INCLUDE)
|
||||
LDFLAGS = -lgcov
|
||||
LDFLAGS_ALL = $(LDFLAGS)
|
||||
OUTPUT_NAME = test_AutomaticDifferentiation
|
||||
|
|
|
|||
102
examples/grad_functor.cpp
Executable file
102
examples/grad_functor.cpp
Executable file
|
|
@ -0,0 +1,102 @@
|
|||
#include "../AutomaticDifferentiation.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::setw;
|
||||
#define PRINT_VAR(x) std::cout << #x << "\t= " << std::setprecision(16) << (x) << std::endl
|
||||
#define PRINT_DUAL(x) std::cout << #x << "\t= " << std::fixed << std::setprecision(4) << std::setw(10) << (x).a << ", " << std::setw(10) << (x).b << std::endl
|
||||
|
||||
template<typename T>
|
||||
T f(const T & x)
|
||||
{
|
||||
// return T(1.) + x + x*x + T(1.)/x + log(x);
|
||||
return 1 + x + x*x + 1/x + log(x);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T df(const T & x)
|
||||
{
|
||||
return 2*x + 1 + 1.0/x - 1/pow(x, 2);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ddf(const T & x)
|
||||
{
|
||||
return 2 - 1/pow(x, 2) + 2/pow(x, 3);
|
||||
}
|
||||
|
||||
struct fFunctor
|
||||
{
|
||||
template<typename Scalar>
|
||||
Scalar operator()(Scalar const& x) {return f(x);}
|
||||
};
|
||||
|
||||
CREATE_GRAD_FUNCTION_OBJECT(f, GradF);
|
||||
|
||||
CREATE_GRAD_FUNCTION_OBJECT_FUNCTOR(fFunctor, GradF_funct);
|
||||
CREATE_GRAD_FUNCTION_OBJECT_FUNCTOR(GradF_funct, Grad2F_funct);
|
||||
|
||||
int main()
|
||||
{
|
||||
cout.precision(16);
|
||||
double xdbl = 1.5;
|
||||
|
||||
{
|
||||
cout << "Analytical\n";
|
||||
cout << "f(x) = " << f(xdbl) << endl;
|
||||
cout << "df(x)/dx = " << df(xdbl) << endl;
|
||||
cout << "d²f(x)/dx² = " << ddf(xdbl) << endl;
|
||||
}
|
||||
|
||||
// 1st derivative forward
|
||||
{
|
||||
using Fd = Dual<double>;
|
||||
Fd x = xdbl;
|
||||
x.diff(0);
|
||||
Fd y = f(x);
|
||||
cout << "\nForward\n";
|
||||
cout << "f(x) = " << y.a << endl;
|
||||
cout << "df(x)/dx = " << y.d(0) << endl;
|
||||
}
|
||||
|
||||
// first derivative using the gradient functor
|
||||
{
|
||||
GradFunc gradf(f<Dual<double>>, xdbl);
|
||||
|
||||
double fx, dfdx;
|
||||
gradf.get_f_grad(xdbl, fx, dfdx);
|
||||
|
||||
cout << "\nForward using gradient function object\n";
|
||||
cout << "f(x) = " << fx << endl;
|
||||
cout << "df(x)/dx = " << dfdx << endl;
|
||||
cout << "df(x)/dx = " << gradf(xdbl) << endl;
|
||||
}
|
||||
|
||||
// first derivative using the gradient functor created through the macro
|
||||
{
|
||||
// GradF<double> gradf;
|
||||
GradF gradf;
|
||||
// GradFunc gradf(f<Dual<double>>, xdbl);
|
||||
|
||||
double fx, dfdx;
|
||||
gradf.get_f_grad(xdbl, fx, dfdx);
|
||||
|
||||
cout << "\nForward using gradient function object created using the macro\n";
|
||||
cout << "f(x) = " << fx << endl;
|
||||
cout << "df(x)/dx = " << dfdx << endl;
|
||||
cout << "df(x)/dx = " << gradf(xdbl) << endl;
|
||||
|
||||
{
|
||||
GradF_funct gradf_funct;
|
||||
Grad2F_funct grad2f_funct;
|
||||
PRINT_VAR(gradf(1.5f));
|
||||
PRINT_VAR(gradf_funct(1.5));
|
||||
// PRINT_VAR(grad2f_funct(1.5));// for this to work, the operator+-*/(A, Dual<B>) must not be defined (conflict with operator from valarray)
|
||||
// third order does not work anyway (can't convert a double to Dual<Dual<Dual<double>>>...)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
92
examples/gradient_vector_var.cpp
Executable file
92
examples/gradient_vector_var.cpp
Executable file
|
|
@ -0,0 +1,92 @@
|
|||
#include "../AutomaticDifferentiation.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <Eigen/Dense>
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::setw;
|
||||
#define PRINT_VAR(x) std::cout << #x << "\t= " << std::setprecision(16) << (x) << std::endl
|
||||
#define PRINT_DUAL(x) std::cout << #x << "\t= " << std::fixed << std::setprecision(4) << std::setw(10) << (x).a << ", " << std::setw(10) << (x).b << std::endl
|
||||
|
||||
template<typename T>
|
||||
T f(const T & x)
|
||||
{
|
||||
return 1 + x + x*x + 1/x + log(x);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T df(const T & x)
|
||||
{
|
||||
return 2*x + 1 + 1.0/x - 1/pow(x, 2);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T ddf(const T & x)
|
||||
{
|
||||
return 2 - 1/pow(x, 2) + 2/pow(x, 3);
|
||||
}
|
||||
|
||||
CREATE_GRAD_FUNCTION_OBJECT(f, GradF);
|
||||
|
||||
int main()
|
||||
{
|
||||
cout.precision(16);
|
||||
double xdbl = 1.5;
|
||||
|
||||
{
|
||||
cout << "Analytical\n";
|
||||
cout << "f(x) = " << f(xdbl) << endl;
|
||||
cout << "df(x)/dx = " << df(xdbl) << endl;
|
||||
cout << "d²f(x)/dx² = " << ddf(xdbl) << endl;
|
||||
}
|
||||
|
||||
// 1st derivative forward
|
||||
{
|
||||
using Fd = Dual<double>;
|
||||
Fd x = xdbl;
|
||||
x.diff(0);
|
||||
Fd y = f(x);
|
||||
cout << "\nForward\n";
|
||||
cout << "f(x) = " << y.a << endl;
|
||||
cout << "df(x)/dx = " << y.d(0) << endl;
|
||||
}
|
||||
|
||||
// first derivative using the gradient functor
|
||||
{
|
||||
GradFunc gradf(f<Dual<double>>, xdbl);
|
||||
|
||||
double fx, dfdx;
|
||||
gradf.get_f_grad(xdbl, fx, dfdx);
|
||||
|
||||
cout << "\nForward using gradient function object\n";
|
||||
cout << "f(x) = " << fx << endl;
|
||||
cout << "df(x)/dx = " << dfdx << endl;
|
||||
cout << "df(x)/dx = " << gradf(xdbl) << endl;
|
||||
}
|
||||
|
||||
// using a vector type
|
||||
{
|
||||
// using vtype = std::valarray<double>;
|
||||
using vtype = Eigen::Array3d;
|
||||
GradF gradf;
|
||||
// vtype x(3, xdbl);
|
||||
vtype x(xdbl/2, xdbl, xdbl*2);
|
||||
vtype fx, dfx;
|
||||
gradf.get_f_grad(x, fx, dfx);
|
||||
|
||||
// Dual<vtype> X(x);
|
||||
// X.diff(0,1);
|
||||
// Dual<vtype> Fx = f(X);
|
||||
// fx = Fx.x();
|
||||
// dfx = Fx.d(0);
|
||||
|
||||
PRINT_VAR(x);
|
||||
PRINT_VAR(fx);
|
||||
PRINT_VAR(dfx);
|
||||
|
||||
// also, using a single dual<vector_type> in a R^n -> R function to get the full gradient does not work : no operator[] in Dual, and adding it does not seem to work either...
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue