1#ifndef STAN_MATH_REV_FUN_LMULTPLY_HPP
2#define STAN_MATH_REV_FUN_LMULTPLY_HPP
98template <
typename T1,
typename T2, require_all_matrix_t<T1, T2>* =
nullptr,
99 require_any_var_matrix_t<T1, T2>* =
nullptr>
102 if constexpr (is_autodiff_v<T1> && is_autodiff_v<T2>) {
108 [arena_a, arena_b](
const auto& res)
mutable {
109 arena_a.adj().array()
110 += res.adj().array() * arena_b.val().array().log();
111 arena_b.adj().array() += res.adj().array() * arena_a.val().array()
112 / arena_b.val().array();
114 }
else if constexpr (is_autodiff_v<T1>) {
119 [arena_a, arena_b](
const auto& res)
mutable {
120 arena_a.adj().array()
122 * arena_b.val().array().log();
129 [arena_a, arena_b](
const auto& res)
mutable {
130 arena_b.adj().array() += res.adj().array()
131 * arena_a.val().array()
132 / arena_b.val().array();
146template <
typename T1,
typename T2, require_var_matrix_t<T1>* =
nullptr,
147 require_stan_scalar_t<T2>* =
nullptr>
148inline auto lmultiply(
const T1& a,
const T2& b) {
151 if constexpr (is_autodiff_v<T1> && is_autodiff_v<T2>) {
157 [arena_a, arena_b](
const auto& res)
mutable {
158 arena_a.adj().array() += res.adj().array() * log(arena_b.val());
159 arena_b.adj() += (res.adj().array() * arena_a.val().array()).sum()
162 }
else if constexpr (is_autodiff_v<T1>) {
163 arena_t<promote_scalar_t<var, T1>> arena_a = a;
166 [arena_a, b](
const auto& res)
mutable {
167 arena_a.adj().array()
171 arena_t<promote_scalar_t<double, T1>> arena_a =
value_of(a);
176 [arena_a, arena_b](
const auto& res)
mutable {
178 += (res.adj().array() * arena_a.array()).sum() / arena_b.val();
192template <
typename T1,
typename T2, require_stan_scalar_t<T1>* =
nullptr,
193 require_var_matrix_t<T2>* =
nullptr>
194inline auto lmultiply(
const T1& a,
const T2& b) {
195 if constexpr (is_autodiff_v<T1> && is_autodiff_v<T2>) {
197 arena_t<promote_scalar_t<var, T2>> arena_b = b;
201 [arena_a, arena_b](
const auto& res)
mutable {
203 += (res.adj().array() * arena_b.val().array().log()).sum();
204 arena_b.adj().array()
205 += arena_a.val() * res.adj().array() / arena_b.val().array();
207 }
else if constexpr (is_autodiff_v<T1>) {
209 arena_t<promote_scalar_t<double, T2>> arena_b =
value_of(b);
213 [arena_a, arena_b](
const auto& res)
mutable {
215 += (res.adj().array() * arena_b.val().array().log()).sum();
218 arena_t<promote_scalar_t<var, T2>> arena_b = b;
221 [a, arena_b](
const auto& res)
mutable {
222 arena_b.adj().array() += value_of(a)
224 / arena_b.val().array();
lmultiply_dv_vari(double a, vari *bvi)
lmultiply_vd_vari(vari *avi, double b)
lmultiply_vv_vari(vari *avi, vari *bvi)
var_value< plain_type_t< T > > make_callback_var(T &&value, F &&functor)
Creates a new var initialized with a callback_vari with a given value and reverse-pass callback funct...
T value_of(const fvar< T > &v)
Return the value of the specified variable.
fvar< T > log(const fvar< T > &x)
fvar< T > lmultiply(const fvar< T > &x1, const fvar< T > &x2)
void check_matching_dims(const char *function, const char *name1, const T1 &y1, const char *name2, const T2 &y2)
Check if the two containers have the same dimensions.
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 ...