mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 19:40:18 +00:00
504 lines
17 KiB
C++
504 lines
17 KiB
C++
#ifndef XTENSOR_XBLOCKWISE_REDUCER_FUNCTORS_HPP
|
|
#define XTENSOR_XBLOCKWISE_REDUCER_FUNCTORS_HPP
|
|
|
|
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <tuple>
|
|
#include <typeinfo>
|
|
|
|
#include "xarray.hpp"
|
|
#include "xbuilder.hpp"
|
|
#include "xchunked_array.hpp"
|
|
#include "xchunked_assign.hpp"
|
|
#include "xchunked_view.hpp"
|
|
#include "xexpression.hpp"
|
|
#include "xmath.hpp"
|
|
#include "xnorm.hpp"
|
|
#include "xreducer.hpp"
|
|
#include "xtl/xclosure.hpp"
|
|
#include "xtl/xsequence.hpp"
|
|
#include "xutils.hpp"
|
|
|
|
namespace xt
|
|
{
|
|
namespace detail
|
|
{
|
|
namespace blockwise
|
|
{
|
|
|
|
struct empty_reduction_variable
|
|
{
|
|
};
|
|
|
|
struct simple_functor_base
|
|
{
|
|
template <class E>
|
|
auto reduction_variable(const E&) const
|
|
{
|
|
return empty_reduction_variable();
|
|
}
|
|
|
|
template <class MR, class E, class R>
|
|
void finalize(const MR&, E&, const R&) const
|
|
{
|
|
}
|
|
};
|
|
|
|
template <class T_E, class T_I = void>
|
|
struct sum_functor : public simple_functor_base
|
|
{
|
|
using value_type = typename std::decay_t<decltype(xt::sum<T_I>(std::declval<xarray<T_E>>()))>::value_type;
|
|
|
|
template <class E, class A, class O>
|
|
auto compute(const E& input, const A& axes, const O& options) const
|
|
{
|
|
return xt::sum<value_type>(input, axes, options);
|
|
}
|
|
|
|
template <class BR, class E, class MR>
|
|
auto merge(const BR& block_result, bool first, E& result, MR&) const
|
|
{
|
|
if (first)
|
|
{
|
|
xt::noalias(result) = block_result;
|
|
}
|
|
else
|
|
{
|
|
xt::noalias(result) += block_result;
|
|
}
|
|
}
|
|
};
|
|
|
|
template <class T_E, class T_I = void>
|
|
struct prod_functor : public simple_functor_base
|
|
{
|
|
using value_type = typename std::decay_t<decltype(xt::sum<T_I>(std::declval<xarray<T_E>>()))>::value_type;
|
|
|
|
template <class E, class A, class O>
|
|
auto compute(const E& input, const A& axes, const O& options) const
|
|
{
|
|
return xt::prod<value_type>(input, axes, options);
|
|
}
|
|
|
|
template <class BR, class E, class MR>
|
|
auto merge(const BR& block_result, bool first, E& result, MR&) const
|
|
{
|
|
if (first)
|
|
{
|
|
xt::noalias(result) = block_result;
|
|
}
|
|
else
|
|
{
|
|
xt::noalias(result) *= block_result;
|
|
}
|
|
}
|
|
};
|
|
|
|
template <class T_E, class T_I = void>
|
|
struct amin_functor : public simple_functor_base
|
|
{
|
|
using value_type = typename std::decay_t<decltype(xt::amin<T_I>(std::declval<xarray<T_E>>()))>::value_type;
|
|
|
|
template <class E, class A, class O>
|
|
auto compute(const E& input, const A& axes, const O& options) const
|
|
{
|
|
return xt::amin(input, axes, options);
|
|
}
|
|
|
|
template <class BR, class E, class MR>
|
|
auto merge(const BR& block_result, bool first, E& result, MR&) const
|
|
{
|
|
if (first)
|
|
{
|
|
xt::noalias(result) = block_result;
|
|
}
|
|
else
|
|
{
|
|
xt::noalias(result) = xt::minimum(block_result, result);
|
|
}
|
|
}
|
|
};
|
|
|
|
template <class T_E, class T_I = void>
|
|
struct amax_functor : public simple_functor_base
|
|
{
|
|
using value_type = typename std::decay_t<decltype(xt::amax<T_I>(std::declval<xarray<T_E>>()))>::value_type;
|
|
|
|
template <class E, class A, class O>
|
|
auto compute(const E& input, const A& axes, const O& options) const
|
|
{
|
|
return xt::amax(input, axes, options);
|
|
}
|
|
|
|
template <class BR, class E, class MR>
|
|
auto merge(const BR& block_result, bool first, E& result, MR&) const
|
|
{
|
|
if (first)
|
|
{
|
|
xt::noalias(result) = block_result;
|
|
}
|
|
else
|
|
{
|
|
xt::noalias(result) = xt::maximum(block_result, result);
|
|
}
|
|
}
|
|
};
|
|
|
|
template <class T_E, class T_I = void>
|
|
struct mean_functor
|
|
{
|
|
using value_type = typename std::decay_t<decltype(xt::mean<T_I>(std::declval<xarray<T_E>>()))>::value_type;
|
|
|
|
template <class E, class A, class O>
|
|
auto compute(const E& input, const A& axes, const O& options) const
|
|
{
|
|
return xt::sum<value_type>(input, axes, options);
|
|
}
|
|
|
|
template <class E>
|
|
auto reduction_variable(const E&) const
|
|
{
|
|
return empty_reduction_variable();
|
|
}
|
|
|
|
template <class BR, class E>
|
|
auto merge(const BR& block_result, bool first, E& result, empty_reduction_variable&) const
|
|
{
|
|
if (first)
|
|
{
|
|
xt::noalias(result) = block_result;
|
|
}
|
|
else
|
|
{
|
|
xt::noalias(result) += block_result;
|
|
}
|
|
}
|
|
|
|
template <class E, class R>
|
|
void finalize(const empty_reduction_variable&, E& results, const R& reducer) const
|
|
{
|
|
const auto& axes = reducer.axes();
|
|
std::decay_t<decltype(reducer.input_shape()[0])> factor = 1;
|
|
for (auto a : axes)
|
|
{
|
|
factor *= reducer.input_shape()[a];
|
|
}
|
|
xt::noalias(results) /= static_cast<typename E::value_type>(factor);
|
|
}
|
|
};
|
|
|
|
template <class T_E, class T_I = void>
|
|
struct variance_functor
|
|
{
|
|
using value_type = typename std::decay_t<decltype(xt::variance<T_I>(std::declval<xarray<T_E>>())
|
|
)>::value_type;
|
|
|
|
template <class E, class A, class O>
|
|
auto compute(const E& input, const A& axes, const O& options) const
|
|
{
|
|
double weight = 1.0;
|
|
for (auto a : axes)
|
|
{
|
|
weight *= static_cast<double>(input.shape()[a]);
|
|
}
|
|
|
|
|
|
return std::make_tuple(
|
|
xt::variance<value_type>(input, axes, options),
|
|
xt::mean<value_type>(input, axes, options),
|
|
weight
|
|
);
|
|
}
|
|
|
|
template <class E>
|
|
auto reduction_variable(const E&) const
|
|
{
|
|
return std::make_tuple(xarray<value_type>(), 0.0);
|
|
}
|
|
|
|
template <class BR, class E, class MR>
|
|
auto merge(const BR& block_result, bool first, E& variance_a, MR& mr) const
|
|
{
|
|
auto& mean_a = std::get<0>(mr);
|
|
auto& n_a = std::get<1>(mr);
|
|
|
|
const auto& variance_b = std::get<0>(block_result);
|
|
const auto& mean_b = std::get<1>(block_result);
|
|
const auto& n_b = std::get<2>(block_result);
|
|
if (first)
|
|
{
|
|
xt::noalias(variance_a) = variance_b;
|
|
xt::noalias(mean_a) = mean_b;
|
|
n_a += n_b;
|
|
}
|
|
else
|
|
{
|
|
auto new_mean = (n_a * mean_a + n_b * mean_b) / (n_a + n_b);
|
|
auto new_variance = (n_a * variance_a + n_b * variance_b
|
|
+ n_a * xt::pow(mean_a - new_mean, 2)
|
|
+ n_b * xt::pow(mean_b - new_mean, 2))
|
|
/ (n_a + n_b);
|
|
xt::noalias(variance_a) = new_variance;
|
|
xt::noalias(mean_a) = new_mean;
|
|
n_a += n_b;
|
|
}
|
|
}
|
|
|
|
template <class MR, class E, class R>
|
|
void finalize(const MR&, E&, const R&) const
|
|
{
|
|
}
|
|
};
|
|
|
|
template <class T_E, class T_I = void>
|
|
struct stddev_functor : public variance_functor<T_E, T_I>
|
|
{
|
|
template <class MR, class E, class R>
|
|
void finalize(const MR&, E& results, const R&) const
|
|
{
|
|
xt::noalias(results) = xt::sqrt(results);
|
|
}
|
|
};
|
|
|
|
template <class T_E>
|
|
struct norm_l0_functor : public simple_functor_base
|
|
{
|
|
using value_type = typename std::decay_t<decltype(xt::norm_l0(std::declval<xarray<T_E>>()))>::value_type;
|
|
|
|
template <class E, class A, class O>
|
|
auto compute(const E& input, const A& axes, const O& options) const
|
|
{
|
|
return xt::sum<value_type>(xt::not_equal(input, xt::zeros<T_E>(input.shape())), axes, options);
|
|
}
|
|
|
|
template <class BR, class E, class MR>
|
|
auto merge(const BR& block_result, bool first, E& result, MR&) const
|
|
{
|
|
if (first)
|
|
{
|
|
xt::noalias(result) = block_result;
|
|
}
|
|
else
|
|
{
|
|
xt::noalias(result) += block_result;
|
|
}
|
|
}
|
|
};
|
|
|
|
template <class T_E>
|
|
struct norm_l1_functor : public simple_functor_base
|
|
{
|
|
using value_type = typename std::decay_t<decltype(xt::norm_l1(std::declval<xarray<T_E>>()))>::value_type;
|
|
|
|
template <class E, class A, class O>
|
|
auto compute(const E& input, const A& axes, const O& options) const
|
|
{
|
|
return xt::sum<value_type>(xt::abs(input), axes, options);
|
|
}
|
|
|
|
template <class BR, class E, class MR>
|
|
auto merge(const BR& block_result, bool first, E& result, MR&) const
|
|
{
|
|
if (first)
|
|
{
|
|
xt::noalias(result) = block_result;
|
|
}
|
|
else
|
|
{
|
|
xt::noalias(result) += block_result;
|
|
}
|
|
}
|
|
};
|
|
|
|
template <class T_E>
|
|
struct norm_l2_functor
|
|
{
|
|
using value_type = typename std::decay_t<decltype(xt::norm_l2(std::declval<xarray<T_E>>()))>::value_type;
|
|
|
|
template <class E, class A, class O>
|
|
auto compute(const E& input, const A& axes, const O& options) const
|
|
{
|
|
return xt::sum<value_type>(xt::square(input), axes, options);
|
|
}
|
|
|
|
template <class E>
|
|
auto reduction_variable(const E&) const
|
|
{
|
|
return empty_reduction_variable();
|
|
}
|
|
|
|
template <class BR, class E>
|
|
auto merge(const BR& block_result, bool first, E& result, empty_reduction_variable&) const
|
|
{
|
|
if (first)
|
|
{
|
|
xt::noalias(result) = block_result;
|
|
}
|
|
else
|
|
{
|
|
xt::noalias(result) += block_result;
|
|
}
|
|
}
|
|
|
|
template <class E, class R>
|
|
void finalize(const empty_reduction_variable&, E& results, const R&) const
|
|
{
|
|
xt::noalias(results) = xt::sqrt(results);
|
|
}
|
|
};
|
|
|
|
template <class T_E>
|
|
struct norm_sq_functor : public simple_functor_base
|
|
{
|
|
using value_type = typename std::decay_t<decltype(xt::norm_sq(std::declval<xarray<T_E>>()))>::value_type;
|
|
|
|
template <class E, class A, class O>
|
|
auto compute(const E& input, const A& axes, const O& options) const
|
|
{
|
|
return xt::sum<value_type>(xt::square(input), axes, options);
|
|
}
|
|
|
|
template <class BR, class E, class MR>
|
|
auto merge(const BR& block_result, bool first, E& result, MR&) const
|
|
{
|
|
if (first)
|
|
{
|
|
xt::noalias(result) = block_result;
|
|
}
|
|
else
|
|
{
|
|
xt::noalias(result) += block_result;
|
|
}
|
|
}
|
|
};
|
|
|
|
template <class T_E>
|
|
struct norm_linf_functor : public simple_functor_base
|
|
{
|
|
using value_type = typename std::decay_t<decltype(xt::norm_linf(std::declval<xarray<T_E>>()))>::value_type;
|
|
|
|
template <class E, class A, class O>
|
|
auto compute(const E& input, const A& axes, const O& options) const
|
|
{
|
|
return xt::amax<value_type>(xt::abs(input), axes, options);
|
|
}
|
|
|
|
template <class BR, class E, class MR>
|
|
auto merge(const BR& block_result, bool first, E& result, MR&) const
|
|
{
|
|
if (first)
|
|
{
|
|
xt::noalias(result) = block_result;
|
|
}
|
|
else
|
|
{
|
|
xt::noalias(result) = xt::maximum(block_result, result);
|
|
}
|
|
}
|
|
};
|
|
|
|
template <class T_E>
|
|
class norm_lp_to_p_functor
|
|
{
|
|
public:
|
|
|
|
using value_type = typename std::decay_t<
|
|
decltype(xt::norm_lp_to_p(std::declval<xarray<T_E>>(), 1.0))>::value_type;
|
|
|
|
norm_lp_to_p_functor(double p)
|
|
: m_p(p)
|
|
{
|
|
}
|
|
|
|
template <class E, class A, class O>
|
|
auto compute(const E& input, const A& axes, const O& options) const
|
|
{
|
|
return xt::sum<value_type>(xt::pow(input, m_p), axes, options);
|
|
}
|
|
|
|
template <class E>
|
|
auto reduction_variable(const E&) const
|
|
{
|
|
return empty_reduction_variable();
|
|
}
|
|
|
|
template <class BR, class E>
|
|
auto merge(const BR& block_result, bool first, E& result, empty_reduction_variable&) const
|
|
{
|
|
if (first)
|
|
{
|
|
xt::noalias(result) = block_result;
|
|
}
|
|
else
|
|
{
|
|
xt::noalias(result) += block_result;
|
|
}
|
|
}
|
|
|
|
template <class E, class R>
|
|
void finalize(const empty_reduction_variable&, E&, const R&) const
|
|
{
|
|
}
|
|
|
|
private:
|
|
|
|
double m_p;
|
|
};
|
|
|
|
template <class T_E>
|
|
class norm_lp_functor
|
|
{
|
|
public:
|
|
|
|
norm_lp_functor(double p)
|
|
: m_p(p)
|
|
{
|
|
}
|
|
|
|
using value_type = typename std::decay_t<decltype(xt::norm_lp(std::declval<xarray<T_E>>(), 1.0)
|
|
)>::value_type;
|
|
|
|
template <class E, class A, class O>
|
|
auto compute(const E& input, const A& axes, const O& options) const
|
|
{
|
|
return xt::sum<value_type>(xt::pow(input, m_p), axes, options);
|
|
}
|
|
|
|
template <class E>
|
|
auto reduction_variable(const E&) const
|
|
{
|
|
return empty_reduction_variable();
|
|
}
|
|
|
|
template <class BR, class E>
|
|
auto merge(const BR& block_result, bool first, E& result, empty_reduction_variable&) const
|
|
{
|
|
if (first)
|
|
{
|
|
xt::noalias(result) = block_result;
|
|
}
|
|
else
|
|
{
|
|
xt::noalias(result) += block_result;
|
|
}
|
|
}
|
|
|
|
template <class E, class R>
|
|
void finalize(const empty_reduction_variable&, E& results, const R&) const
|
|
{
|
|
results = xt::pow(results, 1.0 / m_p);
|
|
}
|
|
|
|
private:
|
|
|
|
double m_p;
|
|
};
|
|
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|