blob: 4e374e6a321936e20cc14634d6245bccac6d64ef [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
Matthew Benthamf1aeab92023-05-30 13:35:34 +00002 * Copyright (c) 2016-2023 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>
Giorgio Arena1e2af2a2020-10-15 17:39:41 +010041#include <unordered_map>
Anthony Barbier6ff3b192017-09-04 18:44:23 +010042#include <utility>
steniu017ce53c62017-09-29 14:55:00 +010043#include <vector>
Anthony Barbier6ff3b192017-09-04 18:44:23 +010044
45namespace arm_compute
46{
Giorgio Arena1e2af2a2020-10-15 17:39:41 +010047class ITensor;
Giorgio Arena4112eed2020-10-23 14:24:26 +010048class ITensorInfo;
Matthew Benthamf1aeab92023-05-30 13:35:34 +000049class ActivationLayerInfo;
Giorgio Arena1e2af2a2020-10-15 17:39:41 +010050
Alex Gildayc357c472018-03-21 13:54:09 +000051/** Calculate the rounded up quotient of val / m.
52 *
53 * @param[in] val Value to divide and round up.
54 * @param[in] m Value to divide by.
55 *
56 * @return the result.
57 */
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +000058template <typename S, typename T>
59constexpr auto DIV_CEIL(S val, T m) -> decltype((val + m - 1) / m)
60{
61 return (val + m - 1) / m;
62}
63
Alex Gildayc357c472018-03-21 13:54:09 +000064/** Computes the smallest number larger or equal to value that is a multiple of divisor.
65 *
66 * @param[in] value Lower bound value
67 * @param[in] divisor Value to compute multiple of.
68 *
69 * @return the result.
70 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010071template <typename S, typename T>
72inline auto ceil_to_multiple(S value, T divisor) -> decltype(((value + divisor - 1) / divisor) * divisor)
73{
74 ARM_COMPUTE_ERROR_ON(value < 0 || divisor <= 0);
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +000075 return DIV_CEIL(value, divisor) * divisor;
Anthony Barbier6ff3b192017-09-04 18:44:23 +010076}
77
Alex Gildayc357c472018-03-21 13:54:09 +000078/** Computes the largest number smaller or equal to value that is a multiple of divisor.
79 *
80 * @param[in] value Upper bound value
81 * @param[in] divisor Value to compute multiple of.
82 *
83 * @return the result.
84 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010085template <typename S, typename T>
86inline auto floor_to_multiple(S value, T divisor) -> decltype((value / divisor) * divisor)
87{
88 ARM_COMPUTE_ERROR_ON(value < 0 || divisor <= 0);
89 return (value / divisor) * divisor;
90}
91
Anthony Barbier6ff3b192017-09-04 18:44:23 +010092/** Load an entire file in memory
93 *
94 * @param[in] filename Name of the file to read.
95 * @param[in] binary Is it a binary file ?
96 *
97 * @return The content of the file.
98 */
99std::string read_file(const std::string &filename, bool binary);
100
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100101/** The size in bytes of the data type
102 *
103 * @param[in] data_type Input data type
104 *
105 * @return The size in bytes of the data type
106 */
107inline size_t data_size_from_type(DataType data_type)
108{
109 switch(data_type)
110 {
111 case DataType::U8:
112 case DataType::S8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100113 case DataType::QSYMM8:
Michel Iwaniec00633802017-10-12 14:14:15 +0100114 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100115 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100116 case DataType::QSYMM8_PER_CHANNEL:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100117 return 1;
118 case DataType::U16:
119 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100120 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100121 case DataType::QASYMM16:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000122 case DataType::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100123 case DataType::F16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100124 return 2;
125 case DataType::F32:
126 case DataType::U32:
127 case DataType::S32:
128 return 4;
129 case DataType::F64:
130 case DataType::U64:
131 case DataType::S64:
132 return 8;
133 case DataType::SIZET:
134 return sizeof(size_t);
135 default:
136 ARM_COMPUTE_ERROR("Invalid data type");
137 return 0;
138 }
139}
140
141/** The size in bytes of the pixel format
142 *
143 * @param[in] format Input format
144 *
145 * @return The size in bytes of the pixel format
146 */
147inline size_t pixel_size_from_format(Format format)
148{
149 switch(format)
150 {
151 case Format::U8:
152 return 1;
153 case Format::U16:
154 case Format::S16:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000155 case Format::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100156 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:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000201 case DataType::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100202 case DataType::F16:
203 return 2;
204 case DataType::U32:
205 case DataType::S32:
206 case DataType::F32:
207 return 4;
208 default:
209 ARM_COMPUTE_ERROR("Undefined element size for given data type");
210 return 0;
211 }
212}
213
214/** Return the data type used by a given single-planar pixel format
215 *
216 * @param[in] format Input format
217 *
218 * @return The size in bytes of the pixel format
219 */
220inline DataType data_type_from_format(Format format)
221{
222 switch(format)
223 {
224 case Format::U8:
225 case Format::UV88:
226 case Format::RGB888:
227 case Format::RGBA8888:
228 case Format::YUYV422:
229 case Format::UYVY422:
230 return DataType::U8;
231 case Format::U16:
232 return DataType::U16;
233 case Format::S16:
234 return DataType::S16;
235 case Format::U32:
236 return DataType::U32;
237 case Format::S32:
238 return DataType::S32;
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000239 case Format::BFLOAT16:
240 return DataType::BFLOAT16;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100241 case Format::F16:
242 return DataType::F16;
243 case Format::F32:
244 return DataType::F32;
245 //Doesn't make sense for planar formats:
246 case Format::NV12:
247 case Format::NV21:
248 case Format::IYUV:
249 case Format::YUV444:
250 default:
251 ARM_COMPUTE_ERROR("Not supported data_type for given format");
252 return DataType::UNKNOWN;
253 }
254}
255
256/** Return the plane index of a given channel given an input format.
257 *
258 * @param[in] format Input format
259 * @param[in] channel Input channel
260 *
261 * @return The plane index of the specific channel of the specific format
262 */
263inline int plane_idx_from_channel(Format format, Channel channel)
264{
265 switch(format)
266 {
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100267 // Single planar formats have a single plane
268 case Format::U8:
269 case Format::U16:
270 case Format::S16:
271 case Format::U32:
272 case Format::S32:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000273 case Format::BFLOAT16:
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100274 case Format::F16:
275 case Format::F32:
276 case Format::UV88:
277 case Format::RGB888:
278 case Format::RGBA8888:
279 case Format::YUYV422:
280 case Format::UYVY422:
281 return 0;
282 // Multi planar formats
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100283 case Format::NV12:
284 case Format::NV21:
285 {
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100286 // Channel U and V share the same plane of format UV88
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100287 switch(channel)
288 {
289 case Channel::Y:
290 return 0;
291 case Channel::U:
292 case Channel::V:
293 return 1;
294 default:
295 ARM_COMPUTE_ERROR("Not supported channel");
296 return 0;
297 }
298 }
299 case Format::IYUV:
300 case Format::YUV444:
301 {
302 switch(channel)
303 {
304 case Channel::Y:
305 return 0;
306 case Channel::U:
307 return 1;
308 case Channel::V:
309 return 2;
310 default:
311 ARM_COMPUTE_ERROR("Not supported channel");
312 return 0;
313 }
314 }
315 default:
316 ARM_COMPUTE_ERROR("Not supported format");
317 return 0;
318 }
319}
320
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100321/** Return the channel index of a given channel given an input format.
322 *
323 * @param[in] format Input format
324 * @param[in] channel Input channel
325 *
326 * @return The channel index of the specific channel of the specific format
327 */
328inline int channel_idx_from_format(Format format, Channel channel)
329{
330 switch(format)
331 {
332 case Format::RGB888:
333 {
334 switch(channel)
335 {
336 case Channel::R:
337 return 0;
338 case Channel::G:
339 return 1;
340 case Channel::B:
341 return 2;
342 default:
343 ARM_COMPUTE_ERROR("Not supported channel");
344 return 0;
345 }
346 }
347 case Format::RGBA8888:
348 {
349 switch(channel)
350 {
351 case Channel::R:
352 return 0;
353 case Channel::G:
354 return 1;
355 case Channel::B:
356 return 2;
357 case Channel::A:
358 return 3;
359 default:
360 ARM_COMPUTE_ERROR("Not supported channel");
361 return 0;
362 }
363 }
364 case Format::YUYV422:
365 {
366 switch(channel)
367 {
368 case Channel::Y:
369 return 0;
370 case Channel::U:
371 return 1;
372 case Channel::V:
373 return 3;
374 default:
375 ARM_COMPUTE_ERROR("Not supported channel");
376 return 0;
377 }
378 }
379 case Format::UYVY422:
380 {
381 switch(channel)
382 {
383 case Channel::Y:
384 return 1;
385 case Channel::U:
386 return 0;
387 case Channel::V:
388 return 2;
389 default:
390 ARM_COMPUTE_ERROR("Not supported channel");
391 return 0;
392 }
393 }
394 case Format::NV12:
395 {
396 switch(channel)
397 {
398 case Channel::Y:
399 return 0;
400 case Channel::U:
401 return 0;
402 case Channel::V:
403 return 1;
404 default:
405 ARM_COMPUTE_ERROR("Not supported channel");
406 return 0;
407 }
408 }
409 case Format::NV21:
410 {
411 switch(channel)
412 {
413 case Channel::Y:
414 return 0;
415 case Channel::U:
416 return 1;
417 case Channel::V:
418 return 0;
419 default:
420 ARM_COMPUTE_ERROR("Not supported channel");
421 return 0;
422 }
423 }
424 case Format::YUV444:
425 case Format::IYUV:
426 {
427 switch(channel)
428 {
429 case Channel::Y:
430 return 0;
431 case Channel::U:
432 return 0;
433 case Channel::V:
434 return 0;
435 default:
436 ARM_COMPUTE_ERROR("Not supported channel");
437 return 0;
438 }
439 }
440 default:
441 ARM_COMPUTE_ERROR("Not supported format");
442 return 0;
443 }
444}
445
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100446/** Return the number of planes for a given format
447 *
448 * @param[in] format Input format
449 *
450 * @return The number of planes for a given image format.
451 */
452inline size_t num_planes_from_format(Format format)
453{
454 switch(format)
455 {
456 case Format::U8:
457 case Format::S16:
458 case Format::U16:
459 case Format::S32:
460 case Format::U32:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000461 case Format::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100462 case Format::F16:
463 case Format::F32:
464 case Format::RGB888:
465 case Format::RGBA8888:
466 case Format::YUYV422:
467 case Format::UYVY422:
468 return 1;
469 case Format::NV12:
470 case Format::NV21:
471 return 2;
472 case Format::IYUV:
473 case Format::YUV444:
474 return 3;
475 default:
476 ARM_COMPUTE_ERROR("Not supported format");
477 return 0;
478 }
479}
480
481/** Return the number of channels for a given single-planar pixel format
482 *
483 * @param[in] format Input format
484 *
485 * @return The number of channels for a given image format.
486 */
487inline size_t num_channels_from_format(Format format)
488{
489 switch(format)
490 {
491 case Format::U8:
492 case Format::U16:
493 case Format::S16:
494 case Format::U32:
495 case Format::S32:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000496 case Format::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100497 case Format::F16:
498 case Format::F32:
499 return 1;
500 // Because the U and V channels are subsampled
501 // these formats appear like having only 2 channels:
502 case Format::YUYV422:
503 case Format::UYVY422:
504 return 2;
505 case Format::UV88:
506 return 2;
507 case Format::RGB888:
508 return 3;
509 case Format::RGBA8888:
510 return 4;
511 //Doesn't make sense for planar formats:
512 case Format::NV12:
513 case Format::NV21:
514 case Format::IYUV:
515 case Format::YUV444:
516 default:
517 return 0;
518 }
519}
520
Chunosovd621bca2017-11-03 17:33:15 +0700521/** Return the promoted data type of a given data type.
522 *
523 * @note If promoted data type is not supported an error will be thrown
524 *
525 * @param[in] dt Data type to get the promoted type of.
526 *
527 * @return Promoted data type
528 */
529inline DataType get_promoted_data_type(DataType dt)
530{
531 switch(dt)
532 {
533 case DataType::U8:
534 return DataType::U16;
535 case DataType::S8:
536 return DataType::S16;
Chunosovd621bca2017-11-03 17:33:15 +0700537 case DataType::U16:
538 return DataType::U32;
539 case DataType::S16:
540 return DataType::S32;
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100541 case DataType::QSYMM8:
Chunosovd621bca2017-11-03 17:33:15 +0700542 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100543 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100544 case DataType::QSYMM8_PER_CHANNEL:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100545 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100546 case DataType::QASYMM16:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000547 case DataType::BFLOAT16:
Chunosovd621bca2017-11-03 17:33:15 +0700548 case DataType::F16:
549 case DataType::U32:
550 case DataType::S32:
551 case DataType::F32:
Chunosovd621bca2017-11-03 17:33:15 +0700552 ARM_COMPUTE_ERROR("Unsupported data type promotions!");
553 default:
554 ARM_COMPUTE_ERROR("Undefined data type!");
555 }
556 return DataType::UNKNOWN;
557}
558
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000559/** Compute the mininum and maximum values a data type can take
560 *
561 * @param[in] dt Data type to get the min/max bounds of
562 *
563 * @return A tuple (min,max) with the minimum and maximum values respectively wrapped in PixelValue.
564 */
565inline std::tuple<PixelValue, PixelValue> get_min_max(DataType dt)
566{
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000567 PixelValue min{};
568 PixelValue max{};
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000569 switch(dt)
570 {
571 case DataType::U8:
572 case DataType::QASYMM8:
573 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000574 min = PixelValue(static_cast<int32_t>(std::numeric_limits<uint8_t>::lowest()));
575 max = PixelValue(static_cast<int32_t>(std::numeric_limits<uint8_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000576 break;
577 }
578 case DataType::S8:
579 case DataType::QSYMM8:
580 case DataType::QASYMM8_SIGNED:
581 case DataType::QSYMM8_PER_CHANNEL:
582 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000583 min = PixelValue(static_cast<int32_t>(std::numeric_limits<int8_t>::lowest()));
584 max = PixelValue(static_cast<int32_t>(std::numeric_limits<int8_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000585 break;
586 }
587 case DataType::U16:
588 case DataType::QASYMM16:
589 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000590 min = PixelValue(static_cast<int32_t>(std::numeric_limits<uint16_t>::lowest()));
591 max = PixelValue(static_cast<int32_t>(std::numeric_limits<uint16_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000592 break;
593 }
594 case DataType::S16:
595 case DataType::QSYMM16:
596 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000597 min = PixelValue(static_cast<int32_t>(std::numeric_limits<int16_t>::lowest()));
598 max = PixelValue(static_cast<int32_t>(std::numeric_limits<int16_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000599 break;
600 }
601 case DataType::U32:
602 {
603 min = PixelValue(std::numeric_limits<uint32_t>::lowest());
604 max = PixelValue(std::numeric_limits<uint32_t>::max());
605 break;
606 }
607 case DataType::S32:
608 {
609 min = PixelValue(std::numeric_limits<int32_t>::lowest());
610 max = PixelValue(std::numeric_limits<int32_t>::max());
611 break;
612 }
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000613 case DataType::BFLOAT16:
614 {
615 min = PixelValue(bfloat16::lowest());
616 max = PixelValue(bfloat16::max());
617 break;
618 }
Luca Foschianiee939fb2020-01-28 10:38:07 +0000619 case DataType::F16:
620 {
621 min = PixelValue(std::numeric_limits<half>::lowest());
622 max = PixelValue(std::numeric_limits<half>::max());
623 break;
624 }
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000625 case DataType::F32:
626 {
627 min = PixelValue(std::numeric_limits<float>::lowest());
628 max = PixelValue(std::numeric_limits<float>::max());
629 break;
630 }
631 default:
632 ARM_COMPUTE_ERROR("Undefined data type!");
633 }
634 return std::make_tuple(min, max);
635}
636
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100637/** Return true if the given format has horizontal subsampling.
638 *
639 * @param[in] format Format to determine subsampling.
640 *
641 * @return True if the format can be subsampled horizontaly.
642 */
643inline bool has_format_horizontal_subsampling(Format format)
644{
645 return (format == Format::YUYV422 || format == Format::UYVY422 || format == Format::NV12 || format == Format::NV21 || format == Format::IYUV || format == Format::UV88) ? true : false;
646}
647
648/** Return true if the given format has vertical subsampling.
649 *
650 * @param[in] format Format to determine subsampling.
651 *
652 * @return True if the format can be subsampled verticaly.
653 */
654inline bool has_format_vertical_subsampling(Format format)
655{
656 return (format == Format::NV12 || format == Format::NV21 || format == Format::IYUV || format == Format::UV88) ? true : false;
657}
658
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100659/** Adjust tensor shape size if width or height are odd for a given multi-planar format. No modification is done for other formats.
660 *
661 * @note Adding here a few links discussing the issue of odd size and sharing the same solution:
Manuel Bottini581c8982019-02-07 10:31:57 +0000662 * <a href="https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/graphics/java/android/graphics/YuvImage.java">Android Source</a>
663 * <a href="https://groups.google.com/a/webmproject.org/forum/#!topic/webm-discuss/LaCKpqiDTXM">WebM</a>
664 * <a href="https://bugs.chromium.org/p/libyuv/issues/detail?id=198&amp;can=1&amp;q=odd%20width">libYUV</a>
665 * <a href="https://sourceforge.net/p/raw-yuvplayer/bugs/1/">YUVPlayer</a> *
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100666 *
667 * @param[in, out] shape Tensor shape of 2D size
668 * @param[in] format Format of the tensor
669 *
Alex Gildayc357c472018-03-21 13:54:09 +0000670 * @return The adjusted tensor shape.
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100671 */
672inline TensorShape adjust_odd_shape(const TensorShape &shape, Format format)
673{
674 TensorShape output{ shape };
675
676 // Force width to be even for formats which require subsampling of the U and V channels
677 if(has_format_horizontal_subsampling(format))
678 {
Georgios Pinitasc70f8b12020-11-15 04:12:37 +0000679 output.set(0, (output.x() + 1) & ~1U);
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100680 }
681
682 // Force height to be even for formats which require subsampling of the U and V channels
683 if(has_format_vertical_subsampling(format))
684 {
Georgios Pinitasc70f8b12020-11-15 04:12:37 +0000685 output.set(1, (output.y() + 1) & ~1U);
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100686 }
687
688 return output;
689}
690
691/** Calculate subsampled shape for a given format and channel
692 *
693 * @param[in] shape Shape of the tensor to calculate the extracted channel.
694 * @param[in] format Format of the tensor.
695 * @param[in] channel Channel to create tensor shape to be extracted.
696 *
697 * @return The subsampled tensor shape.
698 */
699inline TensorShape calculate_subsampled_shape(const TensorShape &shape, Format format, Channel channel = Channel::UNKNOWN)
700{
701 TensorShape output{ shape };
702
703 // Subsample shape only for U or V channel
704 if(Channel::U == channel || Channel::V == channel || Channel::UNKNOWN == channel)
705 {
706 // Subsample width for the tensor shape when channel is U or V
707 if(has_format_horizontal_subsampling(format))
708 {
709 output.set(0, output.x() / 2U);
710 }
711
712 // Subsample height for the tensor shape when channel is U or V
713 if(has_format_vertical_subsampling(format))
714 {
715 output.set(1, output.y() / 2U);
716 }
717 }
718
719 return output;
720}
721
Pablo Tello35767bc2018-12-05 17:36:30 +0000722/** Permutes the given dimensions according the permutation vector
723 *
724 * @param[in,out] dimensions Dimensions to be permuted.
725 * @param[in] perm Vector describing the permutation.
726 *
727 */
728template <typename T>
729inline void permute_strides(Dimensions<T> &dimensions, const PermutationVector &perm)
730{
731 const auto old_dim = utility::make_array<Dimensions<T>::num_max_dimensions>(dimensions.begin(), dimensions.end());
732 for(unsigned int i = 0; i < perm.num_dimensions(); ++i)
733 {
734 T dimension_val = old_dim[i];
735 dimensions.set(perm[i], dimension_val);
736 }
737}
738
Georgios Pinitas4074c992018-01-30 18:13:46 +0000739/** Calculate padding requirements in case of SAME padding
740 *
741 * @param[in] input_shape Input shape
742 * @param[in] weights_shape Weights shape
743 * @param[in] conv_info Convolution information (containing strides)
Isabella Gottardi6a914402019-01-30 15:45:42 +0000744 * @param[in] data_layout (Optional) Data layout of the input and weights tensor
Pablo Tello01bbacb2019-04-30 10:32:42 +0100745 * @param[in] dilation (Optional) Dilation factor used in the convolution.
Giorgio Arena17203582019-08-02 16:00:41 +0100746 * @param[in] rounding_type (Optional) Dimension rounding type when down-scaling.
Georgios Pinitas4074c992018-01-30 18:13:46 +0000747 *
748 * @return PadStrideInfo for SAME padding
749 */
Giorgio Arena17203582019-08-02 16:00:41 +0100750PadStrideInfo calculate_same_pad(TensorShape input_shape, TensorShape weights_shape, PadStrideInfo conv_info, DataLayout data_layout = DataLayout::NCHW, const Size2D &dilation = Size2D(1u, 1u),
751 const DimensionRoundingType &rounding_type = DimensionRoundingType::FLOOR);
Georgios Pinitas4074c992018-01-30 18:13:46 +0000752
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100753/** Returns expected width and height of the deconvolution's output tensor.
754 *
Matthew Jacksonb9070a42019-08-22 16:13:27 +0100755 * @param[in] in_width Width of input tensor (Number of columns)
756 * @param[in] in_height Height of input tensor (Number of rows)
757 * @param[in] kernel_width Kernel width.
758 * @param[in] kernel_height Kernel height.
759 * @param[in] pad_stride_info Pad and stride information.
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100760 *
761 * @return A pair with the new width in the first position and the new height in the second.
762 */
Pablo Tello01bbacb2019-04-30 10:32:42 +0100763std::pair<unsigned int, unsigned int> deconvolution_output_dimensions(unsigned int in_width, unsigned int in_height,
764 unsigned int kernel_width, unsigned int kernel_height,
Matthew Jacksonb9070a42019-08-22 16:13:27 +0100765 const PadStrideInfo &pad_stride_info);
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100766
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100767/** Returns expected width and height of output scaled tensor depending on dimensions rounding mode.
768 *
Gian Marco Iodice4e288692017-06-27 11:41:59 +0100769 * @param[in] width Width of input tensor (Number of columns)
770 * @param[in] height Height of input tensor (Number of rows)
771 * @param[in] kernel_width Kernel width.
772 * @param[in] kernel_height Kernel height.
773 * @param[in] pad_stride_info Pad and stride information.
Alex Gilday7da29b62018-03-23 14:16:00 +0000774 * @param[in] dilation (Optional) Dilation, in elements, across x and y. Defaults to (1, 1).
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100775 *
776 * @return A pair with the new width in the first position and the new height in the second.
777 */
Georgios Pinitas80838f12019-12-12 18:23:13 +0000778std::pair<unsigned int, unsigned int> scaled_dimensions(int width, int height,
779 int kernel_width, int kernel_height,
Pablo Tello01bbacb2019-04-30 10:32:42 +0100780 const PadStrideInfo &pad_stride_info,
781 const Size2D &dilation = Size2D(1U, 1U));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100782
Freddie Liardetafcbb8f2021-05-04 12:41:16 +0100783/** Returns calculated width and height of output scaled tensor depending on dimensions rounding mode.
784 *
785 * @param[in] width Width of input tensor (Number of columns)
786 * @param[in] height Height of input tensor (Number of rows)
787 * @param[in] kernel_width Kernel width.
788 * @param[in] kernel_height Kernel height.
789 * @param[in] pad_stride_info Pad and stride information.
790 *
791 * @return A pair with the new width in the first position and the new height in the second, returned values can be < 1
792 */
793std::pair<int, int> scaled_dimensions_signed(int width, int height,
794 int kernel_width, int kernel_height,
795 const PadStrideInfo &pad_stride_info);
796
ramelg0137515692022-02-26 22:06:20 +0000797/** Returns calculated width, height and depth of output scaled tensor depending on dimensions rounding mode.
798 *
799 * @param[in] width Width of input tensor
800 * @param[in] height Height of input tensor
801 * @param[in] depth Depth of input tensor
802 * @param[in] kernel_width Kernel width.
803 * @param[in] kernel_height Kernel height.
804 * @param[in] kernel_depth Kernel depth.
805 * @param[in] pool3d_info Pad and stride and round information for 3d pooling
806 *
807 * @return A tuple with the new width in the first position, the new height in the second, and the new depth in the third.
808 * Returned values can be < 1
809 */
810std::tuple<int, int, int> scaled_3d_dimensions_signed(int width, int height, int depth,
811 int kernel_width, int kernel_height, int kernel_depth,
812 const Pooling3dLayerInfo &pool3d_info);
813
Sang-Hoon Park2697fd82019-10-15 16:49:24 +0100814/** Check if the given reduction operation should be handled in a serial way.
815 *
816 * @param[in] op Reduction operation to perform
817 * @param[in] dt Data type
818 * @param[in] axis Axis along which to reduce
819 *
820 * @return True if the given reduction operation should be handled in a serial way.
821 */
822bool needs_serialized_reduction(ReductionOperation op, DataType dt, unsigned int axis);
823
Sang-Hoon Park0779fec2019-11-13 17:08:12 +0000824/** Returns output quantization information for softmax layer
825 *
826 * @param[in] input_type The data type of the input tensor
827 * @param[in] is_log True for log softmax
828 *
829 * @return Quantization information for the output tensor
830 */
831QuantizationInfo get_softmax_output_quantization_info(DataType input_type, bool is_log);
832
Sang-Hoon Park4715cf92020-01-08 16:02:47 +0000833/** Returns a pair of minimum and maximum values for a quantized activation
834 *
835 * @param[in] act_info The information for activation
836 * @param[in] data_type The used data type
837 * @param[in] oq_info The output quantization information
838 *
839 * @return The pair with minimum and maximum values
840 */
Matthew Benthamf1aeab92023-05-30 13:35:34 +0000841std::pair<int32_t, int32_t> get_quantized_activation_min_max(const ActivationLayerInfo& act_info, DataType data_type, UniformQuantizationInfo oq_info);
Sang-Hoon Park4715cf92020-01-08 16:02:47 +0000842
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100843/** Convert a tensor format into a string.
844 *
845 * @param[in] format @ref Format to be translated to string.
846 *
847 * @return The string describing the format.
848 */
849const std::string &string_from_format(Format format);
850
851/** Convert a channel identity into a string.
852 *
853 * @param[in] channel @ref Channel to be translated to string.
854 *
855 * @return The string describing the channel.
856 */
857const std::string &string_from_channel(Channel channel);
Michele Di Giorgiobf3c6622018-03-08 11:52:27 +0000858/** Convert a data layout identity into a string.
859 *
860 * @param[in] dl @ref DataLayout to be translated to string.
861 *
862 * @return The string describing the data layout.
863 */
864const std::string &string_from_data_layout(DataLayout dl);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100865/** Convert a data type identity into a string.
866 *
867 * @param[in] dt @ref DataType to be translated to string.
868 *
869 * @return The string describing the data type.
870 */
871const std::string &string_from_data_type(DataType dt);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100872/** Translates a given activation function to a string.
873 *
874 * @param[in] act @ref ActivationLayerInfo::ActivationFunction to be translated to string.
875 *
876 * @return The string describing the activation function.
877 */
Matthew Benthamf1aeab92023-05-30 13:35:34 +0000878const std::string &string_from_activation_func(const ActivationFunction& act);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100879/** Translates a given interpolation policy to a string.
880 *
881 * @param[in] policy @ref InterpolationPolicy to be translated to string.
882 *
883 * @return The string describing the interpolation policy.
884 */
885const std::string &string_from_interpolation_policy(InterpolationPolicy policy);
886/** Translates a given border mode policy to a string.
887 *
888 * @param[in] border_mode @ref BorderMode to be translated to string.
889 *
890 * @return The string describing the border mode.
891 */
892const std::string &string_from_border_mode(BorderMode border_mode);
893/** Translates a given normalization type to a string.
894 *
895 * @param[in] type @ref NormType to be translated to string.
896 *
897 * @return The string describing the normalization type.
898 */
899const std::string &string_from_norm_type(NormType type);
Georgios Pinitascdf51452017-08-31 14:21:36 +0100900/** Translates a given pooling type to a string.
901 *
902 * @param[in] type @ref PoolingType to be translated to string.
903 *
904 * @return The string describing the pooling type.
905 */
906const std::string &string_from_pooling_type(PoolingType type);
SiCongLic4270cf2021-12-22 11:22:40 +0000907/** Check if the pool region is entirely outside the input tensor
908 *
909 * @param[in] info @ref PoolingLayerInfo to be checked.
910 *
911 * @return True if the pool region is entirely outside the input tensor, False otherwise.
912 */
913bool is_pool_region_entirely_outside_input(const PoolingLayerInfo &info);
ramelg0137515692022-02-26 22:06:20 +0000914/** Check if the 3d pool region is entirely outside the input tensor
915 *
916 * @param[in] info @ref Pooling3dLayerInfo to be checked.
917 *
918 * @return True if the pool region is entirely outside the input tensor, False otherwise.
919 */
920bool is_pool_3d_region_entirely_outside_input(const Pooling3dLayerInfo &info);
921/** Check if the 3D padding is symmetric i.e. padding in each opposite sides are euqal (left=right, top=bottom and front=back)
922 *
923 * @param[in] info @ref Padding3D input 3D padding object to check if it is symmetric
924 *
925 * @return True if padding is symmetric
926 */
927inline bool is_symmetric(const Padding3D& info)
928{
929 return ((info.left == info.right) && (info.top == info.bottom) && (info.front == info.back));
930}
Gian Marco Iodice4b908652018-10-18 10:21:02 +0100931/** Translates a given GEMMLowp output stage to a string.
932 *
933 * @param[in] output_stage @ref GEMMLowpOutputStageInfo to be translated to string.
934 *
935 * @return The string describing the GEMMLowp output stage
936 */
937const std::string &string_from_gemmlowp_output_stage(GEMMLowpOutputStageType output_stage);
Giuseppe Rossinid7647d42018-07-17 18:13:13 +0100938/** Convert a PixelValue to a string, represented through the specific data type
939 *
940 * @param[in] value The PixelValue to convert
941 * @param[in] data_type The type to be used to convert the @p value
942 *
943 * @return String representation of the PixelValue through the given data type.
944 */
945std::string string_from_pixel_value(const PixelValue &value, const DataType data_type);
SiCong Lie357a252020-08-09 20:05:52 +0100946/** Convert a string to DataType
947 *
948 * @param[in] name The name of the data type
949 *
950 * @return DataType
951 */
952DataType data_type_from_name(const std::string &name);
Giorgio Arena1e2af2a2020-10-15 17:39:41 +0100953/** Stores padding information before configuring a kernel
954 *
Giorgio Arena4112eed2020-10-23 14:24:26 +0100955 * @param[in] infos list of tensor infos to store the padding info for
956 *
957 * @return An unordered map where each tensor info pointer is paired with its original padding info
958 */
959std::unordered_map<const ITensorInfo *, PaddingSize> get_padding_info(std::initializer_list<const ITensorInfo *> infos);
960/** Stores padding information before configuring a kernel
961 *
Giorgio Arena1e2af2a2020-10-15 17:39:41 +0100962 * @param[in] tensors list of tensors to store the padding info for
963 *
Giorgio Arena4112eed2020-10-23 14:24:26 +0100964 * @return An unordered map where each tensor info pointer is paired with its original padding info
Giorgio Arena1e2af2a2020-10-15 17:39:41 +0100965 */
Giorgio Arena4112eed2020-10-23 14:24:26 +0100966std::unordered_map<const ITensorInfo *, PaddingSize> get_padding_info(std::initializer_list<const ITensor *> tensors);
Giorgio Arena1e2af2a2020-10-15 17:39:41 +0100967/** Check if the previously stored padding info has changed after configuring a kernel
968 *
Giorgio Arena4112eed2020-10-23 14:24:26 +0100969 * @param[in] padding_map an unordered map where each tensor info pointer is paired with its original padding info
Giorgio Arena1e2af2a2020-10-15 17:39:41 +0100970 *
Giorgio Arena4112eed2020-10-23 14:24:26 +0100971 * @return true if any of the tensor infos has changed its paddings
Giorgio Arena1e2af2a2020-10-15 17:39:41 +0100972 */
Giorgio Arena4112eed2020-10-23 14:24:26 +0100973bool has_padding_changed(const std::unordered_map<const ITensorInfo *, PaddingSize> &padding_map);
Giorgio Arena1e2af2a2020-10-15 17:39:41 +0100974
SiCong Lie357a252020-08-09 20:05:52 +0100975/** Input Stream operator for @ref DataType
976 *
977 * @param[in] stream Stream to parse
978 * @param[out] data_type Output data type
979 *
980 * @return Updated stream
981 */
982inline ::std::istream &operator>>(::std::istream &stream, DataType &data_type)
983{
984 std::string value;
985 stream >> value;
986 data_type = data_type_from_name(value);
987 return stream;
988}
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100989/** Lower a given string.
990 *
991 * @param[in] val Given string to lower.
992 *
993 * @return The lowered string
994 */
995std::string lower_string(const std::string &val);
996
ramelg019cca5922021-11-11 10:05:00 +0000997/** Raise a given string to upper case
998 *
999 * @param[in] val Given string to lower.
1000 *
1001 * @return The upper case string
1002 */
1003std::string upper_string(const std::string &val);
1004
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001005/** Check if a given data type is of floating point type
1006 *
1007 * @param[in] dt Input data type.
1008 *
1009 * @return True if data type is of floating point type, else false.
1010 */
1011inline bool is_data_type_float(DataType dt)
1012{
1013 switch(dt)
1014 {
1015 case DataType::F16:
1016 case DataType::F32:
1017 return true;
1018 default:
1019 return false;
1020 }
1021}
1022
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001023/** Check if a given data type is of quantized type
1024 *
1025 * @note Quantized is considered a super-set of fixed-point and asymmetric data types.
1026 *
1027 * @param[in] dt Input data type.
1028 *
1029 * @return True if data type is of quantized type, else false.
1030 */
1031inline bool is_data_type_quantized(DataType dt)
1032{
1033 switch(dt)
1034 {
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001035 case DataType::QSYMM8:
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001036 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001037 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001038 case DataType::QSYMM8_PER_CHANNEL:
Manuel Bottini3689fcd2019-06-14 17:18:12 +01001039 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +01001040 case DataType::QASYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001041 return true;
1042 default:
1043 return false;
1044 }
1045}
1046
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001047/** Check if a given data type is of asymmetric quantized type
1048 *
1049 * @param[in] dt Input data type.
1050 *
Michele Di Giorgio6997fc92019-06-18 10:23:22 +01001051 * @return True if data type is of asymmetric quantized type, else false.
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001052 */
Anton Lokhmotovaf6204c2017-11-08 09:34:19 +00001053inline bool is_data_type_quantized_asymmetric(DataType dt)
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001054{
1055 switch(dt)
1056 {
1057 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001058 case DataType::QASYMM8_SIGNED:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +01001059 case DataType::QASYMM16:
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001060 return true;
1061 default:
1062 return false;
1063 }
1064}
1065
Georgios Pinitas6e1791b2019-12-02 19:01:25 +00001066/** Check if a given data type is of asymmetric quantized signed type
1067 *
1068 * @param[in] dt Input data type.
1069 *
1070 * @return True if data type is of asymmetric quantized signed type, else false.
1071 */
1072inline bool is_data_type_quantized_asymmetric_signed(DataType dt)
1073{
1074 switch(dt)
1075 {
1076 case DataType::QASYMM8_SIGNED:
1077 return true;
1078 default:
1079 return false;
1080 }
1081}
1082
Michele Di Giorgio6997fc92019-06-18 10:23:22 +01001083/** Check if a given data type is of symmetric quantized type
1084 *
1085 * @param[in] dt Input data type.
1086 *
1087 * @return True if data type is of symmetric quantized type, else false.
1088 */
1089inline bool is_data_type_quantized_symmetric(DataType dt)
1090{
1091 switch(dt)
1092 {
1093 case DataType::QSYMM8:
1094 case DataType::QSYMM8_PER_CHANNEL:
1095 case DataType::QSYMM16:
1096 return true;
1097 default:
1098 return false;
1099 }
1100}
1101
Michalis Spyrouc8530212019-08-22 11:44:04 +01001102/** Check if a given data type is of per channel type
1103 *
1104 * @param[in] dt Input data type.
1105 *
1106 * @return True if data type is of per channel type, else false.
1107 */
1108inline bool is_data_type_quantized_per_channel(DataType dt)
1109{
1110 switch(dt)
1111 {
1112 case DataType::QSYMM8_PER_CHANNEL:
Michalis Spyrouc8530212019-08-22 11:44:04 +01001113 return true;
1114 default:
1115 return false;
1116 }
1117}
1118
Georgios Pinitas89010962017-08-04 14:58:27 +01001119/** Create a string with the float in full precision.
1120 *
1121 * @param val Floating point value
1122 *
1123 * @return String with the floating point value.
1124 */
1125inline std::string float_to_string_with_full_precision(float val)
1126{
1127 std::stringstream ss;
Georgios Pinitas7900a9e2018-11-23 11:44:58 +00001128 ss.precision(std::numeric_limits<float>::max_digits10);
Georgios Pinitas89010962017-08-04 14:58:27 +01001129 ss << val;
Giorgio Arena73023022018-09-04 14:55:55 +01001130
1131 if(val != static_cast<int>(val))
1132 {
1133 ss << "f";
1134 }
1135
Georgios Pinitas89010962017-08-04 14:58:27 +01001136 return ss.str();
1137}
1138
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001139/** Returns the number of elements required to go from start to end with the wanted step
1140 *
1141 * @param[in] start start value
1142 * @param[in] end end value
1143 * @param[in] step step value between each number in the wanted sequence
1144 *
1145 * @return number of elements to go from start value to end value using the wanted step
1146 */
1147inline size_t num_of_elements_in_range(const float start, const float end, const float step)
1148{
1149 ARM_COMPUTE_ERROR_ON_MSG(step == 0, "Range Step cannot be 0");
1150 return size_t(std::ceil((end - start) / step));
1151}
1152
1153/** Returns true if the value can be represented by the given data type
1154 *
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001155 * @param[in] val value to be checked
1156 * @param[in] dt data type that is checked
1157 * @param[in] qinfo (Optional) quantization info if the data type is QASYMM8
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001158 *
1159 * @return true if the data type can hold the value.
1160 */
1161template <typename T>
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001162bool check_value_range(T val, DataType dt, QuantizationInfo qinfo = QuantizationInfo())
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001163{
1164 switch(dt)
1165 {
1166 case DataType::U8:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001167 {
1168 const auto val_u8 = static_cast<uint8_t>(val);
Georgios Pinitas41c15172021-02-22 23:43:33 +00001169 return ((val_u8 == val) && val >= std::numeric_limits<uint8_t>::lowest() && val <= std::numeric_limits<uint8_t>::max());
Georgios Pinitase874ef92019-09-09 17:40:33 +01001170 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001171 case DataType::QASYMM8:
1172 {
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001173 double min = static_cast<double>(dequantize_qasymm8(0, qinfo));
1174 double max = static_cast<double>(dequantize_qasymm8(std::numeric_limits<uint8_t>::max(), qinfo));
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001175 return ((double)val >= min && (double)val <= max);
1176 }
1177 case DataType::S8:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001178 {
1179 const auto val_s8 = static_cast<int8_t>(val);
Georgios Pinitas41c15172021-02-22 23:43:33 +00001180 return ((val_s8 == val) && val >= std::numeric_limits<int8_t>::lowest() && val <= std::numeric_limits<int8_t>::max());
Georgios Pinitase874ef92019-09-09 17:40:33 +01001181 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001182 case DataType::U16:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001183 {
1184 const auto val_u16 = static_cast<uint16_t>(val);
Georgios Pinitas41c15172021-02-22 23:43:33 +00001185 return ((val_u16 == val) && val >= std::numeric_limits<uint16_t>::lowest() && val <= std::numeric_limits<uint16_t>::max());
Georgios Pinitase874ef92019-09-09 17:40:33 +01001186 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001187 case DataType::S16:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001188 {
1189 const auto val_s16 = static_cast<int16_t>(val);
Georgios Pinitas41c15172021-02-22 23:43:33 +00001190 return ((val_s16 == val) && val >= std::numeric_limits<int16_t>::lowest() && val <= std::numeric_limits<int16_t>::max());
Georgios Pinitase874ef92019-09-09 17:40:33 +01001191 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001192 case DataType::U32:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001193 {
Mohammed Suhail Munshi2134d1b2022-02-08 15:23:00 +00001194 const auto val_d64 = static_cast<double>(val);
Georgios Pinitase874ef92019-09-09 17:40:33 +01001195 const auto val_u32 = static_cast<uint32_t>(val);
Mohammed Suhail Munshi2134d1b2022-02-08 15:23:00 +00001196 return ((val_u32 == val_d64) && val_d64 >= std::numeric_limits<uint32_t>::lowest() && val_d64 <= std::numeric_limits<uint32_t>::max());
Georgios Pinitase874ef92019-09-09 17:40:33 +01001197 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001198 case DataType::S32:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001199 {
Mohammed Suhail Munshi2134d1b2022-02-08 15:23:00 +00001200 const auto val_d64 = static_cast<double>(val);
Georgios Pinitase874ef92019-09-09 17:40:33 +01001201 const auto val_s32 = static_cast<int32_t>(val);
Mohammed Suhail Munshi2134d1b2022-02-08 15:23:00 +00001202 return ((val_s32 == val_d64) && val_d64 >= std::numeric_limits<int32_t>::lowest() && val_d64 <= std::numeric_limits<int32_t>::max());
Georgios Pinitase874ef92019-09-09 17:40:33 +01001203 }
Georgios Pinitase8291ac2020-02-26 09:58:13 +00001204 case DataType::BFLOAT16:
1205 return (val >= bfloat16::lowest() && val <= bfloat16::max());
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001206 case DataType::F16:
1207 return (val >= std::numeric_limits<half>::lowest() && val <= std::numeric_limits<half>::max());
1208 case DataType::F32:
1209 return (val >= std::numeric_limits<float>::lowest() && val <= std::numeric_limits<float>::max());
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001210 default:
1211 ARM_COMPUTE_ERROR("Data type not supported");
1212 return false;
1213 }
1214}
1215
Giorgio Arenad304adb2020-10-02 10:20:11 +01001216/** Returns the adjusted vector size in case it is less than the input's first dimension, getting rounded down to its closest valid vector size
1217 *
1218 * @param[in] vec_size vector size to be adjusted
1219 * @param[in] dim0 size of the first dimension
1220 *
1221 * @return the number of element processed along the X axis per thread
1222 */
1223inline unsigned int adjust_vec_size(unsigned int vec_size, size_t dim0)
1224{
1225 ARM_COMPUTE_ERROR_ON(vec_size > 16);
1226
Giorgio Arena79acd772020-10-22 14:29:50 +01001227 if((vec_size >= dim0) && (dim0 == 3))
Giorgio Arenad304adb2020-10-02 10:20:11 +01001228 {
1229 return dim0;
1230 }
1231
1232 while(vec_size > dim0)
1233 {
1234 vec_size >>= 1;
1235 }
1236
1237 return vec_size;
1238}
1239
Giorgio Arena5ae8d802021-11-18 18:02:13 +00001240/** Returns the suffix string of CPU kernel implementation names based on the given data type
1241 *
1242 * @param[in] data_type The data type the CPU kernel implemetation uses
1243 *
1244 * @return the suffix string of CPU kernel implementations
1245 */
1246inline std::string cpu_impl_dt(const DataType &data_type)
1247{
1248 std::string ret = "";
1249
1250 switch(data_type)
1251 {
1252 case DataType::F32:
1253 ret = "fp32";
1254 break;
1255 case DataType::F16:
1256 ret = "fp16";
1257 break;
1258 case DataType::U8:
1259 ret = "u8";
1260 break;
1261 case DataType::S16:
1262 ret = "s16";
1263 break;
1264 case DataType::S32:
1265 ret = "s32";
1266 break;
1267 case DataType::QASYMM8:
1268 ret = "qu8";
1269 break;
1270 case DataType::QASYMM8_SIGNED:
1271 ret = "qs8";
1272 break;
1273 case DataType::QSYMM16:
1274 ret = "qs16";
1275 break;
Dana Zlotnikebbae942022-02-03 12:52:15 +02001276 case DataType::QSYMM8_PER_CHANNEL:
1277 ret = "qp8";
1278 break;
Yair Schwarzbaum298b2c02022-02-01 08:55:56 +02001279 case DataType::BFLOAT16:
1280 ret = "bf16";
1281 break;
Giorgio Arena5ae8d802021-11-18 18:02:13 +00001282 default:
1283 ARM_COMPUTE_ERROR("Unsupported.");
1284 }
1285
1286 return ret;
1287}
1288
giuros01edc21e42018-11-16 14:45:31 +00001289#ifdef ARM_COMPUTE_ASSERTS_ENABLED
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001290/** Print consecutive elements to an output stream.
1291 *
1292 * @param[out] s Output stream to print the elements to.
1293 * @param[in] ptr Pointer to print the elements from.
1294 * @param[in] n Number of elements to print.
1295 * @param[in] stream_width (Optional) Width of the stream. If set to 0 the element's width is used. Defaults to 0.
1296 * @param[in] element_delim (Optional) Delimeter among the consecutive elements. Defaults to space delimeter
1297 */
1298template <typename T>
1299void print_consecutive_elements_impl(std::ostream &s, const T *ptr, unsigned int n, int stream_width = 0, const std::string &element_delim = " ")
1300{
1301 using print_type = typename std::conditional<std::is_floating_point<T>::value, T, int>::type;
Michalis Spyrou53860dd2019-07-01 14:20:56 +01001302 std::ios stream_status(nullptr);
1303 stream_status.copyfmt(s);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001304
1305 for(unsigned int i = 0; i < n; ++i)
1306 {
1307 // Set stream width as it is not a "sticky" stream manipulator
1308 if(stream_width != 0)
1309 {
1310 s.width(stream_width);
1311 }
Anthony Barbier7068f992017-10-26 15:23:08 +01001312
1313 if(std::is_same<typename std::decay<T>::type, half>::value)
1314 {
1315 // 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.
1316 s << std::right << static_cast<T>(ptr[i]) << element_delim;
1317 }
Georgios Pinitase8291ac2020-02-26 09:58:13 +00001318 else if(std::is_same<typename std::decay<T>::type, bfloat16>::value)
1319 {
Georgios Pinitasc7b183a2020-03-06 18:12:09 +00001320 // We use T instead of print_type here is because the std::is_floating_point<bfloat16> returns false and then the print_type becomes int.
Georgios Pinitase8291ac2020-02-26 09:58:13 +00001321 s << std::right << float(ptr[i]) << element_delim;
1322 }
Anthony Barbier7068f992017-10-26 15:23:08 +01001323 else
1324 {
1325 s << std::right << static_cast<print_type>(ptr[i]) << element_delim;
1326 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001327 }
Michalis Spyrou53860dd2019-07-01 14:20:56 +01001328
1329 // Restore output stream flags
1330 s.copyfmt(stream_status);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001331}
1332
1333/** Identify the maximum width of n consecutive elements.
1334 *
1335 * @param[in] s The output stream which will be used to print the elements. Used to extract the stream format.
1336 * @param[in] ptr Pointer to the elements.
1337 * @param[in] n Number of elements.
1338 *
1339 * @return The maximum width of the elements.
1340 */
1341template <typename T>
1342int max_consecutive_elements_display_width_impl(std::ostream &s, const T *ptr, unsigned int n)
1343{
1344 using print_type = typename std::conditional<std::is_floating_point<T>::value, T, int>::type;
1345
1346 int max_width = -1;
1347 for(unsigned int i = 0; i < n; ++i)
1348 {
1349 std::stringstream ss;
1350 ss.copyfmt(s);
Anthony Barbier7068f992017-10-26 15:23:08 +01001351
1352 if(std::is_same<typename std::decay<T>::type, half>::value)
1353 {
1354 // 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.
1355 ss << static_cast<T>(ptr[i]);
1356 }
Georgios Pinitase8291ac2020-02-26 09:58:13 +00001357 else if(std::is_same<typename std::decay<T>::type, bfloat16>::value)
1358 {
1359 // We use T instead of print_type here is because the std::is_floating_point<bfloat> returns false and then the print_type becomes int.
1360 ss << float(ptr[i]);
1361 }
Anthony Barbier7068f992017-10-26 15:23:08 +01001362 else
1363 {
1364 ss << static_cast<print_type>(ptr[i]);
1365 }
1366
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001367 max_width = std::max<int>(max_width, ss.str().size());
1368 }
1369 return max_width;
1370}
1371
1372/** Print consecutive elements to an output stream.
1373 *
1374 * @param[out] s Output stream to print the elements to.
1375 * @param[in] dt Data type of the elements
1376 * @param[in] ptr Pointer to print the elements from.
1377 * @param[in] n Number of elements to print.
1378 * @param[in] stream_width (Optional) Width of the stream. If set to 0 the element's width is used. Defaults to 0.
1379 * @param[in] element_delim (Optional) Delimeter among the consecutive elements. Defaults to space delimeter
1380 */
1381void print_consecutive_elements(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n, int stream_width, const std::string &element_delim = " ");
1382
1383/** Identify the maximum width of n consecutive elements.
1384 *
1385 * @param[in] s Output stream to print the elements to.
1386 * @param[in] dt Data type of the elements
1387 * @param[in] ptr Pointer to print the elements from.
1388 * @param[in] n Number of elements to print.
1389 *
1390 * @return The maximum width of the elements.
1391 */
1392int max_consecutive_elements_display_width(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n);
giuros01edc21e42018-11-16 14:45:31 +00001393#endif /* ARM_COMPUTE_ASSERTS_ENABLED */
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001394}
Michalis Spyrouf4643372019-11-29 16:17:13 +00001395#endif /*ARM_COMPUTE_UTILS_H */