Stan Math Library  2.8.0
reverse mode automatic differentiation
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Groups
fma.hpp
Go to the documentation of this file.
1 #ifndef STAN_MATH_REV_SCAL_FUN_FMA_HPP
2 #define STAN_MATH_REV_SCAL_FUN_FMA_HPP
3 
4 #include <math.h>
5 #include <stan/math/rev/core.hpp>
7 #include <boost/math/special_functions/fpclassify.hpp>
9 #include <valarray>
10 #include <limits>
11 
12 #ifdef _MSC_VER
13 template<typename T>
14 T fma(T x, T y, T z) {
15  return x*y+z;
16 }
17 #endif
18 
19 namespace stan {
20  namespace math {
21 
22  namespace {
23  class fma_vvv_vari : public op_vvv_vari {
24  public:
25  fma_vvv_vari(vari* avi, vari* bvi, vari* cvi) :
26  op_vvv_vari(::fma(avi->val_, bvi->val_, cvi->val_),
27  avi, bvi, cvi) {
28  }
29  void chain() {
30  if (unlikely(boost::math::isnan(avi_->val_)
31  || boost::math::isnan(bvi_->val_)
32  || boost::math::isnan(cvi_->val_))) {
33  avi_->adj_ = std::numeric_limits<double>::quiet_NaN();
34  bvi_->adj_ = std::numeric_limits<double>::quiet_NaN();
35  cvi_->adj_ = std::numeric_limits<double>::quiet_NaN();
36  } else {
37  avi_->adj_ += adj_ * bvi_->val_;
38  bvi_->adj_ += adj_ * avi_->val_;
39  cvi_->adj_ += adj_;
40  }
41  }
42  };
43 
44  class fma_vvd_vari : public op_vvd_vari {
45  public:
46  fma_vvd_vari(vari* avi, vari* bvi, double c) :
47  op_vvd_vari(::fma(avi->val_, bvi->val_, c),
48  avi, bvi, c) {
49  }
50  void chain() {
51  if (unlikely(boost::math::isnan(avi_->val_)
52  || boost::math::isnan(bvi_->val_)
53  || boost::math::isnan(cd_))) {
54  avi_->adj_ = std::numeric_limits<double>::quiet_NaN();
55  bvi_->adj_ = std::numeric_limits<double>::quiet_NaN();
56  } else {
57  avi_->adj_ += adj_ * bvi_->val_;
58  bvi_->adj_ += adj_ * avi_->val_;
59  }
60  }
61  };
62 
63  class fma_vdv_vari : public op_vdv_vari {
64  public:
65  fma_vdv_vari(vari* avi, double b, vari* cvi) :
66  op_vdv_vari(::fma(avi->val_ , b, cvi->val_),
67  avi, b, cvi) {
68  }
69  void chain() {
70  if (unlikely(boost::math::isnan(avi_->val_)
71  || boost::math::isnan(cvi_->val_)
72  || boost::math::isnan(bd_))) {
73  avi_->adj_ = std::numeric_limits<double>::quiet_NaN();
74  cvi_->adj_ = std::numeric_limits<double>::quiet_NaN();
75  } else {
76  avi_->adj_ += adj_ * bd_;
77  cvi_->adj_ += adj_;
78  }
79  }
80  };
81 
82  class fma_vdd_vari : public op_vdd_vari {
83  public:
84  fma_vdd_vari(vari* avi, double b, double c) :
85  op_vdd_vari(::fma(avi->val_ , b, c),
86  avi, b, c) {
87  }
88  void chain() {
89  if (unlikely(boost::math::isnan(avi_->val_)
90  || boost::math::isnan(bd_)
91  || boost::math::isnan(cd_)))
92  avi_->adj_ = std::numeric_limits<double>::quiet_NaN();
93  else
94  avi_->adj_ += adj_ * bd_;
95  }
96  };
97 
98  class fma_ddv_vari : public op_ddv_vari {
99  public:
100  fma_ddv_vari(double a, double b, vari* cvi) :
101  op_ddv_vari(::fma(a, b, cvi->val_),
102  a, b, cvi) {
103  }
104  void chain() {
105  if (unlikely(boost::math::isnan(cvi_->val_)
106  || boost::math::isnan(ad_)
107  || boost::math::isnan(bd_)))
108  cvi_->adj_ = std::numeric_limits<double>::quiet_NaN();
109  else
110  cvi_->adj_ += adj_;
111  }
112  };
113  }
114 
136  inline var fma(const stan::math::var& a,
137  const stan::math::var& b,
138  const stan::math::var& c) {
139  return var(new fma_vvv_vari(a.vi_, b.vi_, c.vi_));
140  }
141 
161  inline var fma(const stan::math::var& a,
162  const stan::math::var& b,
163  const double& c) {
164  return var(new fma_vvd_vari(a.vi_, b.vi_, c));
165  }
166 
186  inline var fma(const stan::math::var& a,
187  const double& b,
188  const stan::math::var& c) {
189  return var(new fma_vdv_vari(a.vi_, b, c.vi_));
190  }
191 
209  inline var fma(const stan::math::var& a,
210  const double& b,
211  const double& c) {
212  return var(new fma_vdd_vari(a.vi_, b, c));
213  }
214 
232  inline var fma(const double& a,
233  const stan::math::var& b,
234  const double& c) {
235  return var(new fma_vdd_vari(b.vi_, a, c));
236  }
237 
255  inline var fma(const double& a,
256  const double& b,
257  const stan::math::var& c) {
258  return var(new fma_ddv_vari(a, b, c.vi_));
259  }
260 
280  inline var fma(const double& a,
281  const stan::math::var& b,
282  const stan::math::var& c) {
283  return var(new fma_vdv_vari(b.vi_, a, c.vi_)); // a-b symmetry
284  }
285 
286  }
287 }
288 #endif
Independent (input) and dependent (output) variables for gradients.
Definition: var.hpp:32
bool isnan(const stan::math::var &v)
Checks if the given number is NaN.
Definition: boost_isnan.hpp:22
#define unlikely(x)
Definition: likely.hpp:9
fvar< typename stan::return_type< T1, T2, T3 >::type > fma(const fvar< T1 > &x1, const fvar< T2 > &x2, const fvar< T3 > &x3)
The fused multiply-add operation (C99).
Definition: fma.hpp:61
vari * vi_
Pointer to the implementation of this variable.
Definition: var.hpp:44
var fma(const double &a, const stan::math::var &b, const stan::math::var &c)
The fused multiply-add function for a value and two variables (C99).
Definition: fma.hpp:280

     [ Stan Home Page ] © 2011–2015, Stan Development Team.