#ifndef DEF_AUTOMATIC_DIFFERENTIATION #define DEF_AUTOMATIC_DIFFERENTIATION #include #include /// Implementation of dual numbers for automatic differentiation /// reference : http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.89.7749&rep=rep1&type=pdf template class Dual { public: Dual(const Scalar & _a, const Scalar & _b = Scalar(0.0)) : a(_a), b(_b) {} static Dual d() { return Dual(Scalar(0.), Scalar(1.)); } Dual & operator+=(const Dual & x) { a += x.a; 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 Scalar b; /// Infinitesimal part }; template Dual operator+(A const& v, Dual const& x) { return (Dual(v) + x); } template Dual operator-(A const& v, Dual const& x) { return (Dual(v) - x); } template Dual operator*(A const& v, Dual const& x) { return (Dual(v) * x); } template Dual operator/(A const& v, Dual const& x) { return (Dual(v) / x); } // Basic mathematical functions for Scalar numbers // Trigonometric functions template Scalar sec(const Scalar & x) { return Scalar(1.)/cos(x); } template Scalar cot(const Scalar & x) { return cos(x)/sin(x); } template Scalar csc(const Scalar & x) { return Scalar(1.)/sin(x); } // Inverse trigonometric functions template Scalar asec(const Scalar & x) { return acos(Scalar(1.)/x); } template Scalar acot(const Scalar & x) { return atan(Scalar(1.)/x); } template Scalar acsc(const Scalar & x) { return asin(Scalar(1.)/x); } // Hyperbolic trigonometric functions template Scalar sech(const Scalar & x) { return Scalar(1.)/cosh(x); } template Scalar coth(const Scalar & x) { return cosh(x)/sinh(x); } template Scalar csch(const Scalar & x) { return Scalar(1.)/sinh(x); } // Inverse hyperbolic trigonometric functions template Scalar asech(const Scalar & x) { return log((Scalar(1.) + sqrt(Scalar(1.) - x*x))/x); } template Scalar acoth(const Scalar & x) { return Scalar(0.5)*log((x + Scalar(1.))/(x - Scalar(1.))); } template Scalar acsch(const Scalar & x) { return (x >= Scalar(0.)) ? log((Scalar(1.) + sqrt(Scalar(1.) + x*x))/x) : log((Scalar(1.) - sqrt(Scalar(1.) + x*x))/x); } // Other functions template Scalar exp10(const Scalar & x) { return exp(x*log(Scalar(10.))); } template Scalar sign(const Scalar & x) { return (x >= Scalar(0.)) ? ((x > Scalar(0.)) ? Scalar(1.) : Scalar(0.)) : Scalar(-1.); } template Scalar heaviside(const Scalar & x) { return Scalar(x >= Scalar(0.)); } template Scalar abs(const Scalar & x) { return (x >= Scalar(0.)) ? x : -x; } // Basic mathematical functions for Dual numbers // f(a + b*d) = f(a) + b*f'(a)*d // Trigonometric functions template Dual cos(const Dual & x) { return Dual(cos(x.a), -x.b*sin(x.a)); } template Dual sin(const Dual & x) { return Dual(sin(x.a), x.b*cos(x.a)); } template Dual tan(const Dual & x) { return Dual(tan(x.a), x.b*sec(x.a)*sec(x.a)); } template Dual sec(const Dual & x) { return Dual(sec(x.a), x.b*sec(x.a)*tan(x.a)); } template Dual cot(const Dual & x) { return Dual(cot(x.a), x.b*(-csc(x.a)*csc(x.a))); } template Dual csc(const Dual & x) { return Dual(csc(x.a), x.b*(-cot(x.a)*csc(x.a))); } // Inverse trigonometric functions template Dual acos(const Dual & x) { return Dual(acos(x.a), x.b*(-Scalar(1.)/sqrt(Scalar(1.)-x.a*x.a))); } template Dual asin(const Dual & x) { return Dual(asin(x.a), x.b*(Scalar(1.)/sqrt(Scalar(1.)-x.a*x.a))); } template Dual atan(const Dual & x) { return Dual(atan(x.a), x.b*(Scalar(1.)/(x.a*x.a + Scalar(1.)))); } template Dual asec(const Dual & x) { return Dual(asec(x.a), x.b*(Scalar(1.)/(sqrt(Scalar(1.)-Scalar(1.)/(x.a*x.a))*(x.a*x.a)))); } template Dual acot(const Dual & x) { return Dual(acot(x.a), x.b*(-Scalar(1.)/((x.a*x.a)+Scalar(1.)))); } template Dual acsc(const Dual & x) { return Dual(acsc(x.a), x.b*(-Scalar(1.)/(sqrt(Scalar(1.)-Scalar(1.)/(x.a*x.a))*(x.a*x.a)))); } // Hyperbolic trigonometric functions template Dual cosh(const Dual & x) { return Dual(cosh(x.a), x.b*sinh(x.a)); } template Dual sinh(const Dual & x) { return Dual(sinh(x.a), x.b*cosh(x.a)); } template Dual tanh(const Dual & x) { return Dual(tanh(x.a), x.b*sech(x.a)*sech(x.a)); } template Dual sech(const Dual & x) { return Dual(sech(x.a), x.b*(-sech(x.a)*tanh(x.a))); } template Dual coth(const Dual & x) { return Dual(coth(x.a), x.b*(-csch(x.a)*csch(x.a))); } template Dual csch(const Dual & x) { return Dual(csch(x.a), x.b*(-coth(x.a)*csch(x.a))); } // Inverse hyperbolic trigonometric functions template Dual acosh(const Dual & x) { return Dual(acosh(x.a), x.b*(Scalar(1.)/sqrt((x.a*x.a)-Scalar(1.)))); } template Dual asinh(const Dual & x) { return Dual(asinh(x.a), x.b*(Scalar(1.)/sqrt((x.a*x.a)+Scalar(1.)))); } template Dual atanh(const Dual & x) { return Dual(atanh(x.a), x.b*(Scalar(1.)/(Scalar(1.)-(x.a*x.a)))); } template Dual asech(const Dual & x) { return Dual(asech(x.a), x.b*(Scalar(-1.)/(sqrt(Scalar(1.)/(x.a*x.a)-Scalar(1.))*(x.a*x.a)))); } template Dual acoth(const Dual & x) { return Dual(acoth(x.a), x.b*(-Scalar(1.)/((x.a*x.a)-Scalar(1.)))); } template Dual acsch(const Dual & x) { return Dual(acsch(x.a), x.b*(-Scalar(1.)/(sqrt(Scalar(1.)/(x.a*x.a)+Scalar(1.))*(x.a*x.a)))); } // Exponential functions template Dual exp(const Dual & x) { return Dual(exp(x.a), x.b*exp(x.a)); } template Dual log(const Dual & x) { return Dual(log(x.a), x.b/x.a); } template Dual exp10(const Dual & x) { return Dual(exp10(x.a), x.b*(log(Scalar(10.))*exp10(x.a))); } template Dual log10(const Dual & x) { return Dual(log10(x.a), x.b/(log(Scalar(10.))*x.a)); } template Dual exp2(const Dual & x) { return Dual(exp2(x.a), x.b*(log(Scalar(2.))*exp2(x.a))); } template Dual log2(const Dual & x) { return Dual(log2(x.a), x.b/(log(Scalar(2.))*x.a)); } template Dual pow(const Dual & x, const Dual & n) { return exp(n*log(x)); } // Other functions template Dual sqrt(const Dual & x) { return Dual(sqrt(x.a), x.b/(Scalar(2.)*sqrt(x.a))); } template Dual sign(const Dual & x) { return Dual(sign(x.a), Scalar(0.)); } template Dual abs(const Dual & x) { return Dual(abs(x.a), x.b*sign(x.a)); } template Dual fabs(const Dual & x) { return Dual(fabs(x.a), x.b*sign(x.a)); } template Dual heaviside(const Dual & x) { return Dual(heaviside(x.a), Scalar(0.)); } template Dual floor(const Dual & x) { return Dual(floor(x.a), Scalar(0.)); } template Dual ceil(const Dual & x) { return Dual(ceil(x.a), Scalar(0.)); } template Dual round(const Dual & x) { return Dual(round(x.a), Scalar(0.)); } template std::ostream & operator<<(std::ostream & s, const Dual & x) { return (s << x.a); } #endif