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