MyraMath
zhetrdU


Source: tests/dense/hetrd.cpp

1 // ========================================================================= //
2 // This file is part of MyraMath, copyright (c) 2014-2019 by Ryan A Chilton //
3 // and distributed by MyraCore, LLC. See LICENSE.txt for license terms. //
4 // ========================================================================= //
5 
11 // Containers.
13 #include <myramath/dense/Matrix.h>
15 #include <myramath/dense/Vector.h>
18 
19 // Algorithms.
20 #include <myramath/dense/gemm.h>
21 #include <myramath/dense/ormqr.h>
22 #include <myramath/dense/ormlq.h>
23 #include <myramath/dense/hetrd.h>
24 #include <myramath/dense/syev.h>
25 #include <myramath/dense/heev.h>
29 
30 // Reporting.
31 #include <tests/myratest.h>
32 
33 using namespace myra;
34 
35 namespace {
36 
37 // Tests hetrd('L'ower)
38 template<class Precision> void testL(int N, Precision tolerance)
39  {
40  typedef std::complex<Precision> Number;
41  myra::out() << typestring<Number>() << std::endl;
42 
43  // Make random complex hermitian matrix A, a few copies.
44  auto A = Matrix<Number>::random(N,N);
45  A += hermitian(A);
46  auto A1 = A;
47  auto A2 = A;
48 
49  // Tridiagonalize A = Q*T*Q'.
50  auto tau = hetrd_inplace('L',A);
51 
52  // Extract T factor from diagonal/subdiagonal of A.
53  auto T = Matrix<Precision>::zeros(N,N);
54  for (int n = 0; n < N; ++n)
55  T(n,n) = A(n,n).real();
56  for (int n = 0; n < N-1; ++n)
57  T(n+1,n) = T(n,n+1) = A(n+1,n).real();
58  auto T2 = T;
59 
60  // Verify A and T have same eigenvalues, using syevd() and heevd()
61  auto lambda_A = heev_inplace(A1);
62  auto lambda_T = syev_inplace(T);
63  Precision error1 = frobenius(lambda_A-lambda_T) / frobenius(lambda_A);
64  myra::out() << "|eig(A)-eig(T)| = " << error1 << std::endl;
65  REQUIRE(error1 < tolerance);
66 
67  // Verify Q'*A*Q = T
68  auto Q = A.bottom(N-1).left(N-1);
69  ormqr_inplace(Q,tau,A2.bottom(N-1),'L','H');
70  ormqr_inplace(Q,tau,A2.right(N-1),'R','N');
71  Precision error2 = frobenius(A2-make_complex(T2)) / frobenius(T2);
72  myra::out() << "|Q'*A*Q - T| = " << error2 << std::endl;
73  REQUIRE(error2 < tolerance);
74  }
75 
76 // Tests hetrd('U'pper)
77 template<class Precision> void testU(int N, Precision tolerance)
78  {
79  typedef std::complex<Precision> Number;
80  myra::out() << typestring<Number>() << std::endl;
81 
82  // Make random complex hermitian matrix A, a few copies.
83  auto A = Matrix<Number>::random(N,N);
84  A += hermitian(A);
85  auto A1 = A;
86  auto A2 = A;
87 
88  // Tridiagonalize A = Q'*T*Q.
89  auto tau = hetrd_inplace('U',A);
90 
91  // Extract T factor from diagonal/superdiagonal of A.
92  auto T = Matrix<Precision>::zeros(N,N);
93  for (int n = 0; n < N; ++n)
94  T(n,n) = A(n,n).real();
95  for (int n = 0; n < N-1; ++n)
96  T(n+1,n) = T(n,n+1) = A(n,n+1).real();
97  auto T2 = T;
98 
99  // Verify A and T have same eigenvalues, using syevd() and heevd()
100  auto lambda_A = heev_inplace(A1);
101  auto lambda_T = syev_inplace(T);
102  Precision error1 = frobenius(lambda_A-lambda_T) / frobenius(lambda_A);
103  myra::out() << "|eig(A)-eig(T)| = " << error1 << std::endl;
104  REQUIRE(error1 < tolerance);
105 
106  // Verify Q*A*Q' = T (ormlq)
107  auto Q = A.right(N-1).top(N-1);
108  ormlq_inplace(Q,tau,A2.bottom(N-1),'L','N');
109  ormlq_inplace(Q,tau,A2.right(N-1),'R','H');
110  Precision error2 = frobenius(A2-make_complex(T2)) / frobenius(T2);
111  myra::out() << "|Q*A*Q' - T| = " << error2 << std::endl;
112  // Note, this check will not pass with reference LAPACK/BLAS,
113  // they use a QL decomposition instead of an LQ decomposition.
114  // REQUIRE(error2 < tolerance);
115  }
116 
117 } // namespace
118 
119 ADD_TEST("chetrdL","[dense][lapack]")
120  { testL<float> (157, 1.0e-4f); }
121 
122 ADD_TEST("zhetrdL","[dense][lapack]")
123  { testL<double> (157, 1.0e-8); }
124 
125 ADD_TEST("chetrdU","[dense][lapack]")
126  { testU<float> (157, 1.0e-4f); }
127 
128 ADD_TEST("zhetrdU","[dense][lapack]")
129  { testU<double> (157, 1.0e-8); }
130 
Interface class for representing subranges of DiagonalMatrix&#39;s.
Computes all eigenpairs of real symmetric Matrix.
Interface class for representing subranges of dense Matrix&#39;s.
Routines to apply a Householder Q, as previously factored via gelqf_inplace()
Householder tridiagonalization of a complex hermitian Matrix.
static Matrix< Number > zeros(int I, int J)
Generates a zeros Matrix of specified size.
Definition: Matrix.cpp:357
Routines for computing Frobenius norms of various algebraic containers.
static Matrix< Number > random(int I, int J)
Generates a random Matrix of specified size.
Definition: Matrix.cpp:353
Replaces small values with explicit zeros.
Definition: syntax.dox:1
Various utility functions/classes related to scalar Number types.
General purpose dense matrix container, O(i*j) storage.
Computes all eigenpairs of complex hermitian Matrix.
Container for either a column vector or row vector (depends upon the usage context) ...
Routines to apply a Householder Q, as previously factored via geqrf_inplace()
Returns a hermitian copy of a Matrix. The inplace version only works on a square operand.
Expression< 1, NumberC > make_complex(const Expression< 1, NumberS > &A)
Promotes a real Expression into a complex one.
Definition: functions_complex.cpp:122
Container for a diagonal matrix, O(n) storage. Used by SVD, row/column scaling, etc.
Variety of routines all for dense Matrix*Matrix multiplies. Delegates to the BLAS.


Results: [PASS]

std::complex<double>
|eig(A)-eig(T)| = 1.65718e-15
|Q*A*Q' - T| = 2.05587e-15


Go back to Summary of /test programs.