MyraMath
geqpf_rank


Source: tests/dense/geqpf.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/Vector.h>
14 #include <myramath/dense/Matrix.h>
18 #include <vector>
19 
20 // Algorithms.
21 #include <myramath/dense/triu.h>
22 #include <myramath/dense/gemm.h>
23 #include <myramath/dense/geqpf.h>
24 #include <myramath/dense/orgqr.h>
25 #include <myramath/dense/swaps.h>
27 
28 // Reporting.
29 #include <tests/myratest.h>
31 
32 using namespace myra;
33 using namespace myra_stlprint;
34 
35 namespace {
36 
37 // Test for random tall/skinny A, make sure R is sorted.
38 template<class Number> void test1(typename ReflectPrecision<Number>::type tolerance)
39  {
40  typedef typename ReflectPrecision<Number>::type Precision;
41  int I = 40;
42  int J = 20;
43  auto A = Matrix<Number>::random(I,J);
44  // Factor P*A = Q*R inplace.
45  Matrix<Number> QR = A;
46  auto P_tau = geqpf_inplace(QR);
47  auto P = P_tau.first;
48  auto tau = P_tau.second;
49  // Extract R and form Q explicitly.
50  Matrix<Number> R = triu(QR);
51  MatrixRange<Number> Q = orgqr_inplace(QR,tau);
52  // Verify A = P'*Q*R
53  Matrix<Number> B = Q*R;
54  swap_columns(perm2swaps(P),B);
55  Precision error = frobenius(A-B) / frobenius(A);
56  myra::out() << "|A-P'*Q*R| = " << error << std::endl;
57  REQUIRE(error < tolerance);
58  // Verify the diagonal entries of R are sorted by modulus (big to small).
59  bool sorted = true;
60  int K = std::min(I,J);
61  for (int k = 1; k < K; ++k)
62  if ( scalar_norm1(R(k,k)) > scalar_norm1(R(k-1,k-1)) )
63  sorted = false;
64  REQUIRE(sorted);
65  }
66 
67 // Test for random short/fat A, make sure R is sorted.
68 template<class Number> void test2(typename ReflectPrecision<Number>::type tolerance)
69  {
70  typedef typename ReflectPrecision<Number>::type Precision;
71  int I = 30;
72  int J = 50;
73  auto A = Matrix<Number>::random(I,J);
74  // Factor P*A = Q*R inplace.
75  Matrix<Number> QR = A;
76  auto P_tau = geqpf_inplace(QR);
77  auto P = P_tau.first;
78  auto tau = P_tau.second;
79  // Extract R and form Q explicitly.
80  Matrix<Number> R = triu(QR);
81  MatrixRange<Number> Q = orgqr_inplace(QR,tau);
82  // Verify A = P'*Q*R
83  Matrix<Number> B = Q*R;
84  swap_columns(perm2swaps(P),B);
85  Precision error = frobenius(A-B) / frobenius(A);
86  myra::out() << "|A-P'*Q*R| = " << error << std::endl;
87  REQUIRE(error < tolerance);
88  // Verify the diagonal entries of R are sorted by modulus (big to small).
89  bool sorted = true;
90  int K = std::min(I,J);
91  for (int k = 1; k < K; ++k)
92  if ( scalar_norm1(R(k,k)) > scalar_norm1(R(k-1,k-1)) )
93  sorted = false;
94  REQUIRE(sorted);
95  }
96 
97 // Test for rank-deficient tall/skinny A, make sure its rank is revealed.
98 template<class Number> void test3(typename ReflectPrecision<Number>::type tolerance)
99  {
100  typedef typename ReflectPrecision<Number>::type Precision;
101  int I = 40;
102  int J = 10;
103  auto C = Matrix<Number>::random(I,J);
104  auto M = Matrix<Number>::random(J,2*J);
105  auto A = gemm(C,M);
106  // Factor P*A = Q*R inplace. Note A is size Ix2J, but only has J independent columns.
107  Matrix<Number> Q = A;
108  auto P_tau = geqpf_inplace(Q);
109  auto P = P_tau.first;
110  auto tau = P_tau.second;
111  // Extract R and form Q explicitly.
112  Matrix<Number> R = triu(Q);
113  orgqr_inplace(Q,tau);
114  // Verify A = P'*Q*R
115  Matrix<Number> B = Q*R;
116  swap_columns(perm2swaps(P),B);
117  Precision error = frobenius(A-B) / frobenius(A);
118  myra::out() << "|A-P'*Q*R| = " << error << std::endl;
119  REQUIRE(error < tolerance);
120  // Verify the rank of A is revealed, should be large gap between R(J-1,J-1) and R(J,J)
121  Number r00 = R(J-1,J-1);
122  Number r11 = R(J,J);
123  myra::out() << "|r00| = " << std::abs(r00) << std::endl;
124  myra::out() << "|r11| = " << std::abs(r11) << std::endl;
125  REQUIRE( std::abs(r00)*tolerance > std::abs(r11) );
126  // Check norms of R00 and R11, should be a large gap between them, too.
127  auto R00 = triu( R.top(J).left(J) );
128  auto R11 = triu( R.bottom(J).right(J) );
129  myra::out() << "|R00| = " << frobenius(R00) << std::endl;
130  myra::out() << "|R11| = " << frobenius(R11) << std::endl;
131  REQUIRE( frobenius(R00)*tolerance > frobenius(R11) );
132  }
133 
134 } // namespace
135 
136 ADD_TEST("geqpf_ts_order","[dense][lapack]")
137  {
138  test1<NumberS>(1.0e-4f);
139  test1<NumberD>(1.0e-8);
140  test1<NumberC>(1.0e-4f);
141  test1<NumberZ>(1.0e-8);
142  }
143 
144 ADD_TEST("geqpf_sf_order","[dense][lapack]")
145  {
146  test2<NumberS>(1.0e-4f);
147  test2<NumberD>(1.0e-8);
148  test2<NumberC>(1.0e-4f);
149  test2<NumberZ>(1.0e-8);
150  }
151 
152 ADD_TEST("geqpf_rank","[dense][lapack]")
153  {
154  test3<NumberS>(1.0e-4f);
155  test3<NumberD>(1.0e-8);
156  test3<NumberC>(1.0e-4f);
157  test3<NumberZ>(1.0e-8);
158  }
Routines to reconstruct a Householder Q, as previously factored via geqrf_inplace() ...
Interface class for representing subranges of dense Matrix&#39;s.
Interface class for representing subranges of dense Vector&#39;s.
Tabulates an IxJ matrix. Allows random access, has column major layout to be compatible with BLAS/LAP...
Definition: bdsqr.h:20
Routines to compute a column-pivoted Householder QR decomposition.
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
Definition: syntax.dox:1
Definition: stlprint.h:32
Returns the upper triangle of a dense Matrix.
Routines for printing the contents of various std::container&#39;s to a std::ostream using operator <<...
Various utility functions/classes related to scalar Number types.
Routines related to swap sequences, often used during pivoting.
Represents a mutable MatrixRange.
Definition: conjugate.h:26
General purpose dense matrix container, O(i*j) storage.
Container for either a column vector or row vector (depends upon the usage context) ...
Reflects Precision trait for a Number, scalar Number types should specialize it.
Definition: Number.h:33
Variety of routines all for dense Matrix*Matrix multiplies. Delegates to the BLAS.
Interface class for representing subranges of contiguous int&#39;s.


Results: [PASS]

|A-P'*Q*R| = 1.93144e-07
|r00| = 1.73843
|r11| = 1.97701e-06
|R00| = 24.1719
|R11| = 4.01636e-06
|A-P'*Q*R| = 4.49762e-16
|r00| = 1.89254
|r11| = 3.66976e-15
|R00| = 24.0342
|R11| = 9.08485e-15
|A-P'*Q*R| = 2.29179e-07
|r00| = 3.98357
|r11| = 3.58438e-06
|R00| = 43.324
|R11| = 8.74602e-06
|A-P'*Q*R| = 3.4308e-16
|r00| = 4.158
|r11| = 5.79689e-15
|R00| = 43.1554
|R11| = 1.47554e-14


Go back to Summary of /test programs.