summaryrefslogtreecommitdiff
path: root/runtime/libs
diff options
context:
space:
mode:
authorChunseok Lee <chunseok.lee@samsung.com>2021-10-19 11:32:46 +0900
committerChunseok Lee <chunseok.lee@samsung.com>2021-10-19 11:32:46 +0900
commit33ae5d70a1ed85d215c1293ed63afbf3517b07d5 (patch)
tree9f1ace0f4760a8f7903ef15e2e92f1d1401e4b1e /runtime/libs
parentf4cf19e579a19c5346ccb2aad55bfd251065e447 (diff)
downloadnnfw-33ae5d70a1ed85d215c1293ed63afbf3517b07d5.tar.gz
nnfw-33ae5d70a1ed85d215c1293ed63afbf3517b07d5.tar.bz2
nnfw-33ae5d70a1ed85d215c1293ed63afbf3517b07d5.zip
Diffstat (limited to 'runtime/libs')
-rw-r--r--runtime/libs/ndarray/CMakeLists.txt23
-rw-r--r--runtime/libs/ndarray/example/CMakeLists.txt4
-rw-r--r--runtime/libs/ndarray/example/example_array.cpp76
-rw-r--r--runtime/libs/ndarray/example/example_no_array.cpp85
-rw-r--r--runtime/libs/ndarray/include/ndarray/Array.h195
-rw-r--r--runtime/libs/ndarray/include/ndarray/Common.h22
-rw-r--r--runtime/libs/ndarray/include/ndarray/ContiguousSpan.h108
-rw-r--r--runtime/libs/ndarray/include/ndarray/Shape.h66
-rw-r--r--runtime/libs/ndarray/src/Array.cpp27
-rw-r--r--runtime/libs/ndarray/src/ContiguousSpan.cpp31
-rw-r--r--runtime/libs/ndarray/src/detail/cxx14.h67
-rw-r--r--runtime/libs/ndarray/test/CMakeLists.txt18
-rw-r--r--runtime/libs/ndarray/test/ndarray_test.cpp122
13 files changed, 844 insertions, 0 deletions
diff --git a/runtime/libs/ndarray/CMakeLists.txt b/runtime/libs/ndarray/CMakeLists.txt
new file mode 100644
index 000000000..f88f13186
--- /dev/null
+++ b/runtime/libs/ndarray/CMakeLists.txt
@@ -0,0 +1,23 @@
+add_library(ndarray STATIC src/Array.cpp src/ContiguousSpan.cpp)
+
+set_target_properties(ndarray PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+target_include_directories(ndarray PUBLIC include)
+#can't make this private because of c++ templates
+target_include_directories(ndarray PUBLIC src)
+
+option(NDARRAY_INLINE_TEMPLATES "Set to ON to disable extern declarations for common types")
+
+if(${NDARRAY_INLINE_TEMPLATES})
+ target_compile_definitions(ndarray PUBLIC -DNDARRAY_INLINE_TEMPLATES=1)
+endif()
+
+target_link_libraries(ndarray PRIVATE nnfw_common)
+target_link_libraries(ndarray PRIVATE nnfw_coverage)
+
+if(NOT ENABLE_TEST)
+ return()
+endif(NOT ENABLE_TEST)
+
+add_subdirectory(test)
+add_subdirectory(example)
diff --git a/runtime/libs/ndarray/example/CMakeLists.txt b/runtime/libs/ndarray/example/CMakeLists.txt
new file mode 100644
index 000000000..c4b575dad
--- /dev/null
+++ b/runtime/libs/ndarray/example/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_executable(example_no_array example_no_array.cpp)
+
+add_executable(example_array example_array.cpp)
+target_link_libraries(example_array PRIVATE ndarray)
diff --git a/runtime/libs/ndarray/example/example_array.cpp b/runtime/libs/ndarray/example/example_array.cpp
new file mode 100644
index 000000000..85d274681
--- /dev/null
+++ b/runtime/libs/ndarray/example/example_array.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ndarray/Array.h"
+
+#include <iostream>
+#include <iterator>
+
+using namespace ndarray;
+
+void gather_array(const Array<float> &input, Array<float> &output, const Array<int> &indices)
+{
+ assert(indices.shape().rank() == 3);
+ assert(input.shape().rank() == 3);
+ assert(indices.shape().dim(1) == input.shape().rank());
+
+ for (size_t i = 0; i < indices.shape().dim(0); ++i)
+ {
+ for (size_t j = 0; j < indices.shape().dim(1); ++j)
+ {
+ auto index = indices.slice(i, j);
+ output.slice(i, j).assign(input.slice(index[0], index[1]));
+ }
+ }
+}
+
+int main()
+{
+ // fill tensor of shape[3,3,4] with sequential numbers from [0..36)
+ Shape in_shape{3, 3, 4};
+ std::vector<float> input_data(in_shape.element_count());
+ for (size_t i = 0; i < in_shape.element_count(); ++i)
+ input_data[i] = i;
+
+ Array<float> input(input_data.data(), in_shape);
+
+ // select column-vectors on main diagonal
+ Shape indices_shape{1, 3, 2};
+ std::vector<int> indices_data(indices_shape.element_count());
+ Array<int> indices(indices_data.data(), indices_shape);
+
+ indices.slice(0, 0) = {0, 0};
+ indices.slice(0, 1) = {1, 1};
+ indices.slice(0, 2) = {2, 2};
+
+ Shape output_shape{1, 3, 4};
+ std::vector<float> output_data(output_shape.element_count());
+
+ Array<float> output(output_data.data(), output_shape);
+
+ gather_array(input, output, indices);
+
+ for (size_t i = 0; i < indices_shape.dim(0); ++i)
+ {
+ for (size_t j = 0; j < indices_shape.dim(1); ++j)
+ {
+ auto output_piece = output.slice(i, j);
+ std::ostream_iterator<int> cout_it(std::cout, ", ");
+ std::copy(output_piece.begin(), output_piece.end(), cout_it);
+ std::cout << std::endl;
+ }
+ }
+}
diff --git a/runtime/libs/ndarray/example/example_no_array.cpp b/runtime/libs/ndarray/example/example_no_array.cpp
new file mode 100644
index 000000000..3a4d05dca
--- /dev/null
+++ b/runtime/libs/ndarray/example/example_no_array.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <array>
+#include <vector>
+#include <algorithm>
+#include <cassert>
+#include <iostream>
+
+void gather_no_array(const float *in_data, const std::array<size_t, 3> &dims, float *out_data,
+ const std::array<size_t, 3> &out_dims, //[nselections,
+ const int *indices, const std::array<size_t, 3> &indices_dims)
+{
+ assert(indices_dims[1] == dims.size());
+
+ for (int i = 0; i < indices_dims[0]; ++i)
+ {
+ for (int j = 0; j < indices_dims[1]; ++j)
+ {
+ const int *index_ptr = indices + i * indices_dims[2] * indices_dims[1] + j * indices_dims[2];
+
+ size_t in_offset = index_ptr[0] * dims[2] * dims[1] + index_ptr[1] * dims[2];
+
+ const float *in_ptr = in_data + in_offset;
+
+ size_t out_offset = i * out_dims[2] * out_dims[1] + j * out_dims[2];
+
+ float *out_ptr = out_data + out_offset;
+
+ for (int k = 0; k < dims[2]; ++k)
+ {
+ out_ptr[k] = in_ptr[k];
+ }
+ }
+ }
+}
+
+int main()
+{
+ std::array<size_t, 3> in_dims{3, 3, 4};
+ std::vector<float> input(3 * 3 * 4);
+ for (size_t i = 0; i < 3 * 3 * 4; ++i)
+ input[i] = i;
+
+ std::array<size_t, 3> indices_shape{1, 3, 2};
+ std::vector<int> indices(1 * 3 * 2);
+
+ indices[0] = 0;
+ indices[1] = 0;
+ indices[2] = 1;
+ indices[3] = 1;
+ indices[4] = 2;
+ indices[5] = 2;
+
+ std::array<size_t, 3> output_dims{1, 3, 4};
+ std::vector<float> output(1 * 3 * 4);
+
+ gather_no_array(input.data(), in_dims, output.data(), output_dims, indices.data(), indices_shape);
+
+ for (size_t i = 0; i < output_dims[0]; ++i)
+ {
+ for (size_t j = 0; j < output_dims[1]; ++j)
+ {
+ auto out_ptr = output.data() + i * output_dims[1] * output_dims[2] + j * output_dims[2];
+ for (size_t k = 0; k < output_dims[2]; ++k)
+ {
+ std::cout << out_ptr[k] << ", ";
+ }
+ std::cout << std::endl;
+ }
+ }
+}
diff --git a/runtime/libs/ndarray/include/ndarray/Array.h b/runtime/libs/ndarray/include/ndarray/Array.h
new file mode 100644
index 000000000..09e791763
--- /dev/null
+++ b/runtime/libs/ndarray/include/ndarray/Array.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _NDARRAY_ARRAY_H_
+#define _NDARRAY_ARRAY_H_
+
+#include "Common.h"
+
+#include "ContiguousSpan.h"
+#include "Shape.h"
+
+#if __cplusplus < 201402L
+#include "detail/cxx14.h" //integer_sequence and make_index_dequence definitions
+#else
+#include <utility>
+#endif
+
+#include <algorithm>
+#include <cassert>
+#include <type_traits>
+#include <array>
+#include <tuple>
+#include <cstddef>
+
+namespace ndarray
+{
+
+// there is no index_sequence before c++14
+#if __cplusplus < 201402L
+
+template <size_t... Nums> using index_sequence = cxx14::index_sequence<Nums...>;
+
+template <size_t Num> using make_index_sequence = cxx14::make_index_sequence<Num>;
+
+#else
+
+template <size_t... Nums> using index_sequence = std::index_sequence<Nums...>;
+
+template <size_t _Num> using make_index_sequence = std::make_index_sequence<_Num>;
+
+#endif //__cplusplus < 201402L
+
+struct Strides
+{
+ explicit Strides(Shape s) : _strides{} { fillStrides(s); }
+
+ int operator[](size_t idx) const noexcept { return _strides[idx]; }
+
+ // since we don't have c++14 fold expression
+ template <typename Seq, typename... Ts> struct _calc_offset;
+
+ template <size_t Num, size_t... Nums, typename T, typename... Ts>
+ struct _calc_offset<index_sequence<Num, Nums...>, T, Ts...>
+ {
+ static constexpr size_t get(const std::array<int, 8> &strides, int x, Ts... xs)
+ {
+ return _calc_offset<index_sequence<Nums...>, Ts...>::get(strides, xs...) +
+ x * std::get<Num>(strides);
+ }
+ };
+
+ template <size_t Num, typename T> struct _calc_offset<index_sequence<Num>, T>
+ {
+ static constexpr size_t get(const std::array<int, 8> &strides, int x)
+ {
+ return x * std::get<Num>(strides);
+ }
+ };
+
+ template <typename Seq, typename... Ts> constexpr size_t offset(Seq, Ts... x) const noexcept
+ {
+ // return ( 0 + ... + (std::get<Nums>(_strides) * x)); in c++14
+ return _calc_offset<Seq, Ts...>::get(_strides, x...);
+ }
+
+private:
+ void fillStrides(const Shape &s) noexcept
+ {
+ int rank = s.rank();
+ _strides[rank - 1] = 1;
+ for (int d = rank - 2; d >= 0; --d)
+ {
+ _strides[d] = _strides[d + 1] * s.dim(d + 1);
+ }
+ }
+
+ std::array<int, NDARRAY_MAX_DIMENSION_COUNT> _strides;
+};
+
+template <typename T> class Array
+{
+public:
+ Array(T *data, Shape shape) noexcept : _data(data), _shape(shape), _strides(shape) {}
+
+ Array(const Array &) = delete;
+
+ Array(Array &&a) noexcept : _data(a._data), _shape(a._shape), _strides(a._strides)
+ {
+ a._data = nullptr;
+ }
+
+ template <typename... Ts> T &at(Ts... x) const noexcept { return _at(static_cast<size_t>(x)...); }
+
+ /**
+ * @brief returns last dimension as ContigniousSpan
+ * @param x indices of slice to take. See tests for usage details
+ * @return slice at given position
+ */
+ template <typename... Ts> ContiguousSpan<T, std::is_const<T>::value> slice(Ts... x) noexcept
+ {
+ assert(sizeof...(Ts) == _shape.rank() - 1);
+ return {&at(x..., 0ul), _shape.dim(_shape.rank() - 1)};
+ }
+
+ /**
+ * @brief returns last dimension as ContigniousSpan
+ * @param x indices of slice to take. See tests for usage details
+ * @return slice at given position
+ */
+ template <typename... Ts> ContiguousSpan<T, true> slice(Ts... x) const noexcept
+ {
+ assert(sizeof...(Ts) == _shape.rank() - 1);
+ return {&at(x..., 0ul), _shape.dim(_shape.rank() - 1)};
+ }
+
+ ContiguousSpan<T, std::is_const<T>::value> flat() noexcept
+ {
+ return {_data, _shape.element_count()};
+ }
+
+ ContiguousSpan<T, true> flat() const noexcept { return {_data, _shape.element_count()}; }
+
+ const Shape &shape() const noexcept { return _shape; }
+
+private:
+ template <typename... Ts> T &_at(Ts... x) const noexcept
+ {
+ assert(sizeof...(x) == _shape.rank());
+ using Indices = make_index_sequence<sizeof...(Ts)>;
+ return _data[offset(Indices{}, x...)];
+ }
+
+ template <typename... Ts, size_t... Nums>
+ size_t offset(index_sequence<Nums...> seq, Ts... x) const noexcept
+ {
+ static_assert(
+ sizeof...(Ts) == sizeof...(Nums),
+ "Sanity check failed. Generated index sequence size is not equal to argument count");
+
+ return _strides.offset(seq, x...);
+ }
+
+ T *_data;
+ Shape _shape;
+ Strides _strides;
+};
+
+template <typename To, typename From> Array<To> array_cast(Array<From> &&from, Shape newShape)
+{
+ assert(from.shape().element_count() / (sizeof(To) / sizeof(From)) == newShape.element_count());
+ return Array<To>(reinterpret_cast<To *>(from.flat().data()), newShape);
+}
+
+template <typename To, typename From>
+Array<const To> array_cast(const Array<From> &from, Shape newShape)
+{
+ assert(from.shape().element_count() / (sizeof(To) / sizeof(From)) == newShape.element_count());
+ return Array<To>(reinterpret_cast<const To *>(from.flat().data()), newShape);
+}
+
+#ifndef NDARRAY_INLINE_TEMPLATES
+
+extern template class Array<float>;
+extern template class Array<int32_t>;
+extern template class Array<uint32_t>;
+extern template class Array<uint8_t>;
+
+#endif // NDARRAY_INLINE_TEMPLATES
+
+} // namespace ndarray
+
+#endif //_NDARRAY_ARRAY_H_
diff --git a/runtime/libs/ndarray/include/ndarray/Common.h b/runtime/libs/ndarray/include/ndarray/Common.h
new file mode 100644
index 000000000..aa0cc6fe2
--- /dev/null
+++ b/runtime/libs/ndarray/include/ndarray/Common.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _NDARRAY_COMMON_H_
+#define _NDARRAY_COMMON_H_
+
+#define NDARRAY_MAX_DIMENSION_COUNT 8
+
+#endif //_NDARRAY_COMMON_H_
diff --git a/runtime/libs/ndarray/include/ndarray/ContiguousSpan.h b/runtime/libs/ndarray/include/ndarray/ContiguousSpan.h
new file mode 100644
index 000000000..b322b77db
--- /dev/null
+++ b/runtime/libs/ndarray/include/ndarray/ContiguousSpan.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _NDARRAY_CONTIGNIOUS_SPAN_H_
+#define _NDARRAY_CONTIGNIOUS_SPAN_H_
+
+#include <type_traits>
+#include <vector>
+#include <cstdint>
+#include <cstddef>
+#include <cassert>
+
+namespace ndarray
+{
+
+template <typename T, bool isConst = false> class ContiguousSpan
+{
+public:
+ using pointer_type = typename std::conditional<isConst, const T *, T *>::type;
+ using reference_type = typename std::conditional<isConst, const T &, T &>::type;
+ using iterator_type = pointer_type;
+
+ ContiguousSpan(pointer_type data, size_t len) noexcept : _data(data), _len(len) {}
+
+ template <typename It>
+ explicit ContiguousSpan(It first, It last) noexcept
+ : _data(&*first), _len(std::distance(first, last))
+ {
+ }
+
+ ContiguousSpan(const ContiguousSpan &) = delete;
+
+ ContiguousSpan(ContiguousSpan &&s) noexcept : _data(s._data), _len(s._len) { s._data = nullptr; }
+
+ operator ContiguousSpan<T, true>() { return ContiguousSpan<T, true>{_data, _len}; }
+
+ reference_type operator[](size_t idx) const noexcept { return _data[idx]; }
+
+ reference_type at(size_t idx) const noexcept { return _data[idx]; }
+
+ ContiguousSpan<T, isConst> offset(size_t offset)
+ {
+ assert(offset <= _len);
+ return {_data + offset, _len - offset};
+ }
+
+ template <typename From, bool _ = isConst>
+ typename std::enable_if<!_, void>::type assign(const From &f) noexcept
+ {
+ assignFrom(std::begin(f), std::end(f));
+ }
+
+ template <typename U, bool _ = isConst>
+ typename std::enable_if<!_, ContiguousSpan &>::type
+ operator=(std::initializer_list<U> list) noexcept
+ {
+ assignFrom(std::begin(list), std::end(list));
+ return *this;
+ }
+
+ template <typename It, bool _ = isConst>
+ typename std::enable_if<!_, void>::type assignFrom(It first, It last) noexcept
+ {
+ std::copy(first, last, begin());
+ }
+
+ size_t size() const { return _len; }
+
+ iterator_type begin() const { return iterator_type{_data}; }
+
+ iterator_type end() const { return iterator_type{_data + _len}; }
+
+ pointer_type data() { return _data; }
+
+private:
+ pointer_type _data;
+ size_t _len;
+};
+
+#ifndef NDARRAY_INLINE_TEMPLATES
+
+extern template class ContiguousSpan<float, true>;
+extern template class ContiguousSpan<float, false>;
+extern template class ContiguousSpan<int32_t, true>;
+extern template class ContiguousSpan<int32_t, false>;
+extern template class ContiguousSpan<uint32_t, true>;
+extern template class ContiguousSpan<uint32_t, false>;
+extern template class ContiguousSpan<uint8_t, true>;
+extern template class ContiguousSpan<uint8_t, false>;
+
+#endif // NDARRAY_INLINE_TEMPLATES
+
+} // namespace ndarray
+
+#endif //_NDARRAY_CONTIGNIOUS_SPAN_H_
diff --git a/runtime/libs/ndarray/include/ndarray/Shape.h b/runtime/libs/ndarray/include/ndarray/Shape.h
new file mode 100644
index 000000000..fa58613b8
--- /dev/null
+++ b/runtime/libs/ndarray/include/ndarray/Shape.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _NDARRAY_SHAPE_H_
+#define _NDARRAY_SHAPE_H_
+
+#include "Common.h"
+
+#include <array>
+#include <cassert>
+#include <cstddef>
+
+namespace ndarray
+{
+
+class Shape
+{
+public:
+ //_dims{} here and later since array does not have std::initializer_list ctor
+ // and aggregate initialization is not allowed here
+ explicit Shape(size_t rank) noexcept : _dims{}, _rank(rank)
+ {
+ std::fill(_dims.begin(), _dims.end(), 0);
+ }
+
+ Shape(std::initializer_list<size_t> list) noexcept : _dims{}, _rank(list.size())
+ {
+ std::copy(list.begin(), list.end(), _dims.begin());
+ }
+
+ size_t dim(int i) const noexcept { return _dims.at(i); }
+
+ size_t &dim(int i) noexcept { return _dims.at(i); }
+
+ size_t element_count() const noexcept
+ {
+ uint32_t res = 1;
+ for (size_t i = 0; i < rank(); ++i)
+ res *= dim(i);
+ assert(res <= 0xffffffff);
+ return res;
+ }
+
+ size_t rank() const noexcept { return _rank; }
+
+private:
+ std::array<size_t, NDARRAY_MAX_DIMENSION_COUNT> _dims;
+ size_t _rank;
+};
+
+} // namespace ndarray
+
+#endif //_NDARRAY_SHAPE_H_
diff --git a/runtime/libs/ndarray/src/Array.cpp b/runtime/libs/ndarray/src/Array.cpp
new file mode 100644
index 000000000..f9c9de9d3
--- /dev/null
+++ b/runtime/libs/ndarray/src/Array.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ndarray/Array.h"
+
+namespace ndarray
+{
+
+template class Array<float>;
+template class Array<int32_t>;
+template class Array<uint32_t>;
+template class Array<uint8_t>;
+
+} // namespace ndarray
diff --git a/runtime/libs/ndarray/src/ContiguousSpan.cpp b/runtime/libs/ndarray/src/ContiguousSpan.cpp
new file mode 100644
index 000000000..e06cfc2a1
--- /dev/null
+++ b/runtime/libs/ndarray/src/ContiguousSpan.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ndarray/ContiguousSpan.h"
+
+namespace ndarray
+{
+
+template class ContiguousSpan<float, true>;
+template class ContiguousSpan<float, false>;
+template class ContiguousSpan<int32_t, true>;
+template class ContiguousSpan<int32_t, false>;
+template class ContiguousSpan<uint32_t, true>;
+template class ContiguousSpan<uint32_t, false>;
+template class ContiguousSpan<uint8_t, true>;
+template class ContiguousSpan<uint8_t, false>;
+
+} // namespace ndarray
diff --git a/runtime/libs/ndarray/src/detail/cxx14.h b/runtime/libs/ndarray/src/detail/cxx14.h
new file mode 100644
index 000000000..8b78fb985
--- /dev/null
+++ b/runtime/libs/ndarray/src/detail/cxx14.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _NDARRAY_CXX14_H_
+#define _NDARRAY_CXX14_H_
+
+namespace ndarray
+{
+
+namespace cxx14
+{
+
+template <size_t... Nums> struct index_sequence
+{
+ using value_type = size_t;
+
+ static constexpr std::size_t size() noexcept { return sizeof...(Nums); }
+};
+
+namespace detail
+{
+
+template <size_t v, typename Seq> struct _append;
+
+template <size_t v, size_t... Nums> struct _append<v, index_sequence<Nums...>>
+{
+ using result = index_sequence<Nums..., v>;
+};
+
+template <size_t Len> struct make_index_sequence
+{
+ using result =
+ typename detail::_append<Len - 1, typename make_index_sequence<Len - 1>::result>::result;
+};
+
+template <> struct make_index_sequence<1>
+{
+ using result = index_sequence<0>;
+};
+
+template <> struct make_index_sequence<0>
+{
+ using result = index_sequence<>;
+};
+
+} // namespace detail
+
+template <size_t Num> using make_index_sequence = typename detail::make_index_sequence<Num>::result;
+
+} // namespace cxx14
+
+} // namespace ndarray
+
+#endif //_NDARRAY_CXX14_H_
diff --git a/runtime/libs/ndarray/test/CMakeLists.txt b/runtime/libs/ndarray/test/CMakeLists.txt
new file mode 100644
index 000000000..be1ed6510
--- /dev/null
+++ b/runtime/libs/ndarray/test/CMakeLists.txt
@@ -0,0 +1,18 @@
+if(NOT TARGET ndarray)
+ return()
+endif()
+
+add_executable(ndarray_test ndarray_test.cpp)
+
+target_link_libraries(ndarray_test PRIVATE ndarray)
+
+nnfw_find_package(GTest)
+if(NOT GTest_FOUND)
+ message(STATUS "GTest not avaialble. Skipping NDArray test build")
+ return()
+endif(NOT GTest_FOUND)
+
+target_link_libraries(ndarray_test PUBLIC gtest gtest_main ${LIB_PTHREAD})
+
+add_test(ndarray_test ndarray_test)
+install(TARGETS ndarray_test DESTINATION unittest_standalone)
diff --git a/runtime/libs/ndarray/test/ndarray_test.cpp b/runtime/libs/ndarray/test/ndarray_test.cpp
new file mode 100644
index 000000000..4b5ad5765
--- /dev/null
+++ b/runtime/libs/ndarray/test/ndarray_test.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+
+#include "ndarray/Array.h"
+
+using namespace ndarray;
+
+TEST(NDArray_tests, basic_data_test)
+{
+
+ float raw_data[] = {1, 2, 3, 4};
+
+ Array<float> data22{raw_data, {2, 2}};
+
+ ASSERT_FLOAT_EQ(data22.at(0, 0), 1);
+ ASSERT_FLOAT_EQ(data22.at(0, 1), 2);
+ ASSERT_FLOAT_EQ(data22.at(1, 0), 3);
+ ASSERT_FLOAT_EQ(data22.at(1, 1), 4);
+ ASSERT_EQ(data22.shape().rank(), 2);
+ ASSERT_EQ(data22.shape().dim(0), 2);
+ ASSERT_EQ(data22.shape().dim(1), 2);
+
+ Array<float> data14{raw_data, {1, 4}};
+ ASSERT_FLOAT_EQ(data14.at(0, 0), 1);
+ ASSERT_FLOAT_EQ(data14.at(0, 1), 2);
+ ASSERT_FLOAT_EQ(data14.at(0, 2), 3);
+ ASSERT_FLOAT_EQ(data14.at(0, 3), 4);
+ ASSERT_EQ(data14.shape().rank(), 2);
+ ASSERT_EQ(data14.shape().dim(0), 1);
+ ASSERT_EQ(data14.shape().dim(1), 4);
+
+ ContiguousSpan<float> cs = data22.flat();
+ ASSERT_EQ(cs.size(), 4);
+ ASSERT_FLOAT_EQ(cs.at(3), 4);
+
+ Array<float> lv = std::move(data14);
+ ASSERT_FLOAT_EQ(lv.at(0, 0), 1);
+ ASSERT_FLOAT_EQ(lv.at(0, 1), 2);
+ ASSERT_FLOAT_EQ(lv.at(0, 2), 3);
+ ASSERT_FLOAT_EQ(lv.at(0, 3), 4);
+}
+
+TEST(NDArray_tests, slice_write_test)
+{
+ float raw_data[4] = {0};
+
+ Array<float> data22{raw_data, {2, 2}};
+
+ data22.slice(1) = {1, 2};
+
+ ASSERT_FLOAT_EQ(data22.at(0, 0), 0);
+ ASSERT_FLOAT_EQ(data22.at(0, 1), 0);
+ ASSERT_FLOAT_EQ(data22.at(1, 0), 1);
+ ASSERT_FLOAT_EQ(data22.at(1, 1), 2);
+}
+
+TEST(NDArray_tests, slice_read_test)
+{
+ float raw_data[4] = {1, 2, 3, 4};
+
+ Array<float> data22{raw_data, {2, 2}};
+
+ auto slice = data22.slice(1);
+
+ ASSERT_FLOAT_EQ(slice[0], 3);
+ ASSERT_FLOAT_EQ(slice[1], 4);
+}
+
+TEST(NDArray_tests, multidim_test)
+{
+ float raw_data[5] = {0, 1, 2, 3, 4};
+
+ Array<float> data22{raw_data, {1, 1, 1, 1, 5}};
+
+ ASSERT_FLOAT_EQ(data22.at(0, 0, 0, 0, 0), 0);
+ ASSERT_FLOAT_EQ(data22.at(0, 0, 0, 0, 1), 1);
+ ASSERT_FLOAT_EQ(data22.at(0, 0, 0, 0, 2), 2);
+ ASSERT_FLOAT_EQ(data22.at(0, 0, 0, 0, 3), 3);
+ ASSERT_FLOAT_EQ(data22.at(0, 0, 0, 0, 4), 4);
+}
+
+TEST(NDArray_tests, slice_assign_test)
+{
+ std::vector<float> v1{1, 2, 3, 4, 5};
+ std::vector<float> v2(5);
+
+ ContiguousSpan<float> span1(v1.begin(), v1.end());
+ ContiguousSpan<float> span2(v2.begin(), v2.end());
+
+ span2.assign(span1);
+
+ ASSERT_EQ(v1, v2);
+ ASSERT_EQ(span1.size(), 5);
+ ASSERT_EQ(span2.size(), 5);
+
+ ASSERT_EQ(span2.at(2), 3);
+ ASSERT_EQ(span2.at(4), 5);
+
+ ASSERT_EQ(*(span1.data() + 2), *(span1.data() + 2));
+
+ ContiguousSpan<float> span3(span2.offset(1));
+ ASSERT_EQ(span3.size(), 4);
+ ASSERT_EQ(span3.at(0), 2);
+ ASSERT_EQ(span3.at(1), 3);
+ ASSERT_EQ(span3.at(2), 4);
+ ASSERT_EQ(span3.at(3), 5);
+}