6 #ifndef TURI_FLEXIBLE_TYPE_NDARRAY 7 #define TURI_FLEXIBLE_TYPE_NDARRAY 10 #include <core/logging/assertions.hpp> 11 #include <core/storage/serialization/serialization_includes.hpp> 13 namespace flexible_type_impl {
17 static void mod_helper(T& a,
const T& b,
18 typename std::enable_if<std::is_floating_point<T>::value>::type* = 0) {
22 static void mod_helper(T& a,
const T& b,
23 typename std::enable_if<!std::is_floating_point<T>::value>::type* = 0) {
70 typedef size_t index_type;
72 typedef std::vector<index_type> index_range_type;
73 typedef std::vector<T> container_type;
76 std::shared_ptr<container_type> m_elem;
77 index_range_type m_shape;
78 index_range_type m_stride;
79 index_type m_start = 0;
85 const index_range_type&
shape = index_range_type(),
86 const index_range_type&
stride = index_range_type(),
87 const index_type
start = 0):
93 const index_range_type&
shape = index_range_type(),
94 const index_range_type&
stride = index_range_type(),
95 const index_type
start = 0):
99 if (m_shape.size() == 0 && elements->size() - m_start > 0) {
100 m_shape.push_back(elements->size() - m_start);
103 if (m_stride.size() == 0 && m_shape.size() > 0) {
104 m_stride.resize(m_shape.size());
105 int64_t i = m_shape.size() - 1;
109 m_stride[i] = m_stride[i + 1] * m_shape[i + 1];
114 bool empty = m_shape.size() == 0;
115 for (
size_t i = 0;i < m_shape.size(); ++i) {
116 if (m_shape[i] == 0) {
129 for (
size_t i = 0;i < m_shape.size(); ++i) {
137 const value_type& default_value) {
143 index_type total_size = 1;
145 for(
const index_type& t : shape) {
149 *
this =
ndarray(std::make_shared<container_type>(total_size, default_value),
155 const value_type& default_value)
156 :
ndarray(shape, {}, default_value)
168 if (m_elem.use_count() > 1) {
169 m_elem = std::make_shared<container_type>(*m_elem);
177 if (m_elem->empty()) {
194 template <
typename U>
196 ASSERT_EQ(m_stride.size(), index.size());
199 for (
size_t i = 0; i < index.size(); ++i) {
200 index_type v = index[i];
201 ASSERT_LT(v, m_shape[i]);
202 idx += v * m_stride[i];
217 template <
typename U>
220 for (
size_t i = 0; i < index.size(); ++i) {
221 index_type v = index[i];
222 idx += v * m_stride[i];
236 return (*m_elem)[m_start + elem_index];
244 return (*m_elem)[m_start + elem_index];
254 value_type&
at(
size_t elem_index) {
256 ASSERT_LT(m_start + elem_index, m_elem->size());
257 return (*m_elem)[m_start + elem_index];
264 const value_type&
at(
size_t elem_index)
const {
265 ASSERT_LT(m_start + elem_index, m_elem->size());
266 return (*m_elem)[m_start + elem_index];
312 const index_range_type&
shape()
const {
337 if (m_shape.size() == 0)
return 0;
338 if (m_elem ==
nullptr)
return 0;
340 for (
size_t s: m_shape) {
351 return m_start == 0 &&
353 last_index() == m_elem->size();
364 return m_shape.size() == m_stride.size() &&
365 num_elem() + m_start <= m_elem->size() &&
366 last_index() + m_start <= m_elem->size();
374 if (m_stride.size() == 0)
return true;
375 if (m_stride[0] == 0)
return false;
376 for (
size_t i = 1; i < m_stride.size(); ++i) {
377 if (m_stride[i] == 0 || m_stride[i - 1] < m_stride[i]) {
397 template <
typename U,
typename V>
398 static size_t inline increment_index(std::vector<U>& idx,
const std::vector<V>& _shape) {
400 int64_t i = idx.size() - 1;
401 for (;i >= 0 ; --i) {
403 if (idx[i] < _shape[i])
break;
419 template <
typename U>
440 ret.m_shape = m_shape;
442 ret.m_stride.resize(m_shape.size());
445 if (ret.m_shape.size() == 0 || ret.m_elem->size() == 0) {
450 int64_t i = ret.m_shape.size() - 1;
454 ret.m_stride[i] = ret.m_stride[i + 1] * ret.m_shape[i + 1];
457 std::vector<size_t> idx(m_shape.size(), 0);
461 (*ret.m_elem)[ctr] = (*
this)[
fast_index(idx)];
495 ret.m_shape = m_shape;
497 ret.m_stride.resize(m_shape.size());
500 if (ret.m_shape.size() == 0 || ret.m_elem->size() == 0) {
504 std::vector<std::pair<size_t, size_t>> stride_ordering(m_stride.size());
505 for (
size_t i = 0;i < m_stride.size(); ++i) stride_ordering[i] = {m_stride[i], i};
506 std::sort(stride_ordering.rbegin(), stride_ordering.rend());
509 ret.m_stride[stride_ordering[0].second] = 1;
510 for (
size_t i = 1;i < m_stride.size(); ++i) {
511 ret.m_stride[stride_ordering[i].second] =
512 ret.m_stride[stride_ordering[i - 1].second] * ret.m_shape[stride_ordering[i - 1].second];
515 std::vector<size_t> idx(m_shape.size(), 0);
549 m_elem = std::make_shared<container_type>();
557 if (m_shape.size() != other.m_shape.size())
return false;
558 for (
size_t i = 0;i < m_shape.size(); ++i) {
559 if (m_shape[i] != other.m_shape[i])
return false;
569 std::vector<size_t> idx(m_shape.size(), 0);
580 std::vector<size_t> idx(m_shape.size(), 0);
592 std::vector<size_t> idx(m_shape.size(), 0);
603 std::vector<size_t> idx(m_shape.size(), 0);
615 std::vector<size_t> idx(m_shape.size(), 0);
626 std::vector<size_t> idx(m_shape.size(), 0);
639 std::vector<size_t> idx(m_shape.size(), 0);
650 std::vector<size_t> idx(m_shape.size(), 0);
662 std::vector<size_t> idx(m_shape.size(), 0);
665 mod_helper(left, other[other.
fast_index(idx)]);
674 std::vector<size_t> idx(m_shape.size(), 0);
677 mod_helper(left, other);
686 std::vector<size_t> idx(m_shape.size(), 0);
697 if (&other ==
this)
return true;
700 std::vector<size_t> idx(m_shape.size(), 0);
709 return !((*this) == other);
712 void print(std::ostream& os)
const {
713 std::vector<size_t> idx(m_shape.size(), 0);
717 for (
size_t i = 0;i < idx.size(); ++i) os <<
"[";
718 size_t next_bracket_depth;
719 bool is_first_element =
true;
721 if (is_first_element ==
false) os <<
",";
723 is_first_element =
false;
725 if (next_bracket_depth == 0)
break;
726 for (
size_t i = next_bracket_depth ;i < idx.size(); ++i) os <<
"]";
727 if (next_bracket_depth < idx.size()) os <<
",";
728 for (
size_t i = next_bracket_depth;i < idx.size(); ++i) os <<
"[";
729 if (next_bracket_depth < idx.size()) is_first_element =
true;
731 for (
size_t i = 0;i < idx.size(); ++i) os <<
"]";
739 size_t last_index()
const {
740 if (m_shape.size() == 0)
return 0;
742 for (
size_t i = 0; i < m_shape.size(); ++i) {
743 last_idx += (m_shape[i]-1) * m_stride[i];
752 static_assert(
sizeof(
ndarray<int>*) ==
sizeof(
size_t),
"Pointer to ndarray must be the same size as size_t");
754 template <
typename T>
755 std::ostream& operator<<(std::ostream& os, const ndarray<T>& n) {
ndarray(const std::shared_ptr< container_type > &elements, const index_range_type &shape=index_range_type(), const index_range_type &stride=index_range_type(), const index_type start=0)
construct with custom stride ordering
ndarray< T > & operator%=(T other)
scalar modulo.
const value_type & at(size_t elem_index) const
The serialization input archive object which, provided with a reference to an istream, will read from the istream, providing deserialization capabilities.
bool has_canonical_stride() const
value_type & operator[](size_t elem_index)
std::shared_ptr< sframe > sort(std::shared_ptr< planner_node > sframe_planner_node, const std::vector< std::string > column_names, const std::vector< size_t > &sort_column_indices, const std::vector< bool > &sort_orders)
ndarray< T > & operator*=(T other)
scalar multiplication
ndarray< T > canonicalize() const
bool is_canonical() const
Returns true if the nd-array is in canonical ordering.
void save(oarchive &oarc) const
serializer
container_type & elements()
ndarray< T > & operator/=(const ndarray< T > &other)
element-wise division. The other array must have the same shape.
void load(iarchive &iarc)
deserializer
ndarray< T > compact() const
index_type fast_index(const std::vector< U > &index) const
const index_range_type & shape() const
ndarray< T > & operator*=(const ndarray< T > &other)
element-wise multiplication. The other array must have the same shape.
const index_range_type & stride() const
container_type & raw_elements()
const value_type & operator[](size_t elem_index) const
ndarray< T > & operator+=(T other)
scalar addition.
ndarray< T > & operator%=(const ndarray< T > &other)
element-wise modulo. The other array must have the same shape.
ndarray(const index_range_type &shape, const value_type &default_value)
Construct a new ndarray filled with a default value.
bool operator!=(const ndarray< T > &other) const
inverse of ==
#define ASSERT_TRUE(cond)
static size_t increment_index(std::vector< U > &idx, const std::vector< V > &_shape)
ndarray< T > & negate()
negation
bool operator==(const ndarray< T > &other) const
element-wise equality. The other array must have the same shape.
index_type index(const std::vector< U > &index) const
ndarray(const container_type &elements=container_type(), const index_range_type &shape=index_range_type(), const index_range_type &stride=index_range_type(), const index_type start=0)
construct with custom stride ordering
value_type & at(size_t elem_index)
ndarray< T > & operator+=(const ndarray< T > &other)
element-wise addition. The other array must have the same shape.
const container_type & raw_elements() const
The serialization output archive object which, provided with a reference to an ostream, will write to the ostream, providing serialization capabilities.
bool same_shape(const ndarray< T > &other) const
const container_type & elements() const
ndarray< T > & operator-=(T other)
scalar subtraction.
ndarray< T > & operator-=(const ndarray< T > &other)
element-wise subtraction. The other array must have the same shape.
size_t increment_index(std::vector< U > &idx) const
#define DASSERT_TRUE(cond)
ndarray< T > & operator/=(T other)
scalar division
ndarray(const index_range_type &shape, const index_range_type &stride, const value_type &default_value)
Construct a new ndarray filled with a default value.