diff --git a/AutomaticDifferentiationVector.hpp b/AutomaticDifferentiationVector.hpp index e6455df..40be24f 100644 --- a/AutomaticDifferentiationVector.hpp +++ b/AutomaticDifferentiationVector.hpp @@ -1,10 +1,19 @@ #ifndef DEF_AUTOMATIC_DIFFERENTIATION #define DEF_AUTOMATIC_DIFFERENTIATION +#include #include #include -#include +#include + +template +std::ostream & operator<<(std::ostream & out, std::valarray const& v) +{ + for(size_t i = 0 ; i < v.size() ; i++) + out << v[i] << " "; + return out; +} /// Implementation of dual numbers for automatic differentiation. /// This implementation uses vectors for b so that function gradients can be computed in one function call. @@ -14,9 +23,15 @@ template class DualVector { public: - using VectorT = Eigen::Matrix; + using VectorT = std::valarray; - 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), b(_b) {} @@ -27,14 +42,25 @@ class DualVector b.fill(_b); } + /// Use this function to set what variable is to be derived : x + DualVector::d(i) static DualVector d(int i = 0) { assert(i >= 0); assert(i < N); - VectorT _d = VectorT::Zero(); + VectorT _d = DualVector::__create_VectorT_zeros(); _d[i] = Scalar(1.); 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) { @@ -305,7 +331,7 @@ template DualVector sqrt(const DualVector DualVector sign(const DualVector & x) { - return DualVector(sign(x.a), DualVector::VectorT::Zero()); + return DualVector(sign(x.a), DualVector::DualVector::__create_VectorT_zeros()); } template DualVector abs(const DualVector & x) { @@ -313,19 +339,19 @@ template DualVector abs(const DualVector DualVector heaviside(const DualVector & x) { - return DualVector(heaviside(x.a), DualVector::VectorT::Zero()); + return DualVector(heaviside(x.a), DualVector::DualVector::__create_VectorT_zeros()); } template DualVector floor(const DualVector & x) { - return DualVector(floor(x.a), DualVector::VectorT::Zero()); + return DualVector(floor(x.a), DualVector::DualVector::__create_VectorT_zeros()); } template DualVector ceil(const DualVector & x) { - return DualVector(ceil(x.a), DualVector::VectorT::Zero()); + return DualVector(ceil(x.a), DualVector::DualVector::__create_VectorT_zeros()); } template DualVector round(const DualVector & x) { - return DualVector(round(x.a), DualVector::VectorT::Zero()); + return DualVector(round(x.a), DualVector::DualVector::__create_VectorT_zeros()); } template std::ostream & operator<<(std::ostream & s, const DualVector & x) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9558a74 --- /dev/null +++ b/Makefile @@ -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) diff --git a/test_vector_version_additions_manual.cpp b/test_vector_version_additions_manual.cpp new file mode 100644 index 0000000..3c27c61 --- /dev/null +++ b/test_vector_version_additions_manual.cpp @@ -0,0 +1,94 @@ +#include "AutomaticDifferentiationVector.hpp" + +#include +#include +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(x)).a == fct(x)) +// #define TEST_FUNCTION_ON_DUAL_DOUBLE(fct, x) assert(abs((fct(Dual((x))).a) - (fct((x)))) <= TEST_EQ_TOL) +#define TEST_EQ_DOUBLE(a, b) assert(std::abs((a) - (b)) <= TEST_EQ_TOL) + +template +Scalar f1(const Scalar & x) +{ + return Scalar(5.)*x*x*x + Scalar(3.)*x*x - Scalar(2.)*x + Scalar(4.); +} + +template +Scalar df1(const Scalar & x) +{ + return Scalar(15.)*x*x + Scalar(6.)*x - Scalar(2.); +} + +template +Scalar f3(const Scalar & x, const Scalar & y, const Scalar & z) +{ + return sqrt(z*z+y*y+x*x); +} + +template +Scalar df3x(const Scalar & x, const Scalar & y, const Scalar & z) +{ + return x/sqrt(z*z+y*y+x*x); +} + +template +Scalar df3y(const Scalar & x, const Scalar & y, const Scalar & z) +{ + return y/sqrt(z*z+y*y+x*x); +} + +template +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 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 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; +}