1 /* 2 * Copyright (c) 2017-2019 Arm Limited. 3 * 4 * SPDX-License-Identifier: MIT 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in all 14 * copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 #ifndef ARM_COMPUTE_DIMENSIONS_H 25 #define ARM_COMPUTE_DIMENSIONS_H 26 27 #include "arm_compute/core/Error.h" 28 29 #include <algorithm> 30 #include <array> 31 #include <functional> 32 #include <numeric> 33 34 namespace arm_compute 35 { 36 /** Constant value used to indicate maximum dimensions of a Window, TensorShape and Coordinates */ 37 constexpr size_t MAX_DIMS = 6; 38 39 /** Dimensions with dimensionality */ 40 template <typename T> 41 class Dimensions 42 { 43 public: 44 /** Number of dimensions the tensor has */ 45 static constexpr size_t num_max_dimensions = MAX_DIMS; 46 47 /** Constructor to initialize the tensor shape. 48 * 49 * @param[in] dims Values to initialize the dimensions. 50 */ 51 template <typename... Ts> Dimensions(Ts...dims)52 explicit Dimensions(Ts... dims) 53 : _id{ { static_cast<T>(dims)... } }, _num_dimensions{ sizeof...(dims) } 54 { 55 } 56 57 /** Allow instances of this class to be copy constructed */ 58 Dimensions(const Dimensions &) = default; 59 60 /** Allow instances of this class to be copied */ 61 Dimensions &operator=(const Dimensions &) = default; 62 63 /** Allow instances of this class to be move constructed */ 64 Dimensions(Dimensions &&) = default; 65 66 /** Allow instances of this class to be moved */ 67 Dimensions &operator=(Dimensions &&) = default; 68 69 /** Accessor to set the value of one of the dimensions. 70 * 71 * @param[in] dimension Dimension for which the value is set. 72 * @param[in] value Value to be set for the dimension. 73 */ set(size_t dimension,T value)74 void set(size_t dimension, T value) 75 { 76 ARM_COMPUTE_ERROR_ON(dimension >= num_max_dimensions); 77 _id[dimension] = value; 78 _num_dimensions = std::max(_num_dimensions, dimension + 1); 79 } 80 /** Alias to access the size of the first dimension */ x()81 T x() const 82 { 83 return _id[0]; 84 } 85 /** Alias to access the size of the second dimension */ y()86 T y() const 87 { 88 return _id[1]; 89 } 90 /** Alias to access the size of the third dimension */ z()91 T z() const 92 { 93 return _id[2]; 94 } 95 /** Generic accessor to get the size of any dimension 96 * 97 * @note Precondition: dimension < Dimensions::num_max_dimensions 98 * 99 * @param[in] dimension Dimension of the wanted size 100 * 101 * @return The size of the requested dimension. 102 */ 103 const T &operator[](size_t dimension) const 104 { 105 ARM_COMPUTE_ERROR_ON(dimension >= num_max_dimensions); 106 return _id[dimension]; 107 } 108 /** Generic accessor to get the size of any dimension 109 * 110 * @note Precondition: dimension < Dimensions::num_max_dimensions 111 * 112 * @param[in] dimension Dimension of the wanted size 113 * 114 * @return The size of the requested dimension. 115 */ 116 T &operator[](size_t dimension) 117 { 118 ARM_COMPUTE_ERROR_ON(dimension >= num_max_dimensions); 119 return _id[dimension]; 120 } 121 /** Returns the effective dimensionality of the tensor */ num_dimensions()122 unsigned int num_dimensions() const 123 { 124 return _num_dimensions; 125 } 126 127 /** Set number of dimensions */ set_num_dimensions(size_t num_dimensions)128 void set_num_dimensions(size_t num_dimensions) 129 { 130 _num_dimensions = num_dimensions; 131 } 132 133 /** Collapse dimensions. 134 * 135 * @param[in] n Number of dimensions to collapse into @p first. 136 * @param[in] first Dimensions into which the following @p n are collapsed. 137 */ 138 void collapse(const size_t n, const size_t first = 0) 139 { 140 ARM_COMPUTE_ERROR_ON(first + n > _id.size()); 141 142 const size_t last = std::min(_num_dimensions, first + n); 143 144 if(last > (first + 1)) 145 { 146 // Collapse dimensions into the first 147 _id[first] = std::accumulate(&_id[first], &_id[last], 1, std::multiplies<T>()); 148 // Shift the remaining dimensions down 149 std::copy(&_id[last], &_id[_num_dimensions], &_id[first + 1]); 150 // Reduce the number of dimensions 151 const size_t old_num_dimensions = _num_dimensions; 152 _num_dimensions -= last - first - 1; 153 // Fill the now empty dimensions with zero 154 std::fill(&_id[_num_dimensions], &_id[old_num_dimensions], 0); 155 } 156 } 157 158 /** Collapse dimensions starting from a given point 159 * 160 * @param[in] start Starting point of collapsing dimensions 161 */ collapse_from(size_t start)162 void collapse_from(size_t start) 163 { 164 ARM_COMPUTE_ERROR_ON(start > num_dimensions()); 165 166 collapse(num_dimensions() - start, start); 167 } 168 169 /** Remove dimension of a given index 170 * 171 * @note If index is greater than the number of dimensions no operation is performed 172 * 173 * @param[in] idx Dimension index to remove 174 */ remove(size_t idx)175 void remove(size_t idx) 176 { 177 ARM_COMPUTE_ERROR_ON(_num_dimensions < 1); 178 if(idx >= _num_dimensions) 179 { 180 return; 181 } 182 183 std::copy(_id.begin() + idx + 1, _id.end(), _id.begin() + idx); 184 _num_dimensions--; 185 186 // Make sure all empty dimensions are filled with 0 187 std::fill(_id.begin() + _num_dimensions, _id.end(), 0); 188 } 189 190 /** Returns a read/write iterator that points to the first element in the dimension array. 191 * 192 * @return an iterator. 193 */ begin()194 typename std::array<T, num_max_dimensions>::iterator begin() 195 { 196 return _id.begin(); 197 } 198 /** Returns a read-only (constant) iterator that points to the first element in the dimension array. 199 * 200 * @return an iterator. 201 */ begin()202 typename std::array<T, num_max_dimensions>::const_iterator begin() const 203 { 204 return _id.begin(); 205 } 206 /** Returns a read-only (constant) iterator that points to the first element in the dimension array. 207 * 208 * @return an iterator. 209 */ cbegin()210 typename std::array<T, num_max_dimensions>::const_iterator cbegin() const 211 { 212 return begin(); 213 } 214 /** Returns a read/write iterator that points one past the last element in the dimension array. 215 * 216 * @return an iterator. 217 */ end()218 typename std::array<T, num_max_dimensions>::iterator end() 219 { 220 return _id.end(); 221 } 222 /** Returns a read-only (constant) iterator that points one past the last element in the dimension array. 223 * 224 * @return an iterator. 225 */ end()226 typename std::array<T, num_max_dimensions>::const_iterator end() const 227 { 228 return _id.end(); 229 } 230 /** Returns a read-only (constant) iterator that points one past the last element in the dimension array. 231 * 232 * @return an iterator. 233 */ cend()234 typename std::array<T, num_max_dimensions>::const_iterator cend() const 235 { 236 return end(); 237 } 238 239 protected: 240 /** Protected destructor. */ 241 ~Dimensions() = default; 242 243 std::array<T, num_max_dimensions> _id; 244 size_t _num_dimensions{ 0 }; 245 }; 246 247 /** Check that given dimensions are equal. 248 * 249 * @param[in] lhs Left-hand side Dimensions. 250 * @param[in] rhs Right-hand side Dimensions. 251 * 252 * @return True if the given dimensions are equal. 253 */ 254 template <typename T> 255 inline bool operator==(const Dimensions<T> &lhs, const Dimensions<T> &rhs) 256 { 257 return ((lhs.num_dimensions() == rhs.num_dimensions()) && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin())); 258 } 259 /** Check that given dimensions are not equal. 260 * 261 * @param[in] lhs Left-hand side Dimensions. 262 * @param[in] rhs Right-hand side Dimensions. 263 * 264 * @return True if the given dimensions are not equal. 265 */ 266 template <typename T> 267 inline bool operator!=(const Dimensions<T> &lhs, const Dimensions<T> &rhs) 268 { 269 return !(lhs == rhs); 270 } 271 } 272 #endif /*ARM_COMPUTE_DIMENSIONS_H*/ 273