blob: 1554f63904723d798f62415d71fe3072af9db4fb [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
27#include "arm_compute/core/CL/CLTypes.h"
28#include "arm_compute/core/Coordinates.h"
Georgios Pinitas583137c2017-08-31 18:12:42 +010029#include "arm_compute/core/Error.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010030#include "arm_compute/core/IAccessWindow.h"
31#include "arm_compute/core/Steps.h"
32#include "arm_compute/core/Strides.h"
33#include "arm_compute/core/TensorShape.h"
34#include "arm_compute/core/Types.h"
35#include "arm_compute/core/Window.h"
Georgios Pinitas583137c2017-08-31 18:12:42 +010036
Anthony Barbier6ff3b192017-09-04 18:44:23 +010037#include <array>
38#include <cstddef>
39#include <cstdint>
40#include <memory>
41#include <tuple>
42#include <type_traits>
43#include <utility>
44
45namespace arm_compute
46{
47class IKernel;
48class ITensor;
49class ITensorInfo;
50
Anthony Barbier6ff3b192017-09-04 18:44:23 +010051template <typename T>
52struct enable_bitwise_ops
53{
54 static constexpr bool value = false;
55};
56
57template <typename T>
58typename std::enable_if<enable_bitwise_ops<T>::value, T>::type operator&(T lhs, T rhs)
59{
60 using underlying_type = typename std::underlying_type<T>::type;
61 return static_cast<T>(static_cast<underlying_type>(lhs) & static_cast<underlying_type>(rhs));
62}
63
64namespace traits
65{
66/** Check if a type T is contained in a tuple Tuple of types */
67template <typename T, typename Tuple>
68struct is_contained;
69
70template <typename T>
71struct is_contained<T, std::tuple<>> : std::false_type
72{
73};
74
75template <typename T, typename... Ts>
76struct is_contained<T, std::tuple<T, Ts...>> : std::true_type
77{
78};
79
80template <typename T, typename U, typename... Ts>
81struct is_contained<T, std::tuple<U, Ts...>> : is_contained<T, std::tuple<Ts...>>
82{
83};
84}
85
86/** Computes bilinear interpolation using the pointer to the top-left pixel and the pixel's distance between
Georgios Pinitas583137c2017-08-31 18:12:42 +010087 * the real coordinates and the smallest following integer coordinates. Input must be in single channel format.
Anthony Barbier6ff3b192017-09-04 18:44:23 +010088 *
Georgios Pinitas583137c2017-08-31 18:12:42 +010089 * @param[in] pixel_ptr Pointer to the top-left pixel value of a single channel input.
Anthony Barbier6ff3b192017-09-04 18:44:23 +010090 * @param[in] stride Stride to access the bottom-left and bottom-right pixel values
91 * @param[in] dx Pixel's distance between the X real coordinate and the smallest X following integer
92 * @param[in] dy Pixel's distance between the Y real coordinate and the smallest Y following integer
93 *
94 * @note dx and dy must be in the range [0, 1.0]
95 *
96 * @return The bilinear interpolated pixel value
97 */
Georgios Pinitas583137c2017-08-31 18:12:42 +010098template <typename T>
99inline T delta_bilinear_c1(const T *pixel_ptr, size_t stride, float dx, float dy)
100{
101 ARM_COMPUTE_ERROR_ON(pixel_ptr == nullptr);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100102
Georgios Pinitas583137c2017-08-31 18:12:42 +0100103 const float dx1 = 1.0f - dx;
104 const float dy1 = 1.0f - dy;
105
106 const T a00 = *pixel_ptr;
107 const T a01 = *(pixel_ptr + 1);
108 const T a10 = *(pixel_ptr + stride);
109 const T a11 = *(pixel_ptr + stride + 1);
110
111 const float w1 = dx1 * dy1;
112 const float w2 = dx * dy1;
113 const float w3 = dx1 * dy;
114 const float w4 = dx * dy;
115
116 return static_cast<T>(a00 * w1 + a01 * w2 + a10 * w3 + a11 * w4);
117}
118
Anthony Barbier9a33b542017-12-12 22:08:59 +0000119/** Computes linear interpolation using the pointer to the top pixel and the pixel's distance between
120 * the real coordinates and the smallest following integer coordinates. Input must be in single channel format.
121 *
122 * @param[in] pixel_ptr Pointer to the top pixel value of a single channel input.
123 * @param[in] stride Stride to access the bottom pixel value
124 * @param[in] dy Pixel's distance between the Y real coordinate and the smallest Y following integer
125 *
126 * @note dy must be in the range [0, 1.0]
127 *
128 * @return The linear interpolated pixel value
129 */
130template <typename T>
131inline T delta_linear_c1_y(const T *pixel_ptr, size_t stride, float dy)
132{
133 ARM_COMPUTE_ERROR_ON(pixel_ptr == nullptr);
134
135 const float dy1 = 1.0f - dy;
136
137 const T a00 = *pixel_ptr;
138 const T a10 = *(pixel_ptr + stride);
139
140 const float w1 = dy1;
141 const float w3 = dy;
142
143 return static_cast<T>(a00 * w1 + a10 * w3);
144}
145/** Computes linear interpolation using the pointer to the left pixel and the pixel's distance between
146 * the real coordinates and the smallest following integer coordinates. Input must be in single channel format.
147 *
148 * @param[in] pixel_ptr Pointer to the left pixel value of a single channel input.
149 * @param[in] dx Pixel's distance between the X real coordinate and the smallest X following integer
150 *
151 * @note dx must be in the range [0, 1.0]
152 *
153 * @return The linear interpolated pixel value
154 */
155template <typename T>
156inline T delta_linear_c1_x(const T *pixel_ptr, float dx)
157{
158 ARM_COMPUTE_ERROR_ON(pixel_ptr == nullptr);
159
160 const T a00 = *pixel_ptr;
161 const T a01 = *(pixel_ptr + 1);
162
163 const float dx1 = 1.0f - dx;
164
165 const float w1 = dx1;
166 const float w2 = dx;
167
168 return static_cast<T>(a00 * w1 + a01 * w2);
169}
Georgios Pinitas583137c2017-08-31 18:12:42 +0100170/** Return the pixel at (x,y) using bilinear interpolation.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100171 *
172 * @warning Only works if the iterator was created with an IImage
173 *
Georgios Pinitas583137c2017-08-31 18:12:42 +0100174 * @param[in] first_pixel_ptr Pointer to the first pixel of a single channel input.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100175 * @param[in] stride Stride in bytes of the image;
176 * @param[in] x X position of the wanted pixel
177 * @param[in] y Y position of the wanted pixel
178 *
179 * @return The pixel at (x, y) using bilinear interpolation.
180 */
Georgios Pinitas583137c2017-08-31 18:12:42 +0100181template <typename T>
182inline T pixel_bilinear_c1(const T *first_pixel_ptr, size_t stride, float x, float y)
183{
184 ARM_COMPUTE_ERROR_ON(first_pixel_ptr == nullptr);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100185
Georgios Pinitas583137c2017-08-31 18:12:42 +0100186 const int32_t xi = std::floor(x);
187 const int32_t yi = std::floor(y);
188
189 const float dx = x - xi;
190 const float dy = y - yi;
191
192 return delta_bilinear_c1(first_pixel_ptr + xi + yi * stride, stride, dx, dy);
193}
194
195/** 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 +0100196 *
197 * @warning Only works if the iterator was created with an IImage
198 *
Georgios Pinitas583137c2017-08-31 18:12:42 +0100199 * @param[in] first_pixel_ptr Pointer to the first pixel of a single channel image.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100200 * @param[in] stride Stride in bytes of the image
201 * @param[in] width Width of the image
202 * @param[in] height Height of the image
203 * @param[in] x X position of the wanted pixel
204 * @param[in] y Y position of the wanted pixel
205 *
206 * @return The pixel at (x, y) using bilinear interpolation.
207 */
Georgios Pinitas583137c2017-08-31 18:12:42 +0100208template <typename T>
209inline uint8_t pixel_bilinear_c1_clamp(const T *first_pixel_ptr, size_t stride, size_t width, size_t height, float x, float y)
210{
211 ARM_COMPUTE_ERROR_ON(first_pixel_ptr == nullptr);
212
213 x = std::max(-1.f, std::min(x, static_cast<float>(width)));
214 y = std::max(-1.f, std::min(y, static_cast<float>(height)));
215
216 const float xi = std::floor(x);
217 const float yi = std::floor(y);
218
219 const float dx = x - xi;
220 const float dy = y - yi;
221
Anthony Barbier9a33b542017-12-12 22:08:59 +0000222 if(dx == 0.0f)
223 {
224 if(dy == 0.0f)
225 {
226 return static_cast<T>(first_pixel_ptr[static_cast<int32_t>(xi) + static_cast<int32_t>(yi) * stride]);
227 }
228 return delta_linear_c1_y(first_pixel_ptr + static_cast<int32_t>(xi) + static_cast<int32_t>(yi) * stride, stride, dy);
229 }
230 if(dy == 0.0f)
231 {
232 return delta_linear_c1_x(first_pixel_ptr + static_cast<int32_t>(xi) + static_cast<int32_t>(yi) * stride, dx);
233 }
Georgios Pinitas583137c2017-08-31 18:12:42 +0100234 return delta_bilinear_c1(first_pixel_ptr + static_cast<int32_t>(xi) + static_cast<int32_t>(yi) * stride, stride, dx, dy);
235}
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100236
237/** Return the pixel at (x,y) using area interpolation by clamping when out of borders. The image must be single channel U8
238 *
239 * @note The interpolation area depends on the width and height ration of the input and output images
240 * @note Currently average of the contributing pixels is calculated
241 *
242 * @param[in] first_pixel_ptr Pointer to the first pixel of a single channel U8 image.
243 * @param[in] stride Stride in bytes of the image
244 * @param[in] width Width of the image
245 * @param[in] height Height of the image
246 * @param[in] wr Width ratio among the input image width and output image width.
247 * @param[in] hr Height ratio among the input image height and output image height.
248 * @param[in] x X position of the wanted pixel
249 * @param[in] y Y position of the wanted pixel
250 *
251 * @return The pixel at (x, y) using area interpolation.
252 */
253inline 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);
254
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100255/** Iterator updated by @ref execute_window_loop for each window element */
256class Iterator
257{
258public:
259 /** Default constructor to create an empty iterator */
260 constexpr Iterator();
261 /** Create a container iterator for the metadata and allocation contained in the ITensor
262 *
263 * @param[in] tensor The tensor to associate to the iterator.
264 * @param[in] window The window which will be used to iterate over the tensor.
265 */
266 Iterator(const ITensor *tensor, const Window &window);
267
268 /** Increment the iterator along the specified dimension of the step value associated to the dimension.
269 *
270 * @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.
271 *
272 * @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.
273 *
274 * @param[in] dimension Dimension to increment
275 */
276 void increment(size_t dimension);
277
278 /** Return the offset in bytes from the first element to the current position of the iterator
279 *
280 * @return The current position of the iterator in bytes relative to the first element.
281 */
282 constexpr int offset() const;
283
284 /** Return a pointer to the current pixel.
285 *
286 * @warning Only works if the iterator was created with an ITensor.
287 *
288 * @return equivalent to buffer() + offset()
289 */
290 constexpr uint8_t *ptr() const;
291
292 /** Move the iterator back to the beginning of the specified dimension.
293 *
294 * @param[in] dimension Dimension to reset
295 */
296 void reset(size_t dimension);
297
298private:
299 uint8_t *_ptr;
300
301 class Dimension
302 {
303 public:
304 constexpr Dimension()
305 : _dim_start(0), _stride(0)
306 {
307 }
308
309 int _dim_start;
310 int _stride;
311 };
312
313 std::array<Dimension, Coordinates::num_max_dimensions> _dims;
314};
315
316/** Iterate through the passed window, automatically adjusting the iterators and calling the lambda_functino for each element.
317 * It passes the x and y positions to the lambda_function for each iteration
318 *
319 * @param[in] w Window to iterate through.
320 * @param[in] lambda_function The function of type void(function)( const Coordinates & id ) to call at each iteration.
321 * Where id represents the absolute coordinates of the item to process.
322 * @param[in,out] iterators Tensor iterators which will be updated by this function before calling lambda_function.
323 */
324template <typename L, typename... Ts>
325inline void execute_window_loop(const Window &w, L &&lambda_function, Ts &&... iterators);
326
327/** Update window and padding size for each of the access patterns.
328 *
329 * First the window size is reduced based on all access patterns that are not
330 * allowed to modify the padding of the underlying tensor. Then the padding of
331 * the remaining tensors is increased to match the window.
332 *
333 * @param[in] win Window that is used by the kernel.
334 * @param[in] patterns Access patterns used to calculate the final window and padding.
335 *
336 * @return True if the window has been changed. Changes to the padding do not
337 * influence the returned value.
338 */
339template <typename... Ts>
340bool update_window_and_padding(Window &win, Ts &&... patterns)
341{
342 bool window_changed = false;
343
Diego Lopez Recas490b3d82017-12-19 15:42:25 +0000344 utility::for_each([&](const IAccessWindow & w)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100345 {
346 window_changed |= w.update_window_if_needed(win);
347 },
348 patterns...);
349
350 bool padding_changed = false;
351
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +0000352 utility::for_each([&](IAccessWindow & w)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100353 {
354 padding_changed |= w.update_padding_if_needed(win);
355 },
356 patterns...);
357
358 return window_changed;
359}
360
361/** Calculate the maximum window for a given tensor shape and border setting
362 *
Diego Lopez Recasbcbc9702017-12-18 11:28:27 +0000363 * @param[in] valid_region Valid region object defining the shape of the tensor space for which the window is created.
364 * @param[in] steps (Optional) Number of elements processed for each step.
365 * @param[in] skip_border (Optional) If true exclude the border region from the window.
366 * @param[in] border_size (Optional) Border size.
367 *
368 * @return The maximum window the kernel can be executed on.
369 */
370Window calculate_max_window(const ValidRegion &valid_region, const Steps &steps = Steps(), bool skip_border = false, BorderSize border_size = BorderSize());
371
372/** Calculate the maximum window for a given tensor shape and border setting
373 *
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100374 * @param[in] info Tensor info object defining the shape of the object for which the window is created.
375 * @param[in] steps (Optional) Number of elements processed for each step.
376 * @param[in] skip_border (Optional) If true exclude the border region from the window.
377 * @param[in] border_size (Optional) Border size.
378 *
379 * @return The maximum window the kernel can be executed on.
380 */
Diego Lopez Recasbcbc9702017-12-18 11:28:27 +0000381inline Window calculate_max_window(const ITensorInfo &info, const Steps &steps = Steps(), bool skip_border = false, BorderSize border_size = BorderSize())
382{
383 return calculate_max_window(info.valid_region(), steps, skip_border, border_size);
384}
385
386/** Calculate the maximum window used by a horizontal kernel for a given tensor shape and border setting
387 *
388 * @param[in] valid_region Valid region object defining the shape of the tensor space for which the window is created.
389 * @param[in] steps (Optional) Number of elements processed for each step.
390 * @param[in] skip_border (Optional) If true exclude the border region from the window.
391 * @param[in] border_size (Optional) Border size. The border region will be excluded from the window.
392 *
393 * @return The maximum window the kernel can be executed on.
394 */
395Window 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 +0100396
397/** Calculate the maximum window used by a horizontal kernel for a given tensor shape and border setting
398 *
399 * @param[in] info Tensor info object defining the shape of the object for which the window is created.
400 * @param[in] steps (Optional) Number of elements processed for each step.
401 * @param[in] skip_border (Optional) If true exclude the border region from the window.
Diego Lopez Recasbcbc9702017-12-18 11:28:27 +0000402 * @param[in] border_size (Optional) Border size.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100403 *
404 * @return The maximum window the kernel can be executed on.
405 */
Diego Lopez Recasbcbc9702017-12-18 11:28:27 +0000406inline Window calculate_max_window_horizontal(const ITensorInfo &info, const Steps &steps = Steps(), bool skip_border = false, BorderSize border_size = BorderSize())
407{
408 return calculate_max_window_horizontal(info.valid_region(), steps, skip_border, border_size);
409}
410
411/** Calculate the maximum window for a given tensor shape and border setting. The window will also includes the border.
412 *
413 * @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] border_size (Optional) Border size. The border region will be included in the window.
416 *
417 * @return The maximum window the kernel can be executed on.
418 */
419Window calculate_max_enlarged_window(const ValidRegion &valid_region, const Steps &steps = Steps(), BorderSize border_size = BorderSize());
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100420
421/** Calculate the maximum window for a given tensor shape and border setting. The window will also includes the border.
422 *
423 * @param[in] info Tensor info object defining the shape of the object for which the window is created.
424 * @param[in] steps (Optional) Number of elements processed for each step.
425 * @param[in] border_size (Optional) Border size. The border region will be included in the window.
426 *
427 * @return The maximum window the kernel can be executed on.
428 */
Diego Lopez Recasbcbc9702017-12-18 11:28:27 +0000429inline Window calculate_max_enlarged_window(const ITensorInfo &info, const Steps &steps = Steps(), BorderSize border_size = BorderSize())
430{
431 return calculate_max_enlarged_window(info.valid_region(), steps, border_size);
432}
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100433
434/** Intersect multiple valid regions.
435 *
436 * @param[in] regions Valid regions.
437 *
438 * @return Intersection of all regions.
439 */
440template <typename... Ts>
Diego Lopez Recas490b3d82017-12-19 15:42:25 +0000441ValidRegion intersect_valid_regions(const Ts &... regions)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100442{
443 auto intersect = [](const ValidRegion & r1, const ValidRegion & r2) -> ValidRegion
444 {
445 ValidRegion region;
446
447 for(size_t d = 0; d < std::min(r1.anchor.num_dimensions(), r2.anchor.num_dimensions()); ++d)
448 {
449 region.anchor.set(d, std::max(r1.anchor[d], r2.anchor[d]));
450 }
451
452 for(size_t d = 0; d < std::min(r1.shape.num_dimensions(), r2.shape.num_dimensions()); ++d)
453 {
454 region.shape.set(d, std::min(r1.shape[d], r2.shape[d]));
455 }
456
457 return region;
458 };
459
Diego Lopez Recas490b3d82017-12-19 15:42:25 +0000460 return utility::foldl(intersect, regions...);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100461}
462
463/** Create a strides object based on the provided strides and the tensor dimensions.
464 *
465 * @param[in] info Tensor info object providing the shape of the tensor for unspecified strides.
466 * @param[in] stride_x Stride to be used in X dimension (in bytes).
467 * @param[in] fixed_strides Strides to be used in higher dimensions starting at Y (in bytes).
468 *
469 * @return Strides object based on the specified strides. Missing strides are
470 * calculated based on the tensor shape and the strides of lower dimensions.
471 */
472template <typename T, typename... Ts>
473inline Strides compute_strides(const ITensorInfo &info, T stride_x, Ts &&... fixed_strides)
474{
475 const TensorShape &shape = info.tensor_shape();
476
477 // Create strides object
478 Strides strides(stride_x, fixed_strides...);
479
480 for(size_t i = 1 + sizeof...(Ts); i < info.num_dimensions(); ++i)
481 {
482 strides.set(i, shape[i - 1] * strides[i - 1]);
483 }
484
485 return strides;
486}
487
488/** Create a strides object based on the tensor dimensions.
489 *
490 * @param[in] info Tensor info object used to compute the strides.
491 *
492 * @return Strides object based on element size and tensor shape.
493 */
494template <typename... Ts>
495inline Strides compute_strides(const ITensorInfo &info)
496{
497 return compute_strides(info, info.element_size());
498}
499
Georgios Pinitas8795ffb2017-12-01 16:13:40 +0000500/** Permutes given Dimensions according to a permutation vector
501 *
502 * @warning Validity of permutation is not checked
503 *
504 * @param[in, out] dimensions Dimensions to permute
505 * @param[in] perm Permutation vector
506 */
507template <typename T>
508inline void permute(Dimensions<T> &dimensions, const PermutationVector &perm)
509{
Georgios Pinitas69af6cf2018-02-14 19:23:44 +0000510 auto dimensions_copy = utility::make_array<Dimensions<T>::num_max_dimensions>(dimensions.begin(), dimensions.end());
Georgios Pinitas8795ffb2017-12-01 16:13:40 +0000511 for(unsigned int i = 0; i < perm.num_dimensions(); ++i)
512 {
Georgios Pinitas69af6cf2018-02-14 19:23:44 +0000513 T dimension_val = (perm[i] < dimensions.num_dimensions()) ? dimensions_copy[perm[i]] : 0;
514 dimensions.set(i, dimension_val);
515 }
516}
517
518/** Permutes given TensorShape according to a permutation vector
519 *
520 * @warning Validity of permutation is not checked
521 *
522 * @param[in, out] shape Shape to permute
523 * @param[in] perm Permutation vector
524 */
525inline void permute(TensorShape &shape, const PermutationVector &perm)
526{
527 auto shape_copy = utility::make_array<TensorShape::num_max_dimensions>(shape.begin(), shape.end());
528 for(unsigned int i = 0; i < perm.num_dimensions(); ++i)
529 {
530 size_t dimension_val = (perm[i] < shape.num_dimensions()) ? shape_copy[perm[i]] : 1;
531 shape.set(i, dimension_val);
Georgios Pinitas8795ffb2017-12-01 16:13:40 +0000532 }
533}
534
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100535/* Auto initialize the tensor info (shape, number of channels, data type and fixed point position) if the current assignment is empty.
536 *
537 * @param[in,out] info Tensor info used to check and assign.
538 * @param[in] shape New shape.
539 * @param[in] num_channels New number of channels.
540 * @param[in] data_type New data type
541 * @param[in] fixed_point_position New fixed point position
Georgios Pinitas05078ec2017-11-02 13:06:59 +0000542 * @param[in] quantization_info (Optional) New quantization info
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100543 *
544 * @return True if the tensor info has been initialized
545 */
Georgios Pinitas05078ec2017-11-02 13:06:59 +0000546bool auto_init_if_empty(ITensorInfo &info,
547 const TensorShape &shape,
548 int num_channels, DataType data_type,
549 int fixed_point_position,
550 QuantizationInfo quantization_info = QuantizationInfo());
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100551
Georgios Pinitas283c1792017-11-10 18:14:06 +0000552/** Auto initialize the tensor info using another tensor info.
553 *
554 * @param info_sink Tensor info used to check and assign
555 * @param info_source Tensor info used to assign
556 *
557 * @return True if the tensor info has been initialized
558 */
Pablo Palmiera2b89ca2017-10-05 15:01:34 +0100559bool auto_init_if_empty(ITensorInfo &info_sink, const ITensorInfo &info_source);
Georgios Pinitas283c1792017-11-10 18:14:06 +0000560
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100561/* Set the shape to the specified value if the current assignment is empty.
562 *
563 * @param[in,out] info Tensor info used to check and assign.
564 * @param[in] shape New shape.
565 *
566 * @return True if the shape has been changed.
567 */
568bool set_shape_if_empty(ITensorInfo &info, const TensorShape &shape);
569
570/* Set the format, data type and number of channels to the specified value if
571 * the current data type is unknown.
572 *
573 * @param[in,out] info Tensor info used to check and assign.
574 * @param[in] format New format.
575 *
576 * @return True if the format has been changed.
577 */
578bool set_format_if_unknown(ITensorInfo &info, Format format);
579
580/* Set the data type and number of channels to the specified value if
581 * the current data type is unknown.
582 *
583 * @param[in,out] info Tensor info used to check and assign.
584 * @param[in] data_type New data type.
585 *
586 * @return True if the data type has been changed.
587 */
588bool set_data_type_if_unknown(ITensorInfo &info, DataType data_type);
589
Isabella Gottardid17a6772018-02-27 17:41:55 +0000590/* Set the data layout to the specified value if
591 * the current data layout is unknown.
592 *
593 * @param[in,out] info Tensor info used to check and assign.
594 * @param[in] data_layout New data layout.
595 *
596 * @return True if the data type has been changed.
597 */
598bool set_data_layout_if_unknown(ITensorInfo &info, DataLayout data_layout);
599
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100600/* Set the fixed point position to the specified value if
601 * the current fixed point position is 0 and the data type is QS8 or QS16
602 *
603 * @param[in,out] info Tensor info used to check and assign.
604 * @param[in] fixed_point_position New fixed point position
605 *
606 * @return True if the fixed point position has been changed.
607 */
608bool set_fixed_point_position_if_zero(ITensorInfo &info, int fixed_point_position);
Georgios Pinitas05078ec2017-11-02 13:06:59 +0000609
610/* Set the quantization info to the specified value if
611 * the current quantization info is empty and the data type of asymmetric quantized type
612 *
613 * @param[in,out] info Tensor info used to check and assign.
614 * @param[in] quantization_info Quantization info
615 *
616 * @return True if the quantization info has been changed.
617 */
618bool set_quantization_info_if_empty(ITensorInfo &info, QuantizationInfo quantization_info);
619
Isabella Gottardi1fab09f2017-07-13 15:55:57 +0100620/** Helper function to calculate the Valid Region for Scale.
621 *
Georgios Pinitas6727f122018-03-13 10:29:13 +0000622 * @param[in] src_info Input tensor info used to check.
623 * @param[in] dst_shape Shape of the output.
624 * @param[in] policy Interpolation policy.
625 * @param[in] border_size Size of the border.
626 * @param[in] border_undefined True if the border is undefined.
Isabella Gottardi1fab09f2017-07-13 15:55:57 +0100627 *
Georgios Pinitas6727f122018-03-13 10:29:13 +0000628 * @return The corrispondent valid region
Isabella Gottardi1fab09f2017-07-13 15:55:57 +0100629 */
Georgios Pinitas6727f122018-03-13 10:29:13 +0000630ValidRegion calculate_valid_region_scale(const ITensorInfo &src_info, const TensorShape &dst_shape, InterpolationPolicy policy, BorderSize border_size, bool border_undefined);
Georgios Pinitas05078ec2017-11-02 13:06:59 +0000631
Georgios Pinitas5ee66ea2017-09-07 17:29:16 +0100632/** Convert a linear index into n-dimensional coordinates.
633 *
634 * @param[in] shape Shape of the n-dimensional tensor.
635 * @param[in] index Linear index specifying the i-th element.
636 *
637 * @return n-dimensional coordinates.
638 */
639inline Coordinates index2coords(const TensorShape &shape, int index);
Georgios Pinitas05078ec2017-11-02 13:06:59 +0000640
Georgios Pinitas5ee66ea2017-09-07 17:29:16 +0100641/** Convert n-dimensional coordinates into a linear index.
642 *
643 * @param[in] shape Shape of the n-dimensional tensor.
644 * @param[in] coord N-dimensional coordinates.
645 *
646 * @return linead index
647 */
648inline int coords2index(const TensorShape &shape, const Coordinates &coord);
Isabella Gottardid17a6772018-02-27 17:41:55 +0000649
650/* Get the index of the given dimension.
651 *
652 * @param[in] info Tensor info used to check and assign.
653 * @param[in] data_layout New data layout.
654 *
655 * @return The int conversion of the requested data layout index.
656 */
Isabella Gottardid56e7702018-02-28 14:29:36 +0000657inline size_t get_data_layout_dimension_index(const DataLayout data_layout, const DataLayoutDimension data_layout_dimension);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100658} // namespace arm_compute
659
660#include "arm_compute/core/Helpers.inl"
661#endif /*__ARM_COMPUTE_HELPERS_H__ */