| Server IP : 217.160.0.135 / Your IP : 216.73.217.117 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/types/ |
Upload File : |
#ifndef PYTHONIC_TYPES_NUMPY_EXPR_HPP
#define PYTHONIC_TYPES_NUMPY_EXPR_HPP
#include "pythonic/include/types/numpy_expr.hpp"
#include "pythonic/utils/meta.hpp"
#include "pythonic/types/nditerator.hpp"
#include "pythonic/builtins/ValueError.hpp"
PYTHONIC_NS_BEGIN
namespace types
{
namespace details
{
long best_of()
{
return 1;
}
template <class V0, class... Vs>
long best_of(V0 v0, Vs... vs)
{
long vtail = best_of(vs...);
return ((long)v0 == vtail) ? v0 : (v0 * vtail);
}
template <size_t I, class Args, size_t... Is>
long init_shape_element(Args const &args, utils::index_sequence<Is...>)
{
return best_of(std::get<Is>(args).template shape<I>()...);
}
}
template <class Op, class... Args>
numpy_expr<Op, Args...>::numpy_expr(Args const &... args)
: args(args...)
{
}
template <class Op, class... Args>
template <size_t... I>
typename numpy_expr<Op, Args...>::const_iterator
numpy_expr<Op, Args...>::_begin(utils::index_sequence<I...>) const
{
return {{make_step(size(), std::get<I>(args).template shape<0>())...},
const_cast<typename std::decay<Args>::type const &>(
std::get<I>(args)).begin()...};
}
template <class Op, class... Args>
typename numpy_expr<Op, Args...>::const_iterator
numpy_expr<Op, Args...>::begin() const
{
return _begin(utils::make_index_sequence<sizeof...(Args)>{});
}
template <class Op, class... Args>
template <size_t... I>
typename numpy_expr<Op, Args...>::const_iterator
numpy_expr<Op, Args...>::_end(utils::index_sequence<I...>) const
{
return {{make_step(size(), std::get<I>(args).template shape<0>())...},
const_cast<typename std::decay<Args>::type const &>(
std::get<I>(args)).end()...};
}
template <class Op, class... Args>
typename numpy_expr<Op, Args...>::const_iterator
numpy_expr<Op, Args...>::end() const
{
return _end(utils::make_index_sequence<sizeof...(Args)>{});
}
template <class Op, class... Args>
typename numpy_expr<Op, Args...>::const_fast_iterator
numpy_expr<Op, Args...>::begin(types::fast) const
{
return {*this, 0};
}
template <class Op, class... Args>
typename numpy_expr<Op, Args...>::const_fast_iterator
numpy_expr<Op, Args...>::end(types::fast) const
{
return {*this, size()};
}
template <class Op, class... Args>
template <size_t... I>
bool numpy_expr<Op, Args...>::_no_broadcast(utils::index_sequence<I...>) const
{
bool child_broadcast = false;
(void)std::initializer_list<bool>{
(child_broadcast |= !utils::no_broadcast(std::get<I>(args)))...};
if (child_broadcast)
return false;
bool same_shape = true;
(void)std::initializer_list<bool>{
(same_shape &= (is_trivial_broadcast<I, decltype(args)>() ||
std::get<I>(args).template shape<0>() == size()))...};
return same_shape;
}
template <class Op, class... Args>
template <size_t... I>
bool numpy_expr<Op, Args...>::_no_broadcast_ex(
utils::index_sequence<I...>) const
{
bool child_broadcast = false;
(void)std::initializer_list<bool>{
(child_broadcast |= !utils::no_broadcast_ex(std::get<I>(args)))...};
if (child_broadcast)
return false;
bool same_shape = true;
auto shp = sutils::getshape(*this);
(void)std::initializer_list<bool>{
(same_shape &= (is_trivial_broadcast<I, decltype(args)>() ||
sutils::getshape(std::get<I>(args)) == shp))...};
return same_shape;
}
template <class Op, class... Args>
template <size_t... I>
bool numpy_expr<Op, Args...>::_no_broadcast_vectorize(
utils::index_sequence<I...>) const
{
bool child_broadcast = false;
(void)std::initializer_list<bool>{
(child_broadcast |= !utils::no_broadcast(std::get<I>(args)))...};
if (child_broadcast)
return false;
bool same_shape = true;
(void)std::initializer_list<bool>{
(same_shape &=
((long)std::get<I>(args).template shape<0>() == size()))...};
return same_shape;
}
template <class Op, class... Args>
bool numpy_expr<Op, Args...>::no_broadcast() const
{
return _no_broadcast(utils::make_index_sequence<sizeof...(Args)>{});
}
template <class Op, class... Args>
bool numpy_expr<Op, Args...>::no_broadcast_ex() const
{
return _no_broadcast_ex(utils::make_index_sequence<sizeof...(Args)>{});
}
template <class Op, class... Args>
bool numpy_expr<Op, Args...>::no_broadcast_vectorize() const
{
return _no_broadcast_vectorize(
utils::make_index_sequence<sizeof...(Args)>{});
}
template <class Op, class... Args>
template <size_t... I>
typename numpy_expr<Op, Args...>::iterator
numpy_expr<Op, Args...>::_begin(utils::index_sequence<I...>)
{
return {{make_step(size(), std::get<I>(args).template shape<0>())...},
const_cast<typename std::decay<Args>::type &>(std::get<I>(args))
.begin()...};
}
template <class Op, class... Args>
typename numpy_expr<Op, Args...>::iterator numpy_expr<Op, Args...>::begin()
{
return _begin(utils::make_index_sequence<sizeof...(Args)>{});
}
template <class Op, class... Args>
template <size_t... I>
typename numpy_expr<Op, Args...>::iterator
numpy_expr<Op, Args...>::_end(utils::index_sequence<I...>)
{
return {{make_step(size(), std::get<I>(args).template shape<0>())...},
const_cast<typename std::decay<Args>::type &>(std::get<I>(args))
.end()...};
}
template <class Op, class... Args>
typename numpy_expr<Op, Args...>::iterator numpy_expr<Op, Args...>::end()
{
return _end(utils::make_index_sequence<sizeof...(Args)>{});
}
template <class Op, class... Args>
auto numpy_expr<Op, Args...>::fast(long i) const
-> decltype(this->_fast(i, utils::make_index_sequence<sizeof...(Args)>{}))
{
return _fast(i, utils::make_index_sequence<sizeof...(Args)>{});
}
template <class Op, class... Args>
template <class... Indices>
auto numpy_expr<Op, Args...>::map_fast(Indices... indices) const -> decltype(
this->_map_fast(array<long, sizeof...(Indices)>{{indices...}},
utils::make_index_sequence<sizeof...(Args)>{}))
{
static_assert(sizeof...(Indices) == sizeof...(Args), "compatible call");
return _map_fast(array<long, sizeof...(Indices)>{{indices...}},
utils::make_index_sequence<sizeof...(Args)>{});
}
template <class Op, class... Args>
auto numpy_expr<Op, Args...>::operator[](long i) const
-> decltype(this->fast(i))
{
if (i < 0)
i += size();
return fast(i);
}
#ifdef USE_XSIMD
template <class Op, class... Args>
template <size_t... I>
typename numpy_expr<Op, Args...>::simd_iterator
numpy_expr<Op, Args...>::_vbegin(vectorize,
utils::index_sequence<I...>) const
{
return {{make_step(size(), std::get<I>(args).template shape<0>())...},
std::make_tuple(const_cast<typename std::decay<Args>::type const &>(
std::get<I>(args)).begin()...),
std::get<I>(args).vbegin(vectorize{})...};
}
template <class Op, class... Args>
typename numpy_expr<Op, Args...>::simd_iterator
numpy_expr<Op, Args...>::vbegin(vectorize) const
{
return _vbegin(vectorize{}, utils::make_index_sequence<sizeof...(Args)>{});
}
template <class Op, class... Args>
template <size_t... I>
typename numpy_expr<Op, Args...>::simd_iterator
numpy_expr<Op, Args...>::_vend(vectorize,
utils::index_sequence<I...>) const
{
return {{make_step(size(), std::get<I>(args).template shape<0>())...},
std::make_tuple(const_cast<typename std::decay<Args>::type const &>(
std::get<I>(args)).end()...),
std::get<I>(args).vend(vectorize{})...};
}
template <class Op, class... Args>
typename numpy_expr<Op, Args...>::simd_iterator
numpy_expr<Op, Args...>::vend(vectorize) const
{
return _vend(vectorize{}, utils::make_index_sequence<sizeof...(Args)>{});
}
template <class Op, class... Args>
template <size_t... I>
typename numpy_expr<Op, Args...>::simd_iterator_nobroadcast
numpy_expr<Op, Args...>::_vbegin(vectorize_nobroadcast,
utils::index_sequence<I...>) const
{
return {std::get<I>(args).vbegin(vectorize_nobroadcast{})...};
}
template <class Op, class... Args>
typename numpy_expr<Op, Args...>::simd_iterator_nobroadcast
numpy_expr<Op, Args...>::vbegin(vectorize_nobroadcast) const
{
return _vbegin(vectorize_nobroadcast{},
utils::make_index_sequence<sizeof...(Args)>{});
}
template <class Op, class... Args>
template <size_t... I>
typename numpy_expr<Op, Args...>::simd_iterator_nobroadcast
numpy_expr<Op, Args...>::_vend(vectorize_nobroadcast,
utils::index_sequence<I...>) const
{
return {std::get<I>(args).vend(vectorize_nobroadcast{})...};
}
template <class Op, class... Args>
typename numpy_expr<Op, Args...>::simd_iterator_nobroadcast
numpy_expr<Op, Args...>::vend(vectorize_nobroadcast) const
{
return _vend(vectorize_nobroadcast{},
utils::make_index_sequence<sizeof...(Args)>{});
}
#endif
template <class Op, class... Args>
template <class... S>
auto numpy_expr<Op, Args...>::operator()(S const &... s) const
-> decltype(this->_get(utils::make_index_sequence<sizeof...(Args)>{},
s...))
{
return _get(utils::make_index_sequence<sizeof...(Args)>{}, s...);
}
template <class Op, class... Args>
template <class F>
typename std::enable_if<
is_numexpr_arg<F>::value &&
std::is_same<bool, typename F::dtype>::value &&
!is_pod_array<F>::value,
numpy_vexpr<numpy_expr<Op, Args...>, ndarray<long, pshape<long>>>>::type
numpy_expr<Op, Args...>::fast(F const &filter) const
{
long sz = filter.template shape<0>();
long *raw = (long *)malloc(sz * sizeof(long));
long n = 0;
for (long i = 0; i < sz; ++i)
if (filter.fast(i))
raw[n++] = i;
// realloc(raw, n * sizeof(long));
long shp[1] = {n};
return this->fast(
ndarray<long, pshape<long>>(raw, shp, types::ownership::owned));
}
template <class Op, class... Args>
template <class F>
typename std::enable_if<
is_numexpr_arg<F>::value &&
std::is_same<bool, typename F::dtype>::value &&
!is_pod_array<F>::value,
numpy_vexpr<numpy_expr<Op, Args...>, ndarray<long, pshape<long>>>>::type
numpy_expr<Op, Args...>::
operator[](F const &filter) const
{
return fast(filter);
}
template <class Op, class... Args>
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<numpy_expr<Op, Args...>, F>>::type
numpy_expr<Op, Args...>::
operator[](F const &filter) const
{
return {*this, filter};
}
template <class Op, class... Args>
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<numpy_expr<Op, Args...>, F>>::type
numpy_expr<Op, Args...>::fast(F const &filter) const
{
return {*this, filter};
}
template <class Op, class... Args>
numpy_expr<Op, Args...>::operator bool() const
{
if (sutils::any_of(*this, [](long n) { return n != 1; }))
throw ValueError("The truth value of an array with more than one element "
"is ambiguous. Use a.any() or a.all()");
array<long, value> first = {0};
return operator[](first);
}
template <class Op, class... Args>
long numpy_expr<Op, Args...>::flat_size() const
{
return prod_helper(*this, utils::make_index_sequence<value>());
}
template <class Op, class... Args>
long numpy_expr<Op, Args...>::size() const
{
return this->template shape<0>();
}
}
PYTHONIC_NS_END
#endif