Compute Library
 20.05
Helpers.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2020 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_HELPERS_H
25 #define ARM_COMPUTE_HELPERS_H
26 
28 #include "arm_compute/core/Error.h"
30 #include "arm_compute/core/Steps.h"
33 #include "arm_compute/core/Types.h"
35 #include "support/MemorySupport.h"
36 
37 #include <array>
38 #include <cstddef>
39 #include <cstdint>
40 #include <memory>
41 #include <tuple>
42 #include <type_traits>
43 #include <utility>
44 
45 namespace arm_compute
46 {
47 class IKernel;
48 class ITensor;
49 class ITensorInfo;
50 
51 /** Disable bitwise operations by default */
52 template <typename T>
54 {
55  static constexpr bool value = false; /**< Disabled */
56 };
57 
58 #ifndef DOXYGEN_SKIP_THIS
59 template <typename T>
60 typename std::enable_if<enable_bitwise_ops<T>::value, T>::type operator&(T lhs, T rhs)
61 {
62  using underlying_type = typename std::underlying_type<T>::type;
63  return static_cast<T>(static_cast<underlying_type>(lhs) & static_cast<underlying_type>(rhs));
64 }
65 #endif /* DOXYGEN_SKIP_THIS */
66 
67 /** Helper function to create and return a unique_ptr pointed to a CL/GLES kernel object
68  * It also calls the kernel's configuration.
69  *
70  * @param[in] args All the arguments that need pass to kernel's configuration.
71  *
72  * @return A unique pointer pointed to a CL/GLES kernel object
73  */
74 template <typename Kernel, typename... T>
75 std::unique_ptr<Kernel> create_configure_kernel(T &&... args)
76 {
77  std::unique_ptr<Kernel> k = arm_compute::support::cpp14::make_unique<Kernel>();
78  k->configure(std::forward<T>(args)...);
79  return k;
80 }
81 
82 /** Helper function to create and return a unique_ptr pointed to a CL/GLES kernel object
83  *
84  * @return A unique pointer pointed to a Kernel kernel object
85  */
86 template <typename Kernel>
87 std::unique_ptr<Kernel> create_kernel()
88 {
89  std::unique_ptr<Kernel> k = arm_compute::support::cpp14::make_unique<Kernel>();
90  return k;
91 }
92 
93 namespace traits
94 {
95 /** Check if a type T is contained in a tuple Tuple of types */
96 template <typename T, typename Tuple>
97 struct is_contained;
98 
99 template <typename T>
100 struct is_contained<T, std::tuple<>> : std::false_type
101 {
102 };
103 
104 template <typename T, typename... Ts>
105 struct is_contained<T, std::tuple<T, Ts...>> : std::true_type
106 {
107 };
108 
109 template <typename T, typename U, typename... Ts>
110 struct is_contained<T, std::tuple<U, Ts...>> : is_contained<T, std::tuple<Ts...>>
111 {
112 };
113 }
114 
115 /** Computes bilinear interpolation using the pointer to the top-left pixel and the pixel's distance between
116  * the real coordinates and the smallest following integer coordinates. Input must be in single channel format.
117  *
118  * @param[in] pixel_ptr Pointer to the top-left pixel value of a single channel input.
119  * @param[in] stride Stride to access the bottom-left and bottom-right pixel values
120  * @param[in] dx Pixel's distance between the X real coordinate and the smallest X following integer
121  * @param[in] dy Pixel's distance between the Y real coordinate and the smallest Y following integer
122  *
123  * @note dx and dy must be in the range [0, 1.0]
124  *
125  * @return The bilinear interpolated pixel value
126  */
127 template <typename T>
128 inline T delta_bilinear_c1(const T *pixel_ptr, size_t stride, float dx, float dy)
129 {
130  ARM_COMPUTE_ERROR_ON(pixel_ptr == nullptr);
131 
132  const float dx1 = 1.0f - dx;
133  const float dy1 = 1.0f - dy;
134 
135  const T a00 = *pixel_ptr;
136  const T a01 = *(pixel_ptr + 1);
137  const T a10 = *(pixel_ptr + stride);
138  const T a11 = *(pixel_ptr + stride + 1);
139 
140  const float w1 = dx1 * dy1;
141  const float w2 = dx * dy1;
142  const float w3 = dx1 * dy;
143  const float w4 = dx * dy;
144 
145  return static_cast<T>(a00 * w1 + a01 * w2 + a10 * w3 + a11 * w4);
146 }
147 
148 /** Computes bilinear interpolation for quantized input and output, using the pointer to the top-left pixel and the pixel's distance between
149  * the real coordinates and the smallest following integer coordinates. Input must be QASYMM8 and in single channel format.
150  *
151  * @param[in] pixel_ptr Pointer to the top-left pixel value of a single channel input.
152  * @param[in] stride Stride to access the bottom-left and bottom-right pixel values
153  * @param[in] dx Pixel's distance between the X real coordinate and the smallest X following integer
154  * @param[in] dy Pixel's distance between the Y real coordinate and the smallest Y following integer
155  * @param[in] iq_info Input QuantizationInfo
156  * @param[in] oq_info Output QuantizationInfo
157  *
158  * @note dx and dy must be in the range [0, 1.0]
159  *
160  * @return The bilinear interpolated pixel value
161  */
162 inline uint8_t delta_bilinear_c1_quantized(const uint8_t *pixel_ptr, size_t stride, float dx, float dy, UniformQuantizationInfo iq_info, UniformQuantizationInfo oq_info)
163 {
164  ARM_COMPUTE_ERROR_ON(pixel_ptr == nullptr);
165 
166  const float dx1 = 1.0f - dx;
167  const float dy1 = 1.0f - dy;
168 
169  const float a00 = dequantize_qasymm8(*pixel_ptr, iq_info);
170  const float a01 = dequantize_qasymm8(*(pixel_ptr + 1), iq_info);
171  const float a10 = dequantize_qasymm8(*(pixel_ptr + stride), iq_info);
172  const float a11 = dequantize_qasymm8(*(pixel_ptr + stride + 1), iq_info);
173 
174  const float w1 = dx1 * dy1;
175  const float w2 = dx * dy1;
176  const float w3 = dx1 * dy;
177  const float w4 = dx * dy;
178  float res = a00 * w1 + a01 * w2 + a10 * w3 + a11 * w4;
179  return static_cast<uint8_t>(quantize_qasymm8(res, oq_info));
180 }
181 
182 /** Computes bilinear interpolation for quantized input and output, using the pointer to the top-left pixel and the pixel's distance between
183  * the real coordinates and the smallest following integer coordinates. Input must be QASYMM8_SIGNED and in single channel format.
184  *
185  * @param[in] pixel_ptr Pointer to the top-left pixel value of a single channel input.
186  * @param[in] stride Stride to access the bottom-left and bottom-right pixel values
187  * @param[in] dx Pixel's distance between the X real coordinate and the smallest X following integer
188  * @param[in] dy Pixel's distance between the Y real coordinate and the smallest Y following integer
189  * @param[in] iq_info Input QuantizationInfo
190  * @param[in] oq_info Output QuantizationInfo
191  *
192  * @note dx and dy must be in the range [0, 1.0]
193  *
194  * @return The bilinear interpolated pixel value
195  */
196 inline int8_t delta_bilinear_c1_quantized(const int8_t *pixel_ptr, size_t stride, float dx, float dy, UniformQuantizationInfo iq_info, UniformQuantizationInfo oq_info)
197 {
198  ARM_COMPUTE_ERROR_ON(pixel_ptr == nullptr);
199 
200  const float dx1 = 1.0f - dx;
201  const float dy1 = 1.0f - dy;
202 
203  const float a00 = dequantize_qasymm8_signed(*pixel_ptr, iq_info);
204  const float a01 = dequantize_qasymm8_signed(*(pixel_ptr + 1), iq_info);
205  const float a10 = dequantize_qasymm8_signed(*(pixel_ptr + stride), iq_info);
206  const float a11 = dequantize_qasymm8_signed(*(pixel_ptr + stride + 1), iq_info);
207 
208  const float w1 = dx1 * dy1;
209  const float w2 = dx * dy1;
210  const float w3 = dx1 * dy;
211  const float w4 = dx * dy;
212  float res = a00 * w1 + a01 * w2 + a10 * w3 + a11 * w4;
213  return static_cast<int8_t>(quantize_qasymm8_signed(res, oq_info));
214 }
215 
216 /** Computes linear interpolation using the pointer to the top pixel and the pixel's distance between
217  * the real coordinates and the smallest following integer coordinates. Input must be in single channel format.
218  *
219  * @param[in] pixel_ptr Pointer to the top pixel value of a single channel input.
220  * @param[in] stride Stride to access the bottom pixel value
221  * @param[in] dy Pixel's distance between the Y real coordinate and the smallest Y following integer
222  *
223  * @note dy must be in the range [0, 1.0]
224  *
225  * @return The linear interpolated pixel value
226  */
227 template <typename T>
228 inline T delta_linear_c1_y(const T *pixel_ptr, size_t stride, float dy)
229 {
230  ARM_COMPUTE_ERROR_ON(pixel_ptr == nullptr);
231 
232  const float dy1 = 1.0f - dy;
233 
234  const T a00 = *pixel_ptr;
235  const T a10 = *(pixel_ptr + stride);
236 
237  const float w1 = dy1;
238  const float w3 = dy;
239 
240  return static_cast<T>(a00 * w1 + a10 * w3);
241 }
242 /** Computes linear interpolation using the pointer to the left pixel and the pixel's distance between
243  * the real coordinates and the smallest following integer coordinates. Input must be in single channel format.
244  *
245  * @param[in] pixel_ptr Pointer to the left pixel value of a single channel input.
246  * @param[in] dx Pixel's distance between the X real coordinate and the smallest X following integer
247  *
248  * @note dx must be in the range [0, 1.0]
249  *
250  * @return The linear interpolated pixel value
251  */
252 template <typename T>
253 inline T delta_linear_c1_x(const T *pixel_ptr, float dx)
254 {
255  ARM_COMPUTE_ERROR_ON(pixel_ptr == nullptr);
256 
257  const T a00 = *pixel_ptr;
258  const T a01 = *(pixel_ptr + 1);
259 
260  const float dx1 = 1.0f - dx;
261 
262  const float w1 = dx1;
263  const float w2 = dx;
264 
265  return static_cast<T>(a00 * w1 + a01 * w2);
266 }
267 /** Return the pixel at (x,y) using bilinear interpolation.
268  *
269  * @warning Only works if the iterator was created with an IImage
270  *
271  * @param[in] first_pixel_ptr Pointer to the first pixel of a single channel input.
272  * @param[in] stride Stride in bytes of the image;
273  * @param[in] x X position of the wanted pixel
274  * @param[in] y Y position of the wanted pixel
275  *
276  * @return The pixel at (x, y) using bilinear interpolation.
277  */
278 template <typename T>
279 inline T pixel_bilinear_c1(const T *first_pixel_ptr, size_t stride, float x, float y)
280 {
281  ARM_COMPUTE_ERROR_ON(first_pixel_ptr == nullptr);
282 
283  const int32_t xi = std::floor(x);
284  const int32_t yi = std::floor(y);
285 
286  const float dx = x - xi;
287  const float dy = y - yi;
288 
289  return delta_bilinear_c1(first_pixel_ptr + xi + yi * stride, stride, dx, dy);
290 }
291 
292 /** Return the pixel at (x,y) using bilinear interpolation by clamping when out of borders. The image must be single channel input
293  *
294  * @warning Only works if the iterator was created with an IImage
295  *
296  * @param[in] first_pixel_ptr Pointer to the first pixel of a single channel image.
297  * @param[in] stride Stride in bytes of the image
298  * @param[in] width Width of the image
299  * @param[in] height Height of the image
300  * @param[in] x X position of the wanted pixel
301  * @param[in] y Y position of the wanted pixel
302  *
303  * @return The pixel at (x, y) using bilinear interpolation.
304  */
305 template <typename T>
306 inline uint8_t pixel_bilinear_c1_clamp(const T *first_pixel_ptr, size_t stride, size_t width, size_t height, float x, float y)
307 {
308  ARM_COMPUTE_ERROR_ON(first_pixel_ptr == nullptr);
309 
310  x = std::max(-1.f, std::min(x, static_cast<float>(width)));
311  y = std::max(-1.f, std::min(y, static_cast<float>(height)));
312 
313  const float xi = std::floor(x);
314  const float yi = std::floor(y);
315 
316  const float dx = x - xi;
317  const float dy = y - yi;
318 
319  if(dx == 0.0f)
320  {
321  if(dy == 0.0f)
322  {
323  return static_cast<T>(first_pixel_ptr[static_cast<int32_t>(xi) + static_cast<int32_t>(yi) * stride]);
324  }
325  return delta_linear_c1_y(first_pixel_ptr + static_cast<int32_t>(xi) + static_cast<int32_t>(yi) * stride, stride, dy);
326  }
327  if(dy == 0.0f)
328  {
329  return delta_linear_c1_x(first_pixel_ptr + static_cast<int32_t>(xi) + static_cast<int32_t>(yi) * stride, dx);
330  }
331  return delta_bilinear_c1(first_pixel_ptr + static_cast<int32_t>(xi) + static_cast<int32_t>(yi) * stride, stride, dx, dy);
332 }
333 
334 /** Return the pixel at (x,y) using area interpolation by clamping when out of borders. The image must be single channel U8
335  *
336  * @note The interpolation area depends on the width and height ration of the input and output images
337  * @note Currently average of the contributing pixels is calculated
338  *
339  * @param[in] first_pixel_ptr Pointer to the first pixel of a single channel U8 image.
340  * @param[in] stride Stride in bytes of the image
341  * @param[in] width Width of the image
342  * @param[in] height Height of the image
343  * @param[in] wr Width ratio among the input image width and output image width.
344  * @param[in] hr Height ratio among the input image height and output image height.
345  * @param[in] x X position of the wanted pixel
346  * @param[in] y Y position of the wanted pixel
347  *
348  * @return The pixel at (x, y) using area interpolation.
349  */
350 inline uint8_t pixel_area_c1u8_clamp(const uint8_t *first_pixel_ptr, size_t stride, size_t width, size_t height, float wr, float hr, int x, int y);
351 
352 /** Iterator updated by @ref execute_window_loop for each window element */
353 class Iterator
354 {
355 public:
356  /** Default constructor to create an empty iterator */
357  constexpr Iterator();
358  /** Create a container iterator for the metadata and allocation contained in the ITensor
359  *
360  * @param[in] tensor The tensor to associate to the iterator.
361  * @param[in] window The window which will be used to iterate over the tensor.
362  */
363  Iterator(const ITensor *tensor, const Window &window);
364 
365  /** Increment the iterator along the specified dimension of the step value associated to the dimension.
366  *
367  * @warning It is the caller's responsibility to call increment(dimension+1) when reaching the end of a dimension, the iterator will not check for overflow.
368  *
369  * @note When incrementing a dimension 'n' the coordinates of all the dimensions in the range (0,n-1) are reset. For example if you iterate over a 2D image, everytime you change row (dimension 1), the iterator for the width (dimension 0) is reset to its start.
370  *
371  * @param[in] dimension Dimension to increment
372  */
373  void increment(size_t dimension);
374 
375  /** Return the offset in bytes from the first element to the current position of the iterator
376  *
377  * @return The current position of the iterator in bytes relative to the first element.
378  */
379  constexpr int offset() const;
380 
381  /** Return a pointer to the current pixel.
382  *
383  * @warning Only works if the iterator was created with an ITensor.
384  *
385  * @return equivalent to buffer() + offset()
386  */
387  constexpr uint8_t *ptr() const;
388 
389  /** Move the iterator back to the beginning of the specified dimension.
390  *
391  * @param[in] dimension Dimension to reset
392  */
393  void reset(size_t dimension);
394 
395 private:
396  uint8_t *_ptr;
397 
398  class Dimension
399  {
400  public:
401  constexpr Dimension()
402  : _dim_start(0), _stride(0)
403  {
404  }
405 
406  int _dim_start;
407  int _stride;
408  };
409 
410  std::array<Dimension, Coordinates::num_max_dimensions> _dims;
411 };
412 
413 /** Iterate through the passed window, automatically adjusting the iterators and calling the lambda_functino for each element.
414  * It passes the x and y positions to the lambda_function for each iteration
415  *
416  * @param[in] w Window to iterate through.
417  * @param[in] lambda_function The function of type void(function)( const Coordinates & id ) to call at each iteration.
418  * Where id represents the absolute coordinates of the item to process.
419  * @param[in,out] iterators Tensor iterators which will be updated by this function before calling lambda_function.
420  */
421 template <typename L, typename... Ts>
422 inline void execute_window_loop(const Window &w, L &&lambda_function, Ts &&... iterators);
423 
424 /** Update window and padding size for each of the access patterns.
425  *
426  * First the window size is reduced based on all access patterns that are not
427  * allowed to modify the padding of the underlying tensor. Then the padding of
428  * the remaining tensors is increased to match the window.
429  *
430  * @param[in] win Window that is used by the kernel.
431  * @param[in] patterns Access patterns used to calculate the final window and padding.
432  *
433  * @return True if the window has been changed. Changes to the padding do not
434  * influence the returned value.
435  */
436 template <typename... Ts>
437 bool update_window_and_padding(Window &win, Ts &&... patterns)
438 {
439  bool window_changed = false;
440 
441  utility::for_each([&](const IAccessWindow & w)
442  {
443  window_changed |= w.update_window_if_needed(win);
444  },
445  patterns...);
446 
447  bool padding_changed = false;
448 
450  {
451  padding_changed |= w.update_padding_if_needed(win);
452  },
453  patterns...);
454 
455  return window_changed;
456 }
457 
458 /** Calculate the maximum window for a given tensor shape and border setting
459  *
460  * @param[in] valid_region Valid region object defining the shape of the tensor space for which the window is created.
461  * @param[in] steps (Optional) Number of elements processed for each step.
462  * @param[in] skip_border (Optional) If true exclude the border region from the window.
463  * @param[in] border_size (Optional) Border size.
464  *
465  * @return The maximum window the kernel can be executed on.
466  */
467 Window calculate_max_window(const ValidRegion &valid_region, const Steps &steps = Steps(), bool skip_border = false, BorderSize border_size = BorderSize());
468 
469 /** Calculate the maximum window for a given tensor shape and border setting
470  *
471  * @param[in] info Tensor info object defining the shape of the object for which the window is created.
472  * @param[in] steps (Optional) Number of elements processed for each step.
473  * @param[in] skip_border (Optional) If true exclude the border region from the window.
474  * @param[in] border_size (Optional) Border size.
475  *
476  * @return The maximum window the kernel can be executed on.
477  */
478 inline Window calculate_max_window(const ITensorInfo &info, const Steps &steps = Steps(), bool skip_border = false, BorderSize border_size = BorderSize())
479 {
480  return calculate_max_window(info.valid_region(), steps, skip_border, border_size);
481 }
482 
483 /** Calculate the maximum window used by a horizontal kernel for a given tensor shape and border setting
484  *
485  * @param[in] valid_region Valid region object defining the shape of the tensor space for which the window is created.
486  * @param[in] steps (Optional) Number of elements processed for each step.
487  * @param[in] skip_border (Optional) If true exclude the border region from the window.
488  * @param[in] border_size (Optional) Border size. The border region will be excluded from the window.
489  *
490  * @return The maximum window the kernel can be executed on.
491  */
492 Window calculate_max_window_horizontal(const ValidRegion &valid_region, const Steps &steps = Steps(), bool skip_border = false, BorderSize border_size = BorderSize());
493 
494 /** Calculate the maximum window used by a horizontal kernel for a given tensor shape and border setting
495  *
496  * @param[in] info Tensor info object defining the shape of the object for which the window is created.
497  * @param[in] steps (Optional) Number of elements processed for each step.
498  * @param[in] skip_border (Optional) If true exclude the border region from the window.
499  * @param[in] border_size (Optional) Border size.
500  *
501  * @return The maximum window the kernel can be executed on.
502  */
503 inline Window calculate_max_window_horizontal(const ITensorInfo &info, const Steps &steps = Steps(), bool skip_border = false, BorderSize border_size = BorderSize())
504 {
505  return calculate_max_window_horizontal(info.valid_region(), steps, skip_border, border_size);
506 }
507 
508 /** Calculate the maximum window for a given tensor shape and border setting. The window will also includes the border.
509  *
510  * @param[in] valid_region Valid region object defining the shape of the tensor space for which the window is created.
511  * @param[in] steps (Optional) Number of elements processed for each step.
512  * @param[in] border_size (Optional) Border size. The border region will be included in the window.
513  *
514  * @return The maximum window the kernel can be executed on.
515  */
516 Window calculate_max_enlarged_window(const ValidRegion &valid_region, const Steps &steps = Steps(), BorderSize border_size = BorderSize());
517 
518 /** Calculate the maximum window for a given tensor shape and border setting. The window will also includes the border.
519  *
520  * @param[in] info Tensor info object defining the shape of the object for which the window is created.
521  * @param[in] steps (Optional) Number of elements processed for each step.
522  * @param[in] border_size (Optional) Border size. The border region will be included in the window.
523  *
524  * @return The maximum window the kernel can be executed on.
525  */
526 inline Window calculate_max_enlarged_window(const ITensorInfo &info, const Steps &steps = Steps(), BorderSize border_size = BorderSize())
527 {
528  return calculate_max_enlarged_window(info.valid_region(), steps, border_size);
529 }
530 
531 /** Intersect multiple valid regions.
532  *
533  * @param[in] regions Valid regions.
534  *
535  * @return Intersection of all regions.
536  */
537 template <typename... Ts>
538 ValidRegion intersect_valid_regions(const Ts &... regions)
539 {
540  auto intersect = [](const ValidRegion & r1, const ValidRegion & r2) -> ValidRegion
541  {
542  ValidRegion region;
543 
544  for(size_t d = 0; d < std::min(r1.anchor.num_dimensions(), r2.anchor.num_dimensions()); ++d)
545  {
546  region.anchor.set(d, std::max(r1.anchor[d], r2.anchor[d]));
547  }
548 
549  for(size_t d = 0; d < std::min(r1.shape.num_dimensions(), r2.shape.num_dimensions()); ++d)
550  {
551  region.shape.set(d, std::min(r1.shape[d], r2.shape[d]));
552  }
553 
554  return region;
555  };
556 
557  return utility::foldl(intersect, regions...);
558 }
559 
560 /** Create a strides object based on the provided strides and the tensor dimensions.
561  *
562  * @param[in] info Tensor info object providing the shape of the tensor for unspecified strides.
563  * @param[in] stride_x Stride to be used in X dimension (in bytes).
564  * @param[in] fixed_strides Strides to be used in higher dimensions starting at Y (in bytes).
565  *
566  * @return Strides object based on the specified strides. Missing strides are
567  * calculated based on the tensor shape and the strides of lower dimensions.
568  */
569 template <typename T, typename... Ts>
570 inline Strides compute_strides(const ITensorInfo &info, T stride_x, Ts &&... fixed_strides)
571 {
572  const TensorShape &shape = info.tensor_shape();
573 
574  // Create strides object
575  Strides strides(stride_x, fixed_strides...);
576 
577  for(size_t i = 1 + sizeof...(Ts); i < info.num_dimensions(); ++i)
578  {
579  strides.set(i, shape[i - 1] * strides[i - 1]);
580  }
581 
582  return strides;
583 }
584 
585 /** Create a strides object based on the tensor dimensions.
586  *
587  * @param[in] info Tensor info object used to compute the strides.
588  *
589  * @return Strides object based on element size and tensor shape.
590  */
591 template <typename... Ts>
593 {
594  return compute_strides(info, info.element_size());
595 }
596 
597 /** Permutes given Dimensions according to a permutation vector
598  *
599  * @warning Validity of permutation is not checked
600  *
601  * @param[in, out] dimensions Dimensions to permute
602  * @param[in] perm Permutation vector
603  */
604 template <typename T>
605 inline void permute(Dimensions<T> &dimensions, const PermutationVector &perm)
606 {
607  auto dimensions_copy = utility::make_array<Dimensions<T>::num_max_dimensions>(dimensions.begin(), dimensions.end());
608  for(unsigned int i = 0; i < perm.num_dimensions(); ++i)
609  {
610  T dimension_val = (perm[i] < dimensions.num_dimensions()) ? dimensions_copy[perm[i]] : 0;
611  dimensions.set(i, dimension_val);
612  }
613 }
614 
615 /** Permutes given TensorShape according to a permutation vector
616  *
617  * @warning Validity of permutation is not checked
618  *
619  * @param[in, out] shape Shape to permute
620  * @param[in] perm Permutation vector
621  */
622 inline void permute(TensorShape &shape, const PermutationVector &perm)
623 {
624  TensorShape shape_copy = shape;
625  for(unsigned int i = 0; i < perm.num_dimensions(); ++i)
626  {
627  size_t dimension_val = (perm[i] < shape.num_dimensions()) ? shape_copy[perm[i]] : 1;
628  shape.set(i, dimension_val, false); // Avoid changes in _num_dimension
629  }
630 }
631 
632 /** Auto initialize the tensor info (shape, number of channels and data type) if the current assignment is empty.
633  *
634  * @param[in,out] info Tensor info used to check and assign.
635  * @param[in] shape New shape.
636  * @param[in] num_channels New number of channels.
637  * @param[in] data_type New data type
638  * @param[in] quantization_info (Optional) New quantization info
639  *
640  * @return True if the tensor info has been initialized
641  */
642 bool auto_init_if_empty(ITensorInfo &info,
643  const TensorShape &shape,
644  int num_channels, DataType data_type,
645  QuantizationInfo quantization_info = QuantizationInfo());
646 
647 /** Auto initialize the tensor info using another tensor info.
648  *
649  * @param info_sink Tensor info used to check and assign
650  * @param info_source Tensor info used to assign
651  *
652  * @return True if the tensor info has been initialized
653  */
654 bool auto_init_if_empty(ITensorInfo &info_sink, const ITensorInfo &info_source);
655 
656 /** Set the shape to the specified value if the current assignment is empty.
657  *
658  * @param[in,out] info Tensor info used to check and assign.
659  * @param[in] shape New shape.
660  *
661  * @return True if the shape has been changed.
662  */
663 bool set_shape_if_empty(ITensorInfo &info, const TensorShape &shape);
664 
665 /** Set the format, data type and number of channels to the specified value if
666  * the current data type is unknown.
667  *
668  * @param[in,out] info Tensor info used to check and assign.
669  * @param[in] format New format.
670  *
671  * @return True if the format has been changed.
672  */
673 bool set_format_if_unknown(ITensorInfo &info, Format format);
674 
675 /** Set the data type and number of channels to the specified value if
676  * the current data type is unknown.
677  *
678  * @param[in,out] info Tensor info used to check and assign.
679  * @param[in] data_type New data type.
680  *
681  * @return True if the data type has been changed.
682  */
683 bool set_data_type_if_unknown(ITensorInfo &info, DataType data_type);
684 
685 /** Set the data layout to the specified value if
686  * the current data layout is unknown.
687  *
688  * @param[in,out] info Tensor info used to check and assign.
689  * @param[in] data_layout New data layout.
690  *
691  * @return True if the data type has been changed.
692  */
694 
695 /** Set the quantization info to the specified value if
696  * the current quantization info is empty and the data type of asymmetric quantized type
697  *
698  * @param[in,out] info Tensor info used to check and assign.
699  * @param[in] quantization_info Quantization info
700  *
701  * @return True if the quantization info has been changed.
702  */
703 bool set_quantization_info_if_empty(ITensorInfo &info, QuantizationInfo quantization_info);
704 
705 /** Helper function to calculate the Valid Region for Scale.
706  *
707  * @param[in] src_info Input tensor info used to check.
708  * @param[in] dst_shape Shape of the output.
709  * @param[in] interpolate_policy Interpolation policy.
710  * @param[in] sampling_policy Sampling policy.
711  * @param[in] border_undefined True if the border is undefined.
712  *
713  * @return The corresponding valid region
714  */
715 ValidRegion calculate_valid_region_scale(const ITensorInfo &src_info, const TensorShape &dst_shape,
716  InterpolationPolicy interpolate_policy, SamplingPolicy sampling_policy, bool border_undefined);
717 
718 /** Convert a linear index into n-dimensional coordinates.
719  *
720  * @param[in] shape Shape of the n-dimensional tensor.
721  * @param[in] index Linear index specifying the i-th element.
722  *
723  * @return n-dimensional coordinates.
724  */
725 inline Coordinates index2coords(const TensorShape &shape, int index);
726 
727 /** Convert n-dimensional coordinates into a linear index.
728  *
729  * @param[in] shape Shape of the n-dimensional tensor.
730  * @param[in] coord N-dimensional coordinates.
731  *
732  * @return linead index
733  */
734 inline int coords2index(const TensorShape &shape, const Coordinates &coord);
735 
736 /** Get the index of the given dimension.
737  *
738  * @param[in] data_layout The data layout.
739  * @param[in] data_layout_dimension The dimension which this index is requested for.
740  *
741  * @return The int conversion of the requested data layout index.
742  */
743 inline size_t get_data_layout_dimension_index(const DataLayout data_layout, const DataLayoutDimension data_layout_dimension);
744 
745 /** Get the DataLayoutDimension of a given index and layout.
746  *
747  * @param[in] data_layout The data layout.
748  * @param[in] index The data layout index.
749  *
750  * @return The dimension which this index is requested for.
751  */
753 
754 /** Calculate the normalization dimension index for a given normalization type
755  *
756  * @param[in] layout Data layout of the input and output tensor
757  * @param[in] info Normalization info
758  *
759  * @return Normalization dimension index
760  */
762 {
763  const unsigned int width_idx = get_data_layout_dimension_index(layout, DataLayoutDimension::WIDTH);
764  const unsigned int channel_idx = get_data_layout_dimension_index(layout, DataLayoutDimension::CHANNEL);
765 
766  return info.is_in_map() ? width_idx : channel_idx;
767 }
768 
769 /** Calculate the number of output tiles required by Winograd Convolution layer. This utility function can be used by the Winograd input transform
770  * to know the number of tiles on the x and y direction
771  *
772  * @param[in] in_dims Spatial dimensions of the input tensor of convolution layer
773  * @param[in] kernel_size Kernel size
774  * @param[in] output_tile_size Size of a single output tile
775  * @param[in] conv_info Convolution info (i.e. pad, stride,...)
776  *
777  * @return the number of output tiles along the x and y directions of size "output_tile_size"
778  */
779 inline Size2D compute_winograd_convolution_tiles(const Size2D &in_dims, const Size2D &kernel_size, const Size2D &output_tile_size, const PadStrideInfo &conv_info)
780 {
781  int num_tiles_x = std::ceil((in_dims.width - (kernel_size.width - 1) + conv_info.pad_left() + conv_info.pad_right()) / static_cast<float>(output_tile_size.width));
782  int num_tiles_y = std::ceil((in_dims.height - (kernel_size.height - 1) + conv_info.pad_top() + conv_info.pad_bottom()) / static_cast<float>(output_tile_size.height));
783 
784  // Clamp in case we provide paddings but we have 1D convolution
785  num_tiles_x = std::min(num_tiles_x, static_cast<int>(in_dims.width));
786  num_tiles_y = std::min(num_tiles_y, static_cast<int>(in_dims.height));
787 
788  return Size2D(num_tiles_x, num_tiles_y);
789 }
790 
791 /** Wrap-around a number within the range 0 <= x < m
792  *
793  * @param[in] x Input value
794  * @param[in] m Range
795  *
796  * @return the wrapped-around number
797  */
798 template <typename T>
799 inline T wrap_around(T x, T m)
800 {
801  return x >= 0 ? x % m : (x % m + m) % m;
802 }
803 
804 /** Convert negative coordinates to positive in the range [0, num_dims_input]
805  *
806  * @param[out] coords Array of coordinates to be converted.
807  * @param[in] max_value Maximum value to be used when wrapping the negative values in coords
808  */
809 inline Coordinates &convert_negative_axis(Coordinates &coords, int max_value)
810 {
811  for(unsigned int i = 0; i < coords.num_dimensions(); ++i)
812  {
813  coords[i] = wrap_around(coords[i], max_value);
814  }
815  return coords;
816 }
817 
818 /** Given an integer value, this function returns the next power of two
819  *
820  * @param[in] x Input value
821  *
822  * @return the next power of two
823  */
824 inline unsigned int get_next_power_two(unsigned int x)
825 {
826  // Decrement by 1
827  x--;
828 
829  // Shift right by 1
830  x |= x >> 1u;
831  // Shift right by 2
832  x |= x >> 2u;
833  // Shift right by 4
834  x |= x >> 4u;
835  // Shift right by 8
836  x |= x >> 8u;
837  // Shift right by 16
838  x |= x >> 16u;
839 
840  // Increment by 1
841  x++;
842 
843  return x;
844 }
845 } // namespace arm_compute
846 
848 #endif /*ARM_COMPUTE_HELPERS_H */
InterpolationPolicy
Interpolation method.
Definition: Types.h:369
SimpleTensor< float > w
Definition: DFT.cpp:156
T delta_linear_c1_x(const T *pixel_ptr, float dx)
Computes linear interpolation using the pointer to the left pixel and the pixel's distance between th...
Definition: Helpers.h:253
Shape of a tensor.
Definition: TensorShape.h:39
const DataLayout data_layout
Definition: Im2Col.cpp:146
static constexpr bool value
Disabled.
Definition: Helpers.h:55
Disable bitwise operations by default.
Definition: Helpers.h:53
Coordinates index2coords(const TensorShape &shape, int index)
Convert a linear index into n-dimensional coordinates.
Definition: Helpers.inl:290
uint8_t delta_bilinear_c1_quantized(const uint8_t *pixel_ptr, size_t stride, float dx, float dy, UniformQuantizationInfo iq_info, UniformQuantizationInfo oq_info)
Computes bilinear interpolation for quantized input and output, using the pointer to the top-left pix...
Definition: Helpers.h:162
float dequantize_qasymm8(uint8_t value, const INFO_TYPE &qinfo)
Dequantize a value given an unsigned 8-bit asymmetric quantization scheme.
TensorShape shape
Shape of the valid region.
Definition: Types.h:260
Container for 2D border size.
Definition: Types.h:272
void increment(size_t dimension)
Increment the iterator along the specified dimension of the step value associated to the dimension.
Definition: Helpers.inl:168
unsigned int get_next_power_two(unsigned int x)
Given an integer value, this function returns the next power of two.
Definition: Helpers.h:824
uint8_t quantize_qasymm8(float value, const INFO_TYPE &qinfo, RoundingPolicy rounding_policy=RoundingPolicy::TO_NEAREST_UP)
Quantize a value given an unsigned 8-bit asymmetric quantization scheme.
DataLayoutDimension
[DataLayout enum definition]
Definition: Types.h:129
std::unique_ptr< Kernel > create_configure_kernel(T &&... args)
Helper function to create and return a unique_ptr pointed to a CL/GLES kernel object It also calls th...
Definition: Helpers.h:75
Normalization Layer Information class.
Definition: Types.h:1614
#define ARM_COMPUTE_ERROR_ON(cond)
If the condition is true then an error message is printed and an exception thrown.
Definition: Error.h:466
Store the tensor's metadata.
Definition: ITensorInfo.h:40
Quantization info when assuming per layer quantization.
bool set_data_layout_if_unknown(ITensorInfo &info, DataLayout data_layout)
Set the data layout to the specified value if the current data layout is unknown.
Definition: Helpers.inl:268
Size2D compute_winograd_convolution_tiles(const Size2D &in_dims, const Size2D &kernel_size, const Size2D &output_tile_size, const PadStrideInfo &conv_info)
Calculate the number of output tiles required by Winograd Convolution layer.
Definition: Helpers.h:779
void set(size_t dimension, T value)
Accessor to set the value of one of the dimensions.
Definition: Dimensions.h:74
Interface for NEON tensor.
Definition: ITensor.h:36
bool set_data_type_if_unknown(ITensorInfo &info, DataType data_type)
Set the data type and number of channels to the specified value if the current data type is unknown.
Definition: Helpers.inl:257
Window calculate_max_window(const ValidRegion &valid_region, const Steps &steps=Steps(), bool skip_border=false, BorderSize border_size=BorderSize())
Calculate the maximum window for a given tensor shape and border setting.
Definition: Helpers.cpp:28
Copyright (c) 2017-2020 ARM Limited.
bool auto_init_if_empty(ITensorInfo &info, const TensorShape &shape, int num_channels, DataType data_type, QuantizationInfo quantization_info=QuantizationInfo())
Auto initialize the tensor info (shape, number of channels and data type) if the current assignment i...
Definition: Helpers.inl:202
size_t height
Height of the image region or rectangle.
Definition: Size2D.h:90
Strides compute_strides(const ITensorInfo &info, T stride_x, Ts &&... fixed_strides)
Create a strides object based on the provided strides and the tensor dimensions.
Definition: Helpers.h:570
void permute(Dimensions< T > &dimensions, const PermutationVector &perm)
Permutes given Dimensions according to a permutation vector.
Definition: Helpers.h:605
Window calculate_max_enlarged_window(const ValidRegion &valid_region, const Steps &steps=Steps(), BorderSize border_size=BorderSize())
Calculate the maximum window for a given tensor shape and border setting.
Definition: Helpers.cpp:82
T wrap_around(T x, T m)
Wrap-around a number within the range 0 <= x < m.
Definition: Helpers.h:799
cl::Kernel create_kernel(const CLCompileContext &ctx, const std::string &kernel_name, const std::set< std::string > &build_opts=std::set< std::string >())
Creates an opencl kernel using a compile context.
Definition: CLHelpers.cpp:387
bool update_window_and_padding(Window &win, Ts &&... patterns)
Update window and padding size for each of the access patterns.
Definition: Helpers.h:437
T && foldl(F &&, T &&value)
Base case of foldl.
Definition: Utility.h:130
T delta_linear_c1_y(const T *pixel_ptr, size_t stride, float dy)
Computes linear interpolation using the pointer to the top pixel and the pixel's distance between the...
Definition: Helpers.h:228
Format
Image colour formats.
Definition: Types.h:54
constexpr int offset() const
Return the offset in bytes from the first element to the current position of the iterator.
Definition: Helpers.inl:180
int8_t quantize_qasymm8_signed(float value, const INFO_TYPE &qinfo, RoundingPolicy rounding_policy=RoundingPolicy::TO_NEAREST_UP)
Quantize a value given a signed 8-bit asymmetric quantization scheme.
Class to describe a number of elements in each dimension.
Definition: Steps.h:40
Interface describing methods to update access window and padding based on kernel parameters.
Definition: IAccessWindow.h:71
Coordinates of an item.
Definition: Coordinates.h:37
Check if a type T is contained in a tuple Tuple of types.
Definition: Helpers.h:97
Dimensions with dimensionality.
Definition: Dimensions.h:41
int coords2index(const TensorShape &shape, const Coordinates &coord)
Convert n-dimensional coordinates into a linear index.
Definition: Helpers.inl:309
constexpr uint8_t * ptr() const
Return a pointer to the current pixel.
Definition: Helpers.inl:185
Padding and stride information class.
Definition: Types.h:689
ValidRegion intersect_valid_regions(const Ts &... regions)
Intersect multiple valid regions.
Definition: Helpers.h:538
std::array< T, num_max_dimensions >::iterator begin()
Returns a read/write iterator that points to the first element in the dimension array.
Definition: Dimensions.h:194
DataLayoutDimension get_index_data_layout_dimension(const DataLayout data_layout, const size_t index)
Get the DataLayoutDimension of a given index and layout.
Definition: Helpers.inl:356
constexpr Iterator()
Default constructor to create an empty iterator.
Definition: Helpers.inl:136
T delta_bilinear_c1(const T *pixel_ptr, size_t stride, float dx, float dy)
Computes bilinear interpolation using the pointer to the top-left pixel and the pixel's distance betw...
Definition: Helpers.h:128
void for_each(F &&)
Base case of for_each.
Definition: Utility.h:108
TensorInfo src_info(src_shape, 1, data_type)
Strides of an item in bytes.
Definition: Strides.h:37
ValidRegion calculate_valid_region_scale(const ITensorInfo &src_info, const TensorShape &dst_shape, InterpolationPolicy interpolate_policy, SamplingPolicy sampling_policy, bool border_undefined)
Helper function to calculate the Valid Region for Scale.
Definition: Helpers.cpp:184
uint8_t pixel_area_c1u8_clamp(const uint8_t *first_pixel_ptr, size_t stride, size_t width, size_t height, float wr, float hr, int x, int y)
Return the pixel at (x,y) using area interpolation by clamping when out of borders.
Definition: Helpers.inl:32
DatasetMode operator &(DatasetMode t1, DatasetMode t2)
Definition: DatasetModes.h:48
void reset(size_t dimension)
Move the iterator back to the beginning of the specified dimension.
Definition: Helpers.inl:190
std::array< 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:218
size_t width
Width of the image region or rectangle.
Definition: Size2D.h:89
T pixel_bilinear_c1(const T *first_pixel_ptr, size_t stride, float x, float y)
Return the pixel at (x,y) using bilinear interpolation.
Definition: Helpers.h:279
Class for specifying the size of an image or rectangle.
Definition: Size2D.h:34
unsigned int num_dimensions() const
Returns the effective dimensionality of the tensor.
Definition: Dimensions.h:122
bool set_shape_if_empty(ITensorInfo &info, const TensorShape &shape)
Set the shape to the specified value if the current assignment is empty.
Definition: Helpers.inl:235
float dequantize_qasymm8_signed(int8_t value, const INFO_TYPE &qinfo)
Dequantize a value given a signed 8-bit asymmetric quantization scheme.
TensorShape & set(size_t dimension, size_t value, bool apply_dim_correction=true)
Accessor to set the value of one of the dimensions.
Definition: TensorShape.h:78
void execute_window_loop(const Window &w, L &&lambda_function, Ts &&... iterators)
Iterate through the passed window, automatically adjusting the iterators and calling the lambda_funct...
Definition: Helpers.inl:123
bool set_format_if_unknown(ITensorInfo &info, Format format)
Set the format, data type and number of channels to the specified value if the current data type is u...
Definition: Helpers.inl:246
Coordinates & convert_negative_axis(Coordinates &coords, int max_value)
Convert negative coordinates to positive in the range [0, num_dims_input].
Definition: Helpers.h:809
Container for valid region of a window.
Definition: Types.h:187
size_t get_data_layout_dimension_index(const DataLayout data_layout, const DataLayoutDimension data_layout_dimension)
Get the index of the given dimension.
Definition: Helpers.inl:327
uint8_t pixel_bilinear_c1_clamp(const T *first_pixel_ptr, size_t stride, size_t width, size_t height, float x, float y)
Return the pixel at (x,y) using bilinear interpolation by clamping when out of borders.
Definition: Helpers.h:306
Iterator updated by execute_window_loop for each window element.
Definition: Helpers.h:353
DataType
Available data types.
Definition: Types.h:77
unsigned int get_normalization_dimension_index(DataLayout layout, const NormalizationLayerInfo &info)
Calculate the normalization dimension index for a given normalization type.
Definition: Helpers.h:761
DataLayout
[DataLayout enum definition]
Definition: Types.h:120
bool set_quantization_info_if_empty(ITensorInfo &info, QuantizationInfo quantization_info)
Set the quantization info to the specified value if the current quantization info is empty and the da...
Definition: Helpers.inl:279
Describe a multidimensional execution window.
Definition: Window.h:39
Window calculate_max_window_horizontal(const ValidRegion &valid_region, const Steps &steps=Steps(), bool skip_border=false, BorderSize border_size=BorderSize())
Calculate the maximum window used by a horizontal kernel for a given tensor shape and border setting.
Definition: Helpers.cpp:131
Coordinates anchor
Anchor for the start of the valid region.
Definition: Types.h:259
SamplingPolicy
Available Sampling Policies.
Definition: Types.h:102