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:
parent
d59c41c874
commit
a60cac7f56
3 changed files with 165 additions and 9 deletions
|
|
@ -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,15 +42,26 @@ 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)
|
||||||
{
|
{
|
||||||
a += x.a;
|
a += x.a;
|
||||||
|
|
@ -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
36
Makefile
Normal 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)
|
||||||
94
test_vector_version_additions_manual.cpp
Normal file
94
test_vector_version_additions_manual.cpp
Normal 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;
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue