5 #ifndef GKO_PUBLIC_CORE_BASE_MATH_HPP_
6 #define GKO_PUBLIC_CORE_BASE_MATH_HPP_
13 #include <type_traits>
16 #include <ginkgo/config.hpp>
17 #include <ginkgo/core/base/types.hpp>
18 #include <ginkgo/core/base/utils.hpp>
108 template <
typename T>
109 struct remove_complex_impl {
116 template <
typename T>
117 struct remove_complex_impl<std::complex<T>> {
127 template <
typename T>
128 struct to_complex_impl {
129 using type = std::complex<T>;
137 template <
typename T>
138 struct to_complex_impl<std::complex<T>> {
139 using type = std::complex<T>;
143 template <
typename T>
144 struct is_complex_impl :
public std::integral_constant<bool, false> {};
146 template <
typename T>
147 struct is_complex_impl<std::complex<T>>
148 :
public std::integral_constant<bool, true> {};
151 template <
typename T>
152 struct is_complex_or_scalar_impl : std::is_scalar<T> {};
154 template <
typename T>
155 struct is_complex_or_scalar_impl<std::complex<T>> : std::is_scalar<T> {};
165 template <
template <
typename>
class converter,
typename T>
166 struct template_converter {};
177 template <
template <
typename>
class converter,
template <
typename...>
class T,
179 struct template_converter<converter, T<Rest...>> {
180 using type = T<typename converter<Rest>::type...>;
184 template <
typename T,
typename =
void>
185 struct remove_complex_s {};
193 template <
typename T>
194 struct remove_complex_s<T,
195 std::enable_if_t<is_complex_or_scalar_impl<T>::value>> {
196 using type =
typename detail::remove_complex_impl<T>::type;
205 template <
typename T>
206 struct remove_complex_s<
207 T, std::enable_if_t<!is_complex_or_scalar_impl<T>::value>> {
209 typename detail::template_converter<detail::remove_complex_impl,
214 template <
typename T,
typename =
void>
215 struct to_complex_s {};
223 template <
typename T>
224 struct to_complex_s<T, std::enable_if_t<is_complex_or_scalar_impl<T>::value>> {
225 using type =
typename detail::to_complex_impl<T>::type;
234 template <
typename T>
235 struct to_complex_s<T, std::enable_if_t<!is_complex_or_scalar_impl<T>::value>> {
237 typename detail::template_converter<detail::to_complex_impl, T>::type;
249 template <
typename T>
260 template <
typename T>
263 using type =
typename std::complex<T>::value_type;
275 template <
typename T>
285 template <
typename T>
288 return detail::is_complex_impl<T>::value;
299 template <
typename T>
309 template <
typename T>
312 return detail::is_complex_or_scalar_impl<T>::value;
324 template <
typename T>
343 template <
typename T>
352 template <
typename T>
360 template <
typename T>
361 struct next_precision_impl {};
364 struct next_precision_impl<float> {
369 struct next_precision_impl<double> {
373 template <
typename T>
374 struct next_precision_impl<std::complex<T>> {
375 using type = std::complex<typename next_precision_impl<T>::type>;
379 template <
typename T>
380 struct reduce_precision_impl {
384 template <
typename T>
385 struct reduce_precision_impl<std::complex<T>> {
386 using type = std::complex<typename reduce_precision_impl<T>::type>;
390 struct reduce_precision_impl<double> {
395 struct reduce_precision_impl<float> {
400 template <
typename T>
401 struct increase_precision_impl {
405 template <
typename T>
406 struct increase_precision_impl<std::complex<T>> {
407 using type = std::complex<typename increase_precision_impl<T>::type>;
411 struct increase_precision_impl<float> {
416 struct increase_precision_impl<half> {
421 template <
typename T>
422 struct infinity_impl {
425 static constexpr
auto value = std::numeric_limits<T>::infinity();
432 template <
typename T1,
typename T2>
433 struct highest_precision_impl {
434 using type = decltype(T1{} + T2{});
437 template <
typename T1,
typename T2>
438 struct highest_precision_impl<std::complex<T1>, std::complex<T2>> {
439 using type = std::complex<typename highest_precision_impl<T1, T2>::type>;
442 template <
typename Head,
typename... Tail>
443 struct highest_precision_variadic {
444 using type =
typename highest_precision_impl<
445 Head,
typename highest_precision_variadic<Tail...>::type>::type;
448 template <
typename Head>
449 struct highest_precision_variadic<Head> {
460 template <
typename T>
470 template <
typename T>
477 template <
typename T>
484 template <
typename T>
499 template <
typename... Ts>
501 typename detail::highest_precision_variadic<Ts...>::type;
513 template <
typename T>
529 template <
typename T>
536 template <
typename FloatType,
size_type NumComponents,
size_type ComponentId>
543 template <
typename T>
544 struct truncate_type_impl {
548 template <
typename T,
size_type Components>
549 struct truncate_type_impl<
truncated<T, Components, 0>> {
553 template <
typename T>
554 struct truncate_type_impl<std::complex<T>> {
555 using type = std::complex<typename truncate_type_impl<T>::type>;
559 template <
typename T>
560 struct type_size_impl {
561 static constexpr
auto value =
sizeof(T) *
byte_size;
564 template <
typename T>
565 struct type_size_impl<std::complex<T>> {
566 static constexpr
auto value =
sizeof(T) *
byte_size;
577 template <
typename T,
size_type Limit = sizeof(u
int16) *
byte_size>
579 std::conditional_t<detail::type_size_impl<T>::value >= 2 * Limit,
589 template <
typename S,
typename R>
597 GKO_ATTRIBUTES R
operator()(S val) {
return static_cast<R>(val); }
614 return (num + den - 1) / den;
623 template <
typename T>
639 template <
typename T>
640 GKO_INLINE constexpr T
zero(
const T&)
651 template <
typename T>
652 GKO_INLINE constexpr T
one()
667 template <
typename T>
668 GKO_INLINE constexpr T
one(
const T&)
682 template <
typename T>
685 return value == zero<T>();
697 template <
typename T>
700 return value != zero<T>();
715 template <
typename T>
716 GKO_INLINE constexpr T
max(
const T& x,
const T& y)
718 return x >= y ? x : y;
733 template <
typename T>
734 GKO_INLINE constexpr T
min(
const T& x,
const T& y)
736 return x <= y ? x : y;
752 template <
typename Ref,
typename Dummy = std::
void_t<>>
753 struct has_to_arithmetic_type : std::false_type {
754 static_assert(std::is_same<Dummy, void>::value,
755 "Do not modify the Dummy value!");
759 template <
typename Ref>
760 struct has_to_arithmetic_type<
761 Ref, std::
void_t<decltype(std::declval<Ref>().to_arithmetic_type())>>
763 using type = decltype(std::declval<Ref>().to_arithmetic_type());
771 template <
typename Ref,
typename Dummy = std::
void_t<>>
772 struct has_arithmetic_type : std::false_type {
773 static_assert(std::is_same<Dummy, void>::value,
774 "Do not modify the Dummy value!");
777 template <
typename Ref>
778 struct has_arithmetic_type<Ref, std::
void_t<typename Ref::arithmetic_type>>
793 template <
typename Ref>
794 constexpr GKO_ATTRIBUTES
795 std::enable_if_t<has_to_arithmetic_type<Ref>::value,
796 typename has_to_arithmetic_type<Ref>::type>
797 to_arithmetic_type(
const Ref& ref)
799 return ref.to_arithmetic_type();
802 template <
typename Ref>
803 constexpr GKO_ATTRIBUTES std::enable_if_t<!has_to_arithmetic_type<Ref>::value &&
804 has_arithmetic_type<Ref>::value,
805 typename Ref::arithmetic_type>
806 to_arithmetic_type(
const Ref& ref)
811 template <
typename Ref>
812 constexpr GKO_ATTRIBUTES std::enable_if_t<!has_to_arithmetic_type<Ref>::value &&
813 !has_arithmetic_type<Ref>::value,
815 to_arithmetic_type(
const Ref& ref)
824 template <
typename T>
825 GKO_ATTRIBUTES GKO_INLINE constexpr std::enable_if_t<!is_complex_s<T>::value, T>
826 real_impl(
const T& x)
831 template <
typename T>
832 GKO_ATTRIBUTES GKO_INLINE constexpr std::enable_if_t<is_complex_s<T>::value,
834 real_impl(
const T& x)
840 template <
typename T>
841 GKO_ATTRIBUTES GKO_INLINE constexpr std::enable_if_t<!is_complex_s<T>::value, T>
847 template <
typename T>
848 GKO_ATTRIBUTES GKO_INLINE constexpr std::enable_if_t<is_complex_s<T>::value,
850 imag_impl(
const T& x)
856 template <
typename T>
857 GKO_ATTRIBUTES GKO_INLINE constexpr std::enable_if_t<!is_complex_s<T>::value, T>
858 conj_impl(
const T& x)
863 template <
typename T>
864 GKO_ATTRIBUTES GKO_INLINE constexpr std::enable_if_t<is_complex_s<T>::value, T>
865 conj_impl(
const T& x)
867 return T{real_impl(x), -imag_impl(x)};
883 template <
typename T>
884 GKO_ATTRIBUTES GKO_INLINE constexpr
auto real(
const T& x)
886 return detail::real_impl(detail::to_arithmetic_type(x));
899 template <
typename T>
900 GKO_ATTRIBUTES GKO_INLINE constexpr
auto imag(
const T& x)
902 return detail::imag_impl(detail::to_arithmetic_type(x));
913 template <
typename T>
914 GKO_ATTRIBUTES GKO_INLINE constexpr
auto conj(
const T& x)
916 return detail::conj_impl(detail::to_arithmetic_type(x));
927 template <
typename T>
944 template <
typename T>
945 GKO_INLINE constexpr std::enable_if_t<!is_complex_s<T>::value, T>
abs(
948 return x >= zero<T>() ? x : -x;
952 template <
typename T>
953 GKO_INLINE constexpr std::enable_if_t<is_complex_s<T>::value, remove_complex<T>>
965 template <
typename T>
966 GKO_INLINE constexpr T
pi()
968 return static_cast<T>(3.1415926535897932384626433);
980 template <
typename T>
1001 template <
typename T>
1019 template <
typename T>
1021 const T& hint = T{1}) noexcept
1038 template <
typename T>
1039 GKO_INLINE GKO_ATTRIBUTES std::enable_if_t<!is_complex_s<T>::value,
bool>
1042 constexpr T infinity{detail::infinity_impl<T>::value};
1043 return abs(value) < infinity;
1058 template <
typename T>
1059 GKO_INLINE GKO_ATTRIBUTES std::enable_if_t<is_complex_s<T>::value,
bool>
1077 template <
typename T>
1080 return b == zero<T>() ? zero<T>() : a / b;
1093 template <
typename T>
1095 "is_nan can't be used safely on the device (MSVC+CUDA), and will thus be "
1096 "removed in a future release, without replacement")
1097 GKO_INLINE GKO_ATTRIBUTES
1101 return isnan(value);
1114 template <
typename T>
1116 "is_nan can't be used safely on the device (MSVC+CUDA), and will thus be "
1117 "removed in a future release, without replacement")
1132 template <
typename T>
1133 GKO_INLINE constexpr std::enable_if_t<!is_complex_s<T>::value, T>
nan()
1135 return std::numeric_limits<T>::quiet_NaN();
1146 template <
typename T>
1147 GKO_INLINE constexpr std::enable_if_t<is_complex_s<T>::value, T>
nan()
1156 #endif // GKO_PUBLIC_CORE_BASE_MATH_HPP_