MyraMath
sbdsqr_split1


Source: tests/dense/bdsqr.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/diag.h>
22 #include <myramath/dense/dimm.h>
23 #include <myramath/dense/gemm.h>
24 #include <myramath/dense/bdsqr.h>
28 
29 // Reporting.
30 #include <tests/myratest.h>
31 
32 using namespace myra;
33 
34 namespace {
35 
36 // Implementation detail of all tests.
37 template<class Precision> void test_detail(Vector<Precision>& B0, Vector<Precision>& B1, Precision tolerance)
38  {
39  myra::out() << typestring<Precision>() << std::endl;
40  // Form B.
41  int N = B0.size();
42  auto B = Matrix<Precision>::zeros(N,N);
43  for (int n = 0; n < N; ++n)
44  B(n,n) = B0(n);
45  for (int n = 0; n < N-1; ++n)
46  B(n,n+1) = B1(n);
47  // Decompose B = U*S*V'
48  auto UVt = bdsqr_inplace(B0,B1);
49  const Matrix<Precision>& U = UVt.first;
50  const Matrix<Precision>& Vt = UVt.second;
51  DiagonalMatrix<Precision> S = diag(B0);
52  // Check residual error |R|, where R = B-U*S*V'
53  Precision R_error = frobenius(B-U*S*Vt)/frobenius(S);
54  myra::out() << " |B-U*S*V'| = " << R_error << std::endl;
55  // Check orthogonality of U and V.
56  auto I = Matrix<Precision>::identity(N);
57  Precision U_error = frobenius(gemm(U,'T',U)-I)/N;
58  Precision V_error = frobenius(gemm(Vt,Vt,'T')-I)/N;
59  myra::out() << " |U'U-I| = " << U_error << std::endl;
60  myra::out() << " |VV'-I| = " << V_error << std::endl;
61  // Check the layout assumptions of U (orthogonal columns) and Vt (orthogonal rows).
62  int K = N/2;
63  auto Uk = U.left(K);
64  auto Vk = Vt.top(K);
65  auto Ik = Matrix<Precision>::identity(K);
66  Precision Uk_error = frobenius(gemm(Uk,'T',Uk)-Ik)/N;
67  Precision Vk_error = frobenius(gemm(Vk,Vk,'T')-Ik)/N;
68  myra::out() << " |Uk'Uk-Ik| = " << Uk_error << std::endl;
69  myra::out() << " |Vk'Vk-Ik| = " << Vk_error << std::endl;
70  // Verify singular values are all positive.
71  bool positive = true;
72  for (int n = 0; n < N; ++n)
73  positive &= S(n) >= 0;
74  myra::out() << std::boolalpha;
75  myra::out() << " positive S >= 0 = " << positive << std::endl;
76  // Verify singular are sorted in descending order.
77  bool sorted = true;
78  for (int n = 0; n < N-1; ++n)
79  sorted &= S(n) >= S(n+1);
80  myra::out() << std::boolalpha;
81  myra::out() << " sorted S(n) >= S(n+1) = " << sorted << std::endl;
82  myra::out() << std::endl;
83  // Apply tests.
84  REQUIRE(R_error < tolerance);
85  REQUIRE(U_error < tolerance);
86  REQUIRE(V_error < tolerance);
87  REQUIRE(Uk_error < tolerance);
88  REQUIRE(Vk_error < tolerance);
89  REQUIRE(positive);
90  REQUIRE(sorted);
91  }
92 
93 // Tests a random bidiagonal matrix.
94 template<class Precision> void test_random(int N, Precision tolerance)
95  {
96  auto B0 = Vector<Precision>::random(N);
97  auto B1 = Vector<Precision>::random(N-1);
98  test_detail(B0,B1,tolerance);
99  }
100 
101 // Tests a bidiagonal matrix with zero diagonal (that is, a zero within B0 vector)
102 template<class Precision> void test_split0(int N, int S, Precision tolerance)
103  {
104  auto B0 = Vector<Precision>::random(N);
105  auto B1 = Vector<Precision>::random(N-1);
106  B0(S) = 0;
107  test_detail(B0,B1,tolerance);
108  }
109 
110 // Tests a bidiagonal matrix with zero off-diagonal (that is, a zero within B1 vector)
111 template<class Precision> void test_split1(int N, int S, Precision tolerance)
112  {
113  auto B0 = Vector<Precision>::random(N);
114  auto B1 = Vector<Precision>::random(N-1);
115  B1(S) = 0;
116  test_detail(B0,B1,tolerance);
117  }
118 
119 } // namespace
120 
121 // Random test, float precision.
122 ADD_TEST("sbdsqr","[dense][lapack]")
123  { test_random<float>(50,1.0e-4f); }
124 
125 // Zero diagonal test, float precision.
126 ADD_TEST("sbdsqr_split0","[dense][lapack]")
127  { test_split0<float>(100,27,1.0e-4f); }
128 
129 // Zero off-diagonal test, float precision.
130 ADD_TEST("sbdsqr_split1","[dense][lapack]")
131  { test_split1<float>(100,27,1.0e-4f); }
132 
133 // Stress test for float precision, lots of sizes (N) and lots of trials (T).
134 ADD_TEST("sbdsqr_stress","[dense][lapack][.]")
135  {
136  int N = 100;
137  int T = 10;
138  for (int n = 1; n < N; ++n)
139  for (int t = 0; t < T; ++t)
140  test_random<float>(n,1.0e-4f);
141  }
142 
143 // Random test, double precision.
144 ADD_TEST("dbdsqr","[dense][lapack]")
145  { test_random<double>(10,1.0e-12); }
146 
147 // Zero diagonal test, double precision.
148 ADD_TEST("dbdsqr_split0","[dense][lapack]")
149  { test_split0<double>(100,27,1.0e-12); }
150 
151 // Zero off-diagonal test, double precision.
152 ADD_TEST("dbdsqr_split1","[dense][lapack]")
153  { test_split1<double>(100,27,1.0e-12); }
154 
155 // Stress test for double precision, lots of sizes (N) and lots of trials (T).
156 ADD_TEST("dbdsqr_stress","[dense][lapack][.]")
157  {
158  int N = 100;
159  int T = 10;
160  for (int n = 1; n < N; ++n)
161  for (int t = 0; t < T; ++t)
162  test_random<double>(n,1.0e-12);
163  }
164 
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.
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.
Replaces small values with explicit zeros.
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
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) ...
Returns the diagonal of a dense Matrix or LowerMatrix.
CMatrixRange< Number > left(int j) const
Returns a MatrixRange over the j leftmost columns, this(:,0:j)
Definition: Matrix.cpp:263
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.
Computes all singular triples (u,s,v) of a real bidiagonal matrix.
CMatrixRange< Number > top(int i) const
Returns a MatrixRange over the i topmost rows, this(0:i,:)
Definition: Matrix.cpp:207


Results: [PASS]

float
|B-U*S*V'| = 4.69289e-06
|U'U-I| = 8.21543e-08
|VV'-I| = 7.43378e-08
|Uk'Uk-Ik| = 6.1899e-08
|Vk'Vk-Ik| = 4.91771e-08
positive S >= 0 = true
sorted S(n) >= S(n+1) = true


Go back to Summary of /test programs.