1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com> 5 // 6 // This Source Code Form is subject to the terms of the Mozilla 7 // Public License v. 2.0. If a copy of the MPL was not distributed 8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 10 #ifndef EIGEN_CXX11_TENSOR_TENSOR_TRAITS_H 11 #define EIGEN_CXX11_TENSOR_TENSOR_TRAITS_H 12 13 namespace Eigen { 14 namespace internal { 15 16 17 template<typename Scalar, int Options> 18 class compute_tensor_flags 19 { 20 enum { 21 is_dynamic_size_storage = 1, 22 23 is_aligned = 24 ( 25 ((Options&DontAlign)==0) && ( 26 #if EIGEN_MAX_STATIC_ALIGN_BYTES>0 27 (!is_dynamic_size_storage) 28 #else 29 0 30 #endif 31 | 32 #if EIGEN_MAX_ALIGN_BYTES>0 33 is_dynamic_size_storage 34 #else 35 0 36 #endif 37 ) 38 ), 39 packet_access_bit = packet_traits<Scalar>::Vectorizable && is_aligned ? PacketAccessBit : 0 40 }; 41 42 public: 43 enum { ret = packet_access_bit }; 44 }; 45 46 47 template<typename Scalar_, int NumIndices_, int Options_, typename IndexType_> 48 struct traits<Tensor<Scalar_, NumIndices_, Options_, IndexType_> > 49 { 50 typedef Scalar_ Scalar; 51 typedef Dense StorageKind; 52 typedef IndexType_ Index; 53 static const int NumDimensions = NumIndices_; 54 static const int Layout = Options_ & RowMajor ? RowMajor : ColMajor; 55 enum { 56 Options = Options_, 57 Flags = compute_tensor_flags<Scalar_, Options_>::ret | (is_const<Scalar_>::value ? 0 : LvalueBit) 58 }; 59 template <typename T> struct MakePointer { 60 typedef T* Type; 61 }; 62 typedef typename MakePointer<Scalar>::Type PointerType; 63 }; 64 65 66 template<typename Scalar_, typename Dimensions, int Options_, typename IndexType_> 67 struct traits<TensorFixedSize<Scalar_, Dimensions, Options_, IndexType_> > 68 { 69 typedef Scalar_ Scalar; 70 typedef Dense StorageKind; 71 typedef IndexType_ Index; 72 static const int NumDimensions = array_size<Dimensions>::value; 73 static const int Layout = Options_ & RowMajor ? RowMajor : ColMajor; 74 enum { 75 Options = Options_, 76 Flags = compute_tensor_flags<Scalar_, Options_>::ret | (is_const<Scalar_>::value ? 0: LvalueBit) 77 }; 78 template <typename T> struct MakePointer { 79 typedef T* Type; 80 }; 81 typedef typename MakePointer<Scalar>::Type PointerType; 82 }; 83 84 85 template<typename PlainObjectType, int Options_, template <class> class MakePointer_> 86 struct traits<TensorMap<PlainObjectType, Options_, MakePointer_> > 87 : public traits<PlainObjectType> 88 { 89 typedef traits<PlainObjectType> BaseTraits; 90 typedef typename BaseTraits::Scalar Scalar; 91 typedef typename BaseTraits::StorageKind StorageKind; 92 typedef typename BaseTraits::Index Index; 93 static const int NumDimensions = BaseTraits::NumDimensions; 94 static const int Layout = BaseTraits::Layout; 95 enum { 96 Options = Options_, 97 Flags = BaseTraits::Flags 98 }; 99 template <class T> struct MakePointer { 100 // Intermediate typedef to workaround MSVC issue. 101 typedef MakePointer_<T> MakePointerT; 102 typedef typename MakePointerT::Type Type; 103 }; 104 typedef typename MakePointer<Scalar>::Type PointerType; 105 }; 106 107 template<typename PlainObjectType> 108 struct traits<TensorRef<PlainObjectType> > 109 : public traits<PlainObjectType> 110 { 111 typedef traits<PlainObjectType> BaseTraits; 112 typedef typename BaseTraits::Scalar Scalar; 113 typedef typename BaseTraits::StorageKind StorageKind; 114 typedef typename BaseTraits::Index Index; 115 static const int NumDimensions = BaseTraits::NumDimensions; 116 static const int Layout = BaseTraits::Layout; 117 enum { 118 Options = BaseTraits::Options, 119 Flags = BaseTraits::Flags 120 }; 121 typedef typename BaseTraits::PointerType PointerType; 122 }; 123 124 125 template<typename _Scalar, int NumIndices_, int Options, typename IndexType_> 126 struct eval<Tensor<_Scalar, NumIndices_, Options, IndexType_>, Eigen::Dense> 127 { 128 typedef const Tensor<_Scalar, NumIndices_, Options, IndexType_>EIGEN_DEVICE_REF type; 129 }; 130 131 template<typename _Scalar, int NumIndices_, int Options, typename IndexType_> 132 struct eval<const Tensor<_Scalar, NumIndices_, Options, IndexType_>, Eigen::Dense> 133 { 134 typedef const Tensor<_Scalar, NumIndices_, Options, IndexType_>EIGEN_DEVICE_REF type; 135 }; 136 137 template<typename Scalar_, typename Dimensions, int Options, typename IndexType_> 138 struct eval<TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>, Eigen::Dense> 139 { 140 typedef const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>EIGEN_DEVICE_REF type; 141 }; 142 143 template<typename Scalar_, typename Dimensions, int Options, typename IndexType_> 144 struct eval<const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>, Eigen::Dense> 145 { 146 typedef const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>EIGEN_DEVICE_REF type; 147 }; 148 149 template<typename PlainObjectType, int Options, template <class> class MakePointer> 150 struct eval<TensorMap<PlainObjectType, Options, MakePointer>, Eigen::Dense> 151 { 152 typedef const TensorMap<PlainObjectType, Options, MakePointer>EIGEN_DEVICE_REF type; 153 }; 154 155 template<typename PlainObjectType, int Options, template <class> class MakePointer> 156 struct eval<const TensorMap<PlainObjectType, Options, MakePointer>, Eigen::Dense> 157 { 158 typedef const TensorMap<PlainObjectType, Options, MakePointer>EIGEN_DEVICE_REF type; 159 }; 160 161 template<typename PlainObjectType> 162 struct eval<TensorRef<PlainObjectType>, Eigen::Dense> 163 { 164 typedef const TensorRef<PlainObjectType>EIGEN_DEVICE_REF type; 165 }; 166 167 template<typename PlainObjectType> 168 struct eval<const TensorRef<PlainObjectType>, Eigen::Dense> 169 { 170 typedef const TensorRef<PlainObjectType>EIGEN_DEVICE_REF type; 171 }; 172 173 // TODO nested<> does not exist anymore in Eigen/Core, and it thus has to be removed in favor of ref_selector. 174 template<typename T, int n=1, typename PlainObject = void> struct nested 175 { 176 typedef typename ref_selector<T>::type type; 177 }; 178 179 template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_> 180 struct nested<Tensor<Scalar_, NumIndices_, Options_, IndexType_> > 181 { 182 typedef const Tensor<Scalar_, NumIndices_, Options_, IndexType_>EIGEN_DEVICE_REF type; 183 }; 184 185 template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_> 186 struct nested<const Tensor<Scalar_, NumIndices_, Options_, IndexType_> > 187 { 188 typedef const Tensor<Scalar_, NumIndices_, Options_, IndexType_>EIGEN_DEVICE_REF type; 189 }; 190 191 template <typename Scalar_, typename Dimensions, int Options, typename IndexType_> 192 struct nested<TensorFixedSize<Scalar_, Dimensions, Options, IndexType_> > 193 { 194 typedef const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>EIGEN_DEVICE_REF type; 195 }; 196 197 template <typename Scalar_, typename Dimensions, int Options, typename IndexType_> 198 struct nested<const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_> > 199 { 200 typedef const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>EIGEN_DEVICE_REF type; 201 }; 202 203 204 template <typename PlainObjectType> 205 struct nested<TensorRef<PlainObjectType> > 206 { 207 typedef const TensorRef<PlainObjectType>EIGEN_DEVICE_REF type; 208 }; 209 210 template <typename PlainObjectType> 211 struct nested<const TensorRef<PlainObjectType> > 212 { 213 typedef const TensorRef<PlainObjectType>EIGEN_DEVICE_REF type; 214 }; 215 216 } // end namespace internal 217 218 // Convolutional layers take in an input tensor of shape (D, R, C, B), or (D, C, 219 // R, B), and convolve it with a set of filters, which can also be presented as 220 // a tensor (D, K, K, M), where M is the number of filters, K is the filter 221 // size, and each 3-dimensional tensor of size (D, K, K) is a filter. For 222 // simplicity we assume that we always use square filters (which is usually the 223 // case in images), hence the two Ks in the tensor dimension. It also takes in 224 // a few additional parameters: 225 // Stride (S): The convolution stride is the offset between locations where we 226 // apply the filters. A larger stride means that the output will be 227 // spatially smaller. 228 // Padding (P): The padding we apply to the input tensor along the R and C 229 // dimensions. This is usually used to make sure that the spatial 230 // dimensions of the output matches our intention. 231 // 232 // Two types of padding are often used: 233 // SAME: The pad value is computed so that the output will have size 234 // R/S and C/S. 235 // VALID: no padding is carried out. 236 // When we do padding, the padded values at the padded locations are usually 237 // zero. 238 // 239 // The output dimensions for convolution, when given all the parameters above, 240 // are as follows: 241 // When Padding = SAME: the output size is (B, R', C', M), where 242 // R' = ceil(float(R) / float(S)) 243 // C' = ceil(float(C) / float(S)) 244 // where ceil is the ceiling function. The input tensor is padded with 0 as 245 // needed. The number of padded rows and columns are computed as: 246 // Pr = ((R' - 1) * S + K - R) / 2 247 // Pc = ((C' - 1) * S + K - C) / 2 248 // when the stride is 1, we have the simplified case R'=R, C'=C, Pr=Pc=(K-1)/2. 249 // This is where SAME comes from - the output has the same size as the input has. 250 // When Padding = VALID: the output size is computed as 251 // R' = ceil(float(R - K + 1) / float(S)) 252 // C' = ceil(float(C - K + 1) / float(S)) 253 // and the number of padded rows and columns are computed in the same way as in 254 // the SAME case. 255 // When the stride is 1, we have the simplified case R'=R-K+1, C'=C-K+1, Pr=0, 256 // Pc=0. 257 typedef enum { 258 PADDING_VALID = 1, 259 PADDING_SAME = 2 260 } PaddingType; 261 262 } // end namespace Eigen 263 264 #endif // EIGEN_CXX11_TENSOR_TENSOR_TRAITS_H 265