/**************************************************************************** * Copyright Joaquim R. R. A. Martins, Peter Sturdza * * * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ // NOTE: taken from website http://mdolab.utias.utoronto.ca/resources/complex-step/cpp // // please cite: @article{Martins:2003:CSD, Author = {Joaquim R. R. A. Martins and Peter Sturdza and Juan J. Alonso}, Journal = {{ACM} Transactions on Mathematical Software}, Number = {3}, Pages = {245--262}, Title = {The Complex-Step Derivative Approximation}, Volume = {29}, Year = {2003}} /*** * For automatic differentiation of a C/C++ code: * f'(x) = imag [ f(surreal(x,1)) ] * Define a double precision class that computes and stores values * and derivatives for each variable and overloads all operators. * Tue Jul 18 22:12:28 PDT 2000 ***/ #ifndef HDRderivify #define HDRderivify #include #include // using namespace std; // #define AUTO_DIFF //uncomment this line to use automatic differenciation #ifndef HDRcomplexify inline const double & real(const double& r) { /*** * So the real() statement can be used even with * the double version of the code to be derivified, * and remains compatible with complexified code, too. * Most useful inside printf statements. ***/ return r; } inline double & real(double & r) { return r;} inline double imag(const double& r) { return 0.; } #endif // HDRcomplexify #ifdef AUTO_DIFF class surreal { #define surr_TEENY (1.e-24) /*machine zero compared to nominal value of val*/ double val, deriv; public: surreal(const double& v=0.0, const double& d=0.0) : val(v), deriv(d) {} inline surreal& operator=(const surreal & s) {val = s.val ; deriv = s.deriv; return *this;}; operator double() const {return val;} operator int() const {return int(val);} inline friend const double & real(const surreal& z) ; // born out of inline friend const double & imag(const surreal& z) ; // complex step inline friend double & real(surreal& z) ; // born out of inline friend double & imag(surreal& z) ; // complex step // relational operators inline friend bool operator==(const surreal&,const surreal&); inline friend bool operator==(const surreal&,const double&); inline friend bool operator==(const double&,const surreal&); inline friend bool operator!=(const surreal&,const surreal&); inline friend bool operator!=(const surreal&,const double&); inline friend bool operator!=(const double&,const surreal&); inline friend bool operator>(const surreal&,const surreal&); inline friend bool operator>(const surreal&,const double&); inline friend bool operator>(const double&,const surreal&); inline friend bool operator<(const surreal&,const surreal&); inline friend bool operator<(const surreal&,const double&); inline friend bool operator<(const double&,const surreal&); inline friend bool operator>=(const surreal&,const surreal&); inline friend bool operator>=(const surreal&,const double&); inline friend bool operator>=(const double&,const surreal&); inline friend bool operator<=(const surreal&,const surreal&); inline friend bool operator<=(const surreal&,const double&); inline friend bool operator<=(const double&,const surreal&); // basic arithmetic inline surreal operator+() const; inline surreal operator+(const surreal&) const; inline surreal operator+(const double&) const; inline surreal operator+(const int&) const; inline surreal& operator+=(const surreal&); inline surreal& operator+=(const double&); inline surreal& operator+=(const int&); inline friend surreal operator+(const double&, const surreal&); inline friend surreal operator+(const int&, const surreal&); inline surreal operator-() const; inline surreal operator-(const surreal&) const; inline surreal operator-(const double&) const; inline surreal operator-(const int&) const; inline surreal& operator-=(const surreal&); inline surreal& operator-=(const double&); inline surreal& operator-=(const int&); inline friend surreal operator-(const double&, const surreal&); inline friend surreal operator-(const int&, const surreal&); inline surreal operator*(const surreal&) const; inline surreal operator*(const double&) const; inline surreal operator*(const int&) const; inline surreal& operator*=(const surreal&); inline surreal& operator*=(const double&); inline surreal& operator*=(const int&); inline friend surreal operator*(const double&, const surreal&); inline friend surreal operator*(const int&, const surreal&); inline surreal operator/(const surreal&) const; inline surreal operator/(const double&) const; inline surreal operator/(const int&) const; inline surreal& operator/=(const surreal&); inline surreal& operator/=(const double&); inline surreal& operator/=(const int&); inline friend surreal operator/(const double&, const surreal&); inline friend surreal operator/(const int&, const surreal&); // from // not implemented are ldexp, frexp, modf, and fmod inline friend surreal fabs(const surreal&); inline friend surreal sin(const surreal&); inline friend surreal sinh(const surreal&); inline friend surreal asin(const surreal&); inline friend surreal cos(const surreal&); inline friend surreal cosh(const surreal&); inline friend surreal acos(const surreal&); inline friend surreal tan(const surreal&); inline friend surreal tanh(const surreal&); inline friend surreal atan(const surreal&); inline friend surreal atan2(const surreal&, const surreal&); inline friend surreal log(const surreal&); inline friend surreal log10(const surreal&); inline friend surreal sqrt(const surreal&); inline friend surreal exp(const surreal&); inline friend surreal pow(const surreal&, const surreal&); inline friend surreal pow(const surreal&, const double&); inline friend surreal pow(const surreal&, const int&); inline friend surreal pow(const double&, const surreal&); inline friend surreal pow(const int&, const surreal&); inline friend surreal ceil(const surreal&); inline friend surreal floor(const surreal&); // input/output friend istream& operator>>(istream&, surreal&); friend ostream& operator<<(ostream&, const surreal&); }; inline bool operator==(const surreal& lhs, const surreal& rhs) { return lhs.val == rhs.val; } inline bool operator==(const surreal& lhs, const double& rhs) { return lhs.val == rhs; } inline bool operator==(const double& lhs, const surreal& rhs) { return lhs == rhs.val; } inline bool operator!=(const surreal& lhs, const surreal& rhs) { return lhs.val != rhs.val; } inline bool operator!=(const surreal& lhs, const double& rhs) { return lhs.val != rhs; } inline bool operator!=(const double& lhs, const surreal& rhs) { return lhs != rhs.val; } inline bool operator>(const surreal& lhs, const surreal& rhs) { return lhs.val > rhs.val; } inline bool operator>(const surreal& lhs, const double& rhs) { return lhs.val > rhs; } inline bool operator>(const double& lhs, const surreal& rhs) { return lhs > rhs.val; } inline bool operator<(const surreal& lhs, const surreal& rhs) { return lhs.val < rhs.val; } inline bool operator<(const surreal& lhs, const double& rhs) { return lhs.val < rhs; } inline bool operator<(const double& lhs, const surreal& rhs) { return lhs < rhs.val; } inline bool operator>=(const surreal& lhs, const surreal& rhs) { return lhs.val >= rhs.val; } inline bool operator>=(const surreal& lhs, const double& rhs) { return lhs.val >= rhs; } inline bool operator>=(const double& lhs, const surreal& rhs) { return lhs >= rhs.val; } inline bool operator<=(const surreal& lhs, const surreal& rhs) { return lhs.val <= rhs.val; } inline bool operator<=(const surreal& lhs, const double& rhs) { return lhs.val <= rhs; } inline bool operator<=(const double& lhs, const surreal& rhs) { return lhs <= rhs.val; } inline surreal surreal::operator+() const { return *this; } inline surreal surreal::operator+(const surreal& z) const { return surreal(val+z.val,deriv+z.deriv); } inline surreal surreal::operator+(const double& r) const { return surreal(val+r,deriv); } inline surreal surreal::operator+(const int& i) const { return surreal(val+double(i),deriv); } inline surreal& surreal::operator+=(const surreal& z) { val+=z.val; deriv+=z.deriv; return *this; } inline surreal& surreal::operator+=(const double& r) { val+=r; return *this; } inline surreal& surreal::operator+=(const int& i) { val+=double(i); return *this; } inline surreal operator+(const double& r, const surreal& z) { return surreal(r+z.val,z.deriv); } inline surreal operator+(const int& i, const surreal& z) { return surreal(double(i)+z.val,z.deriv); } inline surreal surreal::operator-() const { return surreal(-val,-deriv); } inline surreal surreal::operator-(const surreal& z) const { return surreal(val-z.val,deriv-z.deriv); } inline surreal surreal::operator-(const double& r) const { return surreal(val-r,deriv); } inline surreal surreal::operator-(const int& i) const { return surreal(val-double(i),deriv); } inline surreal& surreal::operator-=(const surreal& z) { val-=z.val; deriv-=z.deriv; return *this; } inline surreal& surreal::operator-=(const double& r) { val-=r; return *this; } inline surreal& surreal::operator-=(const int& i) { val-=double(i); return *this; } inline surreal operator-(const double& r, const surreal& z) { return surreal(r-z.val,-z.deriv); } inline surreal operator-(const int& i, const surreal& z) { return surreal(double(i)-z.val,-z.deriv); } inline surreal surreal::operator*(const surreal& z) const { return surreal(val*z.val,val*z.deriv+z.val*deriv); } inline surreal surreal::operator*(const double& r) const { return surreal(val*r,deriv*r); } inline surreal surreal::operator*(const int& i) const { return surreal(val*double(i),deriv*double(i)); } inline surreal& surreal::operator*=(const surreal& z) { deriv=val*z.deriv+z.val*deriv; val*=z.val; return *this; } inline surreal& surreal::operator*=(const double& r) { val*=r; deriv*=r; return *this; } inline surreal& surreal::operator*=(const int& i) { val*=double(i); deriv*=double(i); return *this; } inline surreal operator*(const double& r, const surreal& z) { return surreal(r*z.val,r*z.deriv); } inline surreal operator*(const int& i, const surreal& z) { return surreal(double(i)*z.val,double(i)*z.deriv); } inline surreal surreal::operator/(const surreal& z) const { return surreal(val/z.val,(z.val*deriv-val*z.deriv)/(z.val*z.val)); } inline surreal surreal::operator/(const double& r) const { return surreal(val/r,deriv/r); } inline surreal surreal::operator/(const int& i) const { return surreal(val/double(i),deriv/double(i)); } inline surreal& surreal::operator/=(const surreal& z) { deriv=(z.val*deriv-val*z.deriv)/(z.val*z.val); val/=z.val; return *this; } inline surreal& surreal::operator/=(const double& r) { val/=r; deriv/=r; return *this; } inline surreal& surreal::operator/=(const int& i) { val/=double(i); val/=double(i); return *this; } inline surreal operator/(const double& r, const surreal& z) { return surreal(r/z.val,-r*z.deriv/(z.val*z.val)); } inline surreal operator/(const int& i, const surreal& z) { return surreal(double(i)/z.val,-double(i)*z.deriv/(z.val*z.val)); } inline surreal fabs(const surreal& z) { return (z.val<0.0) ? -z:z; } inline surreal sin(const surreal& z) { return surreal(sin(z.val),z.deriv*cos(z.val)); } inline surreal sinh(const surreal& z) { return surreal(sinh(z.val),z.deriv*cosh(z.val)); } inline surreal asin(const surreal& z) { // derivative trouble if z.val = +/- 1.0 return surreal(asin(z.val),z.deriv/sqrt(1.0-z.val*z.val+surr_TEENY)); } inline surreal cos(const surreal& z) { return surreal(cos(z.val),-z.deriv*sin(z.val)); } inline surreal cosh(const surreal& z) { return surreal(cosh(z.val),z.deriv*sinh(z.val)); } inline surreal acos(const surreal& z) { // derivative trouble if z.val = +/- 1.0 return surreal(acos(z.val),-z.deriv/sqrt(1.0-z.val*z.val+surr_TEENY)); } inline surreal tan(const surreal& z) { double cosv=cos(z.val); return surreal(tan(z.val),z.deriv/(cosv*cosv)); } inline surreal tanh(const surreal& z) { double coshv=cosh(z.val); return surreal(tanh(z.val),z.deriv/(coshv*coshv)); } inline surreal atan(const surreal& z) { return surreal(atan(z.val),z.deriv/(1.0+z.val*z.val)); } inline surreal atan2(const surreal& z1, const surreal& z2) { return surreal(atan2(z1.val,z2.val), (z2.val*z1.deriv-z1.val*z2.deriv)/(z1.val*z1.val+z2.val*z2.val)); } inline surreal log(const surreal& z) { return surreal(log(z.val),z.deriv/z.val); } inline surreal log10(const surreal& z) { return surreal(log10(z.val),z.deriv/(z.val*log(10.))); } inline surreal sqrt(const surreal& z) { // if z.val = 0, then there is trouble with the derivative. // this may work if nominal z.val values are scaled properly. double sqrtv=sqrt(z.val); return surreal(sqrtv,0.5*z.deriv/(sqrtv+surr_TEENY)); } inline surreal exp(const surreal& z) { double expv=exp(z.val); return surreal(expv,z.deriv*expv); } inline surreal pow(const surreal& a, const surreal& b) { // many sticky points were derivative is undefined or infinite // badness if 0 <= b.val < 1 and a.val == 0 double powab=pow(a.val,b.val); return surreal(powab, b.val*pow(a.val,b.val-1.)*a.deriv +powab*log(a.val)*b.deriv); } inline surreal pow(const surreal& a, const double& b) { return surreal(pow(a.val,b),b*pow(a.val,b-1.)*a.deriv); } inline surreal pow(const surreal& a, const int& b) { return surreal(pow(a.val,double(b)), double(b)*pow(a.val,double(b-1))*a.deriv); } inline surreal pow(const double& a, const surreal& b) { double powab=pow(a,b.val); return surreal(powab,powab*log(a)*b.deriv); } inline surreal pow(const int& a, const surreal& b) { double powab=pow(double(a),b); return surreal(powab,powab*log(double(a))*b.deriv); } inline surreal ceil(const surreal& z) { return surreal(ceil(z.val),0.); } inline surreal floor(const surreal& z) { return surreal(floor(z.val),0.); } inline istream& operator>>(istream& is, surreal& x) { /*** * Straight from Stroustrup's (third edition) complex version. * Much confusion about the ipfx, isfx functions used in * the GNU library and the sentry type that is supposed to * call them indirectly. Stroustrup implies that this * works fine when streams are tied and other fancy stuff. ***/ double re, im = 0; char c = 0; is >> c; if (c == '(') { is >> re >> c; if (c == ',') is >> im >> c; if (c != ')') is.clear(ios::badbit); } else { is.putback(c); is >> re; } if (is) x = surreal (re, im); return is; } inline ostream& operator<<(ostream& os, const surreal& z) { return os << '(' << real (z) << ',' << imag (z) << ')'; } inline const double & real(const surreal& z) {return z.val;} // born out of inline const double & imag(const surreal& z) {return z.deriv;}// complex step inline double & real(surreal& z) {return z.val;} // born out of inline double & imag(surreal& z) {return z.deriv;}// complex step #endif // #ifdef AUTO_DIFF #undef surr_TEENY #endif