Iteration over tensor
Closed this issue · 3 comments
marty1885 commented
To match numpy's behavior, we should make the Tensor object iteratable. And iterates over the first dim by default.
Ex:
a = ones({4, 4});
for(auto s : a)
a += 1;
etc...
marty1885 commented
This turns out to be quite of a problem. Since views are generated on the fly; the C++ iterator architecture is fitting badly.
//Iterator
struct ETALER_EXPORT iterator
{
iterator(Tensor& t) : t_(&t) {}
Tensor operator*() { return t_->view({curr_}); } // Can't return ref here
Tensor* operator->() {/*real? How am I going to return a pointer from a local variable*/}
bool operator==(iterator rhs) { return curr_ == rhs.curr_ && t_ == rhs.t_; }
bool operator!=(iterator rhs) { !(*this == rhs); }
iterator& operator++() {curr_ += 1; return *this;}
iterator operator++(int) {iterator retval = *this; ++(*this); return retval;}
Tensor* t_; // Using a pointer because Tensor is a incomplete type within the type itself
intmax_t curr_ = 0;
};
marty1885 commented
This is the best I can do
template <typename T>
struct ETALER_EXPORT TensorIterator
{
// Iterator properties
using iterator_category = std::bidirectional_iterator_tag;
using value_type = T;
using raw_value_type = std::remove_const_t<value_type>; // extra
using difference_type = intmax_t;
using pointer = std::unique_ptr<raw_value_type>;
using reference = T&;
using ThisIterator = TensorIterator<T>;
TensorIterator() = default;
TensorIterator(reference t, intmax_t offset = 0) : t_(&t), offset_(offset)
{static_assert(std::is_same_v<raw_value_type, Tensor>); }
value_type operator*() { return t_->view({offset_}); }
// Unfortunatelly returning a pointer is not doable
pointer operator->() { return std::make_unique<raw_value_type>(*(*this)); }
bool operator==(ThisIterator rhs) const { return offset_ == rhs.offset_ && t_ == rhs.t_; }
bool operator!=(ThisIterator rhs) const { return !(*this == rhs); }
ThisIterator& operator++() {offset_ += 1; return *this;}
ThisIterator operator++(int) {ThisIterator retval = *this; ++(*this); return retval;}
ThisIterator& operator--() {offset_ -= 1; return *this;}
ThisIterator operator--(int) {ThisIterator retval = *this; --(*this); return retval;}
value_type* t_ = nullptr; // Using a pointer because Tensor is a incomplete type here
intmax_t offset_ = 0;
};
It works 90% of the time and have few caveats
operator*
should return a referenceoperator->
should return a pointerswap()
(not in the shown code` should accept references, not values