blob: 4a3b01d21f1051f76088cca6235f1625f1651431 [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"
Georgios Pinitas51545e42020-02-11 15:29:01 +000031#include "arm_compute/core/Version.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010032
33#include <algorithm>
34#include <cstdint>
35#include <cstdlib>
Michalis Spyrou53860dd2019-07-01 14:20:56 +010036#include <iomanip>
Anthony Barbier6ff3b192017-09-04 18:44:23 +010037#include <numeric>
38#include <sstream>
39#include <string>
40#include <type_traits>
41#include <utility>
steniu017ce53c62017-09-29 14:55:00 +010042#include <vector>
Anthony Barbier6ff3b192017-09-04 18:44:23 +010043
44namespace arm_compute
45{
Alex Gildayc357c472018-03-21 13:54:09 +000046/** Calculate the rounded up quotient of val / m.
47 *
48 * @param[in] val Value to divide and round up.
49 * @param[in] m Value to divide by.
50 *
51 * @return the result.
52 */
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +000053template <typename S, typename T>
54constexpr auto DIV_CEIL(S val, T m) -> decltype((val + m - 1) / m)
55{
56 return (val + m - 1) / m;
57}
58
Alex Gildayc357c472018-03-21 13:54:09 +000059/** Computes the smallest number larger or equal to value that is a multiple of divisor.
60 *
61 * @param[in] value Lower bound value
62 * @param[in] divisor Value to compute multiple of.
63 *
64 * @return the result.
65 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010066template <typename S, typename T>
67inline auto ceil_to_multiple(S value, T divisor) -> decltype(((value + divisor - 1) / divisor) * divisor)
68{
69 ARM_COMPUTE_ERROR_ON(value < 0 || divisor <= 0);
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +000070 return DIV_CEIL(value, divisor) * divisor;
Anthony Barbier6ff3b192017-09-04 18:44:23 +010071}
72
Alex Gildayc357c472018-03-21 13:54:09 +000073/** Computes the largest number smaller or equal to value that is a multiple of divisor.
74 *
75 * @param[in] value Upper bound value
76 * @param[in] divisor Value to compute multiple of.
77 *
78 * @return the result.
79 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010080template <typename S, typename T>
81inline auto floor_to_multiple(S value, T divisor) -> decltype((value / divisor) * divisor)
82{
83 ARM_COMPUTE_ERROR_ON(value < 0 || divisor <= 0);
84 return (value / divisor) * divisor;
85}
86
Anthony Barbier6ff3b192017-09-04 18:44:23 +010087/** Load an entire file in memory
88 *
89 * @param[in] filename Name of the file to read.
90 * @param[in] binary Is it a binary file ?
91 *
92 * @return The content of the file.
93 */
94std::string read_file(const std::string &filename, bool binary);
95
Anthony Barbier6ff3b192017-09-04 18:44:23 +010096/** The size in bytes of the data type
97 *
98 * @param[in] data_type Input data type
99 *
100 * @return The size in bytes of the data type
101 */
102inline size_t data_size_from_type(DataType data_type)
103{
104 switch(data_type)
105 {
106 case DataType::U8:
107 case DataType::S8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100108 case DataType::QSYMM8:
Michel Iwaniec00633802017-10-12 14:14:15 +0100109 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100110 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100111 case DataType::QSYMM8_PER_CHANNEL:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100112 return 1;
113 case DataType::U16:
114 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100115 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100116 case DataType::QASYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100117 case DataType::F16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100118 return 2;
119 case DataType::F32:
120 case DataType::U32:
121 case DataType::S32:
122 return 4;
123 case DataType::F64:
124 case DataType::U64:
125 case DataType::S64:
126 return 8;
127 case DataType::SIZET:
128 return sizeof(size_t);
129 default:
130 ARM_COMPUTE_ERROR("Invalid data type");
131 return 0;
132 }
133}
134
135/** The size in bytes of the pixel format
136 *
137 * @param[in] format Input format
138 *
139 * @return The size in bytes of the pixel format
140 */
141inline size_t pixel_size_from_format(Format format)
142{
143 switch(format)
144 {
145 case Format::U8:
146 return 1;
147 case Format::U16:
148 case Format::S16:
149 case Format::F16:
150 case Format::UV88:
151 case Format::YUYV422:
152 case Format::UYVY422:
153 return 2;
154 case Format::RGB888:
155 return 3;
156 case Format::RGBA8888:
157 return 4;
158 case Format::U32:
159 case Format::S32:
160 case Format::F32:
161 return 4;
162 //Doesn't make sense for planar formats:
163 case Format::NV12:
164 case Format::NV21:
165 case Format::IYUV:
166 case Format::YUV444:
167 default:
168 ARM_COMPUTE_ERROR("Undefined pixel size for given format");
169 return 0;
170 }
171}
172
173/** The size in bytes of the data type
174 *
175 * @param[in] dt Input data type
176 *
177 * @return The size in bytes of the data type
178 */
179inline size_t element_size_from_data_type(DataType dt)
180{
181 switch(dt)
182 {
183 case DataType::S8:
184 case DataType::U8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100185 case DataType::QSYMM8:
Michel Iwaniec00633802017-10-12 14:14:15 +0100186 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100187 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100188 case DataType::QSYMM8_PER_CHANNEL:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100189 return 1;
190 case DataType::U16:
191 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100192 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100193 case DataType::QASYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100194 case DataType::F16:
195 return 2;
196 case DataType::U32:
197 case DataType::S32:
198 case DataType::F32:
199 return 4;
200 default:
201 ARM_COMPUTE_ERROR("Undefined element size for given data type");
202 return 0;
203 }
204}
205
206/** Return the data type used by a given single-planar pixel format
207 *
208 * @param[in] format Input format
209 *
210 * @return The size in bytes of the pixel format
211 */
212inline DataType data_type_from_format(Format format)
213{
214 switch(format)
215 {
216 case Format::U8:
217 case Format::UV88:
218 case Format::RGB888:
219 case Format::RGBA8888:
220 case Format::YUYV422:
221 case Format::UYVY422:
222 return DataType::U8;
223 case Format::U16:
224 return DataType::U16;
225 case Format::S16:
226 return DataType::S16;
227 case Format::U32:
228 return DataType::U32;
229 case Format::S32:
230 return DataType::S32;
231 case Format::F16:
232 return DataType::F16;
233 case Format::F32:
234 return DataType::F32;
235 //Doesn't make sense for planar formats:
236 case Format::NV12:
237 case Format::NV21:
238 case Format::IYUV:
239 case Format::YUV444:
240 default:
241 ARM_COMPUTE_ERROR("Not supported data_type for given format");
242 return DataType::UNKNOWN;
243 }
244}
245
246/** Return the plane index of a given channel given an input format.
247 *
248 * @param[in] format Input format
249 * @param[in] channel Input channel
250 *
251 * @return The plane index of the specific channel of the specific format
252 */
253inline int plane_idx_from_channel(Format format, Channel channel)
254{
255 switch(format)
256 {
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100257 // Single planar formats have a single plane
258 case Format::U8:
259 case Format::U16:
260 case Format::S16:
261 case Format::U32:
262 case Format::S32:
263 case Format::F16:
264 case Format::F32:
265 case Format::UV88:
266 case Format::RGB888:
267 case Format::RGBA8888:
268 case Format::YUYV422:
269 case Format::UYVY422:
270 return 0;
271 // Multi planar formats
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100272 case Format::NV12:
273 case Format::NV21:
274 {
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100275 // Channel U and V share the same plane of format UV88
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100276 switch(channel)
277 {
278 case Channel::Y:
279 return 0;
280 case Channel::U:
281 case Channel::V:
282 return 1;
283 default:
284 ARM_COMPUTE_ERROR("Not supported channel");
285 return 0;
286 }
287 }
288 case Format::IYUV:
289 case Format::YUV444:
290 {
291 switch(channel)
292 {
293 case Channel::Y:
294 return 0;
295 case Channel::U:
296 return 1;
297 case Channel::V:
298 return 2;
299 default:
300 ARM_COMPUTE_ERROR("Not supported channel");
301 return 0;
302 }
303 }
304 default:
305 ARM_COMPUTE_ERROR("Not supported format");
306 return 0;
307 }
308}
309
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100310/** Return the channel index of a given channel given an input format.
311 *
312 * @param[in] format Input format
313 * @param[in] channel Input channel
314 *
315 * @return The channel index of the specific channel of the specific format
316 */
317inline int channel_idx_from_format(Format format, Channel channel)
318{
319 switch(format)
320 {
321 case Format::RGB888:
322 {
323 switch(channel)
324 {
325 case Channel::R:
326 return 0;
327 case Channel::G:
328 return 1;
329 case Channel::B:
330 return 2;
331 default:
332 ARM_COMPUTE_ERROR("Not supported channel");
333 return 0;
334 }
335 }
336 case Format::RGBA8888:
337 {
338 switch(channel)
339 {
340 case Channel::R:
341 return 0;
342 case Channel::G:
343 return 1;
344 case Channel::B:
345 return 2;
346 case Channel::A:
347 return 3;
348 default:
349 ARM_COMPUTE_ERROR("Not supported channel");
350 return 0;
351 }
352 }
353 case Format::YUYV422:
354 {
355 switch(channel)
356 {
357 case Channel::Y:
358 return 0;
359 case Channel::U:
360 return 1;
361 case Channel::V:
362 return 3;
363 default:
364 ARM_COMPUTE_ERROR("Not supported channel");
365 return 0;
366 }
367 }
368 case Format::UYVY422:
369 {
370 switch(channel)
371 {
372 case Channel::Y:
373 return 1;
374 case Channel::U:
375 return 0;
376 case Channel::V:
377 return 2;
378 default:
379 ARM_COMPUTE_ERROR("Not supported channel");
380 return 0;
381 }
382 }
383 case Format::NV12:
384 {
385 switch(channel)
386 {
387 case Channel::Y:
388 return 0;
389 case Channel::U:
390 return 0;
391 case Channel::V:
392 return 1;
393 default:
394 ARM_COMPUTE_ERROR("Not supported channel");
395 return 0;
396 }
397 }
398 case Format::NV21:
399 {
400 switch(channel)
401 {
402 case Channel::Y:
403 return 0;
404 case Channel::U:
405 return 1;
406 case Channel::V:
407 return 0;
408 default:
409 ARM_COMPUTE_ERROR("Not supported channel");
410 return 0;
411 }
412 }
413 case Format::YUV444:
414 case Format::IYUV:
415 {
416 switch(channel)
417 {
418 case Channel::Y:
419 return 0;
420 case Channel::U:
421 return 0;
422 case Channel::V:
423 return 0;
424 default:
425 ARM_COMPUTE_ERROR("Not supported channel");
426 return 0;
427 }
428 }
429 default:
430 ARM_COMPUTE_ERROR("Not supported format");
431 return 0;
432 }
433}
434
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100435/** Return the number of planes for a given format
436 *
437 * @param[in] format Input format
438 *
439 * @return The number of planes for a given image format.
440 */
441inline size_t num_planes_from_format(Format format)
442{
443 switch(format)
444 {
445 case Format::U8:
446 case Format::S16:
447 case Format::U16:
448 case Format::S32:
449 case Format::U32:
450 case Format::F16:
451 case Format::F32:
452 case Format::RGB888:
453 case Format::RGBA8888:
454 case Format::YUYV422:
455 case Format::UYVY422:
456 return 1;
457 case Format::NV12:
458 case Format::NV21:
459 return 2;
460 case Format::IYUV:
461 case Format::YUV444:
462 return 3;
463 default:
464 ARM_COMPUTE_ERROR("Not supported format");
465 return 0;
466 }
467}
468
469/** Return the number of channels for a given single-planar pixel format
470 *
471 * @param[in] format Input format
472 *
473 * @return The number of channels for a given image format.
474 */
475inline size_t num_channels_from_format(Format format)
476{
477 switch(format)
478 {
479 case Format::U8:
480 case Format::U16:
481 case Format::S16:
482 case Format::U32:
483 case Format::S32:
484 case Format::F16:
485 case Format::F32:
486 return 1;
487 // Because the U and V channels are subsampled
488 // these formats appear like having only 2 channels:
489 case Format::YUYV422:
490 case Format::UYVY422:
491 return 2;
492 case Format::UV88:
493 return 2;
494 case Format::RGB888:
495 return 3;
496 case Format::RGBA8888:
497 return 4;
498 //Doesn't make sense for planar formats:
499 case Format::NV12:
500 case Format::NV21:
501 case Format::IYUV:
502 case Format::YUV444:
503 default:
504 return 0;
505 }
506}
507
Chunosovd621bca2017-11-03 17:33:15 +0700508/** Return the promoted data type of a given data type.
509 *
510 * @note If promoted data type is not supported an error will be thrown
511 *
512 * @param[in] dt Data type to get the promoted type of.
513 *
514 * @return Promoted data type
515 */
516inline DataType get_promoted_data_type(DataType dt)
517{
518 switch(dt)
519 {
520 case DataType::U8:
521 return DataType::U16;
522 case DataType::S8:
523 return DataType::S16;
Chunosovd621bca2017-11-03 17:33:15 +0700524 case DataType::U16:
525 return DataType::U32;
526 case DataType::S16:
527 return DataType::S32;
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100528 case DataType::QSYMM8:
Chunosovd621bca2017-11-03 17:33:15 +0700529 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100530 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100531 case DataType::QSYMM8_PER_CHANNEL:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100532 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100533 case DataType::QASYMM16:
Chunosovd621bca2017-11-03 17:33:15 +0700534 case DataType::F16:
535 case DataType::U32:
536 case DataType::S32:
537 case DataType::F32:
Chunosovd621bca2017-11-03 17:33:15 +0700538 ARM_COMPUTE_ERROR("Unsupported data type promotions!");
539 default:
540 ARM_COMPUTE_ERROR("Undefined data type!");
541 }
542 return DataType::UNKNOWN;
543}
544
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000545/** Compute the mininum and maximum values a data type can take
546 *
547 * @param[in] dt Data type to get the min/max bounds of
548 *
549 * @return A tuple (min,max) with the minimum and maximum values respectively wrapped in PixelValue.
550 */
551inline std::tuple<PixelValue, PixelValue> get_min_max(DataType dt)
552{
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000553 PixelValue min{};
554 PixelValue max{};
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000555 switch(dt)
556 {
557 case DataType::U8:
558 case DataType::QASYMM8:
559 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000560 min = PixelValue(static_cast<int32_t>(std::numeric_limits<uint8_t>::lowest()));
561 max = PixelValue(static_cast<int32_t>(std::numeric_limits<uint8_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000562 break;
563 }
564 case DataType::S8:
565 case DataType::QSYMM8:
566 case DataType::QASYMM8_SIGNED:
567 case DataType::QSYMM8_PER_CHANNEL:
568 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000569 min = PixelValue(static_cast<int32_t>(std::numeric_limits<int8_t>::lowest()));
570 max = PixelValue(static_cast<int32_t>(std::numeric_limits<int8_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000571 break;
572 }
573 case DataType::U16:
574 case DataType::QASYMM16:
575 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000576 min = PixelValue(static_cast<int32_t>(std::numeric_limits<uint16_t>::lowest()));
577 max = PixelValue(static_cast<int32_t>(std::numeric_limits<uint16_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000578 break;
579 }
580 case DataType::S16:
581 case DataType::QSYMM16:
582 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000583 min = PixelValue(static_cast<int32_t>(std::numeric_limits<int16_t>::lowest()));
584 max = PixelValue(static_cast<int32_t>(std::numeric_limits<int16_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000585 break;
586 }
587 case DataType::U32:
588 {
589 min = PixelValue(std::numeric_limits<uint32_t>::lowest());
590 max = PixelValue(std::numeric_limits<uint32_t>::max());
591 break;
592 }
593 case DataType::S32:
594 {
595 min = PixelValue(std::numeric_limits<int32_t>::lowest());
596 max = PixelValue(std::numeric_limits<int32_t>::max());
597 break;
598 }
Luca Foschianiee939fb2020-01-28 10:38:07 +0000599 case DataType::F16:
600 {
601 min = PixelValue(std::numeric_limits<half>::lowest());
602 max = PixelValue(std::numeric_limits<half>::max());
603 break;
604 }
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000605 case DataType::F32:
606 {
607 min = PixelValue(std::numeric_limits<float>::lowest());
608 max = PixelValue(std::numeric_limits<float>::max());
609 break;
610 }
611 default:
612 ARM_COMPUTE_ERROR("Undefined data type!");
613 }
614 return std::make_tuple(min, max);
615}
616
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100617/** Return true if the given format has horizontal subsampling.
618 *
619 * @param[in] format Format to determine subsampling.
620 *
621 * @return True if the format can be subsampled horizontaly.
622 */
623inline bool has_format_horizontal_subsampling(Format format)
624{
625 return (format == Format::YUYV422 || format == Format::UYVY422 || format == Format::NV12 || format == Format::NV21 || format == Format::IYUV || format == Format::UV88) ? true : false;
626}
627
628/** Return true if the given format has vertical subsampling.
629 *
630 * @param[in] format Format to determine subsampling.
631 *
632 * @return True if the format can be subsampled verticaly.
633 */
634inline bool has_format_vertical_subsampling(Format format)
635{
636 return (format == Format::NV12 || format == Format::NV21 || format == Format::IYUV || format == Format::UV88) ? true : false;
637}
638
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100639/** Separate a 2D convolution into two 1D convolutions
Anthony Barbierf202e502017-11-23 18:02:04 +0000640 *
641 * @param[in] conv 2D convolution
642 * @param[out] conv_col 1D vertical convolution
643 * @param[out] conv_row 1D horizontal convolution
644 * @param[in] size Size of the 2D convolution
645 *
646 * @return true if the separation was successful
647 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100648inline bool separate_matrix(const int16_t *conv, int16_t *conv_col, int16_t *conv_row, uint8_t size)
649{
650 int32_t min_col = -1;
651 int16_t min_col_val = -1;
652
653 for(int32_t i = 0; i < size; ++i)
654 {
655 if(conv[i] != 0 && (min_col < 0 || abs(min_col_val) > abs(conv[i])))
656 {
657 min_col = i;
658 min_col_val = conv[i];
659 }
660 }
661
662 if(min_col < 0)
663 {
664 return false;
665 }
666
667 for(uint32_t j = 0; j < size; ++j)
668 {
669 conv_col[j] = conv[min_col + j * size];
670 }
671
672 for(uint32_t i = 0; i < size; i++)
673 {
674 if(static_cast<int>(i) == min_col)
675 {
676 conv_row[i] = 1;
677 }
678 else
679 {
680 int16_t coeff = conv[i] / conv[min_col];
681
682 for(uint32_t j = 1; j < size; ++j)
683 {
684 if(conv[i + j * size] != (conv_col[j] * coeff))
685 {
686 return false;
687 }
688 }
689
690 conv_row[i] = coeff;
691 }
692 }
693
694 return true;
695}
696
697/** Calculate the scale of the given square matrix
698 *
699 * The scale is the absolute value of the sum of all the coefficients in the matrix.
700 *
701 * @note If the coefficients add up to 0 then the scale is set to 1.
702 *
703 * @param[in] matrix Matrix coefficients
704 * @param[in] matrix_size Number of elements per side of the square matrix. (Number of coefficients = matrix_size * matrix_size).
705 *
706 * @return The absolute value of the sum of the coefficients if they don't add up to 0, otherwise 1.
707 */
708inline uint32_t calculate_matrix_scale(const int16_t *matrix, unsigned int matrix_size)
709{
710 const size_t size = matrix_size * matrix_size;
711
712 return std::max(1, std::abs(std::accumulate(matrix, matrix + size, 0)));
713}
714
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100715/** Adjust tensor shape size if width or height are odd for a given multi-planar format. No modification is done for other formats.
716 *
717 * @note Adding here a few links discussing the issue of odd size and sharing the same solution:
Manuel Bottini581c8982019-02-07 10:31:57 +0000718 * <a href="https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/graphics/java/android/graphics/YuvImage.java">Android Source</a>
719 * <a href="https://groups.google.com/a/webmproject.org/forum/#!topic/webm-discuss/LaCKpqiDTXM">WebM</a>
720 * <a href="https://bugs.chromium.org/p/libyuv/issues/detail?id=198&amp;can=1&amp;q=odd%20width">libYUV</a>
721 * <a href="https://sourceforge.net/p/raw-yuvplayer/bugs/1/">YUVPlayer</a> *
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100722 *
723 * @param[in, out] shape Tensor shape of 2D size
724 * @param[in] format Format of the tensor
725 *
Alex Gildayc357c472018-03-21 13:54:09 +0000726 * @return The adjusted tensor shape.
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100727 */
728inline TensorShape adjust_odd_shape(const TensorShape &shape, Format format)
729{
730 TensorShape output{ shape };
731
732 // Force width to be even for formats which require subsampling of the U and V channels
733 if(has_format_horizontal_subsampling(format))
734 {
735 output.set(0, output.x() & ~1U);
736 }
737
738 // Force height to be even for formats which require subsampling of the U and V channels
739 if(has_format_vertical_subsampling(format))
740 {
741 output.set(1, output.y() & ~1U);
742 }
743
744 return output;
745}
746
747/** Calculate subsampled shape for a given format and channel
748 *
749 * @param[in] shape Shape of the tensor to calculate the extracted channel.
750 * @param[in] format Format of the tensor.
751 * @param[in] channel Channel to create tensor shape to be extracted.
752 *
753 * @return The subsampled tensor shape.
754 */
755inline TensorShape calculate_subsampled_shape(const TensorShape &shape, Format format, Channel channel = Channel::UNKNOWN)
756{
757 TensorShape output{ shape };
758
759 // Subsample shape only for U or V channel
760 if(Channel::U == channel || Channel::V == channel || Channel::UNKNOWN == channel)
761 {
762 // Subsample width for the tensor shape when channel is U or V
763 if(has_format_horizontal_subsampling(format))
764 {
765 output.set(0, output.x() / 2U);
766 }
767
768 // Subsample height for the tensor shape when channel is U or V
769 if(has_format_vertical_subsampling(format))
770 {
771 output.set(1, output.y() / 2U);
772 }
773 }
774
775 return output;
776}
777
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100778/** Calculate accurary required by the horizontal and vertical convolution computations
779 *
780 * @param[in] conv_col Pointer to the vertical vector of the separated convolution filter
781 * @param[in] conv_row Pointer to the horizontal vector of the convolution filter
782 * @param[in] size Number of elements per vector of the separated matrix
783 *
784 * @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
785 * element of the pair is the biggest data type needed for the second stage.
786 */
787inline std::pair<DataType, DataType> data_type_for_convolution(const int16_t *conv_col, const int16_t *conv_row, size_t size)
788{
789 DataType first_stage = DataType::UNKNOWN;
790 DataType second_stage = DataType::UNKNOWN;
791
792 auto gez = [](const int16_t &v)
793 {
794 return v >= 0;
795 };
796
797 auto accu_neg = [](const int &first, const int &second)
798 {
799 return first + (second < 0 ? second : 0);
800 };
801
802 auto accu_pos = [](const int &first, const int &second)
803 {
804 return first + (second > 0 ? second : 0);
805 };
806
807 const bool only_positive_coefficients = std::all_of(conv_row, conv_row + size, gez) && std::all_of(conv_col, conv_col + size, gez);
808
809 if(only_positive_coefficients)
810 {
811 const int max_row_value = std::accumulate(conv_row, conv_row + size, 0) * UINT8_MAX;
812 const int max_value = std::accumulate(conv_col, conv_col + size, 0) * max_row_value;
813
814 first_stage = (max_row_value <= UINT16_MAX) ? DataType::U16 : DataType::S32;
815
816 second_stage = (max_value <= UINT16_MAX) ? DataType::U16 : DataType::S32;
817 }
818 else
819 {
820 const int min_row_value = std::accumulate(conv_row, conv_row + size, 0, accu_neg) * UINT8_MAX;
821 const int max_row_value = std::accumulate(conv_row, conv_row + size, 0, accu_pos) * UINT8_MAX;
822 const int neg_coeffs_sum = std::accumulate(conv_col, conv_col + size, 0, accu_neg);
823 const int pos_coeffs_sum = std::accumulate(conv_col, conv_col + size, 0, accu_pos);
824 const int min_value = neg_coeffs_sum * max_row_value + pos_coeffs_sum * min_row_value;
825 const int max_value = neg_coeffs_sum * min_row_value + pos_coeffs_sum * max_row_value;
826
827 first_stage = ((INT16_MIN <= min_row_value) && (max_row_value <= INT16_MAX)) ? DataType::S16 : DataType::S32;
828
829 second_stage = ((INT16_MIN <= min_value) && (max_value <= INT16_MAX)) ? DataType::S16 : DataType::S32;
830 }
831
832 return std::make_pair(first_stage, second_stage);
833}
834
835/** Calculate the accuracy required by the squared convolution calculation.
836 *
837 *
838 * @param[in] conv Pointer to the squared convolution matrix
839 * @param[in] size The total size of the convolution matrix
840 *
841 * @return The return is the biggest data type needed to do the convolution
842 */
843inline DataType data_type_for_convolution_matrix(const int16_t *conv, size_t size)
844{
845 auto gez = [](const int16_t v)
846 {
847 return v >= 0;
848 };
849
850 const bool only_positive_coefficients = std::all_of(conv, conv + size, gez);
851
852 if(only_positive_coefficients)
853 {
854 const int max_conv_value = std::accumulate(conv, conv + size, 0) * UINT8_MAX;
855 if(max_conv_value <= UINT16_MAX)
856 {
857 return DataType::U16;
858 }
859 else
860 {
861 return DataType::S32;
862 }
863 }
864 else
865 {
866 const int min_value = std::accumulate(conv, conv + size, 0, [](int a, int b)
867 {
868 return b < 0 ? a + b : a;
869 })
870 * UINT8_MAX;
871
872 const int max_value = std::accumulate(conv, conv + size, 0, [](int a, int b)
873 {
874 return b > 0 ? a + b : a;
875 })
876 * UINT8_MAX;
877
878 if((INT16_MIN <= min_value) && (INT16_MAX >= max_value))
879 {
880 return DataType::S16;
881 }
882 else
883 {
884 return DataType::S32;
885 }
886 }
887}
888
Pablo Tello35767bc2018-12-05 17:36:30 +0000889/** Permutes the given dimensions according the permutation vector
890 *
891 * @param[in,out] dimensions Dimensions to be permuted.
892 * @param[in] perm Vector describing the permutation.
893 *
894 */
895template <typename T>
896inline void permute_strides(Dimensions<T> &dimensions, const PermutationVector &perm)
897{
898 const auto old_dim = utility::make_array<Dimensions<T>::num_max_dimensions>(dimensions.begin(), dimensions.end());
899 for(unsigned int i = 0; i < perm.num_dimensions(); ++i)
900 {
901 T dimension_val = old_dim[i];
902 dimensions.set(perm[i], dimension_val);
903 }
904}
905
Georgios Pinitas4074c992018-01-30 18:13:46 +0000906/** Calculate padding requirements in case of SAME padding
907 *
908 * @param[in] input_shape Input shape
909 * @param[in] weights_shape Weights shape
910 * @param[in] conv_info Convolution information (containing strides)
Isabella Gottardi6a914402019-01-30 15:45:42 +0000911 * @param[in] data_layout (Optional) Data layout of the input and weights tensor
Pablo Tello01bbacb2019-04-30 10:32:42 +0100912 * @param[in] dilation (Optional) Dilation factor used in the convolution.
Giorgio Arena17203582019-08-02 16:00:41 +0100913 * @param[in] rounding_type (Optional) Dimension rounding type when down-scaling.
Georgios Pinitas4074c992018-01-30 18:13:46 +0000914 *
915 * @return PadStrideInfo for SAME padding
916 */
Giorgio Arena17203582019-08-02 16:00:41 +0100917PadStrideInfo calculate_same_pad(TensorShape input_shape, TensorShape weights_shape, PadStrideInfo conv_info, DataLayout data_layout = DataLayout::NCHW, const Size2D &dilation = Size2D(1u, 1u),
918 const DimensionRoundingType &rounding_type = DimensionRoundingType::FLOOR);
Georgios Pinitas4074c992018-01-30 18:13:46 +0000919
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100920/** Returns expected width and height of the deconvolution's output tensor.
921 *
Matthew Jacksonb9070a42019-08-22 16:13:27 +0100922 * @param[in] in_width Width of input tensor (Number of columns)
923 * @param[in] in_height Height of input tensor (Number of rows)
924 * @param[in] kernel_width Kernel width.
925 * @param[in] kernel_height Kernel height.
926 * @param[in] pad_stride_info Pad and stride information.
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100927 *
928 * @return A pair with the new width in the first position and the new height in the second.
929 */
Pablo Tello01bbacb2019-04-30 10:32:42 +0100930std::pair<unsigned int, unsigned int> deconvolution_output_dimensions(unsigned int in_width, unsigned int in_height,
931 unsigned int kernel_width, unsigned int kernel_height,
Matthew Jacksonb9070a42019-08-22 16:13:27 +0100932 const PadStrideInfo &pad_stride_info);
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100933
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100934/** Returns expected width and height of output scaled tensor depending on dimensions rounding mode.
935 *
Gian Marco Iodice4e288692017-06-27 11:41:59 +0100936 * @param[in] width Width of input tensor (Number of columns)
937 * @param[in] height Height of input tensor (Number of rows)
938 * @param[in] kernel_width Kernel width.
939 * @param[in] kernel_height Kernel height.
940 * @param[in] pad_stride_info Pad and stride information.
Alex Gilday7da29b62018-03-23 14:16:00 +0000941 * @param[in] dilation (Optional) Dilation, in elements, across x and y. Defaults to (1, 1).
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100942 *
943 * @return A pair with the new width in the first position and the new height in the second.
944 */
Georgios Pinitas80838f12019-12-12 18:23:13 +0000945std::pair<unsigned int, unsigned int> scaled_dimensions(int width, int height,
946 int kernel_width, int kernel_height,
Pablo Tello01bbacb2019-04-30 10:32:42 +0100947 const PadStrideInfo &pad_stride_info,
948 const Size2D &dilation = Size2D(1U, 1U));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100949
Sang-Hoon Park2697fd82019-10-15 16:49:24 +0100950/** Check if the given reduction operation should be handled in a serial way.
951 *
952 * @param[in] op Reduction operation to perform
953 * @param[in] dt Data type
954 * @param[in] axis Axis along which to reduce
955 *
956 * @return True if the given reduction operation should be handled in a serial way.
957 */
958bool needs_serialized_reduction(ReductionOperation op, DataType dt, unsigned int axis);
959
Sang-Hoon Park0779fec2019-11-13 17:08:12 +0000960/** Returns output quantization information for softmax layer
961 *
962 * @param[in] input_type The data type of the input tensor
963 * @param[in] is_log True for log softmax
964 *
965 * @return Quantization information for the output tensor
966 */
967QuantizationInfo get_softmax_output_quantization_info(DataType input_type, bool is_log);
968
Sang-Hoon Parkbb123bd2020-01-03 10:57:30 +0000969/** Returns resize ratio between input and output with consideration of aligned corners
970 *
971 * @param[in] input_size The input size
972 * @param[in] output_size the output size
973 * @param[in] align_corners True to align corners of input and output. Defaults to false.
974 *
975 * @return The ratio between input and output (i.e., the input size divided by the output size)
976 */
977float calculate_resize_ratio(size_t input_size, size_t output_size, bool align_corners = false);
978
Sang-Hoon Park4715cf92020-01-08 16:02:47 +0000979/** Returns a pair of minimum and maximum values for a quantized activation
980 *
981 * @param[in] act_info The information for activation
982 * @param[in] data_type The used data type
983 * @param[in] oq_info The output quantization information
984 *
985 * @return The pair with minimum and maximum values
986 */
987std::pair<int32_t, int32_t> get_quantized_activation_min_max(ActivationLayerInfo act_info, DataType data_type, UniformQuantizationInfo oq_info);
988
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100989/** Convert a tensor format into a string.
990 *
991 * @param[in] format @ref Format to be translated to string.
992 *
993 * @return The string describing the format.
994 */
995const std::string &string_from_format(Format format);
996
997/** Convert a channel identity into a string.
998 *
999 * @param[in] channel @ref Channel to be translated to string.
1000 *
1001 * @return The string describing the channel.
1002 */
1003const std::string &string_from_channel(Channel channel);
Michele Di Giorgiobf3c6622018-03-08 11:52:27 +00001004/** Convert a data layout identity into a string.
1005 *
1006 * @param[in] dl @ref DataLayout to be translated to string.
1007 *
1008 * @return The string describing the data layout.
1009 */
1010const std::string &string_from_data_layout(DataLayout dl);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001011/** Convert a data type identity into a string.
1012 *
1013 * @param[in] dt @ref DataType to be translated to string.
1014 *
1015 * @return The string describing the data type.
1016 */
1017const std::string &string_from_data_type(DataType dt);
1018/** Convert a matrix pattern into a string.
1019 *
1020 * @param[in] pattern @ref MatrixPattern to be translated to string.
1021 *
1022 * @return The string describing the matrix pattern.
1023 */
1024const std::string &string_from_matrix_pattern(MatrixPattern pattern);
1025/** Translates a given activation function to a string.
1026 *
1027 * @param[in] act @ref ActivationLayerInfo::ActivationFunction to be translated to string.
1028 *
1029 * @return The string describing the activation function.
1030 */
1031const std::string &string_from_activation_func(ActivationLayerInfo::ActivationFunction act);
1032/** Translates a given non linear function to a string.
1033 *
1034 * @param[in] function @ref NonLinearFilterFunction to be translated to string.
1035 *
1036 * @return The string describing the non linear function.
1037 */
1038const std::string &string_from_non_linear_filter_function(NonLinearFilterFunction function);
1039/** Translates a given interpolation policy to a string.
1040 *
1041 * @param[in] policy @ref InterpolationPolicy to be translated to string.
1042 *
1043 * @return The string describing the interpolation policy.
1044 */
1045const std::string &string_from_interpolation_policy(InterpolationPolicy policy);
1046/** Translates a given border mode policy to a string.
1047 *
1048 * @param[in] border_mode @ref BorderMode to be translated to string.
1049 *
1050 * @return The string describing the border mode.
1051 */
1052const std::string &string_from_border_mode(BorderMode border_mode);
1053/** Translates a given normalization type to a string.
1054 *
1055 * @param[in] type @ref NormType to be translated to string.
1056 *
1057 * @return The string describing the normalization type.
1058 */
1059const std::string &string_from_norm_type(NormType type);
Georgios Pinitascdf51452017-08-31 14:21:36 +01001060/** Translates a given pooling type to a string.
1061 *
1062 * @param[in] type @ref PoolingType to be translated to string.
1063 *
1064 * @return The string describing the pooling type.
1065 */
1066const std::string &string_from_pooling_type(PoolingType type);
Gian Marco Iodice4b908652018-10-18 10:21:02 +01001067/** Translates a given GEMMLowp output stage to a string.
1068 *
1069 * @param[in] output_stage @ref GEMMLowpOutputStageInfo to be translated to string.
1070 *
1071 * @return The string describing the GEMMLowp output stage
1072 */
1073const std::string &string_from_gemmlowp_output_stage(GEMMLowpOutputStageType output_stage);
Giuseppe Rossinid7647d42018-07-17 18:13:13 +01001074/** Convert a PixelValue to a string, represented through the specific data type
1075 *
1076 * @param[in] value The PixelValue to convert
1077 * @param[in] data_type The type to be used to convert the @p value
1078 *
1079 * @return String representation of the PixelValue through the given data type.
1080 */
1081std::string string_from_pixel_value(const PixelValue &value, const DataType data_type);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001082/** Lower a given string.
1083 *
1084 * @param[in] val Given string to lower.
1085 *
1086 * @return The lowered string
1087 */
1088std::string lower_string(const std::string &val);
1089
1090/** Check if a given data type is of floating point type
1091 *
1092 * @param[in] dt Input data type.
1093 *
1094 * @return True if data type is of floating point type, else false.
1095 */
1096inline bool is_data_type_float(DataType dt)
1097{
1098 switch(dt)
1099 {
1100 case DataType::F16:
1101 case DataType::F32:
1102 return true;
1103 default:
1104 return false;
1105 }
1106}
1107
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001108/** Check if a given data type is of quantized type
1109 *
1110 * @note Quantized is considered a super-set of fixed-point and asymmetric data types.
1111 *
1112 * @param[in] dt Input data type.
1113 *
1114 * @return True if data type is of quantized type, else false.
1115 */
1116inline bool is_data_type_quantized(DataType dt)
1117{
1118 switch(dt)
1119 {
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001120 case DataType::QSYMM8:
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001121 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001122 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001123 case DataType::QSYMM8_PER_CHANNEL:
Manuel Bottini3689fcd2019-06-14 17:18:12 +01001124 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +01001125 case DataType::QASYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001126 return true;
1127 default:
1128 return false;
1129 }
1130}
1131
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001132/** Check if a given data type is of asymmetric quantized type
1133 *
1134 * @param[in] dt Input data type.
1135 *
Michele Di Giorgio6997fc92019-06-18 10:23:22 +01001136 * @return True if data type is of asymmetric quantized type, else false.
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001137 */
Anton Lokhmotovaf6204c2017-11-08 09:34:19 +00001138inline bool is_data_type_quantized_asymmetric(DataType dt)
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001139{
1140 switch(dt)
1141 {
1142 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001143 case DataType::QASYMM8_SIGNED:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +01001144 case DataType::QASYMM16:
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001145 return true;
1146 default:
1147 return false;
1148 }
1149}
1150
Georgios Pinitas6e1791b2019-12-02 19:01:25 +00001151/** Check if a given data type is of asymmetric quantized signed type
1152 *
1153 * @param[in] dt Input data type.
1154 *
1155 * @return True if data type is of asymmetric quantized signed type, else false.
1156 */
1157inline bool is_data_type_quantized_asymmetric_signed(DataType dt)
1158{
1159 switch(dt)
1160 {
1161 case DataType::QASYMM8_SIGNED:
1162 return true;
1163 default:
1164 return false;
1165 }
1166}
1167
Michele Di Giorgio6997fc92019-06-18 10:23:22 +01001168/** Check if a given data type is of symmetric quantized type
1169 *
1170 * @param[in] dt Input data type.
1171 *
1172 * @return True if data type is of symmetric quantized type, else false.
1173 */
1174inline bool is_data_type_quantized_symmetric(DataType dt)
1175{
1176 switch(dt)
1177 {
1178 case DataType::QSYMM8:
1179 case DataType::QSYMM8_PER_CHANNEL:
1180 case DataType::QSYMM16:
1181 return true;
1182 default:
1183 return false;
1184 }
1185}
1186
Michalis Spyrouc8530212019-08-22 11:44:04 +01001187/** Check if a given data type is of per channel type
1188 *
1189 * @param[in] dt Input data type.
1190 *
1191 * @return True if data type is of per channel type, else false.
1192 */
1193inline bool is_data_type_quantized_per_channel(DataType dt)
1194{
1195 switch(dt)
1196 {
1197 case DataType::QSYMM8_PER_CHANNEL:
Michalis Spyrouc8530212019-08-22 11:44:04 +01001198 return true;
1199 default:
1200 return false;
1201 }
1202}
1203
Georgios Pinitas89010962017-08-04 14:58:27 +01001204/** Create a string with the float in full precision.
1205 *
1206 * @param val Floating point value
1207 *
1208 * @return String with the floating point value.
1209 */
1210inline std::string float_to_string_with_full_precision(float val)
1211{
1212 std::stringstream ss;
Georgios Pinitas7900a9e2018-11-23 11:44:58 +00001213 ss.precision(std::numeric_limits<float>::max_digits10);
Georgios Pinitas89010962017-08-04 14:58:27 +01001214 ss << val;
Giorgio Arena73023022018-09-04 14:55:55 +01001215
1216 if(val != static_cast<int>(val))
1217 {
1218 ss << "f";
1219 }
1220
Georgios Pinitas89010962017-08-04 14:58:27 +01001221 return ss.str();
1222}
1223
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001224/** Returns the number of elements required to go from start to end with the wanted step
1225 *
1226 * @param[in] start start value
1227 * @param[in] end end value
1228 * @param[in] step step value between each number in the wanted sequence
1229 *
1230 * @return number of elements to go from start value to end value using the wanted step
1231 */
1232inline size_t num_of_elements_in_range(const float start, const float end, const float step)
1233{
1234 ARM_COMPUTE_ERROR_ON_MSG(step == 0, "Range Step cannot be 0");
1235 return size_t(std::ceil((end - start) / step));
1236}
1237
1238/** Returns true if the value can be represented by the given data type
1239 *
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001240 * @param[in] val value to be checked
1241 * @param[in] dt data type that is checked
1242 * @param[in] qinfo (Optional) quantization info if the data type is QASYMM8
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001243 *
1244 * @return true if the data type can hold the value.
1245 */
1246template <typename T>
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001247bool check_value_range(T val, DataType dt, QuantizationInfo qinfo = QuantizationInfo())
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001248{
1249 switch(dt)
1250 {
1251 case DataType::U8:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001252 {
1253 const auto val_u8 = static_cast<uint8_t>(val);
1254 return ((val_u8 == val) && val_u8 >= std::numeric_limits<uint8_t>::lowest() && val_u8 <= std::numeric_limits<uint8_t>::max());
1255 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001256 case DataType::QASYMM8:
1257 {
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001258 double min = static_cast<double>(dequantize_qasymm8(0, qinfo));
1259 double max = static_cast<double>(dequantize_qasymm8(std::numeric_limits<uint8_t>::max(), qinfo));
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001260 return ((double)val >= min && (double)val <= max);
1261 }
1262 case DataType::S8:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001263 {
1264 const auto val_s8 = static_cast<int8_t>(val);
1265 return ((val_s8 == val) && val_s8 >= std::numeric_limits<int8_t>::lowest() && val_s8 <= std::numeric_limits<int8_t>::max());
1266 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001267 case DataType::U16:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001268 {
1269 const auto val_u16 = static_cast<uint16_t>(val);
1270 return ((val_u16 == val) && val_u16 >= std::numeric_limits<uint16_t>::lowest() && val_u16 <= std::numeric_limits<uint16_t>::max());
1271 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001272 case DataType::S16:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001273 {
1274 const auto val_s16 = static_cast<int16_t>(val);
1275 return ((val_s16 == val) && val_s16 >= std::numeric_limits<int16_t>::lowest() && val_s16 <= std::numeric_limits<int16_t>::max());
1276 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001277 case DataType::U32:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001278 {
1279 const auto val_u32 = static_cast<uint32_t>(val);
1280 return ((val_u32 == val) && val_u32 >= std::numeric_limits<uint32_t>::lowest() && val_u32 <= std::numeric_limits<uint32_t>::max());
1281 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001282 case DataType::S32:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001283 {
1284 const auto val_s32 = static_cast<int32_t>(val);
1285 return ((val_s32 == val) && val_s32 >= std::numeric_limits<int32_t>::lowest() && val_s32 <= std::numeric_limits<int32_t>::max());
1286 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001287 case DataType::F16:
1288 return (val >= std::numeric_limits<half>::lowest() && val <= std::numeric_limits<half>::max());
1289 case DataType::F32:
1290 return (val >= std::numeric_limits<float>::lowest() && val <= std::numeric_limits<float>::max());
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001291 default:
1292 ARM_COMPUTE_ERROR("Data type not supported");
1293 return false;
1294 }
1295}
1296
giuros01edc21e42018-11-16 14:45:31 +00001297#ifdef ARM_COMPUTE_ASSERTS_ENABLED
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001298/** Print consecutive elements to an output stream.
1299 *
1300 * @param[out] s Output stream to print the elements to.
1301 * @param[in] ptr Pointer to print the elements from.
1302 * @param[in] n Number of elements to print.
1303 * @param[in] stream_width (Optional) Width of the stream. If set to 0 the element's width is used. Defaults to 0.
1304 * @param[in] element_delim (Optional) Delimeter among the consecutive elements. Defaults to space delimeter
1305 */
1306template <typename T>
1307void print_consecutive_elements_impl(std::ostream &s, const T *ptr, unsigned int n, int stream_width = 0, const std::string &element_delim = " ")
1308{
1309 using print_type = typename std::conditional<std::is_floating_point<T>::value, T, int>::type;
Michalis Spyrou53860dd2019-07-01 14:20:56 +01001310 std::ios stream_status(nullptr);
1311 stream_status.copyfmt(s);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001312
1313 for(unsigned int i = 0; i < n; ++i)
1314 {
1315 // Set stream width as it is not a "sticky" stream manipulator
1316 if(stream_width != 0)
1317 {
1318 s.width(stream_width);
1319 }
Anthony Barbier7068f992017-10-26 15:23:08 +01001320
1321 if(std::is_same<typename std::decay<T>::type, half>::value)
1322 {
1323 // 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.
1324 s << std::right << static_cast<T>(ptr[i]) << element_delim;
1325 }
1326 else
1327 {
1328 s << std::right << static_cast<print_type>(ptr[i]) << element_delim;
1329 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001330 }
Michalis Spyrou53860dd2019-07-01 14:20:56 +01001331
1332 // Restore output stream flags
1333 s.copyfmt(stream_status);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001334}
1335
1336/** Identify the maximum width of n consecutive elements.
1337 *
1338 * @param[in] s The output stream which will be used to print the elements. Used to extract the stream format.
1339 * @param[in] ptr Pointer to the elements.
1340 * @param[in] n Number of elements.
1341 *
1342 * @return The maximum width of the elements.
1343 */
1344template <typename T>
1345int max_consecutive_elements_display_width_impl(std::ostream &s, const T *ptr, unsigned int n)
1346{
1347 using print_type = typename std::conditional<std::is_floating_point<T>::value, T, int>::type;
1348
1349 int max_width = -1;
1350 for(unsigned int i = 0; i < n; ++i)
1351 {
1352 std::stringstream ss;
1353 ss.copyfmt(s);
Anthony Barbier7068f992017-10-26 15:23:08 +01001354
1355 if(std::is_same<typename std::decay<T>::type, half>::value)
1356 {
1357 // 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.
1358 ss << static_cast<T>(ptr[i]);
1359 }
1360 else
1361 {
1362 ss << static_cast<print_type>(ptr[i]);
1363 }
1364
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001365 max_width = std::max<int>(max_width, ss.str().size());
1366 }
1367 return max_width;
1368}
1369
1370/** Print consecutive elements to an output stream.
1371 *
1372 * @param[out] s Output stream to print the elements to.
1373 * @param[in] dt Data type of the elements
1374 * @param[in] ptr Pointer to print the elements from.
1375 * @param[in] n Number of elements to print.
1376 * @param[in] stream_width (Optional) Width of the stream. If set to 0 the element's width is used. Defaults to 0.
1377 * @param[in] element_delim (Optional) Delimeter among the consecutive elements. Defaults to space delimeter
1378 */
1379void print_consecutive_elements(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n, int stream_width, const std::string &element_delim = " ");
1380
1381/** Identify the maximum width of n consecutive elements.
1382 *
1383 * @param[in] s Output stream to print the elements to.
1384 * @param[in] dt Data type of the elements
1385 * @param[in] ptr Pointer to print the elements from.
1386 * @param[in] n Number of elements to print.
1387 *
1388 * @return The maximum width of the elements.
1389 */
1390int max_consecutive_elements_display_width(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n);
giuros01edc21e42018-11-16 14:45:31 +00001391#endif /* ARM_COMPUTE_ASSERTS_ENABLED */
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001392}
Michalis Spyrouf4643372019-11-29 16:17:13 +00001393#endif /*ARM_COMPUTE_UTILS_H */