<T>LAPACK 0.1.2
C++ Template Linear Algebra PACKage
Loading...
Searching...
No Matches
testutils.hpp
Go to the documentation of this file.
1
6//
7// Copyright (c) 2025, University of Colorado Denver. All rights reserved.
8//
9// This file is part of <T>LAPACK.
10// <T>LAPACK is free software: you can redistribute it and/or modify it under
11// the terms of the BSD 3-Clause license. See the accompanying LICENSE file.
12
13#ifndef TLAPACK_TESTUTILS_HH
14#define TLAPACK_TESTUTILS_HH
15
16// Definitions
17#include "testdefinitions.hpp"
18
19// Matrix market
20#include "MatrixMarket.hpp"
21
22// Plugin for debug
24
25// <T>LAPACK
27#include <tlapack/blas/gemm.hpp>
28#include <tlapack/blas/herk.hpp>
33
34#ifndef TLAPACK_BUILD_STANDALONE_TESTS
35 #include <catch2/catch_template_test_macros.hpp>
36 #include <catch2/generators/catch_generators.hpp>
37
39 #define SKIP_TEST return
40#else
41 #include <iostream>
42 #include <tuple>
43
45 #define SKIP_TEST return 0
46
47 // Get first argument of a variadic macro
48 #define GET_FIRST_ARG(arg1, ...) arg1
49
50 // Below, it is a solution found in
51 // https://stackoverflow.com/a/62984543/5253097
52 #define DEPAREN(X) ESC(ISH X)
53 #define ISH(...) ISH __VA_ARGS__
54 #define ESC(...) ESC_(__VA_ARGS__)
55 #define ESC_(...) VAN##__VA_ARGS__
56 #define VANISH
57
58namespace tlapack {
59namespace catch2 {
60
61 std::string return_scanf(const char*);
62 std::string return_scanf(std::string);
63
64 template <class T>
65 T return_scanf(T)
66 {
67 if constexpr (std::is_integral<T>::value) {
68 T arg;
69 std::cin >> arg;
70 return arg;
71 }
72 else if constexpr (std::is_enum<T>::value) {
73 char c;
74 std::cin >> c;
75 return T(c);
76 }
77
78 std::abort();
79 std::cout << "Include more cases here!\n";
80 return {};
81 }
82 template <class T, class U>
84 {
85 const T x = return_scanf(T());
86 const U y = return_scanf(U());
87 return pair<T, U>(x, y);
88 }
89 template <class... Ts>
90 std::tuple<Ts...> return_scanf(std::tuple<Ts...>)
91 {
92 std::tuple<Ts...> t;
93 constexpr size_t N = std::tuple_size<std::tuple<Ts...>>::value;
94 if constexpr (N > 0)
95 std::get<0>(t) = return_scanf(std::get<0>(std::tuple<Ts...>()));
96 if constexpr (N > 1)
97 std::get<1>(t) = return_scanf(std::get<1>(std::tuple<Ts...>()));
98 if constexpr (N > 2)
99 std::get<2>(t) = return_scanf(std::get<2>(std::tuple<Ts...>()));
100 if constexpr (N > 3)
101 std::get<3>(t) = return_scanf(std::get<3>(std::tuple<Ts...>()));
102 if constexpr (N > 4)
103 std::get<4>(t) = return_scanf(std::get<4>(std::tuple<Ts...>()));
104 if constexpr (N > 5)
105 std::get<5>(t) = return_scanf(std::get<5>(std::tuple<Ts...>()));
106 if constexpr (N > 6) {
107 std::abort();
108 std::cout << "Include more cases here!\n";
109 }
110 return t;
111 }
112} // namespace catch2
113} // namespace tlapack
114
115 #define TEMPLATE_TEST_CASE(TITLE, TAGS, ...) \
116 using TestType = DEPAREN(GET_FIRST_ARG(__VA_ARGS__)); \
117 int main(const int argc, const char* argv[])
118
119 #define GENERATE(...) \
120 tlapack::catch2::return_scanf(GET_FIRST_ARG(__VA_ARGS__))
121
122 #define DYNAMIC_SECTION(...) std::cout << __VA_ARGS__ << std::endl;
123
124 #define REQUIRE(cond) \
125 std::cout << #cond << ": " \
126 << (static_cast<bool>(cond) ? "true" : "false") << std::endl
127
128 #define CHECK(cond) \
129 std::cout << #cond << ": " \
130 << (static_cast<bool>(cond) ? "true" : "false") << std::endl
131
132 #define INFO(...) std::cout << __VA_ARGS__ << std::endl;
133 #define UNSCOPED_INFO(...) std::cout << __VA_ARGS__ << std::endl;
134#endif
135
136namespace tlapack {
137
148template <TLAPACK_MATRIX matrix_t>
150{
151 using idx_t = size_type<matrix_t>;
152 using T = type_t<matrix_t>;
153 using real_t = real_type<T>;
154
155 const idx_t m = nrows(Q);
156 const idx_t n = ncols(Q);
157
158 tlapack_check(nrows(res) == ncols(res));
159 tlapack_check(nrows(res) == min(m, n));
160
161 // res = I
162 laset(UPPER_TRIANGLE, (T)0.0, (T)1.0, res);
163 if (n <= m) {
164 // res = Q'Q - I
166 }
167 else {
168 // res = QQ' - I
169 herk(UPPER_TRIANGLE, NO_TRANS, (real_t)1.0, Q, (real_t)-1.0, res);
170 }
171
172 // Compute ||res||_F
174}
175
184template <TLAPACK_MATRIX matrix_t>
186{
187 using T = type_t<matrix_t>;
188 using idx_t = size_type<matrix_t>;
189
190 // Functor
192
193 const idx_t m = min(nrows(Q), ncols(Q));
194
195 std::vector<T> res_;
196 auto res = new_matrix(res_, m, m);
197 return check_orthogonality(Q, res);
198}
199
212template <TLAPACK_MATRIX matrix_t>
215{
216 using T = type_t<matrix_t>;
217 using real_t = real_type<T>;
218
219 tlapack_check(nrows(A) == ncols(A));
220 tlapack_check(nrows(Q) == ncols(Q));
221 tlapack_check(nrows(B) == ncols(B));
222 tlapack_check(nrows(res) == ncols(res));
223 tlapack_check(nrows(work) == ncols(work));
224 tlapack_check(nrows(A) == nrows(Q));
225 tlapack_check(nrows(A) == nrows(B));
226 tlapack_check(nrows(A) == nrows(res));
227 tlapack_check(nrows(A) == nrows(work));
228
229 // res = Q'*A*Q - B
230 lacpy(GENERAL, B, res);
231 gemm(CONJ_TRANS, NO_TRANS, (real_t)1.0, Q, A, work);
232 gemm(NO_TRANS, NO_TRANS, (real_t)1.0, work, Q, (real_t)-1.0, res);
233
234 // Compute ||res||_F
235 return lange(FROB_NORM, res);
236}
237
248template <TLAPACK_MATRIX matrix_t>
250 matrix_t& Q,
251 matrix_t& B)
252{
253 using T = type_t<matrix_t>;
254 using idx_t = size_type<matrix_t>;
255
256 // Functor
258
259 const idx_t n = ncols(A);
260
261 std::vector<T> res_;
262 auto res = new_matrix(res_, n, n);
263 std::vector<T> work_;
264 auto work = new_matrix(work_, n, n);
265
267}
268
282template <TLAPACK_MATRIX matrix_t>
284 matrix_t& A,
285 matrix_t& Q,
286 matrix_t& Z,
287 matrix_t& B,
288 matrix_t& res,
289 matrix_t& work)
290{
291 using T = type_t<matrix_t>;
292 using real_t = real_type<T>;
293
294 tlapack_check(nrows(A) == ncols(A));
295 tlapack_check(nrows(Q) == ncols(Q));
296 tlapack_check(nrows(Z) == ncols(Z));
297 tlapack_check(nrows(B) == ncols(B));
298 tlapack_check(nrows(res) == ncols(res));
299 tlapack_check(nrows(work) == ncols(work));
300 tlapack_check(nrows(A) == nrows(Q));
301 tlapack_check(nrows(A) == nrows(Z));
302 tlapack_check(nrows(A) == nrows(B));
303 tlapack_check(nrows(A) == nrows(res));
304 tlapack_check(nrows(A) == nrows(work));
305
306 // res = Q'*A*Q - B
307 lacpy(GENERAL, B, res);
308 gemm(CONJ_TRANS, NO_TRANS, (real_t)1.0, Q, A, work);
309 gemm(NO_TRANS, NO_TRANS, (real_t)1.0, work, Z, (real_t)-1.0, res);
310
311 // Compute ||res||_F
312 return lange(FROB_NORM, res);
313}
314
326template <TLAPACK_MATRIX matrix_t>
328 matrix_t& Q,
329 matrix_t& Z,
330 matrix_t& B)
331{
332 using T = type_t<matrix_t>;
333 using idx_t = size_type<matrix_t>;
334
335 // Functor
337
338 const idx_t n = ncols(A);
339
340 std::vector<T> res_;
341 auto res = new_matrix(res_, n, n);
342 std::vector<T> work_;
343 auto work = new_matrix(work_, n, n);
344
345 return check_similarity_transform(A, Q, Z, B, res, work);
346}
347
351template <TLAPACK_SCALAR T>
354 T beta1,
355 T beta2,
358 T beta1_ref,
359 T beta2_ref)
360{
362 using real_t = real_type<T>;
363
364 //
365 // First normalize the eigenvalue pairs
366 //
367 real_t s1 = sqrt(abs(alpha1) * abs(alpha1) + abs(beta1) * abs(beta1));
368 real_t s2 = sqrt(abs(alpha2) * abs(alpha2) + abs(beta2) * abs(beta2));
369 real_t s1_ref = sqrt(abs(alpha1_ref) * abs(alpha1_ref) +
370 abs(beta1_ref) * abs(beta1_ref));
371 real_t s2_ref = sqrt(abs(alpha2_ref) * abs(alpha2_ref) +
372 abs(beta2_ref) * abs(beta2_ref));
373
382
383 // Now compute d((a1,b1),(a1_ref,b1_ref)) = min_c ||(a1,b1) -
384 // c*(a1_ref,b1_ref)||_2 = min_{|c| = 1} ||(a1_n,b1_n) -
385 // c*(a1_ref_n,b1_ref_n)||_2
386 // = sqrt{2 - 2*|< (a1_n,b1_n), (a1_ref_n,b1_ref_n) >|}
387 // This will be used to find the best matches
388
389 // Error where we compare alpha1 with alpha1_ref and alpha2 with alpha2_ref
390 real_t err11 = real_t(2) - real_t(2) * abs(alpha1_n * conj(alpha1_ref_n) +
392 real_t err12 = real_t(2) - real_t(2) * abs(alpha2_n * conj(alpha2_ref_n) +
394
395 // Error where we compare alpha1 with alpha2_ref and alpha2 with alpha1_ref
396 real_t err21 = real_t(2) - real_t(2) * abs(alpha1_n * conj(alpha2_ref_n) +
398 real_t err22 = real_t(2) - real_t(2) * abs(alpha2_n * conj(alpha1_ref_n) +
400
401 err11 = max<real_t>(real_t(0.0), err11);
402 err12 = max<real_t>(real_t(0.0), err12);
403 err21 = max<real_t>(real_t(0.0), err21);
404 err22 = max<real_t>(real_t(0.0), err22);
405
406 if (err11 + err12 < err21 + err22) {
407 return std::make_pair(err11, err12);
408 }
409 else {
410 return std::make_pair(err21, err22);
411 }
412}
413
414//
415// GDB doesn't handle templates well, so we explicitly define some versions of
416// the functions for common template arguments
417//
418void print_matrix_r(const LegacyMatrix<float, size_t, Layout::ColMajor>& A);
419void print_matrix_d(const LegacyMatrix<double, size_t, Layout::ColMajor>& A);
420void print_matrix_c(
421 const LegacyMatrix<std::complex<float>, size_t, Layout::ColMajor>& A);
422void print_matrix_z(
423 const LegacyMatrix<std::complex<double>, size_t, Layout::ColMajor>& A);
424void print_rowmajormatrix_r(
426void print_rowmajormatrix_d(
428void print_rowmajormatrix_c(
429 const LegacyMatrix<std::complex<float>, size_t, Layout::RowMajor>& A);
430void print_rowmajormatrix_z(
431 const LegacyMatrix<std::complex<double>, size_t, Layout::RowMajor>& A);
432
433//
434// GDB doesn't handle templates well, so we explicitly define some versions of
435// the functions for common template arguments
436//
437std::string visualize_matrix_r(
439std::string visualize_matrix_d(
441std::string visualize_matrix_c(
442 const LegacyMatrix<std::complex<float>, size_t, Layout::ColMajor>& A);
443std::string visualize_matrix_z(
444 const LegacyMatrix<std::complex<double>, size_t, Layout::ColMajor>& A);
445std::string visualize_rowmajormatrix_r(
447std::string visualize_rowmajormatrix_d(
449std::string visualize_rowmajormatrix_c(
450 const LegacyMatrix<std::complex<float>, size_t, Layout::RowMajor>& A);
451std::string visualize_rowmajormatrix_z(
452 const LegacyMatrix<std::complex<double>, size_t, Layout::RowMajor>& A);
453
454} // namespace tlapack
455
456#endif // TLAPACK_TESTUTILS_HH
MaxtrixMarket class and random generators.
auto lange(norm_t normType, const matrix_t &A)
Calculates the norm of a matrix.
Definition lange.hpp:38
void laset(uplo_t uplo, const type_t< matrix_t > &alpha, const type_t< matrix_t > &beta, matrix_t &A)
Initializes a matrix to diagonal and off-diagonal values.
Definition laset.hpp:38
real_type< type_t< matrix_t > > check_generalized_similarity_transform(matrix_t &A, matrix_t &Q, matrix_t &Z, matrix_t &B, matrix_t &res, matrix_t &work)
Calculates res = Q'*A*Z - B and the frobenius norm of res.
Definition testutils.hpp:283
real_type< type_t< matrix_t > > check_orthogonality(matrix_t &Q, matrix_t &res)
Calculates res = Q'*Q - I if m <= n or res = Q*Q' otherwise Also computes the frobenius norm of res.
Definition testutils.hpp:149
void lacpy(uplo_t uplo, const matrixA_t &A, matrixB_t &B)
Copies a matrix from A to B.
Definition lacpy.hpp:38
auto lanhe(norm_t normType, uplo_t uplo, const matrix_t &A)
Calculates the norm of a hermitian matrix.
Definition lanhe.hpp:43
real_type< type_t< matrix_t > > check_similarity_transform(matrix_t &A, matrix_t &Q, matrix_t &B, matrix_t &res, matrix_t &work)
Calculates res = Q'*A*Q - B and the frobenius norm of res.
Definition testutils.hpp:213
void herk(Uplo uplo, Op trans, const alpha_t &alpha, const matrixA_t &A, const beta_t &beta, matrixC_t &C)
Hermitian rank-k update:
Definition herk.hpp:68
void gemm(Op transA, Op transB, const alpha_t &alpha, const matrixA_t &A, const matrixB_t &B, const beta_t &beta, matrixC_t &C)
General matrix-matrix multiply:
Definition gemm.hpp:61
#define tlapack_check(cond)
Throw an error if cond is false.
Definition exceptionHandling.hpp:98
Concept for matrices that can be converted to a legacy matrix.
Sort the numbers in D in increasing order (if ID = 'I') or in decreasing order (if ID = 'D' ).
Definition arrayTraits.hpp:15
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
constexpr internal::FrobNorm FROB_NORM
Frobenius norm of matrices.
Definition types.hpp:354
constexpr internal::UpperTriangle UPPER_TRIANGLE
Upper Triangle access.
Definition types.hpp:186
constexpr T conj(const T &x) noexcept
Extends std::conj() to real datatypes.
Definition utils.hpp:100
std::pair< T, T > check_generalized_eigenvalues(complex_type< T > alpha1, complex_type< T > alpha2, T beta1, T beta2, complex_type< T > alpha1_ref, complex_type< T > alpha2_ref, T beta1_ref, T beta2_ref)
Calculates the error between two pairs of generalized eigenvalues.
Definition testutils.hpp:352
constexpr internal::GeneralAccess GENERAL
General access.
Definition types.hpp:180
constexpr internal::ConjTranspose CONJ_TRANS
conjugate transpose
Definition types.hpp:264
constexpr internal::NoTranspose NO_TRANS
no transpose
Definition types.hpp:260
@ ColMajor
Column-major layout.
@ RowMajor
Row-major layout.
Definitions for the unit tests.