Automatic Differentiation
 
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
11
12#include <tuple>
13#include <utility>
14
15namespace stan {
16namespace math {
17
22namespace laplace_likelihood {
23
24namespace internal {
35template <typename F, typename Theta, typename Stream, typename... Args,
37inline auto log_likelihood(F&& f, Theta&& theta, Stream* msgs, Args&&... args) {
38 return std::forward<F>(f)(std::forward<Theta>(theta),
39 std::forward<Args>(args)..., msgs);
40}
41
55template <typename F, typename Theta, typename Stream, typename... Args,
57inline auto theta_grad(F&& f, Theta&& theta, Stream* msgs, Args&&... args) {
58 using Eigen::Dynamic;
59 using Eigen::Matrix;
61 arena_t<Matrix<var, Dynamic, 1>> theta_var = theta;
62 var f_var = f(theta_var, args..., msgs);
63 grad(f_var.vi_);
64 return theta_var.adj().eval();
65}
66
80template <typename F, typename Theta, typename Stream, typename... Args,
82inline void ll_arg_grad(F&& f, Theta&& theta, Stream* msgs, Args&&... args) {
83 using Eigen::Dynamic;
84 using Eigen::Matrix;
86 var f_var = f(theta, args..., msgs);
87 grad(f_var.vi_);
88}
89
106template <typename F, typename Theta, typename Stream, typename... Args,
108inline auto diagonal_hessian(F&& f, Theta&& theta, Stream* msgs,
109 Args&&... args) {
110 using Eigen::Dynamic;
111 using Eigen::Matrix;
112 const Eigen::Index theta_size = theta.size();
113 auto v = Eigen::VectorXd::Ones(theta_size);
114 Eigen::VectorXd hessian_v = Eigen::VectorXd::Zero(theta_size);
115 hessian_times_vector(f, hessian_v, std::forward<Theta>(theta), std::move(v),
116 value_of(args)..., msgs);
117 return (-hessian_v).eval();
118}
119
136template <typename F, typename Theta, typename Stream, typename... Args,
138inline auto block_hessian(F&& f, Theta&& theta,
139 const Eigen::Index hessian_block_size, Stream* msgs,
140 Args&&... args) {
141 using Eigen::Dynamic;
142 using Eigen::Matrix;
143 const Eigen::Index theta_size = theta.size();
144 if (hessian_block_size == 1) {
145 auto v = Eigen::VectorXd::Ones(theta_size);
146 Eigen::VectorXd hessian_v = Eigen::VectorXd::Zero(theta_size);
147 hessian_times_vector(f, hessian_v, std::forward<Theta>(theta), std::move(v),
148 value_of(args)..., msgs);
149 Eigen::SparseMatrix<double> hessian_theta(theta_size, theta_size);
150 hessian_theta.reserve(Eigen::VectorXi::Constant(theta_size, 1));
151 for (Eigen::Index i = 0; i < theta_size; i++) {
152 hessian_theta.insert(i, i) = hessian_v(i);
153 }
154 return (-hessian_theta).eval();
155 } else {
156 return (-hessian_block_diag(f, std::forward<Theta>(theta),
157 hessian_block_size, value_of(args)..., msgs))
158 .eval();
159 }
160}
161
179template <typename F, typename Theta, typename Stream, typename... Args,
181inline auto diff(F&& f, Theta&& theta, const Eigen::Index hessian_block_size,
182 Stream* msgs, Args&&... args) {
183 using Eigen::Dynamic;
184 using Eigen::Matrix;
185 const Eigen::Index theta_size = theta.size();
186 auto theta_gradient = [&theta, &f, &msgs](auto&&... args) {
187 nested_rev_autodiff nested;
188 Matrix<var, Dynamic, 1> theta_var = theta;
189 var f_var = f(theta_var, args..., msgs);
190 grad(f_var.vi_);
191 return theta_var.adj().eval();
192 }(args...);
193 if (hessian_block_size == 1) {
194 auto v = Eigen::VectorXd::Ones(theta_size);
195 Eigen::VectorXd hessian_v = Eigen::VectorXd::Zero(theta_size);
196 hessian_times_vector(f, hessian_v, std::forward<Theta>(theta), std::move(v),
197 value_of(args)..., msgs);
198 Eigen::SparseMatrix<double> hessian_theta(theta_size, theta_size);
199 hessian_theta.reserve(Eigen::VectorXi::Constant(theta_size, 1));
200 for (Eigen::Index i = 0; i < theta_size; i++) {
201 hessian_theta.insert(i, i) = hessian_v(i);
202 }
203 return std::make_pair(std::move(theta_gradient), (-hessian_theta).eval());
204 } else {
205 return std::make_pair(
206 std::move(theta_gradient),
207 (-hessian_block_diag(f, std::forward<Theta>(theta), hessian_block_size,
208 value_of(args)..., msgs))
209 .eval());
210 }
211}
212
226template <typename F, typename Theta, typename Stream, typename... Args,
228inline Eigen::VectorXd third_diff(F&& f, Theta&& theta, Stream&& msgs,
229 Args&&... args) {
230 nested_rev_autodiff nested;
231 const Eigen::Index theta_size = theta.size();
233 = std::forward<Theta>(theta);
234 arena_t<Eigen::Matrix<fvar<fvar<var>>, Eigen::Dynamic, 1>> theta_ffvar(
235 theta_size);
236 for (Eigen::Index i = 0; i < theta_size; ++i) {
237 theta_ffvar(i) = fvar<fvar<var>>(fvar<var>(theta_var(i), 1.0), 1.0);
238 }
239 fvar<fvar<var>> ftheta_ffvar = f(theta_ffvar, args..., msgs);
240 grad(ftheta_ffvar.d_.d_.vi_);
241 return theta_var.adj().eval();
242}
243
265template <typename F, typename Theta, typename AMat, typename Stream,
266 typename... Args, require_eigen_vector_t<Theta>* = nullptr>
267inline auto compute_s2(F&& f, Theta&& theta, AMat&& A,
268 const int hessian_block_size, Stream* msgs,
269 Args&&... args) {
270 using Eigen::Dynamic;
271 using Eigen::Matrix;
272 using Eigen::MatrixXd;
273 using Eigen::VectorXd;
274
275 nested_rev_autodiff nested;
276 const Eigen::Index theta_size = theta.size();
277 arena_t<Matrix<var, Dynamic, 1>> theta_var = std::forward<Theta>(theta);
278 int n_blocks = theta_size / hessian_block_size;
279 arena_t<VectorXd> v(theta_size);
280 arena_t<VectorXd> w(theta_size);
281 Matrix<fvar<fvar<var>>, Dynamic, 1> theta_ffvar(theta_size);
282 auto shallow_copy_args
283 = stan::math::internal::shallow_copy_vargs<fvar<fvar<var>>>(
284 std::forward_as_tuple(args...));
285 for (Eigen::Index i = 0; i < hessian_block_size; ++i) {
286 nested_rev_autodiff nested;
287 v.setZero();
288 for (int j = i; j < theta_size; j += hessian_block_size) {
289 v(j) = 1;
290 }
291 w.setZero();
292 for (int j = 0; j < n_blocks; ++j) {
293 for (int k = 0; k < hessian_block_size; ++k) {
294 w(k + j * hessian_block_size)
295 = A(k + j * hessian_block_size, i + j * hessian_block_size);
296 }
297 }
298 for (int j = 0; j < theta_size; ++j) {
299 theta_ffvar(j) = fvar<fvar<var>>(fvar<var>(theta_var(j), v(j)), w(j));
300 }
301 fvar<fvar<var>> target_ffvar = stan::math::apply(
302 [](auto&& f, auto&& theta_ffvar, auto&& msgs, auto&&... inner_args) {
303 return f(theta_ffvar, inner_args..., msgs);
304 },
305 shallow_copy_args, f, theta_ffvar, msgs);
306 grad(target_ffvar.d_.d_.vi_);
307 }
308 return (0.5 * theta_var.adj()).eval();
309}
310
330template <typename F, typename V_t, typename Theta, typename Stream,
331 typename... Args, require_eigen_vector_t<Theta>* = nullptr>
332inline auto diff_eta_implicit(F&& f, V_t&& v, Theta&& theta, Stream* msgs,
333 Args&&... args) {
334 using Eigen::Dynamic;
335 using Eigen::Matrix;
336 using Eigen::VectorXd;
337 constexpr bool contains_var = is_any_var_scalar<Args...>::value;
338 if constexpr (!contains_var) {
339 return;
340 }
341 nested_rev_autodiff nested;
342 const Eigen::Index theta_size = theta.size();
343 arena_t<Matrix<var, Dynamic, 1>> theta_var = std::forward<Theta>(theta);
344 Matrix<fvar<var>, Dynamic, 1> theta_fvar(theta_size);
345 for (Eigen::Index i = 0; i < theta_size; i++) {
346 theta_fvar(i) = fvar<var>(theta_var(i), v(i));
347 }
348 auto shallow_copy_args = stan::math::internal::shallow_copy_vargs<fvar<var>>(
349 std::forward_as_tuple(args...));
351 [](auto&& f, auto&& theta_fvar, auto&& msgs, auto&&... inner_args) {
352 return f(theta_fvar, inner_args..., msgs);
353 },
354 shallow_copy_args, f, theta_fvar, msgs);
355 grad(f_sum.d_.vi_);
356}
357
358} // namespace internal
359
371template <typename F, typename Theta, typename TupleArgs, typename Stream,
374inline auto theta_grad(F&& f, Theta&& theta, TupleArgs&& ll_tup,
375 Stream* msgs = nullptr) {
376 return stan::math::apply(
377 [](auto&& f, auto&& theta, auto&& msgs, auto&&... args) {
378 return internal::theta_grad(std::forward<decltype(f)>(f),
379 std::forward<decltype(theta)>(theta), msgs,
380 std::forward<decltype(args)>(args)...);
381 },
382 std::forward<TupleArgs>(ll_tup), std::forward<F>(f),
383 std::forward<Theta>(theta), msgs);
384}
385
386template <typename F, typename Theta, typename TupleArgs, typename Stream,
389inline auto ll_arg_grad(F&& f, Theta&& theta, TupleArgs&& ll_tup,
390 Stream* msgs = nullptr) {
391 return stan::math::apply(
392 [](auto&& f, auto&& theta, auto&& msgs, auto&&... args) {
393 return internal::ll_arg_grad(std::forward<decltype(f)>(f),
394 std::forward<decltype(theta)>(theta), msgs,
395 std::forward<decltype(args)>(args)...);
396 },
397 std::forward<TupleArgs>(ll_tup), std::forward<F>(f),
398 std::forward<Theta>(theta), msgs);
399}
400
401template <typename F, typename Theta, typename TupleArgs, typename Stream,
404inline auto diagonal_hessian(F&& f, Theta&& theta, TupleArgs&& ll_tuple,
405 Stream* msgs) {
406 return stan::math::apply(
407 [](auto&& f, auto&& theta, auto* msgs, auto&&... args) {
409 std::forward<decltype(f)>(f), std::forward<decltype(theta)>(theta),
410 msgs, std::forward<decltype(args)>(args)...);
411 },
412 std::forward<TupleArgs>(ll_tuple), std::forward<F>(f),
413 std::forward<Theta>(theta), msgs);
414}
415
416template <typename F, typename Theta, typename TupleArgs, typename Stream,
419inline auto block_hessian(F&& f, Theta&& theta,
420 const Eigen::Index hessian_block_size,
421 TupleArgs&& ll_tuple, Stream* msgs) {
422 return stan::math::apply(
423 [](auto&& f, auto&& theta, auto hessian_block_size, auto* msgs,
424 auto&&... args) {
426 std::forward<decltype(f)>(f), std::forward<decltype(theta)>(theta),
427 hessian_block_size, msgs, std::forward<decltype(args)>(args)...);
428 },
429 std::forward<TupleArgs>(ll_tuple), std::forward<F>(f),
430 std::forward<Theta>(theta), hessian_block_size, msgs);
431}
432
444template <typename F, typename Theta, typename TupleArgs, typename Stream,
447inline auto log_likelihood(F&& f, Theta&& theta, TupleArgs&& ll_tup,
448 Stream* msgs) {
449 return stan::math::apply(
450 [](auto&& f, auto&& theta, auto&& msgs, auto&&... args) {
452 std::forward<decltype(f)>(f), std::forward<decltype(theta)>(theta),
453 msgs, std::forward<decltype(args)>(args)...);
454 },
455 std::forward<TupleArgs>(ll_tup), std::forward<F>(f),
456 std::forward<Theta>(theta), msgs);
457}
458
472template <typename F, typename Theta, typename TupleArgs, typename Stream,
475inline auto diff(F&& f, Theta&& theta, const Eigen::Index hessian_block_size,
476 TupleArgs&& ll_tuple, Stream* msgs) {
477 return stan::math::apply(
478 [](auto&& f, auto&& theta, auto hessian_block_size, auto* msgs,
479 auto&&... args) {
480 return internal::diff(
481 std::forward<decltype(f)>(f), std::forward<decltype(theta)>(theta),
482 hessian_block_size, msgs, std::forward<decltype(args)>(args)...);
483 },
484 std::forward<TupleArgs>(ll_tuple), std::forward<F>(f),
485 std::forward<Theta>(theta), hessian_block_size, msgs);
486}
487
499template <typename F, typename Theta, typename TupleArgs, typename Stream,
502inline Eigen::VectorXd third_diff(F&& f, Theta&& theta, TupleArgs&& ll_args,
503 Stream* msgs) {
504 return stan::math::apply(
505 [](auto&& f, auto&& theta, auto&& msgs, auto&&... args) {
506 return internal::third_diff(std::forward<decltype(f)>(f),
507 std::forward<decltype(theta)>(theta), msgs,
508 std::forward<decltype(args)>(args)...);
509 },
510 std::forward<TupleArgs>(ll_args), std::forward<F>(f),
511 std::forward<Theta>(theta), msgs);
512}
513
529template <typename F, typename Theta, typename AMat, typename TupleArgs,
530 typename Stream, require_eigen_vector_t<Theta>* = nullptr,
532inline auto compute_s2(F&& f, Theta&& theta, AMat&& A, int hessian_block_size,
533 TupleArgs&& ll_args, Stream* msgs) {
534 return stan::math::apply(
535 [](auto&& f, auto&& theta, auto&& A, auto hessian_block_size, auto* msgs,
536 auto&&... args) {
538 std::forward<decltype(f)>(f), std::forward<decltype(theta)>(theta),
539 std::forward<decltype(A)>(A), hessian_block_size, msgs,
540 std::forward<decltype(args)>(args)...);
541 },
542 std::forward<TupleArgs>(ll_args), std::forward<F>(f),
543 std::forward<Theta>(theta), std::forward<AMat>(A), hessian_block_size,
544 msgs);
545}
546
560template <typename F, typename V_t, typename Theta, typename TupleArgs,
561 typename Stream, require_tuple_t<TupleArgs>* = nullptr,
563inline auto diff_eta_implicit(F&& f, V_t&& v, Theta&& theta,
564 TupleArgs&& ll_args, Stream* msgs) {
565 return stan::math::apply(
566 [](auto&& f, auto&& v, auto&& theta, auto&& msgs, auto&&... args) {
568 std::forward<decltype(f)>(f), std::forward<decltype(v)>(v),
569 std::forward<decltype(theta)>(theta), msgs,
570 std::forward<decltype(args)>(args)...);
571 },
572 std::forward<TupleArgs>(ll_args), std::forward<F>(f),
573 std::forward<V_t>(v), std::forward<Theta>(theta), msgs);
574}
575
576} // namespace laplace_likelihood
577
578} // namespace math
579} // namespace stan
580
581#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:33
auto block_hessian(F &&f, Theta &&theta, const Eigen::Index hessian_block_size, Stream *msgs, Args &&... args)
Computes negative block diagonal Hessian of f wrttheta and args...
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 diagonal_hessian(F &&f, Theta &&theta, Stream *msgs, Args &&... args)
Computes negative diagonal Hessian of f wrttheta and args...
void ll_arg_grad(F &&f, Theta &&theta, Stream *msgs, Args &&... args)
Computes likelihood argument gradient of f
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.
auto theta_grad(F &&f, Theta &&theta, Stream *msgs, Args &&... args)
Computes theta gradient f wrt theta and args...
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 diagonal_hessian(F &&f, Theta &&theta, TupleArgs &&ll_tuple, Stream *msgs)
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.
auto block_hessian(F &&f, Theta &&theta, const Eigen::Index hessian_block_size, TupleArgs &&ll_tuple, Stream *msgs)
auto theta_grad(F &&f, Theta &&theta, TupleArgs &&ll_tup, Stream *msgs=nullptr)
A wrapper that accepts a tuple as arguments.
auto ll_arg_grad(F &&f, Theta &&theta, TupleArgs &&ll_tup, Stream *msgs=nullptr)
Eigen::VectorXd third_diff(F &&f, Theta &&theta, TupleArgs &&ll_args, Stream *msgs)
A wrapper that accepts a tuple as arguments.
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...
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
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)
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 internal::arena_type_impl< std::decay_t< T > >::type arena_t
Determines a type that can be used in place of T that does any dynamic allocations on the AD stack.
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