11#ifndef XTENSOR_NORM_HPP
12#define XTENSOR_NORM_HPP
19#include <xtl/xtype_traits.hpp>
22#include "xoperation.hpp"
35 struct squared_norm_type;
37 namespace traits_detail
40 template <class T, bool scalar = xtl::is_arithmetic<T>::value>
46 static const bool value =
false;
54 static const bool value =
true;
55 using norm_type = xtl::promote_type_t<T>;
56 using squared_norm_type = xtl::promote_type_t<T>;
72 using norm_type =
typename norm_type<T>::type;
73 using squared_norm_type =
typename squared_norm_type<T>::type;
80 !std::is_same<T, char>::value,
81 "'char' is not a numeric type, use 'signed char' or 'unsigned char'."
102 template <
class ARRAY>
105 static void* test(...);
108 static typename U::value_type test(
U*,
typename U::value_type* = 0);
110 using T =
decltype(test(std::declval<ARRAY*>()));
112 static const bool value = !std::is_same<T, void*>::value;
121 using T = std::decay_t<U>;
124 !std::is_same<T, char>::value,
125 "'char' is not a numeric type, use 'signed char' or 'unsigned char'."
131 static const bool value = norm_of_scalar::value || norm_of_vector::value;
133 static_assert(value,
"norm_type<T> are undefined for type U.");
157 using type =
typename std::conditional<
158 base_type::norm_of_vector::value,
159 typename base_type::norm_of_vector::norm_type,
160 typename base_type::norm_of_scalar::norm_type>::type;
190 using type =
typename std::conditional<
191 base_type::norm_of_vector::value,
192 typename base_type::norm_of_vector::squared_norm_type,
193 typename base_type::norm_of_scalar::squared_norm_type>::type;
207#define XTENSOR_DEFINE_SIGNED_NORMS(T) \
208 inline auto norm_lp(T t, double p) noexcept \
210 using rt = decltype(std::abs(t)); \
211 return p == 0.0 ? static_cast<rt>(t != 0) : std::abs(t); \
213 inline auto norm_lp_to_p(T t, double p) noexcept \
215 using rt = xtl::real_promote_type_t<T>; \
216 return p == 0.0 ? static_cast<rt>(t != 0) \
217 : std::pow(static_cast<rt>(std::abs(t)), static_cast<rt>(p)); \
219 inline std::size_t norm_l0(T t) noexcept \
223 inline auto norm_l1(T t) noexcept \
225 return std::abs(t); \
227 inline auto norm_l2(T t) noexcept \
229 return std::abs(t); \
231 inline auto norm_linf(T t) noexcept \
233 return std::abs(t); \
235 inline auto norm_sq(T t) noexcept \
249#undef XTENSOR_DEFINE_SIGNED_NORMS
251#define XTENSOR_DEFINE_UNSIGNED_NORMS(T) \
252 inline T norm_lp(T t, double p) noexcept \
254 return p == 0.0 ? (t != 0) : t; \
256 inline auto norm_lp_to_p(T t, double p) noexcept \
258 using rt = xtl::real_promote_type_t<T>; \
259 return p == 0.0 ? static_cast<rt>(t != 0) : std::pow(static_cast<rt>(t), static_cast<rt>(p)); \
261 inline T norm_l0(T t) noexcept \
263 return t != 0 ? 1 : 0; \
265 inline T norm_l1(T t) noexcept \
269 inline T norm_l2(T t) noexcept \
273 inline T norm_linf(T t) noexcept \
277 inline auto norm_sq(T t) noexcept \
288#undef XTENSOR_DEFINE_UNSIGNED_NORMS
301 return t.real() != 0 ||
t.imag() != 0;
308 inline auto norm_l1(
const std::complex<T>& t)
noexcept
310 return std::abs(t.real()) + std::abs(t.imag());
318 inline auto norm_l2(
const std::complex<T>& t)
noexcept
329 inline auto norm_sq(
const std::complex<T>& t)
noexcept
332 return t.real() * t.real() + t.imag() * t.imag();
339 inline auto norm_linf(
const std::complex<T>& t)
noexcept
341 return (std::max)(std::abs(t.real()), std::abs(t.imag()));
348 inline auto norm_lp_to_p(
const std::complex<T>& t,
double p)
noexcept
350 using rt =
decltype(std::pow(std::abs(t.real()),
static_cast<T
>(p)));
351 return p == 0 ?
static_cast<rt
>(t.real() != 0 || t.imag() != 0)
352 : std::pow(std::abs(t.real()), static_cast<T>(p))
353 + std::pow(std::abs(t.imag()), static_cast<T>(p));
360 inline auto norm_lp(
const std::complex<T>& t,
double p)
noexcept
369#define XTENSOR_NORM_FUNCTION_AXES(NAME) \
370 template <class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS> \
371 inline auto NAME(E&& e, const I(&axes)[N], EVS es = EVS()) noexcept \
373 using axes_type = std::array<typename std::decay_t<E>::size_type, N>; \
374 return NAME(std::forward<E>(e), xtl::forward_sequence<axes_type, decltype(axes)>(axes), es); \
380 struct norm_value_type
386 struct norm_value_type<std::complex<T>>
392 using norm_value_type_t =
typename norm_value_type<T>::type;
396#define XTENSOR_COMMA ,
397#define XTENSOR_NORM_FUNCTION(NAME, RESULT_TYPE, REDUCE_EXPR, REDUCE_OP, MERGE_FUNC) \
398 template <class E, class X, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(xtl::negation<is_reducer_options<X>>)> \
399 inline auto NAME(E&& e, X&& axes, EVS es = EVS()) noexcept \
401 using value_type = typename std::decay_t<E>::value_type; \
402 using result_type = detail::norm_value_type_t<RESULT_TYPE>; \
404 auto reduce_func = [](result_type const& r, value_type const& v) \
406 return REDUCE_EXPR(r REDUCE_OP NAME(v)); \
410 make_xreducer_functor(std::move(reduce_func), const_value<result_type>(0), MERGE_FUNC<result_type>()), \
411 std::forward<E>(e), \
412 std::forward<X>(axes), \
417 template <class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_xexpression<E>)> \
418 inline auto NAME(E&& e, EVS es = EVS()) noexcept \
420 return NAME(std::forward<E>(e), arange(e.dimension()), es); \
422 XTENSOR_NORM_FUNCTION_AXES(NAME)
424 XTENSOR_NORM_FUNCTION(
norm_l0,
unsigned long long, XTENSOR_EMPTY, +, std::plus)
425 XTENSOR_NORM_FUNCTION(
norm_l1, xtl::big_promote_type_t<value_type>, XTENSOR_EMPTY, +, std::plus)
426 XTENSOR_NORM_FUNCTION(
norm_sq, xtl::big_promote_type_t<value_type>, XTENSOR_EMPTY, +, std::plus)
427 XTENSOR_NORM_FUNCTION(
429 decltype(
norm_linf(std::declval<value_type>())),
430 (std::max<result_type>),
437#undef XTENSOR_NORM_FUNCTION
438#undef XTENSOR_NORM_FUNCTION_AXES
452 template <
class E,
class X,
class EVS,
class>
467 template <
class E,
class X,
class EVS,
class>
482 template <
class E,
class X,
class EVS,
class>
493 template <
class E,
class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_xexpression<E>)>
514 class EVS = DEFAULT_STRATEGY_REDUCERS,
515 XTL_REQUIRES(is_xexpression<E>, xtl::negation<is_reducer_options<X>>)>
518 return sqrt(
norm_sq(std::forward<E>(
e), std::forward<X>(axes),
es));
521 template <
class E,
class I, std::
size_t N,
class EVS = DEFAULT_STRATEGY_REDUCERS>
522 inline auto norm_l2(E&& e,
const I (&axes)[N], EVS es = EVS()) noexcept
524 using axes_type = std::array<typename std::decay_t<E>::size_type, N>;
525 return sqrt(
norm_sq(std::forward<E>(e), xtl::forward_sequence<axes_type,
decltype(axes)>(axes), es));
540 template <
class E,
class X,
class EVS,
class>
556 template <
class E,
class X,
class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(xtl::negation<is_reducer_options<X>>)>
559 using value_type =
typename std::decay_t<E>::value_type;
569 std::forward<X>(axes),
574 template <
class E,
class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_xexpression<E>)>
575 inline auto norm_lp_to_p(E&& e,
double p, EVS es = EVS()) noexcept
580 template <
class E,
class I, std::
size_t N,
class EVS = DEFAULT_STRATEGY_REDUCERS>
581 inline auto norm_lp_to_p(E&& e,
double p,
const I (&axes)[N], EVS es = EVS()) noexcept
583 using axes_type = std::array<typename std::decay_t<E>::size_type, N>;
584 return norm_lp_to_p(std::forward<E>(e), p, xtl::forward_sequence<axes_type,
decltype(axes)>(axes), es);
600 template <
class E,
class X,
class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(xtl::negation<is_reducer_options<X>>)>
603 XTENSOR_PRECONDITION(
p != 0,
"norm_lp(): p must be nonzero, use norm_l0() instead.");
607 template <
class E,
class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_xexpression<E>)>
608 inline auto norm_lp(E&& e,
double p, EVS es = EVS())
610 return norm_lp(std::forward<E>(e), p,
arange(e.dimension()), es);
613 template <
class E,
class I, std::
size_t N,
class EVS = DEFAULT_STRATEGY_REDUCERS>
614 inline auto norm_lp(E&& e,
double p,
const I (&axes)[N], EVS es = EVS())
616 using axes_type = std::array<typename std::decay_t<E>::size_type, N>;
617 return norm_lp(std::forward<E>(e), p, xtl::forward_sequence<axes_type,
decltype(axes)>(axes), es);
629 template <
class E,
class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_xexpression<E>)>
632 XTENSOR_PRECONDITION(
634 "norm_induced_l1(): only applicable to matrices (e.dimension() must be 2)."
649 template <
class E,
class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_xexpression<E>)>
652 XTENSOR_PRECONDITION(
654 "norm_induced_linf(): only applicable to matrices (e.dimension() must be 2)."
auto sqrt(E &&e) noexcept -> detail::xfunction_type_t< math::sqrt_fun, E >
Square root function.
auto pow(E1 &&e1, E2 &&e2) noexcept -> detail::xfunction_type_t< math::pow_fun, E1, E2 >
Power function.
auto norm_sq(E &&e, X &&axes, EVS es) noexcept
Squared L2 norm of an array-like argument over given axes.
auto norm_induced_linf(E &&e, EVS es=EVS())
Induced L-infinity norm of a matrix.
auto norm_lp(E &&e, double p, X &&axes, EVS es=EVS())
Lp norm of an array-like argument over given axes.
auto norm_l2(E &&e, EVS es=EVS()) noexcept
L2 norm of a scalar or array-like argument.
auto norm_induced_l1(E &&e, EVS es=EVS())
Induced L1 norm of a matrix.
auto norm_l1(E &&e, X &&axes, EVS es) noexcept
L1 norm of an array-like argument over given axes.
auto norm_lp_to_p(E &&e, double p, X &&axes, EVS es=EVS()) noexcept
p-th power of the Lp norm of an array-like argument over given axes.
auto norm_l0(E &&e, X &&axes, EVS es) noexcept
L0 (count) pseudo-norm of an array-like argument over given axes.
auto norm_linf(E &&e, X &&axes, EVS es) noexcept
Infinity (maximum) norm of an array-like argument over given axes.
standard mathematical functions for xexpressions
auto arange(T start, T stop, S step=1) noexcept
Generates numbers evenly spaced within given half-open interval [start, stop).
auto reduce(F &&f, E &&e, X &&axes, EVS &&options=EVS())
Returns an xexpression applying the specified reducing function to an expression over the given axes.
typename squared_norm_type< T >::type squared_norm_type_t
Abbreviation of 'typename squared_norm_type<T>::type'.
typename norm_type< T >::type norm_type_t
Abbreviation of 'typename norm_type<T>::type'.
Traits class for the result type of the norm_l2() function.
Traits class for the result type of the norm_sq() function.