Automatic Differentiation
 
Loading...
Searching...
No Matches
operands_and_partials.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_FWD_META_OPERANDS_AND_PARTIALS_HPP
2#define STAN_MATH_FWD_META_OPERANDS_AND_PARTIALS_HPP
3
16#include <vector>
17
18namespace stan {
19namespace math {
20namespace internal {
21
25static constexpr auto sum_dx() { return static_cast<double>(0.0); }
26
36template <typename... Types>
37inline constexpr auto sum_dx(Types&... args) {
38 return (args.dx() + ...);
39}
40
41template <typename InnerType, typename T>
42class ops_partials_edge<InnerType, T, require_fvar_t<T>> {
43 public:
44 using Op = std::decay_t<T>;
45 using Dx = std::decay_t<InnerType>;
46 Dx partial_{0};
47 broadcast_array<Dx> partials_{partial_};
48
49 explicit ops_partials_edge(const T& op)
50 : partial_(0), partials_(partial_), operands_(op) {}
51
53 const ops_partials_edge<InnerType, T, require_fvar_t<T>>& other)
54 : partial_(other.partial_),
55 partials_(partial_),
56 operands_(other.operands_) {}
57
59 ops_partials_edge<InnerType, T, require_fvar_t<T>>&& other)
60 : partial_(other.partial_),
61 partials_(partial_),
62 operands_(other.operands_) {}
63
64 const Op& operands_;
65
66 inline Dx dx() { return this->partial_ * this->operands_.d_; }
67};
68
69// Vectorized Univariate
70template <typename InnerType, typename T>
72 public:
73 using Op = std::decay_t<T>;
74 using Dx = std::decay_t<InnerType>;
75 using partials_t = Eigen::Matrix<Dx, -1, 1>;
76 partials_t partials_; // For univariate use-cases
77 broadcast_array<partials_t> partials_vec_{partials_}; // For multivariate
78 explicit ops_partials_edge(const Op& ops)
79 : partials_(partials_t::Zero(ops.size()).eval()), operands_(ops) {}
80
83 other)
84 : partials_(other.partials_),
85 partials_vec_(partials_),
86 operands_(other.operands_) {}
87
90 other)
91 : partials_(std::move(other.partials_)),
92 partials_vec_(partials_),
93 operands_(other.operands_) {}
94
95 const Op& operands_;
96 inline Dx dx() {
97 return dot_product(as_column_vector_or_scalar(this->partials_),
98 as_column_vector_or_scalar(this->operands_).d());
99 }
100};
101
102template <typename Dx, typename ViewElt>
103class ops_partials_edge<Dx, ViewElt, require_eigen_vt<is_fvar, ViewElt>> {
104 public:
107 partials_t partials_; // For univariate use-cases
108 broadcast_array<partials_t> partials_vec_{partials_}; // For multivariate
109 template <typename OpT, require_eigen_vt<is_fvar, OpT>* = nullptr>
110 explicit ops_partials_edge(const OpT& ops)
111 : partials_(partials_t::Zero(ops.rows(), ops.cols())), operands_(ops) {}
112
115 other)
116 : partials_(other.partials_),
117 partials_vec_(partials_),
118 operands_(other.operands_) {}
119
122 other)
123 : partials_(std::move(other.partials_)),
124 partials_vec_(partials_),
125 operands_(other.operands_) {}
126
128
129 inline Dx dx() {
130 return sum(elt_multiply(this->partials_, this->operands_.d()));
131 }
132};
133
134// Multivariate; vectors of eigen types
135template <typename Dx, int R, int C>
136class ops_partials_edge<Dx, std::vector<Eigen::Matrix<fvar<Dx>, R, C>>> {
137 public:
138 using Op = std::vector<Eigen::Matrix<fvar<Dx>, R, C>>;
139 using partial_t = Eigen::Matrix<Dx, R, C>;
140 std::vector<partial_t> partials_vec_;
141 explicit ops_partials_edge(const Op& ops)
142 : partials_vec_(ops.size()), operands_(ops) {
143 for (size_t i = 0; i < ops.size(); ++i) {
144 partials_vec_[i] = partial_t::Zero(ops[i].rows(), ops[i].cols());
145 }
146 }
147
149
150 inline Dx dx() {
151 Dx derivative(0);
152 for (size_t i = 0; i < this->operands_.size(); ++i) {
154 += sum(elt_multiply(this->partials_vec_[i], this->operands_[i].d()));
155 }
156 return derivative;
157 }
158};
159
160template <typename Dx>
161class ops_partials_edge<Dx, std::vector<std::vector<fvar<Dx>>>> {
162 public:
163 using Op = std::vector<std::vector<fvar<Dx>>>;
164 using partial_t = std::vector<Dx>;
165 std::vector<partial_t> partials_vec_;
166 explicit ops_partials_edge(const Op& ops)
167 : partials_vec_(stan::math::size(ops)), operands_(ops) {
168 for (size_t i = 0; i < stan::math::size(ops); ++i) {
169 partials_vec_[i] = partial_t(stan::math::size(ops[i]), 0.0);
170 }
171 }
172
174 inline Dx dx() {
175 Dx derivative(0);
176 for (size_t i = 0; i < this->operands_.size(); ++i) {
177 for (size_t j = 0; j < this->operands_[i].size(); ++j) {
178 derivative += this->partials_vec_[i][j] * this->operands_[i][j].d_;
179 }
180 }
181 return derivative;
182 }
183};
184
185} // namespace internal
186
226template <typename Op1, typename Op2, typename Op3, typename Op4, typename Op5,
227 typename Op6, typename Op7, typename Op8, typename Dx>
228class operands_and_partials<Op1, Op2, Op3, Op4, Op5, Op6, Op7, Op8, fvar<Dx>> {
229 public:
239 explicit operands_and_partials(const Op1& o1) : edge1_(o1) {}
240 operands_and_partials(const Op1& o1, const Op2& o2)
241 : edge1_(o1), edge2_(o2) {}
242 operands_and_partials(const Op1& o1, const Op2& o2, const Op3& o3)
243 : edge1_(o1), edge2_(o2), edge3_(o3) {}
244 operands_and_partials(const Op1& o1, const Op2& o2, const Op3& o3,
245 const Op4& o4)
246 : edge1_(o1), edge2_(o2), edge3_(o3), edge4_(o4) {}
247 operands_and_partials(const Op1& o1, const Op2& o2, const Op3& o3,
248 const Op4& o4, const Op5& o5)
249 : edge1_(o1), edge2_(o2), edge3_(o3), edge4_(o4), edge5_(o5) {}
250 operands_and_partials(const Op1& o1, const Op2& o2, const Op3& o3,
251 const Op4& o4, const Op5& o5, const Op6& o6)
252 : edge1_(o1),
253 edge2_(o2),
254 edge3_(o3),
255 edge4_(o4),
256 edge5_(o5),
257 edge6_(o6) {}
258 operands_and_partials(const Op1& o1, const Op2& o2, const Op3& o3,
259 const Op4& o4, const Op5& o5, const Op6& o6,
260 const Op7& o7)
261 : edge1_(o1),
262 edge2_(o2),
263 edge3_(o3),
264 edge4_(o4),
265 edge5_(o5),
266 edge6_(o6),
267 edge7_(o7) {}
268 operands_and_partials(const Op1& o1, const Op2& o2, const Op3& o3,
269 const Op4& o4, const Op5& o5, const Op6& o6,
270 const Op7& o7, const Op8& o8)
271 : edge1_(o1),
272 edge2_(o2),
273 edge3_(o3),
274 edge4_(o4),
275 edge5_(o5),
276 edge6_(o6),
277 edge7_(o7),
278 edge8_(o8) {}
279
294 Dx deriv = edge1_.dx() + edge2_.dx() + edge3_.dx() + edge4_.dx()
295 + edge5_.dx() + edge6_.dx() + edge7_.dx() + edge8_.dx();
296 return T_return_type(value, deriv);
297 }
298};
299
300} // namespace math
301} // namespace stan
302#endif
ops_partials_edge(ops_partials_edge< Dx, ViewElt, require_eigen_vt< is_fvar, ViewElt > > &&other)
ops_partials_edge(const ops_partials_edge< Dx, ViewElt, require_eigen_vt< is_fvar, ViewElt > > &other)
ops_partials_edge(ops_partials_edge< InnerType, T, require_fvar_t< T > > &&other)
ops_partials_edge(const ops_partials_edge< InnerType, T, require_fvar_t< T > > &other)
ops_partials_edge(ops_partials_edge< InnerType, T, require_std_vector_vt< is_fvar, T > > &&other)
ops_partials_edge(const ops_partials_edge< InnerType, T, require_std_vector_vt< is_fvar, T > > &other)
An edge holds both the operands and its associated partial derivatives.
operands_and_partials(const Op1 &o1, const Op2 &o2, const Op3 &o3, const Op4 &o4, const Op5 &o5, const Op6 &o6)
operands_and_partials(const Op1 &o1, const Op2 &o2, const Op3 &o3, const Op4 &o4, const Op5 &o5, const Op6 &o6, const Op7 &o7, const Op8 &o8)
operands_and_partials(const Op1 &o1, const Op2 &o2, const Op3 &o3, const Op4 &o4, const Op5 &o5, const Op6 &o6, const Op7 &o7)
operands_and_partials(const Op1 &o1, const Op2 &o2, const Op3 &o3, const Op4 &o4, const Op5 &o5)
This template builds partial derivatives with respect to a set of operands.
require_t< container_type_check_base< is_eigen, value_type_t, TypeCheck, Check... > > require_eigen_vt
Require type satisfies is_eigen.
Definition is_eigen.hpp:155
require_t< is_fvar< std::decay_t< T > > > require_fvar_t
Require type satisfies is_fvar.
Definition is_fvar.hpp:37
elt_multiply_< as_operation_cl_t< T_a >, as_operation_cl_t< T_b > > elt_multiply(T_a &&a, T_b &&b)
auto as_column_vector_or_scalar(T &&a)
as_column_vector_or_scalar of a kernel generator expression.
int64_t cols(const T_x &x)
Returns the number of columns in the specified kernel generator expression.
Definition cols.hpp:21
int64_t rows(const T_x &x)
Returns the number of rows in the specified kernel generator expression.
Definition rows.hpp:22
require_t< container_type_check_base< is_std_vector, value_type_t, TypeCheck, Check... > > require_std_vector_vt
Require type satisfies is_std_vector.
T_return_type build(Dx value)
Build the node to be stored on the autodiff graph.
int64_t size(const T &m)
Returns the size (number of the elements) of a matrix_cl or var_value<matrix_cl<T>>.
Definition size.hpp:19
static constexpr auto sum_dx()
End of recursion for summing .dx() for fvar<T> ops and partials.
void derivative(const F &f, const T &x, T &fx, T &dfx_dx)
Return the derivative of the specified univariate function at the specified argument.
typename promote_scalar_type< std::decay_t< T >, std::decay_t< S > >::type promote_scalar_t
T eval(T &&arg)
Inputs which have a plain_type equal to the own time are forwarded unmodified (for Eigen expressions ...
Definition eval.hpp:20
auto sum(const std::vector< T > &m)
Return the sum of the entries of the specified standard vector.
Definition sum.hpp:23
auto dot_product(const T_a &a, const T_b &b)
Returns the dot product of the specified vectors.
typename plain_type< std::decay_t< T > >::type plain_type_t
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...
STL namespace.
Defines a static member function type which is defined to be false as the primitive scalar types cann...
Definition is_fvar.hpp:15
This template class represents scalars used in forward-mode automatic differentiation,...
Definition fvar.hpp:40