Changed vector type from eigen to valarray. added function diff(int i) to set the derivatives more easily. Created a small test file to check the changes. automated vector tests are not updated yet

This commit is contained in:
Jérôme 2019-03-25 19:47:41 +01:00
parent d59c41c874
commit a60cac7f56
3 changed files with 165 additions and 9 deletions

View file

@ -1,10 +1,19 @@
#ifndef DEF_AUTOMATIC_DIFFERENTIATION #ifndef DEF_AUTOMATIC_DIFFERENTIATION
#define DEF_AUTOMATIC_DIFFERENTIATION #define DEF_AUTOMATIC_DIFFERENTIATION
#include <assert.h>
#include <cmath> #include <cmath>
#include <ostream> #include <ostream>
#include <Eigen/Dense> #include <valarray>
template<typename T>
std::ostream & operator<<(std::ostream & out, std::valarray<T> const& v)
{
for(size_t i = 0 ; i < v.size() ; i++)
out << v[i] << " ";
return out;
}
/// Implementation of dual numbers for automatic differentiation. /// Implementation of dual numbers for automatic differentiation.
/// This implementation uses vectors for b so that function gradients can be computed in one function call. /// This implementation uses vectors for b so that function gradients can be computed in one function call.
@ -14,9 +23,15 @@ template<typename Scalar, int N>
class DualVector class DualVector
{ {
public: public:
using VectorT = Eigen::Matrix<Scalar, N, 1>; using VectorT = std::valarray<Scalar>;
DualVector(const Scalar & _a, const VectorT & _b = VectorT::Zero()) static VectorT __create_VectorT_zeros()
{
VectorT res(Scalar(0.), N);
return res;
}
DualVector(const Scalar & _a, const VectorT & _b = DualVector::__create_VectorT_zeros())
: a(_a), : a(_a),
b(_b) b(_b)
{} {}
@ -27,14 +42,25 @@ class DualVector
b.fill(_b); b.fill(_b);
} }
/// Use this function to set what variable is to be derived : x + DualVector::d(i)
static DualVector d(int i = 0) static DualVector d(int i = 0)
{ {
assert(i >= 0); assert(i >= 0);
assert(i < N); assert(i < N);
VectorT _d = VectorT::Zero(); VectorT _d = DualVector::__create_VectorT_zeros();
_d[i] = Scalar(1.); _d[i] = Scalar(1.);
return DualVector(Scalar(0.), _d); return DualVector(Scalar(0.), _d);
} }
/// Use this function to set what variable is to be derived.
DualVector const& diff(int i = 0)
{
assert(i >= 0);
assert(i < N);
b = DualVector::__create_VectorT_zeros();
b[i] = Scalar(1.);
return *this;
}
DualVector & operator+=(const DualVector & x) DualVector & operator+=(const DualVector & x)
{ {
@ -305,7 +331,7 @@ template<typename Scalar, int N> DualVector<Scalar, N> sqrt(const DualVector<Sca
} }
template<typename Scalar, int N> DualVector<Scalar, N> sign(const DualVector<Scalar, N> & x) { template<typename Scalar, int N> DualVector<Scalar, N> sign(const DualVector<Scalar, N> & x) {
return DualVector<Scalar, N>(sign(x.a), DualVector<Scalar, N>::VectorT::Zero()); return DualVector<Scalar, N>(sign(x.a), DualVector<Scalar, N>::DualVector::__create_VectorT_zeros());
} }
template<typename Scalar, int N> DualVector<Scalar, N> abs(const DualVector<Scalar, N> & x) { template<typename Scalar, int N> DualVector<Scalar, N> abs(const DualVector<Scalar, N> & x) {
@ -313,19 +339,19 @@ template<typename Scalar, int N> DualVector<Scalar, N> abs(const DualVector<Scal
} }
template<typename Scalar, int N> DualVector<Scalar, N> heaviside(const DualVector<Scalar, N> & x) { template<typename Scalar, int N> DualVector<Scalar, N> heaviside(const DualVector<Scalar, N> & x) {
return DualVector<Scalar, N>(heaviside(x.a), DualVector<Scalar, N>::VectorT::Zero()); return DualVector<Scalar, N>(heaviside(x.a), DualVector<Scalar, N>::DualVector::__create_VectorT_zeros());
} }
template<typename Scalar, int N> DualVector<Scalar, N> floor(const DualVector<Scalar, N> & x) { template<typename Scalar, int N> DualVector<Scalar, N> floor(const DualVector<Scalar, N> & x) {
return DualVector<Scalar, N>(floor(x.a), DualVector<Scalar, N>::VectorT::Zero()); return DualVector<Scalar, N>(floor(x.a), DualVector<Scalar, N>::DualVector::__create_VectorT_zeros());
} }
template<typename Scalar, int N> DualVector<Scalar, N> ceil(const DualVector<Scalar, N> & x) { template<typename Scalar, int N> DualVector<Scalar, N> ceil(const DualVector<Scalar, N> & x) {
return DualVector<Scalar, N>(ceil(x.a), DualVector<Scalar, N>::VectorT::Zero()); return DualVector<Scalar, N>(ceil(x.a), DualVector<Scalar, N>::DualVector::__create_VectorT_zeros());
} }
template<typename Scalar, int N> DualVector<Scalar, N> round(const DualVector<Scalar, N> & x) { template<typename Scalar, int N> DualVector<Scalar, N> round(const DualVector<Scalar, N> & x) {
return DualVector<Scalar, N>(round(x.a), DualVector<Scalar, N>::VectorT::Zero()); return DualVector<Scalar, N>(round(x.a), DualVector<Scalar, N>::DualVector::__create_VectorT_zeros());
} }
template<typename Scalar, int N> std::ostream & operator<<(std::ostream & s, const DualVector<Scalar, N> & x) template<typename Scalar, int N> std::ostream & operator<<(std::ostream & s, const DualVector<Scalar, N> & x)

36
Makefile Normal file
View file

@ -0,0 +1,36 @@
CXX = g++
INCLUDE = -I../Catch2-master/single_include
CFLAGS = -Wall -std=c++11 -O0 -fprofile-arcs -ftest-coverage $(INCLUDE)
LDFLAGS = -lgcov
LDFLAGS_ALL = $(LDFLAGS)
OUTPUT_NAME = test_AutomaticDifferentiation
# scalar version
test_AutomaticDifferentiation:test_AutomaticDifferentiation.o test_AutomaticDifferentiation_main.o
$(CXX) -o $(OUTPUT_NAME) test_AutomaticDifferentiation.o test_AutomaticDifferentiation_main.o $(LDFLAGS_ALL)
test_AutomaticDifferentiation_manual:test_AutomaticDifferentiation_manual.o
$(CXX) -o $(OUTPUT_NAME) test_AutomaticDifferentiation_manual.o $(LDFLAGS_ALL)
test_AutomaticDifferentiation_main.o: test_AutomaticDifferentiation_main.cpp
$(CXX) $(CFLAGS) $(LDFLAGS) -c test_AutomaticDifferentiation_main.cpp
test_AutomaticDifferentiation.o: test_AutomaticDifferentiation.cpp
$(CXX) $(CFLAGS) $(LDFLAGS) -c test_AutomaticDifferentiation.cpp
test_AutomaticDifferentiation_manual.o: test_AutomaticDifferentiation_manual.cpp
$(CXX) $(CFLAGS) $(LDFLAGS) -c test_AutomaticDifferentiation_manual.cpp
# Vector version
test_AutomaticDifferentiation_vector:test_AutomaticDifferentiation_vector.o
$(CXX) -o test_AutomaticDifferentiation_vector.exe test_AutomaticDifferentiation_vector.o $(LDFLAGS_ALL)
test_AutomaticDifferentiation_vector.o: test_AutomaticDifferentiation_vector.cpp
$(CXX) $(CFLAGS) $(LDFLAGS) -c test_AutomaticDifferentiation_vector.cpp
clean:
rm *.o
cleaner:
rm *.o
rm $(OUTPUT_NAME)

View file

@ -0,0 +1,94 @@
#include "AutomaticDifferentiationVector.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
#define TEST_EQ_TOL 1e-9
// #define TEST_FUNCTION_ON_DUAL_DOUBLE(fct, x) assert(fct(Dual<double>(x)).a == fct(x))
// #define TEST_FUNCTION_ON_DUAL_DOUBLE(fct, x) assert(abs((fct(Dual<double>((x))).a) - (fct((x)))) <= TEST_EQ_TOL)
#define TEST_EQ_DOUBLE(a, b) assert(std::abs((a) - (b)) <= TEST_EQ_TOL)
template<typename Scalar>
Scalar f1(const Scalar & x)
{
return Scalar(5.)*x*x*x + Scalar(3.)*x*x - Scalar(2.)*x + Scalar(4.);
}
template<typename Scalar>
Scalar df1(const Scalar & x)
{
return Scalar(15.)*x*x + Scalar(6.)*x - Scalar(2.);
}
template<typename Scalar>
Scalar f3(const Scalar & x, const Scalar & y, const Scalar & z)
{
return sqrt(z*z+y*y+x*x);
}
template<typename Scalar>
Scalar df3x(const Scalar & x, const Scalar & y, const Scalar & z)
{
return x/sqrt(z*z+y*y+x*x);
}
template<typename Scalar>
Scalar df3y(const Scalar & x, const Scalar & y, const Scalar & z)
{
return y/sqrt(z*z+y*y+x*x);
}
template<typename Scalar>
Scalar df3z(const Scalar & x, const Scalar & y, const Scalar & z)
{
return z/sqrt(z*z+y*y+x*x);
}
int main()
{
// 1 var function
{
DualVector<double, 1> x = 1.54;
PRINT_DUAL(x);
x.diff(0);
PRINT_DUAL(x);
auto y = f1(x);
PRINT_VAR(x);
PRINT_DUAL(y);
PRINT_VAR(y.b);
PRINT_VAR(df1(x.a));
TEST_EQ_DOUBLE(df1(x.a), y.b[0]);
}
// 3 var function
{
DualVector<double,3> x(2.), y(3.), z(-1.5);
x.diff(0);
y.diff(1);
z.diff(2);
auto res = f3(x, y, z);
PRINT_DUAL(res);
PRINT_VAR(res.b[0]);
PRINT_VAR(res.b[1]);
PRINT_VAR(res.b[2]);
PRINT_VAR(df3x(x.a, y.a, z.a));
PRINT_VAR(df3y(x.a, y.a, z.a));
PRINT_VAR(df3z(x.a, y.a, z.a));
TEST_EQ_DOUBLE(res.b[0], df3x(x.a, y.a, z.a));
TEST_EQ_DOUBLE(res.b[1], df3y(x.a, y.a, z.a));
TEST_EQ_DOUBLE(res.b[2], df3z(x.a, y.a, z.a));
}
return 0;
}