blob: 681a1a708e8d9df470da0e6d4b805d678aaa04c0 [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
Michele Di Giorgiod9eaf612020-07-08 11:12:57 +01002 * 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>
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;
48
Alex Gildayc357c472018-03-21 13:54:09 +000049/** Calculate the rounded up quotient of val / m.
50 *
51 * @param[in] val Value to divide and round up.
52 * @param[in] m Value to divide by.
53 *
54 * @return the result.
55 */
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +000056template <typename S, typename T>
57constexpr auto DIV_CEIL(S val, T m) -> decltype((val + m - 1) / m)
58{
59 return (val + m - 1) / m;
60}
61
Alex Gildayc357c472018-03-21 13:54:09 +000062/** Computes the smallest number larger or equal to value that is a multiple of divisor.
63 *
64 * @param[in] value Lower bound value
65 * @param[in] divisor Value to compute multiple of.
66 *
67 * @return the result.
68 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010069template <typename S, typename T>
70inline auto ceil_to_multiple(S value, T divisor) -> decltype(((value + divisor - 1) / divisor) * divisor)
71{
72 ARM_COMPUTE_ERROR_ON(value < 0 || divisor <= 0);
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +000073 return DIV_CEIL(value, divisor) * divisor;
Anthony Barbier6ff3b192017-09-04 18:44:23 +010074}
75
Alex Gildayc357c472018-03-21 13:54:09 +000076/** Computes the largest number smaller or equal to value that is a multiple of divisor.
77 *
78 * @param[in] value Upper bound value
79 * @param[in] divisor Value to compute multiple of.
80 *
81 * @return the result.
82 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010083template <typename S, typename T>
84inline auto floor_to_multiple(S value, T divisor) -> decltype((value / divisor) * divisor)
85{
86 ARM_COMPUTE_ERROR_ON(value < 0 || divisor <= 0);
87 return (value / divisor) * divisor;
88}
89
Anthony Barbier6ff3b192017-09-04 18:44:23 +010090/** Load an entire file in memory
91 *
92 * @param[in] filename Name of the file to read.
93 * @param[in] binary Is it a binary file ?
94 *
95 * @return The content of the file.
96 */
97std::string read_file(const std::string &filename, bool binary);
98
Anthony Barbier6ff3b192017-09-04 18:44:23 +010099/** The size in bytes of the data type
100 *
101 * @param[in] data_type Input data type
102 *
103 * @return The size in bytes of the data type
104 */
105inline size_t data_size_from_type(DataType data_type)
106{
107 switch(data_type)
108 {
109 case DataType::U8:
110 case DataType::S8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100111 case DataType::QSYMM8:
Michel Iwaniec00633802017-10-12 14:14:15 +0100112 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100113 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100114 case DataType::QSYMM8_PER_CHANNEL:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100115 return 1;
116 case DataType::U16:
117 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100118 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100119 case DataType::QASYMM16:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000120 case DataType::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100121 case DataType::F16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100122 return 2;
123 case DataType::F32:
124 case DataType::U32:
125 case DataType::S32:
126 return 4;
127 case DataType::F64:
128 case DataType::U64:
129 case DataType::S64:
130 return 8;
131 case DataType::SIZET:
132 return sizeof(size_t);
133 default:
134 ARM_COMPUTE_ERROR("Invalid data type");
135 return 0;
136 }
137}
138
139/** The size in bytes of the pixel format
140 *
141 * @param[in] format Input format
142 *
143 * @return The size in bytes of the pixel format
144 */
145inline size_t pixel_size_from_format(Format format)
146{
147 switch(format)
148 {
149 case Format::U8:
150 return 1;
151 case Format::U16:
152 case Format::S16:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000153 case Format::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100154 case Format::F16:
155 case Format::UV88:
156 case Format::YUYV422:
157 case Format::UYVY422:
158 return 2;
159 case Format::RGB888:
160 return 3;
161 case Format::RGBA8888:
162 return 4;
163 case Format::U32:
164 case Format::S32:
165 case Format::F32:
166 return 4;
167 //Doesn't make sense for planar formats:
168 case Format::NV12:
169 case Format::NV21:
170 case Format::IYUV:
171 case Format::YUV444:
172 default:
173 ARM_COMPUTE_ERROR("Undefined pixel size for given format");
174 return 0;
175 }
176}
177
178/** The size in bytes of the data type
179 *
180 * @param[in] dt Input data type
181 *
182 * @return The size in bytes of the data type
183 */
184inline size_t element_size_from_data_type(DataType dt)
185{
186 switch(dt)
187 {
188 case DataType::S8:
189 case DataType::U8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100190 case DataType::QSYMM8:
Michel Iwaniec00633802017-10-12 14:14:15 +0100191 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100192 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100193 case DataType::QSYMM8_PER_CHANNEL:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100194 return 1;
195 case DataType::U16:
196 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100197 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100198 case DataType::QASYMM16:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000199 case DataType::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100200 case DataType::F16:
201 return 2;
202 case DataType::U32:
203 case DataType::S32:
204 case DataType::F32:
205 return 4;
206 default:
207 ARM_COMPUTE_ERROR("Undefined element size for given data type");
208 return 0;
209 }
210}
211
212/** Return the data type used by a given single-planar pixel format
213 *
214 * @param[in] format Input format
215 *
216 * @return The size in bytes of the pixel format
217 */
218inline DataType data_type_from_format(Format format)
219{
220 switch(format)
221 {
222 case Format::U8:
223 case Format::UV88:
224 case Format::RGB888:
225 case Format::RGBA8888:
226 case Format::YUYV422:
227 case Format::UYVY422:
228 return DataType::U8;
229 case Format::U16:
230 return DataType::U16;
231 case Format::S16:
232 return DataType::S16;
233 case Format::U32:
234 return DataType::U32;
235 case Format::S32:
236 return DataType::S32;
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000237 case Format::BFLOAT16:
238 return DataType::BFLOAT16;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100239 case Format::F16:
240 return DataType::F16;
241 case Format::F32:
242 return DataType::F32;
243 //Doesn't make sense for planar formats:
244 case Format::NV12:
245 case Format::NV21:
246 case Format::IYUV:
247 case Format::YUV444:
248 default:
249 ARM_COMPUTE_ERROR("Not supported data_type for given format");
250 return DataType::UNKNOWN;
251 }
252}
253
254/** Return the plane index of a given channel given an input format.
255 *
256 * @param[in] format Input format
257 * @param[in] channel Input channel
258 *
259 * @return The plane index of the specific channel of the specific format
260 */
261inline int plane_idx_from_channel(Format format, Channel channel)
262{
263 switch(format)
264 {
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100265 // Single planar formats have a single plane
266 case Format::U8:
267 case Format::U16:
268 case Format::S16:
269 case Format::U32:
270 case Format::S32:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000271 case Format::BFLOAT16:
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100272 case Format::F16:
273 case Format::F32:
274 case Format::UV88:
275 case Format::RGB888:
276 case Format::RGBA8888:
277 case Format::YUYV422:
278 case Format::UYVY422:
279 return 0;
280 // Multi planar formats
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100281 case Format::NV12:
282 case Format::NV21:
283 {
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100284 // Channel U and V share the same plane of format UV88
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100285 switch(channel)
286 {
287 case Channel::Y:
288 return 0;
289 case Channel::U:
290 case Channel::V:
291 return 1;
292 default:
293 ARM_COMPUTE_ERROR("Not supported channel");
294 return 0;
295 }
296 }
297 case Format::IYUV:
298 case Format::YUV444:
299 {
300 switch(channel)
301 {
302 case Channel::Y:
303 return 0;
304 case Channel::U:
305 return 1;
306 case Channel::V:
307 return 2;
308 default:
309 ARM_COMPUTE_ERROR("Not supported channel");
310 return 0;
311 }
312 }
313 default:
314 ARM_COMPUTE_ERROR("Not supported format");
315 return 0;
316 }
317}
318
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100319/** Return the channel index of a given channel given an input format.
320 *
321 * @param[in] format Input format
322 * @param[in] channel Input channel
323 *
324 * @return The channel index of the specific channel of the specific format
325 */
326inline int channel_idx_from_format(Format format, Channel channel)
327{
328 switch(format)
329 {
330 case Format::RGB888:
331 {
332 switch(channel)
333 {
334 case Channel::R:
335 return 0;
336 case Channel::G:
337 return 1;
338 case Channel::B:
339 return 2;
340 default:
341 ARM_COMPUTE_ERROR("Not supported channel");
342 return 0;
343 }
344 }
345 case Format::RGBA8888:
346 {
347 switch(channel)
348 {
349 case Channel::R:
350 return 0;
351 case Channel::G:
352 return 1;
353 case Channel::B:
354 return 2;
355 case Channel::A:
356 return 3;
357 default:
358 ARM_COMPUTE_ERROR("Not supported channel");
359 return 0;
360 }
361 }
362 case Format::YUYV422:
363 {
364 switch(channel)
365 {
366 case Channel::Y:
367 return 0;
368 case Channel::U:
369 return 1;
370 case Channel::V:
371 return 3;
372 default:
373 ARM_COMPUTE_ERROR("Not supported channel");
374 return 0;
375 }
376 }
377 case Format::UYVY422:
378 {
379 switch(channel)
380 {
381 case Channel::Y:
382 return 1;
383 case Channel::U:
384 return 0;
385 case Channel::V:
386 return 2;
387 default:
388 ARM_COMPUTE_ERROR("Not supported channel");
389 return 0;
390 }
391 }
392 case Format::NV12:
393 {
394 switch(channel)
395 {
396 case Channel::Y:
397 return 0;
398 case Channel::U:
399 return 0;
400 case Channel::V:
401 return 1;
402 default:
403 ARM_COMPUTE_ERROR("Not supported channel");
404 return 0;
405 }
406 }
407 case Format::NV21:
408 {
409 switch(channel)
410 {
411 case Channel::Y:
412 return 0;
413 case Channel::U:
414 return 1;
415 case Channel::V:
416 return 0;
417 default:
418 ARM_COMPUTE_ERROR("Not supported channel");
419 return 0;
420 }
421 }
422 case Format::YUV444:
423 case Format::IYUV:
424 {
425 switch(channel)
426 {
427 case Channel::Y:
428 return 0;
429 case Channel::U:
430 return 0;
431 case Channel::V:
432 return 0;
433 default:
434 ARM_COMPUTE_ERROR("Not supported channel");
435 return 0;
436 }
437 }
438 default:
439 ARM_COMPUTE_ERROR("Not supported format");
440 return 0;
441 }
442}
443
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100444/** Return the number of planes for a given format
445 *
446 * @param[in] format Input format
447 *
448 * @return The number of planes for a given image format.
449 */
450inline size_t num_planes_from_format(Format format)
451{
452 switch(format)
453 {
454 case Format::U8:
455 case Format::S16:
456 case Format::U16:
457 case Format::S32:
458 case Format::U32:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000459 case Format::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100460 case Format::F16:
461 case Format::F32:
462 case Format::RGB888:
463 case Format::RGBA8888:
464 case Format::YUYV422:
465 case Format::UYVY422:
466 return 1;
467 case Format::NV12:
468 case Format::NV21:
469 return 2;
470 case Format::IYUV:
471 case Format::YUV444:
472 return 3;
473 default:
474 ARM_COMPUTE_ERROR("Not supported format");
475 return 0;
476 }
477}
478
479/** Return the number of channels for a given single-planar pixel format
480 *
481 * @param[in] format Input format
482 *
483 * @return The number of channels for a given image format.
484 */
485inline size_t num_channels_from_format(Format format)
486{
487 switch(format)
488 {
489 case Format::U8:
490 case Format::U16:
491 case Format::S16:
492 case Format::U32:
493 case Format::S32:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000494 case Format::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100495 case Format::F16:
496 case Format::F32:
497 return 1;
498 // Because the U and V channels are subsampled
499 // these formats appear like having only 2 channels:
500 case Format::YUYV422:
501 case Format::UYVY422:
502 return 2;
503 case Format::UV88:
504 return 2;
505 case Format::RGB888:
506 return 3;
507 case Format::RGBA8888:
508 return 4;
509 //Doesn't make sense for planar formats:
510 case Format::NV12:
511 case Format::NV21:
512 case Format::IYUV:
513 case Format::YUV444:
514 default:
515 return 0;
516 }
517}
518
Chunosovd621bca2017-11-03 17:33:15 +0700519/** Return the promoted data type of a given data type.
520 *
521 * @note If promoted data type is not supported an error will be thrown
522 *
523 * @param[in] dt Data type to get the promoted type of.
524 *
525 * @return Promoted data type
526 */
527inline DataType get_promoted_data_type(DataType dt)
528{
529 switch(dt)
530 {
531 case DataType::U8:
532 return DataType::U16;
533 case DataType::S8:
534 return DataType::S16;
Chunosovd621bca2017-11-03 17:33:15 +0700535 case DataType::U16:
536 return DataType::U32;
537 case DataType::S16:
538 return DataType::S32;
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100539 case DataType::QSYMM8:
Chunosovd621bca2017-11-03 17:33:15 +0700540 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100541 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100542 case DataType::QSYMM8_PER_CHANNEL:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100543 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100544 case DataType::QASYMM16:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000545 case DataType::BFLOAT16:
Chunosovd621bca2017-11-03 17:33:15 +0700546 case DataType::F16:
547 case DataType::U32:
548 case DataType::S32:
549 case DataType::F32:
Chunosovd621bca2017-11-03 17:33:15 +0700550 ARM_COMPUTE_ERROR("Unsupported data type promotions!");
551 default:
552 ARM_COMPUTE_ERROR("Undefined data type!");
553 }
554 return DataType::UNKNOWN;
555}
556
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000557/** Compute the mininum and maximum values a data type can take
558 *
559 * @param[in] dt Data type to get the min/max bounds of
560 *
561 * @return A tuple (min,max) with the minimum and maximum values respectively wrapped in PixelValue.
562 */
563inline std::tuple<PixelValue, PixelValue> get_min_max(DataType dt)
564{
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000565 PixelValue min{};
566 PixelValue max{};
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000567 switch(dt)
568 {
569 case DataType::U8:
570 case DataType::QASYMM8:
571 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000572 min = PixelValue(static_cast<int32_t>(std::numeric_limits<uint8_t>::lowest()));
573 max = PixelValue(static_cast<int32_t>(std::numeric_limits<uint8_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000574 break;
575 }
576 case DataType::S8:
577 case DataType::QSYMM8:
578 case DataType::QASYMM8_SIGNED:
579 case DataType::QSYMM8_PER_CHANNEL:
580 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000581 min = PixelValue(static_cast<int32_t>(std::numeric_limits<int8_t>::lowest()));
582 max = PixelValue(static_cast<int32_t>(std::numeric_limits<int8_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000583 break;
584 }
585 case DataType::U16:
586 case DataType::QASYMM16:
587 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000588 min = PixelValue(static_cast<int32_t>(std::numeric_limits<uint16_t>::lowest()));
589 max = PixelValue(static_cast<int32_t>(std::numeric_limits<uint16_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000590 break;
591 }
592 case DataType::S16:
593 case DataType::QSYMM16:
594 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000595 min = PixelValue(static_cast<int32_t>(std::numeric_limits<int16_t>::lowest()));
596 max = PixelValue(static_cast<int32_t>(std::numeric_limits<int16_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000597 break;
598 }
599 case DataType::U32:
600 {
601 min = PixelValue(std::numeric_limits<uint32_t>::lowest());
602 max = PixelValue(std::numeric_limits<uint32_t>::max());
603 break;
604 }
605 case DataType::S32:
606 {
607 min = PixelValue(std::numeric_limits<int32_t>::lowest());
608 max = PixelValue(std::numeric_limits<int32_t>::max());
609 break;
610 }
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000611 case DataType::BFLOAT16:
612 {
613 min = PixelValue(bfloat16::lowest());
614 max = PixelValue(bfloat16::max());
615 break;
616 }
Luca Foschianiee939fb2020-01-28 10:38:07 +0000617 case DataType::F16:
618 {
619 min = PixelValue(std::numeric_limits<half>::lowest());
620 max = PixelValue(std::numeric_limits<half>::max());
621 break;
622 }
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000623 case DataType::F32:
624 {
625 min = PixelValue(std::numeric_limits<float>::lowest());
626 max = PixelValue(std::numeric_limits<float>::max());
627 break;
628 }
629 default:
630 ARM_COMPUTE_ERROR("Undefined data type!");
631 }
632 return std::make_tuple(min, max);
633}
634
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100635/** Return true if the given format has horizontal subsampling.
636 *
637 * @param[in] format Format to determine subsampling.
638 *
639 * @return True if the format can be subsampled horizontaly.
640 */
641inline bool has_format_horizontal_subsampling(Format format)
642{
643 return (format == Format::YUYV422 || format == Format::UYVY422 || format == Format::NV12 || format == Format::NV21 || format == Format::IYUV || format == Format::UV88) ? true : false;
644}
645
646/** Return true if the given format has vertical subsampling.
647 *
648 * @param[in] format Format to determine subsampling.
649 *
650 * @return True if the format can be subsampled verticaly.
651 */
652inline bool has_format_vertical_subsampling(Format format)
653{
654 return (format == Format::NV12 || format == Format::NV21 || format == Format::IYUV || format == Format::UV88) ? true : false;
655}
656
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100657/** Separate a 2D convolution into two 1D convolutions
Anthony Barbierf202e502017-11-23 18:02:04 +0000658 *
659 * @param[in] conv 2D convolution
660 * @param[out] conv_col 1D vertical convolution
661 * @param[out] conv_row 1D horizontal convolution
662 * @param[in] size Size of the 2D convolution
663 *
664 * @return true if the separation was successful
665 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100666inline bool separate_matrix(const int16_t *conv, int16_t *conv_col, int16_t *conv_row, uint8_t size)
667{
668 int32_t min_col = -1;
669 int16_t min_col_val = -1;
670
671 for(int32_t i = 0; i < size; ++i)
672 {
673 if(conv[i] != 0 && (min_col < 0 || abs(min_col_val) > abs(conv[i])))
674 {
675 min_col = i;
676 min_col_val = conv[i];
677 }
678 }
679
680 if(min_col < 0)
681 {
682 return false;
683 }
684
685 for(uint32_t j = 0; j < size; ++j)
686 {
687 conv_col[j] = conv[min_col + j * size];
688 }
689
690 for(uint32_t i = 0; i < size; i++)
691 {
692 if(static_cast<int>(i) == min_col)
693 {
694 conv_row[i] = 1;
695 }
696 else
697 {
698 int16_t coeff = conv[i] / conv[min_col];
699
700 for(uint32_t j = 1; j < size; ++j)
701 {
702 if(conv[i + j * size] != (conv_col[j] * coeff))
703 {
704 return false;
705 }
706 }
707
708 conv_row[i] = coeff;
709 }
710 }
711
712 return true;
713}
714
715/** Calculate the scale of the given square matrix
716 *
717 * The scale is the absolute value of the sum of all the coefficients in the matrix.
718 *
719 * @note If the coefficients add up to 0 then the scale is set to 1.
720 *
721 * @param[in] matrix Matrix coefficients
722 * @param[in] matrix_size Number of elements per side of the square matrix. (Number of coefficients = matrix_size * matrix_size).
723 *
724 * @return The absolute value of the sum of the coefficients if they don't add up to 0, otherwise 1.
725 */
726inline uint32_t calculate_matrix_scale(const int16_t *matrix, unsigned int matrix_size)
727{
728 const size_t size = matrix_size * matrix_size;
729
730 return std::max(1, std::abs(std::accumulate(matrix, matrix + size, 0)));
731}
732
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100733/** Adjust tensor shape size if width or height are odd for a given multi-planar format. No modification is done for other formats.
734 *
735 * @note Adding here a few links discussing the issue of odd size and sharing the same solution:
Manuel Bottini581c8982019-02-07 10:31:57 +0000736 * <a href="https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/graphics/java/android/graphics/YuvImage.java">Android Source</a>
737 * <a href="https://groups.google.com/a/webmproject.org/forum/#!topic/webm-discuss/LaCKpqiDTXM">WebM</a>
738 * <a href="https://bugs.chromium.org/p/libyuv/issues/detail?id=198&amp;can=1&amp;q=odd%20width">libYUV</a>
739 * <a href="https://sourceforge.net/p/raw-yuvplayer/bugs/1/">YUVPlayer</a> *
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100740 *
741 * @param[in, out] shape Tensor shape of 2D size
742 * @param[in] format Format of the tensor
743 *
Alex Gildayc357c472018-03-21 13:54:09 +0000744 * @return The adjusted tensor shape.
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100745 */
746inline TensorShape adjust_odd_shape(const TensorShape &shape, Format format)
747{
748 TensorShape output{ shape };
749
750 // Force width to be even for formats which require subsampling of the U and V channels
751 if(has_format_horizontal_subsampling(format))
752 {
753 output.set(0, output.x() & ~1U);
754 }
755
756 // Force height to be even for formats which require subsampling of the U and V channels
757 if(has_format_vertical_subsampling(format))
758 {
759 output.set(1, output.y() & ~1U);
760 }
761
762 return output;
763}
764
765/** Calculate subsampled shape for a given format and channel
766 *
767 * @param[in] shape Shape of the tensor to calculate the extracted channel.
768 * @param[in] format Format of the tensor.
769 * @param[in] channel Channel to create tensor shape to be extracted.
770 *
771 * @return The subsampled tensor shape.
772 */
773inline TensorShape calculate_subsampled_shape(const TensorShape &shape, Format format, Channel channel = Channel::UNKNOWN)
774{
775 TensorShape output{ shape };
776
777 // Subsample shape only for U or V channel
778 if(Channel::U == channel || Channel::V == channel || Channel::UNKNOWN == channel)
779 {
780 // Subsample width for the tensor shape when channel is U or V
781 if(has_format_horizontal_subsampling(format))
782 {
783 output.set(0, output.x() / 2U);
784 }
785
786 // Subsample height for the tensor shape when channel is U or V
787 if(has_format_vertical_subsampling(format))
788 {
789 output.set(1, output.y() / 2U);
790 }
791 }
792
793 return output;
794}
795
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100796/** Calculate accurary required by the horizontal and vertical convolution computations
797 *
798 * @param[in] conv_col Pointer to the vertical vector of the separated convolution filter
799 * @param[in] conv_row Pointer to the horizontal vector of the convolution filter
800 * @param[in] size Number of elements per vector of the separated matrix
801 *
802 * @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
803 * element of the pair is the biggest data type needed for the second stage.
804 */
805inline std::pair<DataType, DataType> data_type_for_convolution(const int16_t *conv_col, const int16_t *conv_row, size_t size)
806{
807 DataType first_stage = DataType::UNKNOWN;
808 DataType second_stage = DataType::UNKNOWN;
809
810 auto gez = [](const int16_t &v)
811 {
812 return v >= 0;
813 };
814
815 auto accu_neg = [](const int &first, const int &second)
816 {
817 return first + (second < 0 ? second : 0);
818 };
819
820 auto accu_pos = [](const int &first, const int &second)
821 {
822 return first + (second > 0 ? second : 0);
823 };
824
825 const bool only_positive_coefficients = std::all_of(conv_row, conv_row + size, gez) && std::all_of(conv_col, conv_col + size, gez);
826
827 if(only_positive_coefficients)
828 {
829 const int max_row_value = std::accumulate(conv_row, conv_row + size, 0) * UINT8_MAX;
830 const int max_value = std::accumulate(conv_col, conv_col + size, 0) * max_row_value;
831
832 first_stage = (max_row_value <= UINT16_MAX) ? DataType::U16 : DataType::S32;
833
834 second_stage = (max_value <= UINT16_MAX) ? DataType::U16 : DataType::S32;
835 }
836 else
837 {
838 const int min_row_value = std::accumulate(conv_row, conv_row + size, 0, accu_neg) * UINT8_MAX;
839 const int max_row_value = std::accumulate(conv_row, conv_row + size, 0, accu_pos) * UINT8_MAX;
840 const int neg_coeffs_sum = std::accumulate(conv_col, conv_col + size, 0, accu_neg);
841 const int pos_coeffs_sum = std::accumulate(conv_col, conv_col + size, 0, accu_pos);
842 const int min_value = neg_coeffs_sum * max_row_value + pos_coeffs_sum * min_row_value;
843 const int max_value = neg_coeffs_sum * min_row_value + pos_coeffs_sum * max_row_value;
844
845 first_stage = ((INT16_MIN <= min_row_value) && (max_row_value <= INT16_MAX)) ? DataType::S16 : DataType::S32;
846
847 second_stage = ((INT16_MIN <= min_value) && (max_value <= INT16_MAX)) ? DataType::S16 : DataType::S32;
848 }
849
850 return std::make_pair(first_stage, second_stage);
851}
852
853/** Calculate the accuracy required by the squared convolution calculation.
854 *
855 *
856 * @param[in] conv Pointer to the squared convolution matrix
857 * @param[in] size The total size of the convolution matrix
858 *
859 * @return The return is the biggest data type needed to do the convolution
860 */
861inline DataType data_type_for_convolution_matrix(const int16_t *conv, size_t size)
862{
863 auto gez = [](const int16_t v)
864 {
865 return v >= 0;
866 };
867
868 const bool only_positive_coefficients = std::all_of(conv, conv + size, gez);
869
870 if(only_positive_coefficients)
871 {
872 const int max_conv_value = std::accumulate(conv, conv + size, 0) * UINT8_MAX;
873 if(max_conv_value <= UINT16_MAX)
874 {
875 return DataType::U16;
876 }
877 else
878 {
879 return DataType::S32;
880 }
881 }
882 else
883 {
884 const int min_value = std::accumulate(conv, conv + size, 0, [](int a, int b)
885 {
886 return b < 0 ? a + b : a;
887 })
888 * UINT8_MAX;
889
890 const int max_value = std::accumulate(conv, conv + size, 0, [](int a, int b)
891 {
892 return b > 0 ? a + b : a;
893 })
894 * UINT8_MAX;
895
896 if((INT16_MIN <= min_value) && (INT16_MAX >= max_value))
897 {
898 return DataType::S16;
899 }
900 else
901 {
902 return DataType::S32;
903 }
904 }
905}
906
Pablo Tello35767bc2018-12-05 17:36:30 +0000907/** Permutes the given dimensions according the permutation vector
908 *
909 * @param[in,out] dimensions Dimensions to be permuted.
910 * @param[in] perm Vector describing the permutation.
911 *
912 */
913template <typename T>
914inline void permute_strides(Dimensions<T> &dimensions, const PermutationVector &perm)
915{
916 const auto old_dim = utility::make_array<Dimensions<T>::num_max_dimensions>(dimensions.begin(), dimensions.end());
917 for(unsigned int i = 0; i < perm.num_dimensions(); ++i)
918 {
919 T dimension_val = old_dim[i];
920 dimensions.set(perm[i], dimension_val);
921 }
922}
923
Georgios Pinitas4074c992018-01-30 18:13:46 +0000924/** Calculate padding requirements in case of SAME padding
925 *
926 * @param[in] input_shape Input shape
927 * @param[in] weights_shape Weights shape
928 * @param[in] conv_info Convolution information (containing strides)
Isabella Gottardi6a914402019-01-30 15:45:42 +0000929 * @param[in] data_layout (Optional) Data layout of the input and weights tensor
Pablo Tello01bbacb2019-04-30 10:32:42 +0100930 * @param[in] dilation (Optional) Dilation factor used in the convolution.
Giorgio Arena17203582019-08-02 16:00:41 +0100931 * @param[in] rounding_type (Optional) Dimension rounding type when down-scaling.
Georgios Pinitas4074c992018-01-30 18:13:46 +0000932 *
933 * @return PadStrideInfo for SAME padding
934 */
Giorgio Arena17203582019-08-02 16:00:41 +0100935PadStrideInfo calculate_same_pad(TensorShape input_shape, TensorShape weights_shape, PadStrideInfo conv_info, DataLayout data_layout = DataLayout::NCHW, const Size2D &dilation = Size2D(1u, 1u),
936 const DimensionRoundingType &rounding_type = DimensionRoundingType::FLOOR);
Georgios Pinitas4074c992018-01-30 18:13:46 +0000937
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100938/** Returns expected width and height of the deconvolution's output tensor.
939 *
Matthew Jacksonb9070a42019-08-22 16:13:27 +0100940 * @param[in] in_width Width of input tensor (Number of columns)
941 * @param[in] in_height Height of input tensor (Number of rows)
942 * @param[in] kernel_width Kernel width.
943 * @param[in] kernel_height Kernel height.
944 * @param[in] pad_stride_info Pad and stride information.
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100945 *
946 * @return A pair with the new width in the first position and the new height in the second.
947 */
Pablo Tello01bbacb2019-04-30 10:32:42 +0100948std::pair<unsigned int, unsigned int> deconvolution_output_dimensions(unsigned int in_width, unsigned int in_height,
949 unsigned int kernel_width, unsigned int kernel_height,
Matthew Jacksonb9070a42019-08-22 16:13:27 +0100950 const PadStrideInfo &pad_stride_info);
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100951
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100952/** Returns expected width and height of output scaled tensor depending on dimensions rounding mode.
953 *
Gian Marco Iodice4e288692017-06-27 11:41:59 +0100954 * @param[in] width Width of input tensor (Number of columns)
955 * @param[in] height Height of input tensor (Number of rows)
956 * @param[in] kernel_width Kernel width.
957 * @param[in] kernel_height Kernel height.
958 * @param[in] pad_stride_info Pad and stride information.
Alex Gilday7da29b62018-03-23 14:16:00 +0000959 * @param[in] dilation (Optional) Dilation, in elements, across x and y. Defaults to (1, 1).
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100960 *
961 * @return A pair with the new width in the first position and the new height in the second.
962 */
Georgios Pinitas80838f12019-12-12 18:23:13 +0000963std::pair<unsigned int, unsigned int> scaled_dimensions(int width, int height,
964 int kernel_width, int kernel_height,
Pablo Tello01bbacb2019-04-30 10:32:42 +0100965 const PadStrideInfo &pad_stride_info,
966 const Size2D &dilation = Size2D(1U, 1U));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100967
Sang-Hoon Park2697fd82019-10-15 16:49:24 +0100968/** Check if the given reduction operation should be handled in a serial way.
969 *
970 * @param[in] op Reduction operation to perform
971 * @param[in] dt Data type
972 * @param[in] axis Axis along which to reduce
973 *
974 * @return True if the given reduction operation should be handled in a serial way.
975 */
976bool needs_serialized_reduction(ReductionOperation op, DataType dt, unsigned int axis);
977
Sang-Hoon Park0779fec2019-11-13 17:08:12 +0000978/** Returns output quantization information for softmax layer
979 *
980 * @param[in] input_type The data type of the input tensor
981 * @param[in] is_log True for log softmax
982 *
983 * @return Quantization information for the output tensor
984 */
985QuantizationInfo get_softmax_output_quantization_info(DataType input_type, bool is_log);
986
Sang-Hoon Park4715cf92020-01-08 16:02:47 +0000987/** Returns a pair of minimum and maximum values for a quantized activation
988 *
989 * @param[in] act_info The information for activation
990 * @param[in] data_type The used data type
991 * @param[in] oq_info The output quantization information
992 *
993 * @return The pair with minimum and maximum values
994 */
995std::pair<int32_t, int32_t> get_quantized_activation_min_max(ActivationLayerInfo act_info, DataType data_type, UniformQuantizationInfo oq_info);
996
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100997/** Convert a tensor format into a string.
998 *
999 * @param[in] format @ref Format to be translated to string.
1000 *
1001 * @return The string describing the format.
1002 */
1003const std::string &string_from_format(Format format);
1004
1005/** Convert a channel identity into a string.
1006 *
1007 * @param[in] channel @ref Channel to be translated to string.
1008 *
1009 * @return The string describing the channel.
1010 */
1011const std::string &string_from_channel(Channel channel);
Michele Di Giorgiobf3c6622018-03-08 11:52:27 +00001012/** Convert a data layout identity into a string.
1013 *
1014 * @param[in] dl @ref DataLayout to be translated to string.
1015 *
1016 * @return The string describing the data layout.
1017 */
1018const std::string &string_from_data_layout(DataLayout dl);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001019/** Convert a data type identity into a string.
1020 *
1021 * @param[in] dt @ref DataType to be translated to string.
1022 *
1023 * @return The string describing the data type.
1024 */
1025const std::string &string_from_data_type(DataType dt);
1026/** Convert a matrix pattern into a string.
1027 *
1028 * @param[in] pattern @ref MatrixPattern to be translated to string.
1029 *
1030 * @return The string describing the matrix pattern.
1031 */
1032const std::string &string_from_matrix_pattern(MatrixPattern pattern);
1033/** Translates a given activation function to a string.
1034 *
1035 * @param[in] act @ref ActivationLayerInfo::ActivationFunction to be translated to string.
1036 *
1037 * @return The string describing the activation function.
1038 */
1039const std::string &string_from_activation_func(ActivationLayerInfo::ActivationFunction act);
1040/** Translates a given non linear function to a string.
1041 *
1042 * @param[in] function @ref NonLinearFilterFunction to be translated to string.
1043 *
1044 * @return The string describing the non linear function.
1045 */
1046const std::string &string_from_non_linear_filter_function(NonLinearFilterFunction function);
1047/** Translates a given interpolation policy to a string.
1048 *
1049 * @param[in] policy @ref InterpolationPolicy to be translated to string.
1050 *
1051 * @return The string describing the interpolation policy.
1052 */
1053const std::string &string_from_interpolation_policy(InterpolationPolicy policy);
1054/** Translates a given border mode policy to a string.
1055 *
1056 * @param[in] border_mode @ref BorderMode to be translated to string.
1057 *
1058 * @return The string describing the border mode.
1059 */
1060const std::string &string_from_border_mode(BorderMode border_mode);
1061/** Translates a given normalization type to a string.
1062 *
1063 * @param[in] type @ref NormType to be translated to string.
1064 *
1065 * @return The string describing the normalization type.
1066 */
1067const std::string &string_from_norm_type(NormType type);
Georgios Pinitascdf51452017-08-31 14:21:36 +01001068/** Translates a given pooling type to a string.
1069 *
1070 * @param[in] type @ref PoolingType to be translated to string.
1071 *
1072 * @return The string describing the pooling type.
1073 */
1074const std::string &string_from_pooling_type(PoolingType type);
Gian Marco Iodice4b908652018-10-18 10:21:02 +01001075/** Translates a given GEMMLowp output stage to a string.
1076 *
1077 * @param[in] output_stage @ref GEMMLowpOutputStageInfo to be translated to string.
1078 *
1079 * @return The string describing the GEMMLowp output stage
1080 */
1081const std::string &string_from_gemmlowp_output_stage(GEMMLowpOutputStageType output_stage);
Giuseppe Rossinid7647d42018-07-17 18:13:13 +01001082/** Convert a PixelValue to a string, represented through the specific data type
1083 *
1084 * @param[in] value The PixelValue to convert
1085 * @param[in] data_type The type to be used to convert the @p value
1086 *
1087 * @return String representation of the PixelValue through the given data type.
1088 */
1089std::string string_from_pixel_value(const PixelValue &value, const DataType data_type);
SiCong Lie357a252020-08-09 20:05:52 +01001090/** Convert a string to DataType
1091 *
1092 * @param[in] name The name of the data type
1093 *
1094 * @return DataType
1095 */
1096DataType data_type_from_name(const std::string &name);
Giorgio Arena1e2af2a2020-10-15 17:39:41 +01001097/** Stores padding information before configuring a kernel
1098 *
1099 * @param[in] tensors list of tensors to store the padding info for
1100 *
1101 * @return An unordered map where each tensor pointer is paired with its original padding info
1102 */
1103std::unordered_map<const ITensor *, PaddingSize> get_padding_info(std::initializer_list<const ITensor *> tensors);
1104/** Check if the previously stored padding info has changed after configuring a kernel
1105 *
1106 * @param[in] padding_map an unordered map where each tensor pointer is paired with its original padding info
1107 *
1108 * @return true if any of the tensors has changed its paddings
1109 */
1110bool has_padding_changed(const std::unordered_map<const ITensor *, PaddingSize> &padding_map);
1111
SiCong Lie357a252020-08-09 20:05:52 +01001112/** Input Stream operator for @ref DataType
1113 *
1114 * @param[in] stream Stream to parse
1115 * @param[out] data_type Output data type
1116 *
1117 * @return Updated stream
1118 */
1119inline ::std::istream &operator>>(::std::istream &stream, DataType &data_type)
1120{
1121 std::string value;
1122 stream >> value;
1123 data_type = data_type_from_name(value);
1124 return stream;
1125}
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001126/** Lower a given string.
1127 *
1128 * @param[in] val Given string to lower.
1129 *
1130 * @return The lowered string
1131 */
1132std::string lower_string(const std::string &val);
1133
1134/** Check if a given data type is of floating point type
1135 *
1136 * @param[in] dt Input data type.
1137 *
1138 * @return True if data type is of floating point type, else false.
1139 */
1140inline bool is_data_type_float(DataType dt)
1141{
1142 switch(dt)
1143 {
1144 case DataType::F16:
1145 case DataType::F32:
1146 return true;
1147 default:
1148 return false;
1149 }
1150}
1151
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001152/** Check if a given data type is of quantized type
1153 *
1154 * @note Quantized is considered a super-set of fixed-point and asymmetric data types.
1155 *
1156 * @param[in] dt Input data type.
1157 *
1158 * @return True if data type is of quantized type, else false.
1159 */
1160inline bool is_data_type_quantized(DataType dt)
1161{
1162 switch(dt)
1163 {
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001164 case DataType::QSYMM8:
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001165 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001166 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001167 case DataType::QSYMM8_PER_CHANNEL:
Manuel Bottini3689fcd2019-06-14 17:18:12 +01001168 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +01001169 case DataType::QASYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001170 return true;
1171 default:
1172 return false;
1173 }
1174}
1175
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001176/** Check if a given data type is of asymmetric quantized type
1177 *
1178 * @param[in] dt Input data type.
1179 *
Michele Di Giorgio6997fc92019-06-18 10:23:22 +01001180 * @return True if data type is of asymmetric quantized type, else false.
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001181 */
Anton Lokhmotovaf6204c2017-11-08 09:34:19 +00001182inline bool is_data_type_quantized_asymmetric(DataType dt)
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001183{
1184 switch(dt)
1185 {
1186 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001187 case DataType::QASYMM8_SIGNED:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +01001188 case DataType::QASYMM16:
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001189 return true;
1190 default:
1191 return false;
1192 }
1193}
1194
Georgios Pinitas6e1791b2019-12-02 19:01:25 +00001195/** Check if a given data type is of asymmetric quantized signed type
1196 *
1197 * @param[in] dt Input data type.
1198 *
1199 * @return True if data type is of asymmetric quantized signed type, else false.
1200 */
1201inline bool is_data_type_quantized_asymmetric_signed(DataType dt)
1202{
1203 switch(dt)
1204 {
1205 case DataType::QASYMM8_SIGNED:
1206 return true;
1207 default:
1208 return false;
1209 }
1210}
1211
Michele Di Giorgio6997fc92019-06-18 10:23:22 +01001212/** Check if a given data type is of symmetric quantized type
1213 *
1214 * @param[in] dt Input data type.
1215 *
1216 * @return True if data type is of symmetric quantized type, else false.
1217 */
1218inline bool is_data_type_quantized_symmetric(DataType dt)
1219{
1220 switch(dt)
1221 {
1222 case DataType::QSYMM8:
1223 case DataType::QSYMM8_PER_CHANNEL:
1224 case DataType::QSYMM16:
1225 return true;
1226 default:
1227 return false;
1228 }
1229}
1230
Michalis Spyrouc8530212019-08-22 11:44:04 +01001231/** Check if a given data type is of per channel type
1232 *
1233 * @param[in] dt Input data type.
1234 *
1235 * @return True if data type is of per channel type, else false.
1236 */
1237inline bool is_data_type_quantized_per_channel(DataType dt)
1238{
1239 switch(dt)
1240 {
1241 case DataType::QSYMM8_PER_CHANNEL:
Michalis Spyrouc8530212019-08-22 11:44:04 +01001242 return true;
1243 default:
1244 return false;
1245 }
1246}
1247
Georgios Pinitas89010962017-08-04 14:58:27 +01001248/** Create a string with the float in full precision.
1249 *
1250 * @param val Floating point value
1251 *
1252 * @return String with the floating point value.
1253 */
1254inline std::string float_to_string_with_full_precision(float val)
1255{
1256 std::stringstream ss;
Georgios Pinitas7900a9e2018-11-23 11:44:58 +00001257 ss.precision(std::numeric_limits<float>::max_digits10);
Georgios Pinitas89010962017-08-04 14:58:27 +01001258 ss << val;
Giorgio Arena73023022018-09-04 14:55:55 +01001259
1260 if(val != static_cast<int>(val))
1261 {
1262 ss << "f";
1263 }
1264
Georgios Pinitas89010962017-08-04 14:58:27 +01001265 return ss.str();
1266}
1267
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001268/** Returns the number of elements required to go from start to end with the wanted step
1269 *
1270 * @param[in] start start value
1271 * @param[in] end end value
1272 * @param[in] step step value between each number in the wanted sequence
1273 *
1274 * @return number of elements to go from start value to end value using the wanted step
1275 */
1276inline size_t num_of_elements_in_range(const float start, const float end, const float step)
1277{
1278 ARM_COMPUTE_ERROR_ON_MSG(step == 0, "Range Step cannot be 0");
1279 return size_t(std::ceil((end - start) / step));
1280}
1281
1282/** Returns true if the value can be represented by the given data type
1283 *
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001284 * @param[in] val value to be checked
1285 * @param[in] dt data type that is checked
1286 * @param[in] qinfo (Optional) quantization info if the data type is QASYMM8
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001287 *
1288 * @return true if the data type can hold the value.
1289 */
1290template <typename T>
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001291bool check_value_range(T val, DataType dt, QuantizationInfo qinfo = QuantizationInfo())
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001292{
1293 switch(dt)
1294 {
1295 case DataType::U8:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001296 {
1297 const auto val_u8 = static_cast<uint8_t>(val);
1298 return ((val_u8 == val) && val_u8 >= std::numeric_limits<uint8_t>::lowest() && val_u8 <= std::numeric_limits<uint8_t>::max());
1299 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001300 case DataType::QASYMM8:
1301 {
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001302 double min = static_cast<double>(dequantize_qasymm8(0, qinfo));
1303 double max = static_cast<double>(dequantize_qasymm8(std::numeric_limits<uint8_t>::max(), qinfo));
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001304 return ((double)val >= min && (double)val <= max);
1305 }
1306 case DataType::S8:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001307 {
1308 const auto val_s8 = static_cast<int8_t>(val);
1309 return ((val_s8 == val) && val_s8 >= std::numeric_limits<int8_t>::lowest() && val_s8 <= std::numeric_limits<int8_t>::max());
1310 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001311 case DataType::U16:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001312 {
1313 const auto val_u16 = static_cast<uint16_t>(val);
1314 return ((val_u16 == val) && val_u16 >= std::numeric_limits<uint16_t>::lowest() && val_u16 <= std::numeric_limits<uint16_t>::max());
1315 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001316 case DataType::S16:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001317 {
1318 const auto val_s16 = static_cast<int16_t>(val);
1319 return ((val_s16 == val) && val_s16 >= std::numeric_limits<int16_t>::lowest() && val_s16 <= std::numeric_limits<int16_t>::max());
1320 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001321 case DataType::U32:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001322 {
1323 const auto val_u32 = static_cast<uint32_t>(val);
1324 return ((val_u32 == val) && val_u32 >= std::numeric_limits<uint32_t>::lowest() && val_u32 <= std::numeric_limits<uint32_t>::max());
1325 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001326 case DataType::S32:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001327 {
1328 const auto val_s32 = static_cast<int32_t>(val);
1329 return ((val_s32 == val) && val_s32 >= std::numeric_limits<int32_t>::lowest() && val_s32 <= std::numeric_limits<int32_t>::max());
1330 }
Georgios Pinitase8291ac2020-02-26 09:58:13 +00001331 case DataType::BFLOAT16:
1332 return (val >= bfloat16::lowest() && val <= bfloat16::max());
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001333 case DataType::F16:
1334 return (val >= std::numeric_limits<half>::lowest() && val <= std::numeric_limits<half>::max());
1335 case DataType::F32:
1336 return (val >= std::numeric_limits<float>::lowest() && val <= std::numeric_limits<float>::max());
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001337 default:
1338 ARM_COMPUTE_ERROR("Data type not supported");
1339 return false;
1340 }
1341}
1342
Giorgio Arenad304adb2020-10-02 10:20:11 +01001343/** 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
1344 *
1345 * @param[in] vec_size vector size to be adjusted
1346 * @param[in] dim0 size of the first dimension
1347 *
1348 * @return the number of element processed along the X axis per thread
1349 */
1350inline unsigned int adjust_vec_size(unsigned int vec_size, size_t dim0)
1351{
1352 ARM_COMPUTE_ERROR_ON(vec_size > 16);
1353
Giorgio Arena79acd772020-10-22 14:29:50 +01001354 if((vec_size >= dim0) && (dim0 == 3))
Giorgio Arenad304adb2020-10-02 10:20:11 +01001355 {
1356 return dim0;
1357 }
1358
1359 while(vec_size > dim0)
1360 {
1361 vec_size >>= 1;
1362 }
1363
1364 return vec_size;
1365}
1366
giuros01edc21e42018-11-16 14:45:31 +00001367#ifdef ARM_COMPUTE_ASSERTS_ENABLED
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001368/** Print consecutive elements to an output stream.
1369 *
1370 * @param[out] s Output stream to print the elements to.
1371 * @param[in] ptr Pointer to print the elements from.
1372 * @param[in] n Number of elements to print.
1373 * @param[in] stream_width (Optional) Width of the stream. If set to 0 the element's width is used. Defaults to 0.
1374 * @param[in] element_delim (Optional) Delimeter among the consecutive elements. Defaults to space delimeter
1375 */
1376template <typename T>
1377void print_consecutive_elements_impl(std::ostream &s, const T *ptr, unsigned int n, int stream_width = 0, const std::string &element_delim = " ")
1378{
1379 using print_type = typename std::conditional<std::is_floating_point<T>::value, T, int>::type;
Michalis Spyrou53860dd2019-07-01 14:20:56 +01001380 std::ios stream_status(nullptr);
1381 stream_status.copyfmt(s);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001382
1383 for(unsigned int i = 0; i < n; ++i)
1384 {
1385 // Set stream width as it is not a "sticky" stream manipulator
1386 if(stream_width != 0)
1387 {
1388 s.width(stream_width);
1389 }
Anthony Barbier7068f992017-10-26 15:23:08 +01001390
1391 if(std::is_same<typename std::decay<T>::type, half>::value)
1392 {
1393 // 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.
1394 s << std::right << static_cast<T>(ptr[i]) << element_delim;
1395 }
Georgios Pinitase8291ac2020-02-26 09:58:13 +00001396 else if(std::is_same<typename std::decay<T>::type, bfloat16>::value)
1397 {
Georgios Pinitasc7b183a2020-03-06 18:12:09 +00001398 // 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 +00001399 s << std::right << float(ptr[i]) << element_delim;
1400 }
Anthony Barbier7068f992017-10-26 15:23:08 +01001401 else
1402 {
1403 s << std::right << static_cast<print_type>(ptr[i]) << element_delim;
1404 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001405 }
Michalis Spyrou53860dd2019-07-01 14:20:56 +01001406
1407 // Restore output stream flags
1408 s.copyfmt(stream_status);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001409}
1410
1411/** Identify the maximum width of n consecutive elements.
1412 *
1413 * @param[in] s The output stream which will be used to print the elements. Used to extract the stream format.
1414 * @param[in] ptr Pointer to the elements.
1415 * @param[in] n Number of elements.
1416 *
1417 * @return The maximum width of the elements.
1418 */
1419template <typename T>
1420int max_consecutive_elements_display_width_impl(std::ostream &s, const T *ptr, unsigned int n)
1421{
1422 using print_type = typename std::conditional<std::is_floating_point<T>::value, T, int>::type;
1423
1424 int max_width = -1;
1425 for(unsigned int i = 0; i < n; ++i)
1426 {
1427 std::stringstream ss;
1428 ss.copyfmt(s);
Anthony Barbier7068f992017-10-26 15:23:08 +01001429
1430 if(std::is_same<typename std::decay<T>::type, half>::value)
1431 {
1432 // 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.
1433 ss << static_cast<T>(ptr[i]);
1434 }
Georgios Pinitase8291ac2020-02-26 09:58:13 +00001435 else if(std::is_same<typename std::decay<T>::type, bfloat16>::value)
1436 {
1437 // 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.
1438 ss << float(ptr[i]);
1439 }
Anthony Barbier7068f992017-10-26 15:23:08 +01001440 else
1441 {
1442 ss << static_cast<print_type>(ptr[i]);
1443 }
1444
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001445 max_width = std::max<int>(max_width, ss.str().size());
1446 }
1447 return max_width;
1448}
1449
1450/** Print consecutive elements to an output stream.
1451 *
1452 * @param[out] s Output stream to print the elements to.
1453 * @param[in] dt Data type of the elements
1454 * @param[in] ptr Pointer to print the elements from.
1455 * @param[in] n Number of elements to print.
1456 * @param[in] stream_width (Optional) Width of the stream. If set to 0 the element's width is used. Defaults to 0.
1457 * @param[in] element_delim (Optional) Delimeter among the consecutive elements. Defaults to space delimeter
1458 */
1459void print_consecutive_elements(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n, int stream_width, const std::string &element_delim = " ");
1460
1461/** Identify the maximum width of n consecutive elements.
1462 *
1463 * @param[in] s Output stream to print the elements to.
1464 * @param[in] dt Data type of the elements
1465 * @param[in] ptr Pointer to print the elements from.
1466 * @param[in] n Number of elements to print.
1467 *
1468 * @return The maximum width of the elements.
1469 */
1470int max_consecutive_elements_display_width(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n);
giuros01edc21e42018-11-16 14:45:31 +00001471#endif /* ARM_COMPUTE_ASSERTS_ENABLED */
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001472}
Michalis Spyrouf4643372019-11-29 16:17:13 +00001473#endif /*ARM_COMPUTE_UTILS_H */