blob: e93d2863c93dc96e8a8b6ffa8b1dfc4a52b82a79 [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
Matthew Bentham043613f2023-05-30 16:43:14 +00002 * Copyright (c) 2016-2020, 2022-2023 Arm Limited.
Anthony Barbier6ff3b192017-09-04 18:44:23 +01003 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
Viet-Hoa Doc210c852023-10-09 10:58:35 +010024#ifndef ACL_ARM_COMPUTE_CORE_WINDOW_H
25#define ACL_ARM_COMPUTE_CORE_WINDOW_H
Anthony Barbier6ff3b192017-09-04 18:44:23 +010026
Anthony Barbier6ff3b192017-09-04 18:44:23 +010027#include "arm_compute/core/Coordinates.h"
28#include "arm_compute/core/Error.h"
29#include "arm_compute/core/ITensorInfo.h"
Matthew Bentham043613f2023-05-30 16:43:14 +000030#include "arm_compute/core/utils/math/Math.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010031
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010032#include <algorithm>
33#include <array>
34#include <cstddef>
35
Anthony Barbier6ff3b192017-09-04 18:44:23 +010036namespace arm_compute
37{
38/** Describe a multidimensional execution window. */
39class Window
40{
41public:
42 /** Alias for dimension 0 also known as X dimension */
43 static constexpr size_t DimX = 0;
44 /** Alias for dimension 1 also known as Y dimension */
45 static constexpr size_t DimY = 1;
46 /** Alias for dimension 2 also known as Z dimension */
47 static constexpr size_t DimZ = 2;
Sang-Hoon Parke4558b52020-10-01 10:13:07 +010048 /** Alias for dimension 3 also known as W dimension */
49 static constexpr size_t DimW = 3;
ramelg0137515692022-02-26 22:06:20 +000050 /** Alias for dimension 4 also known as V dimension */
51 static constexpr size_t DimV = 4;
Anthony Barbier6ff3b192017-09-04 18:44:23 +010052
53 /** Default constructor: create a window containing a single element. */
54 constexpr Window()
Sang-Hoon Parkcecb0a72019-09-17 08:59:09 +010055 : _dims(), _is_broadcasted(utility::generate_array<bool, Coordinates::num_max_dimensions, false>::value)
Anthony Barbier6ff3b192017-09-04 18:44:23 +010056 {
57 }
58 /** Copy constructor
59 *
60 * @param[in] src Copy the values from src to a new object
61 */
62 Window(const Window &src);
Georgios Pinitasf52cd782019-03-25 14:06:14 +000063 /** Copy assignment operator
64 *
65 * @param[in] rhs Copy the values from rhs to the current object
66 *
67 * @return Reference to the updated object
68 */
69 Window &operator=(const Window &rhs);
Anthony Barbier6ff3b192017-09-04 18:44:23 +010070
71 /** Describe one of the image's dimensions with a start, end and step.
72 *
73 * Iteration through the elements of the dimension is done like this:
74 * for(int v = start(); v < end(); v += step())
75 * {
76 * ...
77 * }
78 */
79 class Dimension
80 {
81 public:
82 /** Constructor, by default creates a dimension of 1.
83 *
84 * @param[in] start Start of the dimension
85 * @param[in] end End of the dimension
86 * @param[in] step Step between two elements of the dimension when iterating.
87 *
88 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010089 constexpr Dimension(int start = 0, int end = 1, int step = 1) : _start(start), _end(end), _step(step)
Anthony Barbier6ff3b192017-09-04 18:44:23 +010090 {
91 }
Pablo Marquez Tello586fff92022-06-10 09:20:14 +010092 Dimension(const Dimension &d) = default;
Anthony Barbier6ff3b192017-09-04 18:44:23 +010093 /** Default assignment operator to allow dimensions to be copied */
94 Dimension &operator=(const Dimension &d) = default;
95 /** Return the start of the dimension */
96 constexpr int start() const
97 {
98 return _start;
99 }
100 /** Return the end of the dimension */
101 constexpr int end() const
102 {
103 return _end;
104 }
105 /** Return the step of the dimension */
106 constexpr int step() const
107 {
108 return _step;
109 }
110 /** Set the dimension's step
111 *
112 * @param[in] step The new step
113 */
114 void set_step(int step)
115 {
116 _step = step;
117 }
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000118 /** Set the dimension's end
119 *
120 * @param[in] end The new end
121 */
122 void set_end(int end)
123 {
124 _end = end;
125 }
SiCong Lib63b1192022-01-28 18:24:39 +0000126 /** Check whether two Dimensions are equal.
127 *
128 * @param[in] lhs LHS Dimensions
129 * @param[in] rhs RHS Dimensions
130 *
131 * @return True if the Dimensions are the same.
132 */
133 friend bool operator==(const Dimension &lhs, const Dimension &rhs)
134 {
135 return (lhs._start == rhs._start) && (lhs._end == rhs._end) && (lhs._step == rhs._step);
136 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100137
138 private:
139 int _start; /**< Start of the dimension */
140 int _end; /**< End of the dimension */
141 int _step;
142 };
143
144 /** Read only access to a given dimension of the window
145 *
146 * @note Precondition: dimension < Coordinates::num_max_dimensions
147 *
148 * @param[in] dimension The dimension to access
149 *
150 * @return The requested dimension
151 */
152 constexpr const Dimension &operator[](size_t dimension) const;
153
154 /** Alias to access the first dimension of the window
155 *
156 * @return First dimension of the window
157 */
158 constexpr const Dimension &x() const
159 {
160 return _dims.at(Window::DimX);
161 }
162
163 /** Alias to access the second dimension of the window
164 *
165 * @return Second dimension of the window
166 */
167 constexpr const Dimension &y() const
168 {
169 return _dims.at(Window::DimY);
170 }
171
172 /** Alias to access the third dimension of the window
173 *
174 * @return Third dimension of the window
175 */
176 constexpr const Dimension &z() const
177 {
178 return _dims.at(Window::DimZ);
179 }
180
181 /** Set the values of a given dimension
182 *
183 * @param[in] dimension The dimension to set
184 * @param[in] dim The values to set the dimension to
185 */
186 void set(size_t dimension, const Dimension &dim);
187
Sang-Hoon Parkcecb0a72019-09-17 08:59:09 +0100188 /** Set the dimension as broadcasted dimension
189 *
190 * @param[in] dimension The dimension to set
191 */
192 void set_broadcasted(size_t dimension);
193
194 /** Return whether a dimension has been broadcasted
195 *
196 * @param[in] dimension The requested dimension
197 *
198 * @return true if the dimension has been broadcasted
199 */
200 bool is_broadcasted(size_t dimension) const;
201
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100202 /** Use the tensor's dimensions to fill the window dimensions.
203 *
SiCong Li86b53332017-08-23 11:02:43 +0100204 * @param[in] shape @ref TensorShape to copy the dimensions from.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100205 * @param[in] first_dimension Only copy dimensions which are greater or equal to this value.
206 */
SiCong Li86b53332017-08-23 11:02:43 +0100207 void use_tensor_dimensions(const TensorShape &shape, size_t first_dimension = Window::DimX);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100208
209 /** Shift the values of a given dimension by the given shift_value
210 *
211 * @param[in] dimension The dimension to shift
212 * @param[in] shift_value Value to shift the start and end values of.
213 */
214 void shift(size_t dimension, int shift_value);
215
Viet-Hoa Doc210c852023-10-09 10:58:35 +0100216 /** Shift down all the dimensions of a window starting from the specified dimension.
Michalis Spyrou995f5522018-01-29 13:43:35 +0000217 *
Viet-Hoa Doc210c852023-10-09 10:58:35 +0100218 * new_dims[i] = old_dims[i] for all i < start_dim.
219 * new_dims[i] = old_dims[i+shift_value] for all i >= start_dim.
Michalis Spyrou995f5522018-01-29 13:43:35 +0000220 *
221 * @param[in] shift_value Number of dimensions to shift the window by.
Viet-Hoa Doc210c852023-10-09 10:58:35 +0100222 * @param[in] start_dim The dimension from which the dimensions start to shift.
Michalis Spyrou995f5522018-01-29 13:43:35 +0000223 *
224 * @return The window with the shifted dimensions.
225 */
Viet-Hoa Doc210c852023-10-09 10:58:35 +0100226 Window shift_dimensions(unsigned int shift_value, unsigned int start_dim = 0) const;
Michalis Spyrou995f5522018-01-29 13:43:35 +0000227
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100228 /** Adjust the start or end of a given dimension by the given value
229 *
230 * @param[in] dimension The dimension to adjust
231 * @param[in] adjust_value The adjusted value.
232 * @param[in] is_at_start The flag to indicate whether adjust the start or end of the dimension.
233 */
234 void adjust(size_t dimension, int adjust_value, bool is_at_start);
235
236 /** Scale the values of a given dimension by the given scale_value
237 *
238 * @note The end of the window is rounded up to be a multiple of step after the scaling.
239 *
240 * @param[in] dimension The dimension to scale
241 * @param[in] scale_value Value to scale the start, end and step values of.
242 */
243 void scale(size_t dimension, float scale_value);
244
245 /** Set the step of a given dimension.
246 *
247 * @param[in] dimension Dimension to update
248 * @param[in] step The new dimension's step value
249 */
250 void set_dimension_step(size_t dimension, int step);
251
252 /** Will validate all the window's dimensions' values when asserts are enabled
253 *
254 * No-op when asserts are disabled
255 */
256 void validate() const;
257
258 /** Return the number of iterations needed to iterate through a given dimension
259 *
260 * @param[in] dimension The requested dimension
261 *
262 * @return The number of iterations
263 */
264 constexpr size_t num_iterations(size_t dimension) const;
Anthony Barbier671a11e2018-07-06 15:11:36 +0100265 /** Return the total number of iterations needed to iterate through the entire window
266 *
267 * @return Number of total iterations
268 */
269 size_t num_iterations_total() const;
270 /** Return the shape of the window in number of steps */
271 TensorShape shape() const;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100272 /** Split a window into a set of sub windows along a given dimension
273 *
274 * For example to split a window into 3 sub-windows along the Y axis, you would have to do:<br/>
275 * Window sub0 = window.split_window( 1, 0, 3);<br/>
276 * Window sub1 = window.split_window( 1, 1, 3);<br/>
277 * Window sub2 = window.split_window( 1, 2, 3);<br/>
278 *
279 * @param[in] dimension Dimension along which the split will be performed
280 * @param[in] id Id of the sub-window to return. Must be in the range (0, total-1)
281 * @param[in] total Total number of sub-windows the window will be split into.
282 *
283 * @return The subwindow "id" out of "total"
284 */
285 Window split_window(size_t dimension, size_t id, size_t total) const;
286 /** First 1D slice of the window
287 *
288 * @return The first slice of the window.
289 */
290 Window first_slice_window_1D() const
291 {
292 return first_slice_window<1>();
293 };
294 /** First 2D slice of the window
295 *
296 * @return The first slice of the window.
297 */
298 Window first_slice_window_2D() const
299 {
300 return first_slice_window<2>();
301 };
302 /** First 3D slice of the window
303 *
304 * @return The first slice of the window.
305 */
306 Window first_slice_window_3D() const
307 {
308 return first_slice_window<3>();
309 };
Michalis Spyrou5237e012018-01-17 09:40:27 +0000310 /** First 4D slice of the window
311 *
312 * @return The first slice of the window.
313 */
314 Window first_slice_window_4D() const
315 {
316 return first_slice_window<4>();
317 };
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100318 /** Slide the passed 1D window slice.
319 *
320 * If slice contains the last slice then it will remain unchanged and false will be returned.
321 *
322 * @param[in,out] slice Current slice, to be updated to the next slice.
323 *
324 * @return true if slice contains a new slice, false if slice already contained the last slice
325 */
326 bool slide_window_slice_1D(Window &slice) const
327 {
328 return slide_window_slice<1>(slice);
329 }
330 /** Slide the passed 2D window slice.
331 *
332 * If slice contains the last slice then it will remain unchanged and false will be returned.
333 *
334 * @param[in,out] slice Current slice, to be updated to the next slice.
335 *
336 * @return true if slice contains a new slice, false if slice already contained the last slice
337 */
338 bool slide_window_slice_2D(Window &slice) const
339 {
340 return slide_window_slice<2>(slice);
341 }
342 /** Slide the passed 3D window slice.
343 *
344 * If slice contains the last slice then it will remain unchanged and false will be returned.
345 *
346 * @param[in,out] slice Current slice, to be updated to the next slice.
347 *
348 * @return true if slice contains a new slice, false if slice already contained the last slice
349 */
350 bool slide_window_slice_3D(Window &slice) const
351 {
352 return slide_window_slice<3>(slice);
353 }
354 /** Slide the passed 4D window slice.
355 *
356 * If slice contains the last slice then it will remain unchanged and false will be returned.
357 *
358 * @param[in,out] slice Current slice, to be updated to the next slice.
359 *
360 * @return true if slice contains a new slice, false if slice already contained the last slice
361 */
362 bool slide_window_slice_4D(Window &slice) const
363 {
364 return slide_window_slice<4>(slice);
365 }
Alex Gildayc357c472018-03-21 13:54:09 +0000366 /** Collapse the dimensions between @p first and @p last if possible.
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000367 *
368 * A dimension is collapsable if it starts from 0 and matches the corresponding dimension in the full_window
369 *
370 * @param[in] full_window Full window @p window has been created from.
371 * @param[in] first Start dimension into which the following are collapsed.
372 * @param[in] last End (exclusive) dimension to collapse.
373 * @param[out] has_collapsed (Optional) Whether the window was collapsed.
374 *
375 * @return Collapsed window.
376 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100377 Window
378 collapse_if_possible(const Window &full_window, size_t first, size_t last, bool *has_collapsed = nullptr) const;
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000379
Alex Gildayc357c472018-03-21 13:54:09 +0000380 /** Collapse the dimensions higher than @p first if possible.
Anthony Barbierbe35b0e2017-07-11 18:13:08 +0100381 *
382 * A dimension is collapsable if it starts from 0 and matches the corresponding dimension in the full_window
383 *
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000384 * @param[in] full_window Full window @p window has been created from.
385 * @param[in] first Start dimension into which the following are collapsed.
386 * @param[out] has_collapsed (Optional) Whether the window was collapsed.
Anthony Barbierbe35b0e2017-07-11 18:13:08 +0100387 *
388 * @return Collapsed window.
389 */
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000390 Window collapse_if_possible(const Window &full_window, size_t first, bool *has_collapsed = nullptr) const
391 {
392 return collapse_if_possible(full_window, first, Coordinates::num_max_dimensions, has_collapsed);
393 }
Anthony Barbierbe35b0e2017-07-11 18:13:08 +0100394
Alex Gildayc357c472018-03-21 13:54:09 +0000395 /** Collapse the dimensions between @p first and @p last.
Michalis Spyrou5237e012018-01-17 09:40:27 +0000396 *
397 * A dimension is collapsable if it starts from 0 and matches the corresponding dimension in the full_window
398 *
399 * @param[in] full_window Full window @p window has been created from.
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000400 * @param[in] first Start dimension into which the following are collapsed.
401 * @param[in] last End (exclusive) dimension to collapse.
Michalis Spyrou5237e012018-01-17 09:40:27 +0000402 *
403 * @return Collapsed window if successful.
404 */
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000405 Window collapse(const Window &full_window, size_t first, size_t last = Coordinates::num_max_dimensions) const;
406
Alex Gildayc357c472018-03-21 13:54:09 +0000407 /** Don't advance in the dimension where @p shape is less equal to 1.
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000408 *
409 * @param[in] shape A TensorShape.
410 *
411 * @return Broadcast window.
412 */
413 Window broadcast_if_dimension_le_one(const TensorShape &shape) const;
414
Alex Gildayc357c472018-03-21 13:54:09 +0000415 /** Don't advance in the dimension where shape of @p info is less equal to 1.
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000416 *
417 * @param[in] info An ITensorInfo.
418 *
419 * @return Broadcast window.
420 */
421 Window broadcast_if_dimension_le_one(const ITensorInfo &info) const
422 {
423 return broadcast_if_dimension_le_one(info.tensor_shape());
424 }
Georgios Pinitasf52cd782019-03-25 14:06:14 +0000425 /** Friend function that swaps the contents of two windows
426 *
427 * @param[in] lhs First window to swap.
428 * @param[in] rhs Second window to swap.
429 */
430 friend void swap(Window &lhs, Window &rhs);
SiCong Lib63b1192022-01-28 18:24:39 +0000431 /** Check whether two Windows are equal.
432 *
433 * @param[in] lhs LHS window
434 * @param[in] rhs RHS window
435 *
436 * @return True if the given windows are the same.
437 */
438 friend bool operator==(const Window &lhs, const Window &rhs);
Michalis Spyrou5237e012018-01-17 09:40:27 +0000439
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100440private:
441 /** First slice of the window
442 *
443 * @return The first slice of the window.
444 */
445 template <unsigned int window_dimension>
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100446 Window first_slice_window() const;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100447
448 /** Slide the passed window slice.
449 *
450 * If slice contains the last slice then it will remain unchanged and false will be returned.
451 *
452 * @param[in,out] slice Current slice, to be updated to the next slice.
453 *
454 * @return true if slice contains a new slice, false if slice already contained the last slice
455 */
456 template <unsigned int window_dimension>
457 bool slide_window_slice(Window &slice) const;
458
459private:
460 std::array<Dimension, Coordinates::num_max_dimensions> _dims;
Sang-Hoon Parkcecb0a72019-09-17 08:59:09 +0100461 std::array<bool, Coordinates::num_max_dimensions> _is_broadcasted;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100462};
Georgios Pinitasf52cd782019-03-25 14:06:14 +0000463} // namespace arm_compute
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100464#include "Window.inl"
Viet-Hoa Doc210c852023-10-09 10:58:35 +0100465#endif // ACL_ARM_COMPUTE_CORE_WINDOW_H