• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2016-2020, 2022 Arm Limited.
3 *
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)
27    : _dims(), _is_broadcasted(utility::generate_array<bool, Coordinates::num_max_dimensions, false>::value)
28{
29    for(size_t i = 0; i < Coordinates::num_max_dimensions; ++i)
30    {
31        set(i, src[i]);
32        _is_broadcasted[i] = src.is_broadcasted(i);
33    }
34}
35
36inline Window &Window::operator=(const arm_compute::Window &rhs)
37{
38    Window tmp(rhs);
39    swap(*this, tmp);
40    return *this;
41}
42
43inline constexpr const Window::Dimension &Window::operator[](size_t dimension) const
44{
45    // Precondition: dimension < Coordinates::num_max_dimensions
46    return _dims.at(dimension);
47}
48
49inline void Window::set(size_t dimension, const Window::Dimension &dim)
50{
51    ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
52    _dims[dimension] = dim;
53}
54
55inline 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
68inline Window Window::collapse_if_possible(const Window &full_window, const size_t first,
69                                           const size_t last, bool *has_collapsed) const
70{
71    Window collapsed(*this);
72
73    bool is_collapsable = true;
74    int  collapsed_end  = _dims[first].end();
75
76    for(size_t d = first + 1; is_collapsable && (d < last); ++d)
77    {
78        // The _dims's dimension must match the full _dims dimension to be collapsable:
79        is_collapsable = (_dims[d].start() == 0) && (full_window[d].start() == 0) && (_dims[d].step() <= 1)
80                         && (full_window[d].end() == _dims[d].end());
81        collapsed_end *= _dims[d].end();
82    }
83
84    if(is_collapsable)
85    {
86        collapsed._dims.at(first).set_end(collapsed_end);
87        for(size_t d = first + 1; is_collapsable && (d < last); ++d)
88        {
89            collapsed.set(d, Dimension());
90        }
91    }
92
93    if(has_collapsed != nullptr)
94    {
95        *has_collapsed = is_collapsable;
96    }
97
98    return collapsed;
99}
100
101inline Window Window::shift_dimensions(unsigned int shift_value) const
102{
103    Window shifted_window;
104    for(size_t n = 0; n < (Coordinates::num_max_dimensions - shift_value); n++)
105    {
106        shifted_window.set(n, _dims[n + shift_value]);
107    }
108    return shifted_window;
109}
110
111inline Window Window::collapse(const Window &full_window, const size_t first, const size_t last) const
112{
113    bool   has_collapsed = false;
114    Window collapsed     = collapse_if_possible(full_window, first, last, &has_collapsed);
115    // Make sure that the window has collapsed
116    ARM_COMPUTE_ERROR_ON(!has_collapsed);
117    return collapsed;
118}
119
120inline Window Window::broadcast_if_dimension_le_one(const TensorShape &shape) const
121{
122    Window broadcastWin(*this);
123    for(size_t d = 0; d < TensorShape::num_max_dimensions; ++d)
124    {
125        if(shape[d] <= 1)
126        {
127            broadcastWin.set_broadcasted(d);
128        }
129    }
130    return broadcastWin;
131}
132
133inline void Window::shift(size_t dimension, int shift_value)
134{
135    ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
136    Window::Dimension &d = _dims[dimension];
137    d                    = Window::Dimension(d.start() + shift_value, d.end() + shift_value, d.step());
138}
139
140inline void Window::adjust(size_t dimension, int adjust_value, bool is_at_start)
141{
142    ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
143    Window::Dimension &d = _dims[dimension];
144
145    if(is_at_start)
146    {
147        d = Window::Dimension(d.start() + adjust_value, d.end(), d.step());
148    }
149    else
150    {
151        d = Window::Dimension(d.start(), d.end() + adjust_value, d.step());
152    }
153}
154
155inline void Window::scale(size_t dimension, float scale_value)
156{
157    ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
158    Window::Dimension &d            = _dims[dimension];
159    const int          scaled_step  = d.step() * scale_value;
160    const int          scaled_start = d.start() * scale_value;
161    const int          scaled_diff  = (d.end() - d.start()) * scale_value;
162    const int          scaled_end   = scaled_start + ceil_to_multiple(scaled_diff, scaled_step);
163
164    d = Window::Dimension(scaled_start, scaled_end, scaled_step);
165}
166
167inline void Window::set_dimension_step(size_t dimension, int step)
168{
169    ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
170    _dims[dimension].set_step(step);
171}
172
173inline void Window::validate() const
174{
175    for(size_t i = 0; i < Coordinates::num_max_dimensions; ++i)
176    {
177        ARM_COMPUTE_ERROR_ON(_dims[i].end() < _dims[i].start());
178        ARM_COMPUTE_ERROR_ON((_dims[i].step() != 0) && (((_dims[i].end() - _dims[i].start()) % _dims[i].step()) != 0));
179    }
180}
181
182inline constexpr size_t Window::num_iterations(size_t dimension) const
183{
184    // Precondition: dimension < Coordinates::num_max_dimensions
185    // Precondition: (end - start) % step == 0
186    return (_dims.at(dimension).end() - _dims.at(dimension).start()) / _dims.at(dimension).step();
187}
188
189inline Window Window::split_window(size_t dimension, size_t id, size_t total) const
190{
191    ARM_COMPUTE_ERROR_ON(id >= total);
192    ARM_COMPUTE_ERROR_ON(dimension >= Coordinates::num_max_dimensions);
193
194    Window out;
195
196    for(size_t d = 0; d < Coordinates::num_max_dimensions; ++d)
197    {
198        if(d == dimension)
199        {
200            int       start = _dims[d].start();
201            int       end   = _dims[d].end();
202            const int step  = _dims[d].step();
203
204            const int num_it = num_iterations(d);
205            const int rem    = num_it % total;
206            int       work   = num_it / total;
207
208            int it_start = work * id;
209
210            if(int(id) < rem)
211            {
212                ++work;
213                it_start += id;
214            }
215            else
216            {
217                it_start += rem;
218            }
219
220            start += it_start * step;
221            end = std::min(end, start + work * step);
222
223            out.set(d, Dimension(start, end, step));
224        }
225        else
226        {
227            out.set(d, _dims[d]);
228        }
229    }
230
231    return out;
232}
233
234template <unsigned int window_dimension>
235inline bool Window::slide_window_slice(Window &slice) const
236{
237    for(unsigned int n = window_dimension; n < Coordinates::num_max_dimensions; ++n)
238    {
239        // Did we reach the end of this dimension?
240        const int v = slice._dims[n].start() + 1;
241
242        if(v < _dims[n].end())
243        {
244            // No: increment
245            slice._dims[n] = Dimension(v, v + 1, 1);
246
247            // Reset lower dimensions:
248            for(unsigned int lower = window_dimension; lower < n; ++lower)
249            {
250                slice._dims[lower] = Dimension(_dims[lower].start(), _dims[lower].start() + 1, 1);
251            }
252            return true;
253        }
254    }
255
256    // It was the last slice
257    return false; // Iteration over
258}
259
260template <unsigned int window_dimension>
261inline Window          Window::first_slice_window() const
262{
263    Window slice;
264
265    std::copy_n(_dims.begin(), window_dimension, slice._dims.begin());
266
267    //Initialise higher dimensions to be the first slice.
268    for(unsigned int n = window_dimension; n < Coordinates::num_max_dimensions; ++n)
269    {
270        slice._dims[n] = Dimension(_dims[n].start(), _dims[n].start() + 1, 1);
271    }
272
273    return slice;
274}
275
276inline void Window::use_tensor_dimensions(const TensorShape &shape, size_t first_dimension)
277{
278    for(unsigned int n = first_dimension; n < shape.num_dimensions(); ++n)
279    {
280        set(n, Window::Dimension(0, std::max(shape[n], static_cast<size_t>(1))));
281    }
282}
283
284inline TensorShape Window::shape() const
285{
286    TensorShape shape;
287    for(size_t d = 0; d < TensorShape::num_max_dimensions; ++d)
288    {
289        shape.set(d, (_dims[d].end() - _dims[d].start()) / _dims[d].step());
290    }
291    return shape;
292}
293
294inline size_t Window::num_iterations_total() const
295{
296    size_t total = 1;
297    for(size_t d = 0; d < Coordinates::num_max_dimensions; ++d)
298    {
299        total *= num_iterations(d);
300    }
301    return total;
302}
303
304inline void swap(Window &lhs, Window &rhs)
305{
306    lhs._dims.swap(rhs._dims);
307}
308
309inline bool operator==(const Window &lhs, const Window &rhs)
310{
311    return (lhs._dims == rhs._dims) && (lhs._is_broadcasted == rhs._is_broadcasted);
312}
313} // namespace arm_compute
314