blob: 4863b95045e85efe5c733686945eab52404f00e6 [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
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
Michalis Spyrou995f5522018-01-29 13:43:35 +0000216 /** Shift down all the dimensions of a window
217 *
218 * i.e new_dims[n] = old_dims[n+shift_value].
219 *
220 * @param[in] shift_value Number of dimensions to shift the window by.
221 *
222 * @return The window with the shifted dimensions.
223 */
224 Window shift_dimensions(unsigned int shift_value) const;
225
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100226 /** Adjust the start or end of a given dimension by the given value
227 *
228 * @param[in] dimension The dimension to adjust
229 * @param[in] adjust_value The adjusted value.
230 * @param[in] is_at_start The flag to indicate whether adjust the start or end of the dimension.
231 */
232 void adjust(size_t dimension, int adjust_value, bool is_at_start);
233
234 /** Scale the values of a given dimension by the given scale_value
235 *
236 * @note The end of the window is rounded up to be a multiple of step after the scaling.
237 *
238 * @param[in] dimension The dimension to scale
239 * @param[in] scale_value Value to scale the start, end and step values of.
240 */
241 void scale(size_t dimension, float scale_value);
242
243 /** Set the step of a given dimension.
244 *
245 * @param[in] dimension Dimension to update
246 * @param[in] step The new dimension's step value
247 */
248 void set_dimension_step(size_t dimension, int step);
249
250 /** Will validate all the window's dimensions' values when asserts are enabled
251 *
252 * No-op when asserts are disabled
253 */
254 void validate() const;
255
256 /** Return the number of iterations needed to iterate through a given dimension
257 *
258 * @param[in] dimension The requested dimension
259 *
260 * @return The number of iterations
261 */
262 constexpr size_t num_iterations(size_t dimension) const;
Anthony Barbier671a11e2018-07-06 15:11:36 +0100263 /** Return the total number of iterations needed to iterate through the entire window
264 *
265 * @return Number of total iterations
266 */
267 size_t num_iterations_total() const;
268 /** Return the shape of the window in number of steps */
269 TensorShape shape() const;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100270 /** Split a window into a set of sub windows along a given dimension
271 *
272 * For example to split a window into 3 sub-windows along the Y axis, you would have to do:<br/>
273 * Window sub0 = window.split_window( 1, 0, 3);<br/>
274 * Window sub1 = window.split_window( 1, 1, 3);<br/>
275 * Window sub2 = window.split_window( 1, 2, 3);<br/>
276 *
277 * @param[in] dimension Dimension along which the split will be performed
278 * @param[in] id Id of the sub-window to return. Must be in the range (0, total-1)
279 * @param[in] total Total number of sub-windows the window will be split into.
280 *
281 * @return The subwindow "id" out of "total"
282 */
283 Window split_window(size_t dimension, size_t id, size_t total) const;
284 /** First 1D slice of the window
285 *
286 * @return The first slice of the window.
287 */
288 Window first_slice_window_1D() const
289 {
290 return first_slice_window<1>();
291 };
292 /** First 2D slice of the window
293 *
294 * @return The first slice of the window.
295 */
296 Window first_slice_window_2D() const
297 {
298 return first_slice_window<2>();
299 };
300 /** First 3D slice of the window
301 *
302 * @return The first slice of the window.
303 */
304 Window first_slice_window_3D() const
305 {
306 return first_slice_window<3>();
307 };
Michalis Spyrou5237e012018-01-17 09:40:27 +0000308 /** First 4D slice of the window
309 *
310 * @return The first slice of the window.
311 */
312 Window first_slice_window_4D() const
313 {
314 return first_slice_window<4>();
315 };
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100316 /** Slide the passed 1D window slice.
317 *
318 * If slice contains the last slice then it will remain unchanged and false will be returned.
319 *
320 * @param[in,out] slice Current slice, to be updated to the next slice.
321 *
322 * @return true if slice contains a new slice, false if slice already contained the last slice
323 */
324 bool slide_window_slice_1D(Window &slice) const
325 {
326 return slide_window_slice<1>(slice);
327 }
328 /** Slide the passed 2D window slice.
329 *
330 * If slice contains the last slice then it will remain unchanged and false will be returned.
331 *
332 * @param[in,out] slice Current slice, to be updated to the next slice.
333 *
334 * @return true if slice contains a new slice, false if slice already contained the last slice
335 */
336 bool slide_window_slice_2D(Window &slice) const
337 {
338 return slide_window_slice<2>(slice);
339 }
340 /** Slide the passed 3D window slice.
341 *
342 * If slice contains the last slice then it will remain unchanged and false will be returned.
343 *
344 * @param[in,out] slice Current slice, to be updated to the next slice.
345 *
346 * @return true if slice contains a new slice, false if slice already contained the last slice
347 */
348 bool slide_window_slice_3D(Window &slice) const
349 {
350 return slide_window_slice<3>(slice);
351 }
352 /** Slide the passed 4D window slice.
353 *
354 * If slice contains the last slice then it will remain unchanged and false will be returned.
355 *
356 * @param[in,out] slice Current slice, to be updated to the next slice.
357 *
358 * @return true if slice contains a new slice, false if slice already contained the last slice
359 */
360 bool slide_window_slice_4D(Window &slice) const
361 {
362 return slide_window_slice<4>(slice);
363 }
Alex Gildayc357c472018-03-21 13:54:09 +0000364 /** Collapse the dimensions between @p first and @p last if possible.
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000365 *
366 * A dimension is collapsable if it starts from 0 and matches the corresponding dimension in the full_window
367 *
368 * @param[in] full_window Full window @p window has been created from.
369 * @param[in] first Start dimension into which the following are collapsed.
370 * @param[in] last End (exclusive) dimension to collapse.
371 * @param[out] has_collapsed (Optional) Whether the window was collapsed.
372 *
373 * @return Collapsed window.
374 */
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100375 Window
376 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 +0000377
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>
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100444 Window first_slice_window() const;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100445
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 */