5 #ifndef GKO_PUBLIC_CORE_BASE_MATH_HPP_
6 #define GKO_PUBLIC_CORE_BASE_MATH_HPP_
14 #include <type_traits>
17 #include <ginkgo/config.hpp>
18 #include <ginkgo/core/base/half.hpp>
19 #include <ginkgo/core/base/types.hpp>
20 #include <ginkgo/core/base/utils.hpp>
40 struct remove_complex_impl {
48 struct remove_complex_impl<std::complex<T>> {
59 struct to_complex_impl {
60 using type = std::complex<T>;
69 struct to_complex_impl<std::complex<T>> {
70 using type = std::complex<T>;
75 struct is_complex_impl :
public std::integral_constant<bool, false> {};
78 struct is_complex_impl<std::complex<T>>
79 :
public std::integral_constant<bool, true> {};
83 struct is_complex_or_scalar_impl : std::is_scalar<T> {};
86 struct is_complex_or_scalar_impl<half> : std::true_type {};
89 struct is_complex_or_scalar_impl<bfloat16> : std::true_type {};
92 struct is_complex_or_scalar_impl<std::complex<T>>
93 : is_complex_or_scalar_impl<T> {};
103 template <
template <
typename>
class converter,
typename T>
104 struct template_converter {};
115 template <
template <
typename>
class converter,
template <
typename...>
class T,
117 struct template_converter<converter, T<Rest...>> {
118 using type = T<typename converter<Rest>::type...>;
122 template <
typename T,
typename =
void>
123 struct remove_complex_s {};
131 template <
typename T>
132 struct remove_complex_s<T,
133 std::enable_if_t<is_complex_or_scalar_impl<T>::value>> {
134 using type =
typename detail::remove_complex_impl<T>::type;
143 template <
typename T>
144 struct remove_complex_s<
145 T, std::enable_if_t<!is_complex_or_scalar_impl<T>::value>> {
147 typename detail::template_converter<detail::remove_complex_impl,
152 template <
typename T,
typename =
void>
153 struct to_complex_s {};
161 template <
typename T>
162 struct to_complex_s<T, std::enable_if_t<is_complex_or_scalar_impl<T>::value>> {
163 using type =
typename detail::to_complex_impl<T>::type;
172 template <
typename T>
173 struct to_complex_s<T, std::enable_if_t<!is_complex_or_scalar_impl<T>::value>> {
175 typename detail::template_converter<detail::to_complex_impl, T>::type;
187 template <
typename T>
198 template <
typename T>
201 using type =
typename std::complex<T>::value_type;
213 template <
typename T>
223 template <
typename T>
226 return detail::is_complex_impl<T>::value;
237 template <
typename T>
247 template <
typename T>
250 return detail::is_complex_or_scalar_impl<T>::value;
262 template <
typename T>
281 template <
typename T>
290 template <
typename T>
298 template <
typename T>
299 struct next_precision_base_impl {};
302 struct next_precision_base_impl<float> {
307 struct next_precision_base_impl<double> {
311 template <
typename T>
312 struct next_precision_base_impl<std::complex<T>> {
313 using type = std::complex<typename next_precision_base_impl<T>::type>;
322 template <
typename T,
int step,
typename Visited,
typename... Rest>
323 struct find_precision_list_impl;
325 template <
typename T,
int step,
typename... Visited,
typename U,
327 struct find_precision_list_impl<T, step, std::tuple<Visited...>, U, Rest...> {
329 typename find_precision_list_impl<T, step, std::tuple<Visited..., U>,
333 template <
typename T,
int step,
typename... Visited,
typename... Rest>
334 struct find_precision_list_impl<T, step, std::tuple<Visited...>, T, Rest...> {
335 using tuple = std::tuple<T, Rest..., Visited...>;
336 constexpr
static auto tuple_size =
337 static_cast<int>(std::tuple_size_v<tuple>);
339 constexpr
static int index = (tuple_size + step % tuple_size) % tuple_size;
340 using type = std::tuple_element_t<index, tuple>;
344 template <
typename T,
int step = 1>
345 struct find_precision_impl {
346 using type =
typename find_precision_list_impl<T, step, std::tuple<>,
347 #if GINKGO_ENABLE_HALF
350 #if GINKGO_ENABLE_BFLOAT16
353 float,
double>::type;
357 template <
typename T,
int step>
358 struct find_precision_impl<std::complex<T>, step> {
359 using type = std::complex<typename find_precision_impl<T, step>::type>;
363 template <
typename T>
364 struct reduce_precision_impl {
368 template <
typename T>
369 struct reduce_precision_impl<std::complex<T>> {
370 using type = std::complex<typename reduce_precision_impl<T>::type>;
374 struct reduce_precision_impl<double> {
380 struct reduce_precision_impl<float> {
385 template <
typename T>
386 struct increase_precision_impl {
390 template <
typename T>
391 struct increase_precision_impl<std::complex<T>> {
392 using type = std::complex<typename increase_precision_impl<T>::type>;
396 struct increase_precision_impl<float> {
402 struct increase_precision_impl<
half> {
407 template <
typename T>
408 struct infinity_impl {
411 static constexpr
auto value = std::numeric_limits<T>::infinity();
418 template <
typename T1,
typename T2>
419 struct highest_precision_impl {
420 using type = decltype(T1{} + T2{});
423 template <
typename T1,
typename T2>
424 struct highest_precision_impl<std::complex<T1>, std::complex<T2>> {
425 using type = std::complex<typename highest_precision_impl<T1, T2>::type>;
428 template <
typename Head,
typename... Tail>
429 struct highest_precision_variadic {
430 using type =
typename highest_precision_impl<
431 Head,
typename highest_precision_variadic<Tail...>::type>::type;
434 template <
typename Head>
435 struct highest_precision_variadic<Head> {
446 template <
typename T>
456 template <
typename T>
464 template <
typename T,
int step = 1>
471 template <
typename T,
int step = 1>
478 template <
typename T>
485 template <
typename T>
500 template <
typename... Ts>
502 typename detail::highest_precision_variadic<Ts...>::type;
514 template <
typename T>
530 template <
typename T>
537 template <
typename FloatType,
size_type NumComponents,
size_type ComponentId>
544 template <
typename T>
545 struct truncate_type_impl {
546 using type = truncated<T, 2, 0>;
549 template <
typename T,
size_type Components>
550 struct truncate_type_impl<truncated<T, Components, 0>> {
551 using type = truncated<T, 2 * Components, 0>;
554 template <
typename T>
555 struct truncate_type_impl<std::complex<T>> {
556 using type = std::complex<typename truncate_type_impl<T>::type>;
560 template <
typename T>
561 struct type_size_impl {
562 static constexpr
auto value =
sizeof(T) *
byte_size;
565 template <
typename T>
566 struct type_size_impl<std::complex<T>> {
567 static constexpr
auto value =
sizeof(T) *
byte_size;
578 template <
typename T,
size_type Limit = sizeof(u
int16) *
byte_size>
580 std::conditional_t<detail::type_size_impl<T>::value >= 2 * Limit,
590 template <
typename S,
typename R>
598 GKO_ATTRIBUTES R
operator()(S val) {
return static_cast<R>(val); }
615 return (num + den - 1) / den;
624 template <
typename T>
640 template <
typename T>
641 GKO_INLINE constexpr T
zero(
const T&)
652 template <
typename T>
653 GKO_INLINE constexpr T
one()
659 GKO_INLINE constexpr half one<half>()
661 constexpr
auto bits = static_cast<uint16>(0b0
'01111'0000000000u);
662 return half::create_from_bits(bits);
666 GKO_INLINE constexpr bfloat16 one<bfloat16>()
668 constexpr
auto bits = static_cast<uint16>(0b0
'01111111'0000000u);
669 return bfloat16::create_from_bits(bits);
682 template <
typename T>
683 GKO_INLINE constexpr T
one(
const T&)
697 template <
typename T>
700 return value == zero<T>();
712 template <
typename T>
715 return value != zero<T>();
730 template <
typename T>
731 GKO_INLINE constexpr T
max(
const T& x,
const T& y)
733 return x >= y ? x : y;
748 template <
typename T>
749 GKO_INLINE constexpr T
min(
const T& x,
const T& y)
751 return x <= y ? x : y;
767 template <
typename Ref,
typename Dummy = std::
void_t<>>
768 struct has_to_arithmetic_type : std::false_type {
769 static_assert(std::is_same<Dummy, void>::value,
770 "Do not modify the Dummy value!");
774 template <
typename Ref>
775 struct has_to_arithmetic_type<
776 Ref, std::
void_t<decltype(std::declval<Ref>().to_arithmetic_type())>>
778 using type = decltype(std::declval<Ref>().to_arithmetic_type());
786 template <
typename Ref,
typename Dummy = std::
void_t<>>
787 struct has_arithmetic_type : std::false_type {
788 static_assert(std::is_same<Dummy, void>::value,
789 "Do not modify the Dummy value!");
792 template <
typename Ref>
793 struct has_arithmetic_type<Ref, std::
void_t<typename Ref::arithmetic_type>>
808 template <
typename Ref>
809 constexpr GKO_ATTRIBUTES
810 std::enable_if_t<has_to_arithmetic_type<Ref>::value,
811 typename has_to_arithmetic_type<Ref>::type>
812 to_arithmetic_type(
const Ref& ref)
814 return ref.to_arithmetic_type();
817 template <
typename Ref>
818 constexpr GKO_ATTRIBUTES std::enable_if_t<!has_to_arithmetic_type<Ref>::value &&
819 has_arithmetic_type<Ref>::value,
820 typename Ref::arithmetic_type>
821 to_arithmetic_type(
const Ref& ref)
826 template <
typename Ref>
827 constexpr GKO_ATTRIBUTES std::enable_if_t<!has_to_arithmetic_type<Ref>::value &&
828 !has_arithmetic_type<Ref>::value,
830 to_arithmetic_type(
const Ref& ref)
839 template <
typename T>
840 GKO_ATTRIBUTES GKO_INLINE constexpr std::enable_if_t<!is_complex_s<T>::value, T>
841 real_impl(
const T& x)
846 template <
typename T>
847 GKO_ATTRIBUTES GKO_INLINE constexpr std::enable_if_t<is_complex_s<T>::value,
849 real_impl(
const T& x)
855 template <
typename T>
856 GKO_ATTRIBUTES GKO_INLINE constexpr std::enable_if_t<!is_complex_s<T>::value, T>
862 template <
typename T>
863 GKO_ATTRIBUTES GKO_INLINE constexpr std::enable_if_t<is_complex_s<T>::value,
865 imag_impl(
const T& x)
871 template <
typename T>
872 GKO_ATTRIBUTES GKO_INLINE constexpr std::enable_if_t<!is_complex_s<T>::value, T>
873 conj_impl(
const T& x)
878 template <
typename T>
879 GKO_ATTRIBUTES GKO_INLINE constexpr std::enable_if_t<is_complex_s<T>::value, T>
880 conj_impl(
const T& x)
882 return T{real_impl(x), -imag_impl(x)};
898 template <
typename T>
899 GKO_ATTRIBUTES GKO_INLINE constexpr
auto real(
const T& x)
901 return detail::real_impl(detail::to_arithmetic_type(x));
914 template <
typename T>
915 GKO_ATTRIBUTES GKO_INLINE constexpr
auto imag(
const T& x)
917 return detail::imag_impl(detail::to_arithmetic_type(x));
928 template <
typename T>
929 GKO_ATTRIBUTES GKO_INLINE constexpr
auto conj(
const T& x)
931 return detail::conj_impl(detail::to_arithmetic_type(x));
942 template <
typename T>
960 template <
typename T>
961 GKO_INLINE constexpr std::enable_if_t<!is_complex_s<T>::value, T>
abs(
964 return x >= zero<T>() ? x : -x;
968 template <
typename T>
969 GKO_INLINE constexpr std::enable_if_t<is_complex_s<T>::value, remove_complex<T>>
976 GKO_INLINE
gko::half abs(
const std::complex<gko::half>& x)
979 return static_cast<gko::half>(
abs(std::complex<float>(x)));
985 return static_cast<gko::bfloat16>(
abs(std::complex<float>(x)));
996 GKO_INLINE std::complex<gko::half> sqrt(std::complex<gko::half> a)
998 return std::complex<gko::half>(sqrt(std::complex<float>(
999 static_cast<float>(a.real()), static_cast<float>(a.imag()))));
1007 GKO_INLINE std::complex<gko::bfloat16> sqrt(std::complex<gko::bfloat16> a)
1009 return std::complex<gko::bfloat16>(sqrt(std::complex<float>(
1010 static_cast<float>(a.real()), static_cast<float>(a.imag()))));
1019 template <
typename T>
1020 GKO_INLINE constexpr T
pi()
1022 return static_cast<T>(3.1415926535897932384626433);
1034 template <
typename T>
1055 template <
typename T>
1073 template <
typename T>
1075 const T& hint = T{1}) noexcept
1092 template <
typename T>
1093 GKO_INLINE GKO_ATTRIBUTES std::enable_if_t<!is_complex_s<T>::value,
bool>
1096 constexpr T infinity{detail::infinity_impl<T>::value};
1097 return abs(value) < infinity;
1112 template <
typename T>
1113 GKO_INLINE GKO_ATTRIBUTES std::enable_if_t<is_complex_s<T>::value,
bool>
1131 template <
typename T>
1134 return b == zero<T>() ? zero<T>() : a / b;
1147 template <
typename T>
1149 "is_nan can't be used safely on the device (MSVC+CUDA), and will thus be "
1150 "removed in a future release, without replacement")
1151 GKO_INLINE GKO_ATTRIBUTES
1155 return isnan(value);
1168 template <
typename T>
1170 "is_nan can't be used safely on the device (MSVC+CUDA), and will thus be "
1171 "removed in a future release, without replacement")
1186 template <
typename T>
1187 GKO_INLINE constexpr std::enable_if_t<!is_complex_s<T>::value, T>
nan()
1189 return std::numeric_limits<T>::quiet_NaN();
1200 template <
typename T>
1201 GKO_INLINE constexpr std::enable_if_t<is_complex_s<T>::value, T>
nan()
1210 #endif // GKO_PUBLIC_CORE_BASE_MATH_HPP_