<T>LAPACK 0.1.1
C++ Template Linear Algebra PACKage
Loading...
Searching...
No Matches
utils.hpp
Go to the documentation of this file.
1
3//
4// Copyright (c) 2017-2021, University of Tennessee. All rights reserved.
5// Copyright (c) 2021-2023, University of Colorado Denver. All rights reserved.
6//
7// This file is part of <T>LAPACK.
8// <T>LAPACK is free software: you can redistribute it and/or modify it under
9// the terms of the BSD 3-Clause license. See the accompanying LICENSE file.
10
11#ifndef TLAPACK_UTILS_HH
12#define TLAPACK_UTILS_HH
13
14#include <cmath>
15#include <limits>
16#include <type_traits>
17#include <utility>
18
24
25#ifdef TLAPACK_USE_LAPACKPP
26 #include "lapack.hh" // from LAPACK++
27#endif
28
29namespace tlapack {
30
31// C++ standard utils:
32using std::enable_if_t;
33using std::is_same_v;
34
35// C++ standard math functions:
36using std::abs;
37using std::ceil;
38using std::floor;
39using std::isinf;
40using std::isnan;
41using std::log2;
42using std::max;
43using std::min;
44using std::pow; // We only use pow(int, T), see below in the concept Real.
45using std::sqrt;
46
47// C++ standard types:
48using std::pair;
49
50// -----------------------------------------------------------------------------
51// Utility function for squaring a number to avoid using pow for everything
52template <typename T>
53constexpr T square(const T& x)
54{
55 return x * x;
56}
57
58//------------------------------------------------------------------------------
59// Extends std::real(), std::imag(), std::conj() to real numbers
60
70template <typename T, enable_if_t<is_real<T>, int> = 0>
71constexpr real_type<T> real(const T& x) noexcept
72{
73 return real_type<T>(x);
74}
75
85template <typename T, enable_if_t<is_real<T>, int> = 0>
86constexpr real_type<T> imag(const T& x) noexcept
87{
88 return real_type<T>(0);
89}
90
99template <typename T, enable_if_t<is_real<T>, int> = 0>
100constexpr T conj(const T& x) noexcept
101{
102 return x;
103}
104
105// -----------------------------------------------------------------------------
108template <typename T, enable_if_t<is_real<T>, int> = 0>
109constexpr int sgn(const T& val)
110{
111 return (T(0) < val) - (val < T(0));
112}
113
114// -----------------------------------------------------------------------------
116template <typename T, enable_if_t<is_complex<T>, int> = 0>
117constexpr bool isinf(const T& x) noexcept
118{
119 return isinf(real(x)) || isinf(imag(x));
120}
121
122// -----------------------------------------------------------------------------
124template <typename T, enable_if_t<is_complex<T>, int> = 0>
125constexpr bool isnan(const T& x) noexcept
126{
127 return isnan(real(x)) || isnan(imag(x));
128}
129
130// -----------------------------------------------------------------------------
132template <typename T>
133constexpr real_type<T> abs1(const T& x)
134{
135 return abs(real(x)) + abs(imag(x));
136}
137
138// -----------------------------------------------------------------------------
139// Internal traits: is_matrix and is_vector
140
141namespace traits {
142 namespace internal {
143 template <class T, typename = int>
144 struct has_operator_parenthesis_with_2_indexes : std::false_type {};
145
146 template <class T>
148 T,
149 enable_if_t<!is_same_v<decltype(std::declval<T>()(0, 0)), void>,
150 int>> : std::true_type {};
151
152 template <class T, typename = int>
153 struct has_operator_brackets_with_1_index : std::false_type {};
154
155 template <class T>
157 T,
158 enable_if_t<!is_same_v<decltype(std::declval<T>()[0]), void>, int>>
159 : std::true_type {};
160
161 template <class T>
162 constexpr bool is_matrix =
164
165 template <class T>
166 constexpr bool is_vector = has_operator_brackets_with_1_index<T>::value;
167 } // namespace internal
168} // namespace traits
169
170// -----------------------------------------------------------------------------
171// Specialization of traits::entry_type_trait and traits::size_type_trait
172// matrices and vectors
173
174namespace traits {
175 template <class matrix_t>
177 enable_if_t<internal::is_matrix<matrix_t> &&
178 !internal::is_vector<matrix_t>,
179 int>> {
180 using type = std::decay_t<decltype(
181 ((const matrix_t)std::declval<matrix_t>())(0, 0))>;
182 };
183
184 template <class vector_t>
186 enable_if_t<internal::is_vector<vector_t>, int>> {
187 using type = std::decay_t<decltype(
188 ((const vector_t)std::declval<vector_t>())[0])>;
189 };
190
191 template <class matrix_t>
193 enable_if_t<internal::is_matrix<matrix_t> &&
194 !internal::is_vector<matrix_t>,
195 int>> {
196 using type = std::decay_t<decltype(nrows(std::declval<matrix_t>()))>;
197 };
198
199 template <class vector_t>
201 enable_if_t<internal::is_vector<vector_t>, int>> {
202 using type = std::decay_t<decltype(size(std::declval<vector_t>()))>;
203 };
204} // namespace traits
205
206// -----------------------------------------------------------------------------
207// Optimized BLAS traits
208//
209// allow_optblas<>, enable_if_allow_optblas_t<>, disable_if_allow_optblas_t<>
210
211namespace traits {
212
213 namespace internal {
215 template <class C1, class C2, class... Cs>
216 constexpr bool has_compatible_layout =
220
221 // True if C1 and C2 are matrices with same layout.
222 // Also true if C1 or C2 are strided vectors or scalars
223 template <class C1, class C2>
224 constexpr bool has_compatible_layout<C1, C2> =
227 (layout<C1> == Layout::Strided) ||
228 (layout<C2> == Layout::Strided) || (layout<C1> == layout<C2>);
229
230 // True if C1 and C2 have compatible layouts.
231 template <class C1, class T1, class C2, class T2>
234 } // namespace internal
235
237 template <class... Types>
238 struct allow_optblas_trait : std::false_type {};
239
240 // True if C is a row- or column-major matrix and the entry type can be
241 // used with optimized BLAS implementations.
242 template <class C>
244 C,
245 enable_if_t<internal::is_matrix<C> && !internal::is_vector<C>, int>> {
246 static constexpr bool value =
247 allow_optblas_trait<type_t<C>, int>::value &&
248 (layout<C> == Layout::ColMajor || layout<C> == Layout::RowMajor);
249 };
250
251 // True if C is a strided vector and the entry type can be used with
252 // optimized BLAS implementations.
253 template <class C>
254 struct allow_optblas_trait<C, enable_if_t<internal::is_vector<C>, int>> {
255 static constexpr bool value =
256 allow_optblas_trait<type_t<C>, int>::value &&
257 (layout<C> == Layout::ColMajor || layout<C> == Layout::RowMajor ||
258 layout<C> == Layout::Strided);
259 };
260
261 // A pair of types <C,T> allows optimized BLAS if T allows optimized BLAS
262 // and one of the followings happens:
263 // 1. C is a matrix or vector that allows optimized BLAS and the entry type
264 // is the same as T.
265 // 2. C is not a matrix or vector, but is convertible to T.
266 template <class C, class T>
268 pair<C, T>,
269 enable_if_t<internal::is_matrix<C> || internal::is_vector<C>, int>> {
270 static constexpr bool value =
273 is_same_v<type_t<C>, typename std::decay<T>::type>);
274 };
275 template <class C, class T>
277 pair<C, T>,
278 enable_if_t<!internal::is_matrix<C> && !internal::is_vector<C>, int>> {
279 static constexpr bool value = allow_optblas_trait<T, int>::value &&
280 std::is_constructible<T, C>::value;
281 };
282
283 template <class C1, class T1, class C2, class T2, class... Ps>
284 struct allow_optblas_trait<pair<C1, T1>, pair<C2, T2>, Ps...> {
285 static constexpr bool value =
288 internal::has_compatible_layout<C1, C2, Ps...>;
289 };
290} // namespace traits
291
293template <class... Ts>
294constexpr bool allow_optblas = traits::allow_optblas_trait<Ts..., int>::value;
295
297template <class T1, class... Ts>
298using enable_if_allow_optblas_t = enable_if_t<(allow_optblas<T1, Ts...>), int>;
299
301template <class T1, class... Ts>
303 enable_if_t<(!allow_optblas<T1, Ts...>), int>;
304
305#ifdef TLAPACK_USE_LAPACKPP
306namespace traits {
307 template <>
308 struct allow_optblas_trait<float, int> : std::true_type {};
309 template <>
310 struct allow_optblas_trait<double, int> : std::true_type {};
311 template <>
312 struct allow_optblas_trait<std::complex<float>, int> : std::true_type {};
313 template <>
314 struct allow_optblas_trait<std::complex<double>, int> : std::true_type {};
315 template <>
316 struct allow_optblas_trait<StrongZero, int> : std::true_type {};
317} // namespace traits
318#endif // TLAPACK_USE_LAPACKPP
319
320} // namespace tlapack
321
322#endif // TLAPACK_UTILS_HH
enable_if_t<(!allow_optblas< T1, Ts... >), int > disable_if_allow_optblas_t
Disable if the list of types allows optimized BLAS library.
Definition utils.hpp:303
constexpr bool isnan(const T &x) noexcept
Extends std::isnan() to complex numbers.
Definition utils.hpp:125
enable_if_t<(allow_optblas< T1, Ts... >), int > enable_if_allow_optblas_t
Enable if the list of types allows optimized BLAS library.
Definition utils.hpp:298
constexpr real_type< T > real(const T &x) noexcept
Extends std::real() to real datatypes.
Definition utils.hpp:71
constexpr T conj(const T &x) noexcept
Extends std::conj() to real datatypes.
Definition utils.hpp:100
constexpr bool allow_optblas
True if the list of types allows optimized BLAS library.
Definition utils.hpp:294
constexpr bool has_compatible_layout
True if C1, C2, Cs... have all compatible layouts. False otherwise.
Definition utils.hpp:216
constexpr real_type< T > abs1(const T &x)
1-norm absolute value, |Re(x)| + |Im(x)|
Definition utils.hpp:133
constexpr real_type< T > imag(const T &x) noexcept
Extends std::imag() to real datatypes.
Definition utils.hpp:86
constexpr bool isinf(const T &x) noexcept
Extends std::isinf() to complex numbers.
Definition utils.hpp:117
constexpr int sgn(const T &val)
Type-safe sgn function.
Definition utils.hpp:109
typename traits::real_type_traits< Types..., int >::type real_type
The common real type of the list of types.
Definition scalar_type_traits.hpp:113
Strong zero type.
Definition StrongZero.hpp:43
Trait to determine if the list Types allows optimization.
Definition utils.hpp:238
Entry type trait.
Definition arrayTraits.hpp:40
Size type trait.
Definition arrayTraits.hpp:61