mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-01-18 14:34:17 +08:00
Fix bug #836: extend SparseQR to support more columns than rows.
This commit is contained in:
parent
d73ee84d37
commit
75e574275c
@ -2,7 +2,7 @@
|
|||||||
// for linear algebra.
|
// for linear algebra.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2012-2013 Desire Nuentsa <desire.nuentsa_wakam@inria.fr>
|
// Copyright (C) 2012-2013 Desire Nuentsa <desire.nuentsa_wakam@inria.fr>
|
||||||
// Copyright (C) 2012-2013 Gael Guennebaud <gael.guennebaud@inria.fr>
|
// Copyright (C) 2012-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||||
//
|
//
|
||||||
// This Source Code Form is subject to the terms of the Mozilla
|
// This Source Code Form is subject to the terms of the Mozilla
|
||||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||||
@ -180,7 +180,7 @@ class SparseQR
|
|||||||
y.bottomRows(y.rows()-rank).setZero();
|
y.bottomRows(y.rows()-rank).setZero();
|
||||||
|
|
||||||
// Apply the column permutation
|
// Apply the column permutation
|
||||||
if (m_perm_c.size()) dest.topRows(cols()) = colsPermutation() * y.topRows(cols());
|
if (m_perm_c.size()) dest = colsPermutation() * y.topRows(cols());
|
||||||
else dest = y.topRows(cols());
|
else dest = y.topRows(cols());
|
||||||
|
|
||||||
m_info = Success;
|
m_info = Success;
|
||||||
@ -286,6 +286,7 @@ void SparseQR<MatrixType,OrderingType>::analyzePattern(const MatrixType& mat)
|
|||||||
ord(mat, m_perm_c);
|
ord(mat, m_perm_c);
|
||||||
Index n = mat.cols();
|
Index n = mat.cols();
|
||||||
Index m = mat.rows();
|
Index m = mat.rows();
|
||||||
|
Index diagSize = (std::min)(m,n);
|
||||||
|
|
||||||
if (!m_perm_c.size())
|
if (!m_perm_c.size())
|
||||||
{
|
{
|
||||||
@ -297,13 +298,13 @@ void SparseQR<MatrixType,OrderingType>::analyzePattern(const MatrixType& mat)
|
|||||||
m_outputPerm_c = m_perm_c.inverse();
|
m_outputPerm_c = m_perm_c.inverse();
|
||||||
internal::coletree(mat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
|
internal::coletree(mat, m_etree, m_firstRowElt, m_outputPerm_c.indices().data());
|
||||||
|
|
||||||
m_R.resize(n, n);
|
m_R.resize(m, n);
|
||||||
m_Q.resize(m, n);
|
m_Q.resize(m, diagSize);
|
||||||
|
|
||||||
// Allocate space for nonzero elements : rough estimation
|
// Allocate space for nonzero elements : rough estimation
|
||||||
m_R.reserve(2*mat.nonZeros()); //FIXME Get a more accurate estimation through symbolic factorization with the etree
|
m_R.reserve(2*mat.nonZeros()); //FIXME Get a more accurate estimation through symbolic factorization with the etree
|
||||||
m_Q.reserve(2*mat.nonZeros());
|
m_Q.reserve(2*mat.nonZeros());
|
||||||
m_hcoeffs.resize(n);
|
m_hcoeffs.resize(diagSize);
|
||||||
m_analysisIsok = true;
|
m_analysisIsok = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,11 +324,12 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
|
|||||||
eigen_assert(m_analysisIsok && "analyzePattern() should be called before this step");
|
eigen_assert(m_analysisIsok && "analyzePattern() should be called before this step");
|
||||||
Index m = mat.rows();
|
Index m = mat.rows();
|
||||||
Index n = mat.cols();
|
Index n = mat.cols();
|
||||||
IndexVector mark(m); mark.setConstant(-1); // Record the visited nodes
|
Index diagSize = (std::min)(m,n);
|
||||||
IndexVector Ridx(n), Qidx(m); // Store temporarily the row indexes for the current column of R and Q
|
IndexVector mark((std::max)(m,n)); mark.setConstant(-1); // Record the visited nodes
|
||||||
Index nzcolR, nzcolQ; // Number of nonzero for the current column of R and Q
|
IndexVector Ridx(n), Qidx(m); // Store temporarily the row indexes for the current column of R and Q
|
||||||
ScalarVector tval(m); // The dense vector used to compute the current column
|
Index nzcolR, nzcolQ; // Number of nonzero for the current column of R and Q
|
||||||
bool found_diag;
|
ScalarVector tval(m); // The dense vector used to compute the current column
|
||||||
|
RealScalar pivotThreshold = m_threshold;
|
||||||
|
|
||||||
m_pmat = mat;
|
m_pmat = mat;
|
||||||
m_pmat.uncompress(); // To have the innerNonZeroPtr allocated
|
m_pmat.uncompress(); // To have the innerNonZeroPtr allocated
|
||||||
@ -339,7 +341,7 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
|
|||||||
m_pmat.innerNonZeroPtr()[p] = mat.outerIndexPtr()[i+1] - mat.outerIndexPtr()[i];
|
m_pmat.innerNonZeroPtr()[p] = mat.outerIndexPtr()[i+1] - mat.outerIndexPtr()[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the default threshold, see :
|
/* Compute the default threshold as in MatLab, see:
|
||||||
* Tim Davis, "Algorithm 915, SuiteSparseQR: Multifrontal Multithreaded Rank-Revealing
|
* Tim Davis, "Algorithm 915, SuiteSparseQR: Multifrontal Multithreaded Rank-Revealing
|
||||||
* Sparse QR Factorization, ACM Trans. on Math. Soft. 38(1), 2011, Page 8:3
|
* Sparse QR Factorization, ACM Trans. on Math. Soft. 38(1), 2011, Page 8:3
|
||||||
*/
|
*/
|
||||||
@ -347,24 +349,24 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
|
|||||||
{
|
{
|
||||||
RealScalar max2Norm = 0.0;
|
RealScalar max2Norm = 0.0;
|
||||||
for (int j = 0; j < n; j++) max2Norm = (max)(max2Norm, m_pmat.col(j).norm());
|
for (int j = 0; j < n; j++) max2Norm = (max)(max2Norm, m_pmat.col(j).norm());
|
||||||
m_threshold = 20 * (m + n) * max2Norm * NumTraits<RealScalar>::epsilon();
|
pivotThreshold = 20 * (m + n) * max2Norm * NumTraits<RealScalar>::epsilon();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the numerical permutation
|
// Initialize the numerical permutation
|
||||||
m_pivotperm.setIdentity(n);
|
m_pivotperm.setIdentity(n);
|
||||||
|
|
||||||
Index nonzeroCol = 0; // Record the number of valid pivots
|
Index nonzeroCol = 0; // Record the number of valid pivots
|
||||||
|
m_Q.startVec(0);
|
||||||
|
|
||||||
// Left looking rank-revealing QR factorization: compute a column of R and Q at a time
|
// Left looking rank-revealing QR factorization: compute a column of R and Q at a time
|
||||||
for (Index col = 0; col < (std::min)(n,m); ++col)
|
for (Index col = 0; col < n; ++col)
|
||||||
{
|
{
|
||||||
mark.setConstant(-1);
|
mark.setConstant(-1);
|
||||||
m_R.startVec(col);
|
m_R.startVec(col);
|
||||||
m_Q.startVec(col);
|
|
||||||
mark(nonzeroCol) = col;
|
mark(nonzeroCol) = col;
|
||||||
Qidx(0) = nonzeroCol;
|
Qidx(0) = nonzeroCol;
|
||||||
nzcolR = 0; nzcolQ = 1;
|
nzcolR = 0; nzcolQ = 1;
|
||||||
found_diag = col>=m;
|
bool found_diag = nonzeroCol>=m;
|
||||||
tval.setZero();
|
tval.setZero();
|
||||||
|
|
||||||
// Symbolic factorization: find the nonzero locations of the column k of the factors R and Q, i.e.,
|
// Symbolic factorization: find the nonzero locations of the column k of the factors R and Q, i.e.,
|
||||||
@ -373,7 +375,7 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
|
|||||||
// thus the trick with found_diag that permits to do one more iteration on the diagonal element if this one has not been found.
|
// thus the trick with found_diag that permits to do one more iteration on the diagonal element if this one has not been found.
|
||||||
for (typename MatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp)
|
for (typename MatrixType::InnerIterator itp(m_pmat, col); itp || !found_diag; ++itp)
|
||||||
{
|
{
|
||||||
Index curIdx = nonzeroCol ;
|
Index curIdx = nonzeroCol;
|
||||||
if(itp) curIdx = itp.row();
|
if(itp) curIdx = itp.row();
|
||||||
if(curIdx == nonzeroCol) found_diag = true;
|
if(curIdx == nonzeroCol) found_diag = true;
|
||||||
|
|
||||||
@ -415,7 +417,7 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
|
|||||||
// Browse all the indexes of R(:,col) in reverse order
|
// Browse all the indexes of R(:,col) in reverse order
|
||||||
for (Index i = nzcolR-1; i >= 0; i--)
|
for (Index i = nzcolR-1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
Index curIdx = m_pivotperm.indices()(Ridx(i));
|
Index curIdx = Ridx(i);
|
||||||
|
|
||||||
// Apply the curIdx-th householder vector to the current column (temporarily stored into tval)
|
// Apply the curIdx-th householder vector to the current column (temporarily stored into tval)
|
||||||
Scalar tdot(0);
|
Scalar tdot(0);
|
||||||
@ -444,34 +446,37 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // End update current column
|
} // End update current column
|
||||||
|
|
||||||
// Compute the Householder reflection that eliminate the current column
|
|
||||||
// FIXME this step should call the Householder module.
|
|
||||||
Scalar tau;
|
Scalar tau;
|
||||||
RealScalar beta;
|
RealScalar beta = 0;
|
||||||
Scalar c0 = nzcolQ ? tval(Qidx(0)) : Scalar(0);
|
|
||||||
|
|
||||||
// First, the squared norm of Q((col+1):m, col)
|
if(nonzeroCol < diagSize)
|
||||||
RealScalar sqrNorm = 0.;
|
|
||||||
for (Index itq = 1; itq < nzcolQ; ++itq) sqrNorm += numext::abs2(tval(Qidx(itq)));
|
|
||||||
|
|
||||||
if(sqrNorm == RealScalar(0) && numext::imag(c0) == RealScalar(0))
|
|
||||||
{
|
{
|
||||||
tau = RealScalar(0);
|
// Compute the Householder reflection that eliminate the current column
|
||||||
beta = numext::real(c0);
|
// FIXME this step should call the Householder module.
|
||||||
tval(Qidx(0)) = 1;
|
Scalar c0 = nzcolQ ? tval(Qidx(0)) : Scalar(0);
|
||||||
}
|
|
||||||
else
|
// First, the squared norm of Q((col+1):m, col)
|
||||||
{
|
RealScalar sqrNorm = 0.;
|
||||||
using std::sqrt;
|
for (Index itq = 1; itq < nzcolQ; ++itq) sqrNorm += numext::abs2(tval(Qidx(itq)));
|
||||||
beta = sqrt(numext::abs2(c0) + sqrNorm);
|
if(sqrNorm == RealScalar(0) && numext::imag(c0) == RealScalar(0))
|
||||||
if(numext::real(c0) >= RealScalar(0))
|
{
|
||||||
beta = -beta;
|
tau = RealScalar(0);
|
||||||
tval(Qidx(0)) = 1;
|
beta = numext::real(c0);
|
||||||
for (Index itq = 1; itq < nzcolQ; ++itq)
|
tval(Qidx(0)) = 1;
|
||||||
tval(Qidx(itq)) /= (c0 - beta);
|
}
|
||||||
tau = numext::conj((beta-c0) / beta);
|
else
|
||||||
|
{
|
||||||
|
using std::sqrt;
|
||||||
|
beta = sqrt(numext::abs2(c0) + sqrNorm);
|
||||||
|
if(numext::real(c0) >= RealScalar(0))
|
||||||
|
beta = -beta;
|
||||||
|
tval(Qidx(0)) = 1;
|
||||||
|
for (Index itq = 1; itq < nzcolQ; ++itq)
|
||||||
|
tval(Qidx(itq)) /= (c0 - beta);
|
||||||
|
tau = numext::conj((beta-c0) / beta);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert values in R
|
// Insert values in R
|
||||||
@ -485,24 +490,25 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(abs(beta) >= m_threshold)
|
if(nonzeroCol < diagSize && abs(beta) >= pivotThreshold)
|
||||||
{
|
{
|
||||||
m_R.insertBackByOuterInner(col, nonzeroCol) = beta;
|
m_R.insertBackByOuterInner(col, nonzeroCol) = beta;
|
||||||
nonzeroCol++;
|
|
||||||
// The householder coefficient
|
// The householder coefficient
|
||||||
m_hcoeffs(col) = tau;
|
m_hcoeffs(nonzeroCol) = tau;
|
||||||
// Record the householder reflections
|
// Record the householder reflections
|
||||||
for (Index itq = 0; itq < nzcolQ; ++itq)
|
for (Index itq = 0; itq < nzcolQ; ++itq)
|
||||||
{
|
{
|
||||||
Index iQ = Qidx(itq);
|
Index iQ = Qidx(itq);
|
||||||
m_Q.insertBackByOuterInnerUnordered(col,iQ) = tval(iQ);
|
m_Q.insertBackByOuterInnerUnordered(nonzeroCol,iQ) = tval(iQ);
|
||||||
tval(iQ) = Scalar(0.);
|
tval(iQ) = Scalar(0.);
|
||||||
}
|
}
|
||||||
|
nonzeroCol++;
|
||||||
|
if(nonzeroCol<diagSize)
|
||||||
|
m_Q.startVec(nonzeroCol);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Zero pivot found: move implicitly this column to the end
|
// Zero pivot found: move implicitly this column to the end
|
||||||
m_hcoeffs(col) = Scalar(0);
|
|
||||||
for (Index j = nonzeroCol; j < n-1; j++)
|
for (Index j = nonzeroCol; j < n-1; j++)
|
||||||
std::swap(m_pivotperm.indices()(j), m_pivotperm.indices()[j+1]);
|
std::swap(m_pivotperm.indices()(j), m_pivotperm.indices()[j+1]);
|
||||||
|
|
||||||
@ -511,6 +517,8 @@ void SparseQR<MatrixType,OrderingType>::factorize(const MatrixType& mat)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_hcoeffs.tail(diagSize-nonzeroCol).setZero();
|
||||||
|
|
||||||
// Finalize the column pointers of the sparse matrices R and Q
|
// Finalize the column pointers of the sparse matrices R and Q
|
||||||
m_Q.finalize();
|
m_Q.finalize();
|
||||||
m_Q.makeCompressed();
|
m_Q.makeCompressed();
|
||||||
@ -579,14 +587,16 @@ struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived
|
|||||||
template<typename DesType>
|
template<typename DesType>
|
||||||
void evalTo(DesType& res) const
|
void evalTo(DesType& res) const
|
||||||
{
|
{
|
||||||
|
Index m = m_qr.rows();
|
||||||
Index n = m_qr.cols();
|
Index n = m_qr.cols();
|
||||||
|
Index diagSize = (std::min)(m,n);
|
||||||
res = m_other;
|
res = m_other;
|
||||||
if (m_transpose)
|
if (m_transpose)
|
||||||
{
|
{
|
||||||
eigen_assert(m_qr.m_Q.rows() == m_other.rows() && "Non conforming object sizes");
|
eigen_assert(m_qr.m_Q.rows() == m_other.rows() && "Non conforming object sizes");
|
||||||
//Compute res = Q' * other column by column
|
//Compute res = Q' * other column by column
|
||||||
for(Index j = 0; j < res.cols(); j++){
|
for(Index j = 0; j < res.cols(); j++){
|
||||||
for (Index k = 0; k < n; k++)
|
for (Index k = 0; k < diagSize; k++)
|
||||||
{
|
{
|
||||||
Scalar tau = Scalar(0);
|
Scalar tau = Scalar(0);
|
||||||
tau = m_qr.m_Q.col(k).dot(res.col(j));
|
tau = m_qr.m_Q.col(k).dot(res.col(j));
|
||||||
@ -599,10 +609,10 @@ struct SparseQR_QProduct : ReturnByValue<SparseQR_QProduct<SparseQRType, Derived
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
eigen_assert(m_qr.m_Q.rows() == m_other.rows() && "Non conforming object sizes");
|
eigen_assert(m_qr.m_Q.rows() == m_other.rows() && "Non conforming object sizes");
|
||||||
// Compute res = Q' * other column by column
|
// Compute res = Q * other column by column
|
||||||
for(Index j = 0; j < res.cols(); j++)
|
for(Index j = 0; j < res.cols(); j++)
|
||||||
{
|
{
|
||||||
for (Index k = n-1; k >=0; k--)
|
for (Index k = diagSize-1; k >=0; k--)
|
||||||
{
|
{
|
||||||
Scalar tau = Scalar(0);
|
Scalar tau = Scalar(0);
|
||||||
tau = m_qr.m_Q.col(k).dot(res.col(j));
|
tau = m_qr.m_Q.col(k).dot(res.col(j));
|
||||||
@ -636,7 +646,7 @@ struct SparseQRMatrixQReturnType : public EigenBase<SparseQRMatrixQReturnType<Sp
|
|||||||
return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
|
return SparseQRMatrixQTransposeReturnType<SparseQRType>(m_qr);
|
||||||
}
|
}
|
||||||
inline Index rows() const { return m_qr.rows(); }
|
inline Index rows() const { return m_qr.rows(); }
|
||||||
inline Index cols() const { return m_qr.cols(); }
|
inline Index cols() const { return (std::min)(m_qr.rows(),m_qr.cols()); }
|
||||||
// To use for operations with the transpose of Q
|
// To use for operations with the transpose of Q
|
||||||
SparseQRMatrixQTransposeReturnType<SparseQRType> transpose() const
|
SparseQRMatrixQTransposeReturnType<SparseQRType> transpose() const
|
||||||
{
|
{
|
||||||
|
@ -2,24 +2,24 @@
|
|||||||
// for linear algebra.
|
// for linear algebra.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2012 Desire Nuentsa Wakam <desire.nuentsa_wakam@inria.fr>
|
// Copyright (C) 2012 Desire Nuentsa Wakam <desire.nuentsa_wakam@inria.fr>
|
||||||
|
// Copyright (C) 2014 Gael Guennebaud <gael.guennebaud@inria.fr>
|
||||||
//
|
//
|
||||||
// This Source Code Form is subject to the terms of the Mozilla
|
// This Source Code Form is subject to the terms of the Mozilla
|
||||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||||
#include "sparse.h"
|
#include "sparse.h"
|
||||||
#include <Eigen/SparseQR>
|
#include <Eigen/SparseQR>
|
||||||
|
|
||||||
|
|
||||||
template<typename MatrixType,typename DenseMat>
|
template<typename MatrixType,typename DenseMat>
|
||||||
int generate_sparse_rectangular_problem(MatrixType& A, DenseMat& dA, int maxRows = 300, int maxCols = 300)
|
int generate_sparse_rectangular_problem(MatrixType& A, DenseMat& dA, int maxRows = 300, int maxCols = 150)
|
||||||
{
|
{
|
||||||
eigen_assert(maxRows >= maxCols);
|
eigen_assert(maxRows >= maxCols);
|
||||||
typedef typename MatrixType::Scalar Scalar;
|
typedef typename MatrixType::Scalar Scalar;
|
||||||
int rows = internal::random<int>(1,maxRows);
|
int rows = internal::random<int>(1,maxRows);
|
||||||
int cols = internal::random<int>(1,rows);
|
int cols = internal::random<int>(1,maxCols);
|
||||||
double density = (std::max)(8./(rows*cols), 0.01);
|
double density = (std::max)(8./(rows*cols), 0.01);
|
||||||
|
|
||||||
A.resize(rows,rows);
|
A.resize(rows,cols);
|
||||||
dA.resize(rows,rows);
|
dA.resize(rows,cols);
|
||||||
initSparse<Scalar>(density, dA, A,ForceNonZeroDiag);
|
initSparse<Scalar>(density, dA, A,ForceNonZeroDiag);
|
||||||
A.makeCompressed();
|
A.makeCompressed();
|
||||||
int nop = internal::random<int>(0, internal::random<double>(0,1) > 0.5 ? cols/2 : 0);
|
int nop = internal::random<int>(0, internal::random<double>(0,1) > 0.5 ? cols/2 : 0);
|
||||||
@ -31,6 +31,13 @@ int generate_sparse_rectangular_problem(MatrixType& A, DenseMat& dA, int maxRows
|
|||||||
A.col(j0) = s * A.col(j1);
|
A.col(j0) = s * A.col(j1);
|
||||||
dA.col(j0) = s * dA.col(j1);
|
dA.col(j0) = s * dA.col(j1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if(rows<cols) {
|
||||||
|
// A.conservativeResize(cols,cols);
|
||||||
|
// dA.conservativeResize(cols,cols);
|
||||||
|
// dA.bottomRows(cols-rows).setZero();
|
||||||
|
// }
|
||||||
|
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,11 +49,10 @@ template<typename Scalar> void test_sparseqr_scalar()
|
|||||||
MatrixType A;
|
MatrixType A;
|
||||||
DenseMat dA;
|
DenseMat dA;
|
||||||
DenseVector refX,x,b;
|
DenseVector refX,x,b;
|
||||||
SparseQR<MatrixType, AMDOrdering<int> > solver;
|
SparseQR<MatrixType, COLAMDOrdering<int> > solver;
|
||||||
generate_sparse_rectangular_problem(A,dA);
|
generate_sparse_rectangular_problem(A,dA);
|
||||||
|
|
||||||
int n = A.cols();
|
b = dA * DenseVector::Random(A.cols());
|
||||||
b = DenseVector::Random(n);
|
|
||||||
solver.compute(A);
|
solver.compute(A);
|
||||||
if (solver.info() != Success)
|
if (solver.info() != Success)
|
||||||
{
|
{
|
||||||
@ -60,17 +66,19 @@ template<typename Scalar> void test_sparseqr_scalar()
|
|||||||
std::cerr << "sparse QR factorization failed\n";
|
std::cerr << "sparse QR factorization failed\n";
|
||||||
exit(0);
|
exit(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VERIFY_IS_APPROX(A * x, b);
|
||||||
|
|
||||||
//Compare with a dense QR solver
|
//Compare with a dense QR solver
|
||||||
ColPivHouseholderQR<DenseMat> dqr(dA);
|
ColPivHouseholderQR<DenseMat> dqr(dA);
|
||||||
refX = dqr.solve(b);
|
refX = dqr.solve(b);
|
||||||
|
|
||||||
VERIFY_IS_EQUAL(dqr.rank(), solver.rank());
|
VERIFY_IS_EQUAL(dqr.rank(), solver.rank());
|
||||||
|
if(solver.rank()==A.cols()) // full rank
|
||||||
if(solver.rank()<A.cols())
|
|
||||||
VERIFY((dA * refX - b).norm() * 2 > (A * x - b).norm() );
|
|
||||||
else
|
|
||||||
VERIFY_IS_APPROX(x, refX);
|
VERIFY_IS_APPROX(x, refX);
|
||||||
|
// else
|
||||||
|
// VERIFY((dA * refX - b).norm() * 2 > (A * x - b).norm() );
|
||||||
|
|
||||||
// Compute explicitly the matrix Q
|
// Compute explicitly the matrix Q
|
||||||
MatrixType Q, QtQ, idM;
|
MatrixType Q, QtQ, idM;
|
||||||
@ -88,3 +96,4 @@ void test_sparseqr()
|
|||||||
CALL_SUBTEST_2(test_sparseqr_scalar<std::complex<double> >());
|
CALL_SUBTEST_2(test_sparseqr_scalar<std::complex<double> >());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user