1 /* 2 * Copyright (c) 2017-2021 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 <limits> 33 #include <numeric> 34 35 namespace arm_compute 36 { 37 /** Constant value used to indicate maximum dimensions of a Window, TensorShape and Coordinates */ 38 constexpr size_t MAX_DIMS = 6; 39 40 /** Dimensions with dimensionality */ 41 template <typename T> 42 class Dimensions 43 { 44 public: 45 /** Number of dimensions the tensor has */ 46 static constexpr size_t num_max_dimensions = MAX_DIMS; 47 48 /** Constructor to initialize the tensor shape. 49 * 50 * @param[in] dims Values to initialize the dimensions. 51 */ 52 template <typename... Ts> Dimensions(Ts...dims)53 explicit Dimensions(Ts... dims) 54 : _id{ { static_cast<T>(dims)... } }, _num_dimensions{ sizeof...(dims) } 55 { 56 } 57 58 /** Allow instances of this class to be copy constructed */ 59 Dimensions(const Dimensions &) = default; 60 61 /** Allow instances of this class to be copied */ 62 Dimensions &operator=(const Dimensions &) = default; 63 64 /** Allow instances of this class to be move constructed */ 65 Dimensions(Dimensions &&) = default; 66 67 /** Allow instances of this class to be moved */ 68 Dimensions &operator=(Dimensions &&) = default; 69 70 /** Accessor to set the value of one of the dimensions. 71 * 72 * @param[in] dimension Dimension for which the value is set. 73 * @param[in] value Value to be set for the dimension. 74 * @param[in] increase_dim_unit (Optional) Set to true if new unit dimensions increase the number of dimensions (e.g. for Coordinates), false otherwise (e.g. for TensorShapes) 75 */ 76 void set(size_t dimension, T value, bool increase_dim_unit = true) 77 { 78 ARM_COMPUTE_ERROR_ON(dimension >= num_max_dimensions); 79 _id[dimension] = value; 80 // Don't increase the number of dimensions if the new dimension is 1 81 if(increase_dim_unit || value != 1) 82 { 83 _num_dimensions = std::max(_num_dimensions, dimension + 1); 84 } 85 } 86 /** Alias to access the size of the first dimension */ x()87 T x() const 88 { 89 return _id[0]; 90 } 91 /** Alias to access the size of the second dimension */ y()92 T y() const 93 { 94 return _id[1]; 95 } 96 /** Alias to access the size of the third dimension */ z()97 T z() const 98 { 99 return _id[2]; 100 } 101 /** Increments the given dimension by a step size, avoiding overflows 102 * 103 * @note Precondition: dim < _num_dimensions 104 * 105 * @param[in] dim Dimension to increment. 106 * @param[in] step Step to increment @p dim by. 107 */ 108 void increment(size_t dim, T step = 1) 109 { 110 ARM_COMPUTE_ERROR_ON(dim >= _num_dimensions); 111 if((std::numeric_limits<T>::max() - _id[dim]) >= step) 112 { 113 _id[dim] += step; 114 } 115 } 116 /** Generic accessor to get the size of any dimension 117 * 118 * @note Precondition: dimension < Dimensions::num_max_dimensions 119 * 120 * @param[in] dimension Dimension of the wanted size 121 * 122 * @return The size of the requested dimension. 123 */ 124 const T &operator[](size_t dimension) const 125 { 126 ARM_COMPUTE_ERROR_ON(dimension >= num_max_dimensions); 127 return _id[dimension]; 128 } 129 /** Generic accessor to get the size of any dimension 130 * 131 * @note Precondition: dimension < Dimensions::num_max_dimensions 132 * 133 * @param[in] dimension Dimension of the wanted size 134 * 135 * @return The size of the requested dimension. 136 */ 137 T &operator[](size_t dimension) 138 { 139 ARM_COMPUTE_ERROR_ON(dimension >= num_max_dimensions); 140 return _id[dimension]; 141 } 142 /** Returns the effective dimensionality of the tensor */ num_dimensions()143 unsigned int num_dimensions() const 144 { 145 return _num_dimensions; 146 } 147 148 /** Set number of dimensions */ set_num_dimensions(size_t num_dimensions)149 void set_num_dimensions(size_t num_dimensions) 150 { 151 _num_dimensions = num_dimensions; 152 } 153 154 /** Collapse dimensions. 155 * 156 * @param[in] n Number of dimensions to collapse into @p first. 157 * @param[in] first Dimensions into which the following @p n are collapsed. 158 */ 159 void collapse(const size_t n, const size_t first = 0) 160 { 161 ARM_COMPUTE_ERROR_ON(first + n > _id.size()); 162 163 const size_t last = std::min(_num_dimensions, first + n); 164 165 if(last > (first + 1)) 166 { 167 // Collapse dimensions into the first 168 _id[first] = std::accumulate(&_id[first], &_id[last], 1, std::multiplies<T>()); 169 // Shift the remaining dimensions down 170 std::copy(&_id[last], &_id[_num_dimensions], &_id[first + 1]); 171 // Reduce the number of dimensions 172 const size_t old_num_dimensions = _num_dimensions; 173 _num_dimensions -= last - first - 1; 174 // Fill the now empty dimensions with zero 175 std::fill(&_id[_num_dimensions], &_id[old_num_dimensions], 0); 176 } 177 } 178 179 /** Collapse dimensions starting from a given point 180 * 181 * @param[in] start Starting point of collapsing dimensions 182 */ collapse_from(size_t start)183 void collapse_from(size_t start) 184 { 185 ARM_COMPUTE_ERROR_ON(start > num_dimensions()); 186 187 collapse(num_dimensions() - start, start); 188 } 189 190 /** Remove dimension of a given index 191 * 192 * @note If index is greater than the number of dimensions no operation is performed 193 * 194 * @param[in] idx Dimension index to remove 195 */ remove(size_t idx)196 void remove(size_t idx) 197 { 198 ARM_COMPUTE_ERROR_ON(_num_dimensions < 1); 199 if(idx >= _num_dimensions) 200 { 201 return; 202 } 203 204 std::copy(_id.begin() + idx + 1, _id.end(), _id.begin() + idx); 205 _num_dimensions--; 206 207 // Make sure all empty dimensions are filled with 0 208 std::fill(_id.begin() + _num_dimensions, _id.end(), 0); 209 } 210 211 /** Returns a read/write iterator that points to the first element in the dimension array. 212 * 213 * @return an iterator. 214 */ begin()215 typename std::array<T, num_max_dimensions>::iterator begin() 216 { 217 return _id.begin(); 218 } 219 /** Returns a read-only (constant) iterator that points to the first element in the dimension array. 220 * 221 * @return an iterator. 222 */ begin()223 typename std::array<T, num_max_dimensions>::const_iterator begin() const 224 { 225 return _id.begin(); 226 } 227 /** Returns a read-only (constant) iterator that points to the first element in the dimension array. 228 * 229 * @return an iterator. 230 */ cbegin()231 typename std::array<T, num_max_dimensions>::const_iterator cbegin() const 232 { 233 return begin(); 234 } 235 /** Returns a read/write iterator that points one past the last element in the dimension array. 236 * 237 * @return an iterator. 238 */ end()239 typename std::array<T, num_max_dimensions>::iterator end() 240 { 241 return _id.end(); 242 } 243 /** Returns a read-only (constant) iterator that points one past the last element in the dimension array. 244 * 245 * @return an iterator. 246 */ end()247 typename std::array<T, num_max_dimensions>::const_iterator end() const 248 { 249 return _id.end(); 250 } 251 /** Returns a read-only (constant) iterator that points one past the last element in the dimension array. 252 * 253 * @return an iterator. 254 */ cend()255 typename std::array<T, num_max_dimensions>::const_iterator cend() const 256 { 257 return end(); 258 } 259 260 protected: 261 /** Protected destructor. */ 262 ~Dimensions() = default; 263 264 std::array<T, num_max_dimensions> _id; 265 size_t _num_dimensions{ 0 }; 266 }; 267 268 /** Check that given dimensions are equal. 269 * 270 * @param[in] lhs Left-hand side Dimensions. 271 * @param[in] rhs Right-hand side Dimensions. 272 * 273 * @return True if the given dimensions are equal. 274 */ 275 template <typename T> 276 inline bool operator==(const Dimensions<T> &lhs, const Dimensions<T> &rhs) 277 { 278 return ((lhs.num_dimensions() == rhs.num_dimensions()) && std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin())); 279 } 280 /** Check that given dimensions are not equal. 281 * 282 * @param[in] lhs Left-hand side Dimensions. 283 * @param[in] rhs Right-hand side Dimensions. 284 * 285 * @return True if the given dimensions are not equal. 286 */ 287 template <typename T> 288 inline bool operator!=(const Dimensions<T> &lhs, const Dimensions<T> &rhs) 289 { 290 return !(lhs == rhs); 291 } 292 } 293 #endif /*ARM_COMPUTE_DIMENSIONS_H*/ 294