/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTENSOR_INDEX_VIEW_HPP #define XTENSOR_INDEX_VIEW_HPP #include #include #include #include #include #include #include "xexpression.hpp" #include "xiterable.hpp" #include "xoperation.hpp" #include "xsemantic.hpp" #include "xstrides.hpp" #include "xutils.hpp" namespace xt { /************************* * xindex_view extension * *************************/ namespace extension { template struct xindex_view_base_impl; template struct xindex_view_base_impl { using type = xtensor_empty_base; }; template struct xindex_view_base : xindex_view_base_impl, CT, I> { }; template using xindex_view_base_t = typename xindex_view_base::type; } /*************** * xindex_view * ***************/ template class xindex_view; template struct xcontainer_inner_types> { using xexpression_type = std::decay_t; using temporary_type = xarray; }; template struct xiterable_inner_types> { using inner_shape_type = std::array; using const_stepper = xindexed_stepper, true>; using stepper = xindexed_stepper, false>; }; /** * @class xindex_view * @brief View of an xexpression from vector of indices. * * The xindex_view class implements a flat (1D) view into a multidimensional * xexpression yielding the values at the indices of the index array. * xindex_view is not meant to be used directly, but only with the \ref index_view * and \ref filter helper functions. * * @tparam CT the closure type of the \ref xexpression type underlying this view * @tparam I the index array type of the view * * @sa index_view, filter */ template class xindex_view : public xview_semantic>, public xiterable>, public extension::xindex_view_base_t { public: using self_type = xindex_view; using xexpression_type = std::decay_t; using semantic_base = xview_semantic; using extension_base = extension::xindex_view_base_t; using expression_tag = typename extension_base::expression_tag; using value_type = typename xexpression_type::value_type; using reference = inner_reference_t; using const_reference = typename xexpression_type::const_reference; using pointer = typename xexpression_type::pointer; using const_pointer = typename xexpression_type::const_pointer; using size_type = typename xexpression_type::size_type; using difference_type = typename xexpression_type::difference_type; using iterable_base = xiterable; using inner_shape_type = typename iterable_base::inner_shape_type; using shape_type = inner_shape_type; using indices_type = I; using stepper = typename iterable_base::stepper; using const_stepper = typename iterable_base::const_stepper; using temporary_type = typename xcontainer_inner_types::temporary_type; using base_index_type = xindex_type_t; using bool_load_type = typename xexpression_type::bool_load_type; static constexpr layout_type static_layout = layout_type::dynamic; static constexpr bool contiguous_layout = false; template xindex_view(CTA&& e, I2&& indices) noexcept; template self_type& operator=(const xexpression& e); template disable_xexpression& operator=(const E& e); size_type size() const noexcept; size_type dimension() const noexcept; const inner_shape_type& shape() const noexcept; size_type shape(size_type index) const; layout_type layout() const noexcept; bool is_contiguous() const noexcept; template void fill(const T& value); reference operator()(size_type idx = size_type(0)); template reference operator()(size_type idx0, size_type idx1, Args... args); reference unchecked(size_type idx); template disable_integral_t operator[](const S& index); template reference operator[](std::initializer_list index); reference operator[](size_type i); template reference element(It first, It last); const_reference operator()(size_type idx = size_type(0)) const; template const_reference operator()(size_type idx0, size_type idx1, Args... args) const; const_reference unchecked(size_type idx) const; template disable_integral_t operator[](const S& index) const; template const_reference operator[](std::initializer_list index) const; const_reference operator[](size_type i) const; template const_reference element(It first, It last) const; xexpression_type& expression() noexcept; const xexpression_type& expression() const noexcept; template bool broadcast_shape(O& shape, bool reuse_cache = false) const; template bool has_linear_assign(const O& /*strides*/) const noexcept; template stepper stepper_begin(const ST& shape); template stepper stepper_end(const ST& shape, layout_type); template const_stepper stepper_begin(const ST& shape) const; template const_stepper stepper_end(const ST& shape, layout_type) const; template using rebind_t = xindex_view; template rebind_t build_index_view(E&& e) const; private: CT m_e; const indices_type m_indices; const inner_shape_type m_shape; void assign_temporary_impl(temporary_type&& tmp); friend class xview_semantic>; }; /*************** * xfiltration * ***************/ /** * @class xfiltration * @brief Filter of a xexpression for fast scalar assign. * * The xfiltration class implements a lazy filtration of a multidimentional * \ref xexpression, optimized for scalar and computed scalar assignments. * Actually, the \ref xfiltration class IS NOT an \ref xexpression and the * scalar and computed scalar assignments are the only method it provides. * The filtering condition is not evaluated until the filtration is assigned. * * xfiltration is not meant to be used directly, but only with the \ref filtration * helper function. * * @tparam ECT the closure type of the \ref xexpression type underlying this filtration * @tparam CCR the closure type of the filtering \ref xexpression type * * @sa filtration */ template class xfiltration { public: using self_type = xfiltration; using xexpression_type = std::decay_t; using const_reference = typename xexpression_type::const_reference; template xfiltration(ECTA&& e, CCTA&& condition); template disable_xexpression operator=(const E&); template disable_xexpression operator+=(const E&); template disable_xexpression operator-=(const E&); template disable_xexpression operator*=(const E&); template disable_xexpression operator/=(const E&); template disable_xexpression operator%=(const E&); private: template self_type& apply(F&& func); ECT m_e; CCT m_condition; }; /****************************** * xindex_view implementation * ******************************/ /** * @name Constructor */ //@{ /** * Constructs an xindex_view, selecting the indices specified by \a indices. * The resulting xexpression has a 1D shape with a length of n for n indices. * * @param e the underlying xexpression for this view * @param indices the indices to select */ template template inline xindex_view::xindex_view(CTA&& e, I2&& indices) noexcept : m_e(std::forward(e)) , m_indices(std::forward(indices)) , m_shape({m_indices.size()}) { } //@} /** * @name Extended copy semantic */ //@{ /** * The extended assignment operator. */ template template inline auto xindex_view::operator=(const xexpression& e) -> self_type& { return semantic_base::operator=(e); } //@} template template inline auto xindex_view::operator=(const E& e) -> disable_xexpression& { std::fill(this->begin(), this->end(), e); return *this; } template inline void xindex_view::assign_temporary_impl(temporary_type&& tmp) { std::copy(tmp.cbegin(), tmp.cend(), this->begin()); } /** * @name Size and shape */ //@{ /** * Returns the size of the xindex_view. */ template inline auto xindex_view::size() const noexcept -> size_type { return compute_size(shape()); } /** * Returns the number of dimensions of the xindex_view. */ template inline auto xindex_view::dimension() const noexcept -> size_type { return 1; } /** * Returns the shape of the xindex_view. */ template inline auto xindex_view::shape() const noexcept -> const inner_shape_type& { return m_shape; } /** * Returns the i-th dimension of the expression. */ template inline auto xindex_view::shape(size_type i) const -> size_type { return m_shape[i]; } template inline layout_type xindex_view::layout() const noexcept { return static_layout; } template inline bool xindex_view::is_contiguous() const noexcept { return false; } //@} /** * @name Data */ //@{ /** * Fills the view with the given value. * @param value the value to fill the view with. */ template template inline void xindex_view::fill(const T& value) { std::fill(this->begin(), this->end(), value); } /** * Returns a reference to the element at the specified position in the xindex_view. * @param idx index specifying the position in the index_view. More indices may be provided, * only the last one will be used. */ template inline auto xindex_view::operator()(size_type idx) -> reference { return m_e[m_indices[idx]]; } template template inline auto xindex_view::operator()(size_type, size_type idx1, Args... args) -> reference { return this->operator()(idx1, static_cast(args)...); } /** * Returns a reference to the element at the specified position in the xindex_view. * @param idx index specifying the position in the index_view. */ template inline auto xindex_view::unchecked(size_type idx) -> reference { return this->operator()(idx); } /** * Returns a constant reference to the element at the specified position in the xindex_view. * @param idx index specifying the position in the index_view. More indices may be provided, * only the last one will be used. */ template inline auto xindex_view::operator()(size_type idx) const -> const_reference { return m_e[m_indices[idx]]; } template template inline auto xindex_view::operator()(size_type, size_type idx1, Args... args) const -> const_reference { return this->operator()(idx1, args...); } /** * Returns a constant reference to the element at the specified position in the xindex_view. * @param idx index specifying the position in the index_view. */ template inline auto xindex_view::unchecked(size_type idx) const -> const_reference { return this->operator()(idx); } /** * Returns a reference to the element at the specified position in the container. * @param index a sequence of indices specifying the position in the container. Indices * must be unsigned integers, the number of indices in the list should be equal or greater * than the number of dimensions of the container. */ template template inline auto xindex_view::operator[](const S& index) -> disable_integral_t { return m_e[m_indices[index[0]]]; } template template inline auto xindex_view::operator[](std::initializer_list index) -> reference { return m_e[m_indices[*(index.begin())]]; } template inline auto xindex_view::operator[](size_type i) -> reference { return operator()(i); } /** * Returns a constant reference to the element at the specified position in the container. * @param index a sequence of indices specifying the position in the container. Indices * must be unsigned integers, the number of indices in the list should be equal or greater * than the number of dimensions of the container. */ template template inline auto xindex_view::operator[](const S& index) const -> disable_integral_t { return m_e[m_indices[index[0]]]; } template template inline auto xindex_view::operator[](std::initializer_list index) const -> const_reference { return m_e[m_indices[*(index.begin())]]; } template inline auto xindex_view::operator[](size_type i) const -> const_reference { return operator()(i); } /** * Returns a reference to the element at the specified position in the xindex_view. * @param first iterator starting the sequence of indices * The number of indices in the sequence should be equal to or greater 1. */ template template inline auto xindex_view::element(It first, It /*last*/) -> reference { return m_e[m_indices[(*first)]]; } /** * Returns a reference to the element at the specified position in the xindex_view. * @param first iterator starting the sequence of indices * The number of indices in the sequence should be equal to or greater 1. */ template template inline auto xindex_view::element(It first, It /*last*/) const -> const_reference { return m_e[m_indices[(*first)]]; } /** * Returns a reference to the underlying expression of the view. */ template inline auto xindex_view::expression() noexcept -> xexpression_type& { return m_e; } /** * Returns a constant reference to the underlying expression of the view. */ template inline auto xindex_view::expression() const noexcept -> const xexpression_type& { return m_e; } //@} /** * @name Broadcasting */ //@{ /** * Broadcast the shape of the xindex_view to the specified parameter. * @param shape the result shape * @param reuse_cache parameter for internal optimization * @return a boolean indicating whether the broadcasting is trivial */ template template inline bool xindex_view::broadcast_shape(O& shape, bool) const { return xt::broadcast_shape(m_shape, shape); } /** * Checks whether the xindex_view can be linearly assigned to an expression * with the specified strides. * @return a boolean indicating whether a linear assign is possible */ template template inline bool xindex_view::has_linear_assign(const O& /*strides*/) const noexcept { return false; } //@} /*************** * stepper api * ***************/ template template inline auto xindex_view::stepper_begin(const ST& shape) -> stepper { size_type offset = shape.size() - dimension(); return stepper(this, offset); } template template inline auto xindex_view::stepper_end(const ST& shape, layout_type) -> stepper { size_type offset = shape.size() - dimension(); return stepper(this, offset, true); } template template inline auto xindex_view::stepper_begin(const ST& shape) const -> const_stepper { size_type offset = shape.size() - dimension(); return const_stepper(this, offset); } template template inline auto xindex_view::stepper_end(const ST& shape, layout_type) const -> const_stepper { size_type offset = shape.size() - dimension(); return const_stepper(this, offset, true); } template template inline auto xindex_view::build_index_view(E&& e) const -> rebind_t { return rebind_t(std::forward(e), indices_type(m_indices)); } /****************************** * xfiltration implementation * ******************************/ /** * @name Constructor */ //@{ /** * Constructs a xfiltration on the given expression \c e, selecting * the elements matching the specified \c condition. * * @param e the \ref xexpression to filter. * @param condition the filtering \ref xexpression to apply. */ template template inline xfiltration::xfiltration(ECTA&& e, CCTA&& condition) : m_e(std::forward(e)) , m_condition(std::forward(condition)) { } //@} /** * @name Extended copy semantic */ //@{ /** * Assigns the scalar \c e to \c *this. * @param e the scalar to assign. * @return a reference to \ *this. */ template template inline auto xfiltration::operator=(const E& e) -> disable_xexpression { return apply( [this, &e](const_reference v, bool cond) { return cond ? e : v; } ); } //@} /** * @name Computed assignement */ //@{ /** * Adds the scalar \c e to \c *this. * @param e the scalar to add. * @return a reference to \c *this. */ template template inline auto xfiltration::operator+=(const E& e) -> disable_xexpression { return apply( [&e](const_reference v, bool cond) { return cond ? v + e : v; } ); } /** * Subtracts the scalar \c e from \c *this. * @param e the scalar to subtract. * @return a reference to \c *this. */ template template inline auto xfiltration::operator-=(const E& e) -> disable_xexpression { return apply( [&e](const_reference v, bool cond) { return cond ? v - e : v; } ); } /** * Multiplies \c *this with the scalar \c e. * @param e the scalar involved in the operation. * @return a reference to \c *this. */ template template inline auto xfiltration::operator*=(const E& e) -> disable_xexpression { return apply( [&e](const_reference v, bool cond) { return cond ? v * e : v; } ); } /** * Divides \c *this by the scalar \c e. * @param e the scalar involved in the operation. * @return a reference to \c *this. */ template template inline auto xfiltration::operator/=(const E& e) -> disable_xexpression { return apply( [&e](const_reference v, bool cond) { return cond ? v / e : v; } ); } /** * Computes the remainder of \c *this after division by the scalar \c e. * @param e the scalar involved in the operation. * @return a reference to \c *this. */ template template inline auto xfiltration::operator%=(const E& e) -> disable_xexpression { return apply( [&e](const_reference v, bool cond) { return cond ? v % e : v; } ); } template template inline auto xfiltration::apply(F&& func) -> self_type& { std::transform(m_e.cbegin(), m_e.cend(), m_condition.cbegin(), m_e.begin(), func); return *this; } /** * @brief creates an indexview from a container of indices. * * Returns a 1D view with the elements at \a indices selected. * * @param e the underlying xexpression * @param indices the indices to select * * @code{.cpp} * xarray a = {{1,5,3}, {4,5,6}}; * b = index_view(a, {{0, 0}, {1, 0}, {1, 1}}); * std::cout << b << std::endl; // {1, 4, 5} * b += 100; * std::cout << a << std::endl; // {{101, 5, 3}, {104, 105, 6}} * @endcode */ template inline auto index_view(E&& e, I&& indices) noexcept { using view_type = xindex_view, std::decay_t>; return view_type(std::forward(e), std::forward(indices)); } template inline auto index_view(E&& e, const xindex (&indices)[L]) noexcept { using view_type = xindex_view, std::array>; return view_type(std::forward(e), xt::to_array(indices)); } /** * @brief creates a view into \a e filtered by \a condition. * * Returns a 1D view with the elements selected where \a condition evaluates to \em true. * This is equivalent to \verbatim{index_view(e, argwhere(condition));}\endverbatim * The returned view is not optimal if you just want to assign a scalar to the filtered * elements. In that case, you should consider using the \ref filtration function * instead. * * @tparam L the traversal order * @param e the underlying xexpression * @param condition xexpression with shape of \a e which selects indices * * @code{.cpp} * xarray a = {{1,5,3}, {4,5,6}}; * b = filter(a, a >= 5); * std::cout << b << std::endl; // {5, 5, 6} * @endcode * * \sa filtration */ template inline auto filter(E&& e, O&& condition) noexcept { auto indices = argwhere(std::forward(condition)); using view_type = xindex_view, decltype(indices)>; return view_type(std::forward(e), std::move(indices)); } /** * @brief creates a filtration of \c e filtered by \a condition. * * Returns a lazy filtration optimized for scalar assignment. * Actually, scalar assignment and computed scalar assignments * are the only available methods of the filtration, the filtration * IS NOT an \ref xexpression. * * @param e the \ref xexpression to filter * @param condition the filtering \ref xexpression * * @code{.cpp} * xarray a = {{1,5,3}, {4,5,6}}; * filtration(a, a >= 5) += 2; * std::cout << a << std::endl; // {{1, 7, 3}, {4, 7, 8}} * @endcode */ template inline auto filtration(E&& e, C&& condition) noexcept { using filtration_type = xfiltration, xclosure_t>; return filtration_type(std::forward(e), std::forward(condition)); } } #endif