blob: 374e36442b496cfa3fae46b31f407bf01e9adf72 [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +00002 * Copyright (c) 2016-2018 ARM Limited.
Anthony Barbier6ff3b192017-09-04 18:44:23 +01003 *
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
Anthony Barbier6ff3b192017-09-04 18:44:23 +010027#include "arm_compute/core/Coordinates.h"
Georgios Pinitas583137c2017-08-31 18:12:42 +010028#include "arm_compute/core/Error.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010029#include "arm_compute/core/IAccessWindow.h"
30#include "arm_compute/core/Steps.h"
31#include "arm_compute/core/Strides.h"
32#include "arm_compute/core/TensorShape.h"
33#include "arm_compute/core/Types.h"
34#include "arm_compute/core/Window.h"
Georgios Pinitas583137c2017-08-31 18:12:42 +010035
Anthony Barbier6ff3b192017-09-04 18:44:23 +010036#include <array>
37#include <cstddef>
38#include <cstdint>
39#include <memory>
40#include <tuple>
41#include <type_traits>
42#include <utility>
43
44namespace arm_compute
45{
46class IKernel;
47class ITensor;
48class ITensorInfo;
49
Alex Gildayc357c472018-03-21 13:54:09 +000050/** Disable bitwise operations by default */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010051template <typename T>
52struct enable_bitwise_ops
53{
Alex Gildayc357c472018-03-21 13:54:09 +000054 static constexpr bool value = false; /**< Disabled */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010055};
56
Alex Gildayc357c472018-03-21 13:54:09 +000057#ifndef DOXYGEN_SKIP_THIS
Anthony Barbier6ff3b192017-09-04 18:44:23 +010058template <typename T>
59typename std::enable_if<enable_bitwise_ops<T>::value, T>::type operator&(T lhs, T rhs)
60{
61 using underlying_type = typename std::underlying_type<T>::type;
62 return static_cast<T>(static_cast<underlying_type>(lhs) & static_cast<underlying_type>(rhs));
63}
Alex Gildayc357c472018-03-21 13:54:09 +000064#endif /* DOXYGEN_SKIP_THIS */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010065
Michele Di Giorgiob8fc60f2018-04-25 11:58:07 +010066/** Helper function to create and return a unique_ptr pointed to a CL/GLES kernel object
67 * It also calls the kernel's configuration.
68 *
69 * @param[in] args All the arguments that need pass to kernel's configuration.
70 *
71 * @return A unique pointer pointed to a CL/GLES kernel object
72 */
73template <typename Kernel, typename... T>
74std::unique_ptr<Kernel> create_configure_kernel(T &&... args)
75{
76 std::unique_ptr<Kernel> k = arm_compute::support::cpp14::make_unique<Kernel>();
77 k->configure(std::forward<T>(args)...);
78 return k;
79}
80
81/** Helper function to create and return a unique_ptr pointed to a CL/GLES kernel object
82 *
83 * @return A unique pointer pointed to a Kernel kernel object
84 */
85template <typename Kernel>
86std::unique_ptr<Kernel> create_kernel()
87{
88 std::unique_ptr<Kernel> k = arm_compute::support::cpp14::make_unique<Kernel>();
89 return k;
90}
91
Anthony Barbier6ff3b192017-09-04 18:44:23 +010092namespace traits
93{
94/** Check if a type T is contained in a tuple Tuple of types */
95template <typename T, typename Tuple>
96struct is_contained;
97
98template <typename T>
99struct is_contained<T, std::tuple<>> : std::false_type
100{
101};
102
103template <typename T, typename... Ts>
104struct is_contained<T, std::tuple<T, Ts...>> : std::true_type
105{
106};
107
108template <typename T, typename U, typename... Ts>
109struct is_contained<T, std::tuple<U, Ts...>> : is_contained<T, std::tuple<Ts...>>
110{
111};
112}
113
Gian Marco Iodicef1c2bf02018-06-13 14:05:54 +0100114/** Calculate the number of output tiles required by Winograd Convolution layer. This utility function can be used by the Winograd input transform
115 * to know the number of tiles on the x and y direction
116 *
117 * @param[in] in_dims Spatial dimensions of the input tensor of convolution layer
118 * @param[in] kernel_size Kernel size
119 * @param[in] output_tile_size Size of a single output tile
120 * @param[in] conv_info Convolution info (i.e. pad, stride,...)
121 *
122 * @return the number of output tiles along the x and y directions of size "output_tile_size"
123 */
124inline Size2D compute_winograd_convolution_tiles(const Size2D &in_dims, const Size2D &kernel_size, const Size2D &output_tile_size, const PadStrideInfo &conv_info)
125{
126 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));
127 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));
128
129 // Clamp in case we provide paddings but we have 1D convolution
130 num_tiles_x = std::min(num_tiles_x, static_cast<int>(in_dims.width));
131 num_tiles_y = std::min(num_tiles_y, static_cast<int>(in_dims.height));
132
133 return Size2D(num_tiles_x, num_tiles_y);
134}
135
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100136/** Computes bilinear interpolation using the pointer to the top-left pixel and the pixel's distance between
Georgios Pinitas583137c2017-08-31 18:12:42 +0100137 * the real coordinates and the smallest following integer coordinates. Input must be in single channel format.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100138 *
Georgios Pinitas583137c2017-08-31 18:12:42 +0100139 * @param[in] pixel_ptr Pointer to the top-left pixel value of a single channel input.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100140 * @param[in] stride Stride to access the bottom-left and bottom-right pixel values
141 * @param[in] dx Pixel's distance between the X real coordinate and the smallest X following integer
142 * @param[in] dy Pixel's distance between the Y real coordinate and the smallest Y following integer
143 *
144 * @note dx and dy must be in the range [0, 1.0]
145 *
146 * @return The bilinear interpolated pixel value
147 */
Georgios Pinitas583137c2017-08-31 18:12:42 +0100148template <typename T>
149inline T delta_bilinear_c1(const T *pixel_ptr, size_t stride, float dx, float dy)
150{
151 ARM_COMPUTE_ERROR_ON(pixel_ptr == nullptr);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100152
Georgios Pinitas583137c2017-08-31 18:12:42 +0100153 const float dx1 = 1.0f - dx;
154 const float dy1 = 1.0f - dy;
155
156 const T a00 = *pixel_ptr;
157 const T a01 = *(pixel_ptr + 1);
158 const T a10 = *(pixel_ptr + stride);
159 const T a11 = *(pixel_ptr + stride + 1);
160
161 const float w1 = dx1 * dy1;
162 const float w2 = dx * dy1;
163 const float w3 = dx1 * dy;
164 const float w4 = dx * dy;
165
166 return static_cast<T>(a00 * w1 + a01 * w2 + a10 * w3 + a11 * w4);
167}
168
Anthony Barbier9a33b542017-12-12 22:08:59 +0000169/** Computes linear interpolation using the pointer to the top pixel and the pixel's distance between
170 * the real coordinates and the smallest following integer coordinates. Input must be in single channel format.
171 *
172 * @param[in] pixel_ptr Pointer to the top pixel value of a single channel input.
173 * @param[in] stride Stride to access the bottom pixel value
174 * @param[in] dy Pixel's distance between the Y real coordinate and the smallest Y following integer
175 *
176 * @note dy must be in the range [0, 1.0]
177 *
178 * @return The linear interpolated pixel value
179 */
180template <typename T>
181inline T delta_linear_c1_y(const T *pixel_ptr, size_t stride, float dy)
182{
183 ARM_COMPUTE_ERROR_ON(pixel_ptr == nullptr);
184
185 const float dy1 = 1.0f - dy;
186
187 const T a00 = *pixel_ptr;
188 const T a10 = *(pixel_ptr + stride);
189
190 const float w1 = dy1;
191 const float w3 = dy;
192
193 return static_cast<T>(a00 * w1 + a10 * w3);
194}
195/** Computes linear interpolation using the pointer to the left pixel and the pixel's distance between
196 * the real coordinates and the smallest following integer coordinates. Input must be in single channel format.
197 *
198 * @param[in] pixel_ptr Pointer to the left pixel value of a single channel input.
199 * @param[in] dx Pixel's distance between the X real coordinate and the smallest X following integer
200 *
201 * @note dx must be in the range [0, 1.0]
202 *
203 * @return The linear interpolated pixel value
204 */
205template <typename T>
206inline T delta_linear_c1_x(const T *pixel_ptr, float dx)
207{
208 ARM_COMPUTE_ERROR_ON(pixel_ptr == nullptr);
209
210 const T a00 = *pixel_ptr;
211 const T a01 = *(pixel_ptr + 1);
212
213 const float dx1 = 1.0f - dx;
214
215 const float w1 = dx1;
216 const float w2 = dx;
217
218 return static_cast<T>(a00 * w1 + a01 * w2);
219}
Georgios Pinitas583137c2017-08-31 18:12:42 +0100220/** Return the pixel at (x,y) using bilinear interpolation.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100221 *
222 * @warning Only works if the iterator was created with an IImage
223 *
Georgios Pinitas583137c2017-08-31 18:12:42 +0100224 * @param[in] first_pixel_ptr Pointer to the first pixel of a single channel input.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100225 * @param[in] stride Stride in bytes of the image;
226 * @param[in] x X position of the wanted pixel
227 * @param[in] y Y position of the wanted pixel
228 *
229 * @return The pixel at (x, y) using bilinear interpolation.
230 */
Georgios Pinitas583137c2017-08-31 18:12:42 +0100231template <typename T>
232inline T pixel_bilinear_c1(const T *first_pixel_ptr, size_t stride, float x, float y)
233{
234 ARM_COMPUTE_ERROR_ON(first_pixel_ptr == nullptr);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100235
Georgios Pinitas583137c2017-08-31 18:12:42 +0100236 const int32_t xi = std::floor(x);
237 const int32_t yi = std::floor(y);
238
239 const float dx = x - xi;
240 const float dy = y - yi;
241
242 return delta_bilinear_c1(first_pixel_ptr + xi + yi * stride, stride, dx, dy);
243}
244
245/** Return the pixel at (x,y) using bilinear interpolation by clamping when out of borders. The image must be single channel input
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100246 *
247 * @warning Only works if the iterator was created with an IImage
248 *
Georgios Pinitas583137c2017-08-31 18:12:42 +0100249 * @param[in] first_pixel_ptr Pointer to the first pixel of a single channel image.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100250 * @param[in] stride Stride in bytes of the image
251 * @param[in] width Width of the image
252 * @param[in] height Height of the image
253 * @param[in] x X position of the wanted pixel
254 * @param[in] y Y position of the wanted pixel
255 *
256 * @return The pixel at (x, y) using bilinear interpolation.
257 */
Georgios Pinitas583137c2017-08-31 18:12:42 +0100258template <typename T>
259inline uint8_t pixel_bilinear_c1_clamp(const T *first_pixel_ptr, size_t stride, size_t width, size_t height, float x, float y)
260{
261 ARM_COMPUTE_ERROR_ON(first_pixel_ptr == nullptr);
262
263 x = std::max(-1.f, std::min(x, static_cast<float>(width)));
264 y = std::max(-1.f, std::min(y, static_cast<float>(height)));
265
266 const float xi = std::floor(x);
267 const float yi = std::floor(y);
268
269 const float dx = x - xi;
270 const float dy = y - yi;
271
Anthony Barbier9a33b542017-12-12 22:08:59 +0000272 if(dx == 0.0f)
273 {
274 if(dy == 0.0f)
275 {
276 return static_cast<T>(first_pixel_ptr[static_cast<int32_t>(xi) + static_cast<int32_t>(yi) * stride]);
277 }
278 return delta_linear_c1_y(first_pixel_ptr + static_cast<int32_t>(xi) + static_cast<int32_t>(yi) * stride, stride, dy);
279 }
280 if(dy == 0.0f)
281 {
282 return delta_linear_c1_x(first_pixel_ptr + static_cast<int32_t>(xi) + static_cast<int32_t>(yi) * stride, dx);
283 }
Georgios Pinitas583137c2017-08-31 18:12:42 +0100284 return delta_bilinear_c1(first_pixel_ptr + static_cast<int32_t>(xi) + static_cast<int32_t>(yi) * stride, stride, dx, dy);
285}
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100286
287/** Return the pixel at (x,y) using area interpolation by clamping when out of borders. The image must be single channel U8
288 *
289 * @note The interpolation area depends on the width and height ration of the input and output images
290 * @note Currently average of the contributing pixels is calculated
291 *
292 * @param[in] first_pixel_ptr Pointer to the first pixel of a single channel U8 image.
293 * @param[in] stride Stride in bytes of the image
294 * @param[in] width Width of the image
295 * @param[in] height Height of the image
296 * @param[in] wr Width ratio among the input image width and output image width.
297 * @param[in] hr Height ratio among the input image height and output image height.
298 * @param[in] x X position of the wanted pixel
299 * @param[in] y Y position of the wanted pixel
300 *
301 * @return The pixel at (x, y) using area interpolation.
302 */
303inline 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);
304
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100305/** Iterator updated by @ref execute_window_loop for each window element */
306class Iterator
307{
308public:
309 /** Default constructor to create an empty iterator */
310 constexpr Iterator();
311 /** Create a container iterator for the metadata and allocation contained in the ITensor
312 *
313 * @param[in] tensor The tensor to associate to the iterator.
314 * @param[in] window The window which will be used to iterate over the tensor.
315 */
316 Iterator(const ITensor *tensor, const Window &window);
317
318 /** Increment the iterator along the specified dimension of the step value associated to the dimension.
319 *
320 * @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.
321 *
322 * @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.
323 *
324 * @param[in] dimension Dimension to increment
325 */
326 void increment(size_t dimension);
327
328 /** Return the offset in bytes from the first element to the current position of the iterator
329 *
330 * @return The current position of the iterator in bytes relative to the first element.
331 */
332 constexpr int offset() const;
333
334 /** Return a pointer to the current pixel.
335 *
336 * @warning Only works if the iterator was created with an ITensor.
337 *
338 * @return equivalent to buffer() + offset()
339 */
340 constexpr uint8_t *ptr() const;
341
342 /** Move the iterator back to the beginning of the specified dimension.
343 *
344 * @param[in] dimension Dimension to reset
345 */
346 void reset(size_t dimension);
347
348private:
349 uint8_t *_ptr;
350
351 class Dimension
352 {
353 public:
354 constexpr Dimension()
355 : _dim_start(0), _stride(0)
356 {
357 }
358
359 int _dim_start;
360 int _stride;
361 };
362
363 std::array<Dimension, Coordinates::num_max_dimensions> _dims;
364};
365
366/** Iterate through the passed window, automatically adjusting the iterators and calling the lambda_functino for each element.
367 * It passes the x and y positions to the lambda_function for each iteration
368 *
369 * @param[in] w Window to iterate through.
370 * @param[in] lambda_function The function of type void(function)( const Coordinates & id ) to call at each iteration.
371 * Where id represents the absolute coordinates of the item to process.
372 * @param[in,out] iterators Tensor iterators which will be updated by this function before calling lambda_function.
373 */
374template <typename L, typename... Ts>
375inline void execute_window_loop(const Window &w, L &&lambda_function, Ts &&... iterators);
376
377/** Update window and padding size for each of the access patterns.
378 *
379 * First the window size is reduced based on all access patterns that are not
380 * allowed to modify the padding of the underlying tensor. Then the padding of
381 * the remaining tensors is increased to match the window.
382 *
383 * @param[in] win Window that is used by the kernel.
384 * @param[in] patterns Access patterns used to calculate the final window and padding.
385 *
386 * @return True if the window has been changed. Changes to the padding do not
387 * influence the returned value.
388 */
389template <typename... Ts>
390bool update_window_and_padding(Window &win, Ts &&... patterns)
391{
392 bool window_changed = false;
393
Diego Lopez Recas490b3d82017-12-19 15:42:25 +0000394 utility::for_each([&](const IAccessWindow & w)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100395 {
396 window_changed |= w.update_window_if_needed(win);
397 },
398 patterns...);
399
400 bool padding_changed = false;
401
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +0000402 utility::for_each([&](IAccessWindow & w)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100403 {
404 padding_changed |= w.update_padding_if_needed(win);
405 },
406 patterns...);
407
408 return window_changed;
409}
410
411/** Calculate the maximum window for a given tensor shape and border setting
412 *
Diego Lopez Recasbcbc9702017-12-18 11:28:27 +0000413 * @param[in] valid_region Valid region object defining the shape of the tensor space for which the window is created.
414 * @param[in] steps (Optional) Number of elements processed for each step.
415 * @param[in] skip_border (Optional) If true exclude the border region from the window.
416 * @param[in] border_size (Optional) Border size.
417 *
418 * @return The maximum window the kernel can be executed on.
419 */
420Window calculate_max_window(const ValidRegion &valid_region, const Steps &steps = Steps(), bool skip_border = false, BorderSize border_size = BorderSize());
421
422/** Calculate the maximum window for a given tensor shape and border setting
423 *
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100424 * @param[in] info Tensor info object defining the shape of the object for which the window is created.
425 * @param[in] steps (Optional) Number of elements processed for each step.
426 * @param[in] skip_border (Optional) If true exclude the border region from the window.
427 * @param[in] border_size (Optional) Border size.
428 *
429 * @return The maximum window the kernel can be executed on.
430 */
Diego Lopez Recasbcbc9702017-12-18 11:28:27 +0000431inline Window calculate_max_window(const ITensorInfo &info, const Steps &steps = Steps(), bool skip_border = false, BorderSize border_size = BorderSize())
432{
433 return calculate_max_window(info.valid_region(), steps, skip_border, border_size);
434}
435
436/** Calculate the maximum window used by a horizontal kernel for a given tensor shape and border setting
437 *
438 * @param[in] valid_region Valid region object defining the shape of the tensor space for which the window is created.
439 * @param[in] steps (Optional) Number of elements processed for each step.
440 * @param[in] skip_border (Optional) If true exclude the border region from the window.
441 * @param[in] border_size (Optional) Border size. The border region will be excluded from the window.
442 *
443 * @return The maximum window the kernel can be executed on.
444 */
445Window calculate_max_window_horizontal(const ValidRegion &valid_region, const Steps &steps = Steps(), bool skip_border = false, BorderSize border_size = BorderSize());
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100446
447/** Calculate the maximum window used by a horizontal kernel for a given tensor shape and border setting
448 *
449 * @param[in] info Tensor info object defining the shape of the object for which the window is created.
450 * @param[in] steps (Optional) Number of elements processed for each step.
451 * @param[in] skip_border (Optional) If true exclude the border region from the window.
Diego Lopez Recasbcbc9702017-12-18 11:28:27 +0000452 * @param[in] border_size (Optional) Border size.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100453 *
454 * @return The maximum window the kernel can be executed on.
455 */
Diego Lopez Recasbcbc9702017-12-18 11:28:27 +0000456inline Window calculate_max_window_horizontal(const ITensorInfo &info, const Steps &steps = Steps(), bool skip_border = false, BorderSize border_size = BorderSize())
457{
458 return calculate_max_window_horizontal(info.valid_region(), steps, skip_border, border_size);
459}
460
461/** Calculate the maximum window for a given tensor shape and border setting. The window will also includes the border.
462 *
463 * @param[in] valid_region Valid region object defining the shape of the tensor space for which the window is created.
464 * @param[in] steps (Optional) Number of elements processed for each step.
465 * @param[in] border_size (Optional) Border size. The border region will be included in the window.
466 *
467 * @return The maximum window the kernel can be executed on.
468 */
469Window calculate_max_enlarged_window(const ValidRegion &valid_region, const Steps &steps = Steps(), BorderSize border_size = BorderSize());
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100470
471/** Calculate the maximum window for a given tensor shape and border setting. The window will also includes the border.
472 *
473 * @param[in] info Tensor info object defining the shape of the object for which the window is created.
474 * @param[in] steps (Optional) Number of elements processed for each step.
475 * @param[in] border_size (Optional) Border size. The border region will be included in the window.
476 *
477 * @return The maximum window the kernel can be executed on.
478 */
Diego Lopez Recasbcbc9702017-12-18 11:28:27 +0000479inline Window calculate_max_enlarged_window(const ITensorInfo &info, const Steps &steps = Steps(), BorderSize border_size = BorderSize())
480{
481 return calculate_max_enlarged_window(info.valid_region(), steps, border_size);
482}
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100483
484/** Intersect multiple valid regions.
485 *
486 * @param[in] regions Valid regions.
487 *
488 * @return Intersection of all regions.
489 */
490template <typename... Ts>
Diego Lopez Recas490b3d82017-12-19 15:42:25 +0000491ValidRegion intersect_valid_regions(const Ts &... regions)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100492{
493 auto intersect = [](const ValidRegion & r1, const ValidRegion & r2) -> ValidRegion
494 {
495 ValidRegion region;
496
497 for(size_t d = 0; d < std::min(r1.anchor.num_dimensions(), r2.anchor.num_dimensions()); ++d)
498 {
499 region.anchor.set(d, std::max(r1.anchor[d], r2.anchor[d]));
500 }
501
502 for(size_t d = 0; d < std::min(r1.shape.num_dimensions(), r2.shape.num_dimensions()); ++d)
503 {
504 region.shape.set(d, std::min(r1.shape[d], r2.shape[d]));
505 }
506
507 return region;
508 };
509
Diego Lopez Recas490b3d82017-12-19 15:42:25 +0000510 return utility::foldl(intersect, regions...);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100511}
512
513/** Create a strides object based on the provided strides and the tensor dimensions.
514 *
515 * @param[in] info Tensor info object providing the shape of the tensor for unspecified strides.
516 * @param[in] stride_x Stride to be used in X dimension (in bytes).
517 * @param[in] fixed_strides Strides to be used in higher dimensions starting at Y (in bytes).
518 *
519 * @return Strides object based on the specified strides. Missing strides are
520 * calculated based on the tensor shape and the strides of lower dimensions.
521 */
522template <typename T, typename... Ts>
523inline Strides compute_strides(const ITensorInfo &info, T stride_x, Ts &&... fixed_strides)
524{
525 const TensorShape &shape = info.tensor_shape();
526
527 // Create strides object
528 Strides strides(stride_x, fixed_strides...);
529
530 for(size_t i = 1 + sizeof...(Ts); i < info.num_dimensions(); ++i)
531 {
532 strides.set(i, shape[i - 1] * strides[i - 1]);
533 }
534
535 return strides;
536}
537
538/** Create a strides object based on the tensor dimensions.
539 *
540 * @param[in] info Tensor info object used to compute the strides.
541 *
542 * @return Strides object based on element size and tensor shape.
543 */
544template <typename... Ts>
545inline Strides compute_strides(const ITensorInfo &info)
546{
547 return compute_strides(info, info.element_size());
548}
549
Georgios Pinitas8795ffb2017-12-01 16:13:40 +0000550/** Permutes given Dimensions according to a permutation vector
551 *
552 * @warning Validity of permutation is not checked
553 *
554 * @param[in, out] dimensions Dimensions to permute
555 * @param[in] perm Permutation vector
556 */
557template <typename T>
558inline void permute(Dimensions<T> &dimensions, const PermutationVector &perm)
559{
Georgios Pinitas69af6cf2018-02-14 19:23:44 +0000560 auto dimensions_copy = utility::make_array<Dimensions<T>::num_max_dimensions>(dimensions.begin(), dimensions.end());
Georgios Pinitas8795ffb2017-12-01 16:13:40 +0000561 for(unsigned int i = 0; i < perm.num_dimensions(); ++i)
562 {
Georgios Pinitas69af6cf2018-02-14 19:23:44 +0000563 T dimension_val = (perm[i] < dimensions.num_dimensions()) ? dimensions_copy[perm[i]] : 0;
564 dimensions.set(i, dimension_val);
565 }
566}
567
568/** Permutes given TensorShape according to a permutation vector
569 *
570 * @warning Validity of permutation is not checked
571 *
572 * @param[in, out] shape Shape to permute
573 * @param[in] perm Permutation vector
574 */
575inline void permute(TensorShape &shape, const PermutationVector &perm)
576{
Giorgio Arena563494c2018-04-30 17:29:41 +0100577 TensorShape shape_copy = shape;
Georgios Pinitas69af6cf2018-02-14 19:23:44 +0000578 for(unsigned int i = 0; i < perm.num_dimensions(); ++i)
579 {
580 size_t dimension_val = (perm[i] < shape.num_dimensions()) ? shape_copy[perm[i]] : 1;
Giorgio Arena563494c2018-04-30 17:29:41 +0100581 shape.set(i, dimension_val, false); // Avoid changes in _num_dimension
Georgios Pinitas8795ffb2017-12-01 16:13:40 +0000582 }
583}
584
Vidhya Sudhan Loganathan7485d5a2018-07-04 09:34:00 +0100585/** Auto initialize the tensor info (shape, number of channels and data type) if the current assignment is empty.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100586 *
Vidhya Sudhan Loganathan7485d5a2018-07-04 09:34:00 +0100587 * @param[in,out] info Tensor info used to check and assign.
588 * @param[in] shape New shape.
589 * @param[in] num_channels New number of channels.
590 * @param[in] data_type New data type
591 * @param[in] quantization_info (Optional) New quantization info
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100592 *
593 * @return True if the tensor info has been initialized
594 */
Georgios Pinitas05078ec2017-11-02 13:06:59 +0000595bool auto_init_if_empty(ITensorInfo &info,
596 const TensorShape &shape,
597 int num_channels, DataType data_type,
Georgios Pinitas05078ec2017-11-02 13:06:59 +0000598 QuantizationInfo quantization_info = QuantizationInfo());
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100599
Georgios Pinitas283c1792017-11-10 18:14:06 +0000600/** Auto initialize the tensor info using another tensor info.
601 *
602 * @param info_sink Tensor info used to check and assign
603 * @param info_source Tensor info used to assign
604 *
605 * @return True if the tensor info has been initialized
606 */
Pablo Palmiera2b89ca2017-10-05 15:01:34 +0100607bool auto_init_if_empty(ITensorInfo &info_sink, const ITensorInfo &info_source);
Georgios Pinitas283c1792017-11-10 18:14:06 +0000608
Alex Gildayc357c472018-03-21 13:54:09 +0000609/** Set the shape to the specified value if the current assignment is empty.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100610 *
611 * @param[in,out] info Tensor info used to check and assign.
612 * @param[in] shape New shape.
613 *
614 * @return True if the shape has been changed.
615 */
616bool set_shape_if_empty(ITensorInfo &info, const TensorShape &shape);
617
Alex Gildayc357c472018-03-21 13:54:09 +0000618/** Set the format, data type and number of channels to the specified value if
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100619 * the current data type is unknown.
620 *
621 * @param[in,out] info Tensor info used to check and assign.
622 * @param[in] format New format.
623 *
624 * @return True if the format has been changed.
625 */
626bool set_format_if_unknown(ITensorInfo &info, Format format);
627
Alex Gildayc357c472018-03-21 13:54:09 +0000628/** Set the data type and number of channels to the specified value if
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100629 * the current data type is unknown.
630 *
631 * @param[in,out] info Tensor info used to check and assign.
632 * @param[in] data_type New data type.
633 *
634 * @return True if the data type has been changed.
635 */
636bool set_data_type_if_unknown(ITensorInfo &info, DataType data_type);
637
Alex Gildayc357c472018-03-21 13:54:09 +0000638/** Set the data layout to the specified value if
Isabella Gottardid17a6772018-02-27 17:41:55 +0000639 * the current data layout is unknown.
640 *
641 * @param[in,out] info Tensor info used to check and assign.
642 * @param[in] data_layout New data layout.
643 *
644 * @return True if the data type has been changed.
645 */
646bool set_data_layout_if_unknown(ITensorInfo &info, DataLayout data_layout);
647
Alex Gildayc357c472018-03-21 13:54:09 +0000648/** Set the quantization info to the specified value if
Georgios Pinitas05078ec2017-11-02 13:06:59 +0000649 * the current quantization info is empty and the data type of asymmetric quantized type
650 *
651 * @param[in,out] info Tensor info used to check and assign.
652 * @param[in] quantization_info Quantization info
653 *
654 * @return True if the quantization info has been changed.
655 */
656bool set_quantization_info_if_empty(ITensorInfo &info, QuantizationInfo quantization_info);
657
Isabella Gottardi1fab09f2017-07-13 15:55:57 +0100658/** Helper function to calculate the Valid Region for Scale.
659 *
Diego Lopez Recas00854292018-02-22 13:08:01 +0000660 * @param[in] src_info Input tensor info used to check.
661 * @param[in] dst_shape Shape of the output.
662 * @param[in] interpolate_policy Interpolation policy.
663 * @param[in] sampling_policy Sampling policy.
664 * @param[in] border_undefined True if the border is undefined.
Isabella Gottardi1fab09f2017-07-13 15:55:57 +0100665 *
Diego Lopez Recas00854292018-02-22 13:08:01 +0000666 * @return The corresponding valid region
Isabella Gottardi1fab09f2017-07-13 15:55:57 +0100667 */
Diego Lopez Recas00854292018-02-22 13:08:01 +0000668ValidRegion calculate_valid_region_scale(const ITensorInfo &src_info, const TensorShape &dst_shape,
669 InterpolationPolicy interpolate_policy, SamplingPolicy sampling_policy, bool border_undefined);
Georgios Pinitas05078ec2017-11-02 13:06:59 +0000670
Georgios Pinitas5ee66ea2017-09-07 17:29:16 +0100671/** Convert a linear index into n-dimensional coordinates.
672 *
673 * @param[in] shape Shape of the n-dimensional tensor.
674 * @param[in] index Linear index specifying the i-th element.
675 *
676 * @return n-dimensional coordinates.
677 */
678inline Coordinates index2coords(const TensorShape &shape, int index);
Georgios Pinitas05078ec2017-11-02 13:06:59 +0000679
Georgios Pinitas5ee66ea2017-09-07 17:29:16 +0100680/** Convert n-dimensional coordinates into a linear index.
681 *
682 * @param[in] shape Shape of the n-dimensional tensor.
683 * @param[in] coord N-dimensional coordinates.
684 *
685 * @return linead index
686 */
687inline int coords2index(const TensorShape &shape, const Coordinates &coord);
Isabella Gottardid17a6772018-02-27 17:41:55 +0000688
Alex Gildayc357c472018-03-21 13:54:09 +0000689/** Get the index of the given dimension.
Isabella Gottardid17a6772018-02-27 17:41:55 +0000690 *
Alex Gildayc357c472018-03-21 13:54:09 +0000691 * @param[in] data_layout The data layout.
692 * @param[in] data_layout_dimension The dimension which this index is requested for.
Isabella Gottardid17a6772018-02-27 17:41:55 +0000693 *
694 * @return The int conversion of the requested data layout index.
695 */
Isabella Gottardid56e7702018-02-28 14:29:36 +0000696inline size_t get_data_layout_dimension_index(const DataLayout data_layout, const DataLayoutDimension data_layout_dimension);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100697} // namespace arm_compute
698
699#include "arm_compute/core/Helpers.inl"
700#endif /*__ARM_COMPUTE_HELPERS_H__ */