Compute Library
 23.08
TensorShape.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2021, 2023 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_TENSORSHAPE_H
25 #define ARM_COMPUTE_TENSORSHAPE_H
26 
28 #include "arm_compute/core/Error.h"
30 
31 #include <algorithm>
32 #include <array>
33 #include <functional>
34 #include <numeric>
35 
36 namespace arm_compute
37 {
38 /** Shape of a tensor */
39 class TensorShape : public Dimensions<size_t>
40 {
41 public:
42  /** Constructor to initialize the tensor shape.
43  *
44  * @param[in] dims Values to initialize the dimensions.
45  */
46  template <typename... Ts>
47  TensorShape(Ts... dims)
48  : Dimensions{ dims... }
49  {
50  // Initialize unspecified dimensions to 1
51  if(_num_dimensions > 0)
52  {
53  std::fill(_id.begin() + _num_dimensions, _id.end(), 1);
54  }
55 
56  // Correct number dimensions to ignore trailing dimensions of size 1
57  apply_dimension_correction();
58  }
59  /** Allow instances of this class to be copy constructed */
60  TensorShape(const TensorShape &) = default;
61  /** Allow instances of this class to be copied */
62  TensorShape &operator=(const TensorShape &) = default;
63  /** Allow instances of this class to be move constructed */
64  TensorShape(TensorShape &&) = default;
65  /** Allow instances of this class to be moved */
66  TensorShape &operator=(TensorShape &&) = default;
67  /** Default destructor */
68  ~TensorShape() = 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] apply_dim_correction (Optional) Flag to state whether apply dimension correction after setting one dimension. E.g. when permuting NCHW -> NHWC, 1x1x2 would become 2x1x1, but _num_dimensions should be 3 rather than 1.
75  * @param[in] increase_dim_unit (Optional) Set to true if new unit dimensions increase the number of dimensions of the shape.
76  *
77  * @return *this.
78  */
79  TensorShape &set(size_t dimension, size_t value, bool apply_dim_correction = true, bool increase_dim_unit = true)
80  {
81  // Clear entire shape if one dimension is zero
82  if(value == 0)
83  {
84  _num_dimensions = 0;
85  std::fill(_id.begin(), _id.end(), 0);
86  }
87  else
88  {
89  // Make sure all empty dimensions are filled with 1
90  std::fill(_id.begin() + _num_dimensions, _id.end(), 1);
91 
92  // Set the specified dimension and increase the number of dimensions if
93  // necessary
94  Dimensions::set(dimension, value, increase_dim_unit);
95 
96  // Correct number dimensions to ignore trailing dimensions of size 1
97  if(apply_dim_correction)
98  {
99  apply_dimension_correction();
100  }
101  }
102  return *this;
103  }
104 
105  /** Accessor to remove the dimension n from the tensor shape.
106  *
107  * @note The upper dimensions of the tensor shape will be shifted down by 1
108  *
109  * @param[in] n Dimension to remove
110  * @param[in] apply_dim_correction (Optional) Flag to state whether apply dimension correction (removing trailing dimensions with size of 1) after removing a dimension.
111  */
112  void remove_dimension(size_t n, bool apply_dim_correction = true)
113  {
114  ARM_COMPUTE_ERROR_ON(_num_dimensions < 1);
115  ARM_COMPUTE_ERROR_ON(n >= _num_dimensions);
116 
117  std::copy(_id.begin() + n + 1, _id.end(), _id.begin() + n);
118 
119  // Reduce number of dimensions
120  _num_dimensions--;
121 
122  // Make sure all empty dimensions are filled with 1
123  std::fill(_id.begin() + _num_dimensions, _id.end(), 1);
124 
125  // Correct number dimensions to ignore trailing dimensions of size 1
126  if(apply_dim_correction)
127  {
128  apply_dimension_correction();
129  }
130  }
131 
132  /** Collapse the first n dimensions.
133  *
134  * @param[in] n Number of dimensions to collapse into @p first
135  * @param[in] first Dimensions into which the following @p n are collapsed.
136  */
137  void collapse(size_t n, size_t first = 0)
138  {
139  Dimensions::collapse(n, first);
140 
141  // Make sure all empty dimensions are filled with 1
142  std::fill(_id.begin() + _num_dimensions, _id.end(), 1);
143  }
144  /** Shifts right the tensor shape increasing its dimensions
145  *
146  * @param[in] step Rotation step
147  */
148  void shift_right(size_t step)
149  {
151 
152  std::rotate(begin(), begin() + TensorShape::num_max_dimensions - step, end());
153  _num_dimensions += step;
154 
155  // Correct number dimensions to ignore trailing dimensions of size 1
156  apply_dimension_correction();
157  }
158 
159  /** Return a copy with collapsed dimensions starting from a given point.
160  *
161  * @param[in] start Starting point of collapsing dimensions.
162  *
163  * @return A copy with collapse dimensions starting from start.
164  */
165  TensorShape collapsed_from(size_t start) const
166  {
167  TensorShape copy(*this);
168  copy.collapse(num_dimensions() - start, start);
169  return copy;
170  }
171 
172  /** Collapses all dimensions to a single linear total size.
173  *
174  * @return The total tensor size in terms of elements.
175  */
176  size_t total_size() const
177  {
178  return std::accumulate(_id.begin(), _id.end(), 1, std::multiplies<size_t>());
179  }
180  /** Collapses given dimension and above.
181  *
182  * @param[in] dimension Size of the wanted dimension
183  *
184  * @return The linear size of the collapsed dimensions
185  */
186  size_t total_size_upper(size_t dimension) const
187  {
189  return std::accumulate(_id.begin() + dimension, _id.end(), 1, std::multiplies<size_t>());
190  }
191 
192  /** Compute size of dimensions lower than the given one.
193  *
194  * @param[in] dimension Upper boundary.
195  *
196  * @return The linear size of the collapsed dimensions.
197  */
198  size_t total_size_lower(size_t dimension) const
199  {
201  return std::accumulate(_id.begin(), _id.begin() + dimension, 1, std::multiplies<size_t>());
202  }
203 
204  /** If shapes are broadcast compatible, return the broadcasted shape.
205  *
206  * Two tensor shapes are broadcast compatible if for each dimension, they're equal or one of them is 1.
207  *
208  * If two shapes are compatible, each dimension in the broadcasted shape is the max of the original dimensions.
209  *
210  * @param[in] shapes Tensor shapes.
211  *
212  * @return The broadcasted shape or an empty shape if the shapes are not broadcast compatible.
213  */
214  template <typename... Shapes>
215  static TensorShape broadcast_shape(const Shapes &... shapes)
216  {
217  TensorShape bc_shape;
218 
219  auto broadcast = [&bc_shape](const TensorShape & other)
220  {
221  if(bc_shape.num_dimensions() == 0)
222  {
223  bc_shape = other;
224  }
225  else if(other.num_dimensions() != 0)
226  {
227  for(size_t d = 0; d < TensorShape::num_max_dimensions; ++d)
228  {
229  const size_t dim_min = std::min(bc_shape[d], other[d]);
230  const size_t dim_max = std::max(bc_shape[d], other[d]);
231 
232  if((dim_min != 1) && (dim_min != dim_max))
233  {
234  bc_shape = TensorShape{ 0U };
235  break;
236  }
237 
238  bc_shape.set(d, dim_max);
239  }
240  }
241  };
242 
243  utility::for_each(broadcast, shapes...);
244 
245  return bc_shape;
246  }
247 
248 private:
249  /** Remove trailing dimensions of size 1 from the reported number of dimensions. */
250  void apply_dimension_correction()
251  {
252  for(int i = static_cast<int>(_num_dimensions) - 1; i > 0; --i)
253  {
254  if(_id[i] == 1)
255  {
256  --_num_dimensions;
257  }
258  else
259  {
260  break;
261  }
262  }
263  }
264 };
265 }
266 #endif /*ARM_COMPUTE_TENSORSHAPE_H*/
arm_compute::Dimensions::set
void set(size_t dimension, T value, bool increase_dim_unit=true)
Accessor to set the value of one of the dimensions.
Definition: Dimensions.h:76
arm_compute::TensorShape::TensorShape
TensorShape(Ts... dims)
Constructor to initialize the tensor shape.
Definition: TensorShape.h:47
arm_compute::TensorShape
Shape of a tensor.
Definition: TensorShape.h:39
Error.h
arm_compute::TensorShape::total_size_upper
size_t total_size_upper(size_t dimension) const
Collapses given dimension and above.
Definition: TensorShape.h:186
arm_compute::TensorShape::shift_right
void shift_right(size_t step)
Shifts right the tensor shape increasing its dimensions.
Definition: TensorShape.h:148
arm_compute::utils::cast::U
U
Definition: SaturateCast.h:64
ARM_COMPUTE_ERROR_ON
#define ARM_COMPUTE_ERROR_ON(cond)
If the condition is true then an error message is printed and an exception thrown.
Definition: Error.h:467
Utility.h
arm_compute::TensorShape::total_size_lower
size_t total_size_lower(size_t dimension) const
Compute size of dimensions lower than the given one.
Definition: TensorShape.h:198
arm_compute::TensorShape::operator=
TensorShape & operator=(const TensorShape &)=default
Allow instances of this class to be copied.
arm_compute::TensorShape::total_size
size_t total_size() const
Collapses all dimensions to a single linear total size.
Definition: TensorShape.h:176
arm_compute::TensorShape::broadcast_shape
static TensorShape broadcast_shape(const Shapes &... shapes)
If shapes are broadcast compatible, return the broadcasted shape.
Definition: TensorShape.h:215
arm_compute::Dimensions::collapse
void collapse(const size_t n, const size_t first=0)
Collapse dimensions.
Definition: Dimensions.h:159
arm_compute::test::validation::fill
library fill(src, distribution, 0)
arm_compute::test::validation::reference::copy
SimpleTensor< T > copy(const SimpleTensor< T > &src, const TensorShape &output_shape)
Definition: Copy.cpp:37
arm_compute::TensorShape::~TensorShape
~TensorShape()=default
Default destructor.
arm_compute::test::validation::reference::accumulate
SimpleTensor< T2 > accumulate(const SimpleTensor< T1 > &src, DataType output_data_type)
Definition: Accumulate.cpp:38
arm_compute::Dimensions< size_t >::begin
std::array< size_t, num_max_dimensions >::iterator begin()
Returns a read/write iterator that points to the first element in the dimension array.
Definition: Dimensions.h:215
arm_compute
Copyright (c) 2017-2023 Arm Limited.
Definition: introduction.dox:24
arm_compute::TensorShape::remove_dimension
void remove_dimension(size_t n, bool apply_dim_correction=true)
Accessor to remove the dimension n from the tensor shape.
Definition: TensorShape.h:112
arm_compute::Dimensions< size_t >::end
std::array< size_t, num_max_dimensions >::iterator end()
Returns a read/write iterator that points one past the last element in the dimension array.
Definition: Dimensions.h:239
Dimensions.h
arm_compute::cpu::step
constexpr int step
Definition: fp32.cpp:35
arm_compute::TensorShape::set
TensorShape & set(size_t dimension, size_t value, bool apply_dim_correction=true, bool increase_dim_unit=true)
Accessor to set the value of one of the dimensions.
Definition: TensorShape.h:79
arm_compute::Dimensions
Dimensions with dimensionality.
Definition: Dimensions.h:42
arm_compute::TensorShape::collapsed_from
TensorShape collapsed_from(size_t start) const
Return a copy with collapsed dimensions starting from a given point.
Definition: TensorShape.h:165
arm_compute::utility::for_each
void for_each(F &&)
Base case of for_each.
Definition: Utility.h:111
arm_compute::Dimensions< size_t >::num_dimensions
unsigned int num_dimensions() const
Returns the effective dimensionality of the tensor.
Definition: Dimensions.h:143
arm_compute::Dimensions< size_t >::num_max_dimensions
static constexpr size_t num_max_dimensions
Number of dimensions the tensor has.
Definition: Dimensions.h:46
arm_compute::test::validation::n
const unsigned int n
Definition: GEMMMatrixMultiplyNative.cpp:360
arm_compute::TensorShape::collapse
void collapse(size_t n, size_t first=0)
Collapse the first n dimensions.
Definition: TensorShape.h:137