Automatic Differentiation
 
Loading...
Searching...
No Matches
lmultiply.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_REV_FUN_LMULTPLY_HPP
2#define STAN_MATH_REV_FUN_LMULTPLY_HPP
3
9#include <cmath>
10
11namespace stan {
12namespace math {
13
14namespace internal {
16 public:
18 : op_vv_vari(lmultiply(avi->val_, bvi->val_), avi, bvi) {}
19 void chain() {
20 using std::log;
21 avi_->adj_ += adj_ * log(bvi_->val_);
22 bvi_->adj_ += adj_ * avi_->val_ / bvi_->val_;
23 }
24};
26 public:
27 lmultiply_vd_vari(vari* avi, double b)
28 : op_vd_vari(lmultiply(avi->val_, b), avi, b) {}
29 void chain() {
30 using std::log;
31 avi_->adj_ += adj_ * log(bd_);
32 }
33};
35 public:
36 lmultiply_dv_vari(double a, vari* bvi)
37 : op_dv_vari(lmultiply(a, bvi->val_), a, bvi) {}
38 void chain() { bvi_->adj_ += adj_ * ad_ / bvi_->val_; }
39};
40} // namespace internal
41
53inline var lmultiply(const var& a, const var& b) {
54 return var(new internal::lmultiply_vv_vari(a.vi_, b.vi_));
55}
66inline var lmultiply(const var& a, double b) {
67 return var(new internal::lmultiply_vd_vari(a.vi_, b));
68}
79inline var lmultiply(double a, const var& b) {
80 if (a == 1.0) {
81 return log(b);
82 }
83 return var(new internal::lmultiply_dv_vari(a, b.vi_));
84}
85
98template <typename T1, typename T2, require_all_matrix_t<T1, T2>* = nullptr,
99 require_any_var_matrix_t<T1, T2>* = nullptr>
100inline auto lmultiply(const T1& a, const T2& b) {
101 check_matching_dims("lmultiply", "a", a, "b", b);
102 if constexpr (is_autodiff_v<T1> && is_autodiff_v<T2>) {
105
106 return make_callback_var(
107 lmultiply(arena_a.val(), arena_b.val()),
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();
113 });
114 } else if constexpr (is_autodiff_v<T1>) {
117
118 return make_callback_var(lmultiply(arena_a.val(), arena_b),
119 [arena_a, arena_b](const auto& res) mutable {
120 arena_a.adj().array()
121 += res.adj().array()
122 * arena_b.val().array().log();
123 });
124 } else {
127
128 return make_callback_var(lmultiply(arena_a, arena_b.val()),
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();
133 });
134 }
135}
136
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) {
149 using std::log;
150
151 if constexpr (is_autodiff_v<T1> && is_autodiff_v<T2>) {
153 var arena_b = b;
154
155 return make_callback_var(
156 lmultiply(arena_a.val(), arena_b.val()),
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()
160 / arena_b.val();
161 });
162 } else if constexpr (is_autodiff_v<T1>) {
163 arena_t<promote_scalar_t<var, T1>> arena_a = a;
164
165 return make_callback_var(lmultiply(arena_a.val(), value_of(b)),
166 [arena_a, b](const auto& res) mutable {
167 arena_a.adj().array()
168 += res.adj().array() * log(value_of(b));
169 });
170 } else {
171 arena_t<promote_scalar_t<double, T1>> arena_a = value_of(a);
172 var arena_b = b;
173
174 return make_callback_var(
175 lmultiply(arena_a, arena_b.val()),
176 [arena_a, arena_b](const auto& res) mutable {
177 arena_b.adj()
178 += (res.adj().array() * arena_a.array()).sum() / arena_b.val();
179 });
180 }
181}
182
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>) {
196 var arena_a = a;
197 arena_t<promote_scalar_t<var, T2>> arena_b = b;
198
199 return make_callback_var(
200 lmultiply(arena_a.val(), arena_b.val()),
201 [arena_a, arena_b](const auto& res) mutable {
202 arena_a.adj()
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();
206 });
207 } else if constexpr (is_autodiff_v<T1>) {
208 var arena_a = a;
209 arena_t<promote_scalar_t<double, T2>> arena_b = value_of(b);
210
211 return make_callback_var(
212 lmultiply(arena_a.val(), arena_b),
213 [arena_a, arena_b](const auto& res) mutable {
214 arena_a.adj()
215 += (res.adj().array() * arena_b.val().array().log()).sum();
216 });
217 } else {
218 arena_t<promote_scalar_t<var, T2>> arena_b = b;
219
220 return make_callback_var(lmultiply(value_of(a), arena_b.val()),
221 [a, arena_b](const auto& res) mutable {
222 arena_b.adj().array() += value_of(a)
223 * res.adj().array()
224 / arena_b.val().array();
225 });
226 }
227}
228
229} // namespace math
230} // namespace stan
231#endif
lmultiply_vv_vari(vari *avi, vari *bvi)
Definition lmultiply.hpp:17
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.
Definition value_of.hpp:18
fvar< T > log(const fvar< T > &x)
Definition log.hpp:18
fvar< T > lmultiply(const fvar< T > &x1, const fvar< T > &x2)
Definition lmultiply.hpp:14
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.
var_value< double > var
Definition var.hpp:1187
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 ...