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(Rows == 1 ? 0 : index, 370 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(Rows == 1 ? 0 : index, 379 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(Rows == 1 ? 0 : index, 387 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