mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-03-13 18:37:27 +08:00
PR 567: makes all dense solvers inherit SoverBase (LU,Cholesky,QR,SVD).
This changeset also includes: * add HouseholderSequence::conjugateIf * define int as the StorageIndex type for all dense solvers * dedicated unit tests, including assertion checking * _check_solve_assertion(): this method can be implemented in derived solver classes to implement custom checks * CompleteOrthogonalDecompositions: add applyZOnTheLeftInPlace, fix scalar type in applyZAdjointOnTheLeftInPlace(), add missing assertions * Cholesky: add missing assertions * FullPivHouseholderQR: Corrected Scalar type in _solve_impl() * BDCSVD: Unambiguous return type for ternary operator * SVDBase: Corrected Scalar type in _solve_impl()
This commit is contained in:
parent
7f32109c11
commit
15e53d5d93
@ -16,6 +16,15 @@
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
template<typename _MatrixType, int _UpLo> struct traits<LDLT<_MatrixType, _UpLo> >
|
||||
: traits<_MatrixType>
|
||||
{
|
||||
typedef MatrixXpr XprKind;
|
||||
typedef SolverStorage StorageKind;
|
||||
typedef int StorageIndex;
|
||||
enum { Flags = 0 };
|
||||
};
|
||||
|
||||
template<typename MatrixType, int UpLo> struct LDLT_Traits;
|
||||
|
||||
// PositiveSemiDef means positive semi-definite and non-zero; same for NegativeSemiDef
|
||||
@ -48,20 +57,19 @@ namespace internal {
|
||||
* \sa MatrixBase::ldlt(), SelfAdjointView::ldlt(), class LLT
|
||||
*/
|
||||
template<typename _MatrixType, int _UpLo> class LDLT
|
||||
: public SolverBase<LDLT<_MatrixType, _UpLo> >
|
||||
{
|
||||
public:
|
||||
typedef _MatrixType MatrixType;
|
||||
typedef SolverBase<LDLT> Base;
|
||||
friend class SolverBase<LDLT>;
|
||||
|
||||
EIGEN_GENERIC_PUBLIC_INTERFACE(LDLT)
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime,
|
||||
UpLo = _UpLo
|
||||
};
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
|
||||
typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3
|
||||
typedef typename MatrixType::StorageIndex StorageIndex;
|
||||
typedef Matrix<Scalar, RowsAtCompileTime, 1, 0, MaxRowsAtCompileTime, 1> TmpMatrixType;
|
||||
|
||||
typedef Transpositions<RowsAtCompileTime, MaxRowsAtCompileTime> TranspositionType;
|
||||
@ -180,6 +188,7 @@ template<typename _MatrixType, int _UpLo> class LDLT
|
||||
return m_sign == internal::NegativeSemiDef || m_sign == internal::ZeroSign;
|
||||
}
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** \returns a solution x of \f$ A x = b \f$ using the current decomposition of A.
|
||||
*
|
||||
* This function also supports in-place solves using the syntax <tt>x = decompositionObject.solve(x)</tt> .
|
||||
@ -197,13 +206,8 @@ template<typename _MatrixType, int _UpLo> class LDLT
|
||||
*/
|
||||
template<typename Rhs>
|
||||
inline const Solve<LDLT, Rhs>
|
||||
solve(const MatrixBase<Rhs>& b) const
|
||||
{
|
||||
eigen_assert(m_isInitialized && "LDLT is not initialized.");
|
||||
eigen_assert(m_matrix.rows()==b.rows()
|
||||
&& "LDLT::solve(): invalid number of rows of the right hand side matrix b");
|
||||
return Solve<LDLT, Rhs>(*this, b.derived());
|
||||
}
|
||||
solve(const MatrixBase<Rhs>& b) const;
|
||||
#endif
|
||||
|
||||
template<typename Derived>
|
||||
bool solveInPlace(MatrixBase<Derived> &bAndX) const;
|
||||
@ -259,6 +263,9 @@ template<typename _MatrixType, int _UpLo> class LDLT
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template<typename RhsType, typename DstType>
|
||||
void _solve_impl(const RhsType &rhs, DstType &dst) const;
|
||||
|
||||
template<bool Conjugate, typename RhsType, typename DstType>
|
||||
void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
@ -559,14 +566,22 @@ template<typename _MatrixType, int _UpLo>
|
||||
template<typename RhsType, typename DstType>
|
||||
void LDLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const
|
||||
{
|
||||
eigen_assert(rhs.rows() == rows());
|
||||
_solve_impl_transposed<true>(rhs, dst);
|
||||
}
|
||||
|
||||
template<typename _MatrixType,int _UpLo>
|
||||
template<bool Conjugate, typename RhsType, typename DstType>
|
||||
void LDLT<_MatrixType,_UpLo>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const
|
||||
{
|
||||
// dst = P b
|
||||
dst = m_transpositions * rhs;
|
||||
|
||||
// dst = L^-1 (P b)
|
||||
matrixL().solveInPlace(dst);
|
||||
// dst = L^-*T (P b)
|
||||
matrixL().template conjugateIf<!Conjugate>().solveInPlace(dst);
|
||||
|
||||
// dst = D^-1 (L^-1 P b)
|
||||
// dst = D^-* (L^-1 P b)
|
||||
// dst = D^-1 (L^-*T P b)
|
||||
// more precisely, use pseudo-inverse of D (see bug 241)
|
||||
using std::abs;
|
||||
const typename Diagonal<const MatrixType>::RealReturnType vecD(vectorD());
|
||||
@ -578,7 +593,6 @@ void LDLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) cons
|
||||
// Moreover, Lapack's xSYTRS routines use 0 for the tolerance.
|
||||
// Using numeric_limits::min() gives us more robustness to denormals.
|
||||
RealScalar tolerance = (std::numeric_limits<RealScalar>::min)();
|
||||
|
||||
for (Index i = 0; i < vecD.size(); ++i)
|
||||
{
|
||||
if(abs(vecD(i)) > tolerance)
|
||||
@ -587,10 +601,12 @@ void LDLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) cons
|
||||
dst.row(i).setZero();
|
||||
}
|
||||
|
||||
// dst = L^-T (D^-1 L^-1 P b)
|
||||
matrixU().solveInPlace(dst);
|
||||
// dst = L^-* (D^-* L^-1 P b)
|
||||
// dst = L^-T (D^-1 L^-*T P b)
|
||||
matrixL().transpose().template conjugateIf<Conjugate>().solveInPlace(dst);
|
||||
|
||||
// dst = P^-1 (L^-T D^-1 L^-1 P b) = A^-1 b
|
||||
// dst = P^T (L^-* D^-* L^-1 P b) = A^-1 b
|
||||
// dst = P^-T (L^-T D^-1 L^-*T P b) = A^-1 b
|
||||
dst = m_transpositions.transpose() * dst;
|
||||
}
|
||||
#endif
|
||||
|
@ -13,6 +13,16 @@
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal{
|
||||
|
||||
template<typename _MatrixType, int _UpLo> struct traits<LLT<_MatrixType, _UpLo> >
|
||||
: traits<_MatrixType>
|
||||
{
|
||||
typedef MatrixXpr XprKind;
|
||||
typedef SolverStorage StorageKind;
|
||||
typedef int StorageIndex;
|
||||
enum { Flags = 0 };
|
||||
};
|
||||
|
||||
template<typename MatrixType, int UpLo> struct LLT_Traits;
|
||||
}
|
||||
|
||||
@ -54,18 +64,17 @@ template<typename MatrixType, int UpLo> struct LLT_Traits;
|
||||
* \sa MatrixBase::llt(), SelfAdjointView::llt(), class LDLT
|
||||
*/
|
||||
template<typename _MatrixType, int _UpLo> class LLT
|
||||
: public SolverBase<LLT<_MatrixType, _UpLo> >
|
||||
{
|
||||
public:
|
||||
typedef _MatrixType MatrixType;
|
||||
typedef SolverBase<LLT> Base;
|
||||
friend class SolverBase<LLT>;
|
||||
|
||||
EIGEN_GENERIC_PUBLIC_INTERFACE(LLT)
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
|
||||
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
|
||||
};
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
|
||||
typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3
|
||||
typedef typename MatrixType::StorageIndex StorageIndex;
|
||||
|
||||
enum {
|
||||
PacketSize = internal::packet_traits<Scalar>::size,
|
||||
@ -129,6 +138,7 @@ template<typename _MatrixType, int _UpLo> class LLT
|
||||
return Traits::getL(m_matrix);
|
||||
}
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A.
|
||||
*
|
||||
* Since this LLT class assumes anyway that the matrix A is invertible, the solution
|
||||
@ -141,13 +151,8 @@ template<typename _MatrixType, int _UpLo> class LLT
|
||||
*/
|
||||
template<typename Rhs>
|
||||
inline const Solve<LLT, Rhs>
|
||||
solve(const MatrixBase<Rhs>& b) const
|
||||
{
|
||||
eigen_assert(m_isInitialized && "LLT is not initialized.");
|
||||
eigen_assert(m_matrix.rows()==b.rows()
|
||||
&& "LLT::solve(): invalid number of rows of the right hand side matrix b");
|
||||
return Solve<LLT, Rhs>(*this, b.derived());
|
||||
}
|
||||
solve(const MatrixBase<Rhs>& b) const;
|
||||
#endif
|
||||
|
||||
template<typename Derived>
|
||||
void solveInPlace(const MatrixBase<Derived> &bAndX) const;
|
||||
@ -205,6 +210,9 @@ template<typename _MatrixType, int _UpLo> class LLT
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template<typename RhsType, typename DstType>
|
||||
void _solve_impl(const RhsType &rhs, DstType &dst) const;
|
||||
|
||||
template<bool Conjugate, typename RhsType, typename DstType>
|
||||
void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
@ -476,8 +484,17 @@ template<typename _MatrixType,int _UpLo>
|
||||
template<typename RhsType, typename DstType>
|
||||
void LLT<_MatrixType,_UpLo>::_solve_impl(const RhsType &rhs, DstType &dst) const
|
||||
{
|
||||
dst = rhs;
|
||||
solveInPlace(dst);
|
||||
_solve_impl_transposed<true>(rhs, dst);
|
||||
}
|
||||
|
||||
template<typename _MatrixType,int _UpLo>
|
||||
template<bool Conjugate, typename RhsType, typename DstType>
|
||||
void LLT<_MatrixType,_UpLo>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const
|
||||
{
|
||||
dst = rhs;
|
||||
|
||||
matrixL().template conjugateIf<!Conjugate>().solveInPlace(dst);
|
||||
matrixU().template conjugateIf<!Conjugate>().solveInPlace(dst);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -14,8 +14,35 @@ namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Derived>
|
||||
struct solve_assertion {
|
||||
template<bool Transpose_, typename Rhs>
|
||||
static void run(const Derived& solver, const Rhs& b) { solver.template _check_solve_assertion<Transpose_>(b); }
|
||||
};
|
||||
|
||||
template<typename Derived>
|
||||
struct solve_assertion<Transpose<Derived> >
|
||||
{
|
||||
typedef Transpose<Derived> type;
|
||||
|
||||
template<bool Transpose_, typename Rhs>
|
||||
static void run(const type& transpose, const Rhs& b)
|
||||
{
|
||||
internal::solve_assertion<typename internal::remove_all<Derived>::type>::template run<true>(transpose.nestedExpression(), b);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Scalar, typename Derived>
|
||||
struct solve_assertion<CwiseUnaryOp<Eigen::internal::scalar_conjugate_op<Scalar>, const Transpose<Derived> > >
|
||||
{
|
||||
typedef CwiseUnaryOp<Eigen::internal::scalar_conjugate_op<Scalar>, const Transpose<Derived> > type;
|
||||
|
||||
template<bool Transpose_, typename Rhs>
|
||||
static void run(const type& adjoint, const Rhs& b)
|
||||
{
|
||||
internal::solve_assertion<typename internal::remove_all<Transpose<Derived> >::type>::template run<true>(adjoint.nestedExpression(), b);
|
||||
}
|
||||
};
|
||||
} // end namespace internal
|
||||
|
||||
/** \class SolverBase
|
||||
@ -35,7 +62,7 @@ namespace internal {
|
||||
*
|
||||
* \warning Currently, any other usage of transpose() and adjoint() are not supported and will produce compilation errors.
|
||||
*
|
||||
* \sa class PartialPivLU, class FullPivLU
|
||||
* \sa class PartialPivLU, class FullPivLU, class HouseholderQR, class ColPivHouseholderQR, class FullPivHouseholderQR, class CompleteOrthogonalDecomposition, class LLT, class LDLT, class SVDBase
|
||||
*/
|
||||
template<typename Derived>
|
||||
class SolverBase : public EigenBase<Derived>
|
||||
@ -46,6 +73,9 @@ class SolverBase : public EigenBase<Derived>
|
||||
typedef typename internal::traits<Derived>::Scalar Scalar;
|
||||
typedef Scalar CoeffReturnType;
|
||||
|
||||
template<typename Derived_>
|
||||
friend struct internal::solve_assertion;
|
||||
|
||||
enum {
|
||||
RowsAtCompileTime = internal::traits<Derived>::RowsAtCompileTime,
|
||||
ColsAtCompileTime = internal::traits<Derived>::ColsAtCompileTime,
|
||||
@ -75,7 +105,7 @@ class SolverBase : public EigenBase<Derived>
|
||||
inline const Solve<Derived, Rhs>
|
||||
solve(const MatrixBase<Rhs>& b) const
|
||||
{
|
||||
eigen_assert(derived().rows()==b.rows() && "solve(): invalid number of rows of the right hand side matrix b");
|
||||
internal::solve_assertion<typename internal::remove_all<Derived>::type>::template run<false>(derived(), b);
|
||||
return Solve<Derived, Rhs>(derived(), b.derived());
|
||||
}
|
||||
|
||||
@ -113,6 +143,12 @@ class SolverBase : public EigenBase<Derived>
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
template<bool Transpose_, typename Rhs>
|
||||
void _check_solve_assertion(const Rhs& b) const {
|
||||
eigen_assert(derived().m_isInitialized && "Solver is not initialized.");
|
||||
eigen_assert((Transpose_?derived().cols():derived().rows())==b.rows() && "SolverBase::solve(): invalid number of rows of the right hand side matrix b");
|
||||
}
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
@ -260,6 +260,7 @@ template<typename MatrixType> class HouseholderQR;
|
||||
template<typename MatrixType> class ColPivHouseholderQR;
|
||||
template<typename MatrixType> class FullPivHouseholderQR;
|
||||
template<typename MatrixType> class CompleteOrthogonalDecomposition;
|
||||
template<typename MatrixType> class SVDBase;
|
||||
template<typename MatrixType, int QRPreconditioner = ColPivHouseholderQRPreconditioner> class JacobiSVD;
|
||||
template<typename MatrixType> class BDCSVD;
|
||||
template<typename MatrixType, int UpLo = Lower> class LLT;
|
||||
|
@ -156,6 +156,12 @@ template<typename VectorsType, typename CoeffsType, int Side> class HouseholderS
|
||||
Side
|
||||
> TransposeReturnType;
|
||||
|
||||
typedef HouseholderSequence<
|
||||
typename internal::add_const<VectorsType>::type,
|
||||
typename internal::add_const<CoeffsType>::type,
|
||||
Side
|
||||
> ConstHouseholderSequence;
|
||||
|
||||
/** \brief Constructor.
|
||||
* \param[in] v %Matrix containing the essential parts of the Householder vectors
|
||||
* \param[in] h Vector containing the Householder coefficients
|
||||
@ -244,6 +250,18 @@ template<typename VectorsType, typename CoeffsType, int Side> class HouseholderS
|
||||
.setShift(m_shift);
|
||||
}
|
||||
|
||||
/** \returns an expression of the complex conjugate of \c *this if Cond==true,
|
||||
* returns \c *this otherwise.
|
||||
*/
|
||||
template<bool Cond>
|
||||
EIGEN_DEVICE_FUNC
|
||||
inline typename internal::conditional<Cond,ConjugateReturnType,ConstHouseholderSequence>::type
|
||||
conjugateIf() const
|
||||
{
|
||||
typedef typename internal::conditional<Cond,ConjugateReturnType,ConstHouseholderSequence>::type ReturnType;
|
||||
return ReturnType(m_vectors.template conjugateIf<Cond>(), m_coeffs.template conjugateIf<Cond>());
|
||||
}
|
||||
|
||||
/** \brief Adjoint (conjugate transpose) of the Householder sequence. */
|
||||
AdjointReturnType adjoint() const
|
||||
{
|
||||
|
@ -63,6 +63,7 @@ template<typename _MatrixType> class FullPivLU
|
||||
public:
|
||||
typedef _MatrixType MatrixType;
|
||||
typedef SolverBase<FullPivLU> Base;
|
||||
friend class SolverBase<FullPivLU>;
|
||||
|
||||
EIGEN_GENERIC_PUBLIC_INTERFACE(FullPivLU)
|
||||
enum {
|
||||
@ -218,6 +219,7 @@ template<typename _MatrixType> class FullPivLU
|
||||
return internal::image_retval<FullPivLU>(*this, originalMatrix);
|
||||
}
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** \return a solution x to the equation Ax=b, where A is the matrix of which
|
||||
* *this is the LU decomposition.
|
||||
*
|
||||
@ -237,14 +239,10 @@ template<typename _MatrixType> class FullPivLU
|
||||
*
|
||||
* \sa TriangularView::solve(), kernel(), inverse()
|
||||
*/
|
||||
// FIXME this is a copy-paste of the base-class member to add the isInitialized assertion.
|
||||
template<typename Rhs>
|
||||
inline const Solve<FullPivLU, Rhs>
|
||||
solve(const MatrixBase<Rhs>& b) const
|
||||
{
|
||||
eigen_assert(m_isInitialized && "LU is not initialized.");
|
||||
return Solve<FullPivLU, Rhs>(*this, b.derived());
|
||||
}
|
||||
solve(const MatrixBase<Rhs>& b) const;
|
||||
#endif
|
||||
|
||||
/** \returns an estimate of the reciprocal condition number of the matrix of which \c *this is
|
||||
the LU decomposition.
|
||||
@ -755,7 +753,6 @@ void FullPivLU<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const
|
||||
const Index rows = this->rows(),
|
||||
cols = this->cols(),
|
||||
nonzero_pivots = this->rank();
|
||||
eigen_assert(rhs.rows() == rows);
|
||||
const Index smalldim = (std::min)(rows, cols);
|
||||
|
||||
if(nonzero_pivots == 0)
|
||||
@ -805,7 +802,6 @@ void FullPivLU<_MatrixType>::_solve_impl_transposed(const RhsType &rhs, DstType
|
||||
|
||||
const Index rows = this->rows(), cols = this->cols(),
|
||||
nonzero_pivots = this->rank();
|
||||
eigen_assert(rhs.rows() == cols);
|
||||
const Index smalldim = (std::min)(rows, cols);
|
||||
|
||||
if(nonzero_pivots == 0)
|
||||
|
@ -80,6 +80,8 @@ template<typename _MatrixType> class PartialPivLU
|
||||
|
||||
typedef _MatrixType MatrixType;
|
||||
typedef SolverBase<PartialPivLU> Base;
|
||||
friend class SolverBase<PartialPivLU>;
|
||||
|
||||
EIGEN_GENERIC_PUBLIC_INTERFACE(PartialPivLU)
|
||||
enum {
|
||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
||||
@ -152,6 +154,7 @@ template<typename _MatrixType> class PartialPivLU
|
||||
return m_p;
|
||||
}
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** This method returns the solution x to the equation Ax=b, where A is the matrix of which
|
||||
* *this is the LU decomposition.
|
||||
*
|
||||
@ -169,14 +172,10 @@ template<typename _MatrixType> class PartialPivLU
|
||||
*
|
||||
* \sa TriangularView::solve(), inverse(), computeInverse()
|
||||
*/
|
||||
// FIXME this is a copy-paste of the base-class member to add the isInitialized assertion.
|
||||
template<typename Rhs>
|
||||
inline const Solve<PartialPivLU, Rhs>
|
||||
solve(const MatrixBase<Rhs>& b) const
|
||||
{
|
||||
eigen_assert(m_isInitialized && "PartialPivLU is not initialized.");
|
||||
return Solve<PartialPivLU, Rhs>(*this, b.derived());
|
||||
}
|
||||
solve(const MatrixBase<Rhs>& b) const;
|
||||
#endif
|
||||
|
||||
/** \returns an estimate of the reciprocal condition number of the matrix of which \c *this is
|
||||
the LU decomposition.
|
||||
@ -231,8 +230,6 @@ template<typename _MatrixType> class PartialPivLU
|
||||
* Step 3: replace c by the solution x to Ux = c.
|
||||
*/
|
||||
|
||||
eigen_assert(rhs.rows() == m_lu.rows());
|
||||
|
||||
// Step 1
|
||||
dst = permutationP() * rhs;
|
||||
|
||||
|
@ -17,6 +17,9 @@ namespace internal {
|
||||
template<typename _MatrixType> struct traits<ColPivHouseholderQR<_MatrixType> >
|
||||
: traits<_MatrixType>
|
||||
{
|
||||
typedef MatrixXpr XprKind;
|
||||
typedef SolverStorage StorageKind;
|
||||
typedef int StorageIndex;
|
||||
enum { Flags = 0 };
|
||||
};
|
||||
|
||||
@ -46,20 +49,19 @@ template<typename _MatrixType> struct traits<ColPivHouseholderQR<_MatrixType> >
|
||||
* \sa MatrixBase::colPivHouseholderQr()
|
||||
*/
|
||||
template<typename _MatrixType> class ColPivHouseholderQR
|
||||
: public SolverBase<ColPivHouseholderQR<_MatrixType> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef _MatrixType MatrixType;
|
||||
typedef SolverBase<ColPivHouseholderQR> Base;
|
||||
friend class SolverBase<ColPivHouseholderQR>;
|
||||
|
||||
EIGEN_GENERIC_PUBLIC_INTERFACE(ColPivHouseholderQR)
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
|
||||
};
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
// FIXME should be int
|
||||
typedef typename MatrixType::StorageIndex StorageIndex;
|
||||
typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
|
||||
typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime> PermutationType;
|
||||
typedef typename internal::plain_row_type<MatrixType, Index>::type IntRowVectorType;
|
||||
@ -156,6 +158,7 @@ template<typename _MatrixType> class ColPivHouseholderQR
|
||||
computeInPlace();
|
||||
}
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** This method finds a solution x to the equation Ax=b, where A is the matrix of which
|
||||
* *this is the QR decomposition, if any exists.
|
||||
*
|
||||
@ -172,11 +175,8 @@ template<typename _MatrixType> class ColPivHouseholderQR
|
||||
*/
|
||||
template<typename Rhs>
|
||||
inline const Solve<ColPivHouseholderQR, Rhs>
|
||||
solve(const MatrixBase<Rhs>& b) const
|
||||
{
|
||||
eigen_assert(m_isInitialized && "ColPivHouseholderQR is not initialized.");
|
||||
return Solve<ColPivHouseholderQR, Rhs>(*this, b.derived());
|
||||
}
|
||||
solve(const MatrixBase<Rhs>& b) const;
|
||||
#endif
|
||||
|
||||
HouseholderSequenceType householderQ() const;
|
||||
HouseholderSequenceType matrixQ() const
|
||||
@ -417,6 +417,9 @@ template<typename _MatrixType> class ColPivHouseholderQR
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template<typename RhsType, typename DstType>
|
||||
void _solve_impl(const RhsType &rhs, DstType &dst) const;
|
||||
|
||||
template<bool Conjugate, typename RhsType, typename DstType>
|
||||
void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
@ -583,8 +586,6 @@ template<typename _MatrixType>
|
||||
template<typename RhsType, typename DstType>
|
||||
void ColPivHouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const
|
||||
{
|
||||
eigen_assert(rhs.rows() == rows());
|
||||
|
||||
const Index nonzero_pivots = nonzeroPivots();
|
||||
|
||||
if(nonzero_pivots == 0)
|
||||
@ -604,6 +605,31 @@ void ColPivHouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &
|
||||
for(Index i = 0; i < nonzero_pivots; ++i) dst.row(m_colsPermutation.indices().coeff(i)) = c.row(i);
|
||||
for(Index i = nonzero_pivots; i < cols(); ++i) dst.row(m_colsPermutation.indices().coeff(i)).setZero();
|
||||
}
|
||||
|
||||
template<typename _MatrixType>
|
||||
template<bool Conjugate, typename RhsType, typename DstType>
|
||||
void ColPivHouseholderQR<_MatrixType>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const
|
||||
{
|
||||
const Index nonzero_pivots = nonzeroPivots();
|
||||
|
||||
if(nonzero_pivots == 0)
|
||||
{
|
||||
dst.setZero();
|
||||
return;
|
||||
}
|
||||
|
||||
typename RhsType::PlainObject c(m_colsPermutation.transpose()*rhs);
|
||||
|
||||
m_qr.topLeftCorner(nonzero_pivots, nonzero_pivots)
|
||||
.template triangularView<Upper>()
|
||||
.transpose().template conjugateIf<Conjugate>()
|
||||
.solveInPlace(c.topRows(nonzero_pivots));
|
||||
|
||||
dst.topRows(nonzero_pivots) = c.topRows(nonzero_pivots);
|
||||
dst.bottomRows(rows()-nonzero_pivots).setZero();
|
||||
|
||||
dst.applyOnTheLeft(householderQ().setLength(nonzero_pivots).template conjugateIf<!Conjugate>() );
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace internal {
|
||||
|
@ -16,6 +16,9 @@ namespace internal {
|
||||
template <typename _MatrixType>
|
||||
struct traits<CompleteOrthogonalDecomposition<_MatrixType> >
|
||||
: traits<_MatrixType> {
|
||||
typedef MatrixXpr XprKind;
|
||||
typedef SolverStorage StorageKind;
|
||||
typedef int StorageIndex;
|
||||
enum { Flags = 0 };
|
||||
};
|
||||
|
||||
@ -44,19 +47,21 @@ struct traits<CompleteOrthogonalDecomposition<_MatrixType> >
|
||||
*
|
||||
* \sa MatrixBase::completeOrthogonalDecomposition()
|
||||
*/
|
||||
template <typename _MatrixType>
|
||||
class CompleteOrthogonalDecomposition {
|
||||
template <typename _MatrixType> class CompleteOrthogonalDecomposition
|
||||
: public SolverBase<CompleteOrthogonalDecomposition<_MatrixType> >
|
||||
{
|
||||
public:
|
||||
typedef _MatrixType MatrixType;
|
||||
typedef SolverBase<CompleteOrthogonalDecomposition> Base;
|
||||
|
||||
template<typename Derived>
|
||||
friend struct internal::solve_assertion;
|
||||
|
||||
EIGEN_GENERIC_PUBLIC_INTERFACE(CompleteOrthogonalDecomposition)
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
|
||||
};
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
typedef typename MatrixType::StorageIndex StorageIndex;
|
||||
typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
|
||||
typedef PermutationMatrix<ColsAtCompileTime, MaxColsAtCompileTime>
|
||||
PermutationType;
|
||||
@ -131,9 +136,9 @@ class CompleteOrthogonalDecomposition {
|
||||
m_temp(matrix.cols())
|
||||
{
|
||||
computeInPlace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** This method computes the minimum-norm solution X to a least squares
|
||||
* problem \f[\mathrm{minimize} \|A X - B\|, \f] where \b A is the matrix of
|
||||
* which \c *this is the complete orthogonal decomposition.
|
||||
@ -145,11 +150,8 @@ class CompleteOrthogonalDecomposition {
|
||||
*/
|
||||
template <typename Rhs>
|
||||
inline const Solve<CompleteOrthogonalDecomposition, Rhs> solve(
|
||||
const MatrixBase<Rhs>& b) const {
|
||||
eigen_assert(m_cpqr.m_isInitialized &&
|
||||
"CompleteOrthogonalDecomposition is not initialized.");
|
||||
return Solve<CompleteOrthogonalDecomposition, Rhs>(*this, b.derived());
|
||||
}
|
||||
const MatrixBase<Rhs>& b) const;
|
||||
#endif
|
||||
|
||||
HouseholderSequenceType householderQ(void) const;
|
||||
HouseholderSequenceType matrixQ(void) const { return m_cpqr.householderQ(); }
|
||||
@ -158,8 +160,8 @@ class CompleteOrthogonalDecomposition {
|
||||
*/
|
||||
MatrixType matrixZ() const {
|
||||
MatrixType Z = MatrixType::Identity(m_cpqr.cols(), m_cpqr.cols());
|
||||
applyZAdjointOnTheLeftInPlace(Z);
|
||||
return Z.adjoint();
|
||||
applyZOnTheLeftInPlace<false>(Z);
|
||||
return Z;
|
||||
}
|
||||
|
||||
/** \returns a reference to the matrix where the complete orthogonal
|
||||
@ -275,6 +277,7 @@ class CompleteOrthogonalDecomposition {
|
||||
*/
|
||||
inline const Inverse<CompleteOrthogonalDecomposition> pseudoInverse() const
|
||||
{
|
||||
eigen_assert(m_cpqr.m_isInitialized && "CompleteOrthogonalDecomposition is not initialized.");
|
||||
return Inverse<CompleteOrthogonalDecomposition>(*this);
|
||||
}
|
||||
|
||||
@ -368,6 +371,9 @@ class CompleteOrthogonalDecomposition {
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template <typename RhsType, typename DstType>
|
||||
void _solve_impl(const RhsType& rhs, DstType& dst) const;
|
||||
|
||||
template<bool Conjugate, typename RhsType, typename DstType>
|
||||
void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
@ -375,8 +381,21 @@ class CompleteOrthogonalDecomposition {
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
|
||||
}
|
||||
|
||||
template<bool Transpose_, typename Rhs>
|
||||
void _check_solve_assertion(const Rhs& b) const {
|
||||
eigen_assert(m_cpqr.m_isInitialized && "CompleteOrthogonalDecomposition is not initialized.");
|
||||
eigen_assert((Transpose_?derived().cols():derived().rows())==b.rows() && "CompleteOrthogonalDecomposition::solve(): invalid number of rows of the right hand side matrix b");
|
||||
}
|
||||
|
||||
void computeInPlace();
|
||||
|
||||
/** Overwrites \b rhs with \f$ \mathbf{Z} * \mathbf{rhs} \f$ or
|
||||
* \f$ \mathbf{\overline Z} * \mathbf{rhs} \f$ if \c Conjugate
|
||||
* is set to \c true.
|
||||
*/
|
||||
template <bool Conjugate, typename Rhs>
|
||||
void applyZOnTheLeftInPlace(Rhs& rhs) const;
|
||||
|
||||
/** Overwrites \b rhs with \f$ \mathbf{Z}^* * \mathbf{rhs} \f$.
|
||||
*/
|
||||
template <typename Rhs>
|
||||
@ -464,6 +483,28 @@ void CompleteOrthogonalDecomposition<MatrixType>::computeInPlace()
|
||||
}
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
template <bool Conjugate, typename Rhs>
|
||||
void CompleteOrthogonalDecomposition<MatrixType>::applyZOnTheLeftInPlace(
|
||||
Rhs& rhs) const {
|
||||
const Index cols = this->cols();
|
||||
const Index nrhs = rhs.cols();
|
||||
const Index rank = this->rank();
|
||||
Matrix<typename Rhs::Scalar, Dynamic, 1> temp((std::max)(cols, nrhs));
|
||||
for (Index k = rank-1; k >= 0; --k) {
|
||||
if (k != rank - 1) {
|
||||
rhs.row(k).swap(rhs.row(rank - 1));
|
||||
}
|
||||
rhs.middleRows(rank - 1, cols - rank + 1)
|
||||
.applyHouseholderOnTheLeft(
|
||||
matrixQTZ().row(k).tail(cols - rank).transpose().template conjugateIf<!Conjugate>(), zCoeffs().template conjugateIf<Conjugate>()(k),
|
||||
&temp(0));
|
||||
if (k != rank - 1) {
|
||||
rhs.row(k).swap(rhs.row(rank - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename MatrixType>
|
||||
template <typename Rhs>
|
||||
void CompleteOrthogonalDecomposition<MatrixType>::applyZAdjointOnTheLeftInPlace(
|
||||
@ -471,7 +512,7 @@ void CompleteOrthogonalDecomposition<MatrixType>::applyZAdjointOnTheLeftInPlace(
|
||||
const Index cols = this->cols();
|
||||
const Index nrhs = rhs.cols();
|
||||
const Index rank = this->rank();
|
||||
Matrix<typename MatrixType::Scalar, Dynamic, 1> temp((std::max)(cols, nrhs));
|
||||
Matrix<typename Rhs::Scalar, Dynamic, 1> temp((std::max)(cols, nrhs));
|
||||
for (Index k = 0; k < rank; ++k) {
|
||||
if (k != rank - 1) {
|
||||
rhs.row(k).swap(rhs.row(rank - 1));
|
||||
@ -491,8 +532,6 @@ template <typename _MatrixType>
|
||||
template <typename RhsType, typename DstType>
|
||||
void CompleteOrthogonalDecomposition<_MatrixType>::_solve_impl(
|
||||
const RhsType& rhs, DstType& dst) const {
|
||||
eigen_assert(rhs.rows() == this->rows());
|
||||
|
||||
const Index rank = this->rank();
|
||||
if (rank == 0) {
|
||||
dst.setZero();
|
||||
@ -520,6 +559,34 @@ void CompleteOrthogonalDecomposition<_MatrixType>::_solve_impl(
|
||||
// Undo permutation to get x = P^{-1} * y.
|
||||
dst = colsPermutation() * dst;
|
||||
}
|
||||
|
||||
template<typename _MatrixType>
|
||||
template<bool Conjugate, typename RhsType, typename DstType>
|
||||
void CompleteOrthogonalDecomposition<_MatrixType>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const
|
||||
{
|
||||
const Index rank = this->rank();
|
||||
|
||||
if (rank == 0) {
|
||||
dst.setZero();
|
||||
return;
|
||||
}
|
||||
|
||||
typename RhsType::PlainObject c(colsPermutation().transpose()*rhs);
|
||||
|
||||
if (rank < cols()) {
|
||||
applyZOnTheLeftInPlace<!Conjugate>(c);
|
||||
}
|
||||
|
||||
matrixT().topLeftCorner(rank, rank)
|
||||
.template triangularView<Upper>()
|
||||
.transpose().template conjugateIf<Conjugate>()
|
||||
.solveInPlace(c.topRows(rank));
|
||||
|
||||
dst.topRows(rank) = c.topRows(rank);
|
||||
dst.bottomRows(rows()-rank).setZero();
|
||||
|
||||
dst.applyOnTheLeft(householderQ().setLength(rank).template conjugateIf<!Conjugate>() );
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace internal {
|
||||
|
@ -18,6 +18,9 @@ namespace internal {
|
||||
template<typename _MatrixType> struct traits<FullPivHouseholderQR<_MatrixType> >
|
||||
: traits<_MatrixType>
|
||||
{
|
||||
typedef MatrixXpr XprKind;
|
||||
typedef SolverStorage StorageKind;
|
||||
typedef int StorageIndex;
|
||||
enum { Flags = 0 };
|
||||
};
|
||||
|
||||
@ -55,20 +58,19 @@ struct traits<FullPivHouseholderQRMatrixQReturnType<MatrixType> >
|
||||
* \sa MatrixBase::fullPivHouseholderQr()
|
||||
*/
|
||||
template<typename _MatrixType> class FullPivHouseholderQR
|
||||
: public SolverBase<FullPivHouseholderQR<_MatrixType> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef _MatrixType MatrixType;
|
||||
typedef SolverBase<FullPivHouseholderQR> Base;
|
||||
friend class SolverBase<FullPivHouseholderQR>;
|
||||
|
||||
EIGEN_GENERIC_PUBLIC_INTERFACE(FullPivHouseholderQR)
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
|
||||
};
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
// FIXME should be int
|
||||
typedef typename MatrixType::StorageIndex StorageIndex;
|
||||
typedef internal::FullPivHouseholderQRMatrixQReturnType<MatrixType> MatrixQReturnType;
|
||||
typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
|
||||
typedef Matrix<StorageIndex, 1,
|
||||
@ -156,6 +158,7 @@ template<typename _MatrixType> class FullPivHouseholderQR
|
||||
computeInPlace();
|
||||
}
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** This method finds a solution x to the equation Ax=b, where A is the matrix of which
|
||||
* \c *this is the QR decomposition.
|
||||
*
|
||||
@ -173,11 +176,8 @@ template<typename _MatrixType> class FullPivHouseholderQR
|
||||
*/
|
||||
template<typename Rhs>
|
||||
inline const Solve<FullPivHouseholderQR, Rhs>
|
||||
solve(const MatrixBase<Rhs>& b) const
|
||||
{
|
||||
eigen_assert(m_isInitialized && "FullPivHouseholderQR is not initialized.");
|
||||
return Solve<FullPivHouseholderQR, Rhs>(*this, b.derived());
|
||||
}
|
||||
solve(const MatrixBase<Rhs>& b) const;
|
||||
#endif
|
||||
|
||||
/** \returns Expression object representing the matrix Q
|
||||
*/
|
||||
@ -396,6 +396,9 @@ template<typename _MatrixType> class FullPivHouseholderQR
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template<typename RhsType, typename DstType>
|
||||
void _solve_impl(const RhsType &rhs, DstType &dst) const;
|
||||
|
||||
template<bool Conjugate, typename RhsType, typename DstType>
|
||||
void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
@ -498,15 +501,15 @@ void FullPivHouseholderQR<MatrixType>::computeInPlace()
|
||||
m_nonzero_pivots = k;
|
||||
for(Index i = k; i < size; i++)
|
||||
{
|
||||
m_rows_transpositions.coeffRef(i) = i;
|
||||
m_cols_transpositions.coeffRef(i) = i;
|
||||
m_rows_transpositions.coeffRef(i) = internal::convert_index<StorageIndex>(i);
|
||||
m_cols_transpositions.coeffRef(i) = internal::convert_index<StorageIndex>(i);
|
||||
m_hCoeffs.coeffRef(i) = Scalar(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
m_rows_transpositions.coeffRef(k) = row_of_biggest_in_corner;
|
||||
m_cols_transpositions.coeffRef(k) = col_of_biggest_in_corner;
|
||||
m_rows_transpositions.coeffRef(k) = internal::convert_index<StorageIndex>(row_of_biggest_in_corner);
|
||||
m_cols_transpositions.coeffRef(k) = internal::convert_index<StorageIndex>(col_of_biggest_in_corner);
|
||||
if(k != row_of_biggest_in_corner) {
|
||||
m_qr.row(k).tail(cols-k).swap(m_qr.row(row_of_biggest_in_corner).tail(cols-k));
|
||||
++number_of_transpositions;
|
||||
@ -540,7 +543,6 @@ template<typename _MatrixType>
|
||||
template<typename RhsType, typename DstType>
|
||||
void FullPivHouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const
|
||||
{
|
||||
eigen_assert(rhs.rows() == rows());
|
||||
const Index l_rank = rank();
|
||||
|
||||
// FIXME introduce nonzeroPivots() and use it here. and more generally,
|
||||
@ -553,7 +555,7 @@ void FullPivHouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType
|
||||
|
||||
typename RhsType::PlainObject c(rhs);
|
||||
|
||||
Matrix<Scalar,1,RhsType::ColsAtCompileTime> temp(rhs.cols());
|
||||
Matrix<typename RhsType::Scalar,1,RhsType::ColsAtCompileTime> temp(rhs.cols());
|
||||
for (Index k = 0; k < l_rank; ++k)
|
||||
{
|
||||
Index remainingSize = rows()-k;
|
||||
@ -570,6 +572,42 @@ void FullPivHouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType
|
||||
for(Index i = 0; i < l_rank; ++i) dst.row(m_cols_permutation.indices().coeff(i)) = c.row(i);
|
||||
for(Index i = l_rank; i < cols(); ++i) dst.row(m_cols_permutation.indices().coeff(i)).setZero();
|
||||
}
|
||||
|
||||
template<typename _MatrixType>
|
||||
template<bool Conjugate, typename RhsType, typename DstType>
|
||||
void FullPivHouseholderQR<_MatrixType>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const
|
||||
{
|
||||
const Index l_rank = rank();
|
||||
|
||||
if(l_rank == 0)
|
||||
{
|
||||
dst.setZero();
|
||||
return;
|
||||
}
|
||||
|
||||
typename RhsType::PlainObject c(m_cols_permutation.transpose()*rhs);
|
||||
|
||||
m_qr.topLeftCorner(l_rank, l_rank)
|
||||
.template triangularView<Upper>()
|
||||
.transpose().template conjugateIf<Conjugate>()
|
||||
.solveInPlace(c.topRows(l_rank));
|
||||
|
||||
dst.topRows(l_rank) = c.topRows(l_rank);
|
||||
dst.bottomRows(rows()-l_rank).setZero();
|
||||
|
||||
Matrix<Scalar, 1, DstType::ColsAtCompileTime> temp(dst.cols());
|
||||
const Index size = (std::min)(rows(), cols());
|
||||
for (Index k = size-1; k >= 0; --k)
|
||||
{
|
||||
Index remainingSize = rows()-k;
|
||||
|
||||
dst.bottomRightCorner(remainingSize, dst.cols())
|
||||
.applyHouseholderOnTheLeft(m_qr.col(k).tail(remainingSize-1).template conjugateIf<!Conjugate>(),
|
||||
m_hCoeffs.template conjugateIf<Conjugate>().coeff(k), &temp.coeffRef(0));
|
||||
|
||||
dst.row(k).swap(dst.row(m_rows_transpositions.coeff(k)));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace internal {
|
||||
|
@ -14,6 +14,18 @@
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
template<typename _MatrixType> struct traits<HouseholderQR<_MatrixType> >
|
||||
: traits<_MatrixType>
|
||||
{
|
||||
typedef MatrixXpr XprKind;
|
||||
typedef SolverStorage StorageKind;
|
||||
typedef int StorageIndex;
|
||||
enum { Flags = 0 };
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
|
||||
/** \ingroup QR_Module
|
||||
*
|
||||
*
|
||||
@ -42,20 +54,19 @@ namespace Eigen {
|
||||
* \sa MatrixBase::householderQr()
|
||||
*/
|
||||
template<typename _MatrixType> class HouseholderQR
|
||||
: public SolverBase<HouseholderQR<_MatrixType> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef _MatrixType MatrixType;
|
||||
typedef SolverBase<HouseholderQR> Base;
|
||||
friend class SolverBase<HouseholderQR>;
|
||||
|
||||
EIGEN_GENERIC_PUBLIC_INTERFACE(HouseholderQR)
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
ColsAtCompileTime = MatrixType::ColsAtCompileTime,
|
||||
MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
|
||||
MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
|
||||
};
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename MatrixType::RealScalar RealScalar;
|
||||
// FIXME should be int
|
||||
typedef typename MatrixType::StorageIndex StorageIndex;
|
||||
typedef Matrix<Scalar, RowsAtCompileTime, RowsAtCompileTime, (MatrixType::Flags&RowMajorBit) ? RowMajor : ColMajor, MaxRowsAtCompileTime, MaxRowsAtCompileTime> MatrixQType;
|
||||
typedef typename internal::plain_diag_type<MatrixType>::type HCoeffsType;
|
||||
typedef typename internal::plain_row_type<MatrixType>::type RowVectorType;
|
||||
@ -121,6 +132,7 @@ template<typename _MatrixType> class HouseholderQR
|
||||
computeInPlace();
|
||||
}
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** This method finds a solution x to the equation Ax=b, where A is the matrix of which
|
||||
* *this is the QR decomposition, if any exists.
|
||||
*
|
||||
@ -137,11 +149,8 @@ template<typename _MatrixType> class HouseholderQR
|
||||
*/
|
||||
template<typename Rhs>
|
||||
inline const Solve<HouseholderQR, Rhs>
|
||||
solve(const MatrixBase<Rhs>& b) const
|
||||
{
|
||||
eigen_assert(m_isInitialized && "HouseholderQR is not initialized.");
|
||||
return Solve<HouseholderQR, Rhs>(*this, b.derived());
|
||||
}
|
||||
solve(const MatrixBase<Rhs>& b) const;
|
||||
#endif
|
||||
|
||||
/** This method returns an expression of the unitary matrix Q as a sequence of Householder transformations.
|
||||
*
|
||||
@ -214,6 +223,9 @@ template<typename _MatrixType> class HouseholderQR
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template<typename RhsType, typename DstType>
|
||||
void _solve_impl(const RhsType &rhs, DstType &dst) const;
|
||||
|
||||
template<bool Conjugate, typename RhsType, typename DstType>
|
||||
void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
@ -349,7 +361,6 @@ template<typename RhsType, typename DstType>
|
||||
void HouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) const
|
||||
{
|
||||
const Index rank = (std::min)(rows(), cols());
|
||||
eigen_assert(rhs.rows() == rows());
|
||||
|
||||
typename RhsType::PlainObject c(rhs);
|
||||
|
||||
@ -362,6 +373,25 @@ void HouseholderQR<_MatrixType>::_solve_impl(const RhsType &rhs, DstType &dst) c
|
||||
dst.topRows(rank) = c.topRows(rank);
|
||||
dst.bottomRows(cols()-rank).setZero();
|
||||
}
|
||||
|
||||
template<typename _MatrixType>
|
||||
template<bool Conjugate, typename RhsType, typename DstType>
|
||||
void HouseholderQR<_MatrixType>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const
|
||||
{
|
||||
const Index rank = (std::min)(rows(), cols());
|
||||
|
||||
typename RhsType::PlainObject c(rhs);
|
||||
|
||||
m_qr.topLeftCorner(rank, rank)
|
||||
.template triangularView<Upper>()
|
||||
.transpose().template conjugateIf<Conjugate>()
|
||||
.solveInPlace(c.topRows(rank));
|
||||
|
||||
dst.topRows(rank) = c.topRows(rank);
|
||||
dst.bottomRows(rows()-rank).setZero();
|
||||
|
||||
dst.applyOnTheLeft(householderQ().setLength(rank).template conjugateIf<!Conjugate>() );
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Performs the QR factorization of the given matrix \a matrix. The result of
|
||||
|
@ -39,6 +39,7 @@ namespace internal {
|
||||
|
||||
template<typename _MatrixType>
|
||||
struct traits<BDCSVD<_MatrixType> >
|
||||
: traits<_MatrixType>
|
||||
{
|
||||
typedef _MatrixType MatrixType;
|
||||
};
|
||||
@ -1006,7 +1007,7 @@ void BDCSVD<MatrixType>::perturbCol0
|
||||
#ifdef EIGEN_BDCSVD_SANITY_CHECKS
|
||||
assert((std::isfinite)(tmp));
|
||||
#endif
|
||||
zhat(k) = col0(k) > Literal(0) ? tmp : -tmp;
|
||||
zhat(k) = col0(k) > Literal(0) ? RealScalar(tmp) : RealScalar(-tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -425,6 +425,7 @@ struct svd_precondition_2x2_block_to_be_real<MatrixType, QRPreconditioner, true>
|
||||
|
||||
template<typename _MatrixType, int QRPreconditioner>
|
||||
struct traits<JacobiSVD<_MatrixType,QRPreconditioner> >
|
||||
: traits<_MatrixType>
|
||||
{
|
||||
typedef _MatrixType MatrixType;
|
||||
};
|
||||
|
@ -17,6 +17,18 @@
|
||||
#define EIGEN_SVDBASE_H
|
||||
|
||||
namespace Eigen {
|
||||
|
||||
namespace internal {
|
||||
template<typename Derived> struct traits<SVDBase<Derived> >
|
||||
: traits<Derived>
|
||||
{
|
||||
typedef MatrixXpr XprKind;
|
||||
typedef SolverStorage StorageKind;
|
||||
typedef int StorageIndex;
|
||||
enum { Flags = 0 };
|
||||
};
|
||||
}
|
||||
|
||||
/** \ingroup SVD_Module
|
||||
*
|
||||
*
|
||||
@ -44,15 +56,18 @@ namespace Eigen {
|
||||
* terminate in finite (and reasonable) time.
|
||||
* \sa class BDCSVD, class JacobiSVD
|
||||
*/
|
||||
template<typename Derived>
|
||||
class SVDBase
|
||||
template<typename Derived> class SVDBase
|
||||
: public SolverBase<SVDBase<Derived> >
|
||||
{
|
||||
public:
|
||||
|
||||
template<typename Derived_>
|
||||
friend struct internal::solve_assertion;
|
||||
|
||||
public:
|
||||
typedef typename internal::traits<Derived>::MatrixType MatrixType;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
|
||||
typedef typename MatrixType::StorageIndex StorageIndex;
|
||||
typedef typename Eigen::internal::traits<SVDBase>::StorageIndex StorageIndex;
|
||||
typedef Eigen::Index Index; ///< \deprecated since Eigen 3.3
|
||||
enum {
|
||||
RowsAtCompileTime = MatrixType::RowsAtCompileTime,
|
||||
@ -194,6 +209,7 @@ public:
|
||||
inline Index rows() const { return m_rows; }
|
||||
inline Index cols() const { return m_cols; }
|
||||
|
||||
#ifdef EIGEN_PARSED_BY_DOXYGEN
|
||||
/** \returns a (least squares) solution of \f$ A x = b \f$ using the current SVD decomposition of A.
|
||||
*
|
||||
* \param b the right-hand-side of the equation to solve.
|
||||
@ -205,16 +221,15 @@ public:
|
||||
*/
|
||||
template<typename Rhs>
|
||||
inline const Solve<Derived, Rhs>
|
||||
solve(const MatrixBase<Rhs>& b) const
|
||||
{
|
||||
eigen_assert(m_isInitialized && "SVD is not initialized.");
|
||||
eigen_assert(computeU() && computeV() && "SVD::solve() requires both unitaries U and V to be computed (thin unitaries suffice).");
|
||||
return Solve<Derived, Rhs>(derived(), b.derived());
|
||||
}
|
||||
|
||||
solve(const MatrixBase<Rhs>& b) const;
|
||||
#endif
|
||||
|
||||
#ifndef EIGEN_PARSED_BY_DOXYGEN
|
||||
template<typename RhsType, typename DstType>
|
||||
void _solve_impl(const RhsType &rhs, DstType &dst) const;
|
||||
|
||||
template<bool Conjugate, typename RhsType, typename DstType>
|
||||
void _solve_impl_transposed(const RhsType &rhs, DstType &dst) const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
@ -223,6 +238,13 @@ protected:
|
||||
{
|
||||
EIGEN_STATIC_ASSERT_NON_INTEGER(Scalar);
|
||||
}
|
||||
|
||||
template<bool Transpose_, typename Rhs>
|
||||
void _check_solve_assertion(const Rhs& b) const {
|
||||
eigen_assert(m_isInitialized && "SVD is not initialized.");
|
||||
eigen_assert(computeU() && computeV() && "SVDBase::solve(): Both unitaries U and V are required to be computed (thin unitaries suffice).");
|
||||
eigen_assert((Transpose_?cols():rows())==b.rows() && "SVDBase::solve(): invalid number of rows of the right hand side matrix b");
|
||||
}
|
||||
|
||||
// return true if already allocated
|
||||
bool allocate(Index rows, Index cols, unsigned int computationOptions) ;
|
||||
@ -263,17 +285,30 @@ template<typename Derived>
|
||||
template<typename RhsType, typename DstType>
|
||||
void SVDBase<Derived>::_solve_impl(const RhsType &rhs, DstType &dst) const
|
||||
{
|
||||
eigen_assert(rhs.rows() == rows());
|
||||
|
||||
// A = U S V^*
|
||||
// So A^{-1} = V S^{-1} U^*
|
||||
|
||||
Matrix<Scalar, Dynamic, RhsType::ColsAtCompileTime, 0, MatrixType::MaxRowsAtCompileTime, RhsType::MaxColsAtCompileTime> tmp;
|
||||
Matrix<typename RhsType::Scalar, Dynamic, RhsType::ColsAtCompileTime, 0, MatrixType::MaxRowsAtCompileTime, RhsType::MaxColsAtCompileTime> tmp;
|
||||
Index l_rank = rank();
|
||||
tmp.noalias() = m_matrixU.leftCols(l_rank).adjoint() * rhs;
|
||||
tmp = m_singularValues.head(l_rank).asDiagonal().inverse() * tmp;
|
||||
dst = m_matrixV.leftCols(l_rank) * tmp;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
template<bool Conjugate, typename RhsType, typename DstType>
|
||||
void SVDBase<Derived>::_solve_impl_transposed(const RhsType &rhs, DstType &dst) const
|
||||
{
|
||||
// A = U S V^*
|
||||
// So A^{-*} = U S^{-1} V^*
|
||||
// And A^{-T} = U_conj S^{-1} V^T
|
||||
Matrix<typename RhsType::Scalar, Dynamic, RhsType::ColsAtCompileTime, 0, MatrixType::MaxRowsAtCompileTime, RhsType::MaxColsAtCompileTime> tmp;
|
||||
Index l_rank = rank();
|
||||
|
||||
tmp.noalias() = m_matrixV.leftCols(l_rank).transpose().template conjugateIf<Conjugate>() * rhs;
|
||||
tmp = m_singularValues.head(l_rank).asDiagonal().inverse() * tmp;
|
||||
dst = m_matrixU.template conjugateIf<!Conjugate>().leftCols(l_rank) * tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename MatrixType>
|
||||
|
@ -46,6 +46,8 @@ void bdcsvd_method()
|
||||
VERIFY_RAISES_ASSERT(m.bdcSvd().matrixU());
|
||||
VERIFY_RAISES_ASSERT(m.bdcSvd().matrixV());
|
||||
VERIFY_IS_APPROX(m.bdcSvd(ComputeFullU|ComputeFullV).solve(m), m);
|
||||
VERIFY_IS_APPROX(m.bdcSvd(ComputeFullU|ComputeFullV).transpose().solve(m), m);
|
||||
VERIFY_IS_APPROX(m.bdcSvd(ComputeFullU|ComputeFullV).adjoint().solve(m), m);
|
||||
}
|
||||
|
||||
// compare the Singular values returned with Jacobi and Bdc
|
||||
|
@ -7,15 +7,12 @@
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#ifndef EIGEN_NO_ASSERTION_CHECKING
|
||||
#define EIGEN_NO_ASSERTION_CHECKING
|
||||
#endif
|
||||
|
||||
#define TEST_ENABLE_TEMPORARY_TRACKING
|
||||
|
||||
#include "main.h"
|
||||
#include <Eigen/Cholesky>
|
||||
#include <Eigen/QR>
|
||||
#include "solverbase.h"
|
||||
|
||||
template<typename MatrixType, int UpLo>
|
||||
typename MatrixType::RealScalar matrix_l1_norm(const MatrixType& m) {
|
||||
@ -81,15 +78,17 @@ template<typename MatrixType> void cholesky(const MatrixType& m)
|
||||
}
|
||||
|
||||
{
|
||||
STATIC_CHECK(( internal::is_same<typename LLT<MatrixType,Lower>::StorageIndex,int>::value ));
|
||||
STATIC_CHECK(( internal::is_same<typename LLT<MatrixType,Upper>::StorageIndex,int>::value ));
|
||||
|
||||
SquareMatrixType symmUp = symm.template triangularView<Upper>();
|
||||
SquareMatrixType symmLo = symm.template triangularView<Lower>();
|
||||
|
||||
LLT<SquareMatrixType,Lower> chollo(symmLo);
|
||||
VERIFY_IS_APPROX(symm, chollo.reconstructedMatrix());
|
||||
vecX = chollo.solve(vecB);
|
||||
VERIFY_IS_APPROX(symm * vecX, vecB);
|
||||
matX = chollo.solve(matB);
|
||||
VERIFY_IS_APPROX(symm * matX, matB);
|
||||
|
||||
check_solverbase<VectorType, VectorType>(symm, chollo, rows, rows, 1);
|
||||
check_solverbase<MatrixType, MatrixType>(symm, chollo, rows, cols, rows);
|
||||
|
||||
const MatrixType symmLo_inverse = chollo.solve(MatrixType::Identity(rows,cols));
|
||||
RealScalar rcond = (RealScalar(1) / matrix_l1_norm<MatrixType, Lower>(symmLo)) /
|
||||
@ -143,6 +142,9 @@ template<typename MatrixType> void cholesky(const MatrixType& m)
|
||||
|
||||
// LDLT
|
||||
{
|
||||
STATIC_CHECK(( internal::is_same<typename LDLT<MatrixType,Lower>::StorageIndex,int>::value ));
|
||||
STATIC_CHECK(( internal::is_same<typename LDLT<MatrixType,Upper>::StorageIndex,int>::value ));
|
||||
|
||||
int sign = internal::random<int>()%2 ? 1 : -1;
|
||||
|
||||
if(sign == -1)
|
||||
@ -156,10 +158,9 @@ template<typename MatrixType> void cholesky(const MatrixType& m)
|
||||
LDLT<SquareMatrixType,Lower> ldltlo(symmLo);
|
||||
VERIFY(ldltlo.info()==Success);
|
||||
VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix());
|
||||
vecX = ldltlo.solve(vecB);
|
||||
VERIFY_IS_APPROX(symm * vecX, vecB);
|
||||
matX = ldltlo.solve(matB);
|
||||
VERIFY_IS_APPROX(symm * matX, matB);
|
||||
|
||||
check_solverbase<VectorType, VectorType>(symm, ldltlo, rows, rows, 1);
|
||||
check_solverbase<MatrixType, MatrixType>(symm, ldltlo, rows, cols, rows);
|
||||
|
||||
const MatrixType symmLo_inverse = ldltlo.solve(MatrixType::Identity(rows,cols));
|
||||
RealScalar rcond = (RealScalar(1) / matrix_l1_norm<MatrixType, Lower>(symmLo)) /
|
||||
@ -313,10 +314,9 @@ template<typename MatrixType> void cholesky_cplx(const MatrixType& m)
|
||||
|
||||
LLT<RealMatrixType,Lower> chollo(symmLo);
|
||||
VERIFY_IS_APPROX(symm, chollo.reconstructedMatrix());
|
||||
vecX = chollo.solve(vecB);
|
||||
VERIFY_IS_APPROX(symm * vecX, vecB);
|
||||
// matX = chollo.solve(matB);
|
||||
// VERIFY_IS_APPROX(symm * matX, matB);
|
||||
|
||||
check_solverbase<VectorType, VectorType>(symm, chollo, rows, rows, 1);
|
||||
//check_solverbase<MatrixType, MatrixType>(symm, chollo, rows, cols, rows);
|
||||
}
|
||||
|
||||
// LDLT
|
||||
@ -333,10 +333,9 @@ template<typename MatrixType> void cholesky_cplx(const MatrixType& m)
|
||||
LDLT<RealMatrixType,Lower> ldltlo(symmLo);
|
||||
VERIFY(ldltlo.info()==Success);
|
||||
VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix());
|
||||
vecX = ldltlo.solve(vecB);
|
||||
VERIFY_IS_APPROX(symm * vecX, vecB);
|
||||
// matX = ldltlo.solve(matB);
|
||||
// VERIFY_IS_APPROX(symm * matX, matB);
|
||||
|
||||
check_solverbase<VectorType, VectorType>(symm, ldltlo, rows, rows, 1);
|
||||
//check_solverbase<MatrixType, MatrixType>(symm, ldltlo, rows, cols, rows);
|
||||
}
|
||||
}
|
||||
|
||||
@ -477,16 +476,20 @@ template<typename MatrixType> void cholesky_verify_assert()
|
||||
VERIFY_RAISES_ASSERT(llt.matrixL())
|
||||
VERIFY_RAISES_ASSERT(llt.matrixU())
|
||||
VERIFY_RAISES_ASSERT(llt.solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(llt.solveInPlace(&tmp))
|
||||
VERIFY_RAISES_ASSERT(llt.transpose().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(llt.adjoint().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(llt.solveInPlace(tmp))
|
||||
|
||||
LDLT<MatrixType> ldlt;
|
||||
VERIFY_RAISES_ASSERT(ldlt.matrixL())
|
||||
VERIFY_RAISES_ASSERT(ldlt.permutationP())
|
||||
VERIFY_RAISES_ASSERT(ldlt.transpositionsP())
|
||||
VERIFY_RAISES_ASSERT(ldlt.vectorD())
|
||||
VERIFY_RAISES_ASSERT(ldlt.isPositive())
|
||||
VERIFY_RAISES_ASSERT(ldlt.isNegative())
|
||||
VERIFY_RAISES_ASSERT(ldlt.solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(ldlt.solveInPlace(&tmp))
|
||||
VERIFY_RAISES_ASSERT(ldlt.transpose().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(ldlt.adjoint().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(ldlt.solveInPlace(tmp))
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(cholesky)
|
||||
|
@ -67,6 +67,8 @@ void jacobisvd_method()
|
||||
VERIFY_RAISES_ASSERT(m.jacobiSvd().matrixU());
|
||||
VERIFY_RAISES_ASSERT(m.jacobiSvd().matrixV());
|
||||
VERIFY_IS_APPROX(m.jacobiSvd(ComputeFullU|ComputeFullV).solve(m), m);
|
||||
VERIFY_IS_APPROX(m.jacobiSvd(ComputeFullU|ComputeFullV).transpose().solve(m), m);
|
||||
VERIFY_IS_APPROX(m.jacobiSvd(ComputeFullU|ComputeFullV).adjoint().solve(m), m);
|
||||
}
|
||||
|
||||
namespace Foo {
|
||||
|
66
test/lu.cpp
66
test/lu.cpp
@ -9,6 +9,7 @@
|
||||
|
||||
#include "main.h"
|
||||
#include <Eigen/LU>
|
||||
#include "solverbase.h"
|
||||
using namespace std;
|
||||
|
||||
template<typename MatrixType>
|
||||
@ -96,32 +97,14 @@ template<typename MatrixType> void lu_non_invertible()
|
||||
VERIFY(m1image.fullPivLu().rank() == rank);
|
||||
VERIFY_IS_APPROX(m1 * m1.adjoint() * m1image, m1image);
|
||||
|
||||
check_solverbase<CMatrixType, MatrixType>(m1, lu, rows, cols, cols2);
|
||||
|
||||
m2 = CMatrixType::Random(cols,cols2);
|
||||
m3 = m1*m2;
|
||||
m2 = CMatrixType::Random(cols,cols2);
|
||||
// test that the code, which does resize(), may be applied to an xpr
|
||||
m2.block(0,0,m2.rows(),m2.cols()) = lu.solve(m3);
|
||||
VERIFY_IS_APPROX(m3, m1*m2);
|
||||
|
||||
// test solve with transposed
|
||||
m3 = MatrixType::Random(rows,cols2);
|
||||
m2 = m1.transpose()*m3;
|
||||
m3 = MatrixType::Random(rows,cols2);
|
||||
lu.template _solve_impl_transposed<false>(m2, m3);
|
||||
VERIFY_IS_APPROX(m2, m1.transpose()*m3);
|
||||
m3 = MatrixType::Random(rows,cols2);
|
||||
m3 = lu.transpose().solve(m2);
|
||||
VERIFY_IS_APPROX(m2, m1.transpose()*m3);
|
||||
|
||||
// test solve with conjugate transposed
|
||||
m3 = MatrixType::Random(rows,cols2);
|
||||
m2 = m1.adjoint()*m3;
|
||||
m3 = MatrixType::Random(rows,cols2);
|
||||
lu.template _solve_impl_transposed<true>(m2, m3);
|
||||
VERIFY_IS_APPROX(m2, m1.adjoint()*m3);
|
||||
m3 = MatrixType::Random(rows,cols2);
|
||||
m3 = lu.adjoint().solve(m2);
|
||||
VERIFY_IS_APPROX(m2, m1.adjoint()*m3);
|
||||
}
|
||||
|
||||
template<typename MatrixType> void lu_invertible()
|
||||
@ -150,10 +133,12 @@ template<typename MatrixType> void lu_invertible()
|
||||
VERIFY(lu.isSurjective());
|
||||
VERIFY(lu.isInvertible());
|
||||
VERIFY(lu.image(m1).fullPivLu().isInvertible());
|
||||
|
||||
check_solverbase<MatrixType, MatrixType>(m1, lu, size, size, size);
|
||||
|
||||
MatrixType m1_inverse = lu.inverse();
|
||||
m3 = MatrixType::Random(size,size);
|
||||
m2 = lu.solve(m3);
|
||||
VERIFY_IS_APPROX(m3, m1*m2);
|
||||
MatrixType m1_inverse = lu.inverse();
|
||||
VERIFY_IS_APPROX(m2, m1_inverse*m3);
|
||||
|
||||
RealScalar rcond = (RealScalar(1) / matrix_l1_norm(m1)) / matrix_l1_norm(m1_inverse);
|
||||
@ -162,20 +147,6 @@ template<typename MatrixType> void lu_invertible()
|
||||
// truth.
|
||||
VERIFY(rcond_est > rcond / 10 && rcond_est < rcond * 10);
|
||||
|
||||
// test solve with transposed
|
||||
lu.template _solve_impl_transposed<false>(m3, m2);
|
||||
VERIFY_IS_APPROX(m3, m1.transpose()*m2);
|
||||
m3 = MatrixType::Random(size,size);
|
||||
m3 = lu.transpose().solve(m2);
|
||||
VERIFY_IS_APPROX(m2, m1.transpose()*m3);
|
||||
|
||||
// test solve with conjugate transposed
|
||||
lu.template _solve_impl_transposed<true>(m3, m2);
|
||||
VERIFY_IS_APPROX(m3, m1.adjoint()*m2);
|
||||
m3 = MatrixType::Random(size,size);
|
||||
m3 = lu.adjoint().solve(m2);
|
||||
VERIFY_IS_APPROX(m2, m1.adjoint()*m3);
|
||||
|
||||
// Regression test for Bug 302
|
||||
MatrixType m4 = MatrixType::Random(size,size);
|
||||
VERIFY_IS_APPROX(lu.solve(m3*m4), lu.solve(m3)*m4);
|
||||
@ -197,30 +168,17 @@ template<typename MatrixType> void lu_partial_piv()
|
||||
|
||||
VERIFY_IS_APPROX(m1, plu.reconstructedMatrix());
|
||||
|
||||
check_solverbase<MatrixType, MatrixType>(m1, plu, size, size, size);
|
||||
|
||||
MatrixType m1_inverse = plu.inverse();
|
||||
m3 = MatrixType::Random(size,size);
|
||||
m2 = plu.solve(m3);
|
||||
VERIFY_IS_APPROX(m3, m1*m2);
|
||||
MatrixType m1_inverse = plu.inverse();
|
||||
VERIFY_IS_APPROX(m2, m1_inverse*m3);
|
||||
|
||||
RealScalar rcond = (RealScalar(1) / matrix_l1_norm(m1)) / matrix_l1_norm(m1_inverse);
|
||||
const RealScalar rcond_est = plu.rcond();
|
||||
// Verify that the estimate is within a factor of 10 of the truth.
|
||||
VERIFY(rcond_est > rcond / 10 && rcond_est < rcond * 10);
|
||||
|
||||
// test solve with transposed
|
||||
plu.template _solve_impl_transposed<false>(m3, m2);
|
||||
VERIFY_IS_APPROX(m3, m1.transpose()*m2);
|
||||
m3 = MatrixType::Random(size,size);
|
||||
m3 = plu.transpose().solve(m2);
|
||||
VERIFY_IS_APPROX(m2, m1.transpose()*m3);
|
||||
|
||||
// test solve with conjugate transposed
|
||||
plu.template _solve_impl_transposed<true>(m3, m2);
|
||||
VERIFY_IS_APPROX(m3, m1.adjoint()*m2);
|
||||
m3 = MatrixType::Random(size,size);
|
||||
m3 = plu.adjoint().solve(m2);
|
||||
VERIFY_IS_APPROX(m2, m1.adjoint()*m3);
|
||||
}
|
||||
|
||||
template<typename MatrixType> void lu_verify_assert()
|
||||
@ -234,6 +192,8 @@ template<typename MatrixType> void lu_verify_assert()
|
||||
VERIFY_RAISES_ASSERT(lu.kernel())
|
||||
VERIFY_RAISES_ASSERT(lu.image(tmp))
|
||||
VERIFY_RAISES_ASSERT(lu.solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(lu.transpose().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(lu.adjoint().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(lu.determinant())
|
||||
VERIFY_RAISES_ASSERT(lu.rank())
|
||||
VERIFY_RAISES_ASSERT(lu.dimensionOfKernel())
|
||||
@ -246,6 +206,8 @@ template<typename MatrixType> void lu_verify_assert()
|
||||
VERIFY_RAISES_ASSERT(plu.matrixLU())
|
||||
VERIFY_RAISES_ASSERT(plu.permutationP())
|
||||
VERIFY_RAISES_ASSERT(plu.solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(plu.transpose().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(plu.adjoint().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(plu.determinant())
|
||||
VERIFY_RAISES_ASSERT(plu.inverse())
|
||||
}
|
||||
|
16
test/qr.cpp
16
test/qr.cpp
@ -9,6 +9,7 @@
|
||||
|
||||
#include "main.h"
|
||||
#include <Eigen/QR>
|
||||
#include "solverbase.h"
|
||||
|
||||
template<typename MatrixType> void qr(const MatrixType& m)
|
||||
{
|
||||
@ -41,11 +42,7 @@ template<typename MatrixType, int Cols2> void qr_fixedsize()
|
||||
|
||||
VERIFY_IS_APPROX(m1, qr.householderQ() * r);
|
||||
|
||||
Matrix<Scalar,Cols,Cols2> m2 = Matrix<Scalar,Cols,Cols2>::Random(Cols,Cols2);
|
||||
Matrix<Scalar,Rows,Cols2> m3 = m1*m2;
|
||||
m2 = Matrix<Scalar,Cols,Cols2>::Random(Cols,Cols2);
|
||||
m2 = qr.solve(m3);
|
||||
VERIFY_IS_APPROX(m3, m1*m2);
|
||||
check_solverbase<Matrix<Scalar,Cols,Cols2>, Matrix<Scalar,Rows,Cols2> >(m1, qr, Rows, Cols, Cols2);
|
||||
}
|
||||
|
||||
template<typename MatrixType> void qr_invertible()
|
||||
@ -57,6 +54,8 @@ template<typename MatrixType> void qr_invertible()
|
||||
typedef typename NumTraits<typename MatrixType::Scalar>::Real RealScalar;
|
||||
typedef typename MatrixType::Scalar Scalar;
|
||||
|
||||
STATIC_CHECK(( internal::is_same<typename HouseholderQR<MatrixType>::StorageIndex,int>::value ));
|
||||
|
||||
int size = internal::random<int>(10,50);
|
||||
|
||||
MatrixType m1(size, size), m2(size, size), m3(size, size);
|
||||
@ -70,9 +69,8 @@ template<typename MatrixType> void qr_invertible()
|
||||
}
|
||||
|
||||
HouseholderQR<MatrixType> qr(m1);
|
||||
m3 = MatrixType::Random(size,size);
|
||||
m2 = qr.solve(m3);
|
||||
VERIFY_IS_APPROX(m3, m1*m2);
|
||||
|
||||
check_solverbase<MatrixType, MatrixType>(m1, qr, size, size, size);
|
||||
|
||||
// now construct a matrix with prescribed determinant
|
||||
m1.setZero();
|
||||
@ -95,6 +93,8 @@ template<typename MatrixType> void qr_verify_assert()
|
||||
HouseholderQR<MatrixType> qr;
|
||||
VERIFY_RAISES_ASSERT(qr.matrixQR())
|
||||
VERIFY_RAISES_ASSERT(qr.solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(qr.transpose().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(qr.adjoint().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(qr.householderQ())
|
||||
VERIFY_RAISES_ASSERT(qr.absDeterminant())
|
||||
VERIFY_RAISES_ASSERT(qr.logAbsDeterminant())
|
||||
|
@ -11,9 +11,12 @@
|
||||
#include "main.h"
|
||||
#include <Eigen/QR>
|
||||
#include <Eigen/SVD>
|
||||
#include "solverbase.h"
|
||||
|
||||
template <typename MatrixType>
|
||||
void cod() {
|
||||
STATIC_CHECK(( internal::is_same<typename CompleteOrthogonalDecomposition<MatrixType>::StorageIndex,int>::value ));
|
||||
|
||||
Index rows = internal::random<Index>(2, EIGEN_TEST_MAX_SIZE);
|
||||
Index cols = internal::random<Index>(2, EIGEN_TEST_MAX_SIZE);
|
||||
Index cols2 = internal::random<Index>(2, EIGEN_TEST_MAX_SIZE);
|
||||
@ -46,12 +49,12 @@ void cod() {
|
||||
MatrixType c = q * t * z * cod.colsPermutation().inverse();
|
||||
VERIFY_IS_APPROX(matrix, c);
|
||||
|
||||
check_solverbase<MatrixType, MatrixType>(matrix, cod, rows, cols, cols2);
|
||||
|
||||
// Verify that we get the same minimum-norm solution as the SVD.
|
||||
MatrixType exact_solution = MatrixType::Random(cols, cols2);
|
||||
MatrixType rhs = matrix * exact_solution;
|
||||
MatrixType cod_solution = cod.solve(rhs);
|
||||
VERIFY_IS_APPROX(rhs, matrix * cod_solution);
|
||||
|
||||
// Verify that we get the same minimum-norm solution as the SVD.
|
||||
JacobiSVD<MatrixType> svd(matrix, ComputeThinU | ComputeThinV);
|
||||
MatrixType svd_solution = svd.solve(rhs);
|
||||
VERIFY_IS_APPROX(cod_solution, svd_solution);
|
||||
@ -77,13 +80,13 @@ void cod_fixedsize() {
|
||||
VERIFY(cod.isSurjective() == (rank == Cols));
|
||||
VERIFY(cod.isInvertible() == (cod.isInjective() && cod.isSurjective()));
|
||||
|
||||
check_solverbase<Matrix<Scalar, Cols, Cols2>, Matrix<Scalar, Rows, Cols2> >(matrix, cod, Rows, Cols, Cols2);
|
||||
|
||||
// Verify that we get the same minimum-norm solution as the SVD.
|
||||
Matrix<Scalar, Cols, Cols2> exact_solution;
|
||||
exact_solution.setRandom(Cols, Cols2);
|
||||
Matrix<Scalar, Rows, Cols2> rhs = matrix * exact_solution;
|
||||
Matrix<Scalar, Cols, Cols2> cod_solution = cod.solve(rhs);
|
||||
VERIFY_IS_APPROX(rhs, matrix * cod_solution);
|
||||
|
||||
// Verify that we get the same minimum-norm solution as the SVD.
|
||||
JacobiSVD<MatrixType> svd(matrix, ComputeFullU | ComputeFullV);
|
||||
Matrix<Scalar, Cols, Cols2> svd_solution = svd.solve(rhs);
|
||||
VERIFY_IS_APPROX(cod_solution, svd_solution);
|
||||
@ -93,6 +96,8 @@ template<typename MatrixType> void qr()
|
||||
{
|
||||
using std::sqrt;
|
||||
|
||||
STATIC_CHECK(( internal::is_same<typename ColPivHouseholderQR<MatrixType>::StorageIndex,int>::value ));
|
||||
|
||||
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);
|
||||
Index rank = internal::random<Index>(1, (std::min)(rows, cols)-1);
|
||||
|
||||
@ -133,13 +138,10 @@ template<typename MatrixType> void qr()
|
||||
VERIFY_IS_APPROX_OR_LESS_THAN(y, x);
|
||||
}
|
||||
|
||||
MatrixType m2 = MatrixType::Random(cols,cols2);
|
||||
MatrixType m3 = m1*m2;
|
||||
m2 = MatrixType::Random(cols,cols2);
|
||||
m2 = qr.solve(m3);
|
||||
VERIFY_IS_APPROX(m3, m1*m2);
|
||||
check_solverbase<MatrixType, MatrixType>(m1, qr, rows, cols, cols2);
|
||||
|
||||
{
|
||||
MatrixType m2, m3;
|
||||
Index size = rows;
|
||||
do {
|
||||
m1 = MatrixType::Random(size,size);
|
||||
@ -173,11 +175,8 @@ template<typename MatrixType, int Cols2> void qr_fixedsize()
|
||||
Matrix<Scalar,Rows,Cols> c = qr.householderQ() * r * qr.colsPermutation().inverse();
|
||||
VERIFY_IS_APPROX(m1, c);
|
||||
|
||||
Matrix<Scalar,Cols,Cols2> m2 = Matrix<Scalar,Cols,Cols2>::Random(Cols,Cols2);
|
||||
Matrix<Scalar,Rows,Cols2> m3 = m1*m2;
|
||||
m2 = Matrix<Scalar,Cols,Cols2>::Random(Cols,Cols2);
|
||||
m2 = qr.solve(m3);
|
||||
VERIFY_IS_APPROX(m3, m1*m2);
|
||||
check_solverbase<Matrix<Scalar,Cols,Cols2>, Matrix<Scalar,Rows,Cols2> >(m1, qr, Rows, Cols, Cols2);
|
||||
|
||||
// Verify that the absolute value of the diagonal elements in R are
|
||||
// non-increasing until they reache the singularity threshold.
|
||||
RealScalar threshold =
|
||||
@ -264,9 +263,8 @@ template<typename MatrixType> void qr_invertible()
|
||||
}
|
||||
|
||||
ColPivHouseholderQR<MatrixType> qr(m1);
|
||||
m3 = MatrixType::Random(size,size);
|
||||
m2 = qr.solve(m3);
|
||||
//VERIFY_IS_APPROX(m3, m1*m2);
|
||||
|
||||
check_solverbase<MatrixType, MatrixType>(m1, qr, size, size, size);
|
||||
|
||||
// now construct a matrix with prescribed determinant
|
||||
m1.setZero();
|
||||
@ -286,6 +284,8 @@ template<typename MatrixType> void qr_verify_assert()
|
||||
ColPivHouseholderQR<MatrixType> qr;
|
||||
VERIFY_RAISES_ASSERT(qr.matrixQR())
|
||||
VERIFY_RAISES_ASSERT(qr.solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(qr.transpose().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(qr.adjoint().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(qr.householderQ())
|
||||
VERIFY_RAISES_ASSERT(qr.dimensionOfKernel())
|
||||
VERIFY_RAISES_ASSERT(qr.isInjective())
|
||||
@ -296,6 +296,25 @@ template<typename MatrixType> void qr_verify_assert()
|
||||
VERIFY_RAISES_ASSERT(qr.logAbsDeterminant())
|
||||
}
|
||||
|
||||
template<typename MatrixType> void cod_verify_assert()
|
||||
{
|
||||
MatrixType tmp;
|
||||
|
||||
CompleteOrthogonalDecomposition<MatrixType> cod;
|
||||
VERIFY_RAISES_ASSERT(cod.matrixQTZ())
|
||||
VERIFY_RAISES_ASSERT(cod.solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(cod.transpose().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(cod.adjoint().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(cod.householderQ())
|
||||
VERIFY_RAISES_ASSERT(cod.dimensionOfKernel())
|
||||
VERIFY_RAISES_ASSERT(cod.isInjective())
|
||||
VERIFY_RAISES_ASSERT(cod.isSurjective())
|
||||
VERIFY_RAISES_ASSERT(cod.isInvertible())
|
||||
VERIFY_RAISES_ASSERT(cod.pseudoInverse())
|
||||
VERIFY_RAISES_ASSERT(cod.absDeterminant())
|
||||
VERIFY_RAISES_ASSERT(cod.logAbsDeterminant())
|
||||
}
|
||||
|
||||
EIGEN_DECLARE_TEST(qr_colpivoting)
|
||||
{
|
||||
for(int i = 0; i < g_repeat; i++) {
|
||||
@ -330,6 +349,13 @@ EIGEN_DECLARE_TEST(qr_colpivoting)
|
||||
CALL_SUBTEST_6(qr_verify_assert<MatrixXcf>());
|
||||
CALL_SUBTEST_3(qr_verify_assert<MatrixXcd>());
|
||||
|
||||
CALL_SUBTEST_7(cod_verify_assert<Matrix3f>());
|
||||
CALL_SUBTEST_8(cod_verify_assert<Matrix3d>());
|
||||
CALL_SUBTEST_1(cod_verify_assert<MatrixXf>());
|
||||
CALL_SUBTEST_2(cod_verify_assert<MatrixXd>());
|
||||
CALL_SUBTEST_6(cod_verify_assert<MatrixXcf>());
|
||||
CALL_SUBTEST_3(cod_verify_assert<MatrixXcd>());
|
||||
|
||||
// Test problem size constructors
|
||||
CALL_SUBTEST_9(ColPivHouseholderQR<MatrixXf>(10, 20));
|
||||
|
||||
|
@ -10,9 +10,12 @@
|
||||
|
||||
#include "main.h"
|
||||
#include <Eigen/QR>
|
||||
#include "solverbase.h"
|
||||
|
||||
template<typename MatrixType> void qr()
|
||||
{
|
||||
STATIC_CHECK(( internal::is_same<typename FullPivHouseholderQR<MatrixType>::StorageIndex,int>::value ));
|
||||
|
||||
static const int Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime;
|
||||
Index max_size = EIGEN_TEST_MAX_SIZE;
|
||||
Index min_size = numext::maxi(1,EIGEN_TEST_MAX_SIZE/10);
|
||||
@ -48,13 +51,10 @@ template<typename MatrixType> void qr()
|
||||
MatrixType tmp;
|
||||
VERIFY_IS_APPROX(tmp.noalias() = qr.matrixQ() * r, (qr.matrixQ() * r).eval());
|
||||
|
||||
MatrixType m2 = MatrixType::Random(cols,cols2);
|
||||
MatrixType m3 = m1*m2;
|
||||
m2 = MatrixType::Random(cols,cols2);
|
||||
m2 = qr.solve(m3);
|
||||
VERIFY_IS_APPROX(m3, m1*m2);
|
||||
check_solverbase<MatrixType, MatrixType>(m1, qr, rows, cols, cols2);
|
||||
|
||||
{
|
||||
MatrixType m2, m3;
|
||||
Index size = rows;
|
||||
do {
|
||||
m1 = MatrixType::Random(size,size);
|
||||
@ -93,9 +93,7 @@ template<typename MatrixType> void qr_invertible()
|
||||
VERIFY(qr.isInvertible());
|
||||
VERIFY(qr.isSurjective());
|
||||
|
||||
m3 = MatrixType::Random(size,size);
|
||||
m2 = qr.solve(m3);
|
||||
VERIFY_IS_APPROX(m3, m1*m2);
|
||||
check_solverbase<MatrixType, MatrixType>(m1, qr, size, size, size);
|
||||
|
||||
// now construct a matrix with prescribed determinant
|
||||
m1.setZero();
|
||||
@ -115,6 +113,8 @@ template<typename MatrixType> void qr_verify_assert()
|
||||
FullPivHouseholderQR<MatrixType> qr;
|
||||
VERIFY_RAISES_ASSERT(qr.matrixQR())
|
||||
VERIFY_RAISES_ASSERT(qr.solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(qr.transpose().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(qr.adjoint().solve(tmp))
|
||||
VERIFY_RAISES_ASSERT(qr.matrixQ())
|
||||
VERIFY_RAISES_ASSERT(qr.dimensionOfKernel())
|
||||
VERIFY_RAISES_ASSERT(qr.isInjective())
|
||||
|
36
test/solverbase.h
Normal file
36
test/solverbase.h
Normal file
@ -0,0 +1,36 @@
|
||||
#ifndef TEST_SOLVERBASE_H
|
||||
#define TEST_SOLVERBASE_H
|
||||
|
||||
template<typename DstType, typename RhsType, typename MatrixType, typename SolverType>
|
||||
void check_solverbase(const MatrixType& matrix, const SolverType& solver, Index rows, Index cols, Index cols2)
|
||||
{
|
||||
// solve
|
||||
DstType m2 = DstType::Random(cols,cols2);
|
||||
RhsType m3 = matrix*m2;
|
||||
DstType solver_solution = DstType::Random(cols,cols2);
|
||||
solver._solve_impl(m3, solver_solution);
|
||||
VERIFY_IS_APPROX(m3, matrix*solver_solution);
|
||||
solver_solution = DstType::Random(cols,cols2);
|
||||
solver_solution = solver.solve(m3);
|
||||
VERIFY_IS_APPROX(m3, matrix*solver_solution);
|
||||
// test solve with transposed
|
||||
m3 = RhsType::Random(rows,cols2);
|
||||
m2 = matrix.transpose()*m3;
|
||||
RhsType solver_solution2 = RhsType::Random(rows,cols2);
|
||||
solver.template _solve_impl_transposed<false>(m2, solver_solution2);
|
||||
VERIFY_IS_APPROX(m2, matrix.transpose()*solver_solution2);
|
||||
solver_solution2 = RhsType::Random(rows,cols2);
|
||||
solver_solution2 = solver.transpose().solve(m2);
|
||||
VERIFY_IS_APPROX(m2, matrix.transpose()*solver_solution2);
|
||||
// test solve with conjugate transposed
|
||||
m3 = RhsType::Random(rows,cols2);
|
||||
m2 = matrix.adjoint()*m3;
|
||||
solver_solution2 = RhsType::Random(rows,cols2);
|
||||
solver.template _solve_impl_transposed<true>(m2, solver_solution2);
|
||||
VERIFY_IS_APPROX(m2, matrix.adjoint()*solver_solution2);
|
||||
solver_solution2 = RhsType::Random(rows,cols2);
|
||||
solver_solution2 = solver.adjoint().solve(m2);
|
||||
VERIFY_IS_APPROX(m2, matrix.adjoint()*solver_solution2);
|
||||
}
|
||||
|
||||
#endif // TEST_SOLVERBASE_H
|
@ -17,6 +17,7 @@
|
||||
#endif
|
||||
|
||||
#include "svd_fill.h"
|
||||
#include "solverbase.h"
|
||||
|
||||
// Check that the matrix m is properly reconstructed and that the U and V factors are unitary
|
||||
// The SVD must have already been computed.
|
||||
@ -219,12 +220,33 @@ void svd_min_norm(const MatrixType& m, unsigned int computationOptions)
|
||||
VERIFY_IS_APPROX(x21, x3);
|
||||
}
|
||||
|
||||
template<typename MatrixType, typename SolverType>
|
||||
void svd_test_solvers(const MatrixType& m, const SolverType& solver) {
|
||||
Index rows, cols, cols2;
|
||||
|
||||
rows = m.rows();
|
||||
cols = m.cols();
|
||||
|
||||
if(MatrixType::ColsAtCompileTime==Dynamic)
|
||||
{
|
||||
cols2 = internal::random<int>(2,EIGEN_TEST_MAX_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
cols2 = cols;
|
||||
}
|
||||
typedef Matrix<typename MatrixType::Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> CMatrixType;
|
||||
check_solverbase<CMatrixType, MatrixType>(m, solver, rows, cols, cols2);
|
||||
}
|
||||
|
||||
// Check full, compare_to_full, least_square, and min_norm for all possible compute-options
|
||||
template<typename SvdType, typename MatrixType>
|
||||
void svd_test_all_computation_options(const MatrixType& m, bool full_only)
|
||||
{
|
||||
// if (QRPreconditioner == NoQRPreconditioner && m.rows() != m.cols())
|
||||
// return;
|
||||
STATIC_CHECK(( internal::is_same<typename SvdType::StorageIndex,int>::value ));
|
||||
|
||||
SvdType fullSvd(m, ComputeFullU|ComputeFullV);
|
||||
CALL_SUBTEST(( svd_check_full(m, fullSvd) ));
|
||||
CALL_SUBTEST(( svd_least_square<SvdType>(m, ComputeFullU | ComputeFullV) ));
|
||||
@ -234,6 +256,9 @@ void svd_test_all_computation_options(const MatrixType& m, bool full_only)
|
||||
// remark #111: statement is unreachable
|
||||
#pragma warning disable 111
|
||||
#endif
|
||||
|
||||
svd_test_solvers(m, fullSvd);
|
||||
|
||||
if(full_only)
|
||||
return;
|
||||
|
||||
@ -448,6 +473,8 @@ void svd_verify_assert(const MatrixType& m)
|
||||
VERIFY_RAISES_ASSERT(svd.singularValues())
|
||||
VERIFY_RAISES_ASSERT(svd.matrixV())
|
||||
VERIFY_RAISES_ASSERT(svd.solve(rhs))
|
||||
VERIFY_RAISES_ASSERT(svd.transpose().solve(rhs))
|
||||
VERIFY_RAISES_ASSERT(svd.adjoint().solve(rhs))
|
||||
MatrixType a = MatrixType::Zero(rows, cols);
|
||||
a.setZero();
|
||||
svd.compute(a, 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user