1 | // This file is part of Eigen, a lightweight C++ template library |
2 | // for linear algebra. |
3 | // |
4 | // Copyright (C) 2008-2017 Gael Guennebaud <gael.guennebaud@inria.fr> |
5 | // Copyright (C) 2014 yoco <peter.xiau@gmail.com> |
6 | // |
7 | // This Source Code Form is subject to the terms of the Mozilla |
8 | // Public License v. 2.0. If a copy of the MPL was not distributed |
9 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. |
10 | |
11 | #ifndef EIGEN_RESHAPED_H |
12 | #define EIGEN_RESHAPED_H |
13 | |
14 | namespace Eigen { |
15 | |
16 | /** \class Reshaped |
17 | * \ingroup Core_Module |
18 | * |
19 | * \brief Expression of a fixed-size or dynamic-size reshape |
20 | * |
21 | * \tparam XprType the type of the expression in which we are taking a reshape |
22 | * \tparam Rows the number of rows of the reshape we are taking at compile time (optional) |
23 | * \tparam Cols the number of columns of the reshape we are taking at compile time (optional) |
24 | * \tparam Order can be ColMajor or RowMajor, default is ColMajor. |
25 | * |
26 | * This class represents an expression of either a fixed-size or dynamic-size reshape. |
27 | * It is the return type of DenseBase::reshaped(NRowsType,NColsType) and |
28 | * most of the time this is the only way it is used. |
29 | * |
30 | * However, in C++98, if you want to directly maniputate reshaped expressions, |
31 | * for instance if you want to write a function returning such an expression, you |
32 | * will need to use this class. In C++11, it is advised to use the \em auto |
33 | * keyword for such use cases. |
34 | * |
35 | * Here is an example illustrating the dynamic case: |
36 | * \include class_Reshaped.cpp |
37 | * Output: \verbinclude class_Reshaped.out |
38 | * |
39 | * Here is an example illustrating the fixed-size case: |
40 | * \include class_FixedReshaped.cpp |
41 | * Output: \verbinclude class_FixedReshaped.out |
42 | * |
43 | * \sa DenseBase::reshaped(NRowsType,NColsType) |
44 | */ |
45 | |
46 | namespace internal { |
47 | |
48 | template<typename XprType, int Rows, int Cols, int Order> |
49 | struct traits<Reshaped<XprType, Rows, Cols, Order> > : traits<XprType> |
50 | { |
51 | typedef typename traits<XprType>::Scalar Scalar; |
52 | typedef typename traits<XprType>::StorageKind StorageKind; |
53 | typedef typename traits<XprType>::XprKind XprKind; |
54 | enum{ |
55 | MatrixRows = traits<XprType>::RowsAtCompileTime, |
56 | MatrixCols = traits<XprType>::ColsAtCompileTime, |
57 | RowsAtCompileTime = Rows, |
58 | ColsAtCompileTime = Cols, |
59 | MaxRowsAtCompileTime = Rows, |
60 | MaxColsAtCompileTime = Cols, |
61 | XpxStorageOrder = ((int(traits<XprType>::Flags) & RowMajorBit) == RowMajorBit) ? RowMajor : ColMajor, |
62 | ReshapedStorageOrder = (RowsAtCompileTime == 1 && ColsAtCompileTime != 1) ? RowMajor |
63 | : (ColsAtCompileTime == 1 && RowsAtCompileTime != 1) ? ColMajor |
64 | : XpxStorageOrder, |
65 | HasSameStorageOrderAsXprType = (ReshapedStorageOrder == XpxStorageOrder), |
66 | InnerSize = (ReshapedStorageOrder==int(RowMajor)) ? int(ColsAtCompileTime) : int(RowsAtCompileTime), |
67 | InnerStrideAtCompileTime = HasSameStorageOrderAsXprType |
68 | ? int(inner_stride_at_compile_time<XprType>::ret) |
69 | : Dynamic, |
70 | OuterStrideAtCompileTime = Dynamic, |
71 | |
72 | HasDirectAccess = internal::has_direct_access<XprType>::ret |
73 | && (Order==int(XpxStorageOrder)) |
74 | && ((evaluator<XprType>::Flags&LinearAccessBit)==LinearAccessBit), |
75 | |
76 | MaskPacketAccessBit = (InnerSize == Dynamic || (InnerSize % packet_traits<Scalar>::size) == 0) |
77 | && (InnerStrideAtCompileTime == 1) |
78 | ? PacketAccessBit : 0, |
79 | //MaskAlignedBit = ((OuterStrideAtCompileTime!=Dynamic) && (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % 16) == 0)) ? AlignedBit : 0, |
80 | FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0, |
81 | FlagsLvalueBit = is_lvalue<XprType>::value ? LvalueBit : 0, |
82 | FlagsRowMajorBit = (ReshapedStorageOrder==int(RowMajor)) ? RowMajorBit : 0, |
83 | FlagsDirectAccessBit = HasDirectAccess ? DirectAccessBit : 0, |
84 | Flags0 = traits<XprType>::Flags & ( (HereditaryBits & ~RowMajorBit) | MaskPacketAccessBit), |
85 | |
86 | Flags = (Flags0 | FlagsLinearAccessBit | FlagsLvalueBit | FlagsRowMajorBit | FlagsDirectAccessBit) |
87 | }; |
88 | }; |
89 | |
90 | template<typename XprType, int Rows, int Cols, int Order, bool HasDirectAccess> class ReshapedImpl_dense; |
91 | |
92 | } // end namespace internal |
93 | |
94 | template<typename XprType, int Rows, int Cols, int Order, typename StorageKind> class ReshapedImpl; |
95 | |
96 | template<typename XprType, int Rows, int Cols, int Order> class Reshaped |
97 | : public ReshapedImpl<XprType, Rows, Cols, Order, typename internal::traits<XprType>::StorageKind> |
98 | { |
99 | typedef ReshapedImpl<XprType, Rows, Cols, Order, typename internal::traits<XprType>::StorageKind> Impl; |
100 | public: |
101 | //typedef typename Impl::Base Base; |
102 | typedef Impl Base; |
103 | EIGEN_GENERIC_PUBLIC_INTERFACE(Reshaped) |
104 | EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Reshaped) |
105 | |
106 | /** Fixed-size constructor |
107 | */ |
108 | EIGEN_DEVICE_FUNC |
109 | inline Reshaped(XprType& xpr) |
110 | : Impl(xpr) |
111 | { |
112 | EIGEN_STATIC_ASSERT(RowsAtCompileTime!=Dynamic && ColsAtCompileTime!=Dynamic,THIS_METHOD_IS_ONLY_FOR_FIXED_SIZE) |
113 | eigen_assert(Rows * Cols == xpr.rows() * xpr.cols()); |
114 | } |
115 | |
116 | /** Dynamic-size constructor |
117 | */ |
118 | EIGEN_DEVICE_FUNC |
119 | inline Reshaped(XprType& xpr, |
120 | Index reshapeRows, Index reshapeCols) |
121 | : Impl(xpr, reshapeRows, reshapeCols) |
122 | { |
123 | eigen_assert((RowsAtCompileTime==Dynamic || RowsAtCompileTime==reshapeRows) |
124 | && (ColsAtCompileTime==Dynamic || ColsAtCompileTime==reshapeCols)); |
125 | eigen_assert(reshapeRows * reshapeCols == xpr.rows() * xpr.cols()); |
126 | } |
127 | }; |
128 | |
129 | // The generic default implementation for dense reshape simply forward to the internal::ReshapedImpl_dense |
130 | // that must be specialized for direct and non-direct access... |
131 | template<typename XprType, int Rows, int Cols, int Order> |
132 | class ReshapedImpl<XprType, Rows, Cols, Order, Dense> |
133 | : public internal::ReshapedImpl_dense<XprType, Rows, Cols, Order,internal::traits<Reshaped<XprType,Rows,Cols,Order> >::HasDirectAccess> |
134 | { |
135 | typedef internal::ReshapedImpl_dense<XprType, Rows, Cols, Order,internal::traits<Reshaped<XprType,Rows,Cols,Order> >::HasDirectAccess> Impl; |
136 | public: |
137 | typedef Impl Base; |
138 | EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ReshapedImpl) |
139 | EIGEN_DEVICE_FUNC inline ReshapedImpl(XprType& xpr) : Impl(xpr) {} |
140 | EIGEN_DEVICE_FUNC inline ReshapedImpl(XprType& xpr, Index reshapeRows, Index reshapeCols) |
141 | : Impl(xpr, reshapeRows, reshapeCols) {} |
142 | }; |
143 | |
144 | namespace internal { |
145 | |
146 | /** \internal Internal implementation of dense Reshaped in the general case. */ |
147 | template<typename XprType, int Rows, int Cols, int Order> |
148 | class ReshapedImpl_dense<XprType,Rows,Cols,Order,false> |
149 | : public internal::dense_xpr_base<Reshaped<XprType, Rows, Cols, Order> >::type |
150 | { |
151 | typedef Reshaped<XprType, Rows, Cols, Order> ReshapedType; |
152 | public: |
153 | |
154 | typedef typename internal::dense_xpr_base<ReshapedType>::type Base; |
155 | EIGEN_DENSE_PUBLIC_INTERFACE(ReshapedType) |
156 | EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ReshapedImpl_dense) |
157 | |
158 | typedef typename internal::ref_selector<XprType>::non_const_type MatrixTypeNested; |
159 | typedef typename internal::remove_all<XprType>::type NestedExpression; |
160 | |
161 | class InnerIterator; |
162 | |
163 | /** Fixed-size constructor |
164 | */ |
165 | EIGEN_DEVICE_FUNC |
166 | inline ReshapedImpl_dense(XprType& xpr) |
167 | : m_xpr(xpr), m_rows(Rows), m_cols(Cols) |
168 | {} |
169 | |
170 | /** Dynamic-size constructor |
171 | */ |
172 | EIGEN_DEVICE_FUNC |
173 | inline ReshapedImpl_dense(XprType& xpr, Index nRows, Index nCols) |
174 | : m_xpr(xpr), m_rows(nRows), m_cols(nCols) |
175 | {} |
176 | |
177 | EIGEN_DEVICE_FUNC Index rows() const { return m_rows; } |
178 | EIGEN_DEVICE_FUNC Index cols() const { return m_cols; } |
179 | |
180 | #ifdef EIGEN_PARSED_BY_DOXYGEN |
181 | /** \sa MapBase::data() */ |
182 | EIGEN_DEVICE_FUNC inline const Scalar* data() const; |
183 | EIGEN_DEVICE_FUNC inline Index innerStride() const; |
184 | EIGEN_DEVICE_FUNC inline Index outerStride() const; |
185 | #endif |
186 | |
187 | /** \returns the nested expression */ |
188 | EIGEN_DEVICE_FUNC |
189 | const typename internal::remove_all<XprType>::type& |
190 | nestedExpression() const { return m_xpr; } |
191 | |
192 | /** \returns the nested expression */ |
193 | EIGEN_DEVICE_FUNC |
194 | typename internal::remove_reference<XprType>::type& |
195 | nestedExpression() { return m_xpr; } |
196 | |
197 | protected: |
198 | |
199 | MatrixTypeNested m_xpr; |
200 | const internal::variable_if_dynamic<Index, Rows> m_rows; |
201 | const internal::variable_if_dynamic<Index, Cols> m_cols; |
202 | }; |
203 | |
204 | |
205 | /** \internal Internal implementation of dense Reshaped in the direct access case. */ |
206 | template<typename XprType, int Rows, int Cols, int Order> |
207 | class ReshapedImpl_dense<XprType, Rows, Cols, Order, true> |
208 | : public MapBase<Reshaped<XprType, Rows, Cols, Order> > |
209 | { |
210 | typedef Reshaped<XprType, Rows, Cols, Order> ReshapedType; |
211 | typedef typename internal::ref_selector<XprType>::non_const_type XprTypeNested; |
212 | public: |
213 | |
214 | typedef MapBase<ReshapedType> Base; |
215 | EIGEN_DENSE_PUBLIC_INTERFACE(ReshapedType) |
216 | EIGEN_INHERIT_ASSIGNMENT_OPERATORS(ReshapedImpl_dense) |
217 | |
218 | /** Fixed-size constructor |
219 | */ |
220 | EIGEN_DEVICE_FUNC |
221 | inline ReshapedImpl_dense(XprType& xpr) |
222 | : Base(xpr.data()), m_xpr(xpr) |
223 | {} |
224 | |
225 | /** Dynamic-size constructor |
226 | */ |
227 | EIGEN_DEVICE_FUNC |
228 | inline ReshapedImpl_dense(XprType& xpr, Index nRows, Index nCols) |
229 | : Base(xpr.data(), nRows, nCols), |
230 | m_xpr(xpr) |
231 | {} |
232 | |
233 | EIGEN_DEVICE_FUNC |
234 | const typename internal::remove_all<XprTypeNested>::type& nestedExpression() const |
235 | { |
236 | return m_xpr; |
237 | } |
238 | |
239 | EIGEN_DEVICE_FUNC |
240 | XprType& nestedExpression() { return m_xpr; } |
241 | |
242 | /** \sa MapBase::innerStride() */ |
243 | EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR |
244 | inline Index innerStride() const |
245 | { |
246 | return m_xpr.innerStride(); |
247 | } |
248 | |
249 | /** \sa MapBase::outerStride() */ |
250 | EIGEN_DEVICE_FUNC EIGEN_CONSTEXPR |
251 | inline Index outerStride() const |
252 | { |
253 | return ((Flags&RowMajorBit)==RowMajorBit) ? this->cols() : this->rows(); |
254 | } |
255 | |
256 | protected: |
257 | |
258 | XprTypeNested m_xpr; |
259 | }; |
260 | |
261 | // Evaluators |
262 | template<typename ArgType, int Rows, int Cols, int Order, bool HasDirectAccess> struct reshaped_evaluator; |
263 | |
264 | template<typename ArgType, int Rows, int Cols, int Order> |
265 | struct evaluator<Reshaped<ArgType, Rows, Cols, Order> > |
266 | : reshaped_evaluator<ArgType, Rows, Cols, Order, traits<Reshaped<ArgType,Rows,Cols,Order> >::HasDirectAccess> |
267 | { |
268 | typedef Reshaped<ArgType, Rows, Cols, Order> XprType; |
269 | typedef typename XprType::Scalar Scalar; |
270 | // TODO: should check for smaller packet types |
271 | typedef typename packet_traits<Scalar>::type PacketScalar; |
272 | |
273 | enum { |
274 | CoeffReadCost = evaluator<ArgType>::CoeffReadCost, |
275 | HasDirectAccess = traits<XprType>::HasDirectAccess, |
276 | |
277 | // RowsAtCompileTime = traits<XprType>::RowsAtCompileTime, |
278 | // ColsAtCompileTime = traits<XprType>::ColsAtCompileTime, |
279 | // MaxRowsAtCompileTime = traits<XprType>::MaxRowsAtCompileTime, |
280 | // MaxColsAtCompileTime = traits<XprType>::MaxColsAtCompileTime, |
281 | // |
282 | // InnerStrideAtCompileTime = traits<XprType>::HasSameStorageOrderAsXprType |
283 | // ? int(inner_stride_at_compile_time<ArgType>::ret) |
284 | // : Dynamic, |
285 | // OuterStrideAtCompileTime = Dynamic, |
286 | |
287 | FlagsLinearAccessBit = (traits<XprType>::RowsAtCompileTime == 1 || traits<XprType>::ColsAtCompileTime == 1 || HasDirectAccess) ? LinearAccessBit : 0, |
288 | FlagsRowMajorBit = (traits<XprType>::ReshapedStorageOrder==int(RowMajor)) ? RowMajorBit : 0, |
289 | FlagsDirectAccessBit = HasDirectAccess ? DirectAccessBit : 0, |
290 | Flags0 = evaluator<ArgType>::Flags & (HereditaryBits & ~RowMajorBit), |
291 | Flags = Flags0 | FlagsLinearAccessBit | FlagsRowMajorBit | FlagsDirectAccessBit, |
292 | |
293 | PacketAlignment = unpacket_traits<PacketScalar>::alignment, |
294 | Alignment = evaluator<ArgType>::Alignment |
295 | }; |
296 | typedef reshaped_evaluator<ArgType, Rows, Cols, Order, HasDirectAccess> reshaped_evaluator_type; |
297 | EIGEN_DEVICE_FUNC explicit evaluator(const XprType& xpr) : reshaped_evaluator_type(xpr) |
298 | { |
299 | EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); |
300 | } |
301 | }; |
302 | |
303 | template<typename ArgType, int Rows, int Cols, int Order> |
304 | struct reshaped_evaluator<ArgType, Rows, Cols, Order, /* HasDirectAccess */ false> |
305 | : evaluator_base<Reshaped<ArgType, Rows, Cols, Order> > |
306 | { |
307 | typedef Reshaped<ArgType, Rows, Cols, Order> XprType; |
308 | |
309 | enum { |
310 | CoeffReadCost = evaluator<ArgType>::CoeffReadCost /* TODO + cost of index computations */, |
311 | |
312 | Flags = (evaluator<ArgType>::Flags & (HereditaryBits /*| LinearAccessBit | DirectAccessBit*/)), |
313 | |
314 | Alignment = 0 |
315 | }; |
316 | |
317 | EIGEN_DEVICE_FUNC explicit reshaped_evaluator(const XprType& xpr) : m_argImpl(xpr.nestedExpression()), m_xpr(xpr) |
318 | { |
319 | EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost); |
320 | } |
321 | |
322 | typedef typename XprType::Scalar Scalar; |
323 | typedef typename XprType::CoeffReturnType CoeffReturnType; |
324 | |
325 | typedef std::pair<Index, Index> RowCol; |
326 | |
327 | inline RowCol index_remap(Index rowId, Index colId) const |
328 | { |
329 | if(Order==ColMajor) |
330 | { |
331 | const Index nth_elem_idx = colId * m_xpr.rows() + rowId; |
332 | return RowCol(nth_elem_idx % m_xpr.nestedExpression().rows(), |
333 | nth_elem_idx / m_xpr.nestedExpression().rows()); |
334 | } |
335 | else |
336 | { |
337 | const Index nth_elem_idx = colId + rowId * m_xpr.cols(); |
338 | return RowCol(nth_elem_idx / m_xpr.nestedExpression().cols(), |
339 | nth_elem_idx % m_xpr.nestedExpression().cols()); |
340 | } |
341 | } |
342 | |
343 | EIGEN_DEVICE_FUNC |
344 | inline Scalar& coeffRef(Index rowId, Index colId) |
345 | { |
346 | EIGEN_STATIC_ASSERT_LVALUE(XprType) |
347 | const RowCol row_col = index_remap(rowId, colId); |
348 | return m_argImpl.coeffRef(row_col.first, row_col.second); |
349 | } |
350 | |
351 | EIGEN_DEVICE_FUNC |
352 | inline const Scalar& coeffRef(Index rowId, Index colId) const |
353 | { |
354 | const RowCol row_col = index_remap(rowId, colId); |
355 | return m_argImpl.coeffRef(row_col.first, row_col.second); |
356 | } |
357 | |
358 | EIGEN_DEVICE_FUNC |
359 | EIGEN_STRONG_INLINE const CoeffReturnType coeff(Index rowId, Index colId) const |
360 | { |
361 | const RowCol row_col = index_remap(rowId, colId); |
362 | return m_argImpl.coeff(row_col.first, row_col.second); |
363 | } |
364 | |
365 | EIGEN_DEVICE_FUNC |
366 | inline Scalar& coeffRef(Index index) |
367 | { |
368 | EIGEN_STATIC_ASSERT_LVALUE(XprType) |
369 | const RowCol row_col = index_remap(rowId: Rows == 1 ? 0 : index, |
370 | colId: Rows == 1 ? index : 0); |
371 | return m_argImpl.coeffRef(row_col.first, row_col.second); |
372 | |
373 | } |
374 | |
375 | EIGEN_DEVICE_FUNC |
376 | inline const Scalar& coeffRef(Index index) const |
377 | { |
378 | const RowCol row_col = index_remap(rowId: Rows == 1 ? 0 : index, |
379 | colId: Rows == 1 ? index : 0); |
380 | return m_argImpl.coeffRef(row_col.first, row_col.second); |
381 | } |
382 | |
383 | EIGEN_DEVICE_FUNC |
384 | inline const CoeffReturnType coeff(Index index) const |
385 | { |
386 | const RowCol row_col = index_remap(rowId: Rows == 1 ? 0 : index, |
387 | colId: Rows == 1 ? index : 0); |
388 | return m_argImpl.coeff(row_col.first, row_col.second); |
389 | } |
390 | #if 0 |
391 | EIGEN_DEVICE_FUNC |
392 | template<int LoadMode> |
393 | inline PacketScalar packet(Index rowId, Index colId) const |
394 | { |
395 | const RowCol row_col = index_remap(rowId, colId); |
396 | return m_argImpl.template packet<Unaligned>(row_col.first, row_col.second); |
397 | |
398 | } |
399 | |
400 | template<int LoadMode> |
401 | EIGEN_DEVICE_FUNC |
402 | inline void writePacket(Index rowId, Index colId, const PacketScalar& val) |
403 | { |
404 | const RowCol row_col = index_remap(rowId, colId); |
405 | m_argImpl.const_cast_derived().template writePacket<Unaligned> |
406 | (row_col.first, row_col.second, val); |
407 | } |
408 | |
409 | template<int LoadMode> |
410 | EIGEN_DEVICE_FUNC |
411 | inline PacketScalar packet(Index index) const |
412 | { |
413 | const RowCol row_col = index_remap(RowsAtCompileTime == 1 ? 0 : index, |
414 | RowsAtCompileTime == 1 ? index : 0); |
415 | return m_argImpl.template packet<Unaligned>(row_col.first, row_col.second); |
416 | } |
417 | |
418 | template<int LoadMode> |
419 | EIGEN_DEVICE_FUNC |
420 | inline void writePacket(Index index, const PacketScalar& val) |
421 | { |
422 | const RowCol row_col = index_remap(RowsAtCompileTime == 1 ? 0 : index, |
423 | RowsAtCompileTime == 1 ? index : 0); |
424 | return m_argImpl.template packet<Unaligned>(row_col.first, row_col.second, val); |
425 | } |
426 | #endif |
427 | protected: |
428 | |
429 | evaluator<ArgType> m_argImpl; |
430 | const XprType& m_xpr; |
431 | |
432 | }; |
433 | |
434 | template<typename ArgType, int Rows, int Cols, int Order> |
435 | struct reshaped_evaluator<ArgType, Rows, Cols, Order, /* HasDirectAccess */ true> |
436 | : mapbase_evaluator<Reshaped<ArgType, Rows, Cols, Order>, |
437 | typename Reshaped<ArgType, Rows, Cols, Order>::PlainObject> |
438 | { |
439 | typedef Reshaped<ArgType, Rows, Cols, Order> XprType; |
440 | typedef typename XprType::Scalar Scalar; |
441 | |
442 | EIGEN_DEVICE_FUNC explicit reshaped_evaluator(const XprType& xpr) |
443 | : mapbase_evaluator<XprType, typename XprType::PlainObject>(xpr) |
444 | { |
445 | // TODO: for the 3.4 release, this should be turned to an internal assertion, but let's keep it as is for the beta lifetime |
446 | eigen_assert(((internal::UIntPtr(xpr.data()) % EIGEN_PLAIN_ENUM_MAX(1,evaluator<XprType>::Alignment)) == 0) && "data is not aligned" ); |
447 | } |
448 | }; |
449 | |
450 | } // end namespace internal |
451 | |
452 | } // end namespace Eigen |
453 | |
454 | #endif // EIGEN_RESHAPED_H |
455 | |