blob: 0f7c4fbdd72ad0b2b703326f3a13e2bd1904822b [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
Viet-Hoa Doc210c852023-10-09 10:58:35 +01002 * 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
25#ifndef ACL_ARM_COMPUTE_CORE_WINDOW_INL
26#define ACL_ARM_COMPUTE_CORE_WINDOW_INL
27
Anthony Barbier6ff3b192017-09-04 18:44:23 +010028namespace arm_compute
29{
30inline Window::Window(const Window &src)
Sang-Hoon Parkcecb0a72019-09-17 08:59:09 +010031 : _dims(), _is_broadcasted(utility::generate_array<bool, Coordinates::num_max_dimensions, false>::value)
Anthony Barbier6ff3b192017-09-04 18:44:23 +010032{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010033 for (size_t i = 0; i < Coordinates::num_max_dimensions; ++i)
Anthony Barbier6ff3b192017-09-04 18:44:23 +010034 {
35 set(i, src[i]);
Sang-Hoon Parkcecb0a72019-09-17 08:59:09 +010036 _is_broadcasted[i] = src.is_broadcasted(i);
Anthony Barbier6ff3b192017-09-04 18:44:23 +010037 }
38}
39
Georgios Pinitasf52cd782019-03-25 14:06:14 +000040inline Window &Window::operator=(const arm_compute::Window &rhs)
41{
42 Window tmp(rhs);
43 swap(*this, tmp);
44 return *this;
45}
46
Moritz Pflanzerc186b572017-09-07 09:48:04 +010047inline constexpr const Window::Dimension &Window::operator[](size_t dimension) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +010048{
49 // Precondition: dimension < Coordinates::num_max_dimensions
50 return _dims.at(dimension);
51}
Diego Lopez Recas0021d752017-12-18 14:42:56 +000052
Moritz Pflanzerc186b572017-09-07 09:48:04 +010053inline void Window::set(size_t dimension, const Window::Dimension &dim)
Anthony Barbier6ff3b192017-09-04 18:44:23 +010054{
55 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
56 _dims[dimension] = dim;
57}
58
Sang-Hoon Parkcecb0a72019-09-17 08:59:09 +010059inline void Window::set_broadcasted(size_t dimension)
60{
61 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
62 set(dimension, Dimension(0, 0, 0));
63 _is_broadcasted[dimension] = true;
64}
65
66inline bool Window::is_broadcasted(size_t dimension) const
67{
68 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
69 return _is_broadcasted[dimension];
70}
71
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010072inline Window Window::collapse_if_possible(const Window &full_window,
73 const size_t first,
74 const size_t last,
75 bool *has_collapsed) const
Anthony Barbierbe35b0e2017-07-11 18:13:08 +010076{
Diego Lopez Recas0021d752017-12-18 14:42:56 +000077 Window collapsed(*this);
Anthony Barbierbe35b0e2017-07-11 18:13:08 +010078
Diego Lopez Recas0021d752017-12-18 14:42:56 +000079 bool is_collapsable = true;
80 int collapsed_end = _dims[first].end();
81
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010082 for (size_t d = first + 1; is_collapsable && (d < last); ++d)
Diego Lopez Recas0021d752017-12-18 14:42:56 +000083 {
84 // The _dims's dimension must match the full _dims dimension to be collapsable:
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010085 is_collapsable = (_dims[d].start() == 0) && (full_window[d].start() == 0) && (_dims[d].step() <= 1) &&
86 (full_window[d].end() == _dims[d].end());
Diego Lopez Recas0021d752017-12-18 14:42:56 +000087 collapsed_end *= _dims[d].end();
88 }
89
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010090 if (is_collapsable)
Diego Lopez Recas0021d752017-12-18 14:42:56 +000091 {
92 collapsed._dims.at(first).set_end(collapsed_end);
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010093 for (size_t d = first + 1; is_collapsable && (d < last); ++d)
Anthony Barbierbe35b0e2017-07-11 18:13:08 +010094 {
Diego Lopez Recas0021d752017-12-18 14:42:56 +000095 collapsed.set(d, Dimension());
Anthony Barbierbe35b0e2017-07-11 18:13:08 +010096 }
97 }
Diego Lopez Recas0021d752017-12-18 14:42:56 +000098
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010099 if (has_collapsed != nullptr)
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000100 {
101 *has_collapsed = is_collapsable;
102 }
103
Anthony Barbierbe35b0e2017-07-11 18:13:08 +0100104 return collapsed;
105}
106
Viet-Hoa Doc210c852023-10-09 10:58:35 +0100107inline Window Window::shift_dimensions(unsigned int shift_value, unsigned int start_dim) const
Michalis Spyrou995f5522018-01-29 13:43:35 +0000108{
109 Window shifted_window;
Viet-Hoa Doc210c852023-10-09 10:58:35 +0100110 size_t n = 0;
111
112 for (; n < start_dim; ++n)
113 {
114 shifted_window.set(n, _dims[n]);
115 }
116
117 for (; n < (Coordinates::num_max_dimensions - shift_value); n++)
Michalis Spyrou995f5522018-01-29 13:43:35 +0000118 {
119 shifted_window.set(n, _dims[n + shift_value]);
120 }
Viet-Hoa Doc210c852023-10-09 10:58:35 +0100121
Michalis Spyrou995f5522018-01-29 13:43:35 +0000122 return shifted_window;
123}
124
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000125inline Window Window::collapse(const Window &full_window, const size_t first, const size_t last) const
Michalis Spyrou5237e012018-01-17 09:40:27 +0000126{
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000127 bool has_collapsed = false;
128 Window collapsed = collapse_if_possible(full_window, first, last, &has_collapsed);
Michalis Spyrou5237e012018-01-17 09:40:27 +0000129 // Make sure that the window has collapsed
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000130 ARM_COMPUTE_ERROR_ON(!has_collapsed);
Michalis Spyrou5237e012018-01-17 09:40:27 +0000131 return collapsed;
132}
133
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000134inline Window Window::broadcast_if_dimension_le_one(const TensorShape &shape) const
135{
136 Window broadcastWin(*this);
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100137 for (size_t d = 0; d < TensorShape::num_max_dimensions; ++d)
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000138 {
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100139 if (shape[d] <= 1)
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000140 {
Sang-Hoon Parkcecb0a72019-09-17 08:59:09 +0100141 broadcastWin.set_broadcasted(d);
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000142 }
143 }
144 return broadcastWin;
145}
146
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100147inline void Window::shift(size_t dimension, int shift_value)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100148{
149 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
150 Window::Dimension &d = _dims[dimension];
151 d = Window::Dimension(d.start() + shift_value, d.end() + shift_value, d.step());
152}
153
154inline void Window::adjust(size_t dimension, int adjust_value, bool is_at_start)
155{
156 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
157 Window::Dimension &d = _dims[dimension];
158
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100159 if (is_at_start)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100160 {
161 d = Window::Dimension(d.start() + adjust_value, d.end(), d.step());
162 }
163 else
164 {
165 d = Window::Dimension(d.start(), d.end() + adjust_value, d.step());
166 }
167}
168
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100169inline void Window::scale(size_t dimension, float scale_value)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100170{
171 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
Anthony Barbier7d920f42018-06-04 14:09:09 +0100172 Window::Dimension &d = _dims[dimension];
173 const int scaled_step = d.step() * scale_value;
174 const int scaled_start = d.start() * scale_value;
175 const int scaled_diff = (d.end() - d.start()) * scale_value;
176 const int scaled_end = scaled_start + ceil_to_multiple(scaled_diff, scaled_step);
177
178 d = Window::Dimension(scaled_start, scaled_end, scaled_step);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100179}
180
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100181inline void Window::set_dimension_step(size_t dimension, int step)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100182{
183 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
184 _dims[dimension].set_step(step);
185}
186
187inline void Window::validate() const
188{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100189 for (size_t i = 0; i < Coordinates::num_max_dimensions; ++i)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100190 {
Moritz Pflanzer6c6597c2017-09-24 12:09:41 +0100191 ARM_COMPUTE_ERROR_ON(_dims[i].end() < _dims[i].start());
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000192 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 +0100193 }
194}
195
196inline constexpr size_t Window::num_iterations(size_t dimension) const
197{
198 // Precondition: dimension < Coordinates::num_max_dimensions
199 // Precondition: (end - start) % step == 0
200 return (_dims.at(dimension).end() - _dims.at(dimension).start()) / _dims.at(dimension).step();
201}
202
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100203inline Window Window::split_window(size_t dimension, size_t id, size_t total) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100204{
205 ARM_COMPUTE_ERROR_ON(id >= total);
206 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
207
208 Window out;
209
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100210 for (size_t d = 0; d < Coordinates::num_max_dimensions; ++d)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100211 {
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100212 if (d == dimension)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100213 {
Sheri Zhangd80792a2020-11-05 10:43:37 +0000214 int start = _dims[d].start();
215 int end = _dims[d].end();
216 const int step = _dims[d].step();
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100217
Joseph Dobson51ca6ae2020-02-11 13:10:39 +0000218 const int num_it = num_iterations(d);
219 const int rem = num_it % total;
Sheri Zhangd80792a2020-11-05 10:43:37 +0000220 int work = num_it / total;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100221
Sheri Zhangd80792a2020-11-05 10:43:37 +0000222 int it_start = work * id;
Joseph Dobson51ca6ae2020-02-11 13:10:39 +0000223
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100224 if (int(id) < rem)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100225 {
Joseph Dobson51ca6ae2020-02-11 13:10:39 +0000226 ++work;
227 it_start += id;
228 }
229 else
230 {
231 it_start += rem;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100232 }
233
Joseph Dobson51ca6ae2020-02-11 13:10:39 +0000234 start += it_start * step;
235 end = std::min(end, start + work * step);
236
237 out.set(d, Dimension(start, end, step));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100238 }
239 else
240 {
241 out.set(d, _dims[d]);
242 }
243 }
244
245 return out;
246}
247
248template <unsigned int window_dimension>
249inline bool Window::slide_window_slice(Window &slice) const
250{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100251 for (unsigned int n = window_dimension; n < Coordinates::num_max_dimensions; ++n)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100252 {
253 // Did we reach the end of this dimension?
254 const int v = slice._dims[n].start() + 1;
255
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100256 if (v < _dims[n].end())
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100257 {
258 // No: increment
259 slice._dims[n] = Dimension(v, v + 1, 1);
260
261 // Reset lower dimensions:
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100262 for (unsigned int lower = window_dimension; lower < n; ++lower)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100263 {
264 slice._dims[lower] = Dimension(_dims[lower].start(), _dims[lower].start() + 1, 1);
265 }
266 return true;
267 }
268 }
269
270 // It was the last slice
271 return false; // Iteration over
272}
273
274template <unsigned int window_dimension>
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100275inline Window Window::first_slice_window() const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100276{
277 Window slice;
278
279 std::copy_n(_dims.begin(), window_dimension, slice._dims.begin());
280
281 //Initialise higher dimensions to be the first slice.
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100282 for (unsigned int n = window_dimension; n < Coordinates::num_max_dimensions; ++n)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100283 {
284 slice._dims[n] = Dimension(_dims[n].start(), _dims[n].start() + 1, 1);
285 }
286
287 return slice;
288}
289
SiCong Li86b53332017-08-23 11:02:43 +0100290inline void Window::use_tensor_dimensions(const TensorShape &shape, size_t first_dimension)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100291{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100292 for (unsigned int n = first_dimension; n < shape.num_dimensions(); ++n)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100293 {
Sheri Zhangd80792a2020-11-05 10:43:37 +0000294 set(n, Window::Dimension(0, std::max(shape[n], static_cast<size_t>(1))));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100295 }
296}
Anthony Barbier671a11e2018-07-06 15:11:36 +0100297
298inline TensorShape Window::shape() const
299{
300 TensorShape shape;
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100301 for (size_t d = 0; d < TensorShape::num_max_dimensions; ++d)
Anthony Barbier671a11e2018-07-06 15:11:36 +0100302 {
303 shape.set(d, (_dims[d].end() - _dims[d].start()) / _dims[d].step());
304 }
305 return shape;
306}
307
308inline size_t Window::num_iterations_total() const
309{
310 size_t total = 1;
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100311 for (size_t d = 0; d < Coordinates::num_max_dimensions; ++d)
Anthony Barbier671a11e2018-07-06 15:11:36 +0100312 {
313 total *= num_iterations(d);
314 }
315 return total;
316}
Georgios Pinitasf52cd782019-03-25 14:06:14 +0000317
318inline void swap(Window &lhs, Window &rhs)
319{
320 lhs._dims.swap(rhs._dims);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100321}
SiCong Lib63b1192022-01-28 18:24:39 +0000322
323inline bool operator==(const Window &lhs, const Window &rhs)
324{
325 return (lhs._dims == rhs._dims) && (lhs._is_broadcasted == rhs._is_broadcasted);
326}
Georgios Pinitasf52cd782019-03-25 14:06:14 +0000327} // namespace arm_compute
Viet-Hoa Doc210c852023-10-09 10:58:35 +0100328
329#endif // ACL_ARM_COMPUTE_CORE_WINDOW_INL