[core.ADT] Add kernel index enumerator (#415)
author박종현/동작제어Lab(SR)/Staff Engineer/삼성전자 <jh1302.park@samsung.com>
Tue, 3 Jul 2018 01:19:18 +0000 (10:19 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Tue, 3 Jul 2018 01:19:18 +0000 (10:19 +0900)
This commit adds kernel index enumerator which is almost similar as
that of tensor, but specialized for convolution kernel.

Signed-off-by: Jonghyun Park <jh1302.park@samsung.com>
libs/core/include/nncc/core/ADT/kernel/IndexEnumerator.h [new file with mode: 0644]
libs/core/src/ADT/kernel/IndexEnumerator.cpp [new file with mode: 0644]
libs/core/src/ADT/kernel/IndexEnumerator.test.cpp [new file with mode: 0644]

diff --git a/libs/core/include/nncc/core/ADT/kernel/IndexEnumerator.h b/libs/core/include/nncc/core/ADT/kernel/IndexEnumerator.h
new file mode 100644 (file)
index 0000000..d9a28c4
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef __NNCC_CORE_ADT_KERNEL_INDEX_ENUMERATOR_H__
+#define __NNCC_CORE_ADT_KERNEL_INDEX_ENUMERATOR_H__
+
+#include "nncc/core/ADT/kernel/Shape.h"
+
+namespace nncc
+{
+namespace core
+{
+namespace ADT
+{
+namespace kernel
+{
+
+class IndexEnumerator
+{
+public:
+  explicit IndexEnumerator(const Shape &shape);
+
+public:
+  IndexEnumerator(IndexEnumerator &&) = delete;
+  IndexEnumerator(const IndexEnumerator &) = delete;
+
+public:
+  bool valid(void) const;
+
+public:
+  uint32_t count(void) const;
+  uint32_t depth(void) const;
+  uint32_t height(void) const;
+  uint32_t width(void) const;
+
+public:
+  void advance(void);
+
+private:
+  // Store max and current offset for count/depth/height/width
+  //
+  // NOTE Here explicit array is used instead of kernel::Shape to make
+  //      a room for improvement such as enumeration order (NHWC, NCHW)
+  //      support
+  uint32_t _max[4];
+  uint32_t _cur[4];
+
+private:
+  uint32_t _cursor;
+};
+
+} // namespace kernel
+} // namespace ADT
+} // namespace core
+} // namespace nncc
+
+#endif // __NNCC_CORE_ADT_KERNEL_INDEX_ENUMERATOR_H__
diff --git a/libs/core/src/ADT/kernel/IndexEnumerator.cpp b/libs/core/src/ADT/kernel/IndexEnumerator.cpp
new file mode 100644 (file)
index 0000000..21ed7e3
--- /dev/null
@@ -0,0 +1,68 @@
+#include "nncc/core/ADT/kernel/IndexEnumerator.h"
+
+#include <cassert>
+#include <algorithm>
+
+namespace nncc
+{
+namespace core
+{
+namespace ADT
+{
+namespace kernel
+{
+
+IndexEnumerator::IndexEnumerator(const Shape &shape) : _cursor(0)
+{
+  _max[0] = shape.width();
+  _max[1] = shape.height();
+  _max[2] = shape.depth();
+  _max[3] = shape.count();
+
+  std::fill(_cur, _cur + 4, 0);
+
+  // NOTE Null dimension should NOT exist
+  assert(std::find(_max, _max + 4, 0) == (_max + 4));
+}
+
+bool IndexEnumerator::valid(void) const { return _cursor < 4; }
+
+uint32_t IndexEnumerator::count(void) const { return _cur[3]; }
+uint32_t IndexEnumerator::depth(void) const { return _cur[2]; }
+uint32_t IndexEnumerator::height(void) const { return _cur[1]; }
+uint32_t IndexEnumerator::width(void) const { return _cur[0]; }
+
+void IndexEnumerator::advance(void)
+{
+  while (_cursor < 4)
+  {
+    if (_cur[_cursor] + 1 < _max[_cursor])
+    {
+      break;
+    }
+
+    ++_cursor;
+  }
+
+  if (_cursor == 4)
+  {
+    return;
+  }
+
+  // Increment index
+  _cur[_cursor] += 1;
+
+  // Reset indices for lower dimensions
+  for (uint32_t head = 0; head < _cursor; ++head)
+  {
+    _cur[head] = 0;
+  }
+
+  // Reset cursor
+  _cursor = 0;
+}
+
+} // namespace kernel
+} // namespace ADT
+} // namespace core
+} // namespace nncc
diff --git a/libs/core/src/ADT/kernel/IndexEnumerator.test.cpp b/libs/core/src/ADT/kernel/IndexEnumerator.test.cpp
new file mode 100644 (file)
index 0000000..4e55563
--- /dev/null
@@ -0,0 +1,30 @@
+#include "nncc/core/ADT/kernel/IndexEnumerator.h"
+
+#include <vector>
+#include <algorithm>
+
+#include <gtest/gtest.h>
+
+using nncc::core::ADT::kernel::Shape;
+using nncc::core::ADT::kernel::IndexEnumerator;
+
+TEST(ADT_KERNEL_INDEX_ENUMERATOR, iterate_full_range)
+{
+  const uint32_t N = 2;
+  const uint32_t C = 3;
+  const uint32_t H = 4;
+  const uint32_t W = 5;
+
+  const Shape shape{N, C, H, W};
+
+  std::vector<uint32_t> count;
+  count.resize(N * C * H * W, 0);
+
+  for (IndexEnumerator e{shape}; e.valid(); e.advance())
+  {
+    const uint32_t offset = ((e.count() * C + e.depth()) * H + e.height()) * W + e.width();
+    count.at(offset) += 1;
+  }
+
+  ASSERT_TRUE(std::all_of(count.begin(), count.end(), [](uint32_t n) { return n == 1; }));
+}