Stan Math Library  2.20.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/meta.hpp>
5 #include <stan/math/fwd/core.hpp>
8 #include <boost/math/tools/promotion.hpp>
9 #include <cmath>
10 #include <type_traits>
11 
12 namespace stan {
13 namespace math {
14 
15 /* Returns an array of size N with partials of log_mix wrt to its
16  * parameters instantiated as fvar<T>
17  *
18  * @tparam T_theta theta scalar type
19  * @tparam T_lambda1 lambda_1 scalar type
20  * @tparam T_lambda2 lambda_2 scalar type
21  *
22  * @param[in] N output array size
23  * @param[in] theta_d mixing proportion theta
24  * @param[in] lambda1_d log_density with mixing proportion theta
25  * @param[in] lambda2_d log_density with mixing proportion 1.0 - theta
26  * @param[out] partials_array array of partials derivatives
27  */
28 template <typename T_theta, typename T_lambda1, typename T_lambda2, int N>
30  const T_theta& theta, const T_lambda1& lambda1, const T_lambda2& lambda2,
31  typename boost::math::tools::promote_args<
32  T_theta, T_lambda1, T_lambda2>::type (&partials_array)[N]) {
33  using boost::math::tools::promote_args;
34  using std::exp;
35  typedef typename promote_args<T_theta, T_lambda1, T_lambda2>::type
36  partial_return_type;
37 
38  typename promote_args<T_lambda1, T_lambda2>::type lam2_m_lam1
39  = lambda2 - lambda1;
40  typename promote_args<T_lambda1, T_lambda2>::type exp_lam2_m_lam1
41  = exp(lam2_m_lam1);
42  typename promote_args<T_lambda1, T_lambda2>::type one_m_exp_lam2_m_lam1
43  = 1.0 - exp_lam2_m_lam1;
44  typename promote_args<double, T_theta>::type one_m_t = 1.0 - theta;
45  partial_return_type one_m_t_prod_exp_lam2_m_lam1 = one_m_t * exp_lam2_m_lam1;
46  partial_return_type t_plus_one_m_t_prod_exp_lam2_m_lam1
47  = theta + one_m_t_prod_exp_lam2_m_lam1;
48  partial_return_type one_d_t_plus_one_m_t_prod_exp_lam2_m_lam1
49  = 1.0 / t_plus_one_m_t_prod_exp_lam2_m_lam1;
50 
51  unsigned int offset = 0;
52  if (std::is_same<T_theta, partial_return_type>::value) {
53  partials_array[offset]
54  = one_m_exp_lam2_m_lam1 * one_d_t_plus_one_m_t_prod_exp_lam2_m_lam1;
55  ++offset;
56  }
57  if (std::is_same<T_lambda1, partial_return_type>::value) {
58  partials_array[offset] = theta * one_d_t_plus_one_m_t_prod_exp_lam2_m_lam1;
59  ++offset;
60  }
61  if (std::is_same<T_lambda2, partial_return_type>::value) {
62  partials_array[offset] = one_m_t_prod_exp_lam2_m_lam1
63  * one_d_t_plus_one_m_t_prod_exp_lam2_m_lam1;
64  }
65 }
66 
106 template <typename T>
107 inline fvar<T> log_mix(const fvar<T>& theta, const fvar<T>& lambda1,
108  const fvar<T>& lambda2) {
109  if (lambda1.val_ > lambda2.val_) {
110  fvar<T> partial_deriv_array[3];
111  log_mix_partial_helper(theta, lambda1, lambda2, partial_deriv_array);
112  return fvar<T>(log_mix(theta.val_, lambda1.val_, lambda2.val_),
113  theta.d_ * value_of(partial_deriv_array[0])
114  + lambda1.d_ * value_of(partial_deriv_array[1])
115  + lambda2.d_ * value_of(partial_deriv_array[2]));
116  } else {
117  fvar<T> partial_deriv_array[3];
118  log_mix_partial_helper(1.0 - theta, lambda2, lambda1, partial_deriv_array);
119  return fvar<T>(log_mix(theta.val_, lambda1.val_, lambda2.val_),
120  -theta.d_ * value_of(partial_deriv_array[0])
121  + lambda1.d_ * value_of(partial_deriv_array[2])
122  + lambda2.d_ * value_of(partial_deriv_array[1]));
123  }
124 }
125 
126 template <typename T>
127 inline fvar<T> log_mix(const fvar<T>& theta, const fvar<T>& lambda1,
128  double lambda2) {
129  if (lambda1.val_ > lambda2) {
130  fvar<T> partial_deriv_array[2];
131  log_mix_partial_helper(theta, lambda1, lambda2, partial_deriv_array);
132  return fvar<T>(log_mix(theta.val_, lambda1.val_, lambda2),
133  theta.d_ * value_of(partial_deriv_array[0])
134  + lambda1.d_ * value_of(partial_deriv_array[1]));
135  } else {
136  fvar<T> partial_deriv_array[2];
137  log_mix_partial_helper(1.0 - theta, lambda2, lambda1, partial_deriv_array);
138  return fvar<T>(log_mix(theta.val_, lambda1.val_, lambda2),
139  -theta.d_ * value_of(partial_deriv_array[0])
140  + lambda1.d_ * value_of(partial_deriv_array[1]));
141  }
142 }
143 
144 template <typename T>
145 inline fvar<T> log_mix(const fvar<T>& theta, double lambda1,
146  const fvar<T>& lambda2) {
147  if (lambda1 > lambda2.val_) {
148  fvar<T> partial_deriv_array[2];
149  log_mix_partial_helper(theta, lambda1, lambda2, partial_deriv_array);
150  return fvar<T>(log_mix(theta.val_, lambda1, lambda2.val_),
151  theta.d_ * value_of(partial_deriv_array[0])
152  + lambda2.d_ * value_of(partial_deriv_array[1]));
153  } else {
154  fvar<T> partial_deriv_array[2];
155  log_mix_partial_helper(1.0 - theta, lambda2, lambda1, partial_deriv_array);
156  return fvar<T>(log_mix(theta.val_, lambda1, lambda2.val_),
157  -theta.d_ * value_of(partial_deriv_array[0])
158  + lambda2.d_ * value_of(partial_deriv_array[1]));
159  }
160 }
161 
162 template <typename T>
163 inline fvar<T> log_mix(double theta, const fvar<T>& lambda1,
164  const fvar<T>& lambda2) {
165  if (lambda1.val_ > lambda2.val_) {
166  fvar<T> partial_deriv_array[2];
167  log_mix_partial_helper(theta, lambda1, lambda2, partial_deriv_array);
168  return fvar<T>(log_mix(theta, lambda1.val_, lambda2.val_),
169  lambda1.d_ * value_of(partial_deriv_array[0])
170  + lambda2.d_ * value_of(partial_deriv_array[1]));
171  } else {
172  fvar<T> partial_deriv_array[2];
173  log_mix_partial_helper(1.0 - theta, lambda2, lambda1, partial_deriv_array);
174  return fvar<T>(log_mix(theta, lambda1.val_, lambda2.val_),
175  lambda1.d_ * value_of(partial_deriv_array[1])
176  + lambda2.d_ * value_of(partial_deriv_array[0]));
177  }
178 }
179 
180 template <typename T>
181 inline fvar<T> log_mix(const fvar<T>& theta, double lambda1, double lambda2) {
182  if (lambda1 > lambda2) {
183  fvar<T> partial_deriv_array[1];
184  log_mix_partial_helper(theta, lambda1, lambda2, partial_deriv_array);
185  return fvar<T>(log_mix(theta.val_, lambda1, lambda2),
186  theta.d_ * value_of(partial_deriv_array[0]));
187  } else {
188  fvar<T> partial_deriv_array[1];
189  log_mix_partial_helper(1.0 - theta, lambda2, lambda1, partial_deriv_array);
190  return fvar<T>(log_mix(theta.val_, lambda1, lambda2),
191  -theta.d_ * value_of(partial_deriv_array[0]));
192  }
193 }
194 
195 template <typename T>
196 inline fvar<T> log_mix(double theta, const fvar<T>& lambda1, double lambda2) {
197  if (lambda1.val_ > lambda2) {
198  fvar<T> partial_deriv_array[1];
199  log_mix_partial_helper(theta, lambda1, lambda2, partial_deriv_array);
200  return fvar<T>(log_mix(theta, lambda1.val_, lambda2),
201  lambda1.d_ * value_of(partial_deriv_array[0]));
202  } else {
203  fvar<T> partial_deriv_array[1];
204  log_mix_partial_helper(1.0 - theta, lambda2, lambda1, partial_deriv_array);
205  return fvar<T>(log_mix(theta, lambda1.val_, lambda2),
206  lambda1.d_ * value_of(partial_deriv_array[0]));
207  }
208 }
209 
210 template <typename T>
211 inline fvar<T> log_mix(double theta, double lambda1, const fvar<T>& lambda2) {
212  if (lambda1 > lambda2.val_) {
213  fvar<T> partial_deriv_array[1];
214  log_mix_partial_helper(theta, lambda1, lambda2, partial_deriv_array);
215  return fvar<T>(log_mix(theta, lambda1, lambda2.val_),
216  lambda2.d_ * value_of(partial_deriv_array[0]));
217  } else {
218  fvar<T> partial_deriv_array[1];
219  log_mix_partial_helper(1.0 - theta, lambda2, lambda1, partial_deriv_array);
220  return fvar<T>(log_mix(theta, lambda1, lambda2.val_),
221  lambda2.d_ * value_of(partial_deriv_array[0]));
222  }
223 }
224 } // namespace math
225 } // namespace stan
226 #endif
T d_
The tangent (derivative) of this variable.
Definition: fvar.hpp:50
T value_of(const fvar< T > &v)
Return the value of the specified variable.
Definition: value_of.hpp:17
T val_
The value of this variable.
Definition: fvar.hpp:45
fvar< T > exp(const fvar< T > &x)
Definition: exp.hpp:11
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:29
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:107
This template class represents scalars used in forward-mode automatic differentiation, which consist of values and directional derivatives of the specified template type.
Definition: fvar.hpp:41

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