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 }; 63 64 65 template<typename Scalar_, typename Dimensions, int Options_, typename IndexType_> 66 struct traits<TensorFixedSize<Scalar_, Dimensions, Options_, IndexType_> > 67 { 68 typedef Scalar_ Scalar; 69 typedef Dense StorageKind; 70 typedef IndexType_ Index; 71 static const int NumDimensions = array_size<Dimensions>::value; 72 static const int Layout = Options_ & RowMajor ? RowMajor : ColMajor; 73 enum { 74 Options = Options_, 75 Flags = compute_tensor_flags<Scalar_, Options_>::ret | (is_const<Scalar_>::value ? 0: LvalueBit) 76 }; 77 template <typename T> struct MakePointer { 78 typedef T* Type; 79 }; 80 }; 81 82 83 template<typename PlainObjectType, int Options_, template <class> class MakePointer_> 84 struct traits<TensorMap<PlainObjectType, Options_, MakePointer_> > 85 : public traits<PlainObjectType> 86 { 87 typedef traits<PlainObjectType> BaseTraits; 88 typedef typename BaseTraits::Scalar Scalar; 89 typedef typename BaseTraits::StorageKind StorageKind; 90 typedef typename BaseTraits::Index Index; 91 static const int NumDimensions = BaseTraits::NumDimensions; 92 static const int Layout = BaseTraits::Layout; 93 enum { 94 Options = Options_, 95 Flags = BaseTraits::Flags 96 }; 97 template <class T> struct MakePointer { 98 // Intermediate typedef to workaround MSVC issue. 99 typedef MakePointer_<T> MakePointerT; 100 typedef typename MakePointerT::Type Type; 101 }; 102 }; 103 104 template<typename PlainObjectType> 105 struct traits<TensorRef<PlainObjectType> > 106 : public traits<PlainObjectType> 107 { 108 typedef traits<PlainObjectType> BaseTraits; 109 typedef typename BaseTraits::Scalar Scalar; 110 typedef typename BaseTraits::StorageKind StorageKind; 111 typedef typename BaseTraits::Index Index; 112 static const int NumDimensions = BaseTraits::NumDimensions; 113 static const int Layout = BaseTraits::Layout; 114 enum { 115 Options = BaseTraits::Options, 116 Flags = BaseTraits::Flags 117 }; 118 }; 119 120 121 template<typename _Scalar, int NumIndices_, int Options, typename IndexType_> 122 struct eval<Tensor<_Scalar, NumIndices_, Options, IndexType_>, Eigen::Dense> 123 { 124 typedef const Tensor<_Scalar, NumIndices_, Options, IndexType_>& type; 125 }; 126 127 template<typename _Scalar, int NumIndices_, int Options, typename IndexType_> 128 struct eval<const Tensor<_Scalar, NumIndices_, Options, IndexType_>, Eigen::Dense> 129 { 130 typedef const Tensor<_Scalar, NumIndices_, Options, IndexType_>& type; 131 }; 132 133 template<typename Scalar_, typename Dimensions, int Options, typename IndexType_> 134 struct eval<TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>, Eigen::Dense> 135 { 136 typedef const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>& type; 137 }; 138 139 template<typename Scalar_, typename Dimensions, int Options, typename IndexType_> 140 struct eval<const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>, Eigen::Dense> 141 { 142 typedef const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>& type; 143 }; 144 145 template<typename PlainObjectType, int Options, template <class> class MakePointer> 146 struct eval<TensorMap<PlainObjectType, Options, MakePointer>, Eigen::Dense> 147 { 148 typedef const TensorMap<PlainObjectType, Options, MakePointer>& type; 149 }; 150 151 template<typename PlainObjectType, int Options, template <class> class MakePointer> 152 struct eval<const TensorMap<PlainObjectType, Options, MakePointer>, Eigen::Dense> 153 { 154 typedef const TensorMap<PlainObjectType, Options, MakePointer>& type; 155 }; 156 157 template<typename PlainObjectType> 158 struct eval<TensorRef<PlainObjectType>, Eigen::Dense> 159 { 160 typedef const TensorRef<PlainObjectType>& type; 161 }; 162 163 template<typename PlainObjectType> 164 struct eval<const TensorRef<PlainObjectType>, Eigen::Dense> 165 { 166 typedef const TensorRef<PlainObjectType>& type; 167 }; 168 169 // TODO nested<> does not exist anymore in Eigen/Core, and it thus has to be removed in favor of ref_selector. 170 template<typename T, int n=1, typename PlainObject = void> struct nested 171 { 172 typedef typename ref_selector<T>::type type; 173 }; 174 175 template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_> 176 struct nested<Tensor<Scalar_, NumIndices_, Options_, IndexType_> > 177 { 178 typedef const Tensor<Scalar_, NumIndices_, Options_, IndexType_>& type; 179 }; 180 181 template <typename Scalar_, int NumIndices_, int Options_, typename IndexType_> 182 struct nested<const Tensor<Scalar_, NumIndices_, Options_, IndexType_> > 183 { 184 typedef const Tensor<Scalar_, NumIndices_, Options_, IndexType_>& type; 185 }; 186 187 template <typename Scalar_, typename Dimensions, int Options, typename IndexType_> 188 struct nested<TensorFixedSize<Scalar_, Dimensions, Options, IndexType_> > 189 { 190 typedef const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>& type; 191 }; 192 193 template <typename Scalar_, typename Dimensions, int Options, typename IndexType_> 194 struct nested<const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_> > 195 { 196 typedef const TensorFixedSize<Scalar_, Dimensions, Options, IndexType_>& type; 197 }; 198 199 200 template <typename PlainObjectType, int Options, template <class> class MakePointer> 201 struct nested<TensorMap<PlainObjectType, Options, MakePointer> > 202 { 203 typedef const TensorMap<PlainObjectType, Options, MakePointer>& type; 204 }; 205 206 template <typename PlainObjectType, int Options, template <class> class MakePointer> 207 struct nested<const TensorMap<PlainObjectType, Options, MakePointer> > 208 { 209 typedef const TensorMap<PlainObjectType, Options, MakePointer>& type; 210 }; 211 212 template <typename PlainObjectType> 213 struct nested<TensorRef<PlainObjectType> > 214 { 215 typedef const TensorRef<PlainObjectType>& type; 216 }; 217 218 template <typename PlainObjectType> 219 struct nested<const TensorRef<PlainObjectType> > 220 { 221 typedef const TensorRef<PlainObjectType>& type; 222 }; 223 224 } // end namespace internal 225 226 // Convolutional layers take in an input tensor of shape (D, R, C, B), or (D, C, 227 // R, B), and convolve it with a set of filters, which can also be presented as 228 // a tensor (D, K, K, M), where M is the number of filters, K is the filter 229 // size, and each 3-dimensional tensor of size (D, K, K) is a filter. For 230 // simplicity we assume that we always use square filters (which is usually the 231 // case in images), hence the two Ks in the tensor dimension. It also takes in 232 // a few additional parameters: 233 // Stride (S): The convolution stride is the offset between locations where we 234 // apply the filters. A larger stride means that the output will be 235 // spatially smaller. 236 // Padding (P): The padding we apply to the input tensor along the R and C 237 // dimensions. This is usually used to make sure that the spatial 238 // dimensions of the output matches our intention. 239 // 240 // Two types of padding are often used: 241 // SAME: The pad value is computed so that the output will have size 242 // R/S and C/S. 243 // VALID: no padding is carried out. 244 // When we do padding, the padded values at the padded locations are usually 245 // zero. 246 // 247 // The output dimensions for convolution, when given all the parameters above, 248 // are as follows: 249 // When Padding = SAME: the output size is (B, R', C', M), where 250 // R' = ceil(float(R) / float(S)) 251 // C' = ceil(float(C) / float(S)) 252 // where ceil is the ceiling function. The input tensor is padded with 0 as 253 // needed. The number of padded rows and columns are computed as: 254 // Pr = ((R' - 1) * S + K - R) / 2 255 // Pc = ((C' - 1) * S + K - C) / 2 256 // when the stride is 1, we have the simplified case R'=R, C'=C, Pr=Pc=(K-1)/2. 257 // This is where SAME comes from - the output has the same size as the input has. 258 // When Padding = VALID: the output size is computed as 259 // R' = ceil(float(R - K + 1) / float(S)) 260 // C' = ceil(float(C - K + 1) / float(S)) 261 // and the number of padded rows and columns are computed in the same way as in 262 // the SAME case. 263 // When the stride is 1, we have the simplified case R'=R-K+1, C'=C-K+1, Pr=0, 264 // Pc=0. 265 typedef enum { 266 PADDING_VALID = 1, 267 PADDING_SAME = 2 268 } PaddingType; 269 270 } // end namespace Eigen 271 272 #endif // EIGEN_CXX11_TENSOR_TENSOR_TRAITS_H 273