Automatic Differentiation
 
Loading...
Searching...
No Matches
holder.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_PRIM_FUN_HOLDER_HPP
2#define STAN_MATH_PRIM_FUN_HOLDER_HPP
3
7#include <memory>
8#include <type_traits>
9#include <utility>
63// This was implemented following the tutorial on edding new expressions to
64// Eigen: https://eigen.tuxfamily.org/dox/TopicNewExpressionType.html
65
66namespace stan {
67namespace math {
68
69template <class ArgType, typename... Ptrs>
70class Holder;
71
72} // namespace math
73} // namespace stan
74
75namespace Eigen {
76namespace internal {
77
78template <class ArgType, typename... Ptrs>
79struct traits<stan::math::Holder<ArgType, Ptrs...>> {
80 typedef typename ArgType::StorageKind StorageKind;
82 typedef typename ArgType::StorageIndex StorageIndex;
83 typedef typename ArgType::Scalar Scalar;
84 enum {
85 // Possible flags are documented here:
86 // https://eigen.tuxfamily.org/dox/group__flags.html
87 Flags = (ArgType::Flags
88 & (RowMajorBit | LvalueBit | LinearAccessBit | DirectAccessBit
89 | PacketAccessBit | NoPreferredStorageOrderBit))
90 | NestByRefBit,
91 RowsAtCompileTime = ArgType::RowsAtCompileTime,
92 ColsAtCompileTime = ArgType::ColsAtCompileTime,
93 MaxRowsAtCompileTime = ArgType::MaxRowsAtCompileTime,
94 MaxColsAtCompileTime = ArgType::MaxColsAtCompileTime,
95 InnerStrideAtCompileTime = ArgType::InnerStrideAtCompileTime,
96 OuterStrideAtCompileTime = ArgType::OuterStrideAtCompileTime
97 };
98};
99
100} // namespace internal
101} // namespace Eigen
102
103namespace stan {
104namespace internal {
105template <typename T>
106struct is_holder : std::false_type {};
107template <typename ArgType, typename... Ptrs>
108struct is_holder<stan::math::Holder<ArgType, Ptrs...>> : std::true_type {};
109} // namespace internal
110
111template <typename T>
112struct is_holder : internal::is_holder<std::decay_t<T>> {};
113
114template <typename T>
115inline constexpr bool is_holder_v = is_holder<T>::value;
116
117template <typename T>
119
120namespace math {
121
122template <
123 typename F, typename... Args,
124 require_not_plain_type_t<std::invoke_result_t<F, Args&&...>>* = nullptr>
125inline auto make_holder(F&& func, Args&&... args);
126
137template <typename F, typename... Args,
138 require_plain_type_t<std::invoke_result_t<F, Args&&...>>* = nullptr>
139inline auto make_holder(F&& func, Args&&... args);
147template <typename ArgType, typename... Ptrs>
149 : public Eigen::internal::dense_xpr_base<Holder<ArgType, Ptrs...>>::type {
150 public:
151 typedef typename Eigen::internal::ref_selector<Holder<ArgType, Ptrs...>>::type
153 typename Eigen::internal::ref_selector<ArgType>::non_const_type m_arg;
154 std::tuple<std::unique_ptr<Ptrs>...> m_unique_ptrs;
155 explicit Holder(ArgType&& arg, Ptrs*... pointers)
156 : m_arg(std::forward<ArgType>(arg)),
157 m_unique_ptrs(std::unique_ptr<Ptrs>(pointers)...) {}
158
159 // we need to explicitly default copy and move constructors as we are
160 // defining copy and move assignment operators
163
164 // all these functions just call the same on the argument
165 Eigen::Index rows() const { return m_arg.rows(); }
166 Eigen::Index cols() const { return m_arg.cols(); }
167 Eigen::Index innerStride() const { return m_arg.innerStride(); }
168 Eigen::Index outerStride() const { return m_arg.outerStride(); }
169 auto* data() { return m_arg.data(); }
170 const auto* data() const { return m_arg.data(); }
171
172 const auto& coeffRef(Eigen::Index row, Eigen::Index col) const {
173 return m_arg.coeffRef(row, col);
174 }
175 const auto& coeffRef(Eigen::Index index) const {
176 return m_arg.coeffRef(index);
177 }
178
184 template <typename T, require_eigen_t<T>* = nullptr>
185 inline Holder<ArgType, Ptrs...>& operator=(const T& other) {
186 m_arg = other;
187 return *this;
188 }
189
190 // copy and move assignment operators need to be separately overloaded,
191 // otherwise defaults will be used.
192 inline Holder<ArgType, Ptrs...>& operator=(
193 const Holder<ArgType, Ptrs...>& other) {
194 m_arg = other;
195 return *this;
196 }
197 inline Holder<ArgType, Ptrs...>& operator=(Holder<ArgType, Ptrs...>&& other) {
198 m_arg = std::move(other.m_arg);
199 return *this;
200 }
201};
202
203template <typename T, require_holder_t<T>* = nullptr>
204inline auto operator-(T&& h) {
205 return make_holder([](auto&& arg) { return -arg; }, std::forward<T>(h).m_arg);
206}
207template <typename T, require_holder_t<T>* = nullptr>
208inline auto operator+(T&& h) {
209 return make_holder([](auto&& arg) { return arg; }, std::forward<T>(h).m_arg);
210}
211
212template <typename T, typename Other, require_holder_t<T>* = nullptr,
213 require_holder_t<Other>* = nullptr>
214inline auto operator-(T&& h, Other&& other) {
215 return make_holder(
216 [](auto&& arg, auto&& other_) {
217 return arg - std::forward<decltype(other_)>(other_);
218 },
219 std::forward<T>(h).m_arg, std::forward<Other>(other));
220}
221template <typename T, typename Other, require_holder_t<T>* = nullptr,
222 require_holder_t<Other>* = nullptr>
223inline auto operator+(T&& h, Other&& other) {
224 return make_holder(
225 [](auto&& arg, auto&& other_) {
226 return arg + std::forward<decltype(other_)>(other_);
227 },
228 std::forward<T>(h).m_arg, std::forward<Other>(other));
229}
230template <typename T, typename Other, require_holder_t<T>* = nullptr,
231 require_holder_t<Other>* = nullptr>
232inline auto operator*(T&& h, Other&& other) {
233 return make_holder(
234 [](auto&& arg, auto&& other_) {
235 return arg * std::forward<decltype(other_)>(other_);
236 },
237 std::forward<T>(h).m_arg, std::forward<Other>(other));
238}
239template <typename T, typename Other, require_holder_t<T>* = nullptr,
240 require_holder_t<Other>* = nullptr>
241inline auto operator/(T&& h, Other&& other) {
242 return make_holder(
243 [](auto&& arg, auto&& other_) {
244 return arg / std::forward<decltype(other_)>(other_);
245 },
246 std::forward<T>(h).m_arg, std::forward<Other>(other));
247}
248
249} // namespace math
250} // namespace stan
251
252namespace Eigen {
253namespace internal {
254
255template <typename ArgType, typename... Ptrs>
256struct evaluator<stan::math::Holder<ArgType, Ptrs...>>
257 : evaluator_base<stan::math::Holder<ArgType, Ptrs...>> {
258 using PlainObjectType = stan::math::Holder<ArgType, Ptrs...>;
259 using XprType = stan::math::Holder<ArgType, Ptrs...>;
260 using ArgTypeNestedCleaned = typename remove_all<ArgType>::type;
261 using CoeffReturnType = typename XprType::CoeffReturnType;
262 using Scalar = typename XprType::Scalar;
263 enum {
264 IsRowMajor = XprType::IsRowMajor,
265 IsColMajor = !IsRowMajor,
266 IsVectorAtCompileTime = XprType::IsVectorAtCompileTime,
267 RowsAtCompileTime = XprType::RowsAtCompileTime,
268 ColsAtCompileTime = XprType::ColsAtCompileTime,
269
270 CoeffReadCost = evaluator<ArgTypeNestedCleaned>::CoeffReadCost,
271 Flags = evaluator<ArgTypeNestedCleaned>::Flags,
272 Alignment = evaluator<ArgTypeNestedCleaned>::Alignment,
273 };
274 enum {
275 // We do not need to know the outer stride for vectors
276 OuterStrideAtCompileTime
277 = IsVectorAtCompileTime
278 ? 0
279 : (IsRowMajor ? ColsAtCompileTime : RowsAtCompileTime)
280 };
281
282 evaluator<ArgTypeNestedCleaned> m_argImpl;
283
284 explicit evaluator(const XprType& xpr) : m_argImpl(xpr.m_arg) {}
285 explicit evaluator(XprType&& xpr)
286 : m_argImpl(std::forward<XprType>(xpr).m_arg) {}
287
288 // all these functions just call the same on the argument
289 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row,
290 Index col) const {
291 return m_argImpl.coeff(row, col);
292 }
293 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType
294 coeff(Index index) const {
295 return m_argImpl.coeff(index);
296 }
297
298 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) {
299 return m_argImpl.coeffRef(row, col);
300 }
301 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) {
302 return m_argImpl.coeffRef(index);
303 }
304
305 template <int LoadMode, typename PacketType>
306 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row,
307 Index col) const {
308 return m_argImpl.template packet<LoadMode, PacketType>(row, col);
309 }
310 template <int LoadMode, typename PacketType>
311 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
312 return m_argImpl.template packet<LoadMode, PacketType>(index);
313 }
314
315 template <int StoreMode, typename PacketType>
316 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index row, Index col,
317 const PacketType& x) {
318 return m_argImpl.template writePacket<StoreMode, PacketType>(row, col, x);
319 }
320 template <int StoreMode, typename PacketType>
321 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index index,
322 const PacketType& x) {
323 return m_argImpl.template writePacket<StoreMode, PacketType>(index, x);
324 }
325
326 template <int LoadMode, typename PacketType>
327 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType
328 packetSegment(Index row, Index col, Index begin, Index count) const {
329 return m_argImpl.template packetSegment<LoadMode, PacketType>(row, col,
330 begin, count);
331 }
332
333 template <int LoadMode, typename PacketType>
334 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType
335 packetSegment(Index index, Index begin, Index count) const {
336 return m_argImpl.template packetSegment<LoadMode, PacketType>(index, begin,
337 count);
338 }
339
340 template <int StoreMode, typename PacketType>
341 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacketSegment(
342 Index row, Index col, const PacketType& x, Index begin, Index count) {
343 return m_argImpl.template writePacketSegment<StoreMode, PacketType>(
344 row, col, x, begin, count);
345 }
346
347 template <int StoreMode, typename PacketType>
348 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacketSegment(
349 Index index, const PacketType& x, Index begin, Index count) {
350 return m_argImpl.template writePacketSegment<StoreMode, PacketType>(
351 index, x, begin, count);
352 }
353};
354
355} // namespace internal
356} // namespace Eigen
357
358namespace stan {
359namespace math {
360
371template <typename T, typename... Ptrs,
372 std::enable_if_t<sizeof...(Ptrs) >= 1>* = nullptr>
373inline Holder<T, Ptrs...> holder(T&& arg, Ptrs*... pointers) {
374 return Holder<T, Ptrs...>(std::forward<T>(arg), pointers...);
375}
376// trivial case with no pointers constructs no holder object
377template <typename T>
378inline decltype(auto) holder(T&& arg) {
379 if constexpr (std::is_rvalue_reference<T&&>::value) {
380 return std::decay_t<T>(std::forward<T>(arg));
381 } else {
382 return std::forward<T>(arg);
383 }
384}
385
386namespace internal {
387// the function holder_handle_element is also used in holder_cl
397template <typename T>
398inline auto holder_handle_element(T& a, T*& res) {
399 res = &a;
400 return std::make_tuple();
401}
402template <typename T,
403 std::enable_if_t<!(Eigen::internal::traits<std::decay_t<T>>::Flags
404 & Eigen::NestByRefBit)>* = nullptr>
405inline auto holder_handle_element(T&& a, std::remove_reference_t<T>*& res) {
406 res = &a;
407 return std::make_tuple();
408}
409
420template <typename T, require_t<std::is_rvalue_reference<T&&>>* = nullptr,
421 std::enable_if_t<
422 static_cast<bool>(Eigen::internal::traits<std::decay_t<T>>::Flags&
423 Eigen::NestByRefBit)>* = nullptr>
424inline auto holder_handle_element(T&& a, T*& res) {
425 res = new T(std::move(a));
426 return std::make_tuple(res);
427}
428template <typename T, require_t<std::is_rvalue_reference<T&&>>* = nullptr,
429 require_not_eigen_t<T>* = nullptr>
430inline auto holder_handle_element(T&& a, T*& res) {
431 res = new T(std::move(a));
432 return std::make_tuple(res);
433}
434
446template <typename T, std::size_t... Is, typename... Args>
448 T&& expr, std::index_sequence<Is...>, const std::tuple<Args*...>& ptrs) {
449 return holder(std::forward<T>(expr), std::get<Is>(ptrs)...);
450}
451
461template <typename F, std::size_t... Is, typename... Args>
462inline auto make_holder_impl(F&& func, std::index_sequence<Is...>,
463 Args&&... args) {
464 std::tuple<std::remove_reference_t<Args>*...> res;
465 auto ptrs = std::tuple_cat(
466 holder_handle_element(std::forward<Args>(args), std::get<Is>(res))...);
468 std::forward<F>(func)(*std::get<Is>(res)...),
469 std::make_index_sequence<std::tuple_size<decltype(ptrs)>::value>(), ptrs);
470}
471
472} // namespace internal
473
486template <typename F, typename... Args,
487 require_not_plain_type_t<std::invoke_result_t<F, Args&&...>>*>
488inline auto make_holder(F&& func, Args&&... args) {
489 if constexpr (is_var_matrix_v<std::invoke_result_t<F, Args&&...>>) {
490 return std::forward<F>(func)(std::forward<Args>(args)...);
491 } else {
493 std::forward<F>(func), std::make_index_sequence<sizeof...(Args)>(),
494 std::forward<Args>(args)...);
495 }
496}
497
508template <typename F, typename... Args,
509 require_plain_type_t<std::invoke_result_t<F, Args&&...>>*>
510inline auto make_holder(F&& func, Args&&... args) {
511 return std::forward<F>(func)(std::forward<Args>(args)...);
512}
513
514} // namespace math
515} // namespace stan
516
517#endif
Eigen::internal::ref_selector< Holder< ArgType, Ptrs... > >::type Nested
Definition holder.hpp:152
Holder< ArgType, Ptrs... > & operator=(const Holder< ArgType, Ptrs... > &other)
Definition holder.hpp:192
Eigen::Index outerStride() const
Definition holder.hpp:168
Eigen::Index rows() const
Definition holder.hpp:165
Eigen::Index innerStride() const
Definition holder.hpp:167
Holder< ArgType, Ptrs... > & operator=(Holder< ArgType, Ptrs... > &&other)
Definition holder.hpp:197
Holder(const Holder< ArgType, Ptrs... > &)=default
Holder< ArgType, Ptrs... > & operator=(const T &other)
Assignment operator assigns expressions.
Definition holder.hpp:185
const auto & coeffRef(Eigen::Index index) const
Definition holder.hpp:175
Eigen::Index cols() const
Definition holder.hpp:166
std::tuple< std::unique_ptr< Ptrs >... > m_unique_ptrs
Definition holder.hpp:154
const auto * data() const
Definition holder.hpp:170
Eigen::internal::ref_selector< ArgType >::non_const_type m_arg
Definition holder.hpp:153
Holder(Holder< ArgType, Ptrs... > &&)=default
const auto & coeffRef(Eigen::Index row, Eigen::Index col) const
Definition holder.hpp:172
Holder(ArgType &&arg, Ptrs *... pointers)
Definition holder.hpp:155
A no-op Eigen operation.
Definition holder.hpp:149
auto col(T_x &&x, size_t j)
Return the specified column of the specified kernel generator expression using start-at-1 indexing.
Definition col.hpp:23
auto row(T_x &&x, size_t j)
Return the specified row of the specified kernel generator expression using start-at-1 indexing.
Definition row.hpp:23
require_not_t< is_plain_type< std::decay_t< T > > > require_not_plain_type_t
Require type does not satisfy is_plain_type.
require_t< is_plain_type< std::decay_t< T > > > require_plain_type_t
Require type satisfies is_plain_type.
(Expert) Numerical traits for algorithmic differentiation variables.
auto make_holder_impl_construct_object(T &&expr, std::index_sequence< Is... >, const std::tuple< Args *... > &ptrs)
Second step in implementation of construction holder from a functor.
Definition holder.hpp:447
auto holder_handle_element(T &a, T *&res)
Handles single element (moving rvalue non-expressions to heap) for construction of holder or holder_c...
Definition holder.hpp:398
auto make_holder_impl(F &&func, std::index_sequence< Is... >, Args &&... args)
Implementation of construction holder from a functor.
Definition holder.hpp:462
fvar< T > operator/(const fvar< T > &x1, const fvar< T > &x2)
Return the result of dividing the first argument by the second.
fvar< T > operator-(const fvar< T > &x1, const fvar< T > &x2)
Return the difference of the specified arguments.
fvar< T > operator*(const fvar< T > &x, const fvar< T > &y)
Return the product of the two arguments.
fvar< T > arg(const std::complex< fvar< T > > &z)
Return the phase angle of the complex argument.
Definition arg.hpp:19
auto make_holder(F &&func, Args &&... args)
Calls given function with given arguments.
Definition holder.hpp:488
fvar< T > operator+(const fvar< T > &x1, const fvar< T > &x2)
Return the sum of the specified forward mode addends.
Ptrs holder(T &&arg, Ptrs *... pointers)
Definition holder.hpp:373
require_t< is_holder< T > > require_holder_t
Definition holder.hpp:118
constexpr bool is_holder_v
Definition holder.hpp:115
constexpr bool is_var_matrix_v
std::enable_if_t< Check::value > require_t
If condition is true, template is enabled.
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...
STL namespace.
void writePacket(Index row, Index col, const PacketType &x)
Definition holder.hpp:316
CoeffReturnType coeff(Index row, Index col) const
Definition holder.hpp:289
void writePacketSegment(Index row, Index col, const PacketType &x, Index begin, Index count)
Definition holder.hpp:341
void writePacketSegment(Index index, const PacketType &x, Index begin, Index count)
Definition holder.hpp:348
PacketType packetSegment(Index row, Index col, Index begin, Index count) const
Definition holder.hpp:328
PacketType packetSegment(Index index, Index begin, Index count) const
Definition holder.hpp:335