blob: 22a1e7064d5f36e4fa93e843986c2ad7368d4162 [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
Sang-Hoon Parkbb123bd2020-01-03 10:57:30 +00002 * Copyright (c) 2016-2020 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 */
Michalis Spyrouf4643372019-11-29 16:17:13 +000024#ifndef ARM_COMPUTE_UTILS_H
25#define ARM_COMPUTE_UTILS_H
Anthony Barbier6ff3b192017-09-04 18:44:23 +010026
27#include "arm_compute/core/Error.h"
Giuseppe Rossinid7647d42018-07-17 18:13:13 +010028#include "arm_compute/core/PixelValue.h"
Michel Iwaniec5dfeae62017-11-29 10:48:23 +000029#include "arm_compute/core/Rounding.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010030#include "arm_compute/core/Types.h"
31
32#include <algorithm>
33#include <cstdint>
34#include <cstdlib>
Michalis Spyrou53860dd2019-07-01 14:20:56 +010035#include <iomanip>
Anthony Barbier6ff3b192017-09-04 18:44:23 +010036#include <numeric>
37#include <sstream>
38#include <string>
39#include <type_traits>
40#include <utility>
steniu017ce53c62017-09-29 14:55:00 +010041#include <vector>
Anthony Barbier6ff3b192017-09-04 18:44:23 +010042
43namespace arm_compute
44{
Alex Gildayc357c472018-03-21 13:54:09 +000045/** Calculate the rounded up quotient of val / m.
46 *
47 * @param[in] val Value to divide and round up.
48 * @param[in] m Value to divide by.
49 *
50 * @return the result.
51 */
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +000052template <typename S, typename T>
53constexpr auto DIV_CEIL(S val, T m) -> decltype((val + m - 1) / m)
54{
55 return (val + m - 1) / m;
56}
57
Alex Gildayc357c472018-03-21 13:54:09 +000058/** Computes the smallest number larger or equal to value that is a multiple of divisor.
59 *
60 * @param[in] value Lower bound value
61 * @param[in] divisor Value to compute multiple of.
62 *
63 * @return the result.
64 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010065template <typename S, typename T>
66inline auto ceil_to_multiple(S value, T divisor) -> decltype(((value + divisor - 1) / divisor) * divisor)
67{
68 ARM_COMPUTE_ERROR_ON(value < 0 || divisor <= 0);
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +000069 return DIV_CEIL(value, divisor) * divisor;
Anthony Barbier6ff3b192017-09-04 18:44:23 +010070}
71
Alex Gildayc357c472018-03-21 13:54:09 +000072/** Computes the largest number smaller or equal to value that is a multiple of divisor.
73 *
74 * @param[in] value Upper bound value
75 * @param[in] divisor Value to compute multiple of.
76 *
77 * @return the result.
78 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010079template <typename S, typename T>
80inline auto floor_to_multiple(S value, T divisor) -> decltype((value / divisor) * divisor)
81{
82 ARM_COMPUTE_ERROR_ON(value < 0 || divisor <= 0);
83 return (value / divisor) * divisor;
84}
85
Anthony Barbier6ff3b192017-09-04 18:44:23 +010086/** Returns the arm_compute library build information
87 *
88 * Contains the version number and the build options used to build the library
89 *
90 * @return The arm_compute library build information
91 */
92std::string build_information();
93
94/** Load an entire file in memory
95 *
96 * @param[in] filename Name of the file to read.
97 * @param[in] binary Is it a binary file ?
98 *
99 * @return The content of the file.
100 */
101std::string read_file(const std::string &filename, bool binary);
102
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100103/** The size in bytes of the data type
104 *
105 * @param[in] data_type Input data type
106 *
107 * @return The size in bytes of the data type
108 */
109inline size_t data_size_from_type(DataType data_type)
110{
111 switch(data_type)
112 {
113 case DataType::U8:
114 case DataType::S8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100115 case DataType::QSYMM8:
Michel Iwaniec00633802017-10-12 14:14:15 +0100116 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100117 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100118 case DataType::QSYMM8_PER_CHANNEL:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100119 return 1;
120 case DataType::U16:
121 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100122 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100123 case DataType::QASYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100124 case DataType::F16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100125 return 2;
126 case DataType::F32:
127 case DataType::U32:
128 case DataType::S32:
129 return 4;
130 case DataType::F64:
131 case DataType::U64:
132 case DataType::S64:
133 return 8;
134 case DataType::SIZET:
135 return sizeof(size_t);
136 default:
137 ARM_COMPUTE_ERROR("Invalid data type");
138 return 0;
139 }
140}
141
142/** The size in bytes of the pixel format
143 *
144 * @param[in] format Input format
145 *
146 * @return The size in bytes of the pixel format
147 */
148inline size_t pixel_size_from_format(Format format)
149{
150 switch(format)
151 {
152 case Format::U8:
153 return 1;
154 case Format::U16:
155 case Format::S16:
156 case Format::F16:
157 case Format::UV88:
158 case Format::YUYV422:
159 case Format::UYVY422:
160 return 2;
161 case Format::RGB888:
162 return 3;
163 case Format::RGBA8888:
164 return 4;
165 case Format::U32:
166 case Format::S32:
167 case Format::F32:
168 return 4;
169 //Doesn't make sense for planar formats:
170 case Format::NV12:
171 case Format::NV21:
172 case Format::IYUV:
173 case Format::YUV444:
174 default:
175 ARM_COMPUTE_ERROR("Undefined pixel size for given format");
176 return 0;
177 }
178}
179
180/** The size in bytes of the data type
181 *
182 * @param[in] dt Input data type
183 *
184 * @return The size in bytes of the data type
185 */
186inline size_t element_size_from_data_type(DataType dt)
187{
188 switch(dt)
189 {
190 case DataType::S8:
191 case DataType::U8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100192 case DataType::QSYMM8:
Michel Iwaniec00633802017-10-12 14:14:15 +0100193 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100194 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100195 case DataType::QSYMM8_PER_CHANNEL:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100196 return 1;
197 case DataType::U16:
198 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100199 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100200 case DataType::QASYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100201 case DataType::F16:
202 return 2;
203 case DataType::U32:
204 case DataType::S32:
205 case DataType::F32:
206 return 4;
207 default:
208 ARM_COMPUTE_ERROR("Undefined element size for given data type");
209 return 0;
210 }
211}
212
213/** Return the data type used by a given single-planar pixel format
214 *
215 * @param[in] format Input format
216 *
217 * @return The size in bytes of the pixel format
218 */
219inline DataType data_type_from_format(Format format)
220{
221 switch(format)
222 {
223 case Format::U8:
224 case Format::UV88:
225 case Format::RGB888:
226 case Format::RGBA8888:
227 case Format::YUYV422:
228 case Format::UYVY422:
229 return DataType::U8;
230 case Format::U16:
231 return DataType::U16;
232 case Format::S16:
233 return DataType::S16;
234 case Format::U32:
235 return DataType::U32;
236 case Format::S32:
237 return DataType::S32;
238 case Format::F16:
239 return DataType::F16;
240 case Format::F32:
241 return DataType::F32;
242 //Doesn't make sense for planar formats:
243 case Format::NV12:
244 case Format::NV21:
245 case Format::IYUV:
246 case Format::YUV444:
247 default:
248 ARM_COMPUTE_ERROR("Not supported data_type for given format");
249 return DataType::UNKNOWN;
250 }
251}
252
253/** Return the plane index of a given channel given an input format.
254 *
255 * @param[in] format Input format
256 * @param[in] channel Input channel
257 *
258 * @return The plane index of the specific channel of the specific format
259 */
260inline int plane_idx_from_channel(Format format, Channel channel)
261{
262 switch(format)
263 {
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100264 // Single planar formats have a single plane
265 case Format::U8:
266 case Format::U16:
267 case Format::S16:
268 case Format::U32:
269 case Format::S32:
270 case Format::F16:
271 case Format::F32:
272 case Format::UV88:
273 case Format::RGB888:
274 case Format::RGBA8888:
275 case Format::YUYV422:
276 case Format::UYVY422:
277 return 0;
278 // Multi planar formats
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100279 case Format::NV12:
280 case Format::NV21:
281 {
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100282 // Channel U and V share the same plane of format UV88
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100283 switch(channel)
284 {
285 case Channel::Y:
286 return 0;
287 case Channel::U:
288 case Channel::V:
289 return 1;
290 default:
291 ARM_COMPUTE_ERROR("Not supported channel");
292 return 0;
293 }
294 }
295 case Format::IYUV:
296 case Format::YUV444:
297 {
298 switch(channel)
299 {
300 case Channel::Y:
301 return 0;
302 case Channel::U:
303 return 1;
304 case Channel::V:
305 return 2;
306 default:
307 ARM_COMPUTE_ERROR("Not supported channel");
308 return 0;
309 }
310 }
311 default:
312 ARM_COMPUTE_ERROR("Not supported format");
313 return 0;
314 }
315}
316
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100317/** Return the channel index of a given channel given an input format.
318 *
319 * @param[in] format Input format
320 * @param[in] channel Input channel
321 *
322 * @return The channel index of the specific channel of the specific format
323 */
324inline int channel_idx_from_format(Format format, Channel channel)
325{
326 switch(format)
327 {
328 case Format::RGB888:
329 {
330 switch(channel)
331 {
332 case Channel::R:
333 return 0;
334 case Channel::G:
335 return 1;
336 case Channel::B:
337 return 2;
338 default:
339 ARM_COMPUTE_ERROR("Not supported channel");
340 return 0;
341 }
342 }
343 case Format::RGBA8888:
344 {
345 switch(channel)
346 {
347 case Channel::R:
348 return 0;
349 case Channel::G:
350 return 1;
351 case Channel::B:
352 return 2;
353 case Channel::A:
354 return 3;
355 default:
356 ARM_COMPUTE_ERROR("Not supported channel");
357 return 0;
358 }
359 }
360 case Format::YUYV422:
361 {
362 switch(channel)
363 {
364 case Channel::Y:
365 return 0;
366 case Channel::U:
367 return 1;
368 case Channel::V:
369 return 3;
370 default:
371 ARM_COMPUTE_ERROR("Not supported channel");
372 return 0;
373 }
374 }
375 case Format::UYVY422:
376 {
377 switch(channel)
378 {
379 case Channel::Y:
380 return 1;
381 case Channel::U:
382 return 0;
383 case Channel::V:
384 return 2;
385 default:
386 ARM_COMPUTE_ERROR("Not supported channel");
387 return 0;
388 }
389 }
390 case Format::NV12:
391 {
392 switch(channel)
393 {
394 case Channel::Y:
395 return 0;
396 case Channel::U:
397 return 0;
398 case Channel::V:
399 return 1;
400 default:
401 ARM_COMPUTE_ERROR("Not supported channel");
402 return 0;
403 }
404 }
405 case Format::NV21:
406 {
407 switch(channel)
408 {
409 case Channel::Y:
410 return 0;
411 case Channel::U:
412 return 1;
413 case Channel::V:
414 return 0;
415 default:
416 ARM_COMPUTE_ERROR("Not supported channel");
417 return 0;
418 }
419 }
420 case Format::YUV444:
421 case Format::IYUV:
422 {
423 switch(channel)
424 {
425 case Channel::Y:
426 return 0;
427 case Channel::U:
428 return 0;
429 case Channel::V:
430 return 0;
431 default:
432 ARM_COMPUTE_ERROR("Not supported channel");
433 return 0;
434 }
435 }
436 default:
437 ARM_COMPUTE_ERROR("Not supported format");
438 return 0;
439 }
440}
441
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100442/** Return the number of planes for a given format
443 *
444 * @param[in] format Input format
445 *
446 * @return The number of planes for a given image format.
447 */
448inline size_t num_planes_from_format(Format format)
449{
450 switch(format)
451 {
452 case Format::U8:
453 case Format::S16:
454 case Format::U16:
455 case Format::S32:
456 case Format::U32:
457 case Format::F16:
458 case Format::F32:
459 case Format::RGB888:
460 case Format::RGBA8888:
461 case Format::YUYV422:
462 case Format::UYVY422:
463 return 1;
464 case Format::NV12:
465 case Format::NV21:
466 return 2;
467 case Format::IYUV:
468 case Format::YUV444:
469 return 3;
470 default:
471 ARM_COMPUTE_ERROR("Not supported format");
472 return 0;
473 }
474}
475
476/** Return the number of channels for a given single-planar pixel format
477 *
478 * @param[in] format Input format
479 *
480 * @return The number of channels for a given image format.
481 */
482inline size_t num_channels_from_format(Format format)
483{
484 switch(format)
485 {
486 case Format::U8:
487 case Format::U16:
488 case Format::S16:
489 case Format::U32:
490 case Format::S32:
491 case Format::F16:
492 case Format::F32:
493 return 1;
494 // Because the U and V channels are subsampled
495 // these formats appear like having only 2 channels:
496 case Format::YUYV422:
497 case Format::UYVY422:
498 return 2;
499 case Format::UV88:
500 return 2;
501 case Format::RGB888:
502 return 3;
503 case Format::RGBA8888:
504 return 4;
505 //Doesn't make sense for planar formats:
506 case Format::NV12:
507 case Format::NV21:
508 case Format::IYUV:
509 case Format::YUV444:
510 default:
511 return 0;
512 }
513}
514
Chunosovd621bca2017-11-03 17:33:15 +0700515/** Return the promoted data type of a given data type.
516 *
517 * @note If promoted data type is not supported an error will be thrown
518 *
519 * @param[in] dt Data type to get the promoted type of.
520 *
521 * @return Promoted data type
522 */
523inline DataType get_promoted_data_type(DataType dt)
524{
525 switch(dt)
526 {
527 case DataType::U8:
528 return DataType::U16;
529 case DataType::S8:
530 return DataType::S16;
Chunosovd621bca2017-11-03 17:33:15 +0700531 case DataType::U16:
532 return DataType::U32;
533 case DataType::S16:
534 return DataType::S32;
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100535 case DataType::QSYMM8:
Chunosovd621bca2017-11-03 17:33:15 +0700536 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100537 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100538 case DataType::QSYMM8_PER_CHANNEL:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100539 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100540 case DataType::QASYMM16:
Chunosovd621bca2017-11-03 17:33:15 +0700541 case DataType::F16:
542 case DataType::U32:
543 case DataType::S32:
544 case DataType::F32:
Chunosovd621bca2017-11-03 17:33:15 +0700545 ARM_COMPUTE_ERROR("Unsupported data type promotions!");
546 default:
547 ARM_COMPUTE_ERROR("Undefined data type!");
548 }
549 return DataType::UNKNOWN;
550}
551
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000552/** Compute the mininum and maximum values a data type can take
553 *
554 * @param[in] dt Data type to get the min/max bounds of
555 *
556 * @return A tuple (min,max) with the minimum and maximum values respectively wrapped in PixelValue.
557 */
558inline std::tuple<PixelValue, PixelValue> get_min_max(DataType dt)
559{
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000560 PixelValue min{};
561 PixelValue max{};
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000562 switch(dt)
563 {
564 case DataType::U8:
565 case DataType::QASYMM8:
566 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000567 min = PixelValue(static_cast<int32_t>(std::numeric_limits<uint8_t>::lowest()));
568 max = PixelValue(static_cast<int32_t>(std::numeric_limits<uint8_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000569 break;
570 }
571 case DataType::S8:
572 case DataType::QSYMM8:
573 case DataType::QASYMM8_SIGNED:
574 case DataType::QSYMM8_PER_CHANNEL:
575 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000576 min = PixelValue(static_cast<int32_t>(std::numeric_limits<int8_t>::lowest()));
577 max = PixelValue(static_cast<int32_t>(std::numeric_limits<int8_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000578 break;
579 }
580 case DataType::U16:
581 case DataType::QASYMM16:
582 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000583 min = PixelValue(static_cast<int32_t>(std::numeric_limits<uint16_t>::lowest()));
584 max = PixelValue(static_cast<int32_t>(std::numeric_limits<uint16_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000585 break;
586 }
587 case DataType::S16:
588 case DataType::QSYMM16:
589 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000590 min = PixelValue(static_cast<int32_t>(std::numeric_limits<int16_t>::lowest()));
591 max = PixelValue(static_cast<int32_t>(std::numeric_limits<int16_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000592 break;
593 }
594 case DataType::U32:
595 {
596 min = PixelValue(std::numeric_limits<uint32_t>::lowest());
597 max = PixelValue(std::numeric_limits<uint32_t>::max());
598 break;
599 }
600 case DataType::S32:
601 {
602 min = PixelValue(std::numeric_limits<int32_t>::lowest());
603 max = PixelValue(std::numeric_limits<int32_t>::max());
604 break;
605 }
606 case DataType::F32:
607 {
608 min = PixelValue(std::numeric_limits<float>::lowest());
609 max = PixelValue(std::numeric_limits<float>::max());
610 break;
611 }
612 default:
613 ARM_COMPUTE_ERROR("Undefined data type!");
614 }
615 return std::make_tuple(min, max);
616}
617
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100618/** Return true if the given format has horizontal subsampling.
619 *
620 * @param[in] format Format to determine subsampling.
621 *
622 * @return True if the format can be subsampled horizontaly.
623 */
624inline bool has_format_horizontal_subsampling(Format format)
625{
626 return (format == Format::YUYV422 || format == Format::UYVY422 || format == Format::NV12 || format == Format::NV21 || format == Format::IYUV || format == Format::UV88) ? true : false;
627}
628
629/** Return true if the given format has vertical subsampling.
630 *
631 * @param[in] format Format to determine subsampling.
632 *
633 * @return True if the format can be subsampled verticaly.
634 */
635inline bool has_format_vertical_subsampling(Format format)
636{
637 return (format == Format::NV12 || format == Format::NV21 || format == Format::IYUV || format == Format::UV88) ? true : false;
638}
639
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100640/** Separate a 2D convolution into two 1D convolutions
Anthony Barbierf202e502017-11-23 18:02:04 +0000641 *
642 * @param[in] conv 2D convolution
643 * @param[out] conv_col 1D vertical convolution
644 * @param[out] conv_row 1D horizontal convolution
645 * @param[in] size Size of the 2D convolution
646 *
647 * @return true if the separation was successful
648 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100649inline bool separate_matrix(const int16_t *conv, int16_t *conv_col, int16_t *conv_row, uint8_t size)
650{
651 int32_t min_col = -1;
652 int16_t min_col_val = -1;
653
654 for(int32_t i = 0; i < size; ++i)
655 {
656 if(conv[i] != 0 && (min_col < 0 || abs(min_col_val) > abs(conv[i])))
657 {
658 min_col = i;
659 min_col_val = conv[i];
660 }
661 }
662
663 if(min_col < 0)
664 {
665 return false;
666 }
667
668 for(uint32_t j = 0; j < size; ++j)
669 {
670 conv_col[j] = conv[min_col + j * size];
671 }
672
673 for(uint32_t i = 0; i < size; i++)
674 {
675 if(static_cast<int>(i) == min_col)
676 {
677 conv_row[i] = 1;
678 }
679 else
680 {
681 int16_t coeff = conv[i] / conv[min_col];
682
683 for(uint32_t j = 1; j < size; ++j)
684 {
685 if(conv[i + j * size] != (conv_col[j] * coeff))
686 {
687 return false;
688 }
689 }
690
691 conv_row[i] = coeff;
692 }
693 }
694
695 return true;
696}
697
698/** Calculate the scale of the given square matrix
699 *
700 * The scale is the absolute value of the sum of all the coefficients in the matrix.
701 *
702 * @note If the coefficients add up to 0 then the scale is set to 1.
703 *
704 * @param[in] matrix Matrix coefficients
705 * @param[in] matrix_size Number of elements per side of the square matrix. (Number of coefficients = matrix_size * matrix_size).
706 *
707 * @return The absolute value of the sum of the coefficients if they don't add up to 0, otherwise 1.
708 */
709inline uint32_t calculate_matrix_scale(const int16_t *matrix, unsigned int matrix_size)
710{
711 const size_t size = matrix_size * matrix_size;
712
713 return std::max(1, std::abs(std::accumulate(matrix, matrix + size, 0)));
714}
715
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100716/** Adjust tensor shape size if width or height are odd for a given multi-planar format. No modification is done for other formats.
717 *
718 * @note Adding here a few links discussing the issue of odd size and sharing the same solution:
Manuel Bottini581c8982019-02-07 10:31:57 +0000719 * <a href="https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/graphics/java/android/graphics/YuvImage.java">Android Source</a>
720 * <a href="https://groups.google.com/a/webmproject.org/forum/#!topic/webm-discuss/LaCKpqiDTXM">WebM</a>
721 * <a href="https://bugs.chromium.org/p/libyuv/issues/detail?id=198&amp;can=1&amp;q=odd%20width">libYUV</a>
722 * <a href="https://sourceforge.net/p/raw-yuvplayer/bugs/1/">YUVPlayer</a> *
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100723 *
724 * @param[in, out] shape Tensor shape of 2D size
725 * @param[in] format Format of the tensor
726 *
Alex Gildayc357c472018-03-21 13:54:09 +0000727 * @return The adjusted tensor shape.
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100728 */
729inline TensorShape adjust_odd_shape(const TensorShape &shape, Format format)
730{
731 TensorShape output{ shape };
732
733 // Force width to be even for formats which require subsampling of the U and V channels
734 if(has_format_horizontal_subsampling(format))
735 {
736 output.set(0, output.x() & ~1U);
737 }
738
739 // Force height to be even for formats which require subsampling of the U and V channels
740 if(has_format_vertical_subsampling(format))
741 {
742 output.set(1, output.y() & ~1U);
743 }
744
745 return output;
746}
747
748/** Calculate subsampled shape for a given format and channel
749 *
750 * @param[in] shape Shape of the tensor to calculate the extracted channel.
751 * @param[in] format Format of the tensor.
752 * @param[in] channel Channel to create tensor shape to be extracted.
753 *
754 * @return The subsampled tensor shape.
755 */
756inline TensorShape calculate_subsampled_shape(const TensorShape &shape, Format format, Channel channel = Channel::UNKNOWN)
757{
758 TensorShape output{ shape };
759
760 // Subsample shape only for U or V channel
761 if(Channel::U == channel || Channel::V == channel || Channel::UNKNOWN == channel)
762 {
763 // Subsample width for the tensor shape when channel is U or V
764 if(has_format_horizontal_subsampling(format))
765 {
766 output.set(0, output.x() / 2U);
767 }
768
769 // Subsample height for the tensor shape when channel is U or V
770 if(has_format_vertical_subsampling(format))
771 {
772 output.set(1, output.y() / 2U);
773 }
774 }
775
776 return output;
777}
778
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100779/** Calculate accurary required by the horizontal and vertical convolution computations
780 *
781 * @param[in] conv_col Pointer to the vertical vector of the separated convolution filter
782 * @param[in] conv_row Pointer to the horizontal vector of the convolution filter
783 * @param[in] size Number of elements per vector of the separated matrix
784 *
785 * @return The return type is a pair. The first element of the pair is the biggest data type needed for the first stage. The second
786 * element of the pair is the biggest data type needed for the second stage.
787 */
788inline std::pair<DataType, DataType> data_type_for_convolution(const int16_t *conv_col, const int16_t *conv_row, size_t size)
789{
790 DataType first_stage = DataType::UNKNOWN;
791 DataType second_stage = DataType::UNKNOWN;
792
793 auto gez = [](const int16_t &v)
794 {
795 return v >= 0;
796 };
797
798 auto accu_neg = [](const int &first, const int &second)
799 {
800 return first + (second < 0 ? second : 0);
801 };
802
803 auto accu_pos = [](const int &first, const int &second)
804 {
805 return first + (second > 0 ? second : 0);
806 };
807
808 const bool only_positive_coefficients = std::all_of(conv_row, conv_row + size, gez) && std::all_of(conv_col, conv_col + size, gez);
809
810 if(only_positive_coefficients)
811 {
812 const int max_row_value = std::accumulate(conv_row, conv_row + size, 0) * UINT8_MAX;
813 const int max_value = std::accumulate(conv_col, conv_col + size, 0) * max_row_value;
814
815 first_stage = (max_row_value <= UINT16_MAX) ? DataType::U16 : DataType::S32;
816
817 second_stage = (max_value <= UINT16_MAX) ? DataType::U16 : DataType::S32;
818 }
819 else
820 {
821 const int min_row_value = std::accumulate(conv_row, conv_row + size, 0, accu_neg) * UINT8_MAX;
822 const int max_row_value = std::accumulate(conv_row, conv_row + size, 0, accu_pos) * UINT8_MAX;
823 const int neg_coeffs_sum = std::accumulate(conv_col, conv_col + size, 0, accu_neg);
824 const int pos_coeffs_sum = std::accumulate(conv_col, conv_col + size, 0, accu_pos);
825 const int min_value = neg_coeffs_sum * max_row_value + pos_coeffs_sum * min_row_value;
826 const int max_value = neg_coeffs_sum * min_row_value + pos_coeffs_sum * max_row_value;
827
828 first_stage = ((INT16_MIN <= min_row_value) && (max_row_value <= INT16_MAX)) ? DataType::S16 : DataType::S32;
829
830 second_stage = ((INT16_MIN <= min_value) && (max_value <= INT16_MAX)) ? DataType::S16 : DataType::S32;
831 }
832
833 return std::make_pair(first_stage, second_stage);
834}
835
836/** Calculate the accuracy required by the squared convolution calculation.
837 *
838 *
839 * @param[in] conv Pointer to the squared convolution matrix
840 * @param[in] size The total size of the convolution matrix
841 *
842 * @return The return is the biggest data type needed to do the convolution
843 */
844inline DataType data_type_for_convolution_matrix(const int16_t *conv, size_t size)
845{
846 auto gez = [](const int16_t v)
847 {
848 return v >= 0;
849 };
850
851 const bool only_positive_coefficients = std::all_of(conv, conv + size, gez);
852
853 if(only_positive_coefficients)
854 {
855 const int max_conv_value = std::accumulate(conv, conv + size, 0) * UINT8_MAX;
856 if(max_conv_value <= UINT16_MAX)
857 {
858 return DataType::U16;
859 }
860 else
861 {
862 return DataType::S32;
863 }
864 }
865 else
866 {
867 const int min_value = std::accumulate(conv, conv + size, 0, [](int a, int b)
868 {
869 return b < 0 ? a + b : a;
870 })
871 * UINT8_MAX;
872
873 const int max_value = std::accumulate(conv, conv + size, 0, [](int a, int b)
874 {
875 return b > 0 ? a + b : a;
876 })
877 * UINT8_MAX;
878
879 if((INT16_MIN <= min_value) && (INT16_MAX >= max_value))
880 {
881 return DataType::S16;
882 }
883 else
884 {
885 return DataType::S32;
886 }
887 }
888}
889
Pablo Tello35767bc2018-12-05 17:36:30 +0000890/** Permutes the given dimensions according the permutation vector
891 *
892 * @param[in,out] dimensions Dimensions to be permuted.
893 * @param[in] perm Vector describing the permutation.
894 *
895 */
896template <typename T>
897inline void permute_strides(Dimensions<T> &dimensions, const PermutationVector &perm)
898{
899 const auto old_dim = utility::make_array<Dimensions<T>::num_max_dimensions>(dimensions.begin(), dimensions.end());
900 for(unsigned int i = 0; i < perm.num_dimensions(); ++i)
901 {
902 T dimension_val = old_dim[i];
903 dimensions.set(perm[i], dimension_val);
904 }
905}
906
Georgios Pinitas4074c992018-01-30 18:13:46 +0000907/** Calculate padding requirements in case of SAME padding
908 *
909 * @param[in] input_shape Input shape
910 * @param[in] weights_shape Weights shape
911 * @param[in] conv_info Convolution information (containing strides)
Isabella Gottardi6a914402019-01-30 15:45:42 +0000912 * @param[in] data_layout (Optional) Data layout of the input and weights tensor
Pablo Tello01bbacb2019-04-30 10:32:42 +0100913 * @param[in] dilation (Optional) Dilation factor used in the convolution.
Giorgio Arena17203582019-08-02 16:00:41 +0100914 * @param[in] rounding_type (Optional) Dimension rounding type when down-scaling.
Georgios Pinitas4074c992018-01-30 18:13:46 +0000915 *
916 * @return PadStrideInfo for SAME padding
917 */
Giorgio Arena17203582019-08-02 16:00:41 +0100918PadStrideInfo calculate_same_pad(TensorShape input_shape, TensorShape weights_shape, PadStrideInfo conv_info, DataLayout data_layout = DataLayout::NCHW, const Size2D &dilation = Size2D(1u, 1u),
919 const DimensionRoundingType &rounding_type = DimensionRoundingType::FLOOR);
Georgios Pinitas4074c992018-01-30 18:13:46 +0000920
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100921/** Returns expected width and height of the deconvolution's output tensor.
922 *
Matthew Jacksonb9070a42019-08-22 16:13:27 +0100923 * @param[in] in_width Width of input tensor (Number of columns)
924 * @param[in] in_height Height of input tensor (Number of rows)
925 * @param[in] kernel_width Kernel width.
926 * @param[in] kernel_height Kernel height.
927 * @param[in] pad_stride_info Pad and stride information.
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100928 *
929 * @return A pair with the new width in the first position and the new height in the second.
930 */
Pablo Tello01bbacb2019-04-30 10:32:42 +0100931std::pair<unsigned int, unsigned int> deconvolution_output_dimensions(unsigned int in_width, unsigned int in_height,
932 unsigned int kernel_width, unsigned int kernel_height,
Matthew Jacksonb9070a42019-08-22 16:13:27 +0100933 const PadStrideInfo &pad_stride_info);
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100934
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100935/** Returns expected width and height of output scaled tensor depending on dimensions rounding mode.
936 *
Gian Marco Iodice4e288692017-06-27 11:41:59 +0100937 * @param[in] width Width of input tensor (Number of columns)
938 * @param[in] height Height of input tensor (Number of rows)
939 * @param[in] kernel_width Kernel width.
940 * @param[in] kernel_height Kernel height.
941 * @param[in] pad_stride_info Pad and stride information.
Alex Gilday7da29b62018-03-23 14:16:00 +0000942 * @param[in] dilation (Optional) Dilation, in elements, across x and y. Defaults to (1, 1).
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100943 *
944 * @return A pair with the new width in the first position and the new height in the second.
945 */
Georgios Pinitas80838f12019-12-12 18:23:13 +0000946std::pair<unsigned int, unsigned int> scaled_dimensions(int width, int height,
947 int kernel_width, int kernel_height,
Pablo Tello01bbacb2019-04-30 10:32:42 +0100948 const PadStrideInfo &pad_stride_info,
949 const Size2D &dilation = Size2D(1U, 1U));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100950
Sang-Hoon Park2697fd82019-10-15 16:49:24 +0100951/** Check if the given reduction operation should be handled in a serial way.
952 *
953 * @param[in] op Reduction operation to perform
954 * @param[in] dt Data type
955 * @param[in] axis Axis along which to reduce
956 *
957 * @return True if the given reduction operation should be handled in a serial way.
958 */
959bool needs_serialized_reduction(ReductionOperation op, DataType dt, unsigned int axis);
960
Sang-Hoon Park0779fec2019-11-13 17:08:12 +0000961/** Returns output quantization information for softmax layer
962 *
963 * @param[in] input_type The data type of the input tensor
964 * @param[in] is_log True for log softmax
965 *
966 * @return Quantization information for the output tensor
967 */
968QuantizationInfo get_softmax_output_quantization_info(DataType input_type, bool is_log);
969
Sang-Hoon Parkbb123bd2020-01-03 10:57:30 +0000970/** Returns resize ratio between input and output with consideration of aligned corners
971 *
972 * @param[in] input_size The input size
973 * @param[in] output_size the output size
974 * @param[in] align_corners True to align corners of input and output. Defaults to false.
975 *
976 * @return The ratio between input and output (i.e., the input size divided by the output size)
977 */
978float calculate_resize_ratio(size_t input_size, size_t output_size, bool align_corners = false);
979
Sang-Hoon Park4715cf92020-01-08 16:02:47 +0000980/** Returns a pair of minimum and maximum values for a quantized activation
981 *
982 * @param[in] act_info The information for activation
983 * @param[in] data_type The used data type
984 * @param[in] oq_info The output quantization information
985 *
986 * @return The pair with minimum and maximum values
987 */
988std::pair<int32_t, int32_t> get_quantized_activation_min_max(ActivationLayerInfo act_info, DataType data_type, UniformQuantizationInfo oq_info);
989
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100990/** Convert a tensor format into a string.
991 *
992 * @param[in] format @ref Format to be translated to string.
993 *
994 * @return The string describing the format.
995 */
996const std::string &string_from_format(Format format);
997
998/** Convert a channel identity into a string.
999 *
1000 * @param[in] channel @ref Channel to be translated to string.
1001 *
1002 * @return The string describing the channel.
1003 */
1004const std::string &string_from_channel(Channel channel);
Michele Di Giorgiobf3c6622018-03-08 11:52:27 +00001005/** Convert a data layout identity into a string.
1006 *
1007 * @param[in] dl @ref DataLayout to be translated to string.
1008 *
1009 * @return The string describing the data layout.
1010 */
1011const std::string &string_from_data_layout(DataLayout dl);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001012/** Convert a data type identity into a string.
1013 *
1014 * @param[in] dt @ref DataType to be translated to string.
1015 *
1016 * @return The string describing the data type.
1017 */
1018const std::string &string_from_data_type(DataType dt);
1019/** Convert a matrix pattern into a string.
1020 *
1021 * @param[in] pattern @ref MatrixPattern to be translated to string.
1022 *
1023 * @return The string describing the matrix pattern.
1024 */
1025const std::string &string_from_matrix_pattern(MatrixPattern pattern);
1026/** Translates a given activation function to a string.
1027 *
1028 * @param[in] act @ref ActivationLayerInfo::ActivationFunction to be translated to string.
1029 *
1030 * @return The string describing the activation function.
1031 */
1032const std::string &string_from_activation_func(ActivationLayerInfo::ActivationFunction act);
1033/** Translates a given non linear function to a string.
1034 *
1035 * @param[in] function @ref NonLinearFilterFunction to be translated to string.
1036 *
1037 * @return The string describing the non linear function.
1038 */
1039const std::string &string_from_non_linear_filter_function(NonLinearFilterFunction function);
1040/** Translates a given interpolation policy to a string.
1041 *
1042 * @param[in] policy @ref InterpolationPolicy to be translated to string.
1043 *
1044 * @return The string describing the interpolation policy.
1045 */
1046const std::string &string_from_interpolation_policy(InterpolationPolicy policy);
1047/** Translates a given border mode policy to a string.
1048 *
1049 * @param[in] border_mode @ref BorderMode to be translated to string.
1050 *
1051 * @return The string describing the border mode.
1052 */
1053const std::string &string_from_border_mode(BorderMode border_mode);
1054/** Translates a given normalization type to a string.
1055 *
1056 * @param[in] type @ref NormType to be translated to string.
1057 *
1058 * @return The string describing the normalization type.
1059 */
1060const std::string &string_from_norm_type(NormType type);
Georgios Pinitascdf51452017-08-31 14:21:36 +01001061/** Translates a given pooling type to a string.
1062 *
1063 * @param[in] type @ref PoolingType to be translated to string.
1064 *
1065 * @return The string describing the pooling type.
1066 */
1067const std::string &string_from_pooling_type(PoolingType type);
Gian Marco Iodice4b908652018-10-18 10:21:02 +01001068/** Translates a given GEMMLowp output stage to a string.
1069 *
1070 * @param[in] output_stage @ref GEMMLowpOutputStageInfo to be translated to string.
1071 *
1072 * @return The string describing the GEMMLowp output stage
1073 */
1074const std::string &string_from_gemmlowp_output_stage(GEMMLowpOutputStageType output_stage);
Giuseppe Rossinid7647d42018-07-17 18:13:13 +01001075/** Convert a PixelValue to a string, represented through the specific data type
1076 *
1077 * @param[in] value The PixelValue to convert
1078 * @param[in] data_type The type to be used to convert the @p value
1079 *
1080 * @return String representation of the PixelValue through the given data type.
1081 */
1082std::string string_from_pixel_value(const PixelValue &value, const DataType data_type);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001083/** Lower a given string.
1084 *
1085 * @param[in] val Given string to lower.
1086 *
1087 * @return The lowered string
1088 */
1089std::string lower_string(const std::string &val);
1090
1091/** Check if a given data type is of floating point type
1092 *
1093 * @param[in] dt Input data type.
1094 *
1095 * @return True if data type is of floating point type, else false.
1096 */
1097inline bool is_data_type_float(DataType dt)
1098{
1099 switch(dt)
1100 {
1101 case DataType::F16:
1102 case DataType::F32:
1103 return true;
1104 default:
1105 return false;
1106 }
1107}
1108
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001109/** Check if a given data type is of quantized type
1110 *
1111 * @note Quantized is considered a super-set of fixed-point and asymmetric data types.
1112 *
1113 * @param[in] dt Input data type.
1114 *
1115 * @return True if data type is of quantized type, else false.
1116 */
1117inline bool is_data_type_quantized(DataType dt)
1118{
1119 switch(dt)
1120 {
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001121 case DataType::QSYMM8:
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001122 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001123 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001124 case DataType::QSYMM8_PER_CHANNEL:
Manuel Bottini3689fcd2019-06-14 17:18:12 +01001125 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +01001126 case DataType::QASYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001127 return true;
1128 default:
1129 return false;
1130 }
1131}
1132
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001133/** Check if a given data type is of asymmetric quantized type
1134 *
1135 * @param[in] dt Input data type.
1136 *
Michele Di Giorgio6997fc92019-06-18 10:23:22 +01001137 * @return True if data type is of asymmetric quantized type, else false.
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001138 */
Anton Lokhmotovaf6204c2017-11-08 09:34:19 +00001139inline bool is_data_type_quantized_asymmetric(DataType dt)
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001140{
1141 switch(dt)
1142 {
1143 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001144 case DataType::QASYMM8_SIGNED:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +01001145 case DataType::QASYMM16:
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001146 return true;
1147 default:
1148 return false;
1149 }
1150}
1151
Georgios Pinitas6e1791b2019-12-02 19:01:25 +00001152/** Check if a given data type is of asymmetric quantized signed type
1153 *
1154 * @param[in] dt Input data type.
1155 *
1156 * @return True if data type is of asymmetric quantized signed type, else false.
1157 */
1158inline bool is_data_type_quantized_asymmetric_signed(DataType dt)
1159{
1160 switch(dt)
1161 {
1162 case DataType::QASYMM8_SIGNED:
1163 return true;
1164 default:
1165 return false;
1166 }
1167}
1168
Michele Di Giorgio6997fc92019-06-18 10:23:22 +01001169/** Check if a given data type is of symmetric quantized type
1170 *
1171 * @param[in] dt Input data type.
1172 *
1173 * @return True if data type is of symmetric quantized type, else false.
1174 */
1175inline bool is_data_type_quantized_symmetric(DataType dt)
1176{
1177 switch(dt)
1178 {
1179 case DataType::QSYMM8:
1180 case DataType::QSYMM8_PER_CHANNEL:
1181 case DataType::QSYMM16:
1182 return true;
1183 default:
1184 return false;
1185 }
1186}
1187
Michalis Spyrouc8530212019-08-22 11:44:04 +01001188/** Check if a given data type is of per channel type
1189 *
1190 * @param[in] dt Input data type.
1191 *
1192 * @return True if data type is of per channel type, else false.
1193 */
1194inline bool is_data_type_quantized_per_channel(DataType dt)
1195{
1196 switch(dt)
1197 {
1198 case DataType::QSYMM8_PER_CHANNEL:
Michalis Spyrouc8530212019-08-22 11:44:04 +01001199 return true;
1200 default:
1201 return false;
1202 }
1203}
1204
Georgios Pinitas89010962017-08-04 14:58:27 +01001205/** Create a string with the float in full precision.
1206 *
1207 * @param val Floating point value
1208 *
1209 * @return String with the floating point value.
1210 */
1211inline std::string float_to_string_with_full_precision(float val)
1212{
1213 std::stringstream ss;
Georgios Pinitas7900a9e2018-11-23 11:44:58 +00001214 ss.precision(std::numeric_limits<float>::max_digits10);
Georgios Pinitas89010962017-08-04 14:58:27 +01001215 ss << val;
Giorgio Arena73023022018-09-04 14:55:55 +01001216
1217 if(val != static_cast<int>(val))
1218 {
1219 ss << "f";
1220 }
1221
Georgios Pinitas89010962017-08-04 14:58:27 +01001222 return ss.str();
1223}
1224
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001225/** Returns the number of elements required to go from start to end with the wanted step
1226 *
1227 * @param[in] start start value
1228 * @param[in] end end value
1229 * @param[in] step step value between each number in the wanted sequence
1230 *
1231 * @return number of elements to go from start value to end value using the wanted step
1232 */
1233inline size_t num_of_elements_in_range(const float start, const float end, const float step)
1234{
1235 ARM_COMPUTE_ERROR_ON_MSG(step == 0, "Range Step cannot be 0");
1236 return size_t(std::ceil((end - start) / step));
1237}
1238
1239/** Returns true if the value can be represented by the given data type
1240 *
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001241 * @param[in] val value to be checked
1242 * @param[in] dt data type that is checked
1243 * @param[in] qinfo (Optional) quantization info if the data type is QASYMM8
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001244 *
1245 * @return true if the data type can hold the value.
1246 */
1247template <typename T>
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001248bool check_value_range(T val, DataType dt, QuantizationInfo qinfo = QuantizationInfo())
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001249{
1250 switch(dt)
1251 {
1252 case DataType::U8:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001253 {
1254 const auto val_u8 = static_cast<uint8_t>(val);
1255 return ((val_u8 == val) && val_u8 >= std::numeric_limits<uint8_t>::lowest() && val_u8 <= std::numeric_limits<uint8_t>::max());
1256 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001257 case DataType::QASYMM8:
1258 {
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001259 double min = static_cast<double>(dequantize_qasymm8(0, qinfo));
1260 double max = static_cast<double>(dequantize_qasymm8(std::numeric_limits<uint8_t>::max(), qinfo));
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001261 return ((double)val >= min && (double)val <= max);
1262 }
1263 case DataType::S8:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001264 {
1265 const auto val_s8 = static_cast<int8_t>(val);
1266 return ((val_s8 == val) && val_s8 >= std::numeric_limits<int8_t>::lowest() && val_s8 <= std::numeric_limits<int8_t>::max());
1267 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001268 case DataType::U16:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001269 {
1270 const auto val_u16 = static_cast<uint16_t>(val);
1271 return ((val_u16 == val) && val_u16 >= std::numeric_limits<uint16_t>::lowest() && val_u16 <= std::numeric_limits<uint16_t>::max());
1272 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001273 case DataType::S16:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001274 {
1275 const auto val_s16 = static_cast<int16_t>(val);
1276 return ((val_s16 == val) && val_s16 >= std::numeric_limits<int16_t>::lowest() && val_s16 <= std::numeric_limits<int16_t>::max());
1277 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001278 case DataType::U32:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001279 {
1280 const auto val_u32 = static_cast<uint32_t>(val);
1281 return ((val_u32 == val) && val_u32 >= std::numeric_limits<uint32_t>::lowest() && val_u32 <= std::numeric_limits<uint32_t>::max());
1282 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001283 case DataType::S32:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001284 {
1285 const auto val_s32 = static_cast<int32_t>(val);
1286 return ((val_s32 == val) && val_s32 >= std::numeric_limits<int32_t>::lowest() && val_s32 <= std::numeric_limits<int32_t>::max());
1287 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001288 case DataType::F16:
1289 return (val >= std::numeric_limits<half>::lowest() && val <= std::numeric_limits<half>::max());
1290 case DataType::F32:
1291 return (val >= std::numeric_limits<float>::lowest() && val <= std::numeric_limits<float>::max());
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001292 default:
1293 ARM_COMPUTE_ERROR("Data type not supported");
1294 return false;
1295 }
1296}
1297
giuros01edc21e42018-11-16 14:45:31 +00001298#ifdef ARM_COMPUTE_ASSERTS_ENABLED
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001299/** Print consecutive elements to an output stream.
1300 *
1301 * @param[out] s Output stream to print the elements to.
1302 * @param[in] ptr Pointer to print the elements from.
1303 * @param[in] n Number of elements to print.
1304 * @param[in] stream_width (Optional) Width of the stream. If set to 0 the element's width is used. Defaults to 0.
1305 * @param[in] element_delim (Optional) Delimeter among the consecutive elements. Defaults to space delimeter
1306 */
1307template <typename T>
1308void print_consecutive_elements_impl(std::ostream &s, const T *ptr, unsigned int n, int stream_width = 0, const std::string &element_delim = " ")
1309{
1310 using print_type = typename std::conditional<std::is_floating_point<T>::value, T, int>::type;
Michalis Spyrou53860dd2019-07-01 14:20:56 +01001311 std::ios stream_status(nullptr);
1312 stream_status.copyfmt(s);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001313
1314 for(unsigned int i = 0; i < n; ++i)
1315 {
1316 // Set stream width as it is not a "sticky" stream manipulator
1317 if(stream_width != 0)
1318 {
1319 s.width(stream_width);
1320 }
Anthony Barbier7068f992017-10-26 15:23:08 +01001321
1322 if(std::is_same<typename std::decay<T>::type, half>::value)
1323 {
1324 // We use T instead of print_type here is because the std::is_floating_point<half> returns false and then the print_type becomes int.
1325 s << std::right << static_cast<T>(ptr[i]) << element_delim;
1326 }
1327 else
1328 {
1329 s << std::right << static_cast<print_type>(ptr[i]) << element_delim;
1330 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001331 }
Michalis Spyrou53860dd2019-07-01 14:20:56 +01001332
1333 // Restore output stream flags
1334 s.copyfmt(stream_status);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001335}
1336
1337/** Identify the maximum width of n consecutive elements.
1338 *
1339 * @param[in] s The output stream which will be used to print the elements. Used to extract the stream format.
1340 * @param[in] ptr Pointer to the elements.
1341 * @param[in] n Number of elements.
1342 *
1343 * @return The maximum width of the elements.
1344 */
1345template <typename T>
1346int max_consecutive_elements_display_width_impl(std::ostream &s, const T *ptr, unsigned int n)
1347{
1348 using print_type = typename std::conditional<std::is_floating_point<T>::value, T, int>::type;
1349
1350 int max_width = -1;
1351 for(unsigned int i = 0; i < n; ++i)
1352 {
1353 std::stringstream ss;
1354 ss.copyfmt(s);
Anthony Barbier7068f992017-10-26 15:23:08 +01001355
1356 if(std::is_same<typename std::decay<T>::type, half>::value)
1357 {
1358 // We use T instead of print_type here is because the std::is_floating_point<half> returns false and then the print_type becomes int.
1359 ss << static_cast<T>(ptr[i]);
1360 }
1361 else
1362 {
1363 ss << static_cast<print_type>(ptr[i]);
1364 }
1365
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001366 max_width = std::max<int>(max_width, ss.str().size());
1367 }
1368 return max_width;
1369}
1370
1371/** Print consecutive elements to an output stream.
1372 *
1373 * @param[out] s Output stream to print the elements to.
1374 * @param[in] dt Data type of the elements
1375 * @param[in] ptr Pointer to print the elements from.
1376 * @param[in] n Number of elements to print.
1377 * @param[in] stream_width (Optional) Width of the stream. If set to 0 the element's width is used. Defaults to 0.
1378 * @param[in] element_delim (Optional) Delimeter among the consecutive elements. Defaults to space delimeter
1379 */
1380void print_consecutive_elements(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n, int stream_width, const std::string &element_delim = " ");
1381
1382/** Identify the maximum width of n consecutive elements.
1383 *
1384 * @param[in] s Output stream to print the elements to.
1385 * @param[in] dt Data type of the elements
1386 * @param[in] ptr Pointer to print the elements from.
1387 * @param[in] n Number of elements to print.
1388 *
1389 * @return The maximum width of the elements.
1390 */
1391int max_consecutive_elements_display_width(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n);
giuros01edc21e42018-11-16 14:45:31 +00001392#endif /* ARM_COMPUTE_ASSERTS_ENABLED */
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001393}
Michalis Spyrouf4643372019-11-29 16:17:13 +00001394#endif /*ARM_COMPUTE_UTILS_H */