mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-08-12 11:49:02 +08:00
bug #206 - part 4: Removes heap allocations from JacobiSVD and its preconditioners
This commit is contained in:
parent
5e431779f3
commit
4477843bdd
@ -562,7 +562,7 @@ public:
|
||||
// and v_k is the k-th Householder vector [1,m_qr(k+1,k), m_qr(k+2,k), ...]
|
||||
const Index rows = m_qr.rows();
|
||||
const Index cols = m_qr.cols();
|
||||
const Index size = std::min(rows, cols);
|
||||
const Index size = (std::min)(rows, cols);
|
||||
workspace.resize(rows);
|
||||
result.setIdentity(rows, rows);
|
||||
for (Index k = size-1; k >= 0; k--)
|
||||
|
@ -61,9 +61,12 @@ template<typename MatrixType, int QRPreconditioner, int Case,
|
||||
> struct qr_preconditioner_impl {};
|
||||
|
||||
template<typename MatrixType, int QRPreconditioner, int Case>
|
||||
struct qr_preconditioner_impl<MatrixType, QRPreconditioner, Case, false>
|
||||
class qr_preconditioner_impl<MatrixType, QRPreconditioner, Case, false>
|
||||
{
|
||||
static bool run(JacobiSVD<MatrixType, QRPreconditioner>&, const MatrixType&)
|
||||
public:
|
||||
typedef typename MatrixType::Index Index;
|
||||
void allocate(const JacobiSVD<MatrixType, QRPreconditioner>&) {}
|
||||
bool run(JacobiSVD<MatrixType, QRPreconditioner>&, const MatrixType&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -72,134 +75,279 @@ struct qr_preconditioner_impl<MatrixType, QRPreconditioner, Case, false>
|
||||
/*** preconditioner using FullPivHouseholderQR ***/
|
||||
|
||||
template<typename MatrixType>
|
||||
struct qr_preconditioner_impl<MatrixType, FullPivHouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
|
||||
class qr_preconditioner_impl<MatrixType, FullPivHouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
|
||||
{
|
||||
static bool run(JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
|
||||
public:
|
||||
typedef typename MatrixType::Index Index;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
enum
|
||||
{
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime
|
||||
};
|
||||
typedef Matrix<Scalar, 1, RowsAtCompileTime, RowMajor, 1, MaxRowsAtCompileTime> WorkspaceType;
|
||||
|
||||
void allocate(const JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& svd)
|
||||
{
|
||||
if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols())
|
||||
{
|
||||
m_qr = FullPivHouseholderQR<MatrixType>(svd.rows(), svd.cols());
|
||||
}
|
||||
if (svd.m_computeFullU) m_workspace.resize(svd.rows());
|
||||
}
|
||||
|
||||
bool run(JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
|
||||
{
|
||||
if(matrix.rows() > matrix.cols())
|
||||
{
|
||||
FullPivHouseholderQR<MatrixType> qr(matrix);
|
||||
svd.m_workMatrix = qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView<Upper>();
|
||||
if(svd.m_computeFullU) svd.m_matrixU = qr.matrixQ();
|
||||
if(svd.computeV()) svd.m_matrixV = qr.colsPermutation();
|
||||
m_qr.compute(matrix);
|
||||
svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView<Upper>();
|
||||
if(svd.m_computeFullU) m_qr.matrixQ().evalTo(svd.m_matrixU, m_workspace);
|
||||
if(svd.computeV()) svd.m_matrixV = m_qr.colsPermutation();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
FullPivHouseholderQR<MatrixType> m_qr;
|
||||
WorkspaceType m_workspace;
|
||||
};
|
||||
|
||||
template<typename MatrixType>
|
||||
struct qr_preconditioner_impl<MatrixType, FullPivHouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
|
||||
class qr_preconditioner_impl<MatrixType, FullPivHouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
|
||||
{
|
||||
static bool run(JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
|
||||
public:
|
||||
typedef typename MatrixType::Index Index;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
enum
|
||||
{
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
|
||||
Options = MatrixType::Options
|
||||
};
|
||||
typedef Matrix<Scalar, ColsAtCompileTime, RowsAtCompileTime, Options, MaxColsAtCompileTime, MaxRowsAtCompileTime>
|
||||
TransposeTypeWithSameStorageOrder;
|
||||
|
||||
void allocate(const JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& svd)
|
||||
{
|
||||
if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols())
|
||||
{
|
||||
m_qr = FullPivHouseholderQR<TransposeTypeWithSameStorageOrder>(svd.cols(), svd.rows());
|
||||
}
|
||||
m_adjoint.resize(svd.cols(), svd.rows());
|
||||
if (svd.m_computeFullV) m_workspace.resize(svd.cols());
|
||||
}
|
||||
|
||||
bool run(JacobiSVD<MatrixType, FullPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
|
||||
{
|
||||
if(matrix.cols() > matrix.rows())
|
||||
{
|
||||
typedef Matrix<typename MatrixType::Scalar, MatrixType::ColsAtCompileTime, MatrixType::RowsAtCompileTime,
|
||||
MatrixType::Options, MatrixType::MaxColsAtCompileTime, MatrixType::MaxRowsAtCompileTime>
|
||||
TransposeTypeWithSameStorageOrder;
|
||||
FullPivHouseholderQR<TransposeTypeWithSameStorageOrder> qr(matrix.adjoint());
|
||||
svd.m_workMatrix = qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView<Upper>().adjoint();
|
||||
if(svd.m_computeFullV) svd.m_matrixV = qr.matrixQ();
|
||||
if(svd.computeU()) svd.m_matrixU = qr.colsPermutation();
|
||||
m_adjoint = matrix.adjoint();
|
||||
m_qr.compute(m_adjoint);
|
||||
svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView<Upper>().adjoint();
|
||||
if(svd.m_computeFullV) m_qr.matrixQ().evalTo(svd.m_matrixV, m_workspace);
|
||||
if(svd.computeU()) svd.m_matrixU = m_qr.colsPermutation();
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
private:
|
||||
FullPivHouseholderQR<TransposeTypeWithSameStorageOrder> m_qr;
|
||||
TransposeTypeWithSameStorageOrder m_adjoint;
|
||||
typename internal::plain_row_type<MatrixType>::type m_workspace;
|
||||
};
|
||||
|
||||
/*** preconditioner using ColPivHouseholderQR ***/
|
||||
|
||||
template<typename MatrixType>
|
||||
struct qr_preconditioner_impl<MatrixType, ColPivHouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
|
||||
class qr_preconditioner_impl<MatrixType, ColPivHouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
|
||||
{
|
||||
static bool run(JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
|
||||
public:
|
||||
typedef typename MatrixType::Index Index;
|
||||
|
||||
void allocate(const JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>& svd)
|
||||
{
|
||||
if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols())
|
||||
{
|
||||
m_qr = ColPivHouseholderQR<MatrixType>(svd.rows(), svd.cols());
|
||||
}
|
||||
if (svd.m_computeFullU) m_workspace.resize(svd.rows());
|
||||
else if (svd.m_computeThinU) m_workspace.resize(svd.cols());
|
||||
}
|
||||
|
||||
bool run(JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
|
||||
{
|
||||
if(matrix.rows() > matrix.cols())
|
||||
{
|
||||
ColPivHouseholderQR<MatrixType> qr(matrix);
|
||||
svd.m_workMatrix = qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView<Upper>();
|
||||
if(svd.m_computeFullU) svd.m_matrixU = qr.householderQ();
|
||||
else if(svd.m_computeThinU) {
|
||||
m_qr.compute(matrix);
|
||||
svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView<Upper>();
|
||||
if(svd.m_computeFullU) m_qr.householderQ().evalTo(svd.m_matrixU, m_workspace);
|
||||
else if(svd.m_computeThinU)
|
||||
{
|
||||
svd.m_matrixU.setIdentity(matrix.rows(), matrix.cols());
|
||||
qr.householderQ().applyThisOnTheLeft(svd.m_matrixU);
|
||||
m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixU, m_workspace);
|
||||
}
|
||||
if(svd.computeV()) svd.m_matrixV = qr.colsPermutation();
|
||||
if(svd.computeV()) svd.m_matrixV = m_qr.colsPermutation();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
ColPivHouseholderQR<MatrixType> m_qr;
|
||||
typename internal::plain_col_type<MatrixType>::type m_workspace;
|
||||
};
|
||||
|
||||
template<typename MatrixType>
|
||||
struct qr_preconditioner_impl<MatrixType, ColPivHouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
|
||||
class qr_preconditioner_impl<MatrixType, ColPivHouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
|
||||
{
|
||||
static bool run(JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
|
||||
public:
|
||||
typedef typename MatrixType::Index Index;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
enum
|
||||
{
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
|
||||
Options = MatrixType::Options
|
||||
};
|
||||
|
||||
typedef Matrix<Scalar, ColsAtCompileTime, RowsAtCompileTime, Options, MaxColsAtCompileTime, MaxRowsAtCompileTime>
|
||||
TransposeTypeWithSameStorageOrder;
|
||||
|
||||
void allocate(const JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>& svd)
|
||||
{
|
||||
if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols())
|
||||
{
|
||||
m_qr = ColPivHouseholderQR<TransposeTypeWithSameStorageOrder>(svd.cols(), svd.rows());
|
||||
}
|
||||
if (svd.m_computeFullV) m_workspace.resize(svd.cols());
|
||||
else if (svd.m_computeThinV) m_workspace.resize(svd.rows());
|
||||
m_adjoint.resize(svd.cols(), svd.rows());
|
||||
}
|
||||
|
||||
bool run(JacobiSVD<MatrixType, ColPivHouseholderQRPreconditioner>& svd, const MatrixType& matrix)
|
||||
{
|
||||
if(matrix.cols() > matrix.rows())
|
||||
{
|
||||
typedef Matrix<typename MatrixType::Scalar, MatrixType::ColsAtCompileTime, MatrixType::RowsAtCompileTime,
|
||||
MatrixType::Options, MatrixType::MaxColsAtCompileTime, MatrixType::MaxRowsAtCompileTime>
|
||||
TransposeTypeWithSameStorageOrder;
|
||||
ColPivHouseholderQR<TransposeTypeWithSameStorageOrder> qr(matrix.adjoint());
|
||||
svd.m_workMatrix = qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView<Upper>().adjoint();
|
||||
if(svd.m_computeFullV) svd.m_matrixV = qr.householderQ();
|
||||
else if(svd.m_computeThinV) {
|
||||
m_adjoint = matrix.adjoint();
|
||||
m_qr.compute(m_adjoint);
|
||||
|
||||
svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView<Upper>().adjoint();
|
||||
if(svd.m_computeFullV) m_qr.householderQ().evalTo(svd.m_matrixV, m_workspace);
|
||||
else if(svd.m_computeThinV)
|
||||
{
|
||||
svd.m_matrixV.setIdentity(matrix.cols(), matrix.rows());
|
||||
qr.householderQ().applyThisOnTheLeft(svd.m_matrixV);
|
||||
m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixV, m_workspace);
|
||||
}
|
||||
if(svd.computeU()) svd.m_matrixU = qr.colsPermutation();
|
||||
if(svd.computeU()) svd.m_matrixU = m_qr.colsPermutation();
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
private:
|
||||
ColPivHouseholderQR<TransposeTypeWithSameStorageOrder> m_qr;
|
||||
TransposeTypeWithSameStorageOrder m_adjoint;
|
||||
typename internal::plain_row_type<MatrixType>::type m_workspace;
|
||||
};
|
||||
|
||||
/*** preconditioner using HouseholderQR ***/
|
||||
|
||||
template<typename MatrixType>
|
||||
struct qr_preconditioner_impl<MatrixType, HouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
|
||||
class qr_preconditioner_impl<MatrixType, HouseholderQRPreconditioner, PreconditionIfMoreRowsThanCols, true>
|
||||
{
|
||||
static bool run(JacobiSVD<MatrixType, HouseholderQRPreconditioner>& svd, const MatrixType& matrix)
|
||||
public:
|
||||
typedef typename MatrixType::Index Index;
|
||||
|
||||
void allocate(const JacobiSVD<MatrixType, HouseholderQRPreconditioner>& svd)
|
||||
{
|
||||
if (svd.rows() != m_qr.rows() || svd.cols() != m_qr.cols())
|
||||
{
|
||||
m_qr = HouseholderQR<MatrixType>(svd.rows(), svd.cols());
|
||||
}
|
||||
if (svd.m_computeFullU) m_workspace.resize(svd.rows());
|
||||
else if (svd.m_computeThinU) m_workspace.resize(svd.cols());
|
||||
}
|
||||
|
||||
bool run(JacobiSVD<MatrixType, HouseholderQRPreconditioner>& svd, const MatrixType& matrix)
|
||||
{
|
||||
if(matrix.rows() > matrix.cols())
|
||||
{
|
||||
HouseholderQR<MatrixType> qr(matrix);
|
||||
svd.m_workMatrix = qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView<Upper>();
|
||||
if(svd.m_computeFullU) svd.m_matrixU = qr.householderQ();
|
||||
else if(svd.m_computeThinU) {
|
||||
m_qr.compute(matrix);
|
||||
svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.cols(),matrix.cols()).template triangularView<Upper>();
|
||||
if(svd.m_computeFullU) m_qr.householderQ().evalTo(svd.m_matrixU, m_workspace);
|
||||
else if(svd.m_computeThinU)
|
||||
{
|
||||
svd.m_matrixU.setIdentity(matrix.rows(), matrix.cols());
|
||||
qr.householderQ().applyThisOnTheLeft(svd.m_matrixU);
|
||||
m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixU, m_workspace);
|
||||
}
|
||||
if(svd.computeV()) svd.m_matrixV.setIdentity(matrix.cols(), matrix.cols());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
HouseholderQR<MatrixType> m_qr;
|
||||
typename internal::plain_col_type<MatrixType>::type m_workspace;
|
||||
};
|
||||
|
||||
template<typename MatrixType>
|
||||
struct qr_preconditioner_impl<MatrixType, HouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
|
||||
class qr_preconditioner_impl<MatrixType, HouseholderQRPreconditioner, PreconditionIfMoreColsThanRows, true>
|
||||
{
|
||||
static bool run(JacobiSVD<MatrixType, HouseholderQRPreconditioner>& svd, const MatrixType& matrix)
|
||||
public:
|
||||
typedef typename MatrixType::Index Index;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
enum
|
||||
{
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
|
||||
Options = MatrixType::Options
|
||||
};
|
||||
|
||||
typedef Matrix<Scalar, ColsAtCompileTime, RowsAtCompileTime, Options, MaxColsAtCompileTime, MaxRowsAtCompileTime>
|
||||
TransposeTypeWithSameStorageOrder;
|
||||
|
||||
void allocate(const JacobiSVD<MatrixType, HouseholderQRPreconditioner>& svd)
|
||||
{
|
||||
if (svd.cols() != m_qr.rows() || svd.rows() != m_qr.cols())
|
||||
{
|
||||
m_qr = HouseholderQR<TransposeTypeWithSameStorageOrder>(svd.cols(), svd.rows());
|
||||
}
|
||||
if (svd.m_computeFullV) m_workspace.resize(svd.cols());
|
||||
else if (svd.m_computeThinV) m_workspace.resize(svd.rows());
|
||||
m_adjoint.resize(svd.cols(), svd.rows());
|
||||
}
|
||||
|
||||
bool run(JacobiSVD<MatrixType, HouseholderQRPreconditioner>& svd, const MatrixType& matrix)
|
||||
{
|
||||
if(matrix.cols() > matrix.rows())
|
||||
{
|
||||
typedef Matrix<typename MatrixType::Scalar, MatrixType::ColsAtCompileTime, MatrixType::RowsAtCompileTime,
|
||||
MatrixType::Options, MatrixType::MaxColsAtCompileTime, MatrixType::MaxRowsAtCompileTime>
|
||||
TransposeTypeWithSameStorageOrder;
|
||||
HouseholderQR<TransposeTypeWithSameStorageOrder> qr(matrix.adjoint());
|
||||
svd.m_workMatrix = qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView<Upper>().adjoint();
|
||||
if(svd.m_computeFullV) svd.m_matrixV = qr.householderQ();
|
||||
else if(svd.m_computeThinV) {
|
||||
m_adjoint = matrix.adjoint();
|
||||
m_qr.compute(m_adjoint);
|
||||
|
||||
svd.m_workMatrix = m_qr.matrixQR().block(0,0,matrix.rows(),matrix.rows()).template triangularView<Upper>().adjoint();
|
||||
if(svd.m_computeFullV) m_qr.householderQ().evalTo(svd.m_matrixV, m_workspace);
|
||||
else if(svd.m_computeThinV)
|
||||
{
|
||||
svd.m_matrixV.setIdentity(matrix.cols(), matrix.rows());
|
||||
qr.householderQ().applyThisOnTheLeft(svd.m_matrixV);
|
||||
m_qr.householderQ().applyThisOnTheLeft(svd.m_matrixV, m_workspace);
|
||||
}
|
||||
if(svd.computeU()) svd.m_matrixU.setIdentity(matrix.rows(), matrix.rows());
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
private:
|
||||
HouseholderQR<TransposeTypeWithSameStorageOrder> m_qr;
|
||||
TransposeTypeWithSameStorageOrder m_adjoint;
|
||||
typename internal::plain_row_type<MatrixType>::type m_workspace;
|
||||
};
|
||||
|
||||
/*** 2x2 SVD implementation
|
||||
@ -535,6 +683,9 @@ template<typename _MatrixType, int QRPreconditioner> class JacobiSVD
|
||||
friend struct internal::svd_precondition_2x2_block_to_be_real;
|
||||
template<typename __MatrixType, int _QRPreconditioner, int _Case, bool _DoAnything>
|
||||
friend struct internal::qr_preconditioner_impl;
|
||||
|
||||
internal::qr_preconditioner_impl<MatrixType, QRPreconditioner, internal::PreconditionIfMoreColsThanRows> m_qr_precond_morecols;
|
||||
internal::qr_preconditioner_impl<MatrixType, QRPreconditioner, internal::PreconditionIfMoreRowsThanCols> m_qr_precond_morerows;
|
||||
};
|
||||
|
||||
template<typename MatrixType, int QRPreconditioner>
|
||||
@ -578,6 +729,9 @@ void JacobiSVD<MatrixType, QRPreconditioner>::allocate(Index rows, Index cols, u
|
||||
: m_computeThinV ? m_diagSize
|
||||
: 0);
|
||||
m_workMatrix.resize(m_diagSize, m_diagSize);
|
||||
|
||||
m_qr_precond_morecols.allocate(*this);
|
||||
m_qr_precond_morerows.allocate(*this);
|
||||
}
|
||||
|
||||
template<typename MatrixType, int QRPreconditioner>
|
||||
@ -595,8 +749,7 @@ JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType& matrix, unsig
|
||||
|
||||
/*** step 1. The R-SVD step: we use a QR decomposition to reduce to the case of a square matrix */
|
||||
|
||||
if(!internal::qr_preconditioner_impl<MatrixType, QRPreconditioner, internal::PreconditionIfMoreColsThanRows>::run(*this, matrix)
|
||||
&& !internal::qr_preconditioner_impl<MatrixType, QRPreconditioner, internal::PreconditionIfMoreRowsThanCols>::run(*this, matrix))
|
||||
if(!m_qr_precond_morecols.run(*this, matrix) && !m_qr_precond_morerows.run(*this, matrix))
|
||||
{
|
||||
m_workMatrix = matrix.block(0,0,m_diagSize,m_diagSize);
|
||||
if(m_computeFullU) m_matrixU.setIdentity(m_rows,m_rows);
|
||||
|
Loading…
x
Reference in New Issue
Block a user