TMB Documentation  v1.9.11
tiny_ad.hpp
1 // Copyright (C) 2016 Kasper Kristensen
2 // License: GPL-2
3 
4 #ifndef TINY_AD_H
5 #define TINY_AD_H
6 
7 /* Standalone ? */
8 #ifndef R_RCONFIG_H
9 #include <cmath>
10 #include <iostream>
11 #define CSKIP(x) x
12 #endif
13 
14 /* Select the vector class to use (Default: tiny_vec) */
15 #if defined(TINY_AD_USE_STD_VALARRAY)
16 #include "tiny_valarray.hpp"
17 #define TINY_VECTOR(type,size) tiny_vector<type, size>
18 #elif defined(TINY_AD_USE_EIGEN_VEC)
19 #include <Eigen/Dense>
20 #define TINY_VECTOR(type,size) Eigen::Array<type, size, 1>
21 #else
22 #include "tiny_vec.hpp"
23 #define TINY_VECTOR(type,size) tiny_vec<type, size>
24 #endif
25 
26 namespace tiny_ad {
27  template<class Type, class Vector>
28  struct ad {
29  Type value;
30  Vector deriv;
31  ad(){}
32  ad(Type v, Vector d){value = v; deriv = d;}
33  ad(double v) {value = v; deriv.setZero();}
34  ad operator+ (const ad &other) const{
35  return ad(value + other.value,
36  deriv + other.deriv);
37  }
38  ad operator+ () const{
39  return *this;
40  }
41  ad operator- (const ad &other) const{
42  return ad(value - other.value,
43  deriv - other.deriv);
44  }
45  ad operator- () const{
46  return ad(-value, -deriv);
47  }
48  ad operator* (const ad &other) const{
49  return ad(value * other.value,
50  value * other.deriv +
51  deriv * other.value);
52  }
53  ad operator/ (const ad &other) const{
54  Type res = value / other.value;
55  return ad(res,
56  (deriv - res * other.deriv) /
57  other.value );
58  }
59  /* Comparison operators */
60 #define COMPARISON_OPERATOR(OP) \
61  template<class other> \
62  bool operator OP (const other &x) const{ \
63  return (value OP x); \
64  }
65  COMPARISON_OPERATOR(<)
66  COMPARISON_OPERATOR(>)
67  COMPARISON_OPERATOR(<=)
68  COMPARISON_OPERATOR(>=)
69  COMPARISON_OPERATOR(==)
70  COMPARISON_OPERATOR(!=)
71 #undef COMPARISON_OPERATOR
72  /* Combine ad with other types (constants) */
73  ad operator+ (const double &x) const{
74  return ad(value + x, deriv);
75  }
76  ad operator- (const double &x) const{
77  return ad(value - x, deriv);
78  }
79  ad operator* (const double &x) const{
80  return ad(value * x, deriv * x);
81  }
82  ad operator/ (const double &x) const{
83  return ad(value / x, deriv / x);
84  }
85  /* Note: 'this' and 'other' may point to the same object */
86  ad& operator+=(const ad &other){
87  value += other.value;
88  deriv += other.deriv;
89  return *this;
90  }
91  ad& operator-=(const ad &other){
92  value -= other.value;
93  deriv -= other.deriv;
94  return *this;
95  }
96  ad& operator*=(const ad &other){
97  if (this != &other) {
98  deriv *= other.value;
99  deriv += other.deriv * value;
100  value *= other.value;
101  } else {
102  deriv *= value * 2.;
103  value *= value;
104  }
105  return *this;
106  }
107  ad& operator/=(const ad &other){
108  value /= other.value;
109  deriv -= other.deriv * value;
110  deriv /= other.value;
111  return *this;
112  }
113  };
114  /* Binary operators where a constant is first argument */
115  template<class T, class V>
116  ad<T, V> operator+ (const double &x, const ad<T, V> &y) {
117  return y + x;
118  }
119  template<class T, class V>
120  ad<T, V> operator- (const double &x, const ad<T, V> &y) {
121  return -(y - x);
122  }
123  template<class T, class V>
124  ad<T, V> operator* (const double &x, const ad<T, V> &y) {
125  return y * x;
126  }
127  template<class T, class V>
128  ad<T, V> operator/ (const double &x, const ad<T, V> &y) {
129  T value = x / y.value;
130  return ad<T, V>(value, T(-value / y.value) * y.deriv);
131  }
132  /* Unary operators with trivial derivatives */
133 #define UNARY_MATH_ZERO_DERIV(F) \
134  template<class T, class V> \
135  double F (const ad<T, V> &x){ \
136  return F(x.value); \
137  }
138  using ::floor; using ::ceil;
139  using ::trunc; using ::round;
140  UNARY_MATH_ZERO_DERIV(floor)
141  UNARY_MATH_ZERO_DERIV(ceil)
142  UNARY_MATH_ZERO_DERIV(trunc)
143  UNARY_MATH_ZERO_DERIV(round)
144  template<class T>
145  double sign(const T &x){return (x > 0) - (x < 0);}
146  bool isfinite(const double &x)CSKIP( {return std::isfinite(x);} )
147  template<class T, class V>
148  bool isfinite(const ad<T, V> &x){return isfinite(x.value);}
149 #undef UNARY_MATH_ZERO_DERIV
150  /* Unary operators with non-trivial derivatives */
151 #define UNARY_MATH_DERIVATIVE(F,DF) \
152  template<class T, class V> \
153  ad<T, V> F (const ad<T, V> &x){ \
154  return ad<T, V>(F (x.value), \
155  T(DF(x.value)) * x.deriv); \
156  }
157  using ::exp; using ::log;
158  using ::sin; using ::cos; using ::tan;
159  using ::sinh; using ::cosh; using ::tanh;
160  using ::sqrt; using ::fabs;
161  template<class T> T D_tan(const T &x) {
162  T y = cos(x); return 1. / (y * y);
163  }
164  template<class T> T D_tanh(const T &x) {
165  T y = cosh(x); return 1. / (y * y);
166  }
167  UNARY_MATH_DERIVATIVE(exp, exp)
168  UNARY_MATH_DERIVATIVE(log, 1.0/)
169  UNARY_MATH_DERIVATIVE(sin, cos)
170  UNARY_MATH_DERIVATIVE(cos, -sin)
171  UNARY_MATH_DERIVATIVE(tan, D_tan)
172  UNARY_MATH_DERIVATIVE(sinh, cosh)
173  UNARY_MATH_DERIVATIVE(cosh, sinh)
174  UNARY_MATH_DERIVATIVE(tanh, D_tanh)
175  UNARY_MATH_DERIVATIVE(sqrt, 0.5/sqrt)
176  UNARY_MATH_DERIVATIVE(fabs, sign)
177  using ::expm1; using ::log1p;
178  UNARY_MATH_DERIVATIVE(expm1, exp)
179  template<class T> T D_log1p(const T &x) {return 1. / (x + 1.);}
180  UNARY_MATH_DERIVATIVE(log1p, D_log1p)
181  /* asin, acos, atan */
182  using ::asin; using ::acos; using ::atan;
183  template<class T> T D_asin(const T &x) {
184  return 1. / sqrt(1. - x * x);
185  }
186  template<class T> T D_acos(const T &x) {
187  return -1. / sqrt(1. - x * x);
188  }
189  template<class T> T D_atan(const T &x) {
190  return 1. / (1. + x * x);
191  }
192  UNARY_MATH_DERIVATIVE(asin, D_asin)
193  UNARY_MATH_DERIVATIVE(acos, D_acos)
194  UNARY_MATH_DERIVATIVE(atan, D_atan)
195 #undef UNARY_MATH_DERIVATIVE
196  /* A few more ... */
197  template<class T, class V>
198  ad<T, V> pow (const ad<T, V> &x, const ad<T, V> &y){
199  return exp(y * log(x));
200  }
201  using ::pow;
202  template<class T, class V>
203  ad<T, V> pow (const ad<T, V> &x, const double &y){
204  return ad<T, V> (pow(x.value, y), // Note: x.value could be 0
205  T( y * pow(x.value, y - 1.) ) * x.deriv);
206  }
207  /* Comparison operators where a constant is first argument */
208 #define COMPARISON_OPERATOR_FLIP(OP1, OP2) \
209  template<class T, class V> \
210  bool operator OP1 (const double &x, const ad<T, V> &y) { \
211  return y OP2 x; \
212  }
213  COMPARISON_OPERATOR_FLIP(<,>)
214  COMPARISON_OPERATOR_FLIP(<=,>=)
215  COMPARISON_OPERATOR_FLIP(>,<)
216  COMPARISON_OPERATOR_FLIP(>=,<=)
217  COMPARISON_OPERATOR_FLIP(==,==)
218  COMPARISON_OPERATOR_FLIP(!=,!=)
219 #undef COMPARISON_OPERATOR_FLIP
220  /* Utility: Return the value of a tiny_ad type */
221  double asDouble(double x) CSKIP( {return x;} )
222  template<class T, class V>
223  double asDouble (const ad<T, V> &x){
224  return asDouble(x.value);
225  }
226  /* Utility: Return the max absolute value of all members of a
227  tiny_ad type */
228  double max_fabs(double x) CSKIP( {return fabs(x);} )
229  template<class T, class V>
230  double max_fabs (const ad<T, V> &x){
231  double ans = max_fabs(x.value);
232  for(int i=0; i<x.deriv.size(); i++) {
233  double tmp = max_fabs(x.deriv[i]);
234  ans = (tmp > ans ? tmp : ans);
235  }
236  return ans;
237  }
238  /* R-specific derivatives (rely on Rmath)*/
239 #ifdef R_RCONFIG_H
240  extern "C" {
241  /* See 'R-API: entry points to C-code' (Writing R-extensions) */
242  double Rf_lgammafn(double);
243  double Rf_psigamma(double, double);
244  }
245  template<int deriv>
246  double lgamma(const double &x) {
247  return Rf_psigamma(x, deriv-1);
248  }
249  template<>
250  double lgamma<0>(const double &x) CSKIP( {return Rf_lgammafn(x);} )
251  double lgamma(const double &x) CSKIP( {return lgamma<0>(x);} )
252  template<int deriv, class T, class V>
253  ad<T, V> lgamma (const ad<T, V> &x){
254  return ad<T, V> (lgamma< deriv >(x.value),
255  T(lgamma< deriv + 1 >(x.value)) * x.deriv);
256  }
257  template<class T, class V>
258  ad<T, V> lgamma (const ad<T, V> &x){
259  return lgamma<0>(x);
260  }
261 #endif
262  /* Print method */
263  template<class T, class V>
264  std::ostream &operator<<(std::ostream &os, const ad<T, V> &x) {
265  os << "{";
266  os << " value=" << x.value;
267  os << " deriv=" << x.deriv;
268  os << "}";
269  return os;
270  }
271 
272  /* Interface to higher order derivatives. Example:
273 
274  typedef tiny_ad::variable<3, 2> Float; // Track 3rd order derivs wrt. 2 parameters
275  Float a (1.23, 0); // Let a = 1.23 have parameter index 0
276  Float b (2.34, 1); // Let b = 2.34 have parameter index 1
277  Float y = sin(a + b); // Run the algorithm
278  y.getDeriv(); // Get all 3rd order derivatives
279  */
280 #define VARIABLE(order, nvar, scalartype) variable<order, nvar, scalartype>
281  template<int order, int nvar, class Double=double>
282  struct variable : ad< VARIABLE(order-1, nvar, Double),
283  TINY_VECTOR( VARIABLE(order-1, nvar, Double) , nvar) > {
284  typedef ad< VARIABLE(order-1, nvar, Double),
285  TINY_VECTOR(VARIABLE(order-1, nvar, Double), nvar) > Base;
286  typedef variable<order-1, nvar, Double> Type;
287  static const int result_size = nvar * Type::result_size;
288 #define ___COMMON_CTORS___ \
289  variable() {} \
290  variable(Base x) : Base(x) {} \
291  variable(double x) : Base(x) {} \
292  variable(double x, int id) : Base(x) { \
293  setid(id); \
294  } \
295  template<int T1, int T2, class T3> \
296  variable(variable<T1,T2,T3> x) { \
297  Base::value = x; Base::deriv.setZero(); \
298  } \
299  template<class T1, class T2> \
300  variable(ad<T1,T2> x) { \
301  Base::value = x; Base::deriv.setZero(); \
302  } \
303  template<int T1, int T2, class T3> \
304  variable(variable<T1,T2,T3> x, int id) { \
305  Base::value = x; Base::deriv.setZero(); \
306  setid(id); \
307  } \
308  template<class T1, class T2> \
309  variable(ad<T1,T2> x, int id) { \
310  Base::value = x; Base::deriv.setZero(); \
311  setid(id); \
312  }
313  ___COMMON_CTORS___
314  void setid(int i0, int count = 0){
315  this->value.setid(i0, count);
316  this->deriv[i0].setid(i0, count + 1);
317  }
318  TINY_VECTOR(Double, result_size) getDeriv(){
319  TINY_VECTOR(Double, result_size) ans;
320  int stride = result_size / nvar;
321  for(int i=0; i<nvar; i++)
322  ans.segment(i * stride, stride) = this->deriv[i].getDeriv();
323  return ans;
324  }
325  };
326 #undef VARIABLE
327  template<int nvar, class Double>
328  struct variable<1, nvar, Double> : ad<Double, TINY_VECTOR(Double,nvar) >{
329  typedef ad<Double, TINY_VECTOR(Double,nvar) > Base;
330  static const int result_size = nvar;
331  ___COMMON_CTORS___
332  void setid(int i0, int count = 0){
333  if(count == 0)
334  this->deriv[i0] = 1.0;
335  if(count == 1)
336  this->value = 1.0;
337  }
338  TINY_VECTOR(Double, nvar) getDeriv(){
339  return this->deriv;
340  }
341  };
342 #undef ___COMMON_CTORS___
343 #undef TINY_VECTOR
344 } // End namespace tiny_ad
345 
346 #endif
vector< Type > operator*(matrix< Type > A, vector< Type > x)
Definition: convenience.hpp:42
Type lgamma(Type x)
Logarithm of gamma function (following R argument convention).
Definition: lgamma.hpp:12
std::vector< size_t > order(std::vector< T > x)
Get permutation that sorts a vector.
License: GPL v2