1#ifndef STAN_MATH_REV_FUN_TRACE_GEN_QUAD_FORM_HPP
2#define STAN_MATH_REV_FUN_TRACE_GEN_QUAD_FORM_HPP
19template <
typename Td,
int Rd,
int Cd,
typename Ta,
int Ra,
int Ca,
typename Tb,
24 const Eigen::Matrix<Ta, Ra, Ca>& A,
25 const Eigen::Matrix<Tb, Rb, Cb>& B)
32 Eigen::Matrix<Td, Rd, Cd>
D_;
33 Eigen::Matrix<Ta, Ra, Ca>
A_;
34 Eigen::Matrix<Tb, Rb, Cb>
B_;
37template <
typename Td,
int Rd,
int Cd,
typename Ta,
int Ra,
int Ca,
typename Tb,
42 const Eigen::Matrix<double, Rd, Cd>& D,
43 const Eigen::Matrix<double, Ra, Ca>& A,
44 const Eigen::Matrix<double, Rb, Cb>& B,
45 Eigen::Matrix<var, Rd, Cd>* varD,
46 Eigen::Matrix<var, Ra, Ca>* varA,
47 Eigen::Matrix<var, Rb, Cb>* varB) {
48 Eigen::Matrix<double, Ca, Cb> AtB;
49 Eigen::Matrix<double, Ra, Cb> BD;
54 AtB.noalias() = A.transpose() * B;
58 (*varB).adj() += adj * (A * BD + AtB * D.transpose());
61 (*varA).adj() += adj * (B * BD.transpose());
64 (*varD).adj() += adj * (B.transpose() * AtB);
76 reinterpret_cast<Eigen::Matrix<var, Rd, Cd>*
>(
77 std::is_same<Td, var>::value ? (&
impl_->D_) : NULL),
78 reinterpret_cast<Eigen::Matrix<var, Ra, Ca>*
>(
79 std::is_same<Ta, var>::value ? (&
impl_->A_) : NULL),
80 reinterpret_cast<Eigen::Matrix<var, Rb, Cb>*
>(
81 std::is_same<Tb, var>::value ? (&
impl_->B_) : NULL));
88template <
typename Td,
typename Ta,
typename Tb,
96 constexpr int Rd = Td::RowsAtCompileTime;
97 constexpr int Cd = Td::ColsAtCompileTime;
98 constexpr int Ra = Ta::RowsAtCompileTime;
99 constexpr int Ca = Ta::ColsAtCompileTime;
100 constexpr int Rb = Tb::RowsAtCompileTime;
101 constexpr int Cb = Tb::ColsAtCompileTime;
109 Ra, Ca, Tb_scal, Rb, Cb>(
114 Tb_scal, Rb, Cb>(baseVari));
136template <
typename Td,
typename Ta,
typename Tb,
151 auto arena_BDT =
to_arena(arena_B.val_op() * arena_D.val_op().transpose());
152 auto arena_AB =
to_arena(arena_A.val_op() * arena_B.val_op());
154 var res = (arena_BDT.transpose() * arena_AB).
trace();
157 [arena_A, arena_B, arena_D, arena_BDT, arena_AB, res]()
mutable {
158 double C_adj = res.adj();
160 arena_A.adj() += C_adj * arena_BDT * arena_B.val_op().transpose();
162 arena_B.adj() += C_adj
163 * (arena_AB * arena_D.val_op()
164 + arena_A.val_op().transpose() * arena_BDT);
166 arena_D.adj() += C_adj * (arena_AB.transpose() * arena_B.val_op());
170 }
else if (!is_constant<Ta>::value && !is_constant<Tb>::value
171 && is_constant<Td>::value) {
172 arena_t<promote_scalar_t<double, Td>> arena_D =
value_of(D);
173 arena_t<promote_scalar_t<var, Ta>> arena_A = A;
174 arena_t<promote_scalar_t<var, Tb>> arena_B = B;
176 auto arena_BDT =
to_arena(arena_B.val_op() * arena_D.transpose());
177 auto arena_AB =
to_arena(arena_A.val_op() * arena_B.val_op());
179 var res = (arena_BDT.transpose() * arena_AB).
trace();
183 double C_adj = res.adj();
185 arena_A.adj() += C_adj * arena_BDT * arena_B.val_op().transpose();
188 * (arena_AB * arena_D + arena_A.val_op().transpose() * arena_BDT);
192 }
else if (!is_constant<Ta>::value && is_constant<Tb>::value
193 && !is_constant<Td>::value) {
194 arena_t<promote_scalar_t<var, Td>> arena_D = D;
195 arena_t<promote_scalar_t<var, Ta>> arena_A = A;
196 arena_t<promote_scalar_t<double, Tb>> arena_B =
value_of(B);
198 auto arena_BDT =
to_arena(arena_B.val_op() * arena_D.val_op().transpose());
199 auto arena_AB =
to_arena(arena_A.val_op() * arena_B.val_op());
201 var res = (arena_BDT.transpose() * arena_A.val_op() * arena_B).
trace();
204 [arena_A, arena_B, arena_D, arena_BDT, arena_AB, res]()
mutable {
205 double C_adj = res.adj();
207 arena_A.adj() += C_adj * arena_BDT * arena_B.transpose();
208 arena_D.adj() += C_adj * arena_AB.transpose() * arena_B;
212 }
else if (!is_constant<Ta>::value && is_constant<Tb>::value
213 && is_constant<Td>::value) {
214 arena_t<promote_scalar_t<double, Td>> arena_D =
value_of(D);
215 arena_t<promote_scalar_t<var, Ta>> arena_A = A;
216 arena_t<promote_scalar_t<double, Tb>> arena_B =
value_of(B);
218 auto arena_BDT =
to_arena(arena_B * arena_D);
220 var res = (arena_BDT.transpose() * arena_A.val_op() * arena_B).
trace();
223 arena_A.adj() += res.adj() * arena_BDT * arena_B.val_op().transpose();
227 }
else if (is_constant<Ta>::value && !is_constant<Tb>::value
228 && !is_constant<Td>::value) {
229 arena_t<promote_scalar_t<var, Td>> arena_D = D;
230 arena_t<promote_scalar_t<double, Ta>> arena_A =
value_of(A);
231 arena_t<promote_scalar_t<var, Tb>> arena_B = B;
233 auto arena_AB =
to_arena(arena_A * arena_B.val_op());
234 auto arena_BDT =
to_arena(arena_B.val_op() * arena_D.val_op());
236 var res = (arena_BDT.transpose() * arena_AB).
trace();
240 double C_adj = res.adj();
244 * (arena_AB * arena_D.val_op() + arena_A.transpose() * arena_BDT);
246 arena_D.adj() += C_adj * (arena_AB.transpose() * arena_B.val_op());
250 }
else if (is_constant<Ta>::value && !is_constant<Tb>::value
251 && is_constant<Td>::value) {
252 arena_t<promote_scalar_t<double, Td>> arena_D =
value_of(D);
253 arena_t<promote_scalar_t<double, Ta>> arena_A =
value_of(A);
254 arena_t<promote_scalar_t<var, Tb>> arena_B = B;
256 auto arena_AB =
to_arena(arena_A * arena_B.val_op());
257 auto arena_BDT =
to_arena(arena_B.val_op() * arena_D.val_op());
259 var res = (arena_BDT.transpose() * arena_AB).
trace();
262 [arena_A, arena_B, arena_D, arena_AB, arena_BDT, res]()
mutable {
263 arena_B.adj() += res.adj()
264 * (arena_AB * arena_D.val_op()
265 + arena_A.val_op().transpose() * arena_BDT);
269 }
else if (is_constant<Ta>::value && is_constant<Tb>::value
270 && !is_constant<Td>::value) {
271 arena_t<promote_scalar_t<var, Td>> arena_D = D;
272 arena_t<promote_scalar_t<double, Ta>> arena_A =
value_of(A);
273 arena_t<promote_scalar_t<double, Tb>> arena_B =
value_of(B);
275 auto arena_AB =
to_arena(arena_A * arena_B);
277 var res = (arena_D.val_op() * arena_B.transpose() * arena_AB).
trace();
280 arena_D.adj() += res.adj() * (arena_AB.transpose() * arena_B);
A chainable_alloc is an object which is constructed and destructed normally but the memory lifespan i...
require_all_t< is_eigen< std::decay_t< Types > >... > require_all_eigen_t
Require all of the types satisfy is_eigen.
require_all_t< is_matrix< std::decay_t< Types > >... > require_all_matrix_t
Require all of the types satisfy is_matrix.
typename value_type< T >::type value_type_t
Helper function for accessing underlying type.
require_any_t< is_var_matrix< std::decay_t< Types > >... > require_any_var_matrix_t
Require any of the types satisfy is_var_matrix.
require_any_t< is_var< std::decay_t< Types > >... > require_any_var_t
Require any of the types satisfy is_var.
void check_square(const char *function, const char *name, const T_y &y)
Check if the specified matrix is square.
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.
value_type_t< T > trace(const T &m)
Calculates trace (sum of diagonal) of given kernel generator expression.
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...
auto trace_gen_quad_form(const TD &D, const TA &A, const TB &B)
Return the trace of D times the quadratic form of B and A.
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 ...
Metaprogramming struct to detect whether a given type is constant in the mathematical sense (not the ...