#ifndef FILE_AUTODIFF #define FILE_AUTODIFF /**************************************************************************/ /* File: autodiff.hpp */ /* Author: Joachim Schoeberl */ /* Date: 24. Oct. 02 */ /**************************************************************************/ namespace ngcore { using ngcore::IfPos; // Automatic differentiation datatype template class AutoDiffRec; /** Datatype for automatic differentiation. Contains function value and D derivatives. Algebraic operations are overloaded by using product-rule etc. etc. **/ template class AutoDiffVec { SCAL val; SCAL dval[D?D:1]; public: typedef AutoDiffVec TELEM; typedef SCAL TSCAL; /// elements are undefined // NETGEN_INLINE AutoDiffVec () throw() { }; AutoDiffVec() = default; // { val = 0; for (int i = 0; i < D; i++) dval[i] = 0; } // ! /// copy constructor AutoDiffVec (const AutoDiffVec & ad2) = default; /* NETGEN_INLINE AutoDiffVec (const AutoDiffVec & ad2) throw() { val = ad2.val; for (int i = 0; i < D; i++) dval[i] = ad2.dval[i]; } */ /// initial object with constant value NETGEN_INLINE AutoDiffVec (SCAL aval) throw() { val = aval; for (int i = 0; i < D; i++) dval[i] = 0; } /// init object with (val, e_diffindex) NETGEN_INLINE AutoDiffVec (SCAL aval, int diffindex) throw() { val = aval; for (int i = 0; i < D; i++) dval[i] = 0; dval[diffindex] = 1; } NETGEN_INLINE AutoDiffVec (SCAL aval, const SCAL * grad) { val = aval; LoadGradient (grad); } /// assign constant value NETGEN_INLINE AutoDiffVec & operator= (SCAL aval) throw() { val = aval; for (int i = 0; i < D; i++) dval[i] = 0; return *this; } AutoDiffVec & operator= (const AutoDiffVec & ad2) = default; /// returns value NETGEN_INLINE SCAL Value() const throw() { return val; } /// returns partial derivative NETGEN_INLINE SCAL DValue (int i) const throw() { return dval[i]; } /// NETGEN_INLINE void StoreGradient (SCAL * p) const { for (int i = 0; i < D; i++) p[i] = dval[i]; } NETGEN_INLINE void LoadGradient (const SCAL * p) { for (int i = 0; i < D; i++) dval[i] = p[i]; } /// access value NETGEN_INLINE SCAL & Value() throw() { return val; } /// accesses partial derivative NETGEN_INLINE SCAL & DValue (int i) throw() { return dval[i]; } }; //@{ AutoDiffVec helper functions. /// prints AutoDiffVec template inline ostream & operator<< (ostream & ost, const AutoDiffVec & x) { ost << x.Value() << ", D = "; for (int i = 0; i < D; i++) ost << x.DValue(i) << " "; return ost; } /// AutoDiffVec plus AutoDiffVec template NETGEN_INLINE AutoDiffVec operator+ (const AutoDiffVec & x, const AutoDiffVec & y) throw() { AutoDiffVec res; res.Value () = x.Value()+y.Value(); // AutoDiffVec res(x.Value()+y.Value()); for (int i = 0; i < D; i++) res.DValue(i) = x.DValue(i) + y.DValue(i); return res; } /// AutoDiffVec minus AutoDiffVec template NETGEN_INLINE AutoDiffVec operator- (const AutoDiffVec & x, const AutoDiffVec & y) throw() { AutoDiffVec res; res.Value() = x.Value()-y.Value(); // AutoDiffVec 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 AutoDiffVec template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator+ (SCAL2 x, const AutoDiffVec & y) throw() { AutoDiffVec res; res.Value() = x+y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = y.DValue(i); return res; } /// AutoDiffVec plus double template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator+ (const AutoDiffVec & y, SCAL2 x) throw() { AutoDiffVec res; res.Value() = x+y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = y.DValue(i); return res; } /// minus AutoDiffVec template NETGEN_INLINE AutoDiffVec operator- (const AutoDiffVec & x) throw() { AutoDiffVec res; res.Value() = -x.Value(); for (int i = 0; i < D; i++) res.DValue(i) = -x.DValue(i); return res; } /// AutoDiffVec minus double template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator- (const AutoDiffVec & x, SCAL2 y) throw() { AutoDiffVec res; res.Value() = x.Value()-y; for (int i = 0; i < D; i++) res.DValue(i) = x.DValue(i); return res; } /// template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator- (SCAL2 x, const AutoDiffVec & y) throw() { AutoDiffVec res; res.Value() = x-y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = -y.DValue(i); return res; } /// double times AutoDiffVec template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator* (SCAL2 x, const AutoDiffVec & y) throw() { AutoDiffVec res; res.Value() = x*y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = x*y.DValue(i); return res; } /// AutoDiffVec times double template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator* (const AutoDiffVec & y, SCAL2 x) throw() { AutoDiffVec res; res.Value() = x*y.Value(); for (int i = 0; i < D; i++) res.DValue(i) = x*y.DValue(i); return res; } /// AutoDiffVec times AutoDiffVec template NETGEN_INLINE AutoDiffVec operator* (const AutoDiffVec & x, const AutoDiffVec & y) throw() { AutoDiffVec 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; } /// AutoDiffVec times AutoDiffVec using ngcore::sqr; template NETGEN_INLINE AutoDiffVec sqr (const AutoDiffVec & x) throw() { AutoDiffVec 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; } /// Inverse of AutoDiffVec template NETGEN_INLINE AutoDiffVec Inv (const AutoDiffVec & x) { AutoDiffVec res(1.0 / x.Value()); for (int i = 0; i < D; i++) res.DValue(i) = -x.DValue(i) / (x.Value() * x.Value()); return res; } /// AutoDiffVec div AutoDiffVec template NETGEN_INLINE AutoDiffVec operator/ (const AutoDiffVec & x, const AutoDiffVec & y) { return x * Inv (y); } /// AutoDiffVec div double template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator/ (const AutoDiffVec & x, SCAL2 y) { return (1.0/y) * x; } /// double div AutoDiffVec template::value, int>::type = 0> NETGEN_INLINE AutoDiffVec operator/ (SCAL2 x, const AutoDiffVec & y) { return x * Inv(y); } template NETGEN_INLINE AutoDiffVec & operator+= (AutoDiffVec & x, SCAL2 y) throw() { x.Value() += y; return x; } /// template NETGEN_INLINE AutoDiffVec & operator+= (AutoDiffVec & x, AutoDiffVec y) { x.Value() += y.Value(); for (int i = 0; i < D; i++) x.DValue(i) += y.DValue(i); return x; } /// template NETGEN_INLINE AutoDiffVec & operator-= (AutoDiffVec & x, AutoDiffVec y) { x.Value() -= y.Value(); for (int i = 0; i < D; i++) x.DValue(i) -= y.DValue(i); return x; } template NETGEN_INLINE AutoDiffVec & operator-= (AutoDiffVec & x, SCAL2 y) { x.Value() -= y; return x; } /// template NETGEN_INLINE AutoDiffVec & operator*= (AutoDiffVec & x, AutoDiffVec y) { for (int i = 0; i < D; i++) x.DValue(i) = x.DValue(i)*y.Value() + x.Value() * y.DValue(i); x.Value() *= y.Value(); return x; } /// template NETGEN_INLINE AutoDiffVec & operator*= (AutoDiffVec & x, SCAL2 y) { x.Value() *= y; for (int i = 0; i < D; i++) x.DValue(i) *= y; return x; } /// template NETGEN_INLINE AutoDiffVec & operator/= (AutoDiffVec & x, SCAL y) { SCAL iy = 1.0 / y; x.Value() *= iy; for (int i = 0; i < D; i++) x.DValue(i) *= iy; return x; } /// template NETGEN_INLINE bool operator== (AutoDiffVec x, SCAL val2) { return x.Value() == val2; } /// template NETGEN_INLINE bool operator!= (AutoDiffVec x, SCAL val2) throw() { return x.Value() != val2; } /// template NETGEN_INLINE bool operator< (AutoDiffVec x, SCAL val2) throw() { return x.Value() < val2; } /// template NETGEN_INLINE bool operator> (AutoDiffVec x, SCAL val2) throw() { return x.Value() > val2; } template NETGEN_INLINE AutoDiffVec fabs (const AutoDiffVec & x) { double abs = fabs (x.Value()); AutoDiffVec res( abs ); if (abs != 0.0) for (int i = 0; i < D; i++) res.DValue(i) = x.Value()*x.DValue(i) / abs; else for (int i = 0; i < D; i++) res.DValue(i) = 0.0; return res; } using std::sqrt; template NETGEN_INLINE AutoDiffVec sqrt (const AutoDiffVec & x) { AutoDiffVec res; res.Value() = sqrt(x.Value()); for (int j = 0; j < D; j++) res.DValue(j) = 0.5 / res.Value() * x.DValue(j); return res; } using std::log; template AutoDiffVec log (AutoDiffVec x) { AutoDiffVec res; res.Value() = log(x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) / x.Value(); return res; } using std::exp; template NETGEN_INLINE AutoDiffVec exp (AutoDiffVec x) { AutoDiffVec res; res.Value() = exp(x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) * res.Value(); return res; } using std::pow; template NETGEN_INLINE AutoDiffVec pow (AutoDiffVec x, AutoDiffVec y ) { return exp(log(x)*y); } using std::sin; /* template NETGEN_INLINE AutoDiffVec sin (AutoDiffVec x) { AutoDiffVec res; res.Value() = sin(x.Value()); SCAL c = cos(x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) * c; return res; } */ template NETGEN_INLINE AutoDiffVec sin (AutoDiffVec x) { return sin(AutoDiffRec(x)); } using std::cos; /* template NETGEN_INLINE AutoDiffVec cos (AutoDiffVec x) { AutoDiffVec res; res.Value() = cos(x.Value()); SCAL ms = -sin(x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) * ms; return res; } */ template NETGEN_INLINE AutoDiffVec cos (AutoDiffVec x) { return cos(AutoDiffRec(x)); } using std::tan; template NETGEN_INLINE AutoDiffVec tan (AutoDiffVec x) { return sin(x) / cos(x); } using std::sinh; template NETGEN_INLINE AutoDiffVec sinh (AutoDiffVec x) { AutoDiffVec res; res.Value() = sinh(x.Value()); SCAL ch = cosh(x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) * ch; return res; } using std::cosh; template NETGEN_INLINE AutoDiffVec cosh (AutoDiffVec x) { AutoDiffVec res; res.Value() = cosh(x.Value()); SCAL sh = sinh(x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k) * sh; return res; } using std::erf; template NETGEN_INLINE AutoDiffVec erf (AutoDiffVec x) { return erf(AutoDiffRec(x)); } using std::floor; template NETGEN_INLINE AutoDiffVec floor (const AutoDiffVec & x) { AutoDiffVec res; res.Value() = floor(x.Value()); for (int j = 0; j < D; j++) res.DValue(j) = 0.0; return res; } using std::ceil; template NETGEN_INLINE AutoDiffVec ceil (const AutoDiffVec & x) { AutoDiffVec res; res.Value() = ceil(x.Value()); for (int j = 0; j < D; j++) res.DValue(j) = 0.0; return res; } using std::atan; /* template NETGEN_INLINE AutoDiffVec atan (AutoDiffVec x) { AutoDiffVec res; SCAL a = atan(x.Value()); res.Value() = a; for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k)/(1+x.Value()*x.Value()) ; return res; } */ template AutoDiffVec atan (AutoDiffVec x) { return atan (AutoDiffRec (x)); } using std::atan2; template NETGEN_INLINE AutoDiffVec atan2 (AutoDiffVec x, AutoDiffVec y) { AutoDiffVec res; SCAL a = atan2(x.Value(), y.Value()); res.Value() = a; for (int k = 0; k < D; k++) res.DValue(k) = (x.Value()*y.DValue(k)-y.Value()*x.DValue(k))/(y.Value()*y.Value()+x.Value()*x.Value()); return res; } using std::acos; template NETGEN_INLINE AutoDiffVec acos (AutoDiffVec x) { AutoDiffVec res; SCAL a = acos(x.Value()); res.Value() = a; SCAL da = -1 / sqrt(1-x.Value()*x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k)*da; return res; } using std::asin; template NETGEN_INLINE AutoDiffVec asin (AutoDiffVec x) { AutoDiffVec res; SCAL a = asin(x.Value()); res.Value() = a; SCAL da = 1 / sqrt(1-x.Value()*x.Value()); for (int k = 0; k < D; k++) res.DValue(k) = x.DValue(k)*da; return res; } template auto IfPos (AutoDiffVec a, TB b, TC c) // -> decltype(IfPos (a.Value(), b, c)) { return IfPos (a.Value(), b, c); } template NETGEN_INLINE AutoDiffVec IfPos (SCAL /* SIMD */ a, AutoDiffVec b, AutoDiffVec c) { AutoDiffVec res; res.Value() = IfPos (a, b.Value(), c.Value()); for (int j = 0; j < D; j++) res.DValue(j) = IfPos (a, b.DValue(j), c.DValue(j)); return res; } template NETGEN_INLINE AutoDiffVec IfPos (SCAL /* SIMD */ a, AutoDiffVec b, TC c) { return IfPos (a, b, AutoDiffVec (c)); } //@} template class AutoDiffRec { AutoDiffRec rec; SCAL last; public: NETGEN_INLINE AutoDiffRec () = default; NETGEN_INLINE AutoDiffRec (const AutoDiffRec &) = default; NETGEN_INLINE AutoDiffRec (AutoDiffRec _rec, SCAL _last) : rec(_rec), last(_last) { ; } NETGEN_INLINE AutoDiffRec & operator= (const AutoDiffRec &) = default; NETGEN_INLINE AutoDiffRec (SCAL aval) : rec(aval), last(0.0) { ; } NETGEN_INLINE AutoDiffRec (SCAL aval, int diffindex) : rec(aval, diffindex), last((diffindex==D-1) ? 1.0 : 0.0) { ; } NETGEN_INLINE AutoDiffRec (SCAL aval, const SCAL * grad) : rec(aval, grad), last(grad[D-1]) { } NETGEN_INLINE AutoDiffRec (const AutoDiffVec & ad) { Value() = ad.Value(); for (int i = 0; i < D; i++) DValue(i) = ad.DValue(i); } NETGEN_INLINE AutoDiffRec & operator= (SCAL aval) { rec = aval; last = 0.0; return *this; } NETGEN_INLINE SCAL Value() const { return rec.Value(); } NETGEN_INLINE SCAL DValue(int i) const { return (i == D-1) ? last : rec.DValue(i); } NETGEN_INLINE SCAL & Value() { return rec.Value(); } NETGEN_INLINE SCAL & DValue(int i) { return (i == D-1) ? last : rec.DValue(i); } NETGEN_INLINE auto Rec() const { return rec; } NETGEN_INLINE auto Last() const { return last; } NETGEN_INLINE auto & Rec() { return rec; } NETGEN_INLINE auto & Last() { return last; } NETGEN_INLINE operator AutoDiffVec () const { AutoDiffVec res(Value()); for (int i = 0; i < D; i++) res.DValue(i) = DValue(i); return res; } }; template ostream & operator<< (ostream & ost, AutoDiffRec ad) { return ost << AutoDiffVec (ad); } template class AutoDiffRec<0,SCAL> { SCAL val; public: NETGEN_INLINE AutoDiffRec () = default; NETGEN_INLINE AutoDiffRec (const AutoDiffRec &) = default; NETGEN_INLINE AutoDiffRec (SCAL _val) : val(_val) { ; } NETGEN_INLINE AutoDiffRec (SCAL _val, SCAL /* _dummylast */) : val(_val) { ; } NETGEN_INLINE AutoDiffRec (SCAL aval, const SCAL * /* grad */) : val(aval) { } NETGEN_INLINE AutoDiffRec & operator= (const AutoDiffRec &) = default; NETGEN_INLINE AutoDiffRec & operator= (SCAL aval) { val = aval; return *this; } NETGEN_INLINE SCAL Value() const { return val; } NETGEN_INLINE SCAL DValue(int /* i */) const { return SCAL(0); } NETGEN_INLINE SCAL & Value() { return val; } // SCAL & DValue(int i) { return val; } NETGEN_INLINE auto Rec() const { return val; } NETGEN_INLINE auto Last() const { return SCAL(0); } NETGEN_INLINE auto & Rec() { return val; } NETGEN_INLINE auto & Last() { return val; } NETGEN_INLINE operator AutoDiffVec<0,SCAL> () const { return AutoDiffVec<0,SCAL>(); } }; template class AutoDiffRec<1,SCAL> { SCAL val; SCAL last; public: NETGEN_INLINE AutoDiffRec () = default; NETGEN_INLINE AutoDiffRec (const AutoDiffRec &) = default; NETGEN_INLINE AutoDiffRec (SCAL _val) : val(_val), last(0.0) { ; } NETGEN_INLINE AutoDiffRec (SCAL _val, SCAL _last) : val(_val), last(_last) { ; } NETGEN_INLINE AutoDiffRec (SCAL aval, int diffindex) : val(aval), last((diffindex==0) ? 1.0 : 0.0) { ; } NETGEN_INLINE AutoDiffRec (SCAL aval, const SCAL * grad) : val(aval), last(grad[0]) { } NETGEN_INLINE AutoDiffRec (const AutoDiffVec<1,SCAL> & ad) { Value() = ad.Value(); DValue(0) = ad.DValue(0); } NETGEN_INLINE AutoDiffRec & operator= (const AutoDiffRec &) = default; NETGEN_INLINE AutoDiffRec & operator= (SCAL aval) { val = aval; last = 0.0; return *this; } NETGEN_INLINE SCAL Value() const { return val; } NETGEN_INLINE SCAL DValue(int /* i */) const { return last; } NETGEN_INLINE SCAL & Value() { return val; } NETGEN_INLINE SCAL & DValue(int /* i */) { return last; } NETGEN_INLINE auto Rec() const { return val; } NETGEN_INLINE auto Last() const { return last; } NETGEN_INLINE auto & Rec() { return val; } NETGEN_INLINE auto & Last() { return last; } NETGEN_INLINE operator AutoDiffVec<1,SCAL> () const { AutoDiffVec<1,SCAL> res(Value()); res.DValue(0) = DValue(0); return res; } }; template ::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator+ (SCAL2 a, AutoDiffRec b) { return AutoDiffRec (a+b.Rec(), b.Last()); } template ::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator+ (AutoDiffRec a, SCAL2 b) { return AutoDiffRec (a.Rec()+b, a.Last()); } template NETGEN_INLINE AutoDiffRec operator+ (AutoDiffRec a, AutoDiffRec b) { return AutoDiffRec (a.Rec()+b.Rec(), a.Last()+b.Last()); } template ::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator- (SCAL2 b, AutoDiffRec a) { return AutoDiffRec (b-a.Rec(), -a.Last()); } template ::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator- (AutoDiffRec a, SCAL2 b) { return AutoDiffRec (a.Rec()-b, a.Last()); } template NETGEN_INLINE AutoDiffRec operator- (AutoDiffRec a, AutoDiffRec b) { return AutoDiffRec (a.Rec()-b.Rec(), a.Last()-b.Last()); } /// minus AutoDiff template NETGEN_INLINE AutoDiffRec operator- (AutoDiffRec a) { return AutoDiffRec (-a.Rec(), -a.Last()); } template NETGEN_INLINE AutoDiffRec operator* (AutoDiffRec a, AutoDiffRec b) { return AutoDiffRec (a.Rec()*b.Rec(), a.Value()*b.Last()+b.Value()*a.Last()); } template ::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator* (AutoDiffRec b, SCAL1 a) { return AutoDiffRec (a*b.Rec(), a*b.Last()); } template ::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator* (SCAL1 a, AutoDiffRec b) { return AutoDiffRec (a*b.Rec(), a*b.Last()); } template NETGEN_INLINE AutoDiffRec & operator+= (AutoDiffRec & a, AutoDiffRec b) { a.Rec() += b.Rec(); a.Last() += b.Last(); return a; } template NETGEN_INLINE AutoDiffRec & operator-= (AutoDiffRec & a, double b) { a.Rec() -= b; return a; } template NETGEN_INLINE AutoDiffRec & operator-= (AutoDiffRec & a, AutoDiffRec b) { a.Rec() -= b.Rec(); a.Last() -= b.Last(); return a; } template NETGEN_INLINE AutoDiffRec & operator*= (AutoDiffRec & a, AutoDiffRec b) { a = a*b; return a; } template NETGEN_INLINE AutoDiffRec & operator*= (AutoDiffRec & b, SCAL2 a) { b.Rec() *= a; b.Last() *= a; return b; } /// Inverse of AutoDiffRec template auto Inv1 (SCAL x) { return 1.0/x; } template NETGEN_INLINE AutoDiffRec Inv1 (AutoDiffRec x) { return AutoDiffRec (Inv1(x.Rec()), (-sqr(1.0/x.Value())) * x.Last()); } /// AutoDiffRec div AutoDiffRec template NETGEN_INLINE AutoDiffRec operator/ (const AutoDiffRec & x, const AutoDiffRec & y) { return x * Inv1 (y); } /// AutoDiffVec div double template::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator/ (const AutoDiffRec & x, SCAL2 y) { return (1.0/y) * x; } /// double div AutoDiffVec template::value, int>::type = 0> NETGEN_INLINE AutoDiffRec operator/ (SCAL2 x, const AutoDiffRec & y) { return x * Inv1(y); } /// template NETGEN_INLINE bool operator== (AutoDiffRec x, SCAL val2) { return x.Value() == val2; } /// template NETGEN_INLINE bool operator!= (AutoDiffRec x, SCAL val2) throw() { return x.Value() != val2; } /// template NETGEN_INLINE bool operator< (AutoDiffRec x, SCAL val2) throw() { return x.Value() < val2; } /// template NETGEN_INLINE bool operator> (AutoDiffRec x, SCAL val2) throw() { return x.Value() > val2; } using std::fabs; template NETGEN_INLINE AutoDiffRec fabs (const AutoDiffRec & x) { auto sign = IfPos(x.Value(), SCAL(1.0), IfPos(-x.Value(), SCAL(-1.0), SCAL(0.0))); return AutoDiffRec (fabs(x.Rec()), sign*x.Last()); // return fabs (AutoDiffVec(x)); /* double abs = fabs (x.Value()); AutoDiffVec res( abs ); if (abs != 0.0) for (int i = 0; i < D; i++) res.DValue(i) = x.Value()*x.DValue(i) / abs; else for (int i = 0; i < D; i++) res.DValue(i) = 0.0; return res; */ } template NETGEN_INLINE auto sqrt (const AutoDiffRec & x) { return AutoDiffRec (sqrt(x.Rec()), (0.5/sqrt(x.Value()))*x.Last()); } template auto log (AutoDiffRec x) { return AutoDiffRec (log(x.Rec()), (1.0/x.Value())*x.Last()); } template auto exp (AutoDiffRec x) { return AutoDiffRec (exp(x.Rec()), exp(x.Value())*x.Last()); } template NETGEN_INLINE AutoDiffRec pow (AutoDiffRec x, AutoDiffRec y ) { return exp(log(x)*y); } template auto sin (AutoDiffRec x) { return AutoDiffRec (sin(x.Rec()), cos(x.Value())*x.Last()); } template auto cos (AutoDiffRec x) { return AutoDiffRec (cos(x.Rec()), -sin(x.Value())*x.Last()); } template auto tan (AutoDiffRec x) { return sin(x) / cos(x); } template auto sinh (AutoDiffRec x) { return AutoDiffRec (sinh(x.Rec()), cosh(x.Value())*x.Last()); } template auto cosh (AutoDiffRec x) { return AutoDiffRec (cosh(x.Rec()), sinh(x.Value())*x.Last()); } template auto erf (AutoDiffRec x) { return AutoDiffRec (erf(x.Rec()), 2. / sqrt(M_PI) * exp(- x.Value() * x.Value())*x.Last()); } template auto floor (AutoDiffRec x) { return AutoDiffRec (floor(x.Rec()), 0.0); } template auto ceil (AutoDiffRec x) { return AutoDiffRec (ceil(x.Rec()), 0.0); } template auto atan (AutoDiffRec x) { return AutoDiffRec (atan(x.Rec()), (1./(1.+x.Value()*x.Value()))*x.Last()); } template auto atan2 (AutoDiffRec x, AutoDiffRec y) { return AutoDiffRec (atan2(x.Rec(), y.Rec()), (1./(x.Value()*x.Value()+y.Value()*y.Value()))*(x.Value()*y.Last()-y.Value()*x.Last())); } template auto acos (AutoDiffRec x) { return AutoDiffRec (acos(x.Rec()), (-1./sqrt(1.-x.Value()*x.Value()))*x.Last()); } template auto asin (AutoDiffRec x) { return AutoDiffRec (asin(x.Rec()), (1./sqrt(1.-x.Value()*x.Value()))*x.Last()); } template auto IfPos (AutoDiffRec a, TB b, TC c) // -> decltype(IfPos (a.Value(), b, c)) { return IfPos (a.Value(), b, c); } template NETGEN_INLINE AutoDiffRec IfPos (SCAL /* SIMD */ a, AutoDiffRec b, AutoDiffRec c) { /* AutoDiffRec res; res.Value() = IfPos (a, b.Value(), c.Value()); for (int j = 0; j < D; j++) res.DValue(j) = IfPos (a, b.DValue(j), c.DValue(j)); return res; */ return AutoDiffRec (IfPos(a, b.Rec(), c.Rec()), IfPos(a, b.Last(), c.Last())); } template NETGEN_INLINE AutoDiffRec IfPos (SCAL /* SIMD */ a, AutoDiffRec b, TC c) { return IfPos (a, b, AutoDiffRec (c)); } template using AutoDiff = AutoDiffRec; } namespace ngbla { template struct is_scalar_type; template struct is_scalar_type> { static constexpr bool value = true; }; // not meaningful for AutoDiff, since this is // not (complex) differentiable anyway template inline auto L2Norm2 (const ngcore::AutoDiff & x) { return x*x; } template inline auto L2Norm (const ngcore::AutoDiff & x) throw() { return IfPos(x.Value(), x, -x); } template NETGEN_INLINE auto Conj (const ngcore::AutoDiff & a) { ngcore::AutoDiff b; b.Value() = conj(a.Value()); for(int i=0;i