blob: 13c2971930eeb8ab378026da10701d304dcf1026 [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>
41#include <utility>
steniu017ce53c62017-09-29 14:55:00 +010042#include <vector>
Anthony Barbier6ff3b192017-09-04 18:44:23 +010043
44namespace arm_compute
45{
Alex Gildayc357c472018-03-21 13:54:09 +000046/** Calculate the rounded up quotient of val / m.
47 *
48 * @param[in] val Value to divide and round up.
49 * @param[in] m Value to divide by.
50 *
51 * @return the result.
52 */
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +000053template <typename S, typename T>
54constexpr auto DIV_CEIL(S val, T m) -> decltype((val + m - 1) / m)
55{
56 return (val + m - 1) / m;
57}
58
Alex Gildayc357c472018-03-21 13:54:09 +000059/** Computes the smallest number larger or equal to value that is a multiple of divisor.
60 *
61 * @param[in] value Lower bound value
62 * @param[in] divisor Value to compute multiple of.
63 *
64 * @return the result.
65 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010066template <typename S, typename T>
67inline auto ceil_to_multiple(S value, T divisor) -> decltype(((value + divisor - 1) / divisor) * divisor)
68{
69 ARM_COMPUTE_ERROR_ON(value < 0 || divisor <= 0);
Diego Lopez Recas35ceeb22017-12-04 18:56:10 +000070 return DIV_CEIL(value, divisor) * divisor;
Anthony Barbier6ff3b192017-09-04 18:44:23 +010071}
72
Alex Gildayc357c472018-03-21 13:54:09 +000073/** Computes the largest number smaller or equal to value that is a multiple of divisor.
74 *
75 * @param[in] value Upper bound value
76 * @param[in] divisor Value to compute multiple of.
77 *
78 * @return the result.
79 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +010080template <typename S, typename T>
81inline auto floor_to_multiple(S value, T divisor) -> decltype((value / divisor) * divisor)
82{
83 ARM_COMPUTE_ERROR_ON(value < 0 || divisor <= 0);
84 return (value / divisor) * divisor;
85}
86
Anthony Barbier6ff3b192017-09-04 18:44:23 +010087/** Load an entire file in memory
88 *
89 * @param[in] filename Name of the file to read.
90 * @param[in] binary Is it a binary file ?
91 *
92 * @return The content of the file.
93 */
94std::string read_file(const std::string &filename, bool binary);
95
Anthony Barbier6ff3b192017-09-04 18:44:23 +010096/** The size in bytes of the data type
97 *
98 * @param[in] data_type Input data type
99 *
100 * @return The size in bytes of the data type
101 */
102inline size_t data_size_from_type(DataType data_type)
103{
104 switch(data_type)
105 {
106 case DataType::U8:
107 case DataType::S8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100108 case DataType::QSYMM8:
Michel Iwaniec00633802017-10-12 14:14:15 +0100109 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100110 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100111 case DataType::QSYMM8_PER_CHANNEL:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100112 return 1;
113 case DataType::U16:
114 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100115 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100116 case DataType::QASYMM16:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000117 case DataType::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100118 case DataType::F16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100119 return 2;
120 case DataType::F32:
121 case DataType::U32:
122 case DataType::S32:
123 return 4;
124 case DataType::F64:
125 case DataType::U64:
126 case DataType::S64:
127 return 8;
128 case DataType::SIZET:
129 return sizeof(size_t);
130 default:
131 ARM_COMPUTE_ERROR("Invalid data type");
132 return 0;
133 }
134}
135
136/** The size in bytes of the pixel format
137 *
138 * @param[in] format Input format
139 *
140 * @return The size in bytes of the pixel format
141 */
142inline size_t pixel_size_from_format(Format format)
143{
144 switch(format)
145 {
146 case Format::U8:
147 return 1;
148 case Format::U16:
149 case Format::S16:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000150 case Format::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100151 case Format::F16:
152 case Format::UV88:
153 case Format::YUYV422:
154 case Format::UYVY422:
155 return 2;
156 case Format::RGB888:
157 return 3;
158 case Format::RGBA8888:
159 return 4;
160 case Format::U32:
161 case Format::S32:
162 case Format::F32:
163 return 4;
164 //Doesn't make sense for planar formats:
165 case Format::NV12:
166 case Format::NV21:
167 case Format::IYUV:
168 case Format::YUV444:
169 default:
170 ARM_COMPUTE_ERROR("Undefined pixel size for given format");
171 return 0;
172 }
173}
174
175/** The size in bytes of the data type
176 *
177 * @param[in] dt Input data type
178 *
179 * @return The size in bytes of the data type
180 */
181inline size_t element_size_from_data_type(DataType dt)
182{
183 switch(dt)
184 {
185 case DataType::S8:
186 case DataType::U8:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100187 case DataType::QSYMM8:
Michel Iwaniec00633802017-10-12 14:14:15 +0100188 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100189 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100190 case DataType::QSYMM8_PER_CHANNEL:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100191 return 1;
192 case DataType::U16:
193 case DataType::S16:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100194 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100195 case DataType::QASYMM16:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000196 case DataType::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100197 case DataType::F16:
198 return 2;
199 case DataType::U32:
200 case DataType::S32:
201 case DataType::F32:
202 return 4;
203 default:
204 ARM_COMPUTE_ERROR("Undefined element size for given data type");
205 return 0;
206 }
207}
208
209/** Return the data type used by a given single-planar pixel format
210 *
211 * @param[in] format Input format
212 *
213 * @return The size in bytes of the pixel format
214 */
215inline DataType data_type_from_format(Format format)
216{
217 switch(format)
218 {
219 case Format::U8:
220 case Format::UV88:
221 case Format::RGB888:
222 case Format::RGBA8888:
223 case Format::YUYV422:
224 case Format::UYVY422:
225 return DataType::U8;
226 case Format::U16:
227 return DataType::U16;
228 case Format::S16:
229 return DataType::S16;
230 case Format::U32:
231 return DataType::U32;
232 case Format::S32:
233 return DataType::S32;
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000234 case Format::BFLOAT16:
235 return DataType::BFLOAT16;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100236 case Format::F16:
237 return DataType::F16;
238 case Format::F32:
239 return DataType::F32;
240 //Doesn't make sense for planar formats:
241 case Format::NV12:
242 case Format::NV21:
243 case Format::IYUV:
244 case Format::YUV444:
245 default:
246 ARM_COMPUTE_ERROR("Not supported data_type for given format");
247 return DataType::UNKNOWN;
248 }
249}
250
251/** Return the plane index of a given channel given an input format.
252 *
253 * @param[in] format Input format
254 * @param[in] channel Input channel
255 *
256 * @return The plane index of the specific channel of the specific format
257 */
258inline int plane_idx_from_channel(Format format, Channel channel)
259{
260 switch(format)
261 {
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100262 // Single planar formats have a single plane
263 case Format::U8:
264 case Format::U16:
265 case Format::S16:
266 case Format::U32:
267 case Format::S32:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000268 case Format::BFLOAT16:
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100269 case Format::F16:
270 case Format::F32:
271 case Format::UV88:
272 case Format::RGB888:
273 case Format::RGBA8888:
274 case Format::YUYV422:
275 case Format::UYVY422:
276 return 0;
277 // Multi planar formats
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100278 case Format::NV12:
279 case Format::NV21:
280 {
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100281 // Channel U and V share the same plane of format UV88
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100282 switch(channel)
283 {
284 case Channel::Y:
285 return 0;
286 case Channel::U:
287 case Channel::V:
288 return 1;
289 default:
290 ARM_COMPUTE_ERROR("Not supported channel");
291 return 0;
292 }
293 }
294 case Format::IYUV:
295 case Format::YUV444:
296 {
297 switch(channel)
298 {
299 case Channel::Y:
300 return 0;
301 case Channel::U:
302 return 1;
303 case Channel::V:
304 return 2;
305 default:
306 ARM_COMPUTE_ERROR("Not supported channel");
307 return 0;
308 }
309 }
310 default:
311 ARM_COMPUTE_ERROR("Not supported format");
312 return 0;
313 }
314}
315
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100316/** Return the channel index of a given channel given an input format.
317 *
318 * @param[in] format Input format
319 * @param[in] channel Input channel
320 *
321 * @return The channel index of the specific channel of the specific format
322 */
323inline int channel_idx_from_format(Format format, Channel channel)
324{
325 switch(format)
326 {
327 case Format::RGB888:
328 {
329 switch(channel)
330 {
331 case Channel::R:
332 return 0;
333 case Channel::G:
334 return 1;
335 case Channel::B:
336 return 2;
337 default:
338 ARM_COMPUTE_ERROR("Not supported channel");
339 return 0;
340 }
341 }
342 case Format::RGBA8888:
343 {
344 switch(channel)
345 {
346 case Channel::R:
347 return 0;
348 case Channel::G:
349 return 1;
350 case Channel::B:
351 return 2;
352 case Channel::A:
353 return 3;
354 default:
355 ARM_COMPUTE_ERROR("Not supported channel");
356 return 0;
357 }
358 }
359 case Format::YUYV422:
360 {
361 switch(channel)
362 {
363 case Channel::Y:
364 return 0;
365 case Channel::U:
366 return 1;
367 case Channel::V:
368 return 3;
369 default:
370 ARM_COMPUTE_ERROR("Not supported channel");
371 return 0;
372 }
373 }
374 case Format::UYVY422:
375 {
376 switch(channel)
377 {
378 case Channel::Y:
379 return 1;
380 case Channel::U:
381 return 0;
382 case Channel::V:
383 return 2;
384 default:
385 ARM_COMPUTE_ERROR("Not supported channel");
386 return 0;
387 }
388 }
389 case Format::NV12:
390 {
391 switch(channel)
392 {
393 case Channel::Y:
394 return 0;
395 case Channel::U:
396 return 0;
397 case Channel::V:
398 return 1;
399 default:
400 ARM_COMPUTE_ERROR("Not supported channel");
401 return 0;
402 }
403 }
404 case Format::NV21:
405 {
406 switch(channel)
407 {
408 case Channel::Y:
409 return 0;
410 case Channel::U:
411 return 1;
412 case Channel::V:
413 return 0;
414 default:
415 ARM_COMPUTE_ERROR("Not supported channel");
416 return 0;
417 }
418 }
419 case Format::YUV444:
420 case Format::IYUV:
421 {
422 switch(channel)
423 {
424 case Channel::Y:
425 return 0;
426 case Channel::U:
427 return 0;
428 case Channel::V:
429 return 0;
430 default:
431 ARM_COMPUTE_ERROR("Not supported channel");
432 return 0;
433 }
434 }
435 default:
436 ARM_COMPUTE_ERROR("Not supported format");
437 return 0;
438 }
439}
440
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100441/** Return the number of planes for a given format
442 *
443 * @param[in] format Input format
444 *
445 * @return The number of planes for a given image format.
446 */
447inline size_t num_planes_from_format(Format format)
448{
449 switch(format)
450 {
451 case Format::U8:
452 case Format::S16:
453 case Format::U16:
454 case Format::S32:
455 case Format::U32:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000456 case Format::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100457 case Format::F16:
458 case Format::F32:
459 case Format::RGB888:
460 case Format::RGBA8888:
461 case Format::YUYV422:
462 case Format::UYVY422:
463 return 1;
464 case Format::NV12:
465 case Format::NV21:
466 return 2;
467 case Format::IYUV:
468 case Format::YUV444:
469 return 3;
470 default:
471 ARM_COMPUTE_ERROR("Not supported format");
472 return 0;
473 }
474}
475
476/** Return the number of channels for a given single-planar pixel format
477 *
478 * @param[in] format Input format
479 *
480 * @return The number of channels for a given image format.
481 */
482inline size_t num_channels_from_format(Format format)
483{
484 switch(format)
485 {
486 case Format::U8:
487 case Format::U16:
488 case Format::S16:
489 case Format::U32:
490 case Format::S32:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000491 case Format::BFLOAT16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100492 case Format::F16:
493 case Format::F32:
494 return 1;
495 // Because the U and V channels are subsampled
496 // these formats appear like having only 2 channels:
497 case Format::YUYV422:
498 case Format::UYVY422:
499 return 2;
500 case Format::UV88:
501 return 2;
502 case Format::RGB888:
503 return 3;
504 case Format::RGBA8888:
505 return 4;
506 //Doesn't make sense for planar formats:
507 case Format::NV12:
508 case Format::NV21:
509 case Format::IYUV:
510 case Format::YUV444:
511 default:
512 return 0;
513 }
514}
515
Chunosovd621bca2017-11-03 17:33:15 +0700516/** Return the promoted data type of a given data type.
517 *
518 * @note If promoted data type is not supported an error will be thrown
519 *
520 * @param[in] dt Data type to get the promoted type of.
521 *
522 * @return Promoted data type
523 */
524inline DataType get_promoted_data_type(DataType dt)
525{
526 switch(dt)
527 {
528 case DataType::U8:
529 return DataType::U16;
530 case DataType::S8:
531 return DataType::S16;
Chunosovd621bca2017-11-03 17:33:15 +0700532 case DataType::U16:
533 return DataType::U32;
534 case DataType::S16:
535 return DataType::S32;
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100536 case DataType::QSYMM8:
Chunosovd621bca2017-11-03 17:33:15 +0700537 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +0100538 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +0100539 case DataType::QSYMM8_PER_CHANNEL:
Manuel Bottini3689fcd2019-06-14 17:18:12 +0100540 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +0100541 case DataType::QASYMM16:
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000542 case DataType::BFLOAT16:
Chunosovd621bca2017-11-03 17:33:15 +0700543 case DataType::F16:
544 case DataType::U32:
545 case DataType::S32:
546 case DataType::F32:
Chunosovd621bca2017-11-03 17:33:15 +0700547 ARM_COMPUTE_ERROR("Unsupported data type promotions!");
548 default:
549 ARM_COMPUTE_ERROR("Undefined data type!");
550 }
551 return DataType::UNKNOWN;
552}
553
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000554/** Compute the mininum and maximum values a data type can take
555 *
556 * @param[in] dt Data type to get the min/max bounds of
557 *
558 * @return A tuple (min,max) with the minimum and maximum values respectively wrapped in PixelValue.
559 */
560inline std::tuple<PixelValue, PixelValue> get_min_max(DataType dt)
561{
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000562 PixelValue min{};
563 PixelValue max{};
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000564 switch(dt)
565 {
566 case DataType::U8:
567 case DataType::QASYMM8:
568 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000569 min = PixelValue(static_cast<int32_t>(std::numeric_limits<uint8_t>::lowest()));
570 max = PixelValue(static_cast<int32_t>(std::numeric_limits<uint8_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000571 break;
572 }
573 case DataType::S8:
574 case DataType::QSYMM8:
575 case DataType::QASYMM8_SIGNED:
576 case DataType::QSYMM8_PER_CHANNEL:
577 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000578 min = PixelValue(static_cast<int32_t>(std::numeric_limits<int8_t>::lowest()));
579 max = PixelValue(static_cast<int32_t>(std::numeric_limits<int8_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000580 break;
581 }
582 case DataType::U16:
583 case DataType::QASYMM16:
584 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000585 min = PixelValue(static_cast<int32_t>(std::numeric_limits<uint16_t>::lowest()));
586 max = PixelValue(static_cast<int32_t>(std::numeric_limits<uint16_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000587 break;
588 }
589 case DataType::S16:
590 case DataType::QSYMM16:
591 {
Michalis Spyroue7be8a02019-12-12 16:16:09 +0000592 min = PixelValue(static_cast<int32_t>(std::numeric_limits<int16_t>::lowest()));
593 max = PixelValue(static_cast<int32_t>(std::numeric_limits<int16_t>::max()));
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000594 break;
595 }
596 case DataType::U32:
597 {
598 min = PixelValue(std::numeric_limits<uint32_t>::lowest());
599 max = PixelValue(std::numeric_limits<uint32_t>::max());
600 break;
601 }
602 case DataType::S32:
603 {
604 min = PixelValue(std::numeric_limits<int32_t>::lowest());
605 max = PixelValue(std::numeric_limits<int32_t>::max());
606 break;
607 }
Georgios Pinitase8291ac2020-02-26 09:58:13 +0000608 case DataType::BFLOAT16:
609 {
610 min = PixelValue(bfloat16::lowest());
611 max = PixelValue(bfloat16::max());
612 break;
613 }
Luca Foschianiee939fb2020-01-28 10:38:07 +0000614 case DataType::F16:
615 {
616 min = PixelValue(std::numeric_limits<half>::lowest());
617 max = PixelValue(std::numeric_limits<half>::max());
618 break;
619 }
Georgios Pinitas6e1791b2019-12-02 19:01:25 +0000620 case DataType::F32:
621 {
622 min = PixelValue(std::numeric_limits<float>::lowest());
623 max = PixelValue(std::numeric_limits<float>::max());
624 break;
625 }
626 default:
627 ARM_COMPUTE_ERROR("Undefined data type!");
628 }
629 return std::make_tuple(min, max);
630}
631
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100632/** Return true if the given format has horizontal subsampling.
633 *
634 * @param[in] format Format to determine subsampling.
635 *
636 * @return True if the format can be subsampled horizontaly.
637 */
638inline bool has_format_horizontal_subsampling(Format format)
639{
640 return (format == Format::YUYV422 || format == Format::UYVY422 || format == Format::NV12 || format == Format::NV21 || format == Format::IYUV || format == Format::UV88) ? true : false;
641}
642
643/** Return true if the given format has vertical subsampling.
644 *
645 * @param[in] format Format to determine subsampling.
646 *
647 * @return True if the format can be subsampled verticaly.
648 */
649inline bool has_format_vertical_subsampling(Format format)
650{
651 return (format == Format::NV12 || format == Format::NV21 || format == Format::IYUV || format == Format::UV88) ? true : false;
652}
653
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100654/** Separate a 2D convolution into two 1D convolutions
Anthony Barbierf202e502017-11-23 18:02:04 +0000655 *
656 * @param[in] conv 2D convolution
657 * @param[out] conv_col 1D vertical convolution
658 * @param[out] conv_row 1D horizontal convolution
659 * @param[in] size Size of the 2D convolution
660 *
661 * @return true if the separation was successful
662 */
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100663inline bool separate_matrix(const int16_t *conv, int16_t *conv_col, int16_t *conv_row, uint8_t size)
664{
665 int32_t min_col = -1;
666 int16_t min_col_val = -1;
667
668 for(int32_t i = 0; i < size; ++i)
669 {
670 if(conv[i] != 0 && (min_col < 0 || abs(min_col_val) > abs(conv[i])))
671 {
672 min_col = i;
673 min_col_val = conv[i];
674 }
675 }
676
677 if(min_col < 0)
678 {
679 return false;
680 }
681
682 for(uint32_t j = 0; j < size; ++j)
683 {
684 conv_col[j] = conv[min_col + j * size];
685 }
686
687 for(uint32_t i = 0; i < size; i++)
688 {
689 if(static_cast<int>(i) == min_col)
690 {
691 conv_row[i] = 1;
692 }
693 else
694 {
695 int16_t coeff = conv[i] / conv[min_col];
696
697 for(uint32_t j = 1; j < size; ++j)
698 {
699 if(conv[i + j * size] != (conv_col[j] * coeff))
700 {
701 return false;
702 }
703 }
704
705 conv_row[i] = coeff;
706 }
707 }
708
709 return true;
710}
711
712/** Calculate the scale of the given square matrix
713 *
714 * The scale is the absolute value of the sum of all the coefficients in the matrix.
715 *
716 * @note If the coefficients add up to 0 then the scale is set to 1.
717 *
718 * @param[in] matrix Matrix coefficients
719 * @param[in] matrix_size Number of elements per side of the square matrix. (Number of coefficients = matrix_size * matrix_size).
720 *
721 * @return The absolute value of the sum of the coefficients if they don't add up to 0, otherwise 1.
722 */
723inline uint32_t calculate_matrix_scale(const int16_t *matrix, unsigned int matrix_size)
724{
725 const size_t size = matrix_size * matrix_size;
726
727 return std::max(1, std::abs(std::accumulate(matrix, matrix + size, 0)));
728}
729
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100730/** Adjust tensor shape size if width or height are odd for a given multi-planar format. No modification is done for other formats.
731 *
732 * @note Adding here a few links discussing the issue of odd size and sharing the same solution:
Manuel Bottini581c8982019-02-07 10:31:57 +0000733 * <a href="https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/graphics/java/android/graphics/YuvImage.java">Android Source</a>
734 * <a href="https://groups.google.com/a/webmproject.org/forum/#!topic/webm-discuss/LaCKpqiDTXM">WebM</a>
735 * <a href="https://bugs.chromium.org/p/libyuv/issues/detail?id=198&amp;can=1&amp;q=odd%20width">libYUV</a>
736 * <a href="https://sourceforge.net/p/raw-yuvplayer/bugs/1/">YUVPlayer</a> *
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100737 *
738 * @param[in, out] shape Tensor shape of 2D size
739 * @param[in] format Format of the tensor
740 *
Alex Gildayc357c472018-03-21 13:54:09 +0000741 * @return The adjusted tensor shape.
Ioan-Cristian Szabo9414f642017-10-27 17:35:40 +0100742 */
743inline TensorShape adjust_odd_shape(const TensorShape &shape, Format format)
744{
745 TensorShape output{ shape };
746
747 // Force width to be even for formats which require subsampling of the U and V channels
748 if(has_format_horizontal_subsampling(format))
749 {
750 output.set(0, output.x() & ~1U);
751 }
752
753 // Force height to be even for formats which require subsampling of the U and V channels
754 if(has_format_vertical_subsampling(format))
755 {
756 output.set(1, output.y() & ~1U);
757 }
758
759 return output;
760}
761
762/** Calculate subsampled shape for a given format and channel
763 *
764 * @param[in] shape Shape of the tensor to calculate the extracted channel.
765 * @param[in] format Format of the tensor.
766 * @param[in] channel Channel to create tensor shape to be extracted.
767 *
768 * @return The subsampled tensor shape.
769 */
770inline TensorShape calculate_subsampled_shape(const TensorShape &shape, Format format, Channel channel = Channel::UNKNOWN)
771{
772 TensorShape output{ shape };
773
774 // Subsample shape only for U or V channel
775 if(Channel::U == channel || Channel::V == channel || Channel::UNKNOWN == channel)
776 {
777 // Subsample width for the tensor shape when channel is U or V
778 if(has_format_horizontal_subsampling(format))
779 {
780 output.set(0, output.x() / 2U);
781 }
782
783 // Subsample height for the tensor shape when channel is U or V
784 if(has_format_vertical_subsampling(format))
785 {
786 output.set(1, output.y() / 2U);
787 }
788 }
789
790 return output;
791}
792
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100793/** Calculate accurary required by the horizontal and vertical convolution computations
794 *
795 * @param[in] conv_col Pointer to the vertical vector of the separated convolution filter
796 * @param[in] conv_row Pointer to the horizontal vector of the convolution filter
797 * @param[in] size Number of elements per vector of the separated matrix
798 *
799 * @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
800 * element of the pair is the biggest data type needed for the second stage.
801 */
802inline std::pair<DataType, DataType> data_type_for_convolution(const int16_t *conv_col, const int16_t *conv_row, size_t size)
803{
804 DataType first_stage = DataType::UNKNOWN;
805 DataType second_stage = DataType::UNKNOWN;
806
807 auto gez = [](const int16_t &v)
808 {
809 return v >= 0;
810 };
811
812 auto accu_neg = [](const int &first, const int &second)
813 {
814 return first + (second < 0 ? second : 0);
815 };
816
817 auto accu_pos = [](const int &first, const int &second)
818 {
819 return first + (second > 0 ? second : 0);
820 };
821
822 const bool only_positive_coefficients = std::all_of(conv_row, conv_row + size, gez) && std::all_of(conv_col, conv_col + size, gez);
823
824 if(only_positive_coefficients)
825 {
826 const int max_row_value = std::accumulate(conv_row, conv_row + size, 0) * UINT8_MAX;
827 const int max_value = std::accumulate(conv_col, conv_col + size, 0) * max_row_value;
828
829 first_stage = (max_row_value <= UINT16_MAX) ? DataType::U16 : DataType::S32;
830
831 second_stage = (max_value <= UINT16_MAX) ? DataType::U16 : DataType::S32;
832 }
833 else
834 {
835 const int min_row_value = std::accumulate(conv_row, conv_row + size, 0, accu_neg) * UINT8_MAX;
836 const int max_row_value = std::accumulate(conv_row, conv_row + size, 0, accu_pos) * UINT8_MAX;
837 const int neg_coeffs_sum = std::accumulate(conv_col, conv_col + size, 0, accu_neg);
838 const int pos_coeffs_sum = std::accumulate(conv_col, conv_col + size, 0, accu_pos);
839 const int min_value = neg_coeffs_sum * max_row_value + pos_coeffs_sum * min_row_value;
840 const int max_value = neg_coeffs_sum * min_row_value + pos_coeffs_sum * max_row_value;
841
842 first_stage = ((INT16_MIN <= min_row_value) && (max_row_value <= INT16_MAX)) ? DataType::S16 : DataType::S32;
843
844 second_stage = ((INT16_MIN <= min_value) && (max_value <= INT16_MAX)) ? DataType::S16 : DataType::S32;
845 }
846
847 return std::make_pair(first_stage, second_stage);
848}
849
850/** Calculate the accuracy required by the squared convolution calculation.
851 *
852 *
853 * @param[in] conv Pointer to the squared convolution matrix
854 * @param[in] size The total size of the convolution matrix
855 *
856 * @return The return is the biggest data type needed to do the convolution
857 */
858inline DataType data_type_for_convolution_matrix(const int16_t *conv, size_t size)
859{
860 auto gez = [](const int16_t v)
861 {
862 return v >= 0;
863 };
864
865 const bool only_positive_coefficients = std::all_of(conv, conv + size, gez);
866
867 if(only_positive_coefficients)
868 {
869 const int max_conv_value = std::accumulate(conv, conv + size, 0) * UINT8_MAX;
870 if(max_conv_value <= UINT16_MAX)
871 {
872 return DataType::U16;
873 }
874 else
875 {
876 return DataType::S32;
877 }
878 }
879 else
880 {
881 const int min_value = std::accumulate(conv, conv + size, 0, [](int a, int b)
882 {
883 return b < 0 ? a + b : a;
884 })
885 * UINT8_MAX;
886
887 const int max_value = std::accumulate(conv, conv + size, 0, [](int a, int b)
888 {
889 return b > 0 ? a + b : a;
890 })
891 * UINT8_MAX;
892
893 if((INT16_MIN <= min_value) && (INT16_MAX >= max_value))
894 {
895 return DataType::S16;
896 }
897 else
898 {
899 return DataType::S32;
900 }
901 }
902}
903
Pablo Tello35767bc2018-12-05 17:36:30 +0000904/** Permutes the given dimensions according the permutation vector
905 *
906 * @param[in,out] dimensions Dimensions to be permuted.
907 * @param[in] perm Vector describing the permutation.
908 *
909 */
910template <typename T>
911inline void permute_strides(Dimensions<T> &dimensions, const PermutationVector &perm)
912{
913 const auto old_dim = utility::make_array<Dimensions<T>::num_max_dimensions>(dimensions.begin(), dimensions.end());
914 for(unsigned int i = 0; i < perm.num_dimensions(); ++i)
915 {
916 T dimension_val = old_dim[i];
917 dimensions.set(perm[i], dimension_val);
918 }
919}
920
Georgios Pinitas4074c992018-01-30 18:13:46 +0000921/** Calculate padding requirements in case of SAME padding
922 *
923 * @param[in] input_shape Input shape
924 * @param[in] weights_shape Weights shape
925 * @param[in] conv_info Convolution information (containing strides)
Isabella Gottardi6a914402019-01-30 15:45:42 +0000926 * @param[in] data_layout (Optional) Data layout of the input and weights tensor
Pablo Tello01bbacb2019-04-30 10:32:42 +0100927 * @param[in] dilation (Optional) Dilation factor used in the convolution.
Giorgio Arena17203582019-08-02 16:00:41 +0100928 * @param[in] rounding_type (Optional) Dimension rounding type when down-scaling.
Georgios Pinitas4074c992018-01-30 18:13:46 +0000929 *
930 * @return PadStrideInfo for SAME padding
931 */
Giorgio Arena17203582019-08-02 16:00:41 +0100932PadStrideInfo calculate_same_pad(TensorShape input_shape, TensorShape weights_shape, PadStrideInfo conv_info, DataLayout data_layout = DataLayout::NCHW, const Size2D &dilation = Size2D(1u, 1u),
933 const DimensionRoundingType &rounding_type = DimensionRoundingType::FLOOR);
Georgios Pinitas4074c992018-01-30 18:13:46 +0000934
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100935/** Returns expected width and height of the deconvolution's output tensor.
936 *
Matthew Jacksonb9070a42019-08-22 16:13:27 +0100937 * @param[in] in_width Width of input tensor (Number of columns)
938 * @param[in] in_height Height of input tensor (Number of rows)
939 * @param[in] kernel_width Kernel width.
940 * @param[in] kernel_height Kernel height.
941 * @param[in] pad_stride_info Pad and stride information.
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100942 *
943 * @return A pair with the new width in the first position and the new height in the second.
944 */
Pablo Tello01bbacb2019-04-30 10:32:42 +0100945std::pair<unsigned int, unsigned int> deconvolution_output_dimensions(unsigned int in_width, unsigned int in_height,
946 unsigned int kernel_width, unsigned int kernel_height,
Matthew Jacksonb9070a42019-08-22 16:13:27 +0100947 const PadStrideInfo &pad_stride_info);
Pablo Tellof5f34bb2017-08-22 13:34:13 +0100948
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100949/** Returns expected width and height of output scaled tensor depending on dimensions rounding mode.
950 *
Gian Marco Iodice4e288692017-06-27 11:41:59 +0100951 * @param[in] width Width of input tensor (Number of columns)
952 * @param[in] height Height of input tensor (Number of rows)
953 * @param[in] kernel_width Kernel width.
954 * @param[in] kernel_height Kernel height.
955 * @param[in] pad_stride_info Pad and stride information.
Alex Gilday7da29b62018-03-23 14:16:00 +0000956 * @param[in] dilation (Optional) Dilation, in elements, across x and y. Defaults to (1, 1).
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100957 *
958 * @return A pair with the new width in the first position and the new height in the second.
959 */
Georgios Pinitas80838f12019-12-12 18:23:13 +0000960std::pair<unsigned int, unsigned int> scaled_dimensions(int width, int height,
961 int kernel_width, int kernel_height,
Pablo Tello01bbacb2019-04-30 10:32:42 +0100962 const PadStrideInfo &pad_stride_info,
963 const Size2D &dilation = Size2D(1U, 1U));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100964
Sang-Hoon Park2697fd82019-10-15 16:49:24 +0100965/** Check if the given reduction operation should be handled in a serial way.
966 *
967 * @param[in] op Reduction operation to perform
968 * @param[in] dt Data type
969 * @param[in] axis Axis along which to reduce
970 *
971 * @return True if the given reduction operation should be handled in a serial way.
972 */
973bool needs_serialized_reduction(ReductionOperation op, DataType dt, unsigned int axis);
974
Sang-Hoon Park0779fec2019-11-13 17:08:12 +0000975/** Returns output quantization information for softmax layer
976 *
977 * @param[in] input_type The data type of the input tensor
978 * @param[in] is_log True for log softmax
979 *
980 * @return Quantization information for the output tensor
981 */
982QuantizationInfo get_softmax_output_quantization_info(DataType input_type, bool is_log);
983
Sang-Hoon Park4715cf92020-01-08 16:02:47 +0000984/** Returns a pair of minimum and maximum values for a quantized activation
985 *
986 * @param[in] act_info The information for activation
987 * @param[in] data_type The used data type
988 * @param[in] oq_info The output quantization information
989 *
990 * @return The pair with minimum and maximum values
991 */
992std::pair<int32_t, int32_t> get_quantized_activation_min_max(ActivationLayerInfo act_info, DataType data_type, UniformQuantizationInfo oq_info);
993
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100994/** Convert a tensor format into a string.
995 *
996 * @param[in] format @ref Format to be translated to string.
997 *
998 * @return The string describing the format.
999 */
1000const std::string &string_from_format(Format format);
1001
1002/** Convert a channel identity into a string.
1003 *
1004 * @param[in] channel @ref Channel to be translated to string.
1005 *
1006 * @return The string describing the channel.
1007 */
1008const std::string &string_from_channel(Channel channel);
Michele Di Giorgiobf3c6622018-03-08 11:52:27 +00001009/** Convert a data layout identity into a string.
1010 *
1011 * @param[in] dl @ref DataLayout to be translated to string.
1012 *
1013 * @return The string describing the data layout.
1014 */
1015const std::string &string_from_data_layout(DataLayout dl);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001016/** Convert a data type identity into a string.
1017 *
1018 * @param[in] dt @ref DataType to be translated to string.
1019 *
1020 * @return The string describing the data type.
1021 */
1022const std::string &string_from_data_type(DataType dt);
1023/** Convert a matrix pattern into a string.
1024 *
1025 * @param[in] pattern @ref MatrixPattern to be translated to string.
1026 *
1027 * @return The string describing the matrix pattern.
1028 */
1029const std::string &string_from_matrix_pattern(MatrixPattern pattern);
1030/** Translates a given activation function to a string.
1031 *
1032 * @param[in] act @ref ActivationLayerInfo::ActivationFunction to be translated to string.
1033 *
1034 * @return The string describing the activation function.
1035 */
1036const std::string &string_from_activation_func(ActivationLayerInfo::ActivationFunction act);
1037/** Translates a given non linear function to a string.
1038 *
1039 * @param[in] function @ref NonLinearFilterFunction to be translated to string.
1040 *
1041 * @return The string describing the non linear function.
1042 */
1043const std::string &string_from_non_linear_filter_function(NonLinearFilterFunction function);
1044/** Translates a given interpolation policy to a string.
1045 *
1046 * @param[in] policy @ref InterpolationPolicy to be translated to string.
1047 *
1048 * @return The string describing the interpolation policy.
1049 */
1050const std::string &string_from_interpolation_policy(InterpolationPolicy policy);
1051/** Translates a given border mode policy to a string.
1052 *
1053 * @param[in] border_mode @ref BorderMode to be translated to string.
1054 *
1055 * @return The string describing the border mode.
1056 */
1057const std::string &string_from_border_mode(BorderMode border_mode);
1058/** Translates a given normalization type to a string.
1059 *
1060 * @param[in] type @ref NormType to be translated to string.
1061 *
1062 * @return The string describing the normalization type.
1063 */
1064const std::string &string_from_norm_type(NormType type);
Georgios Pinitascdf51452017-08-31 14:21:36 +01001065/** Translates a given pooling type to a string.
1066 *
1067 * @param[in] type @ref PoolingType to be translated to string.
1068 *
1069 * @return The string describing the pooling type.
1070 */
1071const std::string &string_from_pooling_type(PoolingType type);
Gian Marco Iodice4b908652018-10-18 10:21:02 +01001072/** Translates a given GEMMLowp output stage to a string.
1073 *
1074 * @param[in] output_stage @ref GEMMLowpOutputStageInfo to be translated to string.
1075 *
1076 * @return The string describing the GEMMLowp output stage
1077 */
1078const std::string &string_from_gemmlowp_output_stage(GEMMLowpOutputStageType output_stage);
Giuseppe Rossinid7647d42018-07-17 18:13:13 +01001079/** Convert a PixelValue to a string, represented through the specific data type
1080 *
1081 * @param[in] value The PixelValue to convert
1082 * @param[in] data_type The type to be used to convert the @p value
1083 *
1084 * @return String representation of the PixelValue through the given data type.
1085 */
1086std::string string_from_pixel_value(const PixelValue &value, const DataType data_type);
SiCong Lie357a252020-08-09 20:05:52 +01001087/** Convert a string to DataType
1088 *
1089 * @param[in] name The name of the data type
1090 *
1091 * @return DataType
1092 */
1093DataType data_type_from_name(const std::string &name);
1094/** Input Stream operator for @ref DataType
1095 *
1096 * @param[in] stream Stream to parse
1097 * @param[out] data_type Output data type
1098 *
1099 * @return Updated stream
1100 */
1101inline ::std::istream &operator>>(::std::istream &stream, DataType &data_type)
1102{
1103 std::string value;
1104 stream >> value;
1105 data_type = data_type_from_name(value);
1106 return stream;
1107}
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001108/** Lower a given string.
1109 *
1110 * @param[in] val Given string to lower.
1111 *
1112 * @return The lowered string
1113 */
1114std::string lower_string(const std::string &val);
1115
1116/** Check if a given data type is of floating point type
1117 *
1118 * @param[in] dt Input data type.
1119 *
1120 * @return True if data type is of floating point type, else false.
1121 */
1122inline bool is_data_type_float(DataType dt)
1123{
1124 switch(dt)
1125 {
1126 case DataType::F16:
1127 case DataType::F32:
1128 return true;
1129 default:
1130 return false;
1131 }
1132}
1133
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001134/** Check if a given data type is of quantized type
1135 *
1136 * @note Quantized is considered a super-set of fixed-point and asymmetric data types.
1137 *
1138 * @param[in] dt Input data type.
1139 *
1140 * @return True if data type is of quantized type, else false.
1141 */
1142inline bool is_data_type_quantized(DataType dt)
1143{
1144 switch(dt)
1145 {
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001146 case DataType::QSYMM8:
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001147 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001148 case DataType::QASYMM8_SIGNED:
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001149 case DataType::QSYMM8_PER_CHANNEL:
Manuel Bottini3689fcd2019-06-14 17:18:12 +01001150 case DataType::QSYMM16:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +01001151 case DataType::QASYMM16:
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001152 return true;
1153 default:
1154 return false;
1155 }
1156}
1157
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001158/** Check if a given data type is of asymmetric quantized type
1159 *
1160 * @param[in] dt Input data type.
1161 *
Michele Di Giorgio6997fc92019-06-18 10:23:22 +01001162 * @return True if data type is of asymmetric quantized type, else false.
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001163 */
Anton Lokhmotovaf6204c2017-11-08 09:34:19 +00001164inline bool is_data_type_quantized_asymmetric(DataType dt)
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001165{
1166 switch(dt)
1167 {
1168 case DataType::QASYMM8:
Georgios Pinitasdbdea0d2019-10-16 19:21:40 +01001169 case DataType::QASYMM8_SIGNED:
Michele Di Giorgio35ea9a72019-08-23 12:02:06 +01001170 case DataType::QASYMM16:
Georgios Pinitas05078ec2017-11-02 13:06:59 +00001171 return true;
1172 default:
1173 return false;
1174 }
1175}
1176
Georgios Pinitas6e1791b2019-12-02 19:01:25 +00001177/** Check if a given data type is of asymmetric quantized signed type
1178 *
1179 * @param[in] dt Input data type.
1180 *
1181 * @return True if data type is of asymmetric quantized signed type, else false.
1182 */
1183inline bool is_data_type_quantized_asymmetric_signed(DataType dt)
1184{
1185 switch(dt)
1186 {
1187 case DataType::QASYMM8_SIGNED:
1188 return true;
1189 default:
1190 return false;
1191 }
1192}
1193
Michele Di Giorgio6997fc92019-06-18 10:23:22 +01001194/** Check if a given data type is of symmetric quantized type
1195 *
1196 * @param[in] dt Input data type.
1197 *
1198 * @return True if data type is of symmetric quantized type, else false.
1199 */
1200inline bool is_data_type_quantized_symmetric(DataType dt)
1201{
1202 switch(dt)
1203 {
1204 case DataType::QSYMM8:
1205 case DataType::QSYMM8_PER_CHANNEL:
1206 case DataType::QSYMM16:
1207 return true;
1208 default:
1209 return false;
1210 }
1211}
1212
Michalis Spyrouc8530212019-08-22 11:44:04 +01001213/** Check if a given data type is of per channel type
1214 *
1215 * @param[in] dt Input data type.
1216 *
1217 * @return True if data type is of per channel type, else false.
1218 */
1219inline bool is_data_type_quantized_per_channel(DataType dt)
1220{
1221 switch(dt)
1222 {
1223 case DataType::QSYMM8_PER_CHANNEL:
Michalis Spyrouc8530212019-08-22 11:44:04 +01001224 return true;
1225 default:
1226 return false;
1227 }
1228}
1229
Georgios Pinitas89010962017-08-04 14:58:27 +01001230/** Create a string with the float in full precision.
1231 *
1232 * @param val Floating point value
1233 *
1234 * @return String with the floating point value.
1235 */
1236inline std::string float_to_string_with_full_precision(float val)
1237{
1238 std::stringstream ss;
Georgios Pinitas7900a9e2018-11-23 11:44:58 +00001239 ss.precision(std::numeric_limits<float>::max_digits10);
Georgios Pinitas89010962017-08-04 14:58:27 +01001240 ss << val;
Giorgio Arena73023022018-09-04 14:55:55 +01001241
1242 if(val != static_cast<int>(val))
1243 {
1244 ss << "f";
1245 }
1246
Georgios Pinitas89010962017-08-04 14:58:27 +01001247 return ss.str();
1248}
1249
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001250/** Returns the number of elements required to go from start to end with the wanted step
1251 *
1252 * @param[in] start start value
1253 * @param[in] end end value
1254 * @param[in] step step value between each number in the wanted sequence
1255 *
1256 * @return number of elements to go from start value to end value using the wanted step
1257 */
1258inline size_t num_of_elements_in_range(const float start, const float end, const float step)
1259{
1260 ARM_COMPUTE_ERROR_ON_MSG(step == 0, "Range Step cannot be 0");
1261 return size_t(std::ceil((end - start) / step));
1262}
1263
1264/** Returns true if the value can be represented by the given data type
1265 *
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001266 * @param[in] val value to be checked
1267 * @param[in] dt data type that is checked
1268 * @param[in] qinfo (Optional) quantization info if the data type is QASYMM8
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001269 *
1270 * @return true if the data type can hold the value.
1271 */
1272template <typename T>
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001273bool check_value_range(T val, DataType dt, QuantizationInfo qinfo = QuantizationInfo())
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001274{
1275 switch(dt)
1276 {
1277 case DataType::U8:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001278 {
1279 const auto val_u8 = static_cast<uint8_t>(val);
1280 return ((val_u8 == val) && val_u8 >= std::numeric_limits<uint8_t>::lowest() && val_u8 <= std::numeric_limits<uint8_t>::max());
1281 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001282 case DataType::QASYMM8:
1283 {
Georgios Pinitas4c5469b2019-05-21 13:32:43 +01001284 double min = static_cast<double>(dequantize_qasymm8(0, qinfo));
1285 double max = static_cast<double>(dequantize_qasymm8(std::numeric_limits<uint8_t>::max(), qinfo));
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001286 return ((double)val >= min && (double)val <= max);
1287 }
1288 case DataType::S8:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001289 {
1290 const auto val_s8 = static_cast<int8_t>(val);
1291 return ((val_s8 == val) && val_s8 >= std::numeric_limits<int8_t>::lowest() && val_s8 <= std::numeric_limits<int8_t>::max());
1292 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001293 case DataType::U16:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001294 {
1295 const auto val_u16 = static_cast<uint16_t>(val);
1296 return ((val_u16 == val) && val_u16 >= std::numeric_limits<uint16_t>::lowest() && val_u16 <= std::numeric_limits<uint16_t>::max());
1297 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001298 case DataType::S16:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001299 {
1300 const auto val_s16 = static_cast<int16_t>(val);
1301 return ((val_s16 == val) && val_s16 >= std::numeric_limits<int16_t>::lowest() && val_s16 <= std::numeric_limits<int16_t>::max());
1302 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001303 case DataType::U32:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001304 {
1305 const auto val_u32 = static_cast<uint32_t>(val);
1306 return ((val_u32 == val) && val_u32 >= std::numeric_limits<uint32_t>::lowest() && val_u32 <= std::numeric_limits<uint32_t>::max());
1307 }
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001308 case DataType::S32:
Georgios Pinitase874ef92019-09-09 17:40:33 +01001309 {
1310 const auto val_s32 = static_cast<int32_t>(val);
1311 return ((val_s32 == val) && val_s32 >= std::numeric_limits<int32_t>::lowest() && val_s32 <= std::numeric_limits<int32_t>::max());
1312 }
Georgios Pinitase8291ac2020-02-26 09:58:13 +00001313 case DataType::BFLOAT16:
1314 return (val >= bfloat16::lowest() && val <= bfloat16::max());
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001315 case DataType::F16:
1316 return (val >= std::numeric_limits<half>::lowest() && val <= std::numeric_limits<half>::max());
1317 case DataType::F32:
1318 return (val >= std::numeric_limits<float>::lowest() && val <= std::numeric_limits<float>::max());
Michalis Spyrouf63885b2019-01-16 14:18:09 +00001319 default:
1320 ARM_COMPUTE_ERROR("Data type not supported");
1321 return false;
1322 }
1323}
1324
giuros01edc21e42018-11-16 14:45:31 +00001325#ifdef ARM_COMPUTE_ASSERTS_ENABLED
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001326/** Print consecutive elements to an output stream.
1327 *
1328 * @param[out] s Output stream to print the elements to.
1329 * @param[in] ptr Pointer to print the elements from.
1330 * @param[in] n Number of elements to print.
1331 * @param[in] stream_width (Optional) Width of the stream. If set to 0 the element's width is used. Defaults to 0.
1332 * @param[in] element_delim (Optional) Delimeter among the consecutive elements. Defaults to space delimeter
1333 */
1334template <typename T>
1335void print_consecutive_elements_impl(std::ostream &s, const T *ptr, unsigned int n, int stream_width = 0, const std::string &element_delim = " ")
1336{
1337 using print_type = typename std::conditional<std::is_floating_point<T>::value, T, int>::type;
Michalis Spyrou53860dd2019-07-01 14:20:56 +01001338 std::ios stream_status(nullptr);
1339 stream_status.copyfmt(s);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001340
1341 for(unsigned int i = 0; i < n; ++i)
1342 {
1343 // Set stream width as it is not a "sticky" stream manipulator
1344 if(stream_width != 0)
1345 {
1346 s.width(stream_width);
1347 }
Anthony Barbier7068f992017-10-26 15:23:08 +01001348
1349 if(std::is_same<typename std::decay<T>::type, half>::value)
1350 {
1351 // 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.
1352 s << std::right << static_cast<T>(ptr[i]) << element_delim;
1353 }
Georgios Pinitase8291ac2020-02-26 09:58:13 +00001354 else if(std::is_same<typename std::decay<T>::type, bfloat16>::value)
1355 {
Georgios Pinitasc7b183a2020-03-06 18:12:09 +00001356 // 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 +00001357 s << std::right << float(ptr[i]) << element_delim;
1358 }
Anthony Barbier7068f992017-10-26 15:23:08 +01001359 else
1360 {
1361 s << std::right << static_cast<print_type>(ptr[i]) << element_delim;
1362 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001363 }
Michalis Spyrou53860dd2019-07-01 14:20:56 +01001364
1365 // Restore output stream flags
1366 s.copyfmt(stream_status);
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001367}
1368
1369/** Identify the maximum width of n consecutive elements.
1370 *
1371 * @param[in] s The output stream which will be used to print the elements. Used to extract the stream format.
1372 * @param[in] ptr Pointer to the elements.
1373 * @param[in] n Number of elements.
1374 *
1375 * @return The maximum width of the elements.
1376 */
1377template <typename T>
1378int max_consecutive_elements_display_width_impl(std::ostream &s, const T *ptr, unsigned int n)
1379{
1380 using print_type = typename std::conditional<std::is_floating_point<T>::value, T, int>::type;
1381
1382 int max_width = -1;
1383 for(unsigned int i = 0; i < n; ++i)
1384 {
1385 std::stringstream ss;
1386 ss.copyfmt(s);
Anthony Barbier7068f992017-10-26 15:23:08 +01001387
1388 if(std::is_same<typename std::decay<T>::type, half>::value)
1389 {
1390 // 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.
1391 ss << static_cast<T>(ptr[i]);
1392 }
Georgios Pinitase8291ac2020-02-26 09:58:13 +00001393 else if(std::is_same<typename std::decay<T>::type, bfloat16>::value)
1394 {
1395 // 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.
1396 ss << float(ptr[i]);
1397 }
Anthony Barbier7068f992017-10-26 15:23:08 +01001398 else
1399 {
1400 ss << static_cast<print_type>(ptr[i]);
1401 }
1402
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001403 max_width = std::max<int>(max_width, ss.str().size());
1404 }
1405 return max_width;
1406}
1407
1408/** Print consecutive elements to an output stream.
1409 *
1410 * @param[out] s Output stream to print the elements to.
1411 * @param[in] dt Data type of the elements
1412 * @param[in] ptr Pointer to print the elements from.
1413 * @param[in] n Number of elements to print.
1414 * @param[in] stream_width (Optional) Width of the stream. If set to 0 the element's width is used. Defaults to 0.
1415 * @param[in] element_delim (Optional) Delimeter among the consecutive elements. Defaults to space delimeter
1416 */
1417void print_consecutive_elements(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n, int stream_width, const std::string &element_delim = " ");
1418
1419/** Identify the maximum width of n consecutive elements.
1420 *
1421 * @param[in] s Output stream to print the elements to.
1422 * @param[in] dt Data type of the elements
1423 * @param[in] ptr Pointer to print the elements from.
1424 * @param[in] n Number of elements to print.
1425 *
1426 * @return The maximum width of the elements.
1427 */
1428int max_consecutive_elements_display_width(std::ostream &s, DataType dt, const uint8_t *ptr, unsigned int n);
giuros01edc21e42018-11-16 14:45:31 +00001429#endif /* ARM_COMPUTE_ASSERTS_ENABLED */
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001430}
Michalis Spyrouf4643372019-11-29 16:17:13 +00001431#endif /*ARM_COMPUTE_UTILS_H */