blob: eeef3df7b096999546ded723897a97e84b9d57ce [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
Georgios Pinitasf52cd782019-03-25 14:06:14 +00002 * Copyright (c) 2016-2019 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)
Moritz Pflanzerc186b572017-09-07 09:48:04 +010027 : _dims()
Anthony Barbier6ff3b192017-09-04 18:44:23 +010028{
29 for(size_t i = 0; i < Coordinates::num_max_dimensions; ++i)
30 {
31 set(i, src[i]);
32 }
33}
34
Georgios Pinitasf52cd782019-03-25 14:06:14 +000035inline Window &Window::operator=(const arm_compute::Window &rhs)
36{
37 Window tmp(rhs);
38 swap(*this, tmp);
39 return *this;
40}
41
Moritz Pflanzerc186b572017-09-07 09:48:04 +010042inline constexpr const Window::Dimension &Window::operator[](size_t dimension) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +010043{
44 // Precondition: dimension < Coordinates::num_max_dimensions
45 return _dims.at(dimension);
46}
Diego Lopez Recas0021d752017-12-18 14:42:56 +000047
Moritz Pflanzerc186b572017-09-07 09:48:04 +010048inline void Window::set(size_t dimension, const Window::Dimension &dim)
Anthony Barbier6ff3b192017-09-04 18:44:23 +010049{
50 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
51 _dims[dimension] = dim;
52}
53
Diego Lopez Recas0021d752017-12-18 14:42:56 +000054inline Window Window::collapse_if_possible(const Window &full_window, const size_t first,
55 const size_t last, bool *has_collapsed) const
Anthony Barbierbe35b0e2017-07-11 18:13:08 +010056{
Diego Lopez Recas0021d752017-12-18 14:42:56 +000057 Window collapsed(*this);
Anthony Barbierbe35b0e2017-07-11 18:13:08 +010058
Diego Lopez Recas0021d752017-12-18 14:42:56 +000059 bool is_collapsable = true;
60 int collapsed_end = _dims[first].end();
61
62 for(size_t d = first + 1; is_collapsable && (d < last); ++d)
63 {
64 // The _dims's dimension must match the full _dims dimension to be collapsable:
65 is_collapsable = (_dims[d].start() == 0) && (full_window[d].start() == 0) && (_dims[d].step() <= 1)
66 && (full_window[d].end() == _dims[d].end());
67 collapsed_end *= _dims[d].end();
68 }
69
70 if(is_collapsable)
71 {
72 collapsed._dims.at(first).set_end(collapsed_end);
73 for(size_t d = first + 1; is_collapsable && (d < last); ++d)
Anthony Barbierbe35b0e2017-07-11 18:13:08 +010074 {
Diego Lopez Recas0021d752017-12-18 14:42:56 +000075 collapsed.set(d, Dimension());
Anthony Barbierbe35b0e2017-07-11 18:13:08 +010076 }
77 }
Diego Lopez Recas0021d752017-12-18 14:42:56 +000078
79 if(has_collapsed != nullptr)
80 {
81 *has_collapsed = is_collapsable;
82 }
83
Anthony Barbierbe35b0e2017-07-11 18:13:08 +010084 return collapsed;
85}
86
Michalis Spyrou995f5522018-01-29 13:43:35 +000087inline Window Window::shift_dimensions(unsigned int shift_value) const
88{
89 Window shifted_window;
90 for(size_t n = 0; n < (Coordinates::num_max_dimensions - shift_value); n++)
91 {
92 shifted_window.set(n, _dims[n + shift_value]);
93 }
94 return shifted_window;
95}
96
Diego Lopez Recas0021d752017-12-18 14:42:56 +000097inline Window Window::collapse(const Window &full_window, const size_t first, const size_t last) const
Michalis Spyrou5237e012018-01-17 09:40:27 +000098{
Diego Lopez Recas0021d752017-12-18 14:42:56 +000099 bool has_collapsed = false;
100 Window collapsed = collapse_if_possible(full_window, first, last, &has_collapsed);
Michalis Spyrou5237e012018-01-17 09:40:27 +0000101 // Make sure that the window has collapsed
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000102 ARM_COMPUTE_ERROR_ON(!has_collapsed);
Michalis Spyrou5237e012018-01-17 09:40:27 +0000103 return collapsed;
104}
105
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000106inline Window Window::broadcast_if_dimension_le_one(const TensorShape &shape) const
107{
108 Window broadcastWin(*this);
109 for(size_t d = 0; d < TensorShape::num_max_dimensions; ++d)
110 {
111 if(shape[d] <= 1)
112 {
113 broadcastWin.set(d, Dimension(0, 0, 0));
114 }
115 }
116 return broadcastWin;
117}
118
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100119inline void Window::shift(size_t dimension, int shift_value)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100120{
121 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
122 Window::Dimension &d = _dims[dimension];
123 d = Window::Dimension(d.start() + shift_value, d.end() + shift_value, d.step());
124}
125
126inline void Window::adjust(size_t dimension, int adjust_value, bool is_at_start)
127{
128 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
129 Window::Dimension &d = _dims[dimension];
130
131 if(is_at_start)
132 {
133 d = Window::Dimension(d.start() + adjust_value, d.end(), d.step());
134 }
135 else
136 {
137 d = Window::Dimension(d.start(), d.end() + adjust_value, d.step());
138 }
139}
140
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100141inline void Window::scale(size_t dimension, float scale_value)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100142{
143 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
Anthony Barbier7d920f42018-06-04 14:09:09 +0100144 Window::Dimension &d = _dims[dimension];
145 const int scaled_step = d.step() * scale_value;
146 const int scaled_start = d.start() * scale_value;
147 const int scaled_diff = (d.end() - d.start()) * scale_value;
148 const int scaled_end = scaled_start + ceil_to_multiple(scaled_diff, scaled_step);
149
150 d = Window::Dimension(scaled_start, scaled_end, scaled_step);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100151}
152
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100153inline void Window::set_dimension_step(size_t dimension, int step)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100154{
155 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
156 _dims[dimension].set_step(step);
157}
158
159inline void Window::validate() const
160{
161 for(size_t i = 0; i < Coordinates::num_max_dimensions; ++i)
162 {
Moritz Pflanzer6c6597c2017-09-24 12:09:41 +0100163 ARM_COMPUTE_ERROR_ON(_dims[i].end() < _dims[i].start());
Diego Lopez Recas0021d752017-12-18 14:42:56 +0000164 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 +0100165 }
166}
167
168inline constexpr size_t Window::num_iterations(size_t dimension) const
169{
170 // Precondition: dimension < Coordinates::num_max_dimensions
171 // Precondition: (end - start) % step == 0
172 return (_dims.at(dimension).end() - _dims.at(dimension).start()) / _dims.at(dimension).step();
173}
174
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100175inline Window Window::split_window(size_t dimension, size_t id, size_t total) const
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100176{
177 ARM_COMPUTE_ERROR_ON(id >= total);
178 ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
179
180 Window out;
181
182 for(size_t d = 0; d < Coordinates::num_max_dimensions; ++d)
183 {
184 if(d == dimension)
185 {
186 int start = _dims[d].start();
187 int end = _dims[d].end();
188 int per_sub_window = (num_iterations(d) / total) * _dims[d].step();
189
190 start += id * per_sub_window;
191
192 if(id != total - 1)
193 {
194 end = start + per_sub_window;
195 }
196
197 out.set(d, Dimension(start, end, _dims[d].step()));
198 }
199 else
200 {
201 out.set(d, _dims[d]);
202 }
203 }
204
205 return out;
206}
207
208template <unsigned int window_dimension>
209inline bool Window::slide_window_slice(Window &slice) const
210{
211 for(unsigned int n = window_dimension; n < Coordinates::num_max_dimensions; ++n)
212 {
213 // Did we reach the end of this dimension?
214 const int v = slice._dims[n].start() + 1;
215
216 if(v < _dims[n].end())
217 {
218 // No: increment
219 slice._dims[n] = Dimension(v, v + 1, 1);
220
221 // Reset lower dimensions:
222 for(unsigned int lower = window_dimension; lower < n; ++lower)
223 {
224 slice._dims[lower] = Dimension(_dims[lower].start(), _dims[lower].start() + 1, 1);
225 }
226 return true;
227 }
228 }
229
230 // It was the last slice
231 return false; // Iteration over
232}
233
234template <unsigned int window_dimension>
235inline Window Window::first_slice_window() const
236{
237 Window slice;
238
239 std::copy_n(_dims.begin(), window_dimension, slice._dims.begin());
240
241 //Initialise higher dimensions to be the first slice.
242 for(unsigned int n = window_dimension; n < Coordinates::num_max_dimensions; ++n)
243 {
244 slice._dims[n] = Dimension(_dims[n].start(), _dims[n].start() + 1, 1);
245 }
246
247 return slice;
248}
249
SiCong Li86b53332017-08-23 11:02:43 +0100250inline void Window::use_tensor_dimensions(const TensorShape &shape, size_t first_dimension)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100251{
SiCong Li86b53332017-08-23 11:02:43 +0100252 for(unsigned int n = first_dimension; n < shape.num_dimensions(); ++n)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100253 {
SiCong Li86b53332017-08-23 11:02:43 +0100254 set(n, Window::Dimension(0, std::max(shape[n], static_cast<size_t>(1))));
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100255 }
256}
Anthony Barbier671a11e2018-07-06 15:11:36 +0100257
258inline TensorShape Window::shape() const
259{
260 TensorShape shape;
261 for(size_t d = 0; d < TensorShape::num_max_dimensions; ++d)
262 {
263 shape.set(d, (_dims[d].end() - _dims[d].start()) / _dims[d].step());
264 }
265 return shape;
266}
267
268inline size_t Window::num_iterations_total() const
269{
270 size_t total = 1;
271 for(size_t d = 0; d < Coordinates::num_max_dimensions; ++d)
272 {
273 total *= num_iterations(d);
274 }
275 return total;
276}
Georgios Pinitasf52cd782019-03-25 14:06:14 +0000277
278inline void swap(Window &lhs, Window &rhs)
279{
280 lhs._dims.swap(rhs._dims);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100281}
Georgios Pinitasf52cd782019-03-25 14:06:14 +0000282} // namespace arm_compute