21#include <ElementsKernel/Unused.h>
33 : m_container_ptr(container_ptr)
36 , m_stride{strides.back()}
41NdArray<T>::Iterator<Const>::Iterator(ContainerInterface* container_ptr,
size_t offset,
size_t row_size,
size_t stride,
43 : m_container_ptr(container_ptr), m_offset(offset), m_row_size(row_size), m_stride(stride), m_i(start) {}
47NdArray<T>::Iterator<Const>::Iterator(
const Iterator<false>& other)
48 : m_container_ptr{other.m_container_ptr}
49 , m_offset{other.m_offset}
50 , m_row_size{other.m_row_size}
51 , m_stride{other.m_stride}
56auto NdArray<T>::Iterator<Const>::operator++() -> Iterator& {
63auto NdArray<T>::Iterator<Const>::operator++(
int) ->
const Iterator {
64 return Iterator{m_container_ptr, m_offset, m_row_size, m_stride, m_i + 1};
69bool NdArray<T>::Iterator<Const>::operator==(
const Iterator& other)
const {
70 return m_container_ptr == other.m_container_ptr && m_offset == other.m_offset && m_i == other.m_i;
75bool NdArray<T>::Iterator<Const>::operator!=(
const Iterator& other)
const {
76 return !(*
this == other);
81auto NdArray<T>::Iterator<Const>::operator*() -> value_t& {
87auto NdArray<T>::Iterator<Const>::operator*() const -> value_t {
93auto NdArray<T>::Iterator<Const>::operator+=(
size_t n) -> Iterator& {
100auto NdArray<T>::Iterator<Const>::operator+(
size_t n)
const -> Iterator {
101 return Iterator{m_container_ptr, m_offset, m_row_size, m_stride, m_i + n};
106auto NdArray<T>::Iterator<Const>::operator-=(
size_t n) -> Iterator& {
114auto NdArray<T>::Iterator<Const>::operator-(
size_t n)
const -> Iterator {
116 return Iterator{m_container_ptr, m_offset, m_row_size, m_stride, m_i - n};
121auto NdArray<T>::Iterator<Const>::operator-(
const Iterator& other) -> difference_type {
122 assert(m_container_ptr == other.m_container_ptr);
123 return m_i - other.m_i;
128auto NdArray<T>::Iterator<Const>::operator[](
size_t i) -> value_t& {
129 return m_container_ptr->get(m_offset + (m_i + i) * m_stride);
134auto NdArray<T>::Iterator<Const>::operator[](
size_t i)
const -> value_t {
135 return m_container_ptr->get(m_offset + (m_i + i) * m_stride);
140bool NdArray<T>::Iterator<Const>::operator<(
const Iterator& other) {
141 assert(m_container_ptr == other.m_container_ptr);
142 return m_i < other.m_i;
147bool NdArray<T>::Iterator<Const>::operator>(
const Iterator& other) {
148 assert(m_container_ptr == other.m_container_ptr);
149 return m_i > other.m_i;
154 : m_details_ptr(new Details{0,
166template <
template <
class...>
class Container>
168 : m_details_ptr(new Details{0,
175 if (m_details_ptr->m_size != m_details_ptr->m_container->size()) {
182template <
template <
class...>
class Container>
184 : m_details_ptr(new Details{0,
191 if (m_details_ptr->m_size != m_details_ptr->m_container->size()) {
198template <
template <
class...>
class Container>
200 : m_details_ptr(new Details{0,
207 if (m_details_ptr->m_shape.size() != m_details_ptr->m_stride_size.size()) {
210 if (!
std::is_sorted(m_details_ptr->m_stride_size.rbegin(), m_details_ptr->m_stride_size.rend())) {
216template <
typename II>
218 : m_details_ptr(new Details{0,
225 if (m_details_ptr->m_size != m_details_ptr->m_container->size()) {
232NdArray<T>::NdArray(
const self_type* other) : m_details_ptr(
make_unique<Details>(*other->m_details_ptr)) {
233 m_details_ptr->m_container = other->m_details_ptr->m_container->copy();
243template <
typename... Args>
245 : NdArray(appendAttrShape(shape_, attr_names.size()),
std::
forward<Args>(args)...) {
246 m_details_ptr->m_attr_names = attr_names;
251 if (!m_details_ptr->m_attr_names.empty())
255 if (new_size != m_details_ptr->m_size) {
256 throw std::range_error(
"New shape does not match the number of contained elements");
258 m_details_ptr->m_shape = new_shape;
264template <
typename... D>
265auto NdArray<T>::reshape(
size_t i, D... rest) -> self_type& {
267 return reshape_helper(acc, rest...);
271const T& NdArray<T>::front()
const {
272 return m_details_ptr->m_container->get(m_details_ptr->m_offset);
277 auto offset = get_offset(coords);
279 return m_details_ptr->m_container->get(offset);
284 auto offset = get_offset(coords);
286 return m_details_ptr->m_container->get(offset);
291 auto offset = get_offset(coords, attr);
293 return m_details_ptr->m_container->get(offset);
298 auto offset = get_offset(coords, attr);
300 return m_details_ptr->m_container->get(offset);
304template <
typename... D>
305T& NdArray<T>::at(
size_t i, D... rest) {
306 return at_helper(m_details_ptr->m_offset, 0, i, rest...);
310template <
typename... D>
311const T& NdArray<T>::at(
size_t i, D... rest)
const {
312 return at_helper(m_details_ptr->m_offset, 0, i, rest...);
316auto NdArray<T>::begin() -> iterator {
317 return iterator{m_details_ptr->m_container.get(), m_details_ptr->m_offset, m_details_ptr->m_shape,
318 m_details_ptr->m_stride_size, 0};
322auto NdArray<T>::end() -> iterator {
323 return iterator{m_details_ptr->m_container.get(), m_details_ptr->m_offset, m_details_ptr->m_shape,
324 m_details_ptr->m_stride_size, size()};
328auto NdArray<T>::begin() const -> const_iterator {
329 return const_iterator{m_details_ptr->m_container.get(), m_details_ptr->m_offset, m_details_ptr->m_shape,
330 m_details_ptr->m_stride_size, 0};
334auto NdArray<T>::end() const -> const_iterator {
335 return const_iterator{m_details_ptr->m_container.get(), m_details_ptr->m_offset, m_details_ptr->m_shape,
336 m_details_ptr->m_stride_size, size()};
340size_t NdArray<T>::size()
const {
341 return m_details_ptr->m_size;
345bool NdArray<T>::operator==(
const self_type& b)
const {
346 if (shape() != b.shape())
348 for (
auto ai =
begin(), bi = b.begin(); ai !=
end() && bi != b.end(); ++ai, ++bi) {
356bool NdArray<T>::operator!=(
const self_type& b)
const {
357 return !(*
this == b);
362 return m_details_ptr->m_attr_names;
366auto NdArray<T>::concatenate(
const self_type& other) -> self_type& {
368 if (m_details_ptr->m_shape.size() != other.m_details_ptr->m_shape.size()) {
369 throw std::length_error(
"Can not concatenate arrays with different dimensionality");
371 for (
size_t i = 1; i < m_details_ptr->m_shape.size(); ++i) {
372 if (m_details_ptr->m_shape[i] != other.m_details_ptr->m_shape[i])
373 throw std::length_error(
"The size of all axis except for the first one must match");
377 auto old_size = size();
378 auto new_shape = m_details_ptr->m_shape;
379 new_shape[0] += other.m_details_ptr->m_shape[0];
382 m_details_ptr->m_container->resize(new_shape);
387 m_details_ptr->m_shape = new_shape;
388 m_details_ptr->m_size += other.m_details_ptr->m_size;
396 stride.front() * shape_.front(),
std::
move(shape_),
std::
move(stride),
400NdArray<T>::NdArray(
const self_type& other) : m_details_ptr(
make_unique<Details>(*other.m_details_ptr)) {}
403NdArray<T>& NdArray<T>::operator=(
const self_type& other) {
404 m_details_ptr = make_unique<Details>(*other.m_details_ptr);
409auto NdArray<T>::slice(
size_t i) -> self_type {
410 if (m_details_ptr->m_shape.size() <= 1) {
414 if (!m_details_ptr->m_attr_names.empty()) {
415 attrs.
resize(m_details_ptr->m_attr_names.size());
416 std::copy(m_details_ptr->m_attr_names.begin(), m_details_ptr->m_attr_names.end(), attrs.
begin());
418 if (i >= m_details_ptr->m_shape[0]) {
421 auto offset = m_details_ptr->m_offset + i * m_details_ptr->m_stride_size[0];
422 std::vector<size_t> stride_(m_details_ptr->m_stride_size.begin() + 1, m_details_ptr->m_stride_size.end());
423 std::vector<size_t> shape_(m_details_ptr->m_shape.begin() + 1, m_details_ptr->m_shape.end());
428auto NdArray<T>::slice(
size_t i)
const ->
const self_type {
429 return const_cast<NdArray<T>*
>(
this)->slice(i);
433auto NdArray<T>::rslice(
size_t i) -> self_type {
434 if (m_details_ptr->m_shape.size() <= 1) {
437 if (!m_details_ptr->m_attr_names.empty()) {
440 if (i >= m_details_ptr->m_shape.back()) {
443 auto offset = m_details_ptr->m_offset + i * m_details_ptr->m_stride_size.back();
444 std::vector<size_t> strides_(m_details_ptr->m_stride_size.begin(), m_details_ptr->m_stride_size.end() - 1);
445 std::vector<size_t> shape_(m_details_ptr->m_shape.begin(), m_details_ptr->m_shape.end() - 1);
446 return NdArray(m_details_ptr->m_container, offset,
std::move(shape_),
std::move(strides_),
447 m_details_ptr->m_attr_names);
451auto NdArray<T>::rslice(
size_t i)
const ->
const self_type {
452 return const_cast<NdArray<T>*
>(
this)->rslice(i);
456void NdArray<T>::next_slice() {
457 m_details_ptr->m_offset += m_details_ptr->m_total_stride;
462 if (coords.
size() != m_details_ptr->m_shape.size()) {
467 size_t offset = m_details_ptr->m_offset;
468 for (
size_t i = 0; i < coords.
size(); ++i) {
469 if (coords[i] >= m_details_ptr->m_shape[i]) {
473 offset += coords[i] * m_details_ptr->m_stride_size[i];
476 assert(offset < m_details_ptr->m_container->nbytes());
481size_t NdArray<T>::get_attr_offset(
const std::string& attr)
const {
482 auto i =
std::find(m_details_ptr->m_attr_names.begin(), m_details_ptr->m_attr_names.end(), attr);
483 if (i == m_details_ptr->m_attr_names.end())
485 return (i - m_details_ptr->m_attr_names.begin()) *
sizeof(T);
489void NdArray<T>::update_strides() {
490 m_details_ptr->m_stride_size.resize(m_details_ptr->m_shape.size());
492 size_t acc =
sizeof(T);
493 for (
size_t i = m_details_ptr->m_stride_size.size(); i > 0; --i) {
494 m_details_ptr->m_stride_size[i - 1] = acc;
495 acc *= m_details_ptr->m_shape[i - 1];
498 m_details_ptr->m_total_stride = m_details_ptr->m_shape.front() * m_details_ptr->m_stride_size.front();
505template <
typename... D>
506T& NdArray<T>::at_helper(
size_t offset_acc,
size_t axis,
size_t i, D... rest) {
507 assert(axis <= m_details_ptr->m_shape.size() && i < m_details_ptr->m_shape[axis]);
508 offset_acc += i * m_details_ptr->m_stride_size[axis];
509 return at_helper(offset_acc, ++axis, rest...);
513T& NdArray<T>::at_helper(
size_t offset_acc, ELEMENTS_UNUSED
size_t axis) {
514 assert(axis == m_details_ptr->m_shape.size());
515 assert(offset_acc < m_details_ptr->m_container->nbytes());
516 return m_details_ptr->m_container->get(offset_acc);
520T& NdArray<T>::at_helper(
size_t offset_acc, ELEMENTS_UNUSED
size_t axis,
const std::string& attr) {
521 offset_acc += get_attr_offset(attr);
522 assert(axis == m_details_ptr->m_shape.size() - 1);
523 assert(offset_acc < m_details_ptr->m_container->nbytes());
524 return m_details_ptr->m_container->get(offset_acc);
528template <
typename... D>
529const T& NdArray<T>::at_helper(
size_t offset_acc,
size_t axis,
size_t i, D... rest)
const {
530 assert(axis <= m_details_ptr->m_shape.size() && i < m_details_ptr->m_shape[axis]);
531 offset_acc += i * m_details_ptr->m_stride_size[axis];
532 return at_helper(offset_acc, ++axis, rest...);
536const T& NdArray<T>::at_helper(
size_t offset_acc, ELEMENTS_UNUSED
size_t axis)
const {
537 assert(axis == m_details_ptr->m_shape.size());
538 assert(offset_acc < m_details_ptr->m_container->nbytes());
540 return m_details_ptr->m_container->get(offset_acc);
544const T& NdArray<T>::at_helper(
size_t offset_acc, ELEMENTS_UNUSED
size_t axis,
const std::string& attr)
const {
545 offset_acc += get_attr_offset(attr);
546 assert(axis == m_details_ptr->m_shape.size() - 1);
547 assert(offset_acc < m_details_ptr->m_container->nbytes());
549 return m_details_ptr->m_container->get(offset_acc);
553template <
typename... D>
554auto NdArray<T>::reshape_helper(
std::vector<size_t>& acc,
size_t i, D... rest) -> self_type& {
556 return reshape_helper(acc, rest...);
566 auto shape = ndarray.shape();
568 if (ndarray.size()) {
571 for (i = 0; i < shape.
size() - 1; ++i) {
572 out << shape[i] <<
",";
574 out << shape[i] <<
">";
576 auto iter = ndarray.begin(), end_iter = ndarray.end() - 1;
577 for (; iter != end_iter; ++iter) {
Iterator(ContainerInterface *container_ptr, size_t offset, const std::vector< size_t > &shape, const std::vector< size_t > &strides, size_t start)
ELEMENTS_API std::unique_ptr< T > make_unique(Args &&... args)