#ifndef FILE_AUTODIFF #define FILE_AUTODIFF /**************************************************************************/ /* File: autodiff.hpp */ /* Author: Joachim Schoeberl */ /* Date: 24. Oct. 02 */ /**************************************************************************/ // Automatic differentiation datatype namespace netgen { /** Datatype for automatic differentiation. Contains function value and D derivatives. Algebraic operations are overloaded by using product-rule etc. etc. **/ template class AutoDiff { SCAL val; SCAL dval[D]; public: typedef AutoDiff TELEM; typedef SCAL TSCAL; /// elements are undefined AutoDiff () throw() { }; // { val = 0; for (int i = 0; i < D; i++) dval[i] = 0; } // ! /// copy constructor AutoDiff (const AutoDiff & ad2) throw() { val = ad2.val; for (int i = 0; i < D; i++) dval[i] = ad2.dval[i]; } /// initial object with constant value AutoDiff (SCAL aval) throw() { val = aval; for (int i = 0; i < D; i++) dval[i] = 0; } /// init object with (val, e_diffindex) AutoDiff (SCAL aval, int diffindex) throw() { val = aval; for (int i = 0; i < D; i++) dval[i] = 0; dval[diffindex] = 1; } /// assign constant value AutoDiff & operator= (SCAL aval) throw() { val = aval; for (int i = 0; i < D; i++) dval[i] = 0; return *this; } /// returns value SCAL Value() const throw() { return val; } /// returns partial derivative SCAL DValue (int i) const throw() { return dval[i]; } /// access value SCAL & Value() throw() { return val; } /// accesses partial derivative SCAL & DValue (int i) throw() { return dval[i]; } /// AutoDiff & operator+= (const AutoDiff & y) throw() { val += y.val; for (int i = 0; i < D; i++) dval[i] += y.dval[i]; return *this; } /// AutoDiff & operator-= (const AutoDiff & y) throw() { val -= y.val; for (int i = 0; i < D; i++) dval[i] -= y.dval[i]; return *this; } /// AutoDiff & operator*= (const AutoDiff & y) throw() { for (int i = 0; i < D; i++) { // dval[i] *= y.val; // dval[i] += val * y.dval[i]; dval[i] = dval[i] * y.val + val * y.dval[i]; } val *= y.val; return *this; } /// AutoDiff & operator*= (const SCAL & y) throw() { val *= y; for (int i = 0; i < D; i++) dval[i] *= y; return *this; } /// AutoDiff & operator/= (const SCAL & y) throw() { SCAL iy = 1.0 / y; val *= iy; for (int i = 0; i < D; i++) dval[i] *= iy; return *this; } /// bool operator== (SCAL val2) throw() { return val == val2; } /// bool operator!= (SCAL val2) throw() { return val != val2; } /// bool operator< (SCAL val2) throw() { return val < val2; } /// bool operator> (SCAL val2) throw() { return val > val2; } }; //@{ AutoDiff helper functions. /// prints AutoDiff template inline ostream & operator<< (ostream & ost, const AutoDiff & x) { ost << x.Value() << ", D = "; for (int i = 0; i < D; i++) ost << x.DValue(i) << " "; return ost; } /// AutoDiff plus AutoDiff template inline AutoDiff operator+ (const AutoDiff & x, const AutoDiff & y) throw() { AutoDiff res; res.Value () = x.Value()+y.Value(); // AutoDiff res(x.Value()+y.Value()); for (int i = 0; i < D; i++) res.DValue(i) = x.DValue(i) + y.DValue(i); return res; } /// AutoDiff minus AutoDiff template inline AutoDiff operator- (const AutoDiff & x, const AutoDiff & y) throw() { AutoDiff res; res.Value() = x.Value()-y.Value(); // AutoDiff res (x.Value()-y.Value()); for (int i = 0; i < D; i++) res.DValue(i) = x.DValue(i) - y.DValue(i); return res; } /// double plus AutoDiff template inline AutoDiff operator+ (double x, const AutoDiff & y) throw() { AutoDiff res; res.Value() = x+y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = y.DValue(i); return res; } /// AutoDiff plus double template inline AutoDiff operator+ (const AutoDiff & y, double x) throw() { AutoDiff res; res.Value() = x+y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = y.DValue(i); return res; } /// minus AutoDiff template inline AutoDiff operator- (const AutoDiff & x) throw() { AutoDiff res; res.Value() = -x.Value(); for (int i = 0; i < D; i++) res.DValue(i) = -x.DValue(i); return res; } /// AutoDiff minus double template inline AutoDiff operator- (const AutoDiff & x, double y) throw() { AutoDiff res; res.Value() = x.Value()-y; for (int i = 0; i < D; i++) res.DValue(i) = x.DValue(i); return res; } /// template inline AutoDiff operator- (double x, const AutoDiff & y) throw() { AutoDiff res; res.Value() = x-y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = -y.DValue(i); return res; } /// double times AutoDiff template inline AutoDiff operator* (double x, const AutoDiff & y) throw() { AutoDiff res; res.Value() = x*y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = x*y.DValue(i); return res; } /// AutoDiff times double template inline AutoDiff operator* (const AutoDiff & y, double x) throw() { AutoDiff res; res.Value() = x*y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = x*y.DValue(i); return res; } /// AutoDiff times AutoDiff template inline AutoDiff operator* (const AutoDiff & x, const AutoDiff & y) throw() { AutoDiff res; SCAL hx = x.Value(); SCAL hy = y.Value(); res.Value() = hx*hy; for (int i = 0; i < D; i++) res.DValue(i) = hx*y.DValue(i) + hy*x.DValue(i); return res; } /// Inverse of AutoDiff template inline AutoDiff Inv (const AutoDiff & x) { AutoDiff res(1.0 / x.Value()); for (int i = 0; i < D; i++) res.DValue(i) = -x.DValue(i) / (x.Value() * x.Value()); return res; } /// AutoDiff div AutoDiff template inline AutoDiff operator/ (const AutoDiff & x, const AutoDiff & y) { return x * Inv (y); } /// AutoDiff div double template inline AutoDiff operator/ (const AutoDiff & x, double y) { return (1/y) * x; } /// double div AutoDiff template inline AutoDiff operator/ (double x, const AutoDiff & y) { return x * Inv(y); } } // namespace netgen namespace ngcore { /// AutoDiff times AutoDiff template inline netgen::AutoDiff sqr (const netgen::AutoDiff & x) throw() { netgen::AutoDiff res; SCAL hx = x.Value(); res.Value() = hx*hx; hx *= 2; for (int i = 0; i < D; i++) res.DValue(i) = hx*x.DValue(i); return res; } } // namespace ngcore namespace std { template inline netgen::AutoDiff fabs (const netgen::AutoDiff & x) { double abs = fabs (x.Value()); netgen::AutoDiff res( abs ); if (abs != 0.0) for (int i = 0; i < D; i++) res.DValue(i) = x.DValue(i) / abs; else for (int i = 0; i < D; i++) res.DValue(i) = 0.0; return res; } } // namespace std #endif