sparseqr.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. // This file is part of Eigen, a lightweight C++ template library
  2. // for linear algebra.
  3. //
  4. // Copyright (C) 2012 Desire Nuentsa Wakam <desire.nuentsa_wakam@inria.fr>
  5. // Copyright (C) 2014 Gael Guennebaud <gael.guennebaud@inria.fr>
  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. #include "sparse.h"
  10. #include <Eigen/SparseQR>
  11. template<typename MatrixType,typename DenseMat>
  12. int generate_sparse_rectangular_problem(MatrixType& A, DenseMat& dA, int maxRows = 300, int maxCols = 150)
  13. {
  14. eigen_assert(maxRows >= maxCols);
  15. typedef typename MatrixType::Scalar Scalar;
  16. int rows = internal::random<int>(1,maxRows);
  17. int cols = internal::random<int>(1,maxCols);
  18. double density = (std::max)(8./(rows*cols), 0.01);
  19. A.resize(rows,cols);
  20. dA.resize(rows,cols);
  21. initSparse<Scalar>(density, dA, A,ForceNonZeroDiag);
  22. A.makeCompressed();
  23. int nop = internal::random<int>(0, internal::random<double>(0,1) > 0.5 ? cols/2 : 0);
  24. for(int k=0; k<nop; ++k)
  25. {
  26. int j0 = internal::random<int>(0,cols-1);
  27. int j1 = internal::random<int>(0,cols-1);
  28. Scalar s = internal::random<Scalar>();
  29. A.col(j0) = s * A.col(j1);
  30. dA.col(j0) = s * dA.col(j1);
  31. }
  32. // if(rows<cols) {
  33. // A.conservativeResize(cols,cols);
  34. // dA.conservativeResize(cols,cols);
  35. // dA.bottomRows(cols-rows).setZero();
  36. // }
  37. return rows;
  38. }
  39. template<typename Scalar> void test_sparseqr_scalar()
  40. {
  41. typedef SparseMatrix<Scalar,ColMajor> MatrixType;
  42. typedef Matrix<Scalar,Dynamic,Dynamic> DenseMat;
  43. typedef Matrix<Scalar,Dynamic,1> DenseVector;
  44. MatrixType A;
  45. DenseMat dA;
  46. DenseVector refX,x,b;
  47. SparseQR<MatrixType, COLAMDOrdering<int> > solver;
  48. generate_sparse_rectangular_problem(A,dA);
  49. b = dA * DenseVector::Random(A.cols());
  50. solver.compute(A);
  51. // Q should be MxM
  52. VERIFY_IS_EQUAL(solver.matrixQ().rows(), A.rows());
  53. VERIFY_IS_EQUAL(solver.matrixQ().cols(), A.rows());
  54. // R should be MxN
  55. VERIFY_IS_EQUAL(solver.matrixR().rows(), A.rows());
  56. VERIFY_IS_EQUAL(solver.matrixR().cols(), A.cols());
  57. // Q and R can be multiplied
  58. DenseMat recoveredA = solver.matrixQ()
  59. * DenseMat(solver.matrixR().template triangularView<Upper>())
  60. * solver.colsPermutation().transpose();
  61. VERIFY_IS_EQUAL(recoveredA.rows(), A.rows());
  62. VERIFY_IS_EQUAL(recoveredA.cols(), A.cols());
  63. // and in the full rank case the original matrix is recovered
  64. if (solver.rank() == A.cols())
  65. {
  66. VERIFY_IS_APPROX(A, recoveredA);
  67. }
  68. if(internal::random<float>(0,1)>0.5f)
  69. solver.factorize(A); // this checks that calling analyzePattern is not needed if the pattern do not change.
  70. if (solver.info() != Success)
  71. {
  72. std::cerr << "sparse QR factorization failed\n";
  73. exit(0);
  74. return;
  75. }
  76. x = solver.solve(b);
  77. if (solver.info() != Success)
  78. {
  79. std::cerr << "sparse QR factorization failed\n";
  80. exit(0);
  81. return;
  82. }
  83. VERIFY_IS_APPROX(A * x, b);
  84. //Compare with a dense QR solver
  85. ColPivHouseholderQR<DenseMat> dqr(dA);
  86. refX = dqr.solve(b);
  87. VERIFY_IS_EQUAL(dqr.rank(), solver.rank());
  88. if(solver.rank()==A.cols()) // full rank
  89. VERIFY_IS_APPROX(x, refX);
  90. // else
  91. // VERIFY((dA * refX - b).norm() * 2 > (A * x - b).norm() );
  92. // Compute explicitly the matrix Q
  93. MatrixType Q, QtQ, idM;
  94. Q = solver.matrixQ();
  95. //Check ||Q' * Q - I ||
  96. QtQ = Q * Q.adjoint();
  97. idM.resize(Q.rows(), Q.rows()); idM.setIdentity();
  98. VERIFY(idM.isApprox(QtQ));
  99. // Q to dense
  100. DenseMat dQ;
  101. dQ = solver.matrixQ();
  102. VERIFY_IS_APPROX(Q, dQ);
  103. }
  104. void test_sparseqr()
  105. {
  106. for(int i=0; i<g_repeat; ++i)
  107. {
  108. CALL_SUBTEST_1(test_sparseqr_scalar<double>());
  109. CALL_SUBTEST_2(test_sparseqr_scalar<std::complex<double> >());
  110. }
  111. }