mirror of
				https://github.com/pocketpy/pocketpy
				synced 2025-10-30 16:30:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			3330 lines
		
	
	
		
			121 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			3330 lines
		
	
	
		
			121 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /***************************************************************************
 | |
|  * 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. *
 | |
|  ****************************************************************************/
 | |
| 
 | |
| /**
 | |
|  * @brief standard mathematical functions for xexpressions
 | |
|  */
 | |
| 
 | |
| #ifndef XTENSOR_MATH_HPP
 | |
| #define XTENSOR_MATH_HPP
 | |
| 
 | |
| #include <algorithm>
 | |
| #include <array>
 | |
| #include <cmath>
 | |
| #include <complex>
 | |
| #include <type_traits>
 | |
| 
 | |
| #include <xtl/xcomplex.hpp>
 | |
| #include <xtl/xsequence.hpp>
 | |
| #include <xtl/xtype_traits.hpp>
 | |
| 
 | |
| #include "xaccumulator.hpp"
 | |
| #include "xeval.hpp"
 | |
| #include "xmanipulation.hpp"
 | |
| #include "xoperation.hpp"
 | |
| #include "xreducer.hpp"
 | |
| #include "xslice.hpp"
 | |
| #include "xstrided_view.hpp"
 | |
| #include "xtensor_config.hpp"
 | |
| 
 | |
| namespace xt
 | |
| {
 | |
|     template <class T = double>
 | |
|     struct numeric_constants
 | |
|     {
 | |
|         static constexpr T PI = 3.141592653589793238463;
 | |
|         static constexpr T PI_2 = 1.57079632679489661923;
 | |
|         static constexpr T PI_4 = 0.785398163397448309616;
 | |
|         static constexpr T D_1_PI = 0.318309886183790671538;
 | |
|         static constexpr T D_2_PI = 0.636619772367581343076;
 | |
|         static constexpr T D_2_SQRTPI = 1.12837916709551257390;
 | |
|         static constexpr T SQRT2 = 1.41421356237309504880;
 | |
|         static constexpr T SQRT1_2 = 0.707106781186547524401;
 | |
|         static constexpr T E = 2.71828182845904523536;
 | |
|         static constexpr T LOG2E = 1.44269504088896340736;
 | |
|         static constexpr T LOG10E = 0.434294481903251827651;
 | |
|         static constexpr T LN2 = 0.693147180559945309417;
 | |
|     };
 | |
| 
 | |
|     /***********
 | |
|      * Helpers *
 | |
|      ***********/
 | |
| 
 | |
| #define XTENSOR_UNSIGNED_ABS_FUNC(T)   \
 | |
|     constexpr inline T abs(const T& x) \
 | |
|     {                                  \
 | |
|         return x;                      \
 | |
|     }
 | |
| 
 | |
| #define XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, T) \
 | |
|     constexpr inline bool FUNC_NAME(const T& /*x*/) noexcept      \
 | |
|     {                                                             \
 | |
|         return RETURN_VAL;                                        \
 | |
|     }
 | |
| 
 | |
| #define XTENSOR_INT_SPECIALIZATION(FUNC_NAME, RETURN_VAL)                   \
 | |
|     XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, char);           \
 | |
|     XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, short);          \
 | |
|     XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, int);            \
 | |
|     XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, long);           \
 | |
|     XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, long long);      \
 | |
|     XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned char);  \
 | |
|     XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned short); \
 | |
|     XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned int);   \
 | |
|     XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned long);  \
 | |
|     XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned long long);
 | |
| 
 | |
| 
 | |
| #define XTENSOR_UNARY_MATH_FUNCTOR(NAME)              \
 | |
|     struct NAME##_fun                                 \
 | |
|     {                                                 \
 | |
|         template <class T>                            \
 | |
|         constexpr auto operator()(const T& arg) const \
 | |
|         {                                             \
 | |
|             using math::NAME;                         \
 | |
|             return NAME(arg);                         \
 | |
|         }                                             \
 | |
|         template <class B>                            \
 | |
|         constexpr auto simd_apply(const B& arg) const \
 | |
|         {                                             \
 | |
|             using math::NAME;                         \
 | |
|             return NAME(arg);                         \
 | |
|         }                                             \
 | |
|     }
 | |
| 
 | |
| #define XTENSOR_UNARY_MATH_FUNCTOR_COMPLEX_REDUCING(NAME) \
 | |
|     struct NAME##_fun                                     \
 | |
|     {                                                     \
 | |
|         template <class T>                                \
 | |
|         constexpr auto operator()(const T& arg) const     \
 | |
|         {                                                 \
 | |
|             using math::NAME;                             \
 | |
|             return NAME(arg);                             \
 | |
|         }                                                 \
 | |
|         template <class B>                                \
 | |
|         constexpr auto simd_apply(const B& arg) const     \
 | |
|         {                                                 \
 | |
|             using math::NAME;                             \
 | |
|             return NAME(arg);                             \
 | |
|         }                                                 \
 | |
|     }
 | |
| 
 | |
| #define XTENSOR_BINARY_MATH_FUNCTOR(NAME)                               \
 | |
|     struct NAME##_fun                                                   \
 | |
|     {                                                                   \
 | |
|         template <class T1, class T2>                                   \
 | |
|         constexpr auto operator()(const T1& arg1, const T2& arg2) const \
 | |
|         {                                                               \
 | |
|             using math::NAME;                                           \
 | |
|             return NAME(arg1, arg2);                                    \
 | |
|         }                                                               \
 | |
|         template <class B>                                              \
 | |
|         constexpr auto simd_apply(const B& arg1, const B& arg2) const   \
 | |
|         {                                                               \
 | |
|             using math::NAME;                                           \
 | |
|             return NAME(arg1, arg2);                                    \
 | |
|         }                                                               \
 | |
|     }
 | |
| 
 | |
| #define XTENSOR_TERNARY_MATH_FUNCTOR(NAME)                                              \
 | |
|     struct NAME##_fun                                                                   \
 | |
|     {                                                                                   \
 | |
|         template <class T1, class T2, class T3>                                         \
 | |
|         constexpr auto operator()(const T1& arg1, const T2& arg2, const T3& arg3) const \
 | |
|         {                                                                               \
 | |
|             using math::NAME;                                                           \
 | |
|             return NAME(arg1, arg2, arg3);                                              \
 | |
|         }                                                                               \
 | |
|         template <class B>                                                              \
 | |
|         auto simd_apply(const B& arg1, const B& arg2, const B& arg3) const              \
 | |
|         {                                                                               \
 | |
|             using math::NAME;                                                           \
 | |
|             return NAME(arg1, arg2, arg3);                                              \
 | |
|         }                                                                               \
 | |
|     }
 | |
| 
 | |
|     namespace math
 | |
|     {
 | |
|         using std::abs;
 | |
|         using std::fabs;
 | |
| 
 | |
|         using std::acos;
 | |
|         using std::asin;
 | |
|         using std::atan;
 | |
|         using std::cos;
 | |
|         using std::sin;
 | |
|         using std::tan;
 | |
| 
 | |
|         using std::acosh;
 | |
|         using std::asinh;
 | |
|         using std::atanh;
 | |
|         using std::cosh;
 | |
|         using std::sinh;
 | |
|         using std::tanh;
 | |
| 
 | |
|         using std::cbrt;
 | |
|         using std::sqrt;
 | |
| 
 | |
|         using std::exp;
 | |
|         using std::exp2;
 | |
|         using std::expm1;
 | |
|         using std::ilogb;
 | |
|         using std::log;
 | |
|         using std::log10;
 | |
|         using std::log1p;
 | |
|         using std::log2;
 | |
|         using std::logb;
 | |
| 
 | |
|         using std::ceil;
 | |
|         using std::floor;
 | |
|         using std::llround;
 | |
|         using std::lround;
 | |
|         using std::nearbyint;
 | |
|         using std::remainder;
 | |
|         using std::rint;
 | |
|         using std::round;
 | |
|         using std::trunc;
 | |
| 
 | |
|         using std::erf;
 | |
|         using std::erfc;
 | |
|         using std::lgamma;
 | |
|         using std::tgamma;
 | |
| 
 | |
|         using std::arg;
 | |
|         using std::conj;
 | |
|         using std::imag;
 | |
|         using std::real;
 | |
| 
 | |
|         using std::atan2;
 | |
| 
 | |
| // copysign is not in the std namespace for MSVC
 | |
| #if !defined(_MSC_VER)
 | |
|         using std::copysign;
 | |
| #endif
 | |
|         using std::fdim;
 | |
|         using std::fmax;
 | |
|         using std::fmin;
 | |
|         using std::fmod;
 | |
|         using std::hypot;
 | |
|         using std::pow;
 | |
| 
 | |
|         using std::fma;
 | |
|         using std::fpclassify;
 | |
| 
 | |
|         // Overload isinf, isnan and isfinite because glibc implementation
 | |
|         // might return int instead of bool and the SIMD detection requires
 | |
|         // bool return type.
 | |
|         template <class T>
 | |
|         inline std::enable_if_t<xtl::is_arithmetic<T>::value, bool> isinf(const T& t)
 | |
|         {
 | |
|             return bool(std::isinf(t));
 | |
|         }
 | |
| 
 | |
|         template <class T>
 | |
|         inline std::enable_if_t<xtl::is_arithmetic<T>::value, bool> isnan(const T& t)
 | |
|         {
 | |
|             return bool(std::isnan(t));
 | |
|         }
 | |
| 
 | |
|         template <class T>
 | |
|         inline std::enable_if_t<xtl::is_arithmetic<T>::value, bool> isfinite(const T& t)
 | |
|         {
 | |
|             return bool(std::isfinite(t));
 | |
|         }
 | |
| 
 | |
|         // Overload isinf, isnan and isfinite for complex datatypes,
 | |
|         // following the Python specification:
 | |
|         template <class T>
 | |
|         inline bool isinf(const std::complex<T>& c)
 | |
|         {
 | |
|             return std::isinf(std::real(c)) || std::isinf(std::imag(c));
 | |
|         }
 | |
| 
 | |
|         template <class T>
 | |
|         inline bool isnan(const std::complex<T>& c)
 | |
|         {
 | |
|             return std::isnan(std::real(c)) || std::isnan(std::imag(c));
 | |
|         }
 | |
| 
 | |
|         template <class T>
 | |
|         inline bool isfinite(const std::complex<T>& c)
 | |
|         {
 | |
|             return !isinf(c) && !isnan(c);
 | |
|         }
 | |
| 
 | |
|         // VS2015 STL defines isnan, isinf and isfinite as template
 | |
|         // functions, breaking ADL.
 | |
| #if defined(_WIN32) && defined(XTENSOR_USE_XSIMD)
 | |
|         /*template <class T, class A>
 | |
|         inline xsimd::batch_bool<T, A> isinf(const xsimd::batch<T, A>& b)
 | |
|         {
 | |
|             return xsimd::isinf(b);
 | |
|         }
 | |
|         template <class T, class A>
 | |
|         inline xsimd::batch_bool<T, A> isnan(const xsimd::batch<T, A>& b)
 | |
|         {
 | |
|             return xsimd::isnan(b);
 | |
|         }
 | |
|         template <class T, class A>
 | |
|         inline xsimd::batch_bool<T, A> isfinite(const xsimd::batch<T, A>& b)
 | |
|         {
 | |
|             return xsimd::isfinite(b);
 | |
|         }*/
 | |
| #endif
 | |
|         // The following specializations are needed to avoid 'ambiguous overload' errors,
 | |
|         // whereas 'unsigned char' and 'unsigned short' are automatically converted to 'int'.
 | |
|         // we're still adding those functions to silence warnings
 | |
|         XTENSOR_UNSIGNED_ABS_FUNC(unsigned char)
 | |
|         XTENSOR_UNSIGNED_ABS_FUNC(unsigned short)
 | |
|         XTENSOR_UNSIGNED_ABS_FUNC(unsigned int)
 | |
|         XTENSOR_UNSIGNED_ABS_FUNC(unsigned long)
 | |
|         XTENSOR_UNSIGNED_ABS_FUNC(unsigned long long)
 | |
| 
 | |
| #ifdef _WIN32
 | |
|         XTENSOR_INT_SPECIALIZATION(isinf, false);
 | |
|         XTENSOR_INT_SPECIALIZATION(isnan, false);
 | |
|         XTENSOR_INT_SPECIALIZATION(isfinite, true);
 | |
| #endif
 | |
| 
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR_COMPLEX_REDUCING(abs);
 | |
| 
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(fabs);
 | |
|         XTENSOR_BINARY_MATH_FUNCTOR(fmod);
 | |
|         XTENSOR_BINARY_MATH_FUNCTOR(remainder);
 | |
|         XTENSOR_TERNARY_MATH_FUNCTOR(fma);
 | |
|         XTENSOR_BINARY_MATH_FUNCTOR(fmax);
 | |
|         XTENSOR_BINARY_MATH_FUNCTOR(fmin);
 | |
|         XTENSOR_BINARY_MATH_FUNCTOR(fdim);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(exp);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(exp2);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(expm1);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(log);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(log10);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(log2);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(log1p);
 | |
|         XTENSOR_BINARY_MATH_FUNCTOR(pow);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(sqrt);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(cbrt);
 | |
|         XTENSOR_BINARY_MATH_FUNCTOR(hypot);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(sin);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(cos);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(tan);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(asin);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(acos);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(atan);
 | |
|         XTENSOR_BINARY_MATH_FUNCTOR(atan2);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(sinh);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(cosh);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(tanh);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(asinh);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(acosh);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(atanh);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(erf);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(erfc);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(tgamma);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(lgamma);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(ceil);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(floor);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(trunc);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(round);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(nearbyint);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(rint);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(isfinite);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(isinf);
 | |
|         XTENSOR_UNARY_MATH_FUNCTOR(isnan);
 | |
|     }
 | |
| 
 | |
| #undef XTENSOR_UNARY_MATH_FUNCTOR
 | |
| #undef XTENSOR_BINARY_MATH_FUNCTOR
 | |
| #undef XTENSOR_TERNARY_MATH_FUNCTOR
 | |
| #undef XTENSOR_UNARY_MATH_FUNCTOR_COMPLEX_REDUCING
 | |
| #undef XTENSOR_UNSIGNED_ABS_FUNC
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <class R, class T>
 | |
|         std::enable_if_t<!has_iterator_interface<R>::value, R> fill_init(T init)
 | |
|         {
 | |
|             return R(init);
 | |
|         }
 | |
| 
 | |
|         template <class R, class T>
 | |
|         std::enable_if_t<has_iterator_interface<R>::value, R> fill_init(T init)
 | |
|         {
 | |
|             R result;
 | |
|             std::fill(std::begin(result), std::end(result), init);
 | |
|             return result;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| #define XTENSOR_REDUCER_FUNCTION(NAME, FUNCTOR, INIT_VALUE_TYPE, INIT)                                               \
 | |
|     template <                                                                                                       \
 | |
|         class T = void,                                                                                              \
 | |
|         class E,                                                                                                     \
 | |
|         class X,                                                                                                     \
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,                                                                       \
 | |
|         XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::negation<xtl::is_integral<std::decay_t<X>>>)>        \
 | |
|     inline auto NAME(E&& e, X&& axes, EVS es = EVS())                                                                \
 | |
|     {                                                                                                                \
 | |
|         using init_value_type = std::conditional_t<std::is_same<T, void>::value, INIT_VALUE_TYPE, T>;                \
 | |
|         using functor_type = FUNCTOR;                                                                                \
 | |
|         using init_value_fct = xt::const_value<init_value_type>;                                                     \
 | |
|         return xt::reduce(                                                                                           \
 | |
|             make_xreducer_functor(functor_type(), init_value_fct(detail::fill_init<init_value_type>(INIT))),         \
 | |
|             std::forward<E>(e),                                                                                      \
 | |
|             std::forward<X>(axes),                                                                                   \
 | |
|             es                                                                                                       \
 | |
|         );                                                                                                           \
 | |
|     }                                                                                                                \
 | |
|                                                                                                                      \
 | |
|     template <                                                                                                       \
 | |
|         class T = void,                                                                                              \
 | |
|         class E,                                                                                                     \
 | |
|         class X,                                                                                                     \
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,                                                                       \
 | |
|         XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::is_integral<std::decay_t<X>>)>                       \
 | |
|     inline auto NAME(E&& e, X axis, EVS es = EVS())                                                                  \
 | |
|     {                                                                                                                \
 | |
|         return NAME(std::forward<E>(e), {axis}, es);                                                                 \
 | |
|     }                                                                                                                \
 | |
|                                                                                                                      \
 | |
|     template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)> \
 | |
|     inline auto NAME(E&& e, EVS es = EVS())                                                                          \
 | |
|     {                                                                                                                \
 | |
|         using init_value_type = std::conditional_t<std::is_same<T, void>::value, INIT_VALUE_TYPE, T>;                \
 | |
|         using functor_type = FUNCTOR;                                                                                \
 | |
|         using init_value_fct = xt::const_value<init_value_type>;                                                     \
 | |
|         return xt::reduce(                                                                                           \
 | |
|             make_xreducer_functor(functor_type(), init_value_fct(detail::fill_init<init_value_type>(INIT))),         \
 | |
|             std::forward<E>(e),                                                                                      \
 | |
|             es                                                                                                       \
 | |
|         );                                                                                                           \
 | |
|     }                                                                                                                \
 | |
|                                                                                                                      \
 | |
|     template <class T = void, class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>                \
 | |
|     inline auto NAME(E&& e, const I(&axes)[N], EVS es = EVS())                                                       \
 | |
|     {                                                                                                                \
 | |
|         using init_value_type = std::conditional_t<std::is_same<T, void>::value, INIT_VALUE_TYPE, T>;                \
 | |
|         using functor_type = FUNCTOR;                                                                                \
 | |
|         using init_value_fct = xt::const_value<init_value_type>;                                                     \
 | |
|         return xt::reduce(                                                                                           \
 | |
|             make_xreducer_functor(functor_type(), init_value_fct(detail::fill_init<init_value_type>(INIT))),         \
 | |
|             std::forward<E>(e),                                                                                      \
 | |
|             axes,                                                                                                    \
 | |
|             es                                                                                                       \
 | |
|         );                                                                                                           \
 | |
|     }
 | |
| 
 | |
|     /*******************
 | |
|      * basic functions *
 | |
|      *******************/
 | |
| 
 | |
|     /**
 | |
|      * @defgroup basic_functions Basic functions
 | |
|      */
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Absolute value function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise absolute value
 | |
|      * of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto abs(E&& e) noexcept -> detail::xfunction_type_t<math::abs_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::abs_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Absolute value function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise absolute value
 | |
|      * of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto fabs(E&& e) noexcept -> detail::xfunction_type_t<math::fabs_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::fabs_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Remainder of the floating point division operation.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise remainder of
 | |
|      * the floating point division operation <em>e1 / e2</em>.
 | |
|      * @param e1 an \ref xexpression or a scalar
 | |
|      * @param e2 an \ref xexpression or a scalar
 | |
|      * @return an \ref xfunction
 | |
|      * @note e1 and e2 can't be both scalars.
 | |
|      */
 | |
|     template <class E1, class E2>
 | |
|     inline auto fmod(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::fmod_fun, E1, E2>
 | |
|     {
 | |
|         return detail::make_xfunction<math::fmod_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Signed remainder of the division operation.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise signed remainder
 | |
|      * of the floating point division operation <em>e1 / e2</em>.
 | |
|      * @param e1 an \ref xexpression or a scalar
 | |
|      * @param e2 an \ref xexpression or a scalar
 | |
|      * @return an \ref xfunction
 | |
|      * @note e1 and e2 can't be both scalars.
 | |
|      */
 | |
|     template <class E1, class E2>
 | |
|     inline auto remainder(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::remainder_fun, E1, E2>
 | |
|     {
 | |
|         return detail::make_xfunction<math::remainder_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Fused multiply-add operation.
 | |
|      *
 | |
|      * Returns an \ref xfunction for <em>e1 * e2 + e3</em> as if
 | |
|      * to infinite precision and rounded only once to fit the result type.
 | |
|      * @param e1 an \ref xfunction or a scalar
 | |
|      * @param e2 an \ref xfunction or a scalar
 | |
|      * @param e3 an \ref xfunction or a scalar
 | |
|      * @return an \ref xfunction
 | |
|      * @note e1, e2 and e3 can't be scalars every three.
 | |
|      */
 | |
|     template <class E1, class E2, class E3>
 | |
|     inline auto fma(E1&& e1, E2&& e2, E3&& e3) noexcept -> detail::xfunction_type_t<math::fma_fun, E1, E2, E3>
 | |
|     {
 | |
|         return detail::make_xfunction<math::fma_fun>(
 | |
|             std::forward<E1>(e1),
 | |
|             std::forward<E2>(e2),
 | |
|             std::forward<E3>(e3)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Maximum function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise maximum
 | |
|      * of \a e1 and \a e2.
 | |
|      * @param e1 an \ref xexpression or a scalar
 | |
|      * @param e2 an \ref xexpression or a scalar
 | |
|      * @return an \ref xfunction
 | |
|      * @note e1 and e2 can't be both scalars.
 | |
|      */
 | |
|     template <class E1, class E2>
 | |
|     inline auto fmax(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::fmax_fun, E1, E2>
 | |
|     {
 | |
|         return detail::make_xfunction<math::fmax_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Minimum function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise minimum
 | |
|      * of \a e1 and \a e2.
 | |
|      * @param e1 an \ref xexpression or a scalar
 | |
|      * @param e2 an \ref xexpression or a scalar
 | |
|      * @return an \ref xfunction
 | |
|      * @note e1 and e2 can't be both scalars.
 | |
|      */
 | |
|     template <class E1, class E2>
 | |
|     inline auto fmin(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::fmin_fun, E1, E2>
 | |
|     {
 | |
|         return detail::make_xfunction<math::fmin_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Positive difference function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise positive
 | |
|      * difference of \a e1 and \a e2.
 | |
|      * @param e1 an \ref xexpression or a scalar
 | |
|      * @param e2 an \ref xexpression or a scalar
 | |
|      * @return an \ref xfunction
 | |
|      * @note e1 and e2 can't be both scalars.
 | |
|      */
 | |
|     template <class E1, class E2>
 | |
|     inline auto fdim(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::fdim_fun, E1, E2>
 | |
|     {
 | |
|         return detail::make_xfunction<math::fdim_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
 | |
|     }
 | |
| 
 | |
|     namespace math
 | |
|     {
 | |
|         template <class T = void>
 | |
|         struct minimum
 | |
|         {
 | |
|             template <class A1, class A2>
 | |
|             constexpr auto operator()(const A1& t1, const A2& t2) const noexcept
 | |
|             {
 | |
|                 return xtl::select(t1 < t2, t1, t2);
 | |
|             }
 | |
| 
 | |
|             template <class A1, class A2>
 | |
|             constexpr auto simd_apply(const A1& t1, const A2& t2) const noexcept
 | |
|             {
 | |
|                 return xt_simd::select(t1 < t2, t1, t2);
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         template <class T = void>
 | |
|         struct maximum
 | |
|         {
 | |
|             template <class A1, class A2>
 | |
|             constexpr auto operator()(const A1& t1, const A2& t2) const noexcept
 | |
|             {
 | |
|                 return xtl::select(t1 > t2, t1, t2);
 | |
|             }
 | |
| 
 | |
|             template <class A1, class A2>
 | |
|             constexpr auto simd_apply(const A1& t1, const A2& t2) const noexcept
 | |
|             {
 | |
|                 return xt_simd::select(t1 > t2, t1, t2);
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         struct clamp_fun
 | |
|         {
 | |
|             template <class A1, class A2, class A3>
 | |
|             constexpr auto operator()(const A1& v, const A2& lo, const A3& hi) const
 | |
|             {
 | |
|                 return xtl::select(v < lo, lo, xtl::select(hi < v, hi, v));
 | |
|             }
 | |
| 
 | |
|             template <class A1, class A2, class A3>
 | |
|             constexpr auto simd_apply(const A1& v, const A2& lo, const A3& hi) const
 | |
|             {
 | |
|                 return xt_simd::select(v < lo, lo, xt_simd::select(hi < v, hi, v));
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         struct deg2rad
 | |
|         {
 | |
|             template <class A, std::enable_if_t<xtl::is_integral<A>::value, int> = 0>
 | |
|             constexpr double operator()(const A& a) const noexcept
 | |
|             {
 | |
|                 return a * xt::numeric_constants<double>::PI / 180.0;
 | |
|             }
 | |
| 
 | |
|             template <class A, std::enable_if_t<std::is_floating_point<A>::value, int> = 0>
 | |
|             constexpr auto operator()(const A& a) const noexcept
 | |
|             {
 | |
|                 return a * xt::numeric_constants<A>::PI / A(180.0);
 | |
|             }
 | |
| 
 | |
|             template <class A, std::enable_if_t<xtl::is_integral<A>::value, int> = 0>
 | |
|             constexpr double simd_apply(const A& a) const noexcept
 | |
|             {
 | |
|                 return a * xt::numeric_constants<double>::PI / 180.0;
 | |
|             }
 | |
| 
 | |
|             template <class A, std::enable_if_t<std::is_floating_point<A>::value, int> = 0>
 | |
|             constexpr auto simd_apply(const A& a) const noexcept
 | |
|             {
 | |
|                 return a * xt::numeric_constants<A>::PI / A(180.0);
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         struct rad2deg
 | |
|         {
 | |
|             template <class A, std::enable_if_t<xtl::is_integral<A>::value, int> = 0>
 | |
|             constexpr double operator()(const A& a) const noexcept
 | |
|             {
 | |
|                 return a * 180.0 / xt::numeric_constants<double>::PI;
 | |
|             }
 | |
| 
 | |
|             template <class A, std::enable_if_t<std::is_floating_point<A>::value, int> = 0>
 | |
|             constexpr auto operator()(const A& a) const noexcept
 | |
|             {
 | |
|                 return a * A(180.0) / xt::numeric_constants<A>::PI;
 | |
|             }
 | |
| 
 | |
|             template <class A, std::enable_if_t<xtl::is_integral<A>::value, int> = 0>
 | |
|             constexpr double simd_apply(const A& a) const noexcept
 | |
|             {
 | |
|                 return a * 180.0 / xt::numeric_constants<double>::PI;
 | |
|             }
 | |
| 
 | |
|             template <class A, std::enable_if_t<std::is_floating_point<A>::value, int> = 0>
 | |
|             constexpr auto simd_apply(const A& a) const noexcept
 | |
|             {
 | |
|                 return a * A(180.0) / xt::numeric_constants<A>::PI;
 | |
|             }
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Convert angles from degrees to radians.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise corresponding
 | |
|      * angle in radians of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto deg2rad(E&& e) noexcept -> detail::xfunction_type_t<math::deg2rad, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::deg2rad>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Convert angles from degrees to radians.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise corresponding
 | |
|      * angle in radians of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto radians(E&& e) noexcept -> detail::xfunction_type_t<math::deg2rad, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::deg2rad>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Convert angles from radians to degrees.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise corresponding
 | |
|      * angle in degrees of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto rad2deg(E&& e) noexcept -> detail::xfunction_type_t<math::rad2deg, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::rad2deg>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Convert angles from radians to degrees.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise corresponding
 | |
|      * angle in degrees of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto degrees(E&& e) noexcept -> detail::xfunction_type_t<math::rad2deg, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::rad2deg>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Elementwise maximum
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise
 | |
|      * maximum between e1 and e2.
 | |
|      * @param e1 an \ref xexpression
 | |
|      * @param e2 an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E1, class E2>
 | |
|     inline auto maximum(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::maximum<void>, E1, E2>
 | |
|     {
 | |
|         return detail::make_xfunction<math::maximum<void>>(std::forward<E1>(e1), std::forward<E2>(e2));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Elementwise minimum
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise
 | |
|      * minimum between e1 and e2.
 | |
|      * @param e1 an \ref xexpression
 | |
|      * @param e2 an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E1, class E2>
 | |
|     inline auto minimum(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::minimum<void>, E1, E2>
 | |
|     {
 | |
|         return detail::make_xfunction<math::minimum<void>>(std::forward<E1>(e1), std::forward<E2>(e2));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Maximum element along given axis.
 | |
|      *
 | |
|      * Returns an \ref xreducer for the maximum of elements over given
 | |
|      * \em axes.
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axes the axes along which the maximum is found (optional)
 | |
|      * @param es evaluation strategy of the reducer
 | |
|      * @return an \ref xreducer
 | |
|      */
 | |
|     XTENSOR_REDUCER_FUNCTION(
 | |
|         amax,
 | |
|         math::maximum<void>,
 | |
|         typename std::decay_t<E>::value_type,
 | |
|         std::numeric_limits<xvalue_type_t<std::decay_t<E>>>::lowest()
 | |
|     )
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Minimum element along given axis.
 | |
|      *
 | |
|      * Returns an \ref xreducer for the minimum of elements over given
 | |
|      * \em axes.
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axes the axes along which the minimum is found (optional)
 | |
|      * @param es evaluation strategy of the reducer
 | |
|      * @return an \ref xreducer
 | |
|      */
 | |
|     XTENSOR_REDUCER_FUNCTION(
 | |
|         amin,
 | |
|         math::minimum<void>,
 | |
|         typename std::decay_t<E>::value_type,
 | |
|         std::numeric_limits<xvalue_type_t<std::decay_t<E>>>::max()
 | |
|     )
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Clip values between hi and lo
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise clipped
 | |
|      * values between lo and hi
 | |
|      * @param e1 an \ref xexpression or a scalar
 | |
|      * @param lo a scalar
 | |
|      * @param hi a scalar
 | |
|      *
 | |
|      * @return a \ref xfunction
 | |
|      */
 | |
|     template <class E1, class E2, class E3>
 | |
|     inline auto clip(E1&& e1, E2&& lo, E3&& hi) noexcept
 | |
|         -> detail::xfunction_type_t<math::clamp_fun, E1, E2, E3>
 | |
|     {
 | |
|         return detail::make_xfunction<math::clamp_fun>(
 | |
|             std::forward<E1>(e1),
 | |
|             std::forward<E2>(lo),
 | |
|             std::forward<E3>(hi)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     namespace math
 | |
|     {
 | |
|         template <class T>
 | |
|         struct sign_impl
 | |
|         {
 | |
|             template <class XT = T>
 | |
|             static constexpr std::enable_if_t<xtl::is_signed<XT>::value, T> run(T x)
 | |
|             {
 | |
|                 return std::isnan(x) ? std::numeric_limits<T>::quiet_NaN()
 | |
|                        : x == 0      ? T(copysign(T(0), x))
 | |
|                                      : T(copysign(T(1), x));
 | |
|             }
 | |
| 
 | |
|             template <class XT = T>
 | |
|             static constexpr std::enable_if_t<xtl::is_complex<XT>::value, T> run(T x)
 | |
|             {
 | |
|                 return T(
 | |
|                     sign_impl<typename T::value_type>::run(
 | |
|                         (x.real() != typename T::value_type(0)) ? x.real() : x.imag()
 | |
|                     ),
 | |
|                     0
 | |
|                 );
 | |
|             }
 | |
| 
 | |
|             template <class XT = T>
 | |
|             static constexpr std::enable_if_t<std::is_unsigned<XT>::value, T> run(T x)
 | |
|             {
 | |
|                 return T(x > T(0));
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         struct sign_fun
 | |
|         {
 | |
|             template <class T>
 | |
|             constexpr auto operator()(const T& x) const
 | |
|             {
 | |
|                 return sign_impl<T>::run(x);
 | |
|             }
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Returns an element-wise indication of the sign of a number
 | |
|      *
 | |
|      * If the number is positive, returns +1. If negative, -1. If the number
 | |
|      * is zero, returns 0.
 | |
|      *
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto sign(E&& e) noexcept -> detail::xfunction_type_t<math::sign_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::sign_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /*************************
 | |
|      * exponential functions *
 | |
|      *************************/
 | |
| 
 | |
|     /**
 | |
|      * @defgroup exp_functions Exponential functions
 | |
|      */
 | |
| 
 | |
|     /**
 | |
|      * @ingroup exp_functions
 | |
|      * @brief Natural exponential function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise natural
 | |
|      * exponential of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto exp(E&& e) noexcept -> detail::xfunction_type_t<math::exp_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::exp_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup exp_functions
 | |
|      * @brief Base 2 exponential function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise base 2
 | |
|      * exponential of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto exp2(E&& e) noexcept -> detail::xfunction_type_t<math::exp2_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::exp2_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup exp_functions
 | |
|      * @brief Natural exponential minus one function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise natural
 | |
|      * exponential of \em e, minus 1.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto expm1(E&& e) noexcept -> detail::xfunction_type_t<math::expm1_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::expm1_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup exp_functions
 | |
|      * @brief Natural logarithm function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise natural
 | |
|      * logarithm of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto log(E&& e) noexcept -> detail::xfunction_type_t<math::log_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::log_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup exp_functions
 | |
|      * @brief Base 10 logarithm function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise base 10
 | |
|      * logarithm of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto log10(E&& e) noexcept -> detail::xfunction_type_t<math::log10_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::log10_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup exp_functions
 | |
|      * @brief Base 2 logarithm function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise base 2
 | |
|      * logarithm of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto log2(E&& e) noexcept -> detail::xfunction_type_t<math::log2_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::log2_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup exp_functions
 | |
|      * @brief Natural logarithm of one plus function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise natural
 | |
|      * logarithm of \em e, plus 1.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto log1p(E&& e) noexcept -> detail::xfunction_type_t<math::log1p_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::log1p_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /*******************
 | |
|      * power functions *
 | |
|      *******************/
 | |
| 
 | |
|     /**
 | |
|      * @defgroup pow_functions Power functions
 | |
|      */
 | |
| 
 | |
|     /**
 | |
|      * @ingroup pow_functions
 | |
|      * @brief Power function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise value of
 | |
|      * of \em e1 raised to the power \em e2.
 | |
|      * @param e1 an \ref xexpression or a scalar
 | |
|      * @param e2 an \ref xexpression or a scalar
 | |
|      * @return an \ref xfunction
 | |
|      * @note e1 and e2 can't be both scalars.
 | |
|      */
 | |
|     template <class E1, class E2>
 | |
|     inline auto pow(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::pow_fun, E1, E2>
 | |
|     {
 | |
|         return detail::make_xfunction<math::pow_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
 | |
|     }
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <class F, class... T, typename = decltype(std::declval<F>()(std::declval<T>()...))>
 | |
|         std::true_type supports_test(const F&, const T&...);
 | |
|         std::false_type supports_test(...);
 | |
| 
 | |
|         template <class... T>
 | |
|         struct supports;
 | |
| 
 | |
|         template <class F, class... T>
 | |
|         struct supports<F(T...)> : decltype(supports_test(std::declval<F>(), std::declval<T>()...))
 | |
|         {
 | |
|         };
 | |
| 
 | |
|         template <class F>
 | |
|         struct lambda_adapt
 | |
|         {
 | |
|             explicit lambda_adapt(F&& lmbd)
 | |
|                 : m_lambda(std::move(lmbd))
 | |
|             {
 | |
|             }
 | |
| 
 | |
|             template <class... T>
 | |
|             auto operator()(T... args) const
 | |
|             {
 | |
|                 return m_lambda(args...);
 | |
|             }
 | |
| 
 | |
|             template <class... T, XTL_REQUIRES(detail::supports<F(T...)>)>
 | |
|             auto simd_apply(T... args) const
 | |
|             {
 | |
|                 return m_lambda(args...);
 | |
|             }
 | |
| 
 | |
|             F m_lambda;
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Create a xfunction from a lambda
 | |
|      *
 | |
|      * This function can be used to easily create performant xfunctions from lambdas:
 | |
|      *
 | |
|      * @code{cpp}
 | |
|      * template <class E1>
 | |
|      * inline auto square(E1&& e1) noexcept
 | |
|      * {
 | |
|      *     auto fnct = [](auto x) -> decltype(x * x) {
 | |
|      *         return x * x;
 | |
|      *     };
 | |
|      *     return make_lambda_xfunction(std::move(fnct), std::forward<E1>(e1));
 | |
|      * }
 | |
|      * @endcode
 | |
|      *
 | |
|      * Lambda function allow the reusal of a single arguments in multiple places (otherwise
 | |
|      * only correctly possible when using xshared_expressions). ``auto`` lambda functions are
 | |
|      * automatically vectorized with ``xsimd`` if possible (note that the trailing
 | |
|      * ``-> decltype(...)`` is mandatory for the feature detection to work).
 | |
|      *
 | |
|      * @param lambda the lambda to be vectorized
 | |
|      * @param args forwarded arguments
 | |
|      *
 | |
|      * @return lazy xfunction
 | |
|      */
 | |
|     template <class F, class... E>
 | |
|     inline auto make_lambda_xfunction(F&& lambda, E&&... args)
 | |
|     {
 | |
|         using xfunction_type = typename detail::xfunction_type<detail::lambda_adapt<F>, E...>::type;
 | |
|         return xfunction_type(detail::lambda_adapt<F>(std::forward<F>(lambda)), std::forward<E>(args)...);
 | |
|     }
 | |
| 
 | |
| #define XTENSOR_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
 | |
| 
 | |
| // Workaround for MSVC 2015 & GCC 4.9
 | |
| #if (defined(_MSC_VER) && _MSC_VER < 1910) || (defined(__GNUC__) && GCC_VERSION < 49999)
 | |
| #define XTENSOR_DISABLE_LAMBDA_FCT
 | |
| #endif
 | |
| 
 | |
| #ifdef XTENSOR_DISABLE_LAMBDA_FCT
 | |
|     struct square_fct
 | |
|     {
 | |
|         template <class T>
 | |
|         auto operator()(T x) const -> decltype(x * x)
 | |
|         {
 | |
|             return x * x;
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     struct cube_fct
 | |
|     {
 | |
|         template <class T>
 | |
|         auto operator()(T x) const -> decltype(x * x * x)
 | |
|         {
 | |
|             return x * x * x;
 | |
|         }
 | |
|     };
 | |
| #endif
 | |
| 
 | |
|     /**
 | |
|      * @ingroup pow_functions
 | |
|      * @brief Square power function, equivalent to e1 * e1.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise value of
 | |
|      * of \em e1 * \em e1.
 | |
|      * @param e1 an \ref xexpression or a scalar
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E1>
 | |
|     inline auto square(E1&& e1) noexcept
 | |
|     {
 | |
| #ifdef XTENSOR_DISABLE_LAMBDA_FCT
 | |
|         return make_lambda_xfunction(square_fct{}, std::forward<E1>(e1));
 | |
| #else
 | |
|         auto fnct = [](auto x) -> decltype(x * x)
 | |
|         {
 | |
|             return x * x;
 | |
|         };
 | |
|         return make_lambda_xfunction(std::move(fnct), std::forward<E1>(e1));
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup pow_functions
 | |
|      * @brief Cube power function, equivalent to e1 * e1 * e1.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise value of
 | |
|      * of \em e1 * \em e1.
 | |
|      * @param e1 an \ref xexpression or a scalar
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E1>
 | |
|     inline auto cube(E1&& e1) noexcept
 | |
|     {
 | |
| #ifdef XTENSOR_DISABLE_LAMBDA_FCT
 | |
|         return make_lambda_xfunction(cube_fct{}, std::forward<E1>(e1));
 | |
| #else
 | |
|         auto fnct = [](auto x) -> decltype(x * x * x)
 | |
|         {
 | |
|             return x * x * x;
 | |
|         };
 | |
|         return make_lambda_xfunction(std::move(fnct), std::forward<E1>(e1));
 | |
| #endif
 | |
|     }
 | |
| 
 | |
| #undef XTENSOR_GCC_VERSION
 | |
| #undef XTENSOR_DISABLE_LAMBDA_FCT
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         // Thanks to Matt Pharr in http://pbrt.org/hair.pdf
 | |
|         template <std::size_t N>
 | |
|         struct pow_impl;
 | |
| 
 | |
|         template <std::size_t N>
 | |
|         struct pow_impl
 | |
|         {
 | |
|             template <class T>
 | |
|             auto operator()(T v) const -> decltype(v * v)
 | |
|             {
 | |
|                 T temp = pow_impl<N / 2>{}(v);
 | |
|                 return temp * temp * pow_impl<N & 1>{}(v);
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         template <>
 | |
|         struct pow_impl<1>
 | |
|         {
 | |
|             template <class T>
 | |
|             auto operator()(T v) const -> T
 | |
|             {
 | |
|                 return v;
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         template <>
 | |
|         struct pow_impl<0>
 | |
|         {
 | |
|             template <class T>
 | |
|             auto operator()(T /*v*/) const -> T
 | |
|             {
 | |
|                 return T(1);
 | |
|             }
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup pow_functions
 | |
|      * @brief Integer power function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise power of e1 to
 | |
|      * an integral constant.
 | |
|      *
 | |
|      * Instead of computing the power by using the (expensive) logarithm, this function
 | |
|      * computes the power in a number of straight-forward multiplication steps. This function
 | |
|      * is therefore much faster (even for high N) than the generic pow-function.
 | |
|      *
 | |
|      * For example, `e1^20` can be expressed as `(((e1^2)^2)^2)^2*(e1^2)^2`, which is just 5 multiplications.
 | |
|      *
 | |
|      * @param e an \ref xexpression
 | |
|      * @tparam N the exponent (has to be positive integer)
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <std::size_t N, class E>
 | |
|     inline auto pow(E&& e) noexcept
 | |
|     {
 | |
|         static_assert(N > 0, "integer power cannot be negative");
 | |
|         return make_lambda_xfunction(detail::pow_impl<N>{}, std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup pow_functions
 | |
|      * @brief Square root function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise square
 | |
|      * root of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto sqrt(E&& e) noexcept -> detail::xfunction_type_t<math::sqrt_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::sqrt_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup pow_functions
 | |
|      * @brief Cubic root function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise cubic
 | |
|      * root of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto cbrt(E&& e) noexcept -> detail::xfunction_type_t<math::cbrt_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::cbrt_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup pow_functions
 | |
|      * @brief Hypotenuse function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise square
 | |
|      * root of the sum of the square of \em e1 and \em e2, avoiding
 | |
|      * overflow and underflow at intermediate stages of computation.
 | |
|      * @param e1 an \ref xexpression or a scalar
 | |
|      * @param e2 an \ref xexpression or a scalar
 | |
|      * @return an \ref xfunction
 | |
|      * @note e1 and e2 can't be both scalars.
 | |
|      */
 | |
|     template <class E1, class E2>
 | |
|     inline auto hypot(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::hypot_fun, E1, E2>
 | |
|     {
 | |
|         return detail::make_xfunction<math::hypot_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
 | |
|     }
 | |
| 
 | |
|     /***************************
 | |
|      * trigonometric functions *
 | |
|      ***************************/
 | |
| 
 | |
|     /**
 | |
|      * @defgroup trigo_functions Trigonometric function
 | |
|      */
 | |
| 
 | |
|     /**
 | |
|      * @ingroup trigo_functions
 | |
|      * @brief Sine function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise sine
 | |
|      * of \em e (measured in radians).
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto sin(E&& e) noexcept -> detail::xfunction_type_t<math::sin_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::sin_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup trigo_functions
 | |
|      * @brief Cosine function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise cosine
 | |
|      * of \em e (measured in radians).
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto cos(E&& e) noexcept -> detail::xfunction_type_t<math::cos_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::cos_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup trigo_functions
 | |
|      * @brief Tangent function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise tangent
 | |
|      * of \em e (measured in radians).
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto tan(E&& e) noexcept -> detail::xfunction_type_t<math::tan_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::tan_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup trigo_functions
 | |
|      * @brief Arcsine function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise arcsine
 | |
|      * of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto asin(E&& e) noexcept -> detail::xfunction_type_t<math::asin_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::asin_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup trigo_functions
 | |
|      * @brief Arccosine function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise arccosine
 | |
|      * of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto acos(E&& e) noexcept -> detail::xfunction_type_t<math::acos_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::acos_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup trigo_functions
 | |
|      * @brief Arctangent function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise arctangent
 | |
|      * of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto atan(E&& e) noexcept -> detail::xfunction_type_t<math::atan_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::atan_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup trigo_functions
 | |
|      * @brief Artangent function, using signs to determine quadrants.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise arctangent
 | |
|      * of <em>e1 / e2</em>, using the signs of arguments to determine the
 | |
|      * correct quadrant.
 | |
|      * @param e1 an \ref xexpression or a scalar
 | |
|      * @param e2 an \ref xexpression or a scalar
 | |
|      * @return an \ref xfunction
 | |
|      * @note e1 and e2 can't be both scalars.
 | |
|      */
 | |
|     template <class E1, class E2>
 | |
|     inline auto atan2(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::atan2_fun, E1, E2>
 | |
|     {
 | |
|         return detail::make_xfunction<math::atan2_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
 | |
|     }
 | |
| 
 | |
|     /************************
 | |
|      * hyperbolic functions *
 | |
|      ************************/
 | |
| 
 | |
|     /**
 | |
|      * @defgroup hyper_functions Hyperbolic functions
 | |
|      */
 | |
| 
 | |
|     /**
 | |
|      * @ingroup hyper_functions
 | |
|      * @brief Hyperbolic sine function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise hyperbolic
 | |
|      * sine of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto sinh(E&& e) noexcept -> detail::xfunction_type_t<math::sinh_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::sinh_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup hyper_functions
 | |
|      * @brief Hyperbolic cosine function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise hyperbolic
 | |
|      * cosine of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto cosh(E&& e) noexcept -> detail::xfunction_type_t<math::cosh_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::cosh_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup hyper_functions
 | |
|      * @brief Hyperbolic tangent function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise hyperbolic
 | |
|      * tangent of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto tanh(E&& e) noexcept -> detail::xfunction_type_t<math::tanh_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::tanh_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup hyper_functions
 | |
|      * @brief Inverse hyperbolic sine function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise inverse hyperbolic
 | |
|      * sine of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto asinh(E&& e) noexcept -> detail::xfunction_type_t<math::asinh_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::asinh_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup hyper_functions
 | |
|      * @brief Inverse hyperbolic cosine function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise inverse hyperbolic
 | |
|      * cosine of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto acosh(E&& e) noexcept -> detail::xfunction_type_t<math::acosh_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::acosh_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup hyper_functions
 | |
|      * @brief Inverse hyperbolic tangent function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise inverse hyperbolic
 | |
|      * tangent of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto atanh(E&& e) noexcept -> detail::xfunction_type_t<math::atanh_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::atanh_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /*****************************
 | |
|      * error and gamma functions *
 | |
|      *****************************/
 | |
| 
 | |
|     /**
 | |
|      * @defgroup err_functions Error and gamma functions
 | |
|      */
 | |
| 
 | |
|     /**
 | |
|      * @ingroup err_functions
 | |
|      * @brief Error function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise error function
 | |
|      * of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto erf(E&& e) noexcept -> detail::xfunction_type_t<math::erf_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::erf_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup err_functions
 | |
|      * @brief Complementary error function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise complementary
 | |
|      * error function of \em e, whithout loss of precision for large argument.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto erfc(E&& e) noexcept -> detail::xfunction_type_t<math::erfc_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::erfc_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup err_functions
 | |
|      * @brief Gamma function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise gamma function
 | |
|      * of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto tgamma(E&& e) noexcept -> detail::xfunction_type_t<math::tgamma_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::tgamma_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup err_functions
 | |
|      * @brief Natural logarithm of the gamma function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise logarithm of
 | |
|      * the asbolute value fo the gamma function of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto lgamma(E&& e) noexcept -> detail::xfunction_type_t<math::lgamma_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::lgamma_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /*********************************************
 | |
|      * nearest integer floating point operations *
 | |
|      *********************************************/
 | |
| 
 | |
|     /**
 | |
|      * @defgroup nearint_functions Nearest integer floating point operations
 | |
|      */
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nearint_functions
 | |
|      * @brief ceil function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise smallest integer value
 | |
|      * not less than \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto ceil(E&& e) noexcept -> detail::xfunction_type_t<math::ceil_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::ceil_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nearint_functions
 | |
|      * @brief floor function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise smallest integer value
 | |
|      * not greater than \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto floor(E&& e) noexcept -> detail::xfunction_type_t<math::floor_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::floor_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nearint_functions
 | |
|      * @brief trunc function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise nearest integer not greater
 | |
|      * in magnitude than \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto trunc(E&& e) noexcept -> detail::xfunction_type_t<math::trunc_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::trunc_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nearint_functions
 | |
|      * @brief round function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise nearest integer value
 | |
|      * to \em e, rounding halfway cases away from zero, regardless of the
 | |
|      * current rounding mode.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto round(E&& e) noexcept -> detail::xfunction_type_t<math::round_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::round_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nearint_functions
 | |
|      * @brief nearbyint function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise rounding of \em e to integer
 | |
|      * values in floating point format, using the current rounding mode. nearbyint
 | |
|      * never raises FE_INEXACT error.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto nearbyint(E&& e) noexcept -> detail::xfunction_type_t<math::nearbyint_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::nearbyint_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nearint_functions
 | |
|      * @brief rint function.
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise rounding of \em e to integer
 | |
|      * values in floating point format, using the current rounding mode. Contrary
 | |
|      * to nearbyint, rint may raise FE_INEXACT error.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto rint(E&& e) noexcept -> detail::xfunction_type_t<math::rint_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::rint_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /****************************
 | |
|      * classification functions *
 | |
|      ****************************/
 | |
| 
 | |
|     /**
 | |
|      * @defgroup classif_functions Classification functions
 | |
|      */
 | |
| 
 | |
|     /**
 | |
|      * @ingroup classif_functions
 | |
|      * @brief finite value check
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise finite value check
 | |
|      * tangent of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto isfinite(E&& e) noexcept -> detail::xfunction_type_t<math::isfinite_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::isfinite_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup classif_functions
 | |
|      * @brief infinity check
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise infinity check
 | |
|      * tangent of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto isinf(E&& e) noexcept -> detail::xfunction_type_t<math::isinf_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::isinf_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup classif_functions
 | |
|      * @brief NaN check
 | |
|      *
 | |
|      * Returns an \ref xfunction for the element-wise NaN check
 | |
|      * tangent of \em e.
 | |
|      * @param e an \ref xexpression
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto isnan(E&& e) noexcept -> detail::xfunction_type_t<math::isnan_fun, E>
 | |
|     {
 | |
|         return detail::make_xfunction<math::isnan_fun>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <class FUNCTOR, class T, std::size_t... Is>
 | |
|         inline auto get_functor(T&& args, std::index_sequence<Is...>)
 | |
|         {
 | |
|             return FUNCTOR(std::get<Is>(args)...);
 | |
|         }
 | |
| 
 | |
|         template <class F, class... A, class... E>
 | |
|         inline auto make_xfunction(std::tuple<A...>&& f_args, E&&... e) noexcept
 | |
|         {
 | |
|             using functor_type = F;
 | |
|             using expression_tag = xexpression_tag_t<E...>;
 | |
|             using type = select_xfunction_expression_t<expression_tag, functor_type, const_xclosure_t<E>...>;
 | |
|             auto functor = get_functor<functor_type>(
 | |
|                 std::forward<std::tuple<A...>>(f_args),
 | |
|                 std::make_index_sequence<sizeof...(A)>{}
 | |
|             );
 | |
|             return type(std::move(functor), std::forward<E>(e)...);
 | |
|         }
 | |
| 
 | |
|         struct isclose
 | |
|         {
 | |
|             using result_type = bool;
 | |
| 
 | |
|             isclose(double rtol, double atol, bool equal_nan)
 | |
|                 : m_rtol(rtol)
 | |
|                 , m_atol(atol)
 | |
|                 , m_equal_nan(equal_nan)
 | |
|             {
 | |
|             }
 | |
| 
 | |
|             template <class A1, class A2>
 | |
|             bool operator()(const A1& a, const A2& b) const
 | |
|             {
 | |
|                 using internal_type = xtl::promote_type_t<A1, A2, double>;
 | |
|                 if (math::isnan(a) && math::isnan(b))
 | |
|                 {
 | |
|                     return m_equal_nan;
 | |
|                 }
 | |
|                 if (math::isinf(a) && math::isinf(b))
 | |
|                 {
 | |
|                     // check for both infinity signs equal
 | |
|                     return a == b;
 | |
|                 }
 | |
|                 auto d = math::abs(internal_type(a) - internal_type(b));
 | |
|                 return d <= m_atol
 | |
|                        || d <= m_rtol
 | |
|                                    * double((std::max)(math::abs(internal_type(a)), math::abs(internal_type(b)))
 | |
|                                    );
 | |
|             }
 | |
| 
 | |
|         private:
 | |
| 
 | |
|             double m_rtol;
 | |
|             double m_atol;
 | |
|             bool m_equal_nan;
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup classif_functions
 | |
|      * @brief Element-wise closeness detection
 | |
|      *
 | |
|      * Returns an \ref xfunction that evaluates to
 | |
|      * true if the elements in ``e1`` and ``e2`` are close to each other
 | |
|      * according to parameters ``atol`` and ``rtol``.
 | |
|      * The equation is: ``std::abs(a - b) <= (m_atol + m_rtol * std::abs(b))``.
 | |
|      * @param e1 input array to compare
 | |
|      * @param e2 input array to compare
 | |
|      * @param rtol the relative tolerance parameter (default 1e-05)
 | |
|      * @param atol the absolute tolerance parameter (default 1e-08)
 | |
|      * @param equal_nan if true, isclose returns true if both elements of e1 and e2 are NaN
 | |
|      * @return an \ref xfunction
 | |
|      */
 | |
|     template <class E1, class E2>
 | |
|     inline auto
 | |
|     isclose(E1&& e1, E2&& e2, double rtol = 1e-05, double atol = 1e-08, bool equal_nan = false) noexcept
 | |
|     {
 | |
|         return detail::make_xfunction<detail::isclose>(
 | |
|             std::make_tuple(rtol, atol, equal_nan),
 | |
|             std::forward<E1>(e1),
 | |
|             std::forward<E2>(e2)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup classif_functions
 | |
|      * @brief Check if all elements in \em e1 are close to the
 | |
|      * corresponding elements in \em e2.
 | |
|      *
 | |
|      * Returns true if all elements in ``e1`` and ``e2`` are close to each other
 | |
|      * according to parameters ``atol`` and ``rtol``.
 | |
|      * @param e1 input array to compare
 | |
|      * @param e2 input arrays to compare
 | |
|      * @param rtol the relative tolerance parameter (default 1e-05)
 | |
|      * @param atol the absolute tolerance parameter (default 1e-08)
 | |
|      * @return a boolean
 | |
|      */
 | |
|     template <class E1, class E2>
 | |
|     inline auto allclose(E1&& e1, E2&& e2, double rtol = 1e-05, double atol = 1e-08) noexcept
 | |
|     {
 | |
|         return xt::all(isclose(std::forward<E1>(e1), std::forward<E2>(e2), rtol, atol));
 | |
|     }
 | |
| 
 | |
|     /**********************
 | |
|      * Reducing functions *
 | |
|      **********************/
 | |
| 
 | |
|     /**
 | |
|      * @defgroup  red_functions reducing functions
 | |
|      */
 | |
| 
 | |
|     /**
 | |
|      * @ingroup red_functions
 | |
|      * @brief Sum of elements over given axes.
 | |
|      *
 | |
|      * Returns an \ref xreducer for the sum of elements over given
 | |
|      * \em axes.
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axes the axes along which the sum is performed (optional)
 | |
|      * @param es evaluation strategy of the reducer
 | |
|      * @tparam T the value type used for internal computation. The default is
 | |
|      *           `E::value_type`. `T` is also used for determining the value type
 | |
|      *           of the result, which is the type of `T() + E::value_type()`.
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an \ref xreducer
 | |
|      */
 | |
|     XTENSOR_REDUCER_FUNCTION(sum, detail::plus, typename std::decay_t<E>::value_type, 0)
 | |
| 
 | |
|     /**
 | |
|      * @ingroup red_functions
 | |
|      * @brief Product of elements over given axes.
 | |
|      *
 | |
|      * Returns an \ref xreducer for the product of elements over given
 | |
|      * \em axes.
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axes the axes along which the product is computed (optional)
 | |
|      * @param ddof delta degrees of freedom (optional).
 | |
|      *             The divisor used in calculations is N - ddof, where N represents the number of
 | |
|      *             elements. By default ddof is zero.
 | |
|      * @param es evaluation strategy of the reducer
 | |
|      * @tparam T the value type used for internal computation. The default is `E::value_type`.
 | |
|      *           `T` is also used for determining the value type of the result, which is the type
 | |
|      *           of `T() * E::value_type()`.
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an \ref xreducer
 | |
|      */
 | |
|     XTENSOR_REDUCER_FUNCTION(prod, detail::multiplies, typename std::decay_t<E>::value_type, 1)
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <class T, class S, class ST>
 | |
|         inline auto mean_division(S&& s, ST e_size)
 | |
|         {
 | |
|             using value_type = typename std::conditional_t<std::is_same<T, void>::value, double, T>;
 | |
|             // Avoids floating point exception when s.size is 0
 | |
|             value_type div = s.size() != ST(0) ? static_cast<value_type>(e_size / s.size()) : value_type(0);
 | |
|             return std::move(s) / std::move(div);
 | |
|         }
 | |
| 
 | |
|         template <
 | |
|             class T,
 | |
|             class E,
 | |
|             class X,
 | |
|             class D,
 | |
|             class EVS,
 | |
|             XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::is_integral<D>)>
 | |
|         inline auto mean(E&& e, X&& axes, const D& ddof, EVS es)
 | |
|         {
 | |
|             // sum cannot always be a double. It could be a complex number which cannot operate on
 | |
|             // std::plus<double>.
 | |
|             using size_type = typename std::decay_t<E>::size_type;
 | |
|             const size_type size = e.size();
 | |
|             XTENSOR_ASSERT(static_cast<size_type>(ddof) <= size);
 | |
|             auto s = sum<T>(std::forward<E>(e), std::forward<X>(axes), es);
 | |
|             return mean_division<T>(std::move(s), size - static_cast<size_type>(ddof));
 | |
|         }
 | |
| 
 | |
|         template <class T, class E, class I, std::size_t N, class D, class EVS>
 | |
|         inline auto mean(E&& e, const I (&axes)[N], const D& ddof, EVS es)
 | |
|         {
 | |
|             using size_type = typename std::decay_t<E>::size_type;
 | |
|             const size_type size = e.size();
 | |
|             XTENSOR_ASSERT(static_cast<size_type>(ddof) <= size);
 | |
|             auto s = sum<T>(std::forward<E>(e), axes, es);
 | |
|             return mean_division<T>(std::move(s), size - static_cast<size_type>(ddof));
 | |
|         }
 | |
| 
 | |
|         template <class T, class E, class D, class EVS, XTL_REQUIRES(is_reducer_options<EVS>, xtl::is_integral<D>)>
 | |
|         inline auto mean_noaxis(E&& e, const D& ddof, EVS es)
 | |
|         {
 | |
|             using value_type = typename std::conditional_t<std::is_same<T, void>::value, double, T>;
 | |
|             using size_type = typename std::decay_t<E>::size_type;
 | |
|             const size_type size = e.size();
 | |
|             XTENSOR_ASSERT(static_cast<size_type>(ddof) <= size);
 | |
|             auto s = sum<T>(std::forward<E>(e), es);
 | |
|             return std::move(s) / static_cast<value_type>((size - static_cast<size_type>(ddof)));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup red_functions
 | |
|      * @brief Mean of elements over given axes.
 | |
|      *
 | |
|      * Returns an \ref xreducer for the mean of elements over given
 | |
|      * \em axes.
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axes the axes along which the mean is computed (optional)
 | |
|      * @param es the evaluation strategy (optional)
 | |
|      * @tparam T the value type used for internal computation. The default is
 | |
|      *           `E::value_type`. `T` is also used for determining the value type
 | |
|      *           of the result, which is the type of `T() + E::value_type()`.
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an \ref xexpression
 | |
|      */
 | |
|     template <
 | |
|         class T = void,
 | |
|         class E,
 | |
|         class X,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(xtl::negation<is_reducer_options<X>>)>
 | |
|     inline auto mean(E&& e, X&& axes, EVS es = EVS())
 | |
|     {
 | |
|         return detail::mean<T>(std::forward<E>(e), std::forward<X>(axes), 0u, es);
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
 | |
|     inline auto mean(E&& e, EVS es = EVS())
 | |
|     {
 | |
|         return detail::mean_noaxis<T>(std::forward<E>(e), 0u, es);
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
 | |
|     inline auto mean(E&& e, const I (&axes)[N], EVS es = EVS())
 | |
|     {
 | |
|         return detail::mean<T>(std::forward<E>(e), axes, 0u, es);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup red_functions
 | |
|      * @brief Average of elements over given axes using weights.
 | |
|      *
 | |
|      * Returns an \ref xreducer for the mean of elements over given
 | |
|      * \em axes.
 | |
|      * @param e an \ref xexpression
 | |
|      * @param weights \ref xexpression containing weights associated with the values in \ref e
 | |
|      * @param axes the axes along which the mean is computed (optional)
 | |
|      * @tparam T the value type used for internal computation. The default is
 | |
|      *           `E::value_type`. `T`is also used for determining the value type of the result,
 | |
|      *           which is the type of `T() + E::value_type().
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an \ref xexpression
 | |
|      *
 | |
|      * @sa mean
 | |
|      */
 | |
|     template <
 | |
|         class T = void,
 | |
|         class E,
 | |
|         class W,
 | |
|         class X,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(is_reducer_options<EVS>, xtl::negation<xtl::is_integral<X>>)>
 | |
|     inline auto average(E&& e, W&& weights, X&& axes, EVS ev = EVS())
 | |
|     {
 | |
|         xindex_type_t<typename std::decay_t<E>::shape_type> broadcast_shape;
 | |
|         xt::resize_container(broadcast_shape, e.dimension());
 | |
|         auto ax = normalize_axis(e, axes);
 | |
|         if (weights.dimension() == 1)
 | |
|         {
 | |
|             if (weights.size() != e.shape()[ax[0]])
 | |
|             {
 | |
|                 XTENSOR_THROW(std::runtime_error, "Weights need to have the same shape as expression at axes.");
 | |
|             }
 | |
| 
 | |
|             std::fill(broadcast_shape.begin(), broadcast_shape.end(), std::size_t(1));
 | |
|             broadcast_shape[ax[0]] = weights.size();
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             if (!same_shape(e.shape(), weights.shape()))
 | |
|             {
 | |
|                 XTENSOR_THROW(
 | |
|                     std::runtime_error,
 | |
|                     "Weights with dim > 1 need to have the same shape as expression."
 | |
|                 );
 | |
|             }
 | |
| 
 | |
|             std::copy(e.shape().begin(), e.shape().end(), broadcast_shape.begin());
 | |
|         }
 | |
| 
 | |
|         constexpr layout_type L = default_assignable_layout(std::decay_t<W>::static_layout);
 | |
|         auto weights_view = reshape_view<L>(std::forward<W>(weights), std::move(broadcast_shape));
 | |
|         auto scl = sum<T>(weights_view, ax, xt::evaluation_strategy::immediate);
 | |
|         return sum<T>(std::forward<E>(e) * std::move(weights_view), std::move(ax), ev) / std::move(scl);
 | |
|     }
 | |
| 
 | |
|     template <
 | |
|         class T = void,
 | |
|         class E,
 | |
|         class W,
 | |
|         class X,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(is_reducer_options<EVS>, xtl::is_integral<X>)>
 | |
|     inline auto average(E&& e, W&& weights, X axis, EVS ev = EVS())
 | |
|     {
 | |
|         return average(std::forward<E>(e), std::forward<W>(weights), {axis}, std::forward<EVS>(ev));
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class W, class X, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
 | |
|     inline auto average(E&& e, W&& weights, const X (&axes)[N], EVS ev = EVS())
 | |
|     {
 | |
|         // need to select the X&& overload and forward to different type
 | |
|         using ax_t = std::array<std::size_t, N>;
 | |
|         return average<T>(std::forward<E>(e), std::forward<W>(weights), xt::forward_normalize<ax_t>(e, axes), ev);
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class W, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
 | |
|     inline auto average(E&& e, W&& weights, EVS ev = EVS())
 | |
|     {
 | |
|         if (weights.dimension() != e.dimension()
 | |
|             || !std::equal(weights.shape().begin(), weights.shape().end(), e.shape().begin()))
 | |
|         {
 | |
|             XTENSOR_THROW(std::runtime_error, "Weights need to have the same shape as expression.");
 | |
|         }
 | |
| 
 | |
|         auto div = sum<T>(weights, evaluation_strategy::immediate)();
 | |
|         auto s = sum<T>(std::forward<E>(e) * std::forward<W>(weights), ev) / std::move(div);
 | |
|         return s;
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
 | |
|     inline auto average(E&& e, EVS ev = EVS())
 | |
|     {
 | |
|         return mean<T>(e, ev);
 | |
|     }
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <typename E>
 | |
|         std::enable_if_t<std::is_lvalue_reference<E>::value, E> shared_forward(E e) noexcept
 | |
|         {
 | |
|             return e;
 | |
|         }
 | |
| 
 | |
|         template <typename E>
 | |
|         std::enable_if_t<!std::is_lvalue_reference<E>::value, xshared_expression<E>> shared_forward(E e) noexcept
 | |
|         {
 | |
|             return make_xshared(std::move(e));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     template <
 | |
|         class T = void,
 | |
|         class E,
 | |
|         class D,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(is_reducer_options<EVS>, xtl::is_integral<D>)>
 | |
|     inline auto variance(E&& e, const D& ddof, EVS es = EVS())
 | |
|     {
 | |
|         auto cached_mean = mean<T>(e, es)();
 | |
|         return detail::mean_noaxis<T>(square(std::forward<E>(e) - std::move(cached_mean)), ddof, es);
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
 | |
|     inline auto variance(E&& e, EVS es = EVS())
 | |
|     {
 | |
|         return variance<T>(std::forward<E>(e), 0u, es);
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
 | |
|     inline auto stddev(E&& e, EVS es = EVS())
 | |
|     {
 | |
|         return sqrt(variance<T>(std::forward<E>(e), es));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup red_functions
 | |
|      * @brief Compute the variance along the specified axes
 | |
|      *
 | |
|      * Returns the variance of the array elements, a measure of the spread of a
 | |
|      * distribution. The variance is computed for the flattened array by default,
 | |
|      * otherwise over the specified axes.
 | |
|      *
 | |
|      * Note: this function is not yet specialized for complex numbers.
 | |
|      *
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axes the axes along which the variance is computed (optional)
 | |
|      * @param ddof delta degrees of freedom (optional).
 | |
|      *             The divisor used in calculations is N - ddof, where N represents the number of
 | |
|      *             elements. By default ddof is zero.
 | |
|      * @param es evaluation strategy to use (lazy (default), or immediate)
 | |
|      * @tparam T the value type used for internal computation. The default is
 | |
|      *           `E::value_type`. `T`is also used for determining the value type of the result,
 | |
|      *           which is the type of `T() + E::value_type()`.
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an \ref xexpression
 | |
|      *
 | |
|      * @sa stddev, mean
 | |
|      */
 | |
|     template <
 | |
|         class T = void,
 | |
|         class E,
 | |
|         class X,
 | |
|         class D,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::is_integral<D>)>
 | |
|     inline auto variance(E&& e, X&& axes, const D& ddof, EVS es = EVS())
 | |
|     {
 | |
|         decltype(auto) sc = detail::shared_forward<E>(e);
 | |
|         // note: forcing copy of first axes argument -- is there a better solution?
 | |
|         auto axes_copy = axes;
 | |
|         // always eval to prevent repeated evaluations in the next calls
 | |
|         auto inner_mean = eval(mean<T>(sc, std::move(axes_copy), evaluation_strategy::immediate));
 | |
| 
 | |
|         // fake keep_dims = 1
 | |
|         // Since the inner_shape might have a reference semantic (e.g. xbuffer_adaptor in bindings)
 | |
|         // We need to map it to another type before modifying it.
 | |
|         // We pragmatically abuse `get_strides_t`
 | |
|         using tmp_shape_t = get_strides_t<typename std::decay_t<E>::shape_type>;
 | |
|         tmp_shape_t keep_dim_shape = xtl::forward_sequence<tmp_shape_t, decltype(e.shape())>(e.shape());
 | |
|         for (const auto& el : axes)
 | |
|         {
 | |
|             keep_dim_shape[el] = 1u;
 | |
|         }
 | |
| 
 | |
|         auto mrv = reshape_view<XTENSOR_DEFAULT_LAYOUT>(std::move(inner_mean), std::move(keep_dim_shape));
 | |
|         return detail::mean<T>(square(sc - std::move(mrv)), std::forward<X>(axes), ddof, es);
 | |
|     }
 | |
| 
 | |
|     template <
 | |
|         class T = void,
 | |
|         class E,
 | |
|         class X,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::negation<xtl::is_integral<std::decay_t<X>>>, is_reducer_options<EVS>)>
 | |
|     inline auto variance(E&& e, X&& axes, EVS es = EVS())
 | |
|     {
 | |
|         return variance<T>(std::forward<E>(e), std::forward<X>(axes), 0u, es);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup red_functions
 | |
|      * @brief Compute the standard deviation along the specified axis.
 | |
|      *
 | |
|      * Returns the standard deviation, a measure of the spread of a distribution,
 | |
|      * of the array elements. The standard deviation is computed for the flattened
 | |
|      * array by default, otherwise over the specified axis.
 | |
|      *
 | |
|      * Note: this function is not yet specialized for complex numbers.
 | |
|      *
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axes the axes along which the standard deviation is computed (optional)
 | |
|      * @param es evaluation strategy to use (lazy (default), or immediate)
 | |
|      * @tparam T the value type used for internal computation. The default is
 | |
|      *           `E::value_type`. `T`is also used for determining the value type of the result,
 | |
|      *           which is the type of `T() + E::value_type()`.
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an \ref xexpression
 | |
|      *
 | |
|      * @sa variance, mean
 | |
|      */
 | |
|     template <
 | |
|         class T = void,
 | |
|         class E,
 | |
|         class X,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(xtl::negation<is_reducer_options<X>>)>
 | |
|     inline auto stddev(E&& e, X&& axes, EVS es = EVS())
 | |
|     {
 | |
|         return sqrt(variance<T>(std::forward<E>(e), std::forward<X>(axes), es));
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class A, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
 | |
|     inline auto stddev(E&& e, const A (&axes)[N], EVS es = EVS())
 | |
|     {
 | |
|         return stddev<T>(
 | |
|             std::forward<E>(e),
 | |
|             xtl::forward_sequence<std::array<std::size_t, N>, decltype(axes)>(axes),
 | |
|             es
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     template <
 | |
|         class T = void,
 | |
|         class E,
 | |
|         class A,
 | |
|         std::size_t N,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(is_reducer_options<EVS>)>
 | |
|     inline auto variance(E&& e, const A (&axes)[N], EVS es = EVS())
 | |
|     {
 | |
|         return variance<T>(
 | |
|             std::forward<E>(e),
 | |
|             xtl::forward_sequence<std::array<std::size_t, N>, decltype(axes)>(axes),
 | |
|             es
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class A, std::size_t N, class D, class EVS = DEFAULT_STRATEGY_REDUCERS>
 | |
|     inline auto variance(E&& e, const A (&axes)[N], const D& ddof, EVS es = EVS())
 | |
|     {
 | |
|         return variance<T>(
 | |
|             std::forward<E>(e),
 | |
|             xtl::forward_sequence<std::array<std::size_t, N>, decltype(axes)>(axes),
 | |
|             ddof,
 | |
|             es
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup red_functions
 | |
|      * @brief Minimum and maximum among the elements of an array or expression.
 | |
|      *
 | |
|      * Returns an \ref xreducer for the minimum and maximum of an expression's elements.
 | |
|      * @param e an \ref xexpression
 | |
|      * @param es evaluation strategy to use (lazy (default), or immediate)
 | |
|      * @return an \ref xexpression of type ``std::array<value_type, 2>``, whose first
 | |
|      *         and second element represent the minimum and maximum respectively
 | |
|      */
 | |
|     template <class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
 | |
|     inline auto minmax(E&& e, EVS es = EVS())
 | |
|     {
 | |
|         using std::max;
 | |
|         using std::min;
 | |
|         using value_type = typename std::decay_t<E>::value_type;
 | |
|         using result_type = std::array<value_type, 2>;
 | |
|         using init_value_fct = xt::const_value<result_type>;
 | |
| 
 | |
|         auto reduce_func = [](auto r, const auto& v)
 | |
|         {
 | |
|             r[0] = (min) (r[0], v);
 | |
|             r[1] = (max) (r[1], v);
 | |
|             return r;
 | |
|         };
 | |
| 
 | |
|         auto init_func = init_value_fct(
 | |
|             result_type{std::numeric_limits<value_type>::max(), std::numeric_limits<value_type>::lowest()}
 | |
|         );
 | |
| 
 | |
|         auto merge_func = [](auto r, const auto& s)
 | |
|         {
 | |
|             r[0] = (min) (r[0], s[0]);
 | |
|             r[1] = (max) (r[1], s[1]);
 | |
|             return r;
 | |
|         };
 | |
|         return xt::reduce(
 | |
|             make_xreducer_functor(std::move(reduce_func), std::move(init_func), std::move(merge_func)),
 | |
|             std::forward<E>(e),
 | |
|             arange(e.dimension()),
 | |
|             es
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @defgroup acc_functions accumulating functions
 | |
|      */
 | |
| 
 | |
|     /**
 | |
|      * @ingroup acc_functions
 | |
|      * @brief Cumulative sum.
 | |
|      *
 | |
|      * Returns the accumulated sum for the elements over given
 | |
|      * \em axis (or flattened).
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axis the axes along which the cumulative sum is computed (optional)
 | |
|      * @tparam T the value type used for internal computation. The default is
 | |
|      *           `E::value_type`. `T`is also used for determining the value type of the result,
 | |
|      *           which is the type of `T() + E::value_type()`.
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an \ref xarray<T>
 | |
|      */
 | |
|     template <class T = void, class E>
 | |
|     inline auto cumsum(E&& e, std::ptrdiff_t axis)
 | |
|     {
 | |
|         using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
 | |
|         return accumulate(
 | |
|             make_xaccumulator_functor(detail::plus(), detail::accumulator_identity<init_value_type>()),
 | |
|             std::forward<E>(e),
 | |
|             axis
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E>
 | |
|     inline auto cumsum(E&& e)
 | |
|     {
 | |
|         using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
 | |
|         return accumulate(
 | |
|             make_xaccumulator_functor(detail::plus(), detail::accumulator_identity<init_value_type>()),
 | |
|             std::forward<E>(e)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup acc_functions
 | |
|      * @brief Cumulative product.
 | |
|      *
 | |
|      * Returns the accumulated product for the elements over given
 | |
|      * \em axis (or flattened).
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axis the axes along which the cumulative product is computed (optional)
 | |
|      * @tparam T the value type used for internal computation. The default is
 | |
|      *           `E::value_type`. `T`is also used for determining the value type of the result,
 | |
|      *           which is the type of `T() * E::value_type()`.
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an \ref xarray<T>
 | |
|      */
 | |
|     template <class T = void, class E>
 | |
|     inline auto cumprod(E&& e, std::ptrdiff_t axis)
 | |
|     {
 | |
|         using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
 | |
|         return accumulate(
 | |
|             make_xaccumulator_functor(detail::multiplies(), detail::accumulator_identity<init_value_type>()),
 | |
|             std::forward<E>(e),
 | |
|             axis
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E>
 | |
|     inline auto cumprod(E&& e)
 | |
|     {
 | |
|         using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
 | |
|         return accumulate(
 | |
|             make_xaccumulator_functor(detail::multiplies(), detail::accumulator_identity<init_value_type>()),
 | |
|             std::forward<E>(e)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /*****************
 | |
|      * nan functions *
 | |
|      *****************/
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         struct nan_to_num_functor
 | |
|         {
 | |
|             template <class A>
 | |
|             inline auto operator()(const A& a) const
 | |
|             {
 | |
|                 if (math::isnan(a))
 | |
|                 {
 | |
|                     return A(0);
 | |
|                 }
 | |
|                 if (math::isinf(a))
 | |
|                 {
 | |
|                     if (a < 0)
 | |
|                     {
 | |
|                         return std::numeric_limits<A>::lowest();
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         return (std::numeric_limits<A>::max)();
 | |
|                     }
 | |
|                 }
 | |
|                 return a;
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         struct nan_min
 | |
|         {
 | |
|             template <class T, class U>
 | |
|             constexpr auto operator()(const T lhs, const U rhs) const
 | |
|             {
 | |
|                 // Clunky expression for working with GCC 4.9
 | |
|                 return math::isnan(lhs)
 | |
|                            ? rhs
 | |
|                            : (math::isnan(rhs) ? lhs
 | |
|                                                : std::common_type_t<T, U>(
 | |
|                                                    detail::make_xfunction<math::minimum<void>>(lhs, rhs)
 | |
|                                                ));
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         struct nan_max
 | |
|         {
 | |
|             template <class T, class U>
 | |
|             constexpr auto operator()(const T lhs, const U rhs) const
 | |
|             {
 | |
|                 // Clunky expression for working with GCC 4.9
 | |
|                 return math::isnan(lhs)
 | |
|                            ? rhs
 | |
|                            : (math::isnan(rhs) ? lhs
 | |
|                                                : std::common_type_t<T, U>(
 | |
|                                                    detail::make_xfunction<math::maximum<void>>(lhs, rhs)
 | |
|                                                ));
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         struct nan_plus
 | |
|         {
 | |
|             template <class T, class U>
 | |
|             constexpr auto operator()(const T lhs, const U rhs) const
 | |
|             {
 | |
|                 return !math::isnan(rhs) ? lhs + rhs : lhs;
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         struct nan_multiplies
 | |
|         {
 | |
|             template <class T, class U>
 | |
|             constexpr auto operator()(const T lhs, const U rhs) const
 | |
|             {
 | |
|                 return !math::isnan(rhs) ? lhs * rhs : lhs;
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         template <class T, int V>
 | |
|         struct nan_init
 | |
|         {
 | |
|             using value_type = T;
 | |
|             using result_type = T;
 | |
| 
 | |
|             constexpr result_type operator()(const value_type lhs) const
 | |
|             {
 | |
|                 return math::isnan(lhs) ? result_type(V) : lhs;
 | |
|             }
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @defgroup  nan_functions nan functions
 | |
|      */
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nan_functions
 | |
|      * @brief Convert nan or +/- inf to numbers
 | |
|      *
 | |
|      * This functions converts NaN to 0, and +inf to the highest, -inf to the lowest
 | |
|      * floating point value of the same type.
 | |
|      *
 | |
|      * @param e input \ref xexpression
 | |
|      * @return an \ref xexpression
 | |
|      */
 | |
|     template <class E>
 | |
|     inline auto nan_to_num(E&& e)
 | |
|     {
 | |
|         return detail::make_xfunction<detail::nan_to_num_functor>(std::forward<E>(e));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nan_functions
 | |
|      * @brief Minimum element over given axes, ignoring NaNs.
 | |
|      *
 | |
|      * Returns an \ref xreducer for the minimum of elements over given
 | |
|      * @p axes, ignoring NaNs.
 | |
|      * @warning Casting the result to an integer type can cause undefined behavior.
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axes the axes along which the minimum is found (optional)
 | |
|      * @param es evaluation strategy of the reducer (optional)
 | |
|      * @tparam T the result type. The default is `E::value_type`.
 | |
|      * @return an \ref xreducer
 | |
|      */
 | |
|     XTENSOR_REDUCER_FUNCTION(nanmin, detail::nan_min, typename std::decay_t<E>::value_type, std::nan("0"))
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nan_functions
 | |
|      * @brief Maximum element along given axes, ignoring NaNs.
 | |
|      *
 | |
|      * Returns an \ref xreducer for the sum of elements over given
 | |
|      * @p axes, ignoring NaN.
 | |
|      * @warning Casting the result to an integer type can cause undefined behavior.
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axes the axes along which the sum is performed (optional)
 | |
|      * @param es evaluation strategy of the reducer (optional)
 | |
|      * @tparam T the result type. The default is `E::value_type`.
 | |
|      * @return an \ref xreducer
 | |
|      */
 | |
|     XTENSOR_REDUCER_FUNCTION(nanmax, detail::nan_max, typename std::decay_t<E>::value_type, std::nan("0"))
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nan_functions
 | |
|      * @brief Sum of elements over given axes, replacing NaN with 0.
 | |
|      *
 | |
|      * Returns an \ref xreducer for the sum of elements over given
 | |
|      * @p axes, ignoring NaN.
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axes the axes along which the sum is performed (optional)
 | |
|      * @param es evaluation strategy of the reducer (optional)
 | |
|      * @tparam T the value type used for internal computation. The default is
 | |
|      *           `E::value_type`. `T` is also used for determining the value type
 | |
|      *           of the result, which is the type of `T() + E::value_type()`.
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an \ref xreducer
 | |
|      */
 | |
|     XTENSOR_REDUCER_FUNCTION(nansum, detail::nan_plus, typename std::decay_t<E>::value_type, 0)
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nan_functions
 | |
|      * @brief Product of elements over given axes, replacing NaN with 1.
 | |
|      *
 | |
|      * Returns an \ref xreducer for the sum of elements over given
 | |
|      * @p axes, replacing nan with 1.
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axes the axes along which the sum is performed (optional)
 | |
|      * @param es evaluation strategy of the reducer (optional)
 | |
|      * @tparam T the value type used for internal computation. The default is
 | |
|      *           `E::value_type`. `T` is also used for determining the value type
 | |
|      *           of the result, which is the type of `T() * E::value_type()`.
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an \ref xreducer
 | |
|      */
 | |
|     XTENSOR_REDUCER_FUNCTION(nanprod, detail::nan_multiplies, typename std::decay_t<E>::value_type, 1)
 | |
| 
 | |
| #define COUNT_NON_ZEROS_CONTENT                                                             \
 | |
|     using value_type = typename std::decay_t<E>::value_type;                                \
 | |
|     using result_type = xt::detail::xreducer_size_type_t<value_type>;                       \
 | |
|     using init_value_fct = xt::const_value<result_type>;                                    \
 | |
|                                                                                             \
 | |
|     auto init_fct = init_value_fct(0);                                                      \
 | |
|                                                                                             \
 | |
|     auto reduce_fct = [](const auto& lhs, const auto& rhs)                                  \
 | |
|     {                                                                                       \
 | |
|         using value_t = xt::detail::xreducer_temporary_type_t<std::decay_t<decltype(rhs)>>; \
 | |
|         using result_t = std::decay_t<decltype(lhs)>;                                       \
 | |
|                                                                                             \
 | |
|         return (rhs != value_t(0)) ? lhs + result_t(1) : lhs;                               \
 | |
|     };                                                                                      \
 | |
|     auto merge_func = detail::plus();
 | |
| 
 | |
|     template <class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
 | |
|     inline auto count_nonzero(E&& e, EVS es = EVS())
 | |
|     {
 | |
|         COUNT_NON_ZEROS_CONTENT;
 | |
|         return xt::reduce(
 | |
|             make_xreducer_functor(std::move(reduce_fct), std::move(init_fct), std::move(merge_func)),
 | |
|             std::forward<E>(e),
 | |
|             es
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     template <
 | |
|         class E,
 | |
|         class X,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::negation<xtl::is_integral<X>>)>
 | |
|     inline auto count_nonzero(E&& e, X&& axes, EVS es = EVS())
 | |
|     {
 | |
|         COUNT_NON_ZEROS_CONTENT;
 | |
|         return xt::reduce(
 | |
|             make_xreducer_functor(std::move(reduce_fct), std::move(init_fct), std::move(merge_func)),
 | |
|             std::forward<E>(e),
 | |
|             std::forward<X>(axes),
 | |
|             es
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     template <
 | |
|         class E,
 | |
|         class X,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::is_integral<X>)>
 | |
|     inline auto count_nonzero(E&& e, X axis, EVS es = EVS())
 | |
|     {
 | |
|         return count_nonzero(std::forward<E>(e), {axis}, es);
 | |
|     }
 | |
| 
 | |
|     template <class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
 | |
|     inline auto count_nonzero(E&& e, const I (&axes)[N], EVS es = EVS())
 | |
|     {
 | |
|         COUNT_NON_ZEROS_CONTENT;
 | |
|         return xt::reduce(
 | |
|             make_xreducer_functor(std::move(reduce_fct), std::move(init_fct), std::move(merge_func)),
 | |
|             std::forward<E>(e),
 | |
|             axes,
 | |
|             es
 | |
|         );
 | |
|     }
 | |
| 
 | |
| #undef COUNT_NON_ZEROS_CONTENT
 | |
| 
 | |
|     template <class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
 | |
|     inline auto count_nonnan(E&& e, EVS es = EVS())
 | |
|     {
 | |
|         return xt::count_nonzero(!xt::isnan(std::forward<E>(e)), es);
 | |
|     }
 | |
| 
 | |
|     template <
 | |
|         class E,
 | |
|         class X,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::negation<xtl::is_integral<X>>)>
 | |
|     inline auto count_nonnan(E&& e, X&& axes, EVS es = EVS())
 | |
|     {
 | |
|         return xt::count_nonzero(!xt::isnan(std::forward<E>(e)), std::forward<X>(axes), es);
 | |
|     }
 | |
| 
 | |
|     template <
 | |
|         class E,
 | |
|         class X,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::is_integral<X>)>
 | |
|     inline auto count_nonnan(E&& e, X&& axes, EVS es = EVS())
 | |
|     {
 | |
|         return xt::count_nonzero(!xt::isnan(std::forward<E>(e)), {axes}, es);
 | |
|     }
 | |
| 
 | |
|     template <class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
 | |
|     inline auto count_nonnan(E&& e, const I (&axes)[N], EVS es = EVS())
 | |
|     {
 | |
|         return xt::count_nonzero(!xt::isnan(std::forward<E>(e)), axes, es);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nan_functions
 | |
|      * @brief Cumulative sum, replacing nan with 0.
 | |
|      *
 | |
|      * Returns an xaccumulator for the sum of elements over given
 | |
|      * \em axis, replacing nan with 0.
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axis the axis along which the elements are accumulated (optional)
 | |
|      * @tparam T the value type used for internal computation. The default is
 | |
|      *           `E::value_type`. `T` is also used for determining the value type
 | |
|      *           of the result, which is the type of `T() + E::value_type()`.
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an xaccumulator
 | |
|      */
 | |
|     template <class T = void, class E>
 | |
|     inline auto nancumsum(E&& e, std::ptrdiff_t axis)
 | |
|     {
 | |
|         using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
 | |
|         return accumulate(
 | |
|             make_xaccumulator_functor(detail::nan_plus(), detail::nan_init<init_value_type, 0>()),
 | |
|             std::forward<E>(e),
 | |
|             axis
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E>
 | |
|     inline auto nancumsum(E&& e)
 | |
|     {
 | |
|         using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
 | |
|         return accumulate(
 | |
|             make_xaccumulator_functor(detail::nan_plus(), detail::nan_init<init_value_type, 0>()),
 | |
|             std::forward<E>(e)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nan_functions
 | |
|      * @brief Cumulative product, replacing nan with 1.
 | |
|      *
 | |
|      * Returns an xaccumulator for the product of elements over given
 | |
|      * \em axis, replacing nan with 1.
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axis the axis along which the elements are accumulated (optional)
 | |
|      * @tparam T the value type used for internal computation. The default is
 | |
|      *           `E::value_type`. `T` is also used for determining the value type
 | |
|      *           of the result, which is the type of `T() * E::value_type()`.
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an xaccumulator
 | |
|      */
 | |
|     template <class T = void, class E>
 | |
|     inline auto nancumprod(E&& e, std::ptrdiff_t axis)
 | |
|     {
 | |
|         using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
 | |
|         return accumulate(
 | |
|             make_xaccumulator_functor(detail::nan_multiplies(), detail::nan_init<init_value_type, 1>()),
 | |
|             std::forward<E>(e),
 | |
|             axis
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E>
 | |
|     inline auto nancumprod(E&& e)
 | |
|     {
 | |
|         using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
 | |
|         return accumulate(
 | |
|             make_xaccumulator_functor(detail::nan_multiplies(), detail::nan_init<init_value_type, 1>()),
 | |
|             std::forward<E>(e)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <class T>
 | |
|         struct diff_impl
 | |
|         {
 | |
|             template <class Arg>
 | |
|             inline void operator()(
 | |
|                 Arg& ad,
 | |
|                 const std::size_t& n,
 | |
|                 xstrided_slice_vector& slice1,
 | |
|                 xstrided_slice_vector& slice2,
 | |
|                 std::size_t saxis
 | |
|             )
 | |
|             {
 | |
|                 for (std::size_t i = 0; i < n; ++i)
 | |
|                 {
 | |
|                     slice2[saxis] = range(xnone(), ad.shape()[saxis] - 1);
 | |
|                     ad = strided_view(ad, slice1) - strided_view(ad, slice2);
 | |
|                 }
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         template <>
 | |
|         struct diff_impl<bool>
 | |
|         {
 | |
|             template <class Arg>
 | |
|             inline void operator()(
 | |
|                 Arg& ad,
 | |
|                 const std::size_t& n,
 | |
|                 xstrided_slice_vector& slice1,
 | |
|                 xstrided_slice_vector& slice2,
 | |
|                 std::size_t saxis
 | |
|             )
 | |
|             {
 | |
|                 for (std::size_t i = 0; i < n; ++i)
 | |
|                 {
 | |
|                     slice2[saxis] = range(xnone(), ad.shape()[saxis] - 1);
 | |
|                     ad = not_equal(strided_view(ad, slice1), strided_view(ad, slice2));
 | |
|                 }
 | |
|             }
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nan_functions
 | |
|      * @brief Mean of elements over given axes, excluding NaNs.
 | |
|      *
 | |
|      * Returns an \ref xreducer for the mean of elements over given
 | |
|      * \em axes, excluding NaNs.
 | |
|      * This is not the same as counting NaNs as zero, since excluding NaNs changes the number
 | |
|      * of elements considered in the statistic.
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axes the axes along which the mean is computed (optional)
 | |
|      * @param es the evaluation strategy (optional)
 | |
|      * @tparam T the result type. The default is `E::value_type`.
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an \ref xexpression
 | |
|      */
 | |
|     template <
 | |
|         class T = void,
 | |
|         class E,
 | |
|         class X,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(xtl::negation<is_reducer_options<X>>)>
 | |
|     inline auto nanmean(E&& e, X&& axes, EVS es = EVS())
 | |
|     {
 | |
|         decltype(auto) sc = detail::shared_forward<E>(e);
 | |
|         // note: forcing copy of first axes argument -- is there a better solution?
 | |
|         auto axes_copy = axes;
 | |
|         using value_type = typename std::conditional_t<std::is_same<T, void>::value, double, T>;
 | |
|         using sum_type = typename std::conditional_t<
 | |
|             std::is_same<T, void>::value,
 | |
|             typename std::common_type_t<typename std::decay_t<E>::value_type, value_type>,
 | |
|             T>;
 | |
|         // sum cannot always be a double. It could be a complex number which cannot operate on
 | |
|         // std::plus<double>.
 | |
|         return nansum<sum_type>(sc, std::forward<X>(axes), es)
 | |
|                / xt::cast<value_type>(count_nonnan(sc, std::move(axes_copy), es));
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
 | |
|     inline auto nanmean(E&& e, EVS es = EVS())
 | |
|     {
 | |
|         decltype(auto) sc = detail::shared_forward<E>(e);
 | |
|         using value_type = typename std::conditional_t<std::is_same<T, void>::value, double, T>;
 | |
|         using sum_type = typename std::conditional_t<
 | |
|             std::is_same<T, void>::value,
 | |
|             typename std::common_type_t<typename std::decay_t<E>::value_type, value_type>,
 | |
|             T>;
 | |
|         return nansum<sum_type>(sc, es) / xt::cast<value_type>(count_nonnan(sc, es));
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
 | |
|     inline auto nanmean(E&& e, const I (&axes)[N], EVS es = EVS())
 | |
|     {
 | |
|         return nanmean<T>(
 | |
|             std::forward<E>(e),
 | |
|             xtl::forward_sequence<std::array<std::size_t, N>, decltype(axes)>(axes),
 | |
|             es
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
 | |
|     inline auto nanvar(E&& e, EVS es = EVS())
 | |
|     {
 | |
|         decltype(auto) sc = detail::shared_forward<E>(e);
 | |
|         return nanmean<T>(square(sc - nanmean<T>(sc)), es);
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
 | |
|     inline auto nanstd(E&& e, EVS es = EVS())
 | |
|     {
 | |
|         return sqrt(nanvar<T>(std::forward<E>(e), es));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nan_functions
 | |
|      * @brief Compute the variance along the specified axes, excluding NaNs
 | |
|      *
 | |
|      * Returns the variance of the array elements, a measure of the spread of a
 | |
|      * distribution. The variance is computed for the flattened array by default,
 | |
|      * otherwise over the specified axes.
 | |
|      * Excluding NaNs changes the number of elements considered in the statistic.
 | |
|      *
 | |
|      * Note: this function is not yet specialized for complex numbers.
 | |
|      *
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axes the axes along which the variance is computed (optional)
 | |
|      * @param es evaluation strategy to use (lazy (default), or immediate)
 | |
|      * @tparam T the result type. The default is `E::value_type`.
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an \ref xexpression
 | |
|      *
 | |
|      * @sa nanstd, nanmean
 | |
|      */
 | |
|     template <
 | |
|         class T = void,
 | |
|         class E,
 | |
|         class X,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(xtl::negation<is_reducer_options<X>>)>
 | |
|     inline auto nanvar(E&& e, X&& axes, EVS es = EVS())
 | |
|     {
 | |
|         decltype(auto) sc = detail::shared_forward<E>(e);
 | |
|         // note: forcing copy of first axes argument -- is there a better solution?
 | |
|         auto axes_copy = axes;
 | |
|         using result_type = typename std::conditional_t<std::is_same<T, void>::value, double, T>;
 | |
|         auto inner_mean = nanmean<result_type>(sc, std::move(axes_copy));
 | |
| 
 | |
|         // fake keep_dims = 1
 | |
|         // Since the inner_shape might have a reference semantic (e.g. xbuffer_adaptor in bindings)
 | |
|         // We need to map it to another type before modifying it.
 | |
|         // We pragmatically abuse `get_strides_t`
 | |
|         using tmp_shape_t = get_strides_t<typename std::decay_t<E>::shape_type>;
 | |
|         tmp_shape_t keep_dim_shape = xtl::forward_sequence<tmp_shape_t, decltype(e.shape())>(e.shape());
 | |
|         for (const auto& el : axes)
 | |
|         {
 | |
|             keep_dim_shape[el] = 1;
 | |
|         }
 | |
|         auto mrv = reshape_view<XTENSOR_DEFAULT_LAYOUT>(std::move(inner_mean), std::move(keep_dim_shape));
 | |
|         return nanmean<result_type>(square(cast<result_type>(sc) - std::move(mrv)), std::forward<X>(axes), es);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup nan_functions
 | |
|      * @brief Compute the standard deviation along the specified axis, excluding nans.
 | |
|      *
 | |
|      * Returns the standard deviation, a measure of the spread of a distribution,
 | |
|      * of the array elements. The standard deviation is computed for the flattened
 | |
|      * array by default, otherwise over the specified axis.
 | |
|      * Excluding NaNs changes the number of elements considered in the statistic.
 | |
|      *
 | |
|      * Note: this function is not yet specialized for complex numbers.
 | |
|      *
 | |
|      * @param e an \ref xexpression
 | |
|      * @param axes the axes along which the standard deviation is computed (optional)
 | |
|      * @param es evaluation strategy to use (lazy (default), or immediate)
 | |
|      * @tparam T the result type. The default is `E::value_type`.
 | |
|      *           You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
 | |
|      * @return an \ref xexpression
 | |
|      *
 | |
|      * @sa nanvar, nanmean
 | |
|      */
 | |
|     template <
 | |
|         class T = void,
 | |
|         class E,
 | |
|         class X,
 | |
|         class EVS = DEFAULT_STRATEGY_REDUCERS,
 | |
|         XTL_REQUIRES(xtl::negation<is_reducer_options<X>>)>
 | |
|     inline auto nanstd(E&& e, X&& axes, EVS es = EVS())
 | |
|     {
 | |
|         return sqrt(nanvar<T>(std::forward<E>(e), std::forward<X>(axes), es));
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class A, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
 | |
|     inline auto nanstd(E&& e, const A (&axes)[N], EVS es = EVS())
 | |
|     {
 | |
|         return nanstd<T>(
 | |
|             std::forward<E>(e),
 | |
|             xtl::forward_sequence<std::array<std::size_t, N>, decltype(axes)>(axes),
 | |
|             es
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     template <class T = void, class E, class A, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
 | |
|     inline auto nanvar(E&& e, const A (&axes)[N], EVS es = EVS())
 | |
|     {
 | |
|         return nanvar<T>(
 | |
|             std::forward<E>(e),
 | |
|             xtl::forward_sequence<std::array<std::size_t, N>, decltype(axes)>(axes),
 | |
|             es
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup red_functions
 | |
|      * @brief Calculate the n-th discrete difference along the given axis.
 | |
|      *
 | |
|      * Calculate the n-th discrete difference along the given axis. This function is not lazy (might change in
 | |
|      * the future).
 | |
|      * @param a an \ref xexpression
 | |
|      * @param n The number of times values are differenced. If zero, the input is returned as-is. (optional)
 | |
|      * @param axis The axis along which the difference is taken, default is the last axis.
 | |
|      * @return an xarray
 | |
|      */
 | |
|     template <class T>
 | |
|     auto diff(const xexpression<T>& a, std::size_t n = 1, std::ptrdiff_t axis = -1)
 | |
|     {
 | |
|         typename std::decay_t<T>::temporary_type ad = a.derived_cast();
 | |
|         std::size_t saxis = normalize_axis(ad.dimension(), axis);
 | |
|         if (n <= ad.size())
 | |
|         {
 | |
|             if (n != std::size_t(0))
 | |
|             {
 | |
|                 xstrided_slice_vector slice1(ad.dimension(), all());
 | |
|                 xstrided_slice_vector slice2(ad.dimension(), all());
 | |
|                 slice1[saxis] = range(1, xnone());
 | |
| 
 | |
|                 detail::diff_impl<typename T::value_type> impl;
 | |
|                 impl(ad, n, slice1, slice2, saxis);
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             auto shape = ad.shape();
 | |
|             shape[saxis] = std::size_t(0);
 | |
|             ad.resize(shape);
 | |
|         }
 | |
|         return ad;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup red_functions
 | |
|      * @brief Integrate along the given axis using the composite trapezoidal rule.
 | |
|      *
 | |
|      * Returns definite integral as approximated by trapezoidal rule. This function is not lazy (might change
 | |
|      * in the future).
 | |
|      * @param y an \ref xexpression
 | |
|      * @param dx the spacing between sample points (optional)
 | |
|      * @param axis the axis along which to integrate.
 | |
|      * @return an xarray
 | |
|      */
 | |
|     template <class T>
 | |
|     auto trapz(const xexpression<T>& y, double dx = 1.0, std::ptrdiff_t axis = -1)
 | |
|     {
 | |
|         auto& yd = y.derived_cast();
 | |
|         std::size_t saxis = normalize_axis(yd.dimension(), axis);
 | |
| 
 | |
|         xstrided_slice_vector slice1(yd.dimension(), all());
 | |
|         xstrided_slice_vector slice2(yd.dimension(), all());
 | |
|         slice1[saxis] = range(1, xnone());
 | |
|         slice2[saxis] = range(xnone(), yd.shape()[saxis] - 1);
 | |
| 
 | |
|         auto trap = dx * (strided_view(yd, slice1) + strided_view(yd, slice2)) * 0.5;
 | |
| 
 | |
|         return eval(sum(trap, {saxis}));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup red_functions
 | |
|      * @brief Integrate along the given axis using the composite trapezoidal rule.
 | |
|      *
 | |
|      * Returns definite integral as approximated by trapezoidal rule. This function is not lazy (might change
 | |
|      * in the future).
 | |
|      * @param y an \ref xexpression
 | |
|      * @param x an \ref xexpression representing the sample points corresponding to the y values.
 | |
|      * @param axis the axis along which to integrate.
 | |
|      * @return an xarray
 | |
|      */
 | |
|     template <class T, class E>
 | |
|     auto trapz(const xexpression<T>& y, const xexpression<E>& x, std::ptrdiff_t axis = -1)
 | |
|     {
 | |
|         auto& yd = y.derived_cast();
 | |
|         auto& xd = x.derived_cast();
 | |
|         decltype(diff(x)) dx;
 | |
| 
 | |
|         std::size_t saxis = normalize_axis(yd.dimension(), axis);
 | |
| 
 | |
|         if (xd.dimension() == 1)
 | |
|         {
 | |
|             dx = diff(x);
 | |
|             typename std::decay_t<decltype(yd)>::shape_type shape;
 | |
|             resize_container(shape, yd.dimension());
 | |
|             std::fill(shape.begin(), shape.end(), 1);
 | |
|             shape[saxis] = dx.shape()[0];
 | |
|             dx.reshape(shape);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             dx = diff(x, 1, axis);
 | |
|         }
 | |
| 
 | |
|         xstrided_slice_vector slice1(yd.dimension(), all());
 | |
|         xstrided_slice_vector slice2(yd.dimension(), all());
 | |
|         slice1[saxis] = range(1, xnone());
 | |
|         slice2[saxis] = range(xnone(), yd.shape()[saxis] - 1);
 | |
| 
 | |
|         auto trap = dx * (strided_view(yd, slice1) + strided_view(yd, slice2)) * 0.5;
 | |
| 
 | |
|         return eval(sum(trap, {saxis}));
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Returns the one-dimensional piecewise linear interpolant to a function with given discrete data
 | |
|      * points (xp, fp), evaluated at x.
 | |
|      *
 | |
|      * @param x The x-coordinates at which to evaluate the interpolated values (sorted).
 | |
|      * @param xp The x-coordinates of the data points (sorted).
 | |
|      * @param fp The y-coordinates of the data points, same length as xp.
 | |
|      * @param left Value to return for x < xp[0].
 | |
|      * @param right Value to return for x > xp[-1]
 | |
|      * @return an one-dimensional xarray, same length as x.
 | |
|      */
 | |
|     template <class E1, class E2, class E3, typename T>
 | |
|     inline auto interp(const E1& x, const E2& xp, const E3& fp, T left, T right)
 | |
|     {
 | |
|         using size_type = common_size_type_t<E1, E2, E3>;
 | |
|         using value_type = typename E3::value_type;
 | |
| 
 | |
|         // basic checks
 | |
|         XTENSOR_ASSERT(xp.dimension() == 1);
 | |
|         XTENSOR_ASSERT(std::is_sorted(x.cbegin(), x.cend()));
 | |
|         XTENSOR_ASSERT(std::is_sorted(xp.cbegin(), xp.cend()));
 | |
| 
 | |
|         // allocate output
 | |
|         auto f = xtensor<value_type, 1>::from_shape(x.shape());
 | |
| 
 | |
|         // counter in "x": from left
 | |
|         size_type i = 0;
 | |
| 
 | |
|         // fill f[i] for x[i] <= xp[0]
 | |
|         for (; i < x.size(); ++i)
 | |
|         {
 | |
|             if (x[i] > xp[0])
 | |
|             {
 | |
|                 break;
 | |
|             }
 | |
|             f[i] = static_cast<value_type>(left);
 | |
|         }
 | |
| 
 | |
|         // counter in "x": from right
 | |
|         // (index counts one right, to terminate the reverse loop, without risking being negative)
 | |
|         size_type imax = x.size();
 | |
| 
 | |
|         // fill f[i] for x[-1] >= xp[-1]
 | |
|         for (; imax > 0; --imax)
 | |
|         {
 | |
|             if (x[imax - 1] < xp[xp.size() - 1])
 | |
|             {
 | |
|                 break;
 | |
|             }
 | |
|             f[imax - 1] = static_cast<value_type>(right);
 | |
|         }
 | |
| 
 | |
|         // catch edge case: all entries are "right"
 | |
|         if (imax == 0)
 | |
|         {
 | |
|             return f;
 | |
|         }
 | |
| 
 | |
|         // set "imax" as actual index
 | |
|         // (counted one right, see above)
 | |
|         --imax;
 | |
| 
 | |
|         // counter in "xp"
 | |
|         size_type ip = 1;
 | |
| 
 | |
|         // fill f[i] for the interior
 | |
|         for (; i <= imax; ++i)
 | |
|         {
 | |
|             // - search next value in "xp"
 | |
|             while (x[i] > xp[ip])
 | |
|             {
 | |
|                 ++ip;
 | |
|             }
 | |
|             // - distances as doubles
 | |
|             double dfp = static_cast<double>(fp[ip] - fp[ip - 1]);
 | |
|             double dxp = static_cast<double>(xp[ip] - xp[ip - 1]);
 | |
|             double dx = static_cast<double>(x[i] - xp[ip - 1]);
 | |
|             // - interpolate
 | |
|             f[i] = fp[ip - 1] + static_cast<value_type>(dfp / dxp * dx);
 | |
|         }
 | |
| 
 | |
|         return f;
 | |
|     }
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <class E1, class E2>
 | |
|         auto calculate_discontinuity(E1&& discontinuity, E2&&)
 | |
|         {
 | |
|             return discontinuity;
 | |
|         }
 | |
| 
 | |
|         template <class E2>
 | |
|         auto calculate_discontinuity(xt::placeholders::xtuph, E2&& period)
 | |
|         {
 | |
|             return 0.5 * period;
 | |
|         }
 | |
| 
 | |
|         template <class E1, class E2>
 | |
|         auto
 | |
|         calculate_interval(E2&& period, typename std::enable_if<std::is_integral<E1>::value, E1>::type* = 0)
 | |
|         {
 | |
|             auto interval_high = 0.5 * period;
 | |
|             uint64_t remainder = static_cast<uint64_t>(period) % 2;
 | |
|             auto boundary_ambiguous = (remainder == 0);
 | |
|             return std::make_tuple(interval_high, boundary_ambiguous);
 | |
|         }
 | |
| 
 | |
|         template <class E1, class E2>
 | |
|         auto
 | |
|         calculate_interval(E2&& period, typename std::enable_if<std::is_floating_point<E1>::value, E1>::type* = 0)
 | |
|         {
 | |
|             auto interval_high = 0.5 * period;
 | |
|             auto boundary_ambiguous = true;
 | |
|             return std::make_tuple(interval_high, boundary_ambiguous);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Unwrap by taking the complement of large deltas with respect to the period
 | |
|      * @details https://numpy.org/doc/stable/reference/generated/numpy.unwrap.html
 | |
|      * @param p Input array.
 | |
|      * @param discontinuity
 | |
|      *     Maximum discontinuity between values, default is `period / 2`.
 | |
|      *     Values below `period / 2` are treated as if they were `period / 2`.
 | |
|      *     To have an effect different from the default, use `discontinuity > period / 2`.
 | |
|      * @param axis Axis along which unwrap will operate, default: the last axis.
 | |
|      * @param period Size of the range over which the input wraps. Default: \f$ 2 \pi \f$.
 | |
|      */
 | |
| 
 | |
|     template <class E1, class E2 = xt::placeholders::xtuph, class E3 = double>
 | |
|     inline auto unwrap(
 | |
|         E1&& p,
 | |
|         E2 discontinuity = xnone(),
 | |
|         std::ptrdiff_t axis = -1,
 | |
|         E3 period = 2.0 * xt::numeric_constants<double>::PI
 | |
|     )
 | |
|     {
 | |
|         auto discont = detail::calculate_discontinuity(discontinuity, period);
 | |
|         using value_type = typename std::decay_t<E1>::value_type;
 | |
|         std::size_t saxis = normalize_axis(p.dimension(), axis);
 | |
|         auto dd = diff(p, 1, axis);
 | |
|         xstrided_slice_vector slice(p.dimension(), all());
 | |
|         slice[saxis] = range(1, xnone());
 | |
|         auto interval_tuple = detail::calculate_interval<value_type>(period);
 | |
|         auto interval_high = std::get<0>(interval_tuple);
 | |
|         auto boundary_ambiguous = std::get<1>(interval_tuple);
 | |
|         auto interval_low = -interval_high;
 | |
|         auto ddmod = xt::eval(xt::fmod(xt::fmod(dd - interval_low, period) + period, period) + interval_low);
 | |
|         if (boundary_ambiguous)
 | |
|         {
 | |
|             // for `mask = (abs(dd) == period/2)`, the above line made
 | |
|             //`ddmod[mask] == -period/2`. correct these such that
 | |
|             //`ddmod[mask] == sign(dd[mask])*period/2`.
 | |
|             auto boolmap = xt::equal(ddmod, interval_low) && (xt::greater(dd, 0.0));
 | |
|             ddmod = xt::where(boolmap, interval_high, ddmod);
 | |
|         }
 | |
|         auto ph_correct = xt::eval(ddmod - dd);
 | |
|         ph_correct = xt::where(xt::abs(dd) < discont, 0.0, ph_correct);
 | |
|         E1 up(p);
 | |
|         strided_view(up, slice) = strided_view(p, slice)
 | |
|                                   + xt::cumsum(ph_correct, static_cast<std::ptrdiff_t>(saxis));
 | |
|         return up;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @ingroup basic_functions
 | |
|      * @brief Returns the one-dimensional piecewise linear interpolant to a function with given discrete data
 | |
|      * points (xp, fp), evaluated at x.
 | |
|      *
 | |
|      * @param x The x-coordinates at which to evaluate the interpolated values (sorted).
 | |
|      * @param xp The x-coordinates of the data points (sorted).
 | |
|      * @param fp The y-coordinates of the data points, same length as xp.
 | |
|      * @return an one-dimensional xarray, same length as x.
 | |
|      */
 | |
|     template <class E1, class E2, class E3>
 | |
|     inline auto interp(const E1& x, const E2& xp, const E3& fp)
 | |
|     {
 | |
|         return interp(x, xp, fp, fp[0], fp[fp.size() - 1]);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @brief Returns the covariance matrix
 | |
|      *
 | |
|      * @param x one or two dimensional array
 | |
|      * @param y optional one-dimensional array to build covariance to x
 | |
|      */
 | |
|     template <class E1>
 | |
|     inline auto cov(const E1& x, const E1& y = E1())
 | |
|     {
 | |
|         using value_type = typename E1::value_type;
 | |
| 
 | |
|         if (y.dimension() == 0)
 | |
|         {
 | |
|             auto s = x.shape();
 | |
|             using size_type = std::decay_t<decltype(s[0])>;
 | |
|             if (x.dimension() == 1)
 | |
|             {
 | |
|                 auto covar = eval(zeros<value_type>({1, 1}));
 | |
|                 auto x_norm = x - eval(mean(x));
 | |
|                 covar(0, 0) = std::inner_product(x_norm.begin(), x_norm.end(), x_norm.begin(), 0.0)
 | |
|                               / value_type(s[0] - 1);
 | |
|                 return covar;
 | |
|             }
 | |
| 
 | |
|             XTENSOR_ASSERT(x.dimension() == 2);
 | |
| 
 | |
|             auto covar = eval(zeros<value_type>({s[0], s[0]}));
 | |
|             auto m = eval(mean(x, {1}));
 | |
|             m.reshape({m.shape()[0], 1});
 | |
|             auto x_norm = x - m;
 | |
|             for (size_type i = 0; i < s[0]; i++)
 | |
|             {
 | |
|                 auto xi = strided_view(x_norm, {range(i, i + 1), all()});
 | |
|                 for (size_type j = i; j < s[0]; j++)
 | |
|                 {
 | |
|                     auto xj = strided_view(x_norm, {range(j, j + 1), all()});
 | |
|                     covar(j, i) = std::inner_product(xi.begin(), xi.end(), xj.begin(), 0.0)
 | |
|                                   / value_type(s[1] - 1);
 | |
|                 }
 | |
|             }
 | |
|             return eval(covar + transpose(covar) - diag(diagonal(covar)));
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return cov(eval(stack(xtuple(x, y))));
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * convolution mode placeholders for selecting the algorithm
 | |
|      * used in computing a 1D convolution.
 | |
|      * Same as NumPy's mode parameter.
 | |
|      */
 | |
|     namespace convolve_mode
 | |
|     {
 | |
|         struct valid
 | |
|         {
 | |
|         };
 | |
| 
 | |
|         struct full
 | |
|         {
 | |
|         };
 | |
|     }
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         template <class E1, class E2>
 | |
|         inline auto convolve_impl(E1&& e1, E2&& e2, convolve_mode::valid)
 | |
|         {
 | |
|             using value_type = typename std::decay<E1>::type::value_type;
 | |
| 
 | |
|             const std::size_t na = e1.size();
 | |
|             const std::size_t nv = e2.size();
 | |
|             const std::size_t n = na - nv + 1;
 | |
|             xt::xtensor<value_type, 1> out = xt::zeros<value_type>({n});
 | |
|             for (std::size_t i = 0; i < n; i++)
 | |
|             {
 | |
|                 for (std::size_t j = 0; j < nv; j++)
 | |
|                 {
 | |
|                     out(i) += e1(j) * e2(j + i);
 | |
|                 }
 | |
|             }
 | |
|             return out;
 | |
|         }
 | |
| 
 | |
|         template <class E1, class E2>
 | |
|         inline auto convolve_impl(E1&& e1, E2&& e2, convolve_mode::full)
 | |
|         {
 | |
|             using value_type = typename std::decay<E1>::type::value_type;
 | |
| 
 | |
|             const std::size_t na = e1.size();
 | |
|             const std::size_t nv = e2.size();
 | |
|             const std::size_t n = na + nv - 1;
 | |
|             xt::xtensor<value_type, 1> out = xt::zeros<value_type>({n});
 | |
|             for (std::size_t i = 0; i < n; i++)
 | |
|             {
 | |
|                 const std::size_t jmn = (i >= nv - 1) ? i - (nv - 1) : 0;
 | |
|                 const std::size_t jmx = (i < na - 1) ? i : na - 1;
 | |
|                 for (std::size_t j = jmn; j <= jmx; ++j)
 | |
|                 {
 | |
|                     out(i) += e1(j) * e2(i - j);
 | |
|                 }
 | |
|             }
 | |
|             return out;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|      * @brief computes the 1D convolution between two 1D expressions
 | |
|      *
 | |
|      * @param a 1D expression
 | |
|      * @param v 1D expression
 | |
|      * @param mode placeholder Select algorithm #convolve_mode
 | |
|      *
 | |
|      * @detail the algorithm convolves a with v and will incur a copy overhead
 | |
|      *   should v be longer than a.
 | |
|      */
 | |
|     template <class E1, class E2, class E3>
 | |
|     inline auto convolve(E1&& a, E2&& v, E3 mode)
 | |
|     {
 | |
|         if (a.dimension() != 1 || v.dimension() != 1)
 | |
|         {
 | |
|             XTENSOR_THROW(std::runtime_error, "Invalid dimentions convolution arguments must be 1D expressions");
 | |
|         }
 | |
| 
 | |
|         XTENSOR_ASSERT(a.size() > 0 && v.size() > 0);
 | |
| 
 | |
|         // swap them so a is always the longest one
 | |
|         if (a.size() < v.size())
 | |
|         {
 | |
|             return detail::convolve_impl(std::forward<E2>(v), std::forward<E1>(a), mode);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             return detail::convolve_impl(std::forward<E1>(a), std::forward<E2>(v), mode);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| #endif
 |