Update ACL pin to b309fc249e4383b4d40ae03e377c3cbad3f9f5f7
[platform/upstream/armnn.git] / src / armnn / Descriptors.cpp
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 #include "armnn/Descriptors.hpp"
6 #include "armnn/Logging.hpp"
7
8 #include <armnn/utility/Assert.hpp>
9 #include <armnn/utility/NumericCast.hpp>
10
11 #include <algorithm>
12 #include <array>
13 #include <vector>
14
15 #include <fmt/format.h>
16
17 namespace armnn
18 {
19
20 PermutationVector::PermutationVector(const ValueType *dimMappings, const SizeType numDimMappings)
21 {
22     // Validation
23
24     if (numDimMappings > MaxNumOfTensorDimensions)
25     {
26         throw InvalidArgumentException(
27             fmt::format("The number of mappings ({0}) cannot be greater "
28                         "than the maximum number of dimensions supported ({1})",
29                         numDimMappings,
30                         MaxNumOfTensorDimensions));
31     }
32
33     if ((dimMappings == nullptr) && (numDimMappings != 0))
34     {
35         throw InvalidArgumentException("Dimension mappings must not be NULL if the number of mappings is positive");
36     }
37
38     for (SizeType i = 0; i < numDimMappings; ++i)
39     {
40         const ValueType dstIndex = dimMappings[i];
41         if (dstIndex >= numDimMappings)
42         {
43             throw InvalidArgumentException(
44                 fmt::format("Dimension mapping at index {0} is invalid: "
45                             "{1} is outside of the valid range [0,{2}]",
46                             i,
47                             dstIndex,
48                             (numDimMappings - 1)));
49         }
50     }
51
52     // Validation: Detect duplicates
53     {
54         std::array<bool, MaxNumOfTensorDimensions> observedDims;
55         observedDims.fill(false);
56
57         for (SizeType i = 0; i < numDimMappings; ++i)
58         {
59             const ValueType dstIndex = dimMappings[i];
60             if (observedDims[dstIndex])
61             {
62                 throw InvalidArgumentException("Invalid dimension mappings: Two or more source dimensions are mapped "
63                     "to the same output dimension");
64             }
65             observedDims[dstIndex] = true;
66         }
67     }
68
69     // Initialize
70     for (SizeType i = 0; i < numDimMappings; ++i)
71     {
72         m_DimMappings[i] = dimMappings[i];
73     }
74     m_NumDimMappings = numDimMappings;
75 }
76
77 PermutationVector::PermutationVector(std::initializer_list<ValueType> dimMappings)
78     : PermutationVector(dimMappings.begin(), armnn::numeric_cast<SizeType>(dimMappings.size()))
79 {
80 }
81
82 OriginsDescriptor::OriginsDescriptor()
83 : m_ConcatAxis(1)
84 , m_NumViews(0)
85 , m_NumDimensions(0)
86 , m_ViewOrigins(nullptr)
87 {}
88
89 OriginsDescriptor::OriginsDescriptor(uint32_t numViews, uint32_t numDimensions /*= 4*/)
90 : m_ConcatAxis(1)
91 , m_NumViews(numViews)
92 , m_NumDimensions(numDimensions)
93 , m_ViewOrigins(numViews && numDimensions > 0 ? new uint32_t *[numViews]() : nullptr)
94 {
95     for (uint32_t i = 0; m_NumDimensions > 0 && i < m_NumViews; ++i)
96     {
97         m_ViewOrigins[i] = new uint32_t[m_NumDimensions]();
98     }
99 }
100
101 OriginsDescriptor::OriginsDescriptor(const OriginsDescriptor& other)
102 : m_ConcatAxis(other.m_ConcatAxis)
103 , m_NumViews(other.m_NumViews)
104 , m_NumDimensions(other.m_NumDimensions)
105 , m_ViewOrigins(other.m_NumViews && other.m_NumDimensions > 0 ? new uint32_t *[other.m_NumViews]() : nullptr)
106 {
107     for (uint32_t i = 0; m_NumDimensions > 0 && i < m_NumViews; ++i)
108     {
109         m_ViewOrigins[i] = new uint32_t[m_NumDimensions]();
110         memcpy(m_ViewOrigins[i], other.m_ViewOrigins[i], m_NumDimensions * sizeof(uint32_t));
111     }
112 }
113
114 OriginsDescriptor::OriginsDescriptor(OriginsDescriptor&& other)
115 : OriginsDescriptor()
116 {
117     swap(*this, other);
118 }
119
120 OriginsDescriptor::~OriginsDescriptor()
121 {
122     for (uint32_t i = 0; m_NumDimensions > 0 && i < m_NumViews; ++i)
123     {
124         delete[] m_ViewOrigins[i];
125     }
126     delete[] m_ViewOrigins;
127 }
128
129 OriginsDescriptor& OriginsDescriptor::operator=(OriginsDescriptor rhs)
130 {
131     swap(*this, rhs);
132     return *this;
133 }
134
135 bool OriginsDescriptor::operator==(const OriginsDescriptor& rhs) const
136 {
137     if (GetNumViews()      != rhs.GetNumViews() ||
138         GetNumDimensions() != rhs.GetNumDimensions() ||
139         GetConcatAxis()    != rhs.GetConcatAxis())
140     {
141         return false;
142     }
143
144     for (unsigned int i = 0u; i < GetNumViews(); ++i)
145     {
146         for (unsigned int j = 0u; j < GetNumDimensions(); ++j)
147         {
148             if (GetViewOrigin(i)[j] != rhs.GetViewOrigin(i)[j])
149             {
150                 return false;
151             }
152         }
153     }
154
155     return true;
156 }
157
158 void OriginsDescriptor::SetConcatAxis(unsigned int concatAxis)
159 {
160     m_ConcatAxis = concatAxis;
161 }
162 unsigned int OriginsDescriptor::GetConcatAxis() const
163 {
164     return m_ConcatAxis;
165 }
166
167 Status OriginsDescriptor::SetViewOriginCoord(uint32_t view, uint32_t coord, uint32_t value)
168 {
169     if (view >= m_NumViews)
170     {
171         ARMNN_LOG(error) << "OriginsDescriptor::SetViewOriginCoord: view argument:" << view <<
172             " is out of range";
173         return Status::Failure;
174     }
175     if (coord >= m_NumDimensions)
176     {
177         ARMNN_LOG(error) << "OriginsDescriptor::SetViewOriginCoord: coord argument:" << coord <<
178             " is out of range";
179         return Status::Failure;
180     }
181
182     m_ViewOrigins[view][coord] = value;
183     return Status::Success;
184 }
185
186
187 uint32_t OriginsDescriptor::GetNumViews() const
188 {
189     return m_NumViews;
190 }
191
192 uint32_t OriginsDescriptor::GetNumDimensions() const
193 {
194     return m_NumDimensions;
195 }
196
197 const uint32_t* OriginsDescriptor::GetViewOrigin(uint32_t idx) const
198 {
199     return m_ViewOrigins ? m_ViewOrigins[idx] : nullptr;
200 }
201
202
203 // Reorders the viewOrigins in accordance with the indices presented in newOrdering array.
204 void OriginsDescriptor::ReorderOrigins(unsigned int*  newOrdering, unsigned int numNewOrdering)
205 {
206     ARMNN_ASSERT_MSG(m_NumViews == numNewOrdering, "number of views must match number of "
207         "elements in the new ordering array");
208     std::vector<uint32_t*> viewOrigins(&m_ViewOrigins[0], &m_ViewOrigins[m_NumViews]);
209
210     for (unsigned int i = 0; i < numNewOrdering; ++i)
211     {
212         m_ViewOrigins[i] = viewOrigins[newOrdering[i]];
213     }
214 }
215
216 ViewsDescriptor::ViewsDescriptor()
217 : m_Origins()
218 , m_ViewSizes(nullptr)
219 {}
220
221 ViewsDescriptor::ViewsDescriptor(uint32_t numViews, uint32_t numDimensions /*= 4*/)
222     : m_Origins(numViews, numDimensions)
223     , m_ViewSizes(numViews > 0 && numDimensions > 0 ?
224                       new uint32_t *[numViews]() : nullptr)
225 {
226     if (m_ViewSizes)
227     {
228         for (uint32_t i = 0; GetNumDimensions() > 0 && i < GetNumViews(); ++i)
229         {
230             m_ViewSizes[i] = new uint32_t[GetNumDimensions()]();
231         }
232     }
233 }
234
235 ViewsDescriptor::ViewsDescriptor(const ViewsDescriptor& other)
236     : m_Origins(other.m_Origins)
237     , m_ViewSizes(other.GetNumViews() > 0 && other.GetNumDimensions() > 0 ?
238                       new uint32_t *[other.GetNumViews()]() : nullptr)
239 {
240     if (m_ViewSizes)
241     {
242         for (uint32_t i = 0; GetNumDimensions() > 0 && i < GetNumViews(); ++i)
243         {
244             m_ViewSizes[i] = new uint32_t[GetNumDimensions()]();
245             memcpy(m_ViewSizes[i], other.m_ViewSizes[i], GetNumDimensions() * sizeof(uint32_t));
246         }
247     }
248 }
249
250 ViewsDescriptor::ViewsDescriptor(ViewsDescriptor&& other)
251     : ViewsDescriptor()
252 {
253     swap(*this, other);
254 }
255
256 ViewsDescriptor::~ViewsDescriptor()
257 {
258     if (m_ViewSizes)
259     {
260         for (uint32_t i = 0; GetNumDimensions() > 0 && i < GetNumViews(); ++i)
261         {
262             delete[] m_ViewSizes[i];
263         }
264         delete[] m_ViewSizes;
265     }
266 }
267
268 ViewsDescriptor& ViewsDescriptor::operator=(ViewsDescriptor rhs)
269 {
270     swap(*this, rhs);
271     return *this;
272 }
273
274 bool ViewsDescriptor::operator==(const ViewsDescriptor& rhs) const
275 {
276     if (GetNumViews() != rhs.GetNumViews() || GetNumDimensions() != rhs.GetNumDimensions())
277     {
278         return false;
279     }
280
281     for (unsigned int i = 0u; i < GetNumViews(); ++i)
282     {
283         for (unsigned int j = 0u; j < GetNumDimensions(); ++j)
284         {
285             if (GetViewOrigin(i)[j] != rhs.GetViewOrigin(i)[j] || GetViewSizes(i)[j] != rhs.GetViewSizes(i)[j])
286             {
287                 return false;
288             }
289         }
290     }
291
292     return true;
293 }
294
295 uint32_t ViewsDescriptor::GetNumViews() const
296 {
297     return m_Origins.GetNumViews();
298 }
299
300 uint32_t ViewsDescriptor::GetNumDimensions() const
301 {
302     return m_Origins.GetNumDimensions();
303 }
304
305 const uint32_t* ViewsDescriptor::GetViewOrigin(uint32_t idx) const
306 {
307     return m_Origins.GetViewOrigin(idx);
308 }
309
310 Status ViewsDescriptor::SetViewOriginCoord(uint32_t view, uint32_t coord, uint32_t value)
311 {
312     return m_Origins.SetViewOriginCoord(view, coord, value);
313 }
314
315 Status ViewsDescriptor::SetViewSize(uint32_t view, uint32_t coord, uint32_t value)
316 {
317     if (!m_ViewSizes)
318     {
319         ARMNN_LOG(error) << "ViewsDescriptor::SetViewSize: invalid view sizes";
320         return Status::Failure;
321     }
322
323     if (view >= GetNumViews())
324     {
325         ARMNN_LOG(error) << "ViewsDescriptor::SetViewSize: view argument:" << view <<
326                                  " is out of range";
327         return Status::Failure;
328     }
329     if (coord >= GetNumDimensions())
330     {
331         ARMNN_LOG(error) << "ViewsDescriptor::SetViewSize: coord argument:" << coord <<
332                                  " is out of range";
333         return Status::Failure;
334     }
335
336     m_ViewSizes[view][coord] = value;
337     return Status::Success;
338 }
339
340 const uint32_t* ViewsDescriptor::GetViewSizes(uint32_t idx) const
341 {
342     return m_ViewSizes ? m_ViewSizes[idx] : nullptr;
343 }
344
345 const OriginsDescriptor& ViewsDescriptor::GetOrigins() const
346 {
347     return m_Origins;
348 }
349
350 void swap(OriginsDescriptor& first, OriginsDescriptor& second)
351 {
352     using std::swap;
353     swap(first.m_NumViews, second.m_NumViews);
354     swap(first.m_NumDimensions, second.m_NumDimensions);
355     swap(first.m_ViewOrigins, second.m_ViewOrigins);
356     swap(first.m_ConcatAxis, second.m_ConcatAxis);
357 }
358
359 void swap(ViewsDescriptor& first, ViewsDescriptor& second)
360 {
361     using std::swap;
362     swap(first.m_Origins, second.m_Origins);
363     swap(first.m_ViewSizes, second.m_ViewSizes);
364 }
365
366 int StridedSliceDescriptor::GetStartForAxis(const TensorShape& inputShape,
367                                             unsigned int axis) const
368 {
369     int start = m_Begin[axis];
370
371     if (m_BeginMask & (1 << axis))
372     {
373         if (m_Stride[axis] > 0)
374         {
375             start = std::numeric_limits<int>::min();
376         }
377         else
378         {
379             start = std::numeric_limits<int>::max();
380         }
381     }
382
383     const int axisSize = armnn::numeric_cast<int>(inputShape[axis]);
384     if (start < 0)
385     {
386         start += (axisSize);
387     }
388
389     return std::max(0, std::min(start, axisSize - 1));
390
391 }
392
393 int StridedSliceDescriptor::GetStopForAxis(const TensorShape& inputShape,
394                                            unsigned int axis,
395                                            int startForAxis) const
396 {
397
398     if (m_ShrinkAxisMask & (1 << axis))
399     {
400         return startForAxis + 1;
401     }
402
403     int stop = m_End[axis];
404
405     if (m_EndMask & (1 << axis))
406     {
407         if (m_Stride[axis] > 0)
408         {
409             stop = std::numeric_limits<int>::max();
410         }
411         else
412         {
413             stop = std::numeric_limits<int>::min();
414         }
415     }
416
417     const int axisSize = armnn::numeric_cast<int>(inputShape[axis]);
418     if (stop < 0)
419     {
420         stop += axisSize;
421     }
422
423     return m_Stride[axis] > 0 ? std::max(0, std::min(stop, axisSize)) :
424                                 std::max(-1, std::min(stop, axisSize - 1));
425
426 }
427
428 }