blob: c566cffa88e7066ad0d786424e69cf78a844b024 [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
SiCong Lib63b1192022-01-28 18:24:39 +00002 * Copyright (c) 2016-2020, 2022 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"
34#include "arm_compute/core/Utils.h"
35
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 }
93 /** 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 */
375 Window collapse_if_possible(const Window &full_window, size_t first, size_t last, bool *has_collapsed = nullptr) const;
376
Alex Gildayc357c472018-03-21 13:54:09 +0000377 /** Collapse the dimensions higher than @p first if possible.
Anthony Barbierbe35b0e2017-07-11 18:13:08 +0100378 *
379 * A dimension is collapsable if it starts from 0 and matches the corresponding dimension in the full_window
380 *
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000381 * @param[in] full_window Full window @p window has been created from.
382 * @param[in] first Start dimension into which the following are collapsed.
383 * @param[out] has_collapsed (Optional) Whether the window was collapsed.
Anthony Barbierbe35b0e2017-07-11 18:13:08 +0100384 *
385 * @return Collapsed window.
386 */
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000387 Window collapse_if_possible(const Window &full_window, size_t first, bool *has_collapsed = nullptr) const
388 {
389 return collapse_if_possible(full_window, first, Coordinates::num_max_dimensions, has_collapsed);
390 }
Anthony Barbierbe35b0e2017-07-11 18:13:08 +0100391
Alex Gildayc357c472018-03-21 13:54:09 +0000392 /** Collapse the dimensions between @p first and @p last.
Michalis Spyrou5237e012018-01-17 09:40:27 +0000393 *
394 * A dimension is collapsable if it starts from 0 and matches the corresponding dimension in the full_window
395 *
396 * @param[in] full_window Full window @p window has been created from.
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000397 * @param[in] first Start dimension into which the following are collapsed.
398 * @param[in] last End (exclusive) dimension to collapse.
Michalis Spyrou5237e012018-01-17 09:40:27 +0000399 *
400 * @return Collapsed window if successful.
401 */
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000402 Window collapse(const Window &full_window, size_t first, size_t last = Coordinates::num_max_dimensions) const;
403
Alex Gildayc357c472018-03-21 13:54:09 +0000404 /** Don't advance in the dimension where @p shape is less equal to 1.
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000405 *
406 * @param[in] shape A TensorShape.
407 *
408 * @return Broadcast window.
409 */
410 Window broadcast_if_dimension_le_one(const TensorShape &shape) const;
411
Alex Gildayc357c472018-03-21 13:54:09 +0000412 /** Don't advance in the dimension where shape of @p info is less equal to 1.
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000413 *
414 * @param[in] info An ITensorInfo.
415 *
416 * @return Broadcast window.
417 */
418 Window broadcast_if_dimension_le_one(const ITensorInfo &info) const
419 {
420 return broadcast_if_dimension_le_one(info.tensor_shape());
421 }
Georgios Pinitasf52cd782019-03-25 14:06:14 +0000422 /** Friend function that swaps the contents of two windows
423 *
424 * @param[in] lhs First window to swap.
425 * @param[in] rhs Second window to swap.
426 */
427 friend void swap(Window &lhs, Window &rhs);
SiCong Lib63b1192022-01-28 18:24:39 +0000428 /** Check whether two Windows are equal.
429 *
430 * @param[in] lhs LHS window
431 * @param[in] rhs RHS window
432 *
433 * @return True if the given windows are the same.
434 */
435 friend bool operator==(const Window &lhs, const Window &rhs);
Michalis Spyrou5237e012018-01-17 09:40:27 +0000436
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100437private:
438 /** First slice of the window
439 *
440 * @return The first slice of the window.
441 */
442 template <unsigned int window_dimension>
443 Window first_slice_window() const;
444
445 /** Slide the passed window slice.
446 *
447 * If slice contains the last slice then it will remain unchanged and false will be returned.
448 *
449 * @param[in,out] slice Current slice, to be updated to the next slice.
450 *
451 * @return true if slice contains a new slice, false if slice already contained the last slice
452 */
453 template <unsigned int window_dimension>
454 bool slide_window_slice(Window &slice) const;
455
456private:
457 std::array<Dimension, Coordinates::num_max_dimensions> _dims;
Sang-Hoon Parkcecb0a72019-09-17 08:59:09 +0100458 std::array<bool, Coordinates::num_max_dimensions> _is_broadcasted;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100459};
Georgios Pinitasf52cd782019-03-25 14:06:14 +0000460} // namespace arm_compute
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100461#include "Window.inl"
Michalis Spyrouf4643372019-11-29 16:17:13 +0000462#endif /*ARM_COMPUTE_WINDOW_H */