Loading [MathJax]/extensions/TeX/AMSmath.js
Automatic Differentiation
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
laplace_likelihood.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_MIX_FUNCTOR_LAPLACE_LIKELIHOOD_HPP
2#define STAN_MATH_MIX_FUNCTOR_LAPLACE_LIKELIHOOD_HPP
3
7
8namespace stan {
9namespace math {
10
15namespace laplace_likelihood {
16namespace internal {
27template <typename F, typename Theta, typename Stream, typename... Args,
29inline auto log_likelihood(F&& f, Theta&& theta, Stream* msgs, Args&&... args) {
30 return std::forward<F>(f)(std::forward<Theta>(theta),
31 std::forward<Args>(args)..., msgs);
32}
33
38enum class COPY_TYPE { SHALLOW = 0, DEEP = 1 };
39
52template <template <typename...> class Filter,
53 typename PromotedType = stan::math::var,
54 COPY_TYPE CopyType = COPY_TYPE::DEEP, typename... Args>
55inline auto conditional_copy_and_promote(Args&&... args) {
56 return map_if<Filter>(
57 [](auto&& arg) {
58 if constexpr (is_tuple_v<decltype(arg)>) {
59 return stan::math::apply(
60 [](auto&&... inner_args) {
61 return make_holder_tuple(
62 conditional_copy_and_promote<Filter, PromotedType,
63 CopyType>(
64 std::forward<decltype(inner_args)>(inner_args))...);
65 },
66 std::forward<decltype(arg)>(arg));
67 } else if constexpr (is_std_vector_v<decltype(arg)>) {
68 std::vector<decltype(conditional_copy_and_promote<
69 Filter, PromotedType, CopyType>(arg[0]))>
70 ret;
71 for (std::size_t i = 0; i < arg.size(); ++i) {
72 ret.push_back(
73 conditional_copy_and_promote<Filter, PromotedType, CopyType>(
74 arg[i]));
75 }
76 return ret;
77 } else {
78 if constexpr (CopyType == COPY_TYPE::DEEP) {
79 return stan::math::eval(promote_scalar<PromotedType>(
80 value_of_rec(std::forward<decltype(arg)>(arg))));
81 } else if (CopyType == COPY_TYPE::SHALLOW) {
82 if constexpr (std::is_same_v<PromotedType,
83 scalar_type_t<decltype(arg)>>) {
84 return std::forward<decltype(arg)>(arg);
85 } else {
86 return stan::math::eval(promote_scalar<PromotedType>(
87 std::forward<decltype(arg)>(arg)));
88 }
89 }
90 }
91 },
92 std::forward<Args>(args)...);
93}
94
95template <typename PromotedType, typename... Args>
96inline auto deep_copy_vargs(Args&&... args) {
99 std::forward<Args>(args)...);
100}
101
102template <typename PromotedType, typename... Args>
103inline auto shallow_copy_vargs(Args&&... args) {
106 std::forward<Args>(args)...);
107}
108
126template <typename F, typename Theta, typename Stream, typename... Args,
128inline auto diff(F&& f, Theta&& theta, const Eigen::Index hessian_block_size,
129 Stream* msgs, Args&&... args) {
130 using Eigen::Dynamic;
131 using Eigen::Matrix;
132 const Eigen::Index theta_size = theta.size();
133 auto theta_gradient = [&theta, &f, &msgs](auto&&... args) {
134 nested_rev_autodiff nested;
135 Matrix<var, Dynamic, 1> theta_var = theta;
136 var f_var = f(theta_var, args..., msgs);
137 grad(f_var.vi_);
138 return theta_var.adj().eval();
139 }(args...);
140 if (hessian_block_size == 1) {
141 auto v = Eigen::VectorXd::Ones(theta_size);
142 Eigen::VectorXd hessian_v = Eigen::VectorXd::Zero(theta_size);
143 hessian_times_vector(f, hessian_v, std::forward<Theta>(theta), std::move(v),
144 value_of(args)..., msgs);
145 Eigen::SparseMatrix<double> hessian_theta(theta_size, theta_size);
146 hessian_theta.reserve(Eigen::VectorXi::Constant(theta_size, 1));
147 for (Eigen::Index i = 0; i < theta_size; i++) {
148 hessian_theta.insert(i, i) = hessian_v(i);
149 }
150 return std::make_pair(std::move(theta_gradient), (-hessian_theta).eval());
151 } else {
152 return std::make_pair(
153 std::move(theta_gradient),
154 (-hessian_block_diag(f, std::forward<Theta>(theta), hessian_block_size,
155 value_of(args)..., msgs))
156 .eval());
157 }
158}
159
173template <typename F, typename Theta, typename Stream, typename... Args,
175inline Eigen::VectorXd third_diff(F&& f, Theta&& theta, Stream&& msgs,
176 Args&&... args) {
177 nested_rev_autodiff nested;
178 const Eigen::Index theta_size = theta.size();
179 Eigen::Matrix<var, Eigen::Dynamic, 1> theta_var = std::forward<Theta>(theta);
180 Eigen::Matrix<fvar<fvar<var>>, Eigen::Dynamic, 1> theta_ffvar(theta_size);
181 for (Eigen::Index i = 0; i < theta_size; ++i) {
182 theta_ffvar(i) = fvar<fvar<var>>(fvar<var>(theta_var(i), 1.0), 1.0);
183 }
184 fvar<fvar<var>> ftheta_ffvar = f(theta_ffvar, args..., msgs);
185 grad(ftheta_ffvar.d_.d_.vi_);
186 return theta_var.adj().eval();
187}
188
210template <typename F, typename Theta, typename AMat, typename Stream,
211 typename... Args, require_eigen_vector_t<Theta>* = nullptr>
212inline auto compute_s2(F&& f, Theta&& theta, AMat&& A,
213 const int hessian_block_size, Stream* msgs,
214 Args&&... args) {
215 using Eigen::Dynamic;
216 using Eigen::Matrix;
217 using Eigen::MatrixXd;
218 using Eigen::VectorXd;
219
220 nested_rev_autodiff nested;
221 const Eigen::Index theta_size = theta.size();
222 Matrix<var, Dynamic, 1> theta_var = std::forward<Theta>(theta);
223 int n_blocks = theta_size / hessian_block_size;
224 VectorXd v(theta_size);
225 VectorXd w(theta_size);
226 Matrix<fvar<fvar<var>>, Dynamic, 1> theta_ffvar(theta_size);
227 auto shallow_copy_args
228 = shallow_copy_vargs<fvar<fvar<var>>>(std::forward_as_tuple(args...));
229 for (Eigen::Index i = 0; i < hessian_block_size; ++i) {
230 nested_rev_autodiff nested;
231 v.setZero();
232 for (int j = i; j < theta_size; j += hessian_block_size) {
233 v(j) = 1;
234 }
235 w.setZero();
236 for (int j = 0; j < n_blocks; ++j) {
237 for (int k = 0; k < hessian_block_size; ++k) {
238 w(k + j * hessian_block_size)
239 = A(k + j * hessian_block_size, i + j * hessian_block_size);
240 }
241 }
242 for (int j = 0; j < theta_size; ++j) {
243 theta_ffvar(j) = fvar<fvar<var>>(fvar<var>(theta_var(j), v(j)), w(j));
244 }
245 fvar<fvar<var>> target_ffvar = stan::math::apply(
246 [](auto&& f, auto&& theta_ffvar, auto&& msgs, auto&&... inner_args) {
247 return f(theta_ffvar, inner_args..., msgs);
248 },
249 shallow_copy_args, f, theta_ffvar, msgs);
250 grad(target_ffvar.d_.d_.vi_);
251 }
252 return (0.5 * theta_var.adj()).eval();
253}
254
274template <typename F, typename V_t, typename Theta, typename Stream,
275 typename... Args, require_eigen_vector_t<Theta>* = nullptr>
276inline auto diff_eta_implicit(F&& f, V_t&& v, Theta&& theta, Stream* msgs,
277 Args&&... args) {
278 using Eigen::Dynamic;
279 using Eigen::Matrix;
280 using Eigen::VectorXd;
281 constexpr bool contains_var = is_any_var_scalar<Args...>::value;
282 if constexpr (!contains_var) {
283 return;
284 }
285 nested_rev_autodiff nested;
286 const Eigen::Index theta_size = theta.size();
287 Matrix<var, Dynamic, 1> theta_var = std::forward<Theta>(theta);
288 Matrix<fvar<var>, Dynamic, 1> theta_fvar(theta_size);
289 for (Eigen::Index i = 0; i < theta_size; i++) {
290 theta_fvar(i) = fvar<var>(theta_var(i), v(i));
291 }
292 auto shallow_copy_args
293 = shallow_copy_vargs<fvar<var>>(std::forward_as_tuple(args...));
295 [](auto&& f, auto&& theta_fvar, auto&& msgs, auto&&... inner_args) {
296 return f(theta_fvar, inner_args..., msgs);
297 },
298 shallow_copy_args, f, theta_fvar, msgs);
299 grad(f_sum.d_.vi_);
300}
301
302} // namespace internal
303
315template <typename F, typename Theta, typename TupleArgs, typename Stream,
318inline auto log_likelihood(F&& f, Theta&& theta, TupleArgs&& ll_tup,
319 Stream* msgs) {
320 return apply(
321 [](auto&& f, auto&& theta, auto&& msgs, auto&&... args) {
323 std::forward<decltype(f)>(f), std::forward<decltype(theta)>(theta),
324 msgs, std::forward<decltype(args)>(args)...);
325 },
326 std::forward<TupleArgs>(ll_tup), std::forward<F>(f),
327 std::forward<Theta>(theta), msgs);
328}
329
343template <typename F, typename Theta, typename TupleArgs, typename Stream,
346inline auto diff(F&& f, Theta&& theta, const Eigen::Index hessian_block_size,
347 TupleArgs&& ll_tuple, Stream* msgs) {
348 return apply(
349 [](auto&& f, auto&& theta, auto hessian_block_size, auto* msgs,
350 auto&&... args) {
351 return internal::diff(
352 std::forward<decltype(f)>(f), std::forward<decltype(theta)>(theta),
353 hessian_block_size, msgs, std::forward<decltype(args)>(args)...);
354 },
355 std::forward<TupleArgs>(ll_tuple), std::forward<F>(f),
356 std::forward<Theta>(theta), hessian_block_size, msgs);
357}
358
370template <typename F, typename Theta, typename TupleArgs, typename Stream,
373inline Eigen::VectorXd third_diff(F&& f, Theta&& theta, TupleArgs&& ll_args,
374 Stream* msgs) {
375 return apply(
376 [](auto&& f, auto&& theta, auto&& msgs, auto&&... args) {
377 return internal::third_diff(std::forward<decltype(f)>(f),
378 std::forward<decltype(theta)>(theta), msgs,
379 std::forward<decltype(args)>(args)...);
380 },
381 std::forward<TupleArgs>(ll_args), std::forward<F>(f),
382 std::forward<Theta>(theta), msgs);
383}
384
400template <typename F, typename Theta, typename AMat, typename TupleArgs,
401 typename Stream, require_eigen_vector_t<Theta>* = nullptr,
403inline auto compute_s2(F&& f, Theta&& theta, AMat&& A, int hessian_block_size,
404 TupleArgs&& ll_args, Stream* msgs) {
405 return apply(
406 [](auto&& f, auto&& theta, auto&& A, auto hessian_block_size, auto* msgs,
407 auto&&... args) {
409 std::forward<decltype(f)>(f), std::forward<decltype(theta)>(theta),
410 std::forward<decltype(A)>(A), hessian_block_size, msgs,
411 std::forward<decltype(args)>(args)...);
412 },
413 std::forward<TupleArgs>(ll_args), std::forward<F>(f),
414 std::forward<Theta>(theta), std::forward<AMat>(A), hessian_block_size,
415 msgs);
416}
417
431template <typename F, typename V_t, typename Theta, typename TupleArgs,
432 typename Stream, require_tuple_t<TupleArgs>* = nullptr,
434inline auto diff_eta_implicit(F&& f, V_t&& v, Theta&& theta,
435 TupleArgs&& ll_args, Stream* msgs) {
436 return apply(
437 [](auto&& f, auto&& v, auto&& theta, auto&& msgs, auto&&... args) {
439 std::forward<decltype(f)>(f), std::forward<decltype(v)>(v),
440 std::forward<decltype(theta)>(theta), msgs,
441 std::forward<decltype(args)>(args)...);
442 },
443 std::forward<TupleArgs>(ll_args), std::forward<F>(f),
444 std::forward<V_t>(v), std::forward<Theta>(theta), msgs);
445}
446
447} // namespace laplace_likelihood
448
449} // namespace math
450} // namespace stan
451
452#endif
A class following the RAII idiom to start and recover nested autodiff scopes.
require_t< is_eigen_vector< std::decay_t< T > > > require_eigen_vector_t
Require type satisfies is_eigen_vector.
require_t< container_type_check_base< is_eigen_vector, value_type_t, TypeCheck, Check... > > require_eigen_vector_vt
Require type satisfies is_eigen_vector.
require_t< is_tuple< std::decay_t< T > > > require_tuple_t
Require type satisfies is_tuple.
Definition is_tuple.hpp:32
auto conditional_copy_and_promote(Args &&... args)
Conditional copy and promote a type's scalar type to a PromotedType.
Eigen::VectorXd third_diff(F &&f, Theta &&theta, Stream &&msgs, Args &&... args)
Compute third order derivative of f wrt theta and args...
auto diff_eta_implicit(F &&f, V_t &&v, Theta &&theta, Stream *msgs, Args &&... args)
Compute second order gradient of f wrt theta and args...
auto log_likelihood(F &&f, Theta &&theta, Stream *msgs, Args &&... args)
auto diff(F &&f, Theta &&theta, const Eigen::Index hessian_block_size, Stream *msgs, Args &&... args)
Computes theta gradient and negative block diagonal Hessian of f wrt theta and args....
auto compute_s2(F &&f, Theta &&theta, AMat &&A, const int hessian_block_size, Stream *msgs, Args &&... args)
The derivative of the log likelihood wrt theta evaluated at the mode.
COPY_TYPE
Decide if object should be deep or shallow copied when using conditional_copy_and_promote .
auto compute_s2(F &&f, Theta &&theta, AMat &&A, int hessian_block_size, TupleArgs &&ll_args, Stream *msgs)
A wrapper that accepts a tuple as arguments.
auto diff(F &&f, Theta &&theta, const Eigen::Index hessian_block_size, TupleArgs &&ll_tuple, Stream *msgs)
A wrapper that accepts a tuple as arguments.
auto diff_eta_implicit(F &&f, V_t &&v, Theta &&theta, TupleArgs &&ll_args, Stream *msgs)
A wrapper that accepts a tuple as arguments.
auto log_likelihood(F &&f, Theta &&theta, TupleArgs &&ll_tup, Stream *msgs)
A wrapper that accepts a tuple as arguments.
Eigen::VectorXd third_diff(F &&f, Theta &&theta, TupleArgs &&ll_args, Stream *msgs)
A wrapper that accepts a tuple as arguments.
double value_of_rec(const fvar< T > &v)
Return the value of the specified variable.
Eigen::SparseMatrix< double > hessian_block_diag(F &&f, const Eigen::VectorXd &x, const Eigen::Index hessian_block_size, Args &&... args)
Returns a block diagonal Hessian by computing the relevant directional derivatives and storing them i...
fvar< T > arg(const std::complex< fvar< T > > &z)
Return the phase angle of the complex argument.
Definition arg.hpp:19
T eval(T &&arg)
Inputs which have a plain_type equal to the own time are forwarded unmodified (for Eigen expressions ...
Definition eval.hpp:20
constexpr auto make_holder_tuple(Types &&... args)
Holds ownership of rvalues and forwards lvalues into a tuple.
T value_of(const fvar< T > &v)
Return the value of the specified variable.
Definition value_of.hpp:18
void hessian_times_vector(const F &f, const Eigen::Matrix< double, Eigen::Dynamic, 1 > &x, const Eigen::Matrix< double, Eigen::Dynamic, 1 > &v, double &fx, Eigen::Matrix< double, Eigen::Dynamic, 1 > &Hv)
var_value< double > var
Definition var.hpp:1187
constexpr bool is_tuple_v
Definition is_tuple.hpp:23
static void grad()
Compute the gradient for all variables starting from the end of the AD tape.
Definition grad.hpp:26
constexpr decltype(auto) apply(F &&f, Tuple &&t, PreArgs &&... pre_args)
Definition apply.hpp:51
typename scalar_type< T >::type scalar_type_t
constexpr bool is_std_vector_v
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...
Scalar d_
The tangent (derivative) of this variable.
Definition fvar.hpp:61
This template class represents scalars used in forward-mode automatic differentiation,...
Definition fvar.hpp:40