Stan Math Library  2.12.0
reverse mode automatic differentiation
log_mix.hpp
Go to the documentation of this file.
1 #ifndef STAN_MATH_FWD_SCAL_FUN_LOG_MIX_HPP
2 #define STAN_MATH_FWD_SCAL_FUN_LOG_MIX_HPP
3 
4 #include <stan/math/fwd/core.hpp>
7 #include <boost/math/tools/promotion.hpp>
8 #include <cmath>
9 
10 namespace stan {
11  namespace math {
12 
13  /* Returns an array of size N with partials of log_mix wrt to its
14  * parameters instantiated as fvar<T>
15  *
16  * @tparam T_theta theta scalar type
17  * @tparam T_lambda1 lambda_1 scalar type
18  * @tparam T_lambda2 lambda_2 scalar type
19  *
20  * @param[in] N output array size
21  * @param[in] theta_d mixing proportion theta
22  * @param[in] lambda1_d log_density with mixing proportion theta
23  * @param[in] lambda2_d log_density with mixing proportion 1.0 - theta
24  * @param[out] partials_array array of partials derivatives
25  */
26  template <typename T_theta, typename T_lambda1, typename T_lambda2, int N>
27  inline void
28  log_mix_partial_helper(const T_theta& theta,
29  const T_lambda1& lambda1,
30  const T_lambda2& lambda2,
31  typename
32  boost::math::tools::promote_args<
33  T_theta, T_lambda1, T_lambda2>::type
34  (&partials_array)[N]) {
35  using std::exp;
36  using boost::is_same;
37  using boost::math::tools::promote_args;
38  typedef typename promote_args<T_theta, T_lambda1, T_lambda2>::type
39  partial_return_type;
40 
41  typename promote_args<T_lambda1, T_lambda2>::type lam2_m_lam1
42  = lambda2 - lambda1;
43  typename promote_args<T_lambda1, T_lambda2>::type exp_lam2_m_lam1
44  = exp(lam2_m_lam1);
45  typename promote_args<T_lambda1, T_lambda2>::type one_m_exp_lam2_m_lam1
46  = 1.0 - exp_lam2_m_lam1;
47  typename promote_args<double, T_theta>::type one_m_t = 1.0 - theta;
48  partial_return_type one_m_t_prod_exp_lam2_m_lam1
49  = one_m_t * exp_lam2_m_lam1;
50  partial_return_type t_plus_one_m_t_prod_exp_lam2_m_lam1
51  = theta + one_m_t_prod_exp_lam2_m_lam1;
52  partial_return_type one_d_t_plus_one_m_t_prod_exp_lam2_m_lam1
53  = 1.0 / t_plus_one_m_t_prod_exp_lam2_m_lam1;
54 
55  unsigned int offset = 0;
56  if (is_same<T_theta, partial_return_type>::value) {
57  partials_array[offset]
58  = one_m_exp_lam2_m_lam1
59  * one_d_t_plus_one_m_t_prod_exp_lam2_m_lam1;
60  ++offset;
61  }
62  if (is_same<T_lambda1, partial_return_type>::value) {
63  partials_array[offset]
64  = theta * one_d_t_plus_one_m_t_prod_exp_lam2_m_lam1;
65  ++offset;
66  }
67  if (is_same<T_lambda2, partial_return_type>::value) {
68  partials_array[offset]
69  = one_m_t_prod_exp_lam2_m_lam1
70  * one_d_t_plus_one_m_t_prod_exp_lam2_m_lam1;
71  }
72  }
73 
113  template <typename T>
114  inline
115  fvar<T>
116  log_mix(const fvar<T>& theta, const fvar<T>& lambda1,
117  const fvar<T>& lambda2) {
118  if (lambda1.val_ > lambda2.val_) {
119  fvar<T> partial_deriv_array[3];
120  log_mix_partial_helper(theta, lambda1, lambda2, partial_deriv_array);
121  return fvar<T>(log_mix(theta.val_, lambda1.val_, lambda2.val_),
122  theta.d_ * value_of(partial_deriv_array[0])
123  + lambda1.d_ * value_of(partial_deriv_array[1])
124  + lambda2.d_ * value_of(partial_deriv_array[2]));
125  } else {
126  fvar<T> partial_deriv_array[3];
127  log_mix_partial_helper(1.0 - theta, lambda2, lambda1,
128  partial_deriv_array);
129  return fvar<T>(log_mix(theta.val_, lambda1.val_, lambda2.val_),
130  -theta.d_ * value_of(partial_deriv_array[0])
131  + lambda1.d_ * value_of(partial_deriv_array[2])
132  + lambda2.d_ * value_of(partial_deriv_array[1]));
133  }
134  }
135 
136  template <typename T>
137  inline
138  fvar<T>
139  log_mix(const fvar<T>& theta, const fvar<T>& lambda1,
140  const double lambda2) {
141  if (lambda1.val_ > lambda2) {
142  fvar<T> partial_deriv_array[2];
143  log_mix_partial_helper(theta, lambda1, lambda2,
144  partial_deriv_array);
145  return fvar<T>(log_mix(theta.val_, lambda1.val_, lambda2),
146  theta.d_ * value_of(partial_deriv_array[0])
147  + lambda1.d_ * value_of(partial_deriv_array[1]));
148  } else {
149  fvar<T> partial_deriv_array[2];
150  log_mix_partial_helper(1.0 - theta, lambda2, lambda1,
151  partial_deriv_array);
152  return fvar<T>(log_mix(theta.val_, lambda1.val_, lambda2),
153  -theta.d_ * value_of(partial_deriv_array[0])
154  + lambda1.d_ * value_of(partial_deriv_array[1]));
155  }
156  }
157 
158  template<typename T>
159  inline
160  fvar<T>
161  log_mix(const fvar<T>& theta, const double lambda1,
162  const fvar<T>& lambda2) {
163  if (lambda1 > lambda2.val_) {
164  fvar<T> partial_deriv_array[2];
165  log_mix_partial_helper(theta, lambda1, lambda2,
166  partial_deriv_array);
167  return fvar<T>(log_mix(theta.val_, lambda1, lambda2.val_),
168  theta.d_ * value_of(partial_deriv_array[0])
169  + lambda2.d_ * value_of(partial_deriv_array[1]));
170  } else {
171  fvar<T> partial_deriv_array[2];
172  log_mix_partial_helper(1.0 - theta, lambda2, lambda1,
173  partial_deriv_array);
174  return fvar<T>(log_mix(theta.val_, lambda1, lambda2.val_),
175  -theta.d_ * value_of(partial_deriv_array[0])
176  + lambda2.d_ * value_of(partial_deriv_array[1]));
177  }
178  }
179 
180  template<typename T>
181  inline
182  fvar<T>
183  log_mix(const double theta, const fvar<T>& lambda1,
184  const fvar<T>& lambda2) {
185  if (lambda1.val_ > lambda2.val_) {
186  fvar<T> partial_deriv_array[2];
187  log_mix_partial_helper(theta, lambda1, lambda2, partial_deriv_array);
188  return fvar<T>(log_mix(theta, lambda1.val_, lambda2.val_),
189  lambda1.d_ * value_of(partial_deriv_array[0])
190  + lambda2.d_ * value_of(partial_deriv_array[1]));
191  } else {
192  fvar<T> partial_deriv_array[2];
193  log_mix_partial_helper(1.0 - theta, lambda2, lambda1,
194  partial_deriv_array);
195  return fvar<T>(log_mix(theta, lambda1.val_, lambda2.val_),
196  lambda1.d_ * value_of(partial_deriv_array[1])
197  + lambda2.d_ * value_of(partial_deriv_array[0]));
198  }
199  }
200 
201  template<typename T>
202  inline
203  fvar<T>
204  log_mix(const fvar<T>& theta, const double lambda1, const double lambda2) {
205  if (lambda1 > lambda2) {
206  fvar<T> partial_deriv_array[1];
207  log_mix_partial_helper(theta, lambda1, lambda2, partial_deriv_array);
208  return fvar<T>(log_mix(theta.val_, lambda1, lambda2),
209  theta.d_ * value_of(partial_deriv_array[0]));
210  } else {
211  fvar<T> partial_deriv_array[1];
212  log_mix_partial_helper(1.0 - theta, lambda2, lambda1,
213  partial_deriv_array);
214  return fvar<T>(log_mix(theta.val_, lambda1, lambda2),
215  -theta.d_ * value_of(partial_deriv_array[0]));
216  }
217  }
218 
219  template<typename T>
220  inline
221  fvar<T>
222  log_mix(const double theta, const fvar<T>& lambda1, const double lambda2) {
223  if (lambda1.val_ > lambda2) {
224  fvar<T> partial_deriv_array[1];
225  log_mix_partial_helper(theta, lambda1, lambda2, partial_deriv_array);
226  return fvar<T>(log_mix(theta, lambda1.val_, lambda2),
227  lambda1.d_ * value_of(partial_deriv_array[0]));
228  } else {
229  fvar<T> partial_deriv_array[1];
230  log_mix_partial_helper(1.0 - theta, lambda2, lambda1,
231  partial_deriv_array);
232  return fvar<T>(log_mix(theta, lambda1.val_, lambda2),
233  lambda1.d_ * value_of(partial_deriv_array[0]));
234  }
235  }
236 
237  template<typename T>
238  inline
239  fvar<T>
240  log_mix(const double theta, const double lambda1, const fvar<T>& lambda2) {
241  if (lambda1 > lambda2.val_) {
242  fvar<T> partial_deriv_array[1];
243  log_mix_partial_helper(theta, lambda1, lambda2, partial_deriv_array);
244  return fvar<T>(log_mix(theta, lambda1, lambda2.val_),
245  lambda2.d_ * value_of(partial_deriv_array[0]));
246  } else {
247  fvar<T> partial_deriv_array[1];
248  log_mix_partial_helper(1.0 - theta, lambda2, lambda1,
249  partial_deriv_array);
250  return fvar<T>(log_mix(theta, lambda1, lambda2.val_),
251  lambda2.d_ * value_of(partial_deriv_array[0]));
252  }
253  }
254  }
255 }
256 #endif
T value_of(const fvar< T > &v)
Return the value of the specified variable.
Definition: value_of.hpp:16
fvar< T > exp(const fvar< T > &x)
Definition: exp.hpp:10
void log_mix_partial_helper(const T_theta &theta, const T_lambda1 &lambda1, const T_lambda2 &lambda2, typename boost::math::tools::promote_args< T_theta, T_lambda1, T_lambda2 >::type(&partials_array)[N])
Definition: log_mix.hpp:28
fvar< T > log_mix(const fvar< T > &theta, const fvar< T > &lambda1, const fvar< T > &lambda2)
Return the log mixture density with specified mixing proportion and log densities and its derivative ...
Definition: log_mix.hpp:116

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