blob: d935507b1d8b7a1ef9d4eff5671bd05333d182ab [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 */
24namespace arm_compute
25{
26inline Window::Window(const Window &src)
Sang-Hoon Parkcecb0a72019-09-17 08:59:09 +010027 : _dims(), _is_broadcasted(utility::generate_array<bool, Coordinates::num_max_dimensions, false>::value)
Anthony Barbier6ff3b192017-09-04 18:44:23 +010028{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010029 for (size_t i = 0; i < Coordinates::num_max_dimensions; ++i)
Anthony Barbier6ff3b192017-09-04 18:44:23 +010030 {
31 set(i, src[i]);
Sang-Hoon Parkcecb0a72019-09-17 08:59:09 +010032 _is_broadcasted[i] = src.is_broadcasted(i);
Anthony Barbier6ff3b192017-09-04 18:44:23 +010033 }
34}
35
Georgios Pinitasf52cd782019-03-25 14:06:14 +000036inline Window &Window::operator=(const arm_compute::Window &rhs)
37{
38 Window tmp(rhs);
39 swap(*this, tmp);
40 return *this;
41}
42
Moritz Pflanzerc186b572017-09-07 09:48:04 +010043inline constexpr const Window::Dimension &Window::operator[](size_t dimension) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +010044{
45 // Precondition: dimension < Coordinates::num_max_dimensions
46 return _dims.at(dimension);
47}
Diego Lopez Recas0021d752017-12-18 14:42:56 +000048
Moritz Pflanzerc186b572017-09-07 09:48:04 +010049inline void Window::set(size_t dimension, const Window::Dimension &dim)
Anthony Barbier6ff3b192017-09-04 18:44:23 +010050{
51 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
52 _dims[dimension] = dim;
53}
54
Sang-Hoon Parkcecb0a72019-09-17 08:59:09 +010055inline void Window::set_broadcasted(size_t dimension)
56{
57 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
58 set(dimension, Dimension(0, 0, 0));
59 _is_broadcasted[dimension] = true;
60}
61
62inline bool Window::is_broadcasted(size_t dimension) const
63{
64 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
65 return _is_broadcasted[dimension];
66}
67
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010068inline Window Window::collapse_if_possible(const Window &full_window,
69 const size_t first,
70 const size_t last,
71 bool *has_collapsed) const
Anthony Barbierbe35b0e2017-07-11 18:13:08 +010072{
Diego Lopez Recas0021d752017-12-18 14:42:56 +000073 Window collapsed(*this);
Anthony Barbierbe35b0e2017-07-11 18:13:08 +010074
Diego Lopez Recas0021d752017-12-18 14:42:56 +000075 bool is_collapsable = true;
76 int collapsed_end = _dims[first].end();
77
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010078 for (size_t d = first + 1; is_collapsable && (d < last); ++d)
Diego Lopez Recas0021d752017-12-18 14:42:56 +000079 {
80 // The _dims's dimension must match the full _dims dimension to be collapsable:
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010081 is_collapsable = (_dims[d].start() == 0) && (full_window[d].start() == 0) && (_dims[d].step() <= 1) &&
82 (full_window[d].end() == _dims[d].end());
Diego Lopez Recas0021d752017-12-18 14:42:56 +000083 collapsed_end *= _dims[d].end();
84 }
85
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010086 if (is_collapsable)
Diego Lopez Recas0021d752017-12-18 14:42:56 +000087 {
88 collapsed._dims.at(first).set_end(collapsed_end);
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010089 for (size_t d = first + 1; is_collapsable && (d < last); ++d)
Anthony Barbierbe35b0e2017-07-11 18:13:08 +010090 {
Diego Lopez Recas0021d752017-12-18 14:42:56 +000091 collapsed.set(d, Dimension());
Anthony Barbierbe35b0e2017-07-11 18:13:08 +010092 }
93 }
Diego Lopez Recas0021d752017-12-18 14:42:56 +000094
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010095 if (has_collapsed != nullptr)
Diego Lopez Recas0021d752017-12-18 14:42:56 +000096 {
97 *has_collapsed = is_collapsable;
98 }
99
Anthony Barbierbe35b0e2017-07-11 18:13:08 +0100100 return collapsed;
101}
102
Michalis Spyrou995f5522018-01-29 13:43:35 +0000103inline Window Window::shift_dimensions(unsigned int shift_value) const
104{
105 Window shifted_window;
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100106 for (size_t n = 0; n < (Coordinates::num_max_dimensions - shift_value); n++)
Michalis Spyrou995f5522018-01-29 13:43:35 +0000107 {
108 shifted_window.set(n, _dims[n + shift_value]);
109 }
110 return shifted_window;
111}
112
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000113inline Window Window::collapse(const Window &full_window, const size_t first, const size_t last) const
Michalis Spyrou5237e012018-01-17 09:40:27 +0000114{
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000115 bool has_collapsed = false;
116 Window collapsed = collapse_if_possible(full_window, first, last, &has_collapsed);
Michalis Spyrou5237e012018-01-17 09:40:27 +0000117 // Make sure that the window has collapsed
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000118 ARM_COMPUTE_ERROR_ON(!has_collapsed);
Michalis Spyrou5237e012018-01-17 09:40:27 +0000119 return collapsed;
120}
121
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000122inline Window Window::broadcast_if_dimension_le_one(const TensorShape &shape) const
123{
124 Window broadcastWin(*this);
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100125 for (size_t d = 0; d < TensorShape::num_max_dimensions; ++d)
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000126 {
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100127 if (shape[d] <= 1)
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000128 {
Sang-Hoon Parkcecb0a72019-09-17 08:59:09 +0100129 broadcastWin.set_broadcasted(d);
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000130 }
131 }
132 return broadcastWin;
133}
134
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100135inline void Window::shift(size_t dimension, int shift_value)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100136{
137 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
138 Window::Dimension &d = _dims[dimension];
139 d = Window::Dimension(d.start() + shift_value, d.end() + shift_value, d.step());
140}
141
142inline void Window::adjust(size_t dimension, int adjust_value, bool is_at_start)
143{
144 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
145 Window::Dimension &d = _dims[dimension];
146
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100147 if (is_at_start)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100148 {
149 d = Window::Dimension(d.start() + adjust_value, d.end(), d.step());
150 }
151 else
152 {
153 d = Window::Dimension(d.start(), d.end() + adjust_value, d.step());
154 }
155}
156
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100157inline void Window::scale(size_t dimension, float scale_value)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100158{
159 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
Anthony Barbier7d920f42018-06-04 14:09:09 +0100160 Window::Dimension &d = _dims[dimension];
161 const int scaled_step = d.step() * scale_value;
162 const int scaled_start = d.start() * scale_value;
163 const int scaled_diff = (d.end() - d.start()) * scale_value;
164 const int scaled_end = scaled_start + ceil_to_multiple(scaled_diff, scaled_step);
165
166 d = Window::Dimension(scaled_start, scaled_end, scaled_step);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100167}
168
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100169inline void Window::set_dimension_step(size_t dimension, int step)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100170{
171 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
172 _dims[dimension].set_step(step);
173}
174
175inline void Window::validate() const
176{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100177 for (size_t i = 0; i < Coordinates::num_max_dimensions; ++i)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100178 {
Moritz Pflanzer6c6597c2017-09-24 12:09:41 +0100179 ARM_COMPUTE_ERROR_ON(_dims[i].end() < _dims[i].start());
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000180 ARM_COMPUTE_ERROR_ON((_dims[i].step() != 0) && (((_dims[i].end() - _dims[i].start()) % _dims[i].step()) != 0));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100181 }
182}
183
184inline constexpr size_t Window::num_iterations(size_t dimension) const
185{
186 // Precondition: dimension < Coordinates::num_max_dimensions
187 // Precondition: (end - start) % step == 0
188 return (_dims.at(dimension).end() - _dims.at(dimension).start()) / _dims.at(dimension).step();
189}
190
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100191inline Window Window::split_window(size_t dimension, size_t id, size_t total) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100192{
193 ARM_COMPUTE_ERROR_ON(id >= total);
194 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
195
196 Window out;
197
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100198 for (size_t d = 0; d < Coordinates::num_max_dimensions; ++d)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100199 {
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100200 if (d == dimension)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100201 {
Sheri Zhangd80792a2020-11-05 10:43:37 +0000202 int start = _dims[d].start();
203 int end = _dims[d].end();
204 const int step = _dims[d].step();
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100205
Joseph Dobson51ca6ae2020-02-11 13:10:39 +0000206 const int num_it = num_iterations(d);
207 const int rem = num_it % total;
Sheri Zhangd80792a2020-11-05 10:43:37 +0000208 int work = num_it / total;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100209
Sheri Zhangd80792a2020-11-05 10:43:37 +0000210 int it_start = work * id;
Joseph Dobson51ca6ae2020-02-11 13:10:39 +0000211
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100212 if (int(id) < rem)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100213 {
Joseph Dobson51ca6ae2020-02-11 13:10:39 +0000214 ++work;
215 it_start += id;
216 }
217 else
218 {
219 it_start += rem;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100220 }
221
Joseph Dobson51ca6ae2020-02-11 13:10:39 +0000222 start += it_start * step;
223 end = std::min(end, start + work * step);
224
225 out.set(d, Dimension(start, end, step));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100226 }
227 else
228 {
229 out.set(d, _dims[d]);
230 }
231 }
232
233 return out;
234}
235
236template <unsigned int window_dimension>
237inline bool Window::slide_window_slice(Window &slice) const
238{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100239 for (unsigned int n = window_dimension; n < Coordinates::num_max_dimensions; ++n)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100240 {
241 // Did we reach the end of this dimension?
242 const int v = slice._dims[n].start() + 1;
243
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100244 if (v < _dims[n].end())
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100245 {
246 // No: increment
247 slice._dims[n] = Dimension(v, v + 1, 1);
248
249 // Reset lower dimensions:
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100250 for (unsigned int lower = window_dimension; lower < n; ++lower)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100251 {
252 slice._dims[lower] = Dimension(_dims[lower].start(), _dims[lower].start() + 1, 1);
253 }
254 return true;
255 }
256 }
257
258 // It was the last slice
259 return false; // Iteration over
260}
261
262template <unsigned int window_dimension>
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100263inline Window Window::first_slice_window() const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100264{
265 Window slice;
266
267 std::copy_n(_dims.begin(), window_dimension, slice._dims.begin());
268
269 //Initialise higher dimensions to be the first slice.
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100270 for (unsigned int n = window_dimension; n < Coordinates::num_max_dimensions; ++n)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100271 {
272 slice._dims[n] = Dimension(_dims[n].start(), _dims[n].start() + 1, 1);
273 }
274
275 return slice;
276}
277
SiCong Li86b53332017-08-23 11:02:43 +0100278inline void Window::use_tensor_dimensions(const TensorShape &shape, size_t first_dimension)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100279{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100280 for (unsigned int n = first_dimension; n < shape.num_dimensions(); ++n)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100281 {
Sheri Zhangd80792a2020-11-05 10:43:37 +0000282 set(n, Window::Dimension(0, std::max(shape[n], static_cast<size_t>(1))));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100283 }
284}
Anthony Barbier671a11e2018-07-06 15:11:36 +0100285
286inline TensorShape Window::shape() const
287{
288 TensorShape shape;
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100289 for (size_t d = 0; d < TensorShape::num_max_dimensions; ++d)
Anthony Barbier671a11e2018-07-06 15:11:36 +0100290 {
291 shape.set(d, (_dims[d].end() - _dims[d].start()) / _dims[d].step());
292 }
293 return shape;
294}
295
296inline size_t Window::num_iterations_total() const
297{
298 size_t total = 1;
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100299 for (size_t d = 0; d < Coordinates::num_max_dimensions; ++d)
Anthony Barbier671a11e2018-07-06 15:11:36 +0100300 {
301 total *= num_iterations(d);
302 }
303 return total;
304}
Georgios Pinitasf52cd782019-03-25 14:06:14 +0000305
306inline void swap(Window &lhs, Window &rhs)
307{
308 lhs._dims.swap(rhs._dims);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100309}
SiCong Lib63b1192022-01-28 18:24:39 +0000310
311inline bool operator==(const Window &lhs, const Window &rhs)
312{
313 return (lhs._dims == rhs._dims) && (lhs._is_broadcasted == rhs._is_broadcasted);
314}
Georgios Pinitasf52cd782019-03-25 14:06:14 +0000315} // namespace arm_compute