Automatic Differentiation
 
Loading...
Searching...
No Matches
elt_divide.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_REV_FUN_ELT_DIVIDE_HPP
2#define STAN_MATH_REV_FUN_ELT_DIVIDE_HPP
3
10
11namespace stan {
12namespace math {
13
25template <typename Mat1, typename Mat2,
26 require_all_matrix_t<Mat1, Mat2>* = nullptr,
27 require_any_rev_matrix_t<Mat1, Mat2>* = nullptr>
28auto elt_divide(const Mat1& m1, const Mat2& m2) {
29 check_matching_dims("elt_divide", "m1", m1, "m2", m2);
30 using inner_ret_type
31 = decltype((value_of(m1).array() / value_of(m2).array()).matrix());
32 using ret_type = return_var_matrix_t<inner_ret_type, Mat1, Mat2>;
33 if (!is_constant<Mat1>::value && !is_constant<Mat2>::value) {
34 arena_t<promote_scalar_t<var, Mat1>> arena_m1 = m1;
35 arena_t<promote_scalar_t<var, Mat2>> arena_m2 = m2;
36 arena_t<ret_type> ret(arena_m1.val().array() / arena_m2.val().array());
37 reverse_pass_callback([ret, arena_m1, arena_m2]() mutable {
38 for (Eigen::Index j = 0; j < arena_m2.cols(); ++j) {
39 for (Eigen::Index i = 0; i < arena_m2.rows(); ++i) {
40 const auto ret_div
41 = ret.adj().coeff(i, j) / arena_m2.val().coeff(i, j);
42 arena_m1.adj().coeffRef(i, j) += ret_div;
43 arena_m2.adj().coeffRef(i, j) -= ret.val().coeff(i, j) * ret_div;
44 }
45 }
46 });
47 return ret_type(ret);
48 } else if (!is_constant<Mat1>::value) {
49 arena_t<promote_scalar_t<var, Mat1>> arena_m1 = m1;
50 arena_t<promote_scalar_t<double, Mat2>> arena_m2 = value_of(m2);
51 arena_t<ret_type> ret(arena_m1.val().array() / arena_m2.array());
52 reverse_pass_callback([ret, arena_m1, arena_m2]() mutable {
53 arena_m1.adj().array() += ret.adj().array() / arena_m2.array();
54 });
55 return ret_type(ret);
56 } else if (!is_constant<Mat2>::value) {
57 arena_t<promote_scalar_t<double, Mat1>> arena_m1 = value_of(m1);
58 arena_t<promote_scalar_t<var, Mat2>> arena_m2 = m2;
59 arena_t<ret_type> ret(arena_m1.array() / arena_m2.val().array());
60 reverse_pass_callback([ret, arena_m2, arena_m1]() mutable {
61 arena_m2.adj().array()
62 -= ret.val().array() * ret.adj().array() / arena_m2.val().array();
63 });
64 return ret_type(ret);
65 }
66}
67
79template <typename Scal, typename Mat, require_stan_scalar_t<Scal>* = nullptr,
80 require_var_matrix_t<Mat>* = nullptr>
81auto elt_divide(Scal s, const Mat& m) {
82 plain_type_t<Mat> res = value_of(s) / m.val().array();
83
84 reverse_pass_callback([m, s, res]() mutable {
85 m.adj().array() -= res.val().array() * res.adj().array() / m.val().array();
86 if (!is_constant<Scal>::value)
87 forward_as<var>(s).adj() += (res.adj().array() / m.val().array()).sum();
88 });
89
90 return res;
91}
92
93} // namespace math
94} // namespace stan
95
96#endif
elt_divide_< as_operation_cl_t< T_a >, as_operation_cl_t< T_b > > elt_divide(T_a &&a, T_b &&b)
void reverse_pass_callback(F &&functor)
Puts a callback on the autodiff stack to be called in reverse pass.
T value_of(const fvar< T > &v)
Return the value of the specified variable.
Definition value_of.hpp:18
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.
auto sum(const std::vector< T > &m)
Return the sum of the entries of the specified standard vector.
Definition sum.hpp:23
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...