Automatic Differentiation
 
Loading...
Searching...
No Matches
trace_gen_quad_form.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_REV_FUN_TRACE_GEN_QUAD_FORM_HPP
2#define STAN_MATH_REV_FUN_TRACE_GEN_QUAD_FORM_HPP
3
12#include <type_traits>
13
14namespace stan {
15namespace math {
16namespace internal {
17
18template <typename Td, int Rd, int Cd, typename Ta, int Ra, int Ca, typename Tb,
19 int Rb, int Cb>
21 public:
22 trace_gen_quad_form_vari_alloc(const Eigen::Matrix<Td, Rd, Cd>& D,
23 const Eigen::Matrix<Ta, Ra, Ca>& A,
24 const Eigen::Matrix<Tb, Rb, Cb>& B)
25 : D_(D), A_(A), B_(B) {}
26
27 double compute() {
29 }
30
31 Eigen::Matrix<Td, Rd, Cd> D_;
32 Eigen::Matrix<Ta, Ra, Ca> A_;
33 Eigen::Matrix<Tb, Rb, Cb> B_;
34};
35
36template <typename Td, int Rd, int Cd, typename Ta, int Ra, int Ca, typename Tb,
37 int Rb, int Cb>
39 protected:
40 static inline void computeAdjoints(double adj,
41 const Eigen::Matrix<double, Rd, Cd>& D,
42 const Eigen::Matrix<double, Ra, Ca>& A,
43 const Eigen::Matrix<double, Rb, Cb>& B,
44 Eigen::Matrix<var, Rd, Cd>* varD,
45 Eigen::Matrix<var, Ra, Ca>* varA,
46 Eigen::Matrix<var, Rb, Cb>* varB) {
47 Eigen::Matrix<double, Ca, Cb> AtB;
48 Eigen::Matrix<double, Ra, Cb> BD;
49 if (varB || varA) {
50 BD.noalias() = B * D;
51 }
52 if (varB || varD) {
53 AtB.noalias() = A.transpose() * B;
54 }
55
56 if (varB) {
57 (*varB).adj() += adj * (A * BD + AtB * D.transpose());
58 }
59 if (varA) {
60 (*varA).adj() += adj * (B * BD.transpose());
61 }
62 if (varD) {
63 (*varD).adj() += adj * (B.transpose() * AtB);
64 }
65 }
66
67 public:
70 : vari(impl->compute()), impl_(impl) {}
71
72 virtual void chain() {
74 value_of(impl_->B_),
75 reinterpret_cast<Eigen::Matrix<var, Rd, Cd>*>(
76 std::is_same<Td, var>::value ? (&impl_->D_) : NULL),
77 reinterpret_cast<Eigen::Matrix<var, Ra, Ca>*>(
78 std::is_same<Ta, var>::value ? (&impl_->A_) : NULL),
79 reinterpret_cast<Eigen::Matrix<var, Rb, Cb>*>(
80 std::is_same<Tb, var>::value ? (&impl_->B_) : NULL));
81 }
82
84};
85} // namespace internal
86
87template <typename Td, typename Ta, typename Tb,
91inline var trace_gen_quad_form(const Td& D, const Ta& A, const Tb& B) {
92 using Td_scal = value_type_t<Td>;
93 using Ta_scal = value_type_t<Ta>;
94 using Tb_scal = value_type_t<Tb>;
95 constexpr int Rd = Td::RowsAtCompileTime;
96 constexpr int Cd = Td::ColsAtCompileTime;
97 constexpr int Ra = Ta::RowsAtCompileTime;
98 constexpr int Ca = Ta::ColsAtCompileTime;
99 constexpr int Rb = Tb::RowsAtCompileTime;
100 constexpr int Cb = Tb::ColsAtCompileTime;
101 check_square("trace_gen_quad_form", "A", A);
102 check_square("trace_gen_quad_form", "D", D);
103 check_multiplicable("trace_gen_quad_form", "A", A, "B", B);
104 check_multiplicable("trace_gen_quad_form", "B", B, "D", D);
105
106 auto* baseVari
107 = new internal::trace_gen_quad_form_vari_alloc<Td_scal, Rd, Cd, Ta_scal,
108 Ra, Ca, Tb_scal, Rb, Cb>(
109 D, A, B);
110
111 return var(
112 new internal::trace_gen_quad_form_vari<Td_scal, Rd, Cd, Ta_scal, Ra, Ca,
113 Tb_scal, Rb, Cb>(baseVari));
114}
115
135template <typename Td, typename Ta, typename Tb,
138inline var trace_gen_quad_form(const Td& D, const Ta& A, const Tb& B) {
139 check_square("trace_gen_quad_form", "A", A);
140 check_square("trace_gen_quad_form", "D", D);
141 check_multiplicable("trace_gen_quad_form", "A", A, "B", B);
142 check_multiplicable("trace_gen_quad_form", "B", B, "D", D);
143
149
150 auto arena_BDT = to_arena(arena_B.val_op() * arena_D.val_op().transpose());
151 auto arena_AB = to_arena(arena_A.val_op() * arena_B.val_op());
152
153 var res = (arena_BDT.transpose() * arena_AB).trace();
154
156 [arena_A, arena_B, arena_D, arena_BDT, arena_AB, res]() mutable {
157 double C_adj = res.adj();
158
159 arena_A.adj() += C_adj * arena_BDT * arena_B.val_op().transpose();
160
161 arena_B.adj() += C_adj
162 * (arena_AB * arena_D.val_op()
163 + arena_A.val_op().transpose() * arena_BDT);
164
165 arena_D.adj() += C_adj * (arena_AB.transpose() * arena_B.val_op());
166 });
167
168 return res;
169 } else if (!is_constant<Ta>::value && !is_constant<Tb>::value
170 && is_constant<Td>::value) {
171 arena_t<promote_scalar_t<double, Td>> arena_D = value_of(D);
172 arena_t<promote_scalar_t<var, Ta>> arena_A = A;
173 arena_t<promote_scalar_t<var, Tb>> arena_B = B;
174
175 auto arena_BDT = to_arena(arena_B.val_op() * arena_D.transpose());
176 auto arena_AB = to_arena(arena_A.val_op() * arena_B.val_op());
177
178 var res = (arena_BDT.transpose() * arena_AB).trace();
179
180 reverse_pass_callback([arena_A, arena_B, arena_D, arena_BDT, arena_AB,
181 res]() mutable {
182 double C_adj = res.adj();
183
184 arena_A.adj() += C_adj * arena_BDT * arena_B.val_op().transpose();
185 arena_B.adj()
186 += C_adj
187 * (arena_AB * arena_D + arena_A.val_op().transpose() * arena_BDT);
188 });
189
190 return res;
191 } else if (!is_constant<Ta>::value && is_constant<Tb>::value
192 && !is_constant<Td>::value) {
193 arena_t<promote_scalar_t<var, Td>> arena_D = D;
194 arena_t<promote_scalar_t<var, Ta>> arena_A = A;
195 arena_t<promote_scalar_t<double, Tb>> arena_B = value_of(B);
196
197 auto arena_BDT = to_arena(arena_B.val_op() * arena_D.val_op().transpose());
198 auto arena_AB = to_arena(arena_A.val_op() * arena_B.val_op());
199
200 var res = (arena_BDT.transpose() * arena_A.val_op() * arena_B).trace();
201
203 [arena_A, arena_B, arena_D, arena_BDT, arena_AB, res]() mutable {
204 double C_adj = res.adj();
205
206 arena_A.adj() += C_adj * arena_BDT * arena_B.transpose();
207 arena_D.adj() += C_adj * arena_AB.transpose() * arena_B;
208 });
209
210 return res;
211 } else if (!is_constant<Ta>::value && is_constant<Tb>::value
212 && is_constant<Td>::value) {
213 arena_t<promote_scalar_t<double, Td>> arena_D = value_of(D);
214 arena_t<promote_scalar_t<var, Ta>> arena_A = A;
215 arena_t<promote_scalar_t<double, Tb>> arena_B = value_of(B);
216
217 auto arena_BDT = to_arena(arena_B * arena_D);
218
219 var res = (arena_BDT.transpose() * arena_A.val_op() * arena_B).trace();
220
221 reverse_pass_callback([arena_A, arena_B, arena_BDT, res]() mutable {
222 arena_A.adj() += res.adj() * arena_BDT * arena_B.val_op().transpose();
223 });
224
225 return res;
226 } else if (is_constant<Ta>::value && !is_constant<Tb>::value
227 && !is_constant<Td>::value) {
228 arena_t<promote_scalar_t<var, Td>> arena_D = D;
229 arena_t<promote_scalar_t<double, Ta>> arena_A = value_of(A);
230 arena_t<promote_scalar_t<var, Tb>> arena_B = B;
231
232 auto arena_AB = to_arena(arena_A * arena_B.val_op());
233 auto arena_BDT = to_arena(arena_B.val_op() * arena_D.val_op());
234
235 var res = (arena_BDT.transpose() * arena_AB).trace();
236
237 reverse_pass_callback([arena_A, arena_B, arena_D, arena_AB, arena_BDT,
238 res]() mutable {
239 double C_adj = res.adj();
240
241 arena_B.adj()
242 += C_adj
243 * (arena_AB * arena_D.val_op() + arena_A.transpose() * arena_BDT);
244
245 arena_D.adj() += C_adj * (arena_AB.transpose() * arena_B.val_op());
246 });
247
248 return res;
249 } else if (is_constant<Ta>::value && !is_constant<Tb>::value
250 && is_constant<Td>::value) {
251 arena_t<promote_scalar_t<double, Td>> arena_D = value_of(D);
252 arena_t<promote_scalar_t<double, Ta>> arena_A = value_of(A);
253 arena_t<promote_scalar_t<var, Tb>> arena_B = B;
254
255 auto arena_AB = to_arena(arena_A * arena_B.val_op());
256 auto arena_BDT = to_arena(arena_B.val_op() * arena_D.val_op());
257
258 var res = (arena_BDT.transpose() * arena_AB).trace();
259
261 [arena_A, arena_B, arena_D, arena_AB, arena_BDT, res]() mutable {
262 arena_B.adj() += res.adj()
263 * (arena_AB * arena_D.val_op()
264 + arena_A.val_op().transpose() * arena_BDT);
265 });
266
267 return res;
268 } else if (is_constant<Ta>::value && is_constant<Tb>::value
269 && !is_constant<Td>::value) {
270 arena_t<promote_scalar_t<var, Td>> arena_D = D;
271 arena_t<promote_scalar_t<double, Ta>> arena_A = value_of(A);
272 arena_t<promote_scalar_t<double, Tb>> arena_B = value_of(B);
273
274 auto arena_AB = to_arena(arena_A * arena_B);
275
276 var res = (arena_D.val_op() * arena_B.transpose() * arena_AB).trace();
277
278 reverse_pass_callback([arena_AB, arena_B, arena_D, res]() mutable {
279 arena_D.adj() += res.adj() * (arena_AB.transpose() * arena_B);
280 });
281
282 return res;
283 }
284}
285
286} // namespace math
287} // namespace stan
288#endif
A chainable_alloc is an object which is constructed and destructed normally but the memory lifespan i...
trace_gen_quad_form_vari_alloc(const Eigen::Matrix< Td, Rd, Cd > &D, const Eigen::Matrix< Ta, Ra, Ca > &A, const Eigen::Matrix< Tb, Rb, Cb > &B)
trace_gen_quad_form_vari(trace_gen_quad_form_vari_alloc< Td, Rd, Cd, Ta, Ra, Ca, Tb, Rb, Cb > *impl)
static void computeAdjoints(double adj, const Eigen::Matrix< double, Rd, Cd > &D, const Eigen::Matrix< double, Ra, Ca > &A, const Eigen::Matrix< double, Rb, Cb > &B, Eigen::Matrix< var, Rd, Cd > *varD, Eigen::Matrix< var, Ra, Ca > *varA, Eigen::Matrix< var, Rb, Cb > *varB)
trace_gen_quad_form_vari_alloc< Td, Rd, Cd, Ta, Ra, Ca, Tb, Rb, Cb > * impl_
require_all_t< is_eigen< std::decay_t< Types > >... > require_all_eigen_t
Require all of the types satisfy is_eigen.
Definition is_eigen.hpp:120
require_all_t< is_matrix< std::decay_t< Types > >... > require_all_matrix_t
Require all of the types satisfy is_matrix.
Definition is_matrix.hpp:38
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.
Definition is_var.hpp:39
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.
Definition value_of.hpp:18
value_type_t< T > trace(const T &m)
Calculates trace (sum of diagonal) of given kernel generator expression.
Definition trace.hpp:22
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...
Definition to_arena.hpp:25
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.
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 ...
Metaprogramming struct to detect whether a given type is constant in the mathematical sense (not the ...