blob: 8ae859f4b325902744fa67a40228035e6383e775 [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 */
Michalis Spyrouf4643372019-11-29 16:17:13 +000024#ifndef ARM_COMPUTE_WINDOW_H
25#define ARM_COMPUTE_WINDOW_H
Anthony Barbier6ff3b192017-09-04 18:44:23 +010026
27#include <algorithm>
28#include <array>
29#include <cstddef>
30
31#include "arm_compute/core/Coordinates.h"
32#include "arm_compute/core/Error.h"
33#include "arm_compute/core/ITensorInfo.h"
Matthew Bentham043613f2023-05-30 16:43:14 +000034#include "arm_compute/core/utils/math/Math.h"
Anthony Barbier6ff3b192017-09-04 18:44:23 +010035
36namespace 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 */
89 constexpr Dimension(int start = 0, int end = 1, int step = 1)
90 : _start(start), _end(end), _step(step)
91 {
92 }
Pablo Marquez Tello586fff92022-06-10 09:20:14 +010093 Dimension(const Dimension &d) = default;
Anthony Barbier6ff3b192017-09-04 18:44:23 +010094 /** Default assignment operator to allow dimensions to be copied */
95 Dimension &operator=(const Dimension &d) = default;
96 /** Return the start of the dimension */
97 constexpr int start() const
98 {
99 return _start;
100 }
101 /** Return the end of the dimension */
102 constexpr int end() const
103 {
104 return _end;
105 }
106 /** Return the step of the dimension */
107 constexpr int step() const
108 {
109 return _step;
110 }
111 /** Set the dimension's step
112 *
113 * @param[in] step The new step
114 */
115 void set_step(int step)
116 {
117 _step = step;
118 }
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000119 /** Set the dimension's end
120 *
121 * @param[in] end The new end
122 */
123 void set_end(int end)
124 {
125 _end = end;
126 }
SiCong Lib63b1192022-01-28 18:24:39 +0000127 /** Check whether two Dimensions are equal.
128 *
129 * @param[in] lhs LHS Dimensions
130 * @param[in] rhs RHS Dimensions
131 *
132 * @return True if the Dimensions are the same.
133 */
134 friend bool operator==(const Dimension &lhs, const Dimension &rhs)
135 {
136 return (lhs._start == rhs._start) && (lhs._end == rhs._end) && (lhs._step == rhs._step);
137 }
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100138
139 private:
140 int _start; /**< Start of the dimension */
141 int _end; /**< End of the dimension */
142 int _step;
143 };
144
145 /** Read only access to a given dimension of the window
146 *
147 * @note Precondition: dimension < Coordinates::num_max_dimensions
148 *
149 * @param[in] dimension The dimension to access
150 *
151 * @return The requested dimension
152 */
153 constexpr const Dimension &operator[](size_t dimension) const;
154
155 /** Alias to access the first dimension of the window
156 *
157 * @return First dimension of the window
158 */
159 constexpr const Dimension &x() const
160 {
161 return _dims.at(Window::DimX);
162 }
163
164 /** Alias to access the second dimension of the window
165 *
166 * @return Second dimension of the window
167 */
168 constexpr const Dimension &y() const
169 {
170 return _dims.at(Window::DimY);
171 }
172
173 /** Alias to access the third dimension of the window
174 *
175 * @return Third dimension of the window
176 */
177 constexpr const Dimension &z() const
178 {
179 return _dims.at(Window::DimZ);
180 }
181
182 /** Set the values of a given dimension
183 *
184 * @param[in] dimension The dimension to set
185 * @param[in] dim The values to set the dimension to
186 */
187 void set(size_t dimension, const Dimension &dim);
188
Sang-Hoon Parkcecb0a72019-09-17 08:59:09 +0100189 /** Set the dimension as broadcasted dimension
190 *
191 * @param[in] dimension The dimension to set
192 */
193 void set_broadcasted(size_t dimension);
194
195 /** Return whether a dimension has been broadcasted
196 *
197 * @param[in] dimension The requested dimension
198 *
199 * @return true if the dimension has been broadcasted
200 */
201 bool is_broadcasted(size_t dimension) const;
202
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100203 /** Use the tensor's dimensions to fill the window dimensions.
204 *
SiCong Li86b53332017-08-23 11:02:43 +0100205 * @param[in] shape @ref TensorShape to copy the dimensions from.
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100206 * @param[in] first_dimension Only copy dimensions which are greater or equal to this value.
207 */
SiCong Li86b53332017-08-23 11:02:43 +0100208 void use_tensor_dimensions(const TensorShape &shape, size_t first_dimension = Window::DimX);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100209
210 /** Shift the values of a given dimension by the given shift_value
211 *
212 * @param[in] dimension The dimension to shift
213 * @param[in] shift_value Value to shift the start and end values of.
214 */
215 void shift(size_t dimension, int shift_value);
216
Michalis Spyrou995f5522018-01-29 13:43:35 +0000217 /** Shift down all the dimensions of a window
218 *
219 * i.e new_dims[n] = old_dims[n+shift_value].
220 *
221 * @param[in] shift_value Number of dimensions to shift the window by.
222 *
223 * @return The window with the shifted dimensions.
224 */
225 Window shift_dimensions(unsigned int shift_value) const;
226
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100227 /** Adjust the start or end of a given dimension by the given value
228 *
229 * @param[in] dimension The dimension to adjust
230 * @param[in] adjust_value The adjusted value.
231 * @param[in] is_at_start The flag to indicate whether adjust the start or end of the dimension.
232 */
233 void adjust(size_t dimension, int adjust_value, bool is_at_start);
234
235 /** Scale the values of a given dimension by the given scale_value
236 *
237 * @note The end of the window is rounded up to be a multiple of step after the scaling.
238 *
239 * @param[in] dimension The dimension to scale
240 * @param[in] scale_value Value to scale the start, end and step values of.
241 */
242 void scale(size_t dimension, float scale_value);
243
244 /** Set the step of a given dimension.
245 *
246 * @param[in] dimension Dimension to update
247 * @param[in] step The new dimension's step value
248 */
249 void set_dimension_step(size_t dimension, int step);
250
251 /** Will validate all the window's dimensions' values when asserts are enabled
252 *
253 * No-op when asserts are disabled
254 */
255 void validate() const;
256
257 /** Return the number of iterations needed to iterate through a given dimension
258 *
259 * @param[in] dimension The requested dimension
260 *
261 * @return The number of iterations
262 */
263 constexpr size_t num_iterations(size_t dimension) const;
Anthony Barbier671a11e2018-07-06 15:11:36 +0100264 /** Return the total number of iterations needed to iterate through the entire window
265 *
266 * @return Number of total iterations
267 */
268 size_t num_iterations_total() const;
269 /** Return the shape of the window in number of steps */
270 TensorShape shape() const;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100271 /** Split a window into a set of sub windows along a given dimension
272 *
273 * For example to split a window into 3 sub-windows along the Y axis, you would have to do:<br/>
274 * Window sub0 = window.split_window( 1, 0, 3);<br/>
275 * Window sub1 = window.split_window( 1, 1, 3);<br/>
276 * Window sub2 = window.split_window( 1, 2, 3);<br/>
277 *
278 * @param[in] dimension Dimension along which the split will be performed
279 * @param[in] id Id of the sub-window to return. Must be in the range (0, total-1)
280 * @param[in] total Total number of sub-windows the window will be split into.
281 *
282 * @return The subwindow "id" out of "total"
283 */
284 Window split_window(size_t dimension, size_t id, size_t total) const;
285 /** First 1D slice of the window
286 *
287 * @return The first slice of the window.
288 */
289 Window first_slice_window_1D() const
290 {
291 return first_slice_window<1>();
292 };
293 /** First 2D slice of the window
294 *
295 * @return The first slice of the window.
296 */
297 Window first_slice_window_2D() const
298 {
299 return first_slice_window<2>();
300 };
301 /** First 3D slice of the window
302 *
303 * @return The first slice of the window.
304 */
305 Window first_slice_window_3D() const
306 {
307 return first_slice_window<3>();
308 };
Michalis Spyrou5237e012018-01-17 09:40:27 +0000309 /** First 4D slice of the window
310 *
311 * @return The first slice of the window.
312 */
313 Window first_slice_window_4D() const
314 {
315 return first_slice_window<4>();
316 };
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100317 /** Slide the passed 1D window slice.
318 *
319 * If slice contains the last slice then it will remain unchanged and false will be returned.
320 *
321 * @param[in,out] slice Current slice, to be updated to the next slice.
322 *
323 * @return true if slice contains a new slice, false if slice already contained the last slice
324 */
325 bool slide_window_slice_1D(Window &slice) const
326 {
327 return slide_window_slice<1>(slice);
328 }
329 /** Slide the passed 2D window slice.
330 *
331 * If slice contains the last slice then it will remain unchanged and false will be returned.
332 *
333 * @param[in,out] slice Current slice, to be updated to the next slice.
334 *
335 * @return true if slice contains a new slice, false if slice already contained the last slice
336 */
337 bool slide_window_slice_2D(Window &slice) const
338 {
339 return slide_window_slice<2>(slice);
340 }
341 /** Slide the passed 3D window slice.
342 *
343 * If slice contains the last slice then it will remain unchanged and false will be returned.
344 *
345 * @param[in,out] slice Current slice, to be updated to the next slice.
346 *
347 * @return true if slice contains a new slice, false if slice already contained the last slice
348 */
349 bool slide_window_slice_3D(Window &slice) const
350 {
351 return slide_window_slice<3>(slice);
352 }
353 /** Slide the passed 4D window slice.
354 *
355 * If slice contains the last slice then it will remain unchanged and false will be returned.
356 *
357 * @param[in,out] slice Current slice, to be updated to the next slice.
358 *
359 * @return true if slice contains a new slice, false if slice already contained the last slice
360 */
361 bool slide_window_slice_4D(Window &slice) const
362 {
363 return slide_window_slice<4>(slice);
364 }
Alex Gildayc357c472018-03-21 13:54:09 +0000365 /** Collapse the dimensions between @p first and @p last if possible.
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000366 *
367 * A dimension is collapsable if it starts from 0 and matches the corresponding dimension in the full_window
368 *
369 * @param[in] full_window Full window @p window has been created from.
370 * @param[in] first Start dimension into which the following are collapsed.
371 * @param[in] last End (exclusive) dimension to collapse.
372 * @param[out] has_collapsed (Optional) Whether the window was collapsed.
373 *
374 * @return Collapsed window.
375 */
376 Window collapse_if_possible(const Window &full_window, size_t first, size_t last, bool *has_collapsed = nullptr) const;
377
Alex Gildayc357c472018-03-21 13:54:09 +0000378 /** Collapse the dimensions higher than @p first if possible.
Anthony Barbierbe35b0e2017-07-11 18:13:08 +0100379 *
380 * A dimension is collapsable if it starts from 0 and matches the corresponding dimension in the full_window
381 *
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000382 * @param[in] full_window Full window @p window has been created from.
383 * @param[in] first Start dimension into which the following are collapsed.
384 * @param[out] has_collapsed (Optional) Whether the window was collapsed.
Anthony Barbierbe35b0e2017-07-11 18:13:08 +0100385 *
386 * @return Collapsed window.
387 */
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000388 Window collapse_if_possible(const Window &full_window, size_t first, bool *has_collapsed = nullptr) const
389 {
390 return collapse_if_possible(full_window, first, Coordinates::num_max_dimensions, has_collapsed);
391 }
Anthony Barbierbe35b0e2017-07-11 18:13:08 +0100392
Alex Gildayc357c472018-03-21 13:54:09 +0000393 /** Collapse the dimensions between @p first and @p last.
Michalis Spyrou5237e012018-01-17 09:40:27 +0000394 *
395 * A dimension is collapsable if it starts from 0 and matches the corresponding dimension in the full_window
396 *
397 * @param[in] full_window Full window @p window has been created from.
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000398 * @param[in] first Start dimension into which the following are collapsed.
399 * @param[in] last End (exclusive) dimension to collapse.
Michalis Spyrou5237e012018-01-17 09:40:27 +0000400 *
401 * @return Collapsed window if successful.
402 */
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000403 Window collapse(const Window &full_window, size_t first, size_t last = Coordinates::num_max_dimensions) const;
404
Alex Gildayc357c472018-03-21 13:54:09 +0000405 /** Don't advance in the dimension where @p shape is less equal to 1.
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000406 *
407 * @param[in] shape A TensorShape.
408 *
409 * @return Broadcast window.
410 */
411 Window broadcast_if_dimension_le_one(const TensorShape &shape) const;
412
Alex Gildayc357c472018-03-21 13:54:09 +0000413 /** Don't advance in the dimension where shape of @p info is less equal to 1.
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000414 *
415 * @param[in] info An ITensorInfo.
416 *
417 * @return Broadcast window.
418 */
419 Window broadcast_if_dimension_le_one(const ITensorInfo &info) const
420 {
421 return broadcast_if_dimension_le_one(info.tensor_shape());
422 }
Georgios Pinitasf52cd782019-03-25 14:06:14 +0000423 /** Friend function that swaps the contents of two windows
424 *
425 * @param[in] lhs First window to swap.
426 * @param[in] rhs Second window to swap.
427 */
428 friend void swap(Window &lhs, Window &rhs);
SiCong Lib63b1192022-01-28 18:24:39 +0000429 /** Check whether two Windows are equal.
430 *
431 * @param[in] lhs LHS window
432 * @param[in] rhs RHS window
433 *
434 * @return True if the given windows are the same.
435 */
436 friend bool operator==(const Window &lhs, const Window &rhs);
Michalis Spyrou5237e012018-01-17 09:40:27 +0000437
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100438private:
439 /** First slice of the window
440 *
441 * @return The first slice of the window.
442 */
443 template <unsigned int window_dimension>
444 Window first_slice_window() const;
445
446 /** Slide the passed window slice.
447 *
448 * If slice contains the last slice then it will remain unchanged and false will be returned.
449 *
450 * @param[in,out] slice Current slice, to be updated to the next slice.
451 *
452 * @return true if slice contains a new slice, false if slice already contained the last slice
453 */
454 template <unsigned int window_dimension>
455 bool slide_window_slice(Window &slice) const;
456
457private:
458 std::array<Dimension, Coordinates::num_max_dimensions> _dims;
Sang-Hoon Parkcecb0a72019-09-17 08:59:09 +0100459 std::array<bool, Coordinates::num_max_dimensions> _is_broadcasted;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100460};
Georgios Pinitasf52cd782019-03-25 14:06:14 +0000461} // namespace arm_compute
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100462#include "Window.inl"
Michalis Spyrouf4643372019-11-29 16:17:13 +0000463#endif /*ARM_COMPUTE_WINDOW_H */