MyraMath
dstev


Source: tests/dense/stev.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>
14 #include <myramath/dense/Vector.h>
19 
20 // Algorithms.
21 #include <myramath/dense/expr.h>
22 #include <myramath/dense/gemm.h>
23 #include <myramath/dense/dimm.h>
24 #include <myramath/dense/stev.h>
27 
28 // Reporting.
29 #include <tests/myratest.h>
30 
31 using namespace myra;
32 
33 namespace {
34 
35 // Implementation detail of all tests.
36 template<class Precision> void test_detail(Vector<Precision>& T0, Vector<Precision>& T1, Precision tolerance)
37  {
38  myra::out() << typestring<Precision>() << std::endl;
39  // Form T.
40  int N = T0.size();
41  Matrix<Precision> T(N,N);
42  for (int n = 0; n < N; ++n)
43  T(n,n) = T0(n);
44  for (int n = 0; n < N-1; ++n)
45  T(n+1,n) = T(n,n+1) = T1(n);
46  // Decompose T = X*D*X'
47  auto XD = stev(T0,T1);
48  const auto& X = XD.first;
49  const auto& D = XD.second;
50  auto I = Matrix<Precision>::identity(N);
51  // Check residual error |R|, where R = T-X*D*X'
52  Precision R_error = frobenius(T-X*D*transpose(X))/frobenius(D);
53  myra::out() << " |T-X*D*X'| = " << R_error << std::endl;
54  // Check eigenvector orthogonality, X'X = I.
55  Precision X_error = frobenius(gemm(X,'T',X)-I);
56  myra::out() << " |X'X-I| = " << X_error << std::endl;
57  // Check the layout assumptions of X (orthogonal columns)
58  int K = N/2;
59  auto Xk = X.left(K);
60  auto Ik = Matrix<Precision>::identity(K);
61  Precision Xk_error = frobenius(gemm(Xk,'T',Xk)-Ik)/N;
62  myra::out() << " |Xk'Xk-Ik| = " << Xk_error << std::endl;
63  // Verify eigenvalues are sorted in ascending order.
64  bool sorted = true;
65  for (int n = 0; n < N-1; ++n)
66  sorted &= D(n) <= D(n+1);
67  myra::out() << std::boolalpha;
68  myra::out() << " sorted D(n) <= D(n+1) = " << sorted << std::endl;
69  // Apply tests.
70  REQUIRE(R_error < tolerance);
71  REQUIRE(X_error < tolerance);
72  REQUIRE(Xk_error < tolerance);
73  REQUIRE(sorted);
74  }
75 
76 // Tests a random tridiagonal matrix.
77 template<class Precision> void test_random(int N, Precision tolerance)
78  {
79  auto T0 = Vector<Precision>::random(N);
80  auto T1 = Vector<Precision>::random(N-1);
81  test_detail(T0,T1,tolerance);
82  }
83 
84 // Tests a tridiagonal matrix with zero off-diagonal (that is, a zero within T1 vector)
85 template<class Precision> void test_split(int N, int S, Precision tolerance)
86  {
87  auto T0 = Vector<Precision>::random(N);
88  auto T1 = Vector<Precision>::random(N-1);
89  T1(S) = 0;
90  test_detail(T0,T1,tolerance);
91  }
92 
93 } // namespace
94 
95 // Random test, float precision.
96 ADD_TEST("sstev","[dense][lapack]")
97  { test_random<float>(50,1.0e-4f); }
98 
99 // Zero off-diagonal test, float precision.
100 ADD_TEST("sstev_split","[dense][lapack]")
101  { test_split<float>(100,27,1.0e-4f); }
102 
103 // Stress test for float precision, lots of sizes (N) and lots of trials (T).
104 ADD_TEST("sstev_stress","[dense][lapack][.]")
105  {
106  int N = 100;
107  int T = 10;
108  for (int n = 1; n < N; ++n)
109  for (int t = 0; t < T; ++t)
110  test_random<float>(n,1.0e-4f);
111  }
112 
113 // Random test, double precision.
114 ADD_TEST("dstev","[dense][lapack]")
115  { test_random<double>(50,1.0e-12); }
116 
117 // Zero off-diagonal test, double precision.
118 ADD_TEST("dstev_split","[dense][lapack]")
119  { test_split<double>(100,27,1.0e-12); }
120 
121 // Stress test for double precision, lots of sizes (N) and lots of trials (T).
122 ADD_TEST("dstev_stress","[dense][lapack][.]")
123  {
124  int N = 100;
125  int T = 10;
126  for (int n = 1; n < N; ++n)
127  for (int t = 0; t < T; ++t)
128  test_random<double>(n,1.0e-12);
129  }
130 
Interface class for representing subranges of DiagonalMatrix&#39;s.
Interface class for representing subranges of dense Matrix&#39;s.
Interface class for representing subranges of dense Vector&#39;s.
Routines for computing Frobenius norms of various algebraic containers.
Routines for multiplying by a DiagonalMatrix.
static Vector< Number > random(int N)
Generates a random Vector of specified size.
Definition: Vector.cpp:276
Definition: syntax.dox:1
Overloads expr() for Matrix<Number>, LowerMatrix<Number>, Vector<Number> and DiagonalMatrix<Number> ...
Returns a transposed copy of a Matrix. The inplace version only works on a square operand...
Various utility functions/classes related to scalar Number types.
static Matrix< Number > identity(int IJ)
Generates an identity Matrix of specified size.
Definition: Matrix.cpp:349
General purpose dense matrix container, O(i*j) storage.
int size() const
Size inspector.
Definition: Vector.cpp:118
Tabulates a vector of length N, allows random access.
Definition: conjugate.h:21
Container for either a column vector or row vector (depends upon the usage context) ...
Computes all eigenpairs of real symmetric tridiagonal matrix.
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]

double
|T-X*D*X'| = 4.3845e-15
|X'X-I| = 1.22716e-14
|Xk'Xk-Ik| = 1.56473e-16
sorted D(n) <= D(n+1) = true


Go back to Summary of /test programs.