qr_colpivoting.cpp
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
5 // Copyright (C) 2009 Benoit Jacob <jacob.benoit.1@gmail.com>
6 //
7 // This Source Code Form is subject to the terms of the Mozilla
8 // Public License v. 2.0. If a copy of the MPL was not distributed
9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 
11 #include "main.h"
12 #include <Eigen/QR>
13 #include <Eigen/SVD>
14 
15 template <typename MatrixType>
16 void cod() {
17  Index rows = internal::random<Index>(2, EIGEN_TEST_MAX_SIZE);
18  Index cols = internal::random<Index>(2, EIGEN_TEST_MAX_SIZE);
19  Index cols2 = internal::random<Index>(2, EIGEN_TEST_MAX_SIZE);
20  Index rank = internal::random<Index>(1, (std::min)(rows, cols) - 1);
21 
22  typedef typename MatrixType::Scalar Scalar;
23  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime,
24  MatrixType::RowsAtCompileTime>
25  MatrixQType;
27  createRandomPIMatrixOfRank(rank, rows, cols, matrix);
29  VERIFY(rank == cod.rank());
30  VERIFY(cols - cod.rank() == cod.dimensionOfKernel());
31  VERIFY(!cod.isInjective());
32  VERIFY(!cod.isInvertible());
33  VERIFY(!cod.isSurjective());
34 
35  MatrixQType q = cod.householderQ();
37 
38  MatrixType z = cod.matrixZ();
40 
41  MatrixType t;
42  t.setZero(rows, cols);
43  t.topLeftCorner(rank, rank) =
44  cod.matrixT().topLeftCorner(rank, rank).template triangularView<Upper>();
45 
46  MatrixType c = q * t * z * cod.colsPermutation().inverse();
47  VERIFY_IS_APPROX(matrix, c);
48 
49  MatrixType exact_solution = MatrixType::Random(cols, cols2);
50  MatrixType rhs = matrix * exact_solution;
51  MatrixType cod_solution = cod.solve(rhs);
52  VERIFY_IS_APPROX(rhs, matrix * cod_solution);
53 
54  // Verify that we get the same minimum-norm solution as the SVD.
56  MatrixType svd_solution = svd.solve(rhs);
57  VERIFY_IS_APPROX(cod_solution, svd_solution);
58 
59  MatrixType pinv = cod.pseudoInverse();
60  VERIFY_IS_APPROX(cod_solution, pinv * rhs);
61 }
62 
63 template <typename MatrixType, int Cols2>
64 void cod_fixedsize() {
65  enum {
66  Rows = MatrixType::RowsAtCompileTime,
67  Cols = MatrixType::ColsAtCompileTime
68  };
69  typedef typename MatrixType::Scalar Scalar;
70  int rank = internal::random<int>(1, (std::min)(int(Rows), int(Cols)) - 1);
72  createRandomPIMatrixOfRank(rank, Rows, Cols, matrix);
74  VERIFY(rank == cod.rank());
75  VERIFY(Cols - cod.rank() == cod.dimensionOfKernel());
76  VERIFY(cod.isInjective() == (rank == Rows));
77  VERIFY(cod.isSurjective() == (rank == Cols));
78  VERIFY(cod.isInvertible() == (cod.isInjective() && cod.isSurjective()));
79 
80  Matrix<Scalar, Cols, Cols2> exact_solution;
81  exact_solution.setRandom(Cols, Cols2);
82  Matrix<Scalar, Rows, Cols2> rhs = matrix * exact_solution;
83  Matrix<Scalar, Cols, Cols2> cod_solution = cod.solve(rhs);
84  VERIFY_IS_APPROX(rhs, matrix * cod_solution);
85 
86  // Verify that we get the same minimum-norm solution as the SVD.
88  Matrix<Scalar, Cols, Cols2> svd_solution = svd.solve(rhs);
89  VERIFY_IS_APPROX(cod_solution, svd_solution);
90 }
91 
92 template<typename MatrixType> void qr()
93 {
94  using std::sqrt;
95 
96  Index rows = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE), cols = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE), cols2 = internal::random<Index>(2,EIGEN_TEST_MAX_SIZE);
97  Index rank = internal::random<Index>(1, (std::min)(rows, cols)-1);
98 
99  typedef typename MatrixType::Scalar Scalar;
100  typedef typename MatrixType::RealScalar RealScalar;
102  MatrixType m1;
103  createRandomPIMatrixOfRank(rank,rows,cols,m1);
105  VERIFY_IS_EQUAL(rank, qr.rank());
107  VERIFY(!qr.isInjective());
108  VERIFY(!qr.isInvertible());
109  VERIFY(!qr.isSurjective());
110 
111  MatrixQType q = qr.householderQ();
113 
114  MatrixType r = qr.matrixQR().template triangularView<Upper>();
115  MatrixType c = q * r * qr.colsPermutation().inverse();
116  VERIFY_IS_APPROX(m1, c);
117 
118  // Verify that the absolute value of the diagonal elements in R are
119  // non-increasing until they reach the singularity threshold.
120  RealScalar threshold =
122  for (Index i = 0; i < (std::min)(rows, cols) - 1; ++i) {
123  RealScalar x = numext::abs(r(i, i));
124  RealScalar y = numext::abs(r(i + 1, i + 1));
125  if (x < threshold && y < threshold) continue;
126  if (!test_isApproxOrLessThan(y, x)) {
127  for (Index j = 0; j < (std::min)(rows, cols); ++j) {
128  std::cout << "i = " << j << ", |r_ii| = " << numext::abs(r(j, j)) << std::endl;
129  }
130  std::cout << "Failure at i=" << i << ", rank=" << rank
131  << ", threshold=" << threshold << std::endl;
132  }
134  }
135 
136  MatrixType m2 = MatrixType::Random(cols,cols2);
137  MatrixType m3 = m1*m2;
138  m2 = MatrixType::Random(cols,cols2);
139  m2 = qr.solve(m3);
140  VERIFY_IS_APPROX(m3, m1*m2);
141 
142  {
143  Index size = rows;
144  do {
145  m1 = MatrixType::Random(size,size);
146  qr.compute(m1);
147  } while(!qr.isInvertible());
148  MatrixType m1_inv = qr.inverse();
149  m3 = m1 * MatrixType::Random(size,cols2);
150  m2 = qr.solve(m3);
151  VERIFY_IS_APPROX(m2, m1_inv*m3);
152  }
153 }
154 
155 template<typename MatrixType, int Cols2> void qr_fixedsize()
156 {
157  using std::sqrt;
158  using std::abs;
159  enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime };
160  typedef typename MatrixType::Scalar Scalar;
161  typedef typename MatrixType::RealScalar RealScalar;
162  int rank = internal::random<int>(1, (std::min)(int(Rows), int(Cols))-1);
164  createRandomPIMatrixOfRank(rank,Rows,Cols,m1);
166  VERIFY_IS_EQUAL(rank, qr.rank());
168  VERIFY_IS_EQUAL(qr.isInjective(), (rank == Rows));
169  VERIFY_IS_EQUAL(qr.isSurjective(), (rank == Cols));
171 
172  Matrix<Scalar,Rows,Cols> r = qr.matrixQR().template triangularView<Upper>();
174  VERIFY_IS_APPROX(m1, c);
175 
179  m2 = qr.solve(m3);
180  VERIFY_IS_APPROX(m3, m1*m2);
181  // Verify that the absolute value of the diagonal elements in R are
182  // non-increasing until they reache the singularity threshold.
183  RealScalar threshold =
184  sqrt(RealScalar(Rows)) * (std::abs)(r(0, 0)) * NumTraits<Scalar>::epsilon();
185  for (Index i = 0; i < (std::min)(int(Rows), int(Cols)) - 1; ++i) {
186  RealScalar x = numext::abs(r(i, i));
187  RealScalar y = numext::abs(r(i + 1, i + 1));
188  if (x < threshold && y < threshold) continue;
189  if (!test_isApproxOrLessThan(y, x)) {
190  for (Index j = 0; j < (std::min)(int(Rows), int(Cols)); ++j) {
191  std::cout << "i = " << j << ", |r_ii| = " << numext::abs(r(j, j)) << std::endl;
192  }
193  std::cout << "Failure at i=" << i << ", rank=" << rank
194  << ", threshold=" << threshold << std::endl;
195  }
197  }
198 }
199 
200 // This test is meant to verify that pivots are chosen such that
201 // even for a graded matrix, the diagonal of R falls of roughly
202 // monotonically until it reaches the threshold for singularity.
203 // We use the so-called Kahan matrix, which is a famous counter-example
204 // for rank-revealing QR. See
205 // http://www.netlib.org/lapack/lawnspdf/lawn176.pdf
206 // page 3 for more detail.
207 template<typename MatrixType> void qr_kahan_matrix()
208 {
209  using std::sqrt;
210  using std::abs;
211  typedef typename MatrixType::Scalar Scalar;
212  typedef typename MatrixType::RealScalar RealScalar;
213 
214  Index rows = 300, cols = rows;
215 
216  MatrixType m1;
217  m1.setZero(rows,cols);
218  RealScalar s = std::pow(NumTraits<RealScalar>::epsilon(), 1.0 / rows);
219  RealScalar c = std::sqrt(1 - s*s);
220  RealScalar pow_s_i(1.0); // pow(s,i)
221  for (Index i = 0; i < rows; ++i) {
222  m1(i, i) = pow_s_i;
223  m1.row(i).tail(rows - i - 1) = -pow_s_i * c * MatrixType::Ones(1, rows - i - 1);
224  pow_s_i *= s;
225  }
226  m1 = (m1 + m1.transpose()).eval();
228  MatrixType r = qr.matrixQR().template triangularView<Upper>();
229 
230  RealScalar threshold =
232  for (Index i = 0; i < (std::min)(rows, cols) - 1; ++i) {
233  RealScalar x = numext::abs(r(i, i));
234  RealScalar y = numext::abs(r(i + 1, i + 1));
235  if (x < threshold && y < threshold) continue;
236  if (!test_isApproxOrLessThan(y, x)) {
237  for (Index j = 0; j < (std::min)(rows, cols); ++j) {
238  std::cout << "i = " << j << ", |r_ii| = " << numext::abs(r(j, j)) << std::endl;
239  }
240  std::cout << "Failure at i=" << i << ", rank=" << qr.rank()
241  << ", threshold=" << threshold << std::endl;
242  }
244  }
245 }
246 
247 template<typename MatrixType> void qr_invertible()
248 {
249  using std::log;
250  using std::abs;
252  typedef typename MatrixType::Scalar Scalar;
253 
254  int size = internal::random<int>(10,50);
255 
256  MatrixType m1(size, size), m2(size, size), m3(size, size);
257  m1 = MatrixType::Random(size,size);
258 
260  {
261  // let's build a matrix more stable to inverse
262  MatrixType a = MatrixType::Random(size,size*2);
263  m1 += a * a.adjoint();
264  }
265 
267  m3 = MatrixType::Random(size,size);
268  m2 = qr.solve(m3);
269  //VERIFY_IS_APPROX(m3, m1*m2);
270 
271  // now construct a matrix with prescribed determinant
272  m1.setZero();
273  for(int i = 0; i < size; i++) m1(i,i) = internal::random<Scalar>();
274  RealScalar absdet = abs(m1.diagonal().prod());
275  m3 = qr.householderQ(); // get a unitary
276  m1 = m3 * m1 * m3;
277  qr.compute(m1);
278  VERIFY_IS_APPROX(absdet, qr.absDeterminant());
279  VERIFY_IS_APPROX(log(absdet), qr.logAbsDeterminant());
280 }
281 
282 template<typename MatrixType> void qr_verify_assert()
283 {
284  MatrixType tmp;
285 
288  VERIFY_RAISES_ASSERT(qr.solve(tmp))
297 }
298 
300 {
301  for(int i = 0; i < g_repeat; i++) {
302  CALL_SUBTEST_1( qr<MatrixXf>() );
303  CALL_SUBTEST_2( qr<MatrixXd>() );
304  CALL_SUBTEST_3( qr<MatrixXcd>() );
305  CALL_SUBTEST_4(( qr_fixedsize<Matrix<float,3,5>, 4 >() ));
306  CALL_SUBTEST_5(( qr_fixedsize<Matrix<double,6,2>, 3 >() ));
307  CALL_SUBTEST_5(( qr_fixedsize<Matrix<double,1,1>, 1 >() ));
308  }
309 
310  for(int i = 0; i < g_repeat; i++) {
311  CALL_SUBTEST_1( cod<MatrixXf>() );
312  CALL_SUBTEST_2( cod<MatrixXd>() );
313  CALL_SUBTEST_3( cod<MatrixXcd>() );
314  CALL_SUBTEST_4(( cod_fixedsize<Matrix<float,3,5>, 4 >() ));
315  CALL_SUBTEST_5(( cod_fixedsize<Matrix<double,6,2>, 3 >() ));
316  CALL_SUBTEST_5(( cod_fixedsize<Matrix<double,1,1>, 1 >() ));
317  }
318 
319  for(int i = 0; i < g_repeat; i++) {
320  CALL_SUBTEST_1( qr_invertible<MatrixXf>() );
321  CALL_SUBTEST_2( qr_invertible<MatrixXd>() );
322  CALL_SUBTEST_6( qr_invertible<MatrixXcf>() );
323  CALL_SUBTEST_3( qr_invertible<MatrixXcd>() );
324  }
325 
326  CALL_SUBTEST_7(qr_verify_assert<Matrix3f>());
327  CALL_SUBTEST_8(qr_verify_assert<Matrix3d>());
328  CALL_SUBTEST_1(qr_verify_assert<MatrixXf>());
329  CALL_SUBTEST_2(qr_verify_assert<MatrixXd>());
330  CALL_SUBTEST_6(qr_verify_assert<MatrixXcf>());
331  CALL_SUBTEST_3(qr_verify_assert<MatrixXcd>());
332 
333  // Test problem size constructors
334  CALL_SUBTEST_9(ColPivHouseholderQR<MatrixXf>(10, 20));
335 
336  CALL_SUBTEST_1( qr_kahan_matrix<MatrixXf>() );
337  CALL_SUBTEST_2( qr_kahan_matrix<MatrixXd>() );
338 }
void test_qr_colpivoting()
const PermutationType & colsPermutation() const
SCALAR Scalar
Definition: bench_gemm.cpp:33
#define VERIFY_RAISES_ASSERT(a)
Definition: main.h:285
cout<< "Here is the matrix m:"<< endl<< m<< endl;JacobiSVD< MatrixXf > svd(m, ComputeThinU|ComputeThinV)
const Solve< CompleteOrthogonalDecomposition, Rhs > solve(const MatrixBase< Rhs > &b) const
const Inverse< ColPivHouseholderQR > inverse() const
Scalar * y
return int(ret)+1
const Solve< ColPivHouseholderQR, Rhs > solve(const MatrixBase< Rhs > &b) const
#define min(a, b)
Definition: datatypes.h:19
MatrixType::RealScalar logAbsDeterminant() const
MatrixType m2(n_dims)
Scalar Scalar * c
Definition: benchVecAdd.cpp:17
EIGEN_DEVICE_FUNC const LogReturnType log() const
EIGEN_DEVICE_FUNC const SqrtReturnType sqrt() const
MatrixXf MatrixType
Holds information about the various numeric (i.e. scalar) types allowed by Eigen. ...
Definition: NumTraits.h:150
HouseholderSequenceType householderQ(void) const
void cod_fixedsize()
Complete orthogonal decomposition (COD) of a matrix.
void cod()
static double epsilon
Definition: testRot3.cpp:39
Array33i a
void qr_invertible()
bool test_isApproxOrLessThan(const Real &a, const Real &b)
Scalar Scalar int size
Definition: benchVecAdd.cpp:17
#define VERIFY_IS_APPROX(a, b)
ColPivHouseholderQR & compute(const EigenBase< InputType > &matrix)
#define VERIFY_IS_EQUAL(a, b)
Definition: main.h:331
void qr()
Matrix3d m1
Definition: IOFormat.cpp:2
const MatrixType & matrixQR() const
static int g_repeat
Definition: main.h:144
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:33
HouseholderSequenceType householderQ() const
RealScalar s
EIGEN_DEVICE_FUNC const Scalar & q
NumTraits< Scalar >::Real RealScalar
Definition: bench_gemm.cpp:34
void qr_kahan_matrix()
static const int Cols
InverseReturnType inverse() const
MatrixType::RealScalar absDeterminant() const
#define VERIFY(a)
Definition: main.h:325
#define EIGEN_TEST_MAX_SIZE
void qr_verify_assert()
#define VERIFY_IS_UNITARY(a)
Definition: main.h:340
Two-sided Jacobi SVD decomposition of a rectangular matrix.
void qr_fixedsize()
#define VERIFY_IS_APPROX_OR_LESS_THAN(a, b)
Definition: main.h:337
void createRandomPIMatrixOfRank(Index desired_rank, Index rows, Index cols, MatrixType &m)
Definition: main.h:603
internal::nested_eval< T, 1 >::type eval(const T &xpr)
Jet< T, N > pow(const Jet< T, N > &f, double g)
Definition: jet.h:570
Map< Matrix< T, Dynamic, Dynamic, ColMajor >, 0, OuterStride<> > matrix(T *data, int rows, int cols, int stride)
The matrix class, also used for vectors and row-vectors.
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
#define abs(x)
Definition: datatypes.h:17
Matrix< _Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols > & setRandom(Index size)
const Solve< JacobiSVD< _MatrixType, QRPreconditioner >, Rhs > solve(const MatrixBase< Rhs > &b) const
Definition: SVDBase.h:208
std::ptrdiff_t j
Point2 t(10, 10)
const Inverse< CompleteOrthogonalDecomposition > pseudoInverse() const


gtsam
Author(s):
autogenerated on Sat May 8 2021 02:43:46