![]() |
Eigen-unsupported
3.3.3
|
00001 // This file is part of Eigen, a lightweight C++ template library 00002 // for linear algebra. 00003 // 00004 // Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com> 00005 // 00006 // This Source Code Form is subject to the terms of the Mozilla 00007 // Public License v. 2.0. If a copy of the MPL was not distributed 00008 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 00009 00010 #ifndef EIGEN_CXX11_TENSOR_TENSOR_PADDING_H 00011 #define EIGEN_CXX11_TENSOR_TENSOR_PADDING_H 00012 00013 namespace Eigen { 00014 00022 namespace internal { 00023 template<typename PaddingDimensions, typename XprType> 00024 struct traits<TensorPaddingOp<PaddingDimensions, XprType> > : public traits<XprType> 00025 { 00026 typedef typename XprType::Scalar Scalar; 00027 typedef traits<XprType> XprTraits; 00028 typedef typename XprTraits::StorageKind StorageKind; 00029 typedef typename XprTraits::Index Index; 00030 typedef typename XprType::Nested Nested; 00031 typedef typename remove_reference<Nested>::type _Nested; 00032 static const int NumDimensions = XprTraits::NumDimensions; 00033 static const int Layout = XprTraits::Layout; 00034 }; 00035 00036 template<typename PaddingDimensions, typename XprType> 00037 struct eval<TensorPaddingOp<PaddingDimensions, XprType>, Eigen::Dense> 00038 { 00039 typedef const TensorPaddingOp<PaddingDimensions, XprType>& type; 00040 }; 00041 00042 template<typename PaddingDimensions, typename XprType> 00043 struct nested<TensorPaddingOp<PaddingDimensions, XprType>, 1, typename eval<TensorPaddingOp<PaddingDimensions, XprType> >::type> 00044 { 00045 typedef TensorPaddingOp<PaddingDimensions, XprType> type; 00046 }; 00047 00048 } // end namespace internal 00049 00050 00051 00052 template<typename PaddingDimensions, typename XprType> 00053 class TensorPaddingOp : public TensorBase<TensorPaddingOp<PaddingDimensions, XprType>, ReadOnlyAccessors> 00054 { 00055 public: 00056 typedef typename Eigen::internal::traits<TensorPaddingOp>::Scalar Scalar; 00057 typedef typename Eigen::NumTraits<Scalar>::Real RealScalar; 00058 typedef typename XprType::CoeffReturnType CoeffReturnType; 00059 typedef typename Eigen::internal::nested<TensorPaddingOp>::type Nested; 00060 typedef typename Eigen::internal::traits<TensorPaddingOp>::StorageKind StorageKind; 00061 typedef typename Eigen::internal::traits<TensorPaddingOp>::Index Index; 00062 00063 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorPaddingOp(const XprType& expr, const PaddingDimensions& padding_dims, const Scalar padding_value) 00064 : m_xpr(expr), m_padding_dims(padding_dims), m_padding_value(padding_value) {} 00065 00066 EIGEN_DEVICE_FUNC 00067 const PaddingDimensions& padding() const { return m_padding_dims; } 00068 EIGEN_DEVICE_FUNC 00069 Scalar padding_value() const { return m_padding_value; } 00070 00071 EIGEN_DEVICE_FUNC 00072 const typename internal::remove_all<typename XprType::Nested>::type& 00073 expression() const { return m_xpr; } 00074 00075 protected: 00076 typename XprType::Nested m_xpr; 00077 const PaddingDimensions m_padding_dims; 00078 const Scalar m_padding_value; 00079 }; 00080 00081 00082 // Eval as rvalue 00083 template<typename PaddingDimensions, typename ArgType, typename Device> 00084 struct TensorEvaluator<const TensorPaddingOp<PaddingDimensions, ArgType>, Device> 00085 { 00086 typedef TensorPaddingOp<PaddingDimensions, ArgType> XprType; 00087 typedef typename XprType::Index Index; 00088 static const int NumDims = internal::array_size<PaddingDimensions>::value; 00089 typedef DSizes<Index, NumDims> Dimensions; 00090 typedef typename XprType::Scalar Scalar; 00091 typedef typename XprType::CoeffReturnType CoeffReturnType; 00092 typedef typename PacketType<CoeffReturnType, Device>::type PacketReturnType; 00093 static const int PacketSize = internal::unpacket_traits<PacketReturnType>::size; 00094 00095 enum { 00096 IsAligned = true, 00097 PacketAccess = TensorEvaluator<ArgType, Device>::PacketAccess, 00098 Layout = TensorEvaluator<ArgType, Device>::Layout, 00099 CoordAccess = true, 00100 RawAccess = false 00101 }; 00102 00103 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorEvaluator(const XprType& op, const Device& device) 00104 : m_impl(op.expression(), device), m_padding(op.padding()), m_paddingValue(op.padding_value()) 00105 { 00106 // The padding op doesn't change the rank of the tensor. Directly padding a scalar would lead 00107 // to a vector, which doesn't make sense. Instead one should reshape the scalar into a vector 00108 // of 1 element first and then pad. 00109 EIGEN_STATIC_ASSERT((NumDims > 0), YOU_MADE_A_PROGRAMMING_MISTAKE); 00110 00111 // Compute dimensions 00112 m_dimensions = m_impl.dimensions(); 00113 for (int i = 0; i < NumDims; ++i) { 00114 m_dimensions[i] += m_padding[i].first + m_padding[i].second; 00115 } 00116 const typename TensorEvaluator<ArgType, Device>::Dimensions& input_dims = m_impl.dimensions(); 00117 if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) { 00118 m_inputStrides[0] = 1; 00119 m_outputStrides[0] = 1; 00120 for (int i = 1; i < NumDims; ++i) { 00121 m_inputStrides[i] = m_inputStrides[i-1] * input_dims[i-1]; 00122 m_outputStrides[i] = m_outputStrides[i-1] * m_dimensions[i-1]; 00123 } 00124 m_outputStrides[NumDims] = m_outputStrides[NumDims-1] * m_dimensions[NumDims-1]; 00125 } else { 00126 m_inputStrides[NumDims - 1] = 1; 00127 m_outputStrides[NumDims] = 1; 00128 for (int i = NumDims - 2; i >= 0; --i) { 00129 m_inputStrides[i] = m_inputStrides[i+1] * input_dims[i+1]; 00130 m_outputStrides[i+1] = m_outputStrides[i+2] * m_dimensions[i+1]; 00131 } 00132 m_outputStrides[0] = m_outputStrides[1] * m_dimensions[0]; 00133 } 00134 } 00135 00136 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions& dimensions() const { return m_dimensions; } 00137 00138 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool evalSubExprsIfNeeded(Scalar*) { 00139 m_impl.evalSubExprsIfNeeded(NULL); 00140 return true; 00141 } 00142 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void cleanup() { 00143 m_impl.cleanup(); 00144 } 00145 00146 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const 00147 { 00148 eigen_assert(index < dimensions().TotalSize()); 00149 Index inputIndex = 0; 00150 if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) { 00151 for (int i = NumDims - 1; i > 0; --i) { 00152 const Index idx = index / m_outputStrides[i]; 00153 if (isPaddingAtIndexForDim(idx, i)) { 00154 return m_paddingValue; 00155 } 00156 inputIndex += (idx - m_padding[i].first) * m_inputStrides[i]; 00157 index -= idx * m_outputStrides[i]; 00158 } 00159 if (isPaddingAtIndexForDim(index, 0)) { 00160 return m_paddingValue; 00161 } 00162 inputIndex += (index - m_padding[0].first); 00163 } else { 00164 for (int i = 0; i < NumDims - 1; ++i) { 00165 const Index idx = index / m_outputStrides[i+1]; 00166 if (isPaddingAtIndexForDim(idx, i)) { 00167 return m_paddingValue; 00168 } 00169 inputIndex += (idx - m_padding[i].first) * m_inputStrides[i]; 00170 index -= idx * m_outputStrides[i+1]; 00171 } 00172 if (isPaddingAtIndexForDim(index, NumDims-1)) { 00173 return m_paddingValue; 00174 } 00175 inputIndex += (index - m_padding[NumDims-1].first); 00176 } 00177 return m_impl.coeff(inputIndex); 00178 } 00179 00180 template<int LoadMode> 00181 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packet(Index index) const 00182 { 00183 if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) { 00184 return packetColMajor(index); 00185 } 00186 return packetRowMajor(index); 00187 } 00188 00189 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE TensorOpCost costPerCoeff(bool vectorized) const { 00190 TensorOpCost cost = m_impl.costPerCoeff(vectorized); 00191 if (static_cast<int>(Layout) == static_cast<int>(ColMajor)) { 00192 for (int i = 0; i < NumDims; ++i) 00193 updateCostPerDimension(cost, i, i == 0); 00194 } else { 00195 for (int i = NumDims - 1; i >= 0; --i) 00196 updateCostPerDimension(cost, i, i == NumDims - 1); 00197 } 00198 return cost; 00199 } 00200 00201 EIGEN_DEVICE_FUNC Scalar* data() const { return NULL; } 00202 00203 private: 00204 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool isPaddingAtIndexForDim( 00205 Index index, int dim_index) const { 00206 #if defined(EIGEN_HAS_INDEX_LIST) 00207 return (!internal::index_pair_first_statically_eq<PaddingDimensions>(dim_index, 0) && 00208 index < m_padding[dim_index].first) || 00209 (!internal::index_pair_second_statically_eq<PaddingDimensions>(dim_index, 0) && 00210 index >= m_dimensions[dim_index] - m_padding[dim_index].second); 00211 #else 00212 return (index < m_padding[dim_index].first) || 00213 (index >= m_dimensions[dim_index] - m_padding[dim_index].second); 00214 #endif 00215 } 00216 00217 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool isLeftPaddingCompileTimeZero( 00218 int dim_index) const { 00219 #if defined(EIGEN_HAS_INDEX_LIST) 00220 return internal::index_pair_first_statically_eq<PaddingDimensions>(dim_index, 0); 00221 #else 00222 EIGEN_UNUSED_VARIABLE(dim_index); 00223 return false; 00224 #endif 00225 } 00226 00227 EIGEN_DEVICE_FUNC EIGEN_ALWAYS_INLINE bool isRightPaddingCompileTimeZero( 00228 int dim_index) const { 00229 #if defined(EIGEN_HAS_INDEX_LIST) 00230 return internal::index_pair_second_statically_eq<PaddingDimensions>(dim_index, 0); 00231 #else 00232 EIGEN_UNUSED_VARIABLE(dim_index); 00233 return false; 00234 #endif 00235 } 00236 00237 00238 void updateCostPerDimension(TensorOpCost& cost, int i, bool first) const { 00239 const double in = static_cast<double>(m_impl.dimensions()[i]); 00240 const double out = in + m_padding[i].first + m_padding[i].second; 00241 if (out == 0) 00242 return; 00243 const double reduction = in / out; 00244 cost *= reduction; 00245 if (first) { 00246 cost += TensorOpCost(0, 0, 2 * TensorOpCost::AddCost<Index>() + 00247 reduction * (1 * TensorOpCost::AddCost<Index>())); 00248 } else { 00249 cost += TensorOpCost(0, 0, 2 * TensorOpCost::AddCost<Index>() + 00250 2 * TensorOpCost::MulCost<Index>() + 00251 reduction * (2 * TensorOpCost::MulCost<Index>() + 00252 1 * TensorOpCost::DivCost<Index>())); 00253 } 00254 } 00255 00256 protected: 00257 00258 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetColMajor(Index index) const 00259 { 00260 EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) 00261 eigen_assert(index+PacketSize-1 < dimensions().TotalSize()); 00262 00263 const Index initialIndex = index; 00264 Index inputIndex = 0; 00265 for (int i = NumDims - 1; i > 0; --i) { 00266 const Index first = index; 00267 const Index last = index + PacketSize - 1; 00268 const Index lastPaddedLeft = m_padding[i].first * m_outputStrides[i]; 00269 const Index firstPaddedRight = (m_dimensions[i] - m_padding[i].second) * m_outputStrides[i]; 00270 const Index lastPaddedRight = m_outputStrides[i+1]; 00271 00272 if (!isLeftPaddingCompileTimeZero(i) && last < lastPaddedLeft) { 00273 // all the coefficient are in the padding zone. 00274 return internal::pset1<PacketReturnType>(m_paddingValue); 00275 } 00276 else if (!isRightPaddingCompileTimeZero(i) && first >= firstPaddedRight && last < lastPaddedRight) { 00277 // all the coefficient are in the padding zone. 00278 return internal::pset1<PacketReturnType>(m_paddingValue); 00279 } 00280 else if ((isLeftPaddingCompileTimeZero(i) && isRightPaddingCompileTimeZero(i)) || (first >= lastPaddedLeft && last < firstPaddedRight)) { 00281 // all the coefficient are between the 2 padding zones. 00282 const Index idx = index / m_outputStrides[i]; 00283 inputIndex += (idx - m_padding[i].first) * m_inputStrides[i]; 00284 index -= idx * m_outputStrides[i]; 00285 } 00286 else { 00287 // Every other case 00288 return packetWithPossibleZero(initialIndex); 00289 } 00290 } 00291 00292 const Index last = index + PacketSize - 1; 00293 const Index first = index; 00294 const Index lastPaddedLeft = m_padding[0].first; 00295 const Index firstPaddedRight = (m_dimensions[0] - m_padding[0].second); 00296 const Index lastPaddedRight = m_outputStrides[1]; 00297 00298 if (!isLeftPaddingCompileTimeZero(0) && last < lastPaddedLeft) { 00299 // all the coefficient are in the padding zone. 00300 return internal::pset1<PacketReturnType>(m_paddingValue); 00301 } 00302 else if (!isRightPaddingCompileTimeZero(0) && first >= firstPaddedRight && last < lastPaddedRight) { 00303 // all the coefficient are in the padding zone. 00304 return internal::pset1<PacketReturnType>(m_paddingValue); 00305 } 00306 else if ((isLeftPaddingCompileTimeZero(0) && isRightPaddingCompileTimeZero(0)) || (first >= lastPaddedLeft && last < firstPaddedRight)) { 00307 // all the coefficient are between the 2 padding zones. 00308 inputIndex += (index - m_padding[0].first); 00309 return m_impl.template packet<Unaligned>(inputIndex); 00310 } 00311 // Every other case 00312 return packetWithPossibleZero(initialIndex); 00313 } 00314 00315 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetRowMajor(Index index) const 00316 { 00317 EIGEN_STATIC_ASSERT((PacketSize > 1), YOU_MADE_A_PROGRAMMING_MISTAKE) 00318 eigen_assert(index+PacketSize-1 < dimensions().TotalSize()); 00319 00320 const Index initialIndex = index; 00321 Index inputIndex = 0; 00322 00323 for (int i = 0; i < NumDims - 1; ++i) { 00324 const Index first = index; 00325 const Index last = index + PacketSize - 1; 00326 const Index lastPaddedLeft = m_padding[i].first * m_outputStrides[i+1]; 00327 const Index firstPaddedRight = (m_dimensions[i] - m_padding[i].second) * m_outputStrides[i+1]; 00328 const Index lastPaddedRight = m_outputStrides[i]; 00329 00330 if (!isLeftPaddingCompileTimeZero(i) && last < lastPaddedLeft) { 00331 // all the coefficient are in the padding zone. 00332 return internal::pset1<PacketReturnType>(m_paddingValue); 00333 } 00334 else if (!isRightPaddingCompileTimeZero(i) && first >= firstPaddedRight && last < lastPaddedRight) { 00335 // all the coefficient are in the padding zone. 00336 return internal::pset1<PacketReturnType>(m_paddingValue); 00337 } 00338 else if ((isLeftPaddingCompileTimeZero(i) && isRightPaddingCompileTimeZero(i)) || (first >= lastPaddedLeft && last < firstPaddedRight)) { 00339 // all the coefficient are between the 2 padding zones. 00340 const Index idx = index / m_outputStrides[i+1]; 00341 inputIndex += (idx - m_padding[i].first) * m_inputStrides[i]; 00342 index -= idx * m_outputStrides[i+1]; 00343 } 00344 else { 00345 // Every other case 00346 return packetWithPossibleZero(initialIndex); 00347 } 00348 } 00349 00350 const Index last = index + PacketSize - 1; 00351 const Index first = index; 00352 const Index lastPaddedLeft = m_padding[NumDims-1].first; 00353 const Index firstPaddedRight = (m_dimensions[NumDims-1] - m_padding[NumDims-1].second); 00354 const Index lastPaddedRight = m_outputStrides[NumDims-1]; 00355 00356 if (!isLeftPaddingCompileTimeZero(NumDims-1) && last < lastPaddedLeft) { 00357 // all the coefficient are in the padding zone. 00358 return internal::pset1<PacketReturnType>(m_paddingValue); 00359 } 00360 else if (!isRightPaddingCompileTimeZero(NumDims-1) && first >= firstPaddedRight && last < lastPaddedRight) { 00361 // all the coefficient are in the padding zone. 00362 return internal::pset1<PacketReturnType>(m_paddingValue); 00363 } 00364 else if ((isLeftPaddingCompileTimeZero(NumDims-1) && isRightPaddingCompileTimeZero(NumDims-1)) || (first >= lastPaddedLeft && last < firstPaddedRight)) { 00365 // all the coefficient are between the 2 padding zones. 00366 inputIndex += (index - m_padding[NumDims-1].first); 00367 return m_impl.template packet<Unaligned>(inputIndex); 00368 } 00369 // Every other case 00370 return packetWithPossibleZero(initialIndex); 00371 } 00372 00373 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketReturnType packetWithPossibleZero(Index index) const 00374 { 00375 EIGEN_ALIGN_MAX typename internal::remove_const<CoeffReturnType>::type values[PacketSize]; 00376 for (int i = 0; i < PacketSize; ++i) { 00377 values[i] = coeff(index+i); 00378 } 00379 PacketReturnType rslt = internal::pload<PacketReturnType>(values); 00380 return rslt; 00381 } 00382 00383 Dimensions m_dimensions; 00384 array<Index, NumDims+1> m_outputStrides; 00385 array<Index, NumDims> m_inputStrides; 00386 TensorEvaluator<ArgType, Device> m_impl; 00387 PaddingDimensions m_padding; 00388 00389 Scalar m_paddingValue; 00390 }; 00391 00392 00393 00394 00395 } // end namespace Eigen 00396 00397 #endif // EIGEN_CXX11_TENSOR_TENSOR_PADDING_H