| Server IP : 217.160.0.135 / Your IP : 216.73.217.85 Web Server : Apache System : Linux www 6.18.52-i1-ampere #1203 SMP Mon Sep 14 18:29:59 CEST 2026 aarch64 User : sws1074145052 ( 1074145052) PHP Version : 8.3.32 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /lib/python3/dist-packages/pythran/pythonic/include/types/ |
Upload File : |
#ifndef PYTHONIC_INCLUDE_TYPES_NDARRAY_HPP
#define PYTHONIC_INCLUDE_TYPES_NDARRAY_HPP
#include "pythonic/include/types/assignable.hpp"
#include "pythonic/include/types/empty_iterator.hpp"
#include "pythonic/include/types/attr.hpp"
#include "pythonic/include/utils/nested_container.hpp"
#include "pythonic/include/utils/shared_ref.hpp"
#include "pythonic/include/utils/reserve.hpp"
#include "pythonic/include/utils/int_.hpp"
#include "pythonic/include/utils/broadcast_copy.hpp"
#include "pythonic/include/types/slice.hpp"
#include "pythonic/include/types/tuple.hpp"
#include "pythonic/include/types/list.hpp"
#include "pythonic/include/types/raw_array.hpp"
#include "pythonic/include/numpy/bool_.hpp"
#include "pythonic/include/numpy/uint8.hpp"
#include "pythonic/include/numpy/int8.hpp"
#include "pythonic/include/numpy/uint16.hpp"
#include "pythonic/include/numpy/int16.hpp"
#include "pythonic/include/numpy/uint32.hpp"
#include "pythonic/include/numpy/int32.hpp"
#include "pythonic/include/numpy/uint64.hpp"
#include "pythonic/include/numpy/int64.hpp"
#include "pythonic/include/numpy/float32.hpp"
#include "pythonic/include/numpy/float64.hpp"
#include "pythonic/include/numpy/complex64.hpp"
#include "pythonic/include/numpy/complex128.hpp"
#include "pythonic/include/types/dynamic_tuple.hpp"
#include "pythonic/include/types/vectorizable_type.hpp"
#include "pythonic/include/types/numpy_op_helper.hpp"
#include "pythonic/include/types/numpy_expr.hpp"
#include "pythonic/include/types/numpy_texpr.hpp"
#include "pythonic/include/types/numpy_iexpr.hpp"
#include "pythonic/include/types/numpy_gexpr.hpp"
#include "pythonic/include/types/numpy_vexpr.hpp"
#include "pythonic/include/utils/numpy_traits.hpp"
#include "pythonic/include/utils/array_helper.hpp"
#include "pythonic/include/types/pointer.hpp"
#include "pythonic/include/builtins/len.hpp"
#include <cassert>
#include <ostream>
#include <iterator>
#include <array>
#include <initializer_list>
#include <numeric>
#ifdef ENABLE_PYTHON_MODULE
// Cython still uses the deprecated API, so we can't set this macro in this
// case!
#ifndef CYTHON_ABI
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#endif
#include "numpy/arrayobject.h"
#endif
#ifdef USE_XSIMD
#include <xsimd/xsimd.hpp>
#endif
PYTHONIC_NS_BEGIN
namespace types
{
template <class T, class pS>
struct ndarray;
template <class T>
struct type_helper;
/* Helper for dimension-specific part of ndarray
*
* Instead of specializing the whole ndarray class, the dimension-specific
*behavior are stored here.
* There are two specialization for this type:
* - a specialization depending on the dimensionality (==1 || > 1)
* - a specialization depending on the constness.
*
* The raw ndarray<T,pS> specialization implies a *swallow copy* of the
*ndarray, && thus a refcount increase.
* It is meant to be used when indexing an rvalue, as in
*``np.zeros(10)[i]``.
*
* The ndarray<T,pS> const& specialization implies a *reference copy*. It is
*used when indexing a lvalue, as in ``a[i]``
*/
template <class T, class pS>
struct type_helper<ndarray<T, pS>> {
static_assert(std::tuple_size<pS>::value != 1, "matching ok");
using type = numpy_iexpr<ndarray<T, pS>>;
using iterator = nditerator<ndarray<T, pS>>;
using const_iterator = const_nditerator<ndarray<T, pS>>;
type_helper() = delete; // Not intended to be instantiated
static iterator make_iterator(ndarray<T, pS> &n, long i);
static const_iterator make_iterator(ndarray<T, pS> const &n, long i);
template <class S, class Iter>
static T *initialize_from_iterable(S &shape, T *from, Iter &&iter);
static numpy_iexpr<ndarray<T, pS>> get(ndarray<T, pS> &&self, long i);
};
template <class T, class pS>
struct type_helper<ndarray<T, pS> const &> {
static_assert(std::tuple_size<pS>::value != 1, "matching ok");
using type = numpy_iexpr<ndarray<T, pS> const &>;
using iterator = nditerator<ndarray<T, pS>>;
using const_iterator = const_nditerator<ndarray<T, pS>>;
type_helper() = delete; // Not intended to be instantiated
static iterator make_iterator(ndarray<T, pS> &n, long i);
static const_iterator make_iterator(ndarray<T, pS> const &n, long i);
template <class S, class Iter>
static T *initialize_from_iterable(S &shape, T *from, Iter &&iter);
static numpy_iexpr<ndarray<T, pS> const &> get(ndarray<T, pS> const &self,
long i);
};
template <class T, class pS>
struct type_helper<ndarray<T, pshape<pS>>> {
using type = T;
using iterator = T *;
using const_iterator = T const *;
type_helper() = delete; // Not intended to be instantiated
static iterator make_iterator(ndarray<T, pshape<pS>> &n, long i);
static const_iterator make_iterator(ndarray<T, pshape<pS>> const &n,
long i);
template <class S, class Iter>
static T *initialize_from_iterable(S &shape, T *from, Iter &&iter);
static type get(ndarray<T, pshape<pS>> &&self, long i);
};
template <class T, class pS>
struct type_helper<ndarray<T, pshape<pS>> const &> {
using type = T;
using iterator = T *;
using const_iterator = T const *;
type_helper() = delete; // Not intended to be instantiated
static iterator make_iterator(ndarray<T, pshape<pS>> &n, long i);
static const_iterator make_iterator(ndarray<T, pshape<pS>> const &n,
long i);
template <class S, class Iter>
static T *initialize_from_iterable(S &shape, T *from, Iter &&iter);
static type &get(ndarray<T, pshape<pS>> const &self, long i);
};
template <class T, class pS>
struct type_helper<ndarray<T, array<pS, 1>>> {
using type = T;
using iterator = T *;
using const_iterator = T const *;
type_helper() = delete; // Not intended to be instantiated
static iterator make_iterator(ndarray<T, array<pS, 1>> &n, long i);
static const_iterator make_iterator(ndarray<T, array<pS, 1>> const &n,
long i);
template <class S, class Iter>
static T *initialize_from_iterable(S &shape, T *from, Iter &&iter);
static type get(ndarray<T, array<pS, 1>> &&self, long i);
};
template <class T, class pS>
struct type_helper<ndarray<T, array<pS, 1>> const &> {
using type = T;
using iterator = T *;
using const_iterator = T const *;
type_helper() = delete; // Not intended to be instantiated
static iterator make_iterator(ndarray<T, array<pS, 1>> &n, long i);
static const_iterator make_iterator(ndarray<T, array<pS, 1>> const &n,
long i);
template <class S, class Iter>
static T *initialize_from_iterable(S &shape, T *from, Iter &&iter);
static type &get(ndarray<T, array<pS, 1>> const &self, long i);
};
/* Multidimensional array of values
*
* An ndarray wraps a raw array pointers && manages multiple dimensions
* casted overt the raw data.
* The number of dimensions is fixed as well as the type of the underlying
* data.
* A shared pointer is used internally to mimic Python's behavior.
*
*/
template <class T, class pS>
struct ndarray {
static const bool is_vectorizable = types::is_vectorizable<T>::value;
static const bool is_strided = false;
/* types */
static constexpr size_t value = std::tuple_size<pS>::value;
using dtype = T;
using value_type = typename type_helper<ndarray>::type;
using reference = value_type &;
using const_reference = value_type const &;
using iterator = typename type_helper<ndarray>::iterator;
using const_iterator = typename type_helper<ndarray>::const_iterator;
using flat_iterator = T *;
using const_flat_iterator = T const *;
using shape_t = pS;
static_assert(std::tuple_size<shape_t>::value == value,
"consistent shape size");
/* members */
utils::shared_ref<raw_array<T>> mem; // shared data pointer
T *buffer; // pointer to the first data stored in the equivalent flat
// array
shape_t _shape; // shape of the multidimensional array
sutils::concat_t<types::array<long, value - 1>,
pshape<std::integral_constant<long, 1>>>
_strides; // strides
/* mem management */
void mark_memory_external(extern_type obj)
{
mem.external(obj);
mem->forget();
}
/* constructors */
ndarray();
ndarray(ndarray const &) = default;
ndarray(ndarray &&) = default;
/* assignment */
ndarray &operator=(ndarray const &other) = default;
/* from other memory */
ndarray(utils::shared_ref<raw_array<T>> const &mem, pS const &shape);
ndarray(utils::shared_ref<raw_array<T>> &&mem, pS const &shape);
/* from other array */
template <class Tp, class pSp>
ndarray(ndarray<Tp, pSp> const &other);
template <class pSp>
ndarray(ndarray<T, pSp> const &other);
/* from a seed */
ndarray(pS const &shape, none_type init);
ndarray(pS const &shape, T init);
/* from a foreign pointer */
template <class S>
ndarray(T *data, S const *pshape, ownership o);
ndarray(T *data, pS const &pshape, ownership o);
#ifdef ENABLE_PYTHON_MODULE
template <class S>
ndarray(T *data, S const *pshape, PyObject *obj);
ndarray(T *data, pS const &pshape, PyObject *obj);
#endif
template <
class Iterable,
class = typename std::enable_if<
!is_array<typename std::remove_cv<
typename std::remove_reference<Iterable>::type>::type>::value &&
is_iterable<typename std::remove_cv<
typename std::remove_reference<Iterable>::type>::type>::
value,
void>::type>
ndarray(Iterable &&iterable);
/* from a numpy expression */
template <class E>
void initialize_from_expr(E const &expr);
template <class Op, class... Args>
ndarray(numpy_expr<Op, Args...> const &expr);
template <class Arg>
ndarray(numpy_texpr<Arg> const &expr);
template <class Arg>
ndarray(numpy_texpr_2<Arg> const &expr);
template <class Arg, class... S>
ndarray(numpy_gexpr<Arg, S...> const &expr);
template <class Arg>
ndarray(numpy_iexpr<Arg> const &expr);
template <class Arg, class F>
ndarray(numpy_vexpr<Arg, F> const &expr);
/* update operators */
template <class Op, class Expr>
ndarray &update_(Expr const &expr);
template <class Expr>
ndarray &operator+=(Expr const &expr);
template <class Expr>
ndarray &operator-=(Expr const &expr);
template <class Expr>
ndarray &operator*=(Expr const &expr);
template <class Expr>
ndarray &operator/=(Expr const &expr);
template <class Expr>
ndarray &operator&=(Expr const &expr);
template <class Expr>
ndarray &operator|=(Expr const &expr);
template <class Expr>
ndarray &operator^=(Expr const &expr);
template <class E, class... Indices>
void store(E elt, Indices... indices)
{
static_assert(is_dtype<E>::value, "valid store");
*(buffer + noffset<std::tuple_size<pS>::value>{}(
*this, array<long, value>{{indices...}})) =
static_cast<E>(elt);
}
template <class... Indices>
dtype load(Indices... indices) const
{
return *(buffer + noffset<std::tuple_size<pS>::value>{}(
*this, array<long, value>{{indices...}}));
}
template <class Op, class E, class... Indices>
void update(E elt, Indices... indices) const
{
static_assert(is_dtype<E>::value, "valid store");
Op{}(*(buffer + noffset<std::tuple_size<pS>::value>{}(
*this, array<long, value>{{indices...}})),
static_cast<E>(elt));
}
/* element indexing
* differentiate const from non const, && r-value from l-value
* */
auto fast(long i) const
& -> decltype(type_helper<ndarray const &>::get(*this, i))
{
return type_helper<ndarray const &>::get(*this, i);
}
auto fast(long i) &&
-> decltype(type_helper<ndarray>::get(std::move(*this), i))
{
return type_helper<ndarray>::get(std::move(*this), i);
}
template <class Ty>
typename std::enable_if<std::is_integral<Ty>::value, T &>::type
fast(array<Ty, value> const &indices);
template <class Ty>
typename std::enable_if<std::is_integral<Ty>::value, T>::type
fast(array<Ty, value> const &indices) const;
template <class Ty, size_t M>
auto fast(array<Ty, M> const &indices) const & ->
typename std::enable_if<std::is_integral<Ty>::value,
decltype(nget<M - 1>().fast(*this,
indices))>::type;
template <class Ty, size_t M>
auto fast(array<Ty, M> const &indices) &&
-> typename std::enable_if<std::is_integral<Ty>::value,
decltype(nget<M - 1>().fast(std::move(*this),
indices))>::type;
#ifdef USE_XSIMD
using simd_iterator = const_simd_nditerator<ndarray>;
using simd_iterator_nobroadcast = simd_iterator;
template <class vectorizer>
simd_iterator vbegin(vectorizer) const;
template <class vectorizer>
simd_iterator vend(vectorizer) const;
#endif
#ifndef NDEBUG
template <class IndicesTy>
bool inbound_indices(IndicesTy const &indices) const
{
auto const shp = sutils::getshape(*this);
for (size_t i = 0, n = indices.size(); i < n; ++i) {
auto const index = indices[i];
auto const dim = shp[i];
if (0 > index || index >= dim)
return false;
}
return true;
}
#endif
/* slice indexing */
ndarray<T, sutils::push_front_t<pS, std::integral_constant<long, 1>>>
operator[](none_type) const;
template <class S>
typename std::enable_if<is_slice<S>::value,
numpy_gexpr<ndarray const &, normalize_t<S>>>::type
operator[](S const &s) const &;
template <class S>
typename std::enable_if<is_slice<S>::value,
numpy_gexpr<ndarray, normalize_t<S>>>::type
operator[](S const &s) &&
;
long size() const;
/* extended slice indexing */
template <class Ty>
auto operator()(Ty s) const ->
typename std::enable_if<std::is_integral<Ty>::value,
decltype((*this)[s])>::type
{
return (*this)[s];
}
template <class S0, class... S>
auto operator()(S0 const &s0, S const &... s) const & -> decltype(
extended_slice<count_new_axis<S0, S...>::value>{}((*this), s0, s...));
template <class S0, class... S>
auto operator()(S0 const &s0, S const &... s) &
-> decltype(extended_slice<count_new_axis<S0, S...>::value>{}((*this),
s0,
s...));
template <class S0, class... S>
auto operator()(S0 const &s0, S const &... s) &&
-> decltype(extended_slice<count_new_axis<S0, S...>::value>{}(
std::move(*this), s0, s...));
/* element filtering */
template <class F> // indexing through an array of boolean -- a mask
typename std::enable_if<
is_numexpr_arg<F>::value &&
std::is_same<bool, typename F::dtype>::value && F::value == 1 &&
!is_pod_array<F>::value,
numpy_vexpr<ndarray, ndarray<long, pshape<long>>>>::type
fast(F const &filter) const;
template <class F> // indexing through an array of boolean -- a mask
typename std::enable_if<
is_numexpr_arg<F>::value &&
std::is_same<bool, typename F::dtype>::value && F::value == 1 &&
!is_pod_array<F>::value,
numpy_vexpr<ndarray, ndarray<long, pshape<long>>>>::type
operator[](F const &filter) const;
template <class F> // indexing through an array of boolean -- a mask
typename std::enable_if<is_numexpr_arg<F>::value &&
std::is_same<bool, typename F::dtype>::value &&
F::value != 1 && !is_pod_array<F>::value,
numpy_vexpr<ndarray<T, pshape<long>>,
ndarray<long, pshape<long>>>>::type
fast(F const &filter) const;
template <class F> // indexing through an array of boolean -- a mask
typename std::enable_if<is_numexpr_arg<F>::value &&
std::is_same<bool, typename F::dtype>::value &&
F::value != 1 && !is_pod_array<F>::value,
numpy_vexpr<ndarray<T, pshape<long>>,
ndarray<long, pshape<long>>>>::type
operator[](F const &filter) const;
template <class F> // indexing through an array of indices -- a view
typename std::enable_if<is_numexpr_arg<F>::value &&
!is_array_index<F>::value &&
!std::is_same<bool, typename F::dtype>::value &&
!is_pod_array<F>::value,
numpy_vexpr<ndarray, F>>::type
operator[](F const &filter) const;
template <class F> // indexing through an array of indices -- a view
typename std::enable_if<is_numexpr_arg<F>::value &&
!is_array_index<F>::value &&
!std::is_same<bool, typename F::dtype>::value &&
!is_pod_array<F>::value,
numpy_vexpr<ndarray, F>>::type
fast(F const &filter) const;
auto operator[](long i) const & -> decltype(this->fast(i))
{
if (i < 0)
i += std::get<0>(_shape);
assert(0 <= i && i < std::get<0>(_shape));
return fast(i);
}
auto operator[](long i) && -> decltype(std::move(*this).fast(i))
{
if (i < 0)
i += std::get<0>(_shape);
assert(0 <= i && i < std::get<0>(_shape));
return std::move(*this).fast(i);
}
template <class Ty>
typename std::enable_if<std::is_integral<Ty>::value, T const &>::type
operator[](array<Ty, value> const &indices) const;
template <class Ty>
typename std::enable_if<std::is_integral<Ty>::value, T &>::type
operator[](array<Ty, value> const &indices);
template <class Ty, size_t M>
auto operator[](array<Ty, M> const &indices) const & ->
typename std::enable_if<std::is_integral<Ty>::value,
decltype(nget<M - 1>()(*this, indices))>::type;
template <class Ty, size_t M>
auto operator[](array<Ty, M> const &indices) &&
-> typename std::enable_if<std::is_integral<Ty>::value,
decltype(nget<M - 1>()(std::move(*this),
indices))>::type;
template <class Ty>
auto operator[](std::tuple<Ty> const &indices) const
-> decltype((*this)[std::get<0>(indices)])
{
return (*this)[std::get<0>(indices)];
}
template <class Ty0, class Ty1, class... Tys>
auto operator[](std::tuple<Ty0, Ty1, Tys...> const &indices) const ->
typename std::enable_if<
std::is_integral<Ty0>::value,
decltype((*this)[std::get<0>(indices)][tuple_tail(indices)])>::type
{
return (*this)[std::get<0>(indices)][tuple_tail(indices)];
}
template <class Slices, size_t... Is>
auto _fwdindex(Slices const &indices, utils::index_sequence<Is...>) const
& -> decltype((*this)(std::get<Is>(indices)...))
{
return (*this)(std::get<Is>(indices)...);
}
template <class S, size_t... Is>
auto _fwdindex(dynamic_tuple<S> const &indices,
utils::index_sequence<Is...>) const
& -> decltype((*this)(std::get<Is>(indices)...))
{
return (*this)((indices.size() > Is ? std::get<Is>(indices)
: contiguous_slice())...);
}
template <class Ty0, class Ty1, class... Tys,
class _ = typename std::enable_if<is_numexpr_arg<Ty0>::value,
void>::type>
auto operator[](std::tuple<Ty0, Ty1, Tys...> const &indices) const ->
typename std::enable_if<is_numexpr_arg<Ty0>::value,
decltype(this->_fwdindex(
indices, utils::make_index_sequence<
2 + sizeof...(Tys)>()))>::type;
template <class Ty, size_t M, class _ = typename std::enable_if<
!std::is_integral<Ty>::value, void>::type>
auto operator[](array<Ty, M> const &indices) const
& -> decltype(this->_fwdindex(indices, utils::make_index_sequence<M>()))
{
return _fwdindex(indices, utils::make_index_sequence<M>());
}
template <class S>
auto operator[](dynamic_tuple<S> const &indices) const
-> decltype(this->_fwdindex(indices,
utils::make_index_sequence<value>()))
{
return _fwdindex(indices, utils::make_index_sequence<value>());
}
/* through iterators */
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
const_flat_iterator fbegin() const;
const_flat_iterator fend() const;
flat_iterator fbegin();
flat_iterator fend();
/* member functions */
long flat_size() const;
bool may_overlap(ndarray const &) const;
template <class qS>
ndarray<T, qS> reshape(qS const &shape) const &;
template <class qS>
ndarray<T, qS> reshape(qS const &shape) &&
;
explicit operator bool() const;
ndarray<T, pshape<long>> flat() const;
ndarray<T, pS> copy() const;
intptr_t id() const;
template <size_t I>
auto shape() const -> decltype(std::get<I>(_shape))
{
return std::get<I>(_shape);
}
template <size_t I>
auto strides() const -> decltype(std::get<I>(_strides))
{
return std::get<I>(_strides);
}
operator pointer<T>()
{
return {buffer};
}
};
/* pretty printing { */
template <class T, class pS>
std::ostream &operator<<(std::ostream &os, ndarray<T, pS> const &e);
template <class E>
typename std::enable_if<is_array<E>::value, std::ostream &>::type
operator<<(std::ostream &os, E const &e);
/* } */
}
PYTHONIC_NS_END
/* std::get overloads */
namespace std
{
template <size_t I, class E>
auto get(E &&a) -> typename std::enable_if<
pythonic::types::is_array<typename std::remove_cv<
typename std::remove_reference<E>::type>::type>::value,
decltype(std::forward<E>(a)[I])>::type;
template <size_t I, class T, class pS>
struct tuple_element<I, pythonic::types::ndarray<T, pS>> {
using type = typename pythonic::types::ndarray<T, pS>::value_type;
};
template <size_t I, class Op, class... Args>
struct tuple_element<I, pythonic::types::numpy_expr<Op, Args...>> {
using type = typename pythonic::types::numpy_expr<Op, Args...>::dtype;
};
template <size_t I, class E>
struct tuple_element<I, pythonic::types::numpy_iexpr<E>> {
using type = decltype(std::declval<pythonic::types::numpy_iexpr<E>>()[0]);
};
template <size_t I, class E>
struct tuple_element<I, pythonic::types::numpy_texpr<E>> {
using type = decltype(std::declval<pythonic::types::numpy_texpr<E>>()[0]);
};
template <size_t I, class E, class... S>
struct tuple_element<I, pythonic::types::numpy_gexpr<E, S...>> {
using type =
decltype(std::declval<pythonic::types::numpy_gexpr<E, S...>>()[0]);
};
}
/* pythran attribute system { */
#include "pythonic/include/numpy/transpose.hpp"
PYTHONIC_NS_BEGIN
namespace types
{
namespace details
{
using dtype_table = std::tuple<void, pythonic::numpy::functor::int8,
pythonic::numpy::functor::int16, void,
pythonic::numpy::functor::int32, void, void,
void, pythonic::numpy::functor::int64>;
using dtype_utable =
std::tuple<void, pythonic::numpy::functor::uint8,
pythonic::numpy::functor::uint16, void,
pythonic::numpy::functor::uint32, void, void, void,
pythonic::numpy::functor::uint64>;
template <class T>
struct dtype_helper {
using table = typename std::conditional<std::is_signed<T>::value,
dtype_table, dtype_utable>::type;
using type = typename std::tuple_element <
(sizeof(T) < std::tuple_size<table>::value)
? sizeof(T)
: 0,
table > ::type;
};
template <>
struct dtype_helper<bool> {
using type = pythonic::numpy::functor::bool_;
};
template <>
struct dtype_helper<float> {
using type = pythonic::numpy::functor::float32;
};
template <>
struct dtype_helper<double> {
using type = pythonic::numpy::functor::float64;
};
template <>
struct dtype_helper<std::complex<float>> {
using type = pythonic::numpy::functor::complex64;
};
template <>
struct dtype_helper<std::complex<double>> {
using type = pythonic::numpy::functor::complex128;
};
template <>
struct dtype_helper<std::complex<long double>> {
using type = pythonic::numpy::functor::complex256;
};
}
template <class T>
using dtype_t = typename details::dtype_helper<T>::type;
}
namespace builtins
{
namespace details
{
template <size_t N>
struct _build_gexpr {
template <class E, class... S>
auto operator()(E const &a, S const &... slices)
-> decltype(_build_gexpr<N - 1>{}(a, types::contiguous_slice(),
slices...));
};
template <>
struct _build_gexpr<1> {
template <class E, class... S>
types::numpy_gexpr<E, types::normalize_t<S>...>
operator()(E const &a, S const &... slices);
};
template <class E>
E _make_real(E const &a, utils::int_<0>);
template <class E>
auto _make_real(E const &a, utils::int_<1>)
-> decltype(_build_gexpr<E::value>{}(
types::ndarray<typename types::is_complex<typename E::dtype>::type,
types::array<long, E::value>>{},
types::slice()));
template <class T, class Ss, size_t... Is>
auto real_get(T &&expr, Ss const &indices, utils::index_sequence<Is...>)
-> decltype(std::forward<T>(expr)(std::get<Is>(indices)...))
{
return std::forward<T>(expr)(std::get<Is>(indices)...);
}
template <class E>
types::ndarray<typename E::dtype, typename E::shape_t>
_make_imag(E const &a, utils::int_<0>);
template <class E>
auto _make_imag(E const &a, utils::int_<1>)
-> decltype(_build_gexpr<E::value>{}(
types::ndarray<typename types::is_complex<typename E::dtype>::type,
types::array<long, E::value>>{},
types::slice()));
template <class T, class Ss, size_t... Is>
auto imag_get(T &&expr, Ss const &indices, utils::index_sequence<Is...>)
-> decltype(std::forward<T>(expr)(std::get<Is>(indices)...))
{
return std::forward<T>(expr)(std::get<Is>(indices)...);
}
}
template <class E>
types::array<long, E::value> getattr(types::attr::SHAPE, E const &a);
template <class E>
long getattr(types::attr::NDIM, E const &a);
template <class E>
types::array<long, E::value> getattr(types::attr::STRIDES, E const &a);
template <class E>
long getattr(types::attr::SIZE, E const &a);
template <class E>
long getattr(types::attr::ITEMSIZE, E const &a);
template <class E>
long getattr(types::attr::NBYTES, E const &a);
template <class E>
auto getattr(types::attr::FLAT, E const &a) -> decltype(a.flat());
template <class E>
auto getattr(types::attr::T, E const &a) -> decltype(numpy::transpose(a))
{
return numpy::transpose(a);
}
template <class T, class pS>
auto getattr(types::attr::REAL, types::ndarray<T, pS> const &a) -> decltype(
details::_make_real(a, utils::int_<types::is_complex<T>::value>{}));
template <class Op, class... Args>
auto getattr(types::attr::REAL, types::numpy_expr<Op, Args...> const &a)
-> decltype(details::_make_real(
a, utils::int_<types::is_complex<
typename types::numpy_expr<Op, Args...>::dtype>::value>{}));
template <class E>
auto getattr(types::attr::REAL, types::numpy_texpr<E> const &a) -> decltype(
types::numpy_texpr<decltype(getattr(types::attr::REAL{}, a.arg))>{
getattr(types::attr::REAL{}, a.arg)});
template <class E>
auto getattr(types::attr::REAL, types::numpy_iexpr<E> const &a) -> decltype(
types::numpy_iexpr<decltype(getattr(types::attr::REAL{}, a.arg))>{
getattr(types::attr::REAL{}, a.arg)})
{
return {getattr(types::attr::REAL{}, a.arg)};
}
template <class T, class F>
auto getattr(types::attr::REAL, types::numpy_vexpr<T, F> const &a)
-> decltype(
types::numpy_vexpr<decltype(getattr(types::attr::REAL{}, a.data_)),
F>{getattr(types::attr::REAL{}, a.data_), a.view_})
{
return {getattr(types::attr::REAL{}, a.data_), a.view_};
}
template <class E, class... S>
auto getattr(types::attr::REAL, types::numpy_gexpr<E, S...> const &a)
-> decltype(
details::real_get(getattr(types::attr::REAL{}, a.arg), a.slices,
utils::make_index_sequence<
std::tuple_size<decltype(a.slices)>::value>()))
{
return details::real_get(getattr(types::attr::REAL{}, a.arg), a.slices,
utils::make_index_sequence<
std::tuple_size<decltype(a.slices)>::value>());
}
template <class T, class pS>
auto getattr(types::attr::IMAG, types::ndarray<T, pS> const &a) -> decltype(
details::_make_imag(a, utils::int_<types::is_complex<T>::value>{}));
template <class Op, class... Args>
auto getattr(types::attr::IMAG, types::numpy_expr<Op, Args...> const &a)
-> decltype(details::_make_imag(
a, utils::int_<types::is_complex<
typename types::numpy_expr<Op, Args...>::dtype>::value>{}));
template <class E>
auto getattr(types::attr::IMAG, types::numpy_texpr<E> const &a) -> decltype(
types::numpy_texpr<decltype(getattr(types::attr::IMAG{}, a.arg))>{
getattr(types::attr::IMAG{}, a.arg)});
template <class E>
auto geatttr(types::attr::IMAG, types::numpy_iexpr<E> const &a) -> decltype(
types::numpy_iexpr<decltype(getattr(types::attr::IMAG{}, a.arg))>{
getattr(types::attr::IMAG{}, a.arg)})
{
return {getattr(types::attr::IMAG{}, a.arg)};
}
template <class T, class F>
auto getattr(types::attr::IMAG, types::numpy_vexpr<T, F> const &a)
-> decltype(
types::numpy_vexpr<decltype(getattr(types::attr::IMAG{}, a.data_)),
F>{getattr(types::attr::IMAG{}, a.data_), a.view_})
{
return {getattr(types::attr::IMAG{}, a.data_), a.view_};
}
template <class E, class... S>
auto getattr(types::attr::IMAG, types::numpy_gexpr<E, S...> const &a)
-> decltype(
details::imag_get(getattr(types::attr::IMAG{}, a.arg), a.slices,
utils::make_index_sequence<
std::tuple_size<decltype(a.slices)>::value>()))
{
return details::imag_get(getattr(types::attr::IMAG{}, a.arg), a.slices,
utils::make_index_sequence<
std::tuple_size<decltype(a.slices)>::value>());
}
template <class E>
types::dtype_t<typename types::dtype_of<E>::type> getattr(types::attr::DTYPE,
E const &);
}
PYTHONIC_NS_END
/* } */
/* type inference stuff {*/
#include "pythonic/include/types/combined.hpp"
template <class T1, class T2, class pS1, class pS2>
struct __combined<pythonic::types::ndarray<T1, pS1>,
pythonic::types::ndarray<T2, pS2>> {
using type = pythonic::types::ndarray<
typename __combined<T1, T2>::type,
pythonic::sutils::common_shapes_t<std::tuple_size<pS1>::value, pS1, pS2>>;
};
template <class pS, class T, class... Tys>
struct __combined<pythonic::types::ndarray<T, pS>,
pythonic::types::numpy_expr<Tys...>> {
using expr_type = pythonic::types::numpy_expr<Tys...>;
using type = pythonic::types::ndarray<
typename __combined<T, typename expr_type::dtype>::type,
pythonic::sutils::common_shapes_t<std::tuple_size<pS>::value, pS,
typename expr_type::shape_t>>;
};
template <class pS, class T, class O>
struct __combined<pythonic::types::ndarray<T, pS>, O> {
using type = pythonic::types::ndarray<T, pS>;
};
template <class pS, class T, class O>
struct __combined<pythonic::types::ndarray<T, pS>, pythonic::types::none<O>> {
using type = pythonic::types::none<
typename __combined<pythonic::types::ndarray<T, pS>, O>::type>;
};
template <class pS, class T, class O>
struct __combined<pythonic::types::none<O>, pythonic::types::ndarray<T, pS>> {
using type = pythonic::types::none<
typename __combined<O, pythonic::types::ndarray<T, pS>>::type>;
};
template <class pS, class T>
struct __combined<pythonic::types::ndarray<T, pS>, pythonic::types::none_type> {
using type = pythonic::types::none<pythonic::types::ndarray<T, pS>>;
};
template <class pS, class T>
struct __combined<pythonic::types::none_type, pythonic::types::ndarray<T, pS>> {
using type = pythonic::types::none<pythonic::types::ndarray<T, pS>>;
};
template <class pS, class T, class C, class I>
struct __combined<indexable_container<C, I>, pythonic::types::ndarray<T, pS>> {
using type = pythonic::types::ndarray<T, pS>;
};
template <class pS, class T, class C>
struct __combined<indexable<C>, pythonic::types::ndarray<T, pS>> {
using type = pythonic::types::ndarray<T, pS>;
};
template <class pS, class T, class C>
struct __combined<container<C>, pythonic::types::ndarray<T, pS>> {
using type = pythonic::types::ndarray<T, pS>;
};
/* } */
#include "pythonic/include/types/numpy_operators.hpp"
#ifdef ENABLE_PYTHON_MODULE
#include "pythonic/python/core.hpp"
PYTHONIC_NS_BEGIN
template <class T, class pS>
struct to_python<types::ndarray<T, pS>> {
static PyObject *convert(types::ndarray<T, pS> const &n,
bool transpose = false);
};
template <class Arg>
struct to_python<types::numpy_iexpr<Arg>> {
static PyObject *convert(types::numpy_iexpr<Arg> const &v,
bool transpose = false);
};
template <class Arg, class... S>
struct to_python<types::numpy_gexpr<Arg, S...>> {
static PyObject *convert(types::numpy_gexpr<Arg, S...> const &v,
bool transpose = false);
};
template <class E>
struct to_python<types::numpy_texpr<E>> {
static PyObject *convert(types::numpy_texpr<E> const &t,
bool transpose = false)
{
auto const &n = t.arg;
PyObject *result = to_python<E>::convert(n, !transpose);
return result;
}
};
template <typename T, class pS>
struct from_python<types::ndarray<T, pS>> {
static bool is_convertible(PyObject *obj);
static types::ndarray<T, pS> convert(PyObject *obj);
};
template <typename T, class pS, class... S>
struct from_python<types::numpy_gexpr<types::ndarray<T, pS>, S...>> {
static bool is_convertible(PyObject *obj);
static types::numpy_gexpr<types::ndarray<T, pS>, S...> convert(PyObject *obj);
};
template <typename T, class pS, class... S>
struct from_python<types::numpy_gexpr<types::ndarray<T, pS> const &, S...>>
: from_python<types::numpy_gexpr<types::ndarray<T, pS>, S...>> {
};
template <typename E>
struct from_python<types::numpy_texpr<E>> {
static bool is_convertible(PyObject *obj);
static types::numpy_texpr<E> convert(PyObject *obj);
};
PYTHONIC_NS_END
/* specialization of std::copy to avoid the multiple calls implied by the
* recursive calls to std::copy */
namespace std
{
template <class T, class pS>
typename pythonic::types::nditerator<pythonic::types::ndarray<T, pS>> copy(
typename pythonic::types::const_nditerator<
pythonic::types::ndarray<T, pS>> begin,
typename pythonic::types::const_nditerator<
pythonic::types::ndarray<T, pS>> end,
typename pythonic::types::nditerator<pythonic::types::ndarray<T, pS>> out)
{
const long offset = pythonic::sutils::prod_tail(begin.data);
std::copy(begin.data.buffer + begin.index * offset,
end.data.buffer + end.index * offset,
out.data.buffer + out.index * offset);
return out + (end - begin);
}
}
#endif
#endif