1#ifndef STAN_MATH_REV_FUN_MULTIPLY_HPP
2#define STAN_MATH_REV_FUN_MULTIPLY_HPP
26template <
typename T1,
typename T2, require_all_matrix_t<T1, T2>* =
nullptr,
27 require_return_type_t<is_var, T1, T2>* =
nullptr,
28 require_not_row_and_col_vector_t<T1, T2>* =
nullptr>
34 auto arena_A_val =
to_arena(arena_A.val());
35 auto arena_B_val =
to_arena(arena_B.val());
41 [arena_A, arena_B, arena_A_val, arena_B_val, res]()
mutable {
43 arena_A.adj() += res.adj_op() * arena_B_val.transpose();
44 arena_B.adj() += arena_A_val.transpose() * res.adj_op();
46 auto res_adj = res.adj().eval();
47 arena_A.adj() += res_adj * arena_B_val.transpose();
48 arena_B.adj() += arena_A_val.transpose() * res_adj;
59 arena_B.adj() += arena_A.transpose() * res.adj_op();
70 arena_A.adj() += res.adj_op() * arena_B.transpose();
87template <
typename T1,
typename T2, require_all_matrix_t<T1, T2>* =
nullptr,
88 require_return_type_t<is_var, T1, T2>* =
nullptr,
89 require_row_and_col_vector_t<T1, T2>* =
nullptr>
97 var res = arena_A_val.dot(arena_B_val);
100 [arena_A, arena_B, arena_A_val, arena_B_val, res]()
mutable {
101 auto res_adj = res.adj();
102 arena_A.adj().array() += res_adj * arena_B_val.transpose().array();
103 arena_B.adj().array() += arena_A_val.transpose().array() * res_adj;
111 arena_B.adj().array() += arena_A_val.transpose().array() * res.adj();
119 arena_A.adj().array() += res.adj() * arena_B_val.transpose().array();
136template <
typename T1,
typename T2, require_not_matrix_t<T1>* =
nullptr,
137 require_matrix_t<T2>* =
nullptr,
138 require_return_type_t<is_var, T1, T2>* =
nullptr,
139 require_not_row_and_col_vector_t<T1, T2>* =
nullptr>
148 for (Eigen::Index j = 0; j < res.cols(); ++j) {
149 for (Eigen::Index i = 0; i < res.rows(); ++i) {
150 const auto res_adj = res.adj().coeffRef(i, j);
151 av.adj() += res_adj * arena_B.val().coeff(i, j);
152 arena_B.adj().coeffRef(i, j) += a_val * res_adj;
163 arena_B.adj().array() += val_a * res.adj().array();
172 av.adj() += (res.adj().array() * arena_B.array()).sum();
189template <
typename T1,
typename T2, require_matrix_t<T1>* =
nullptr,
190 require_not_matrix_t<T2>* =
nullptr,
191 require_any_st_var<T1, T2>* =
nullptr,
192 require_not_complex_t<value_type_t<T1>>* =
nullptr,
193 require_not_complex_t<value_type_t<T2>>* =
nullptr,
194 require_not_row_and_col_vector_t<T1, T2>* =
nullptr>
196 return multiply(std::forward<T2>(B), std::forward<T1>(A));
209template <
typename T1,
typename T2, require_any_var_matrix_t<T1, T2>* =
nullptr>
211 return multiply(std::forward<T1>(a), std::forward<T2>(b));
fvar< T > operator*(const fvar< T > &x, const fvar< T > &y)
Return the product of the two arguments.
void check_multiplicable(const char *function, const char *name1, const T1 &y1, const char *name2, const T2 &y2)
Check if the matrices can be multiplied.
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.
auto multiply(const Mat1 &m1, const Mat2 &m2)
Return the product of the specified matrices.
arena_t< T > to_arena(const T &a)
Converts given argument into a type that either has any dynamic allocation on AD stack or schedules i...
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.
std::conditional_t< is_any_var_matrix< ReturnType, Types... >::value, stan::math::var_value< stan::math::promote_scalar_t< double, plain_type_t< ReturnType > > >, stan::math::promote_scalar_t< stan::math::var_value< double >, plain_type_t< ReturnType > > > return_var_matrix_t
Given an Eigen type and several inputs, determine if a matrix should be var<Matrix> or Matrix<var>.
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...
Metaprogramming struct to detect whether a given type is constant in the mathematical sense (not the ...
Check if a type is a var_value whose value_type is derived from Eigen::EigenBase