2016-02-06 16:32:00 -08:00
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2016 Rasmus Munk Larsen <rmlarsen@google.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
# ifndef EIGEN_COMPLETEORTHOGONALDECOMPOSITION_H
# define EIGEN_COMPLETEORTHOGONALDECOMPOSITION_H
namespace Eigen {
namespace internal {
2021-08-04 22:41:52 +00:00
template < typename MatrixType_ >
struct traits < CompleteOrthogonalDecomposition < MatrixType_ > >
: traits < MatrixType_ > {
2019-01-17 01:17:39 +01:00
typedef MatrixXpr XprKind ;
typedef SolverStorage StorageKind ;
typedef int StorageIndex ;
2016-02-06 16:32:00 -08:00
enum { Flags = 0 } ;
} ;
} // end namespace internal
/** \ingroup QR_Module
*
* \ class CompleteOrthogonalDecomposition
*
* \ brief Complete orthogonal decomposition ( COD ) of a matrix .
*
* \ param MatrixType the type of the matrix of which we are computing the COD .
*
2016-07-27 09:55:39 +02:00
* This class performs a rank - revealing complete orthogonal decomposition of a
2016-02-06 16:32:00 -08:00
* matrix \ b A into matrices \ b P , \ b Q , \ b T , and \ b Z such that
* \ f [
2016-07-27 09:55:39 +02:00
* \ mathbf { A } \ , \ mathbf { P } = \ mathbf { Q } \ ,
* \ begin { bmatrix } \ mathbf { T } & \ mathbf { 0 } \ \
* \ mathbf { 0 } & \ mathbf { 0 } \ end { bmatrix } \ , \ mathbf { Z }
2016-02-06 16:32:00 -08:00
* \ f ]
* by using Householder transformations . Here , \ b P is a permutation matrix ,
* \ b Q and \ b Z are unitary matrices and \ b T an upper triangular matrix of
* size rank - by - rank . \ b A may be rank deficient .
*
2016-07-04 17:18:26 +02:00
* This class supports the \ link InplaceDecomposition inplace decomposition \ endlink mechanism .
*
2016-02-06 16:32:00 -08:00
* \ sa MatrixBase : : completeOrthogonalDecomposition ( )
*/
2021-08-04 22:41:52 +00:00
template < typename MatrixType_ > class CompleteOrthogonalDecomposition
: public SolverBase < CompleteOrthogonalDecomposition < MatrixType_ > >
2019-01-17 01:17:39 +01:00
{
2016-02-06 16:32:00 -08:00
public :
2021-08-04 22:41:52 +00:00
typedef MatrixType_ MatrixType ;
2019-01-17 01:17:39 +01:00
typedef SolverBase < CompleteOrthogonalDecomposition > Base ;
template < typename Derived >
friend struct internal : : solve_assertion ;
EIGEN_GENERIC_PUBLIC_INTERFACE ( CompleteOrthogonalDecomposition )
2016-02-06 16:32:00 -08:00
enum {
MaxRowsAtCompileTime = MatrixType : : MaxRowsAtCompileTime ,
MaxColsAtCompileTime = MatrixType : : MaxColsAtCompileTime
} ;
typedef typename internal : : plain_diag_type < MatrixType > : : type HCoeffsType ;
typedef PermutationMatrix < ColsAtCompileTime , MaxColsAtCompileTime >
PermutationType ;
typedef typename internal : : plain_row_type < MatrixType , Index > : : type
IntRowVectorType ;
typedef typename internal : : plain_row_type < MatrixType > : : type RowVectorType ;
typedef typename internal : : plain_row_type < MatrixType , RealScalar > : : type
RealRowVectorType ;
typedef HouseholderSequence <
MatrixType , typename internal : : remove_all <
typename HCoeffsType : : ConjugateReturnType > : : type >
HouseholderSequenceType ;
2016-02-09 20:35:20 -08:00
typedef typename MatrixType : : PlainObject PlainObject ;
2016-02-06 16:32:00 -08:00
private :
typedef typename PermutationType : : Index PermIndexType ;
public :
/**
* \ brief Default Constructor .
*
* The default constructor is useful in cases in which the user intends to
* perform decompositions via
* \ c CompleteOrthogonalDecomposition : : compute ( const * MatrixType & ) .
*/
CompleteOrthogonalDecomposition ( ) : m_cpqr ( ) , m_zCoeffs ( ) , m_temp ( ) { }
/** \brief Default Constructor with memory preallocation
*
* Like the default constructor but with preallocation of the internal data
* according to the specified problem \ a size .
* \ sa CompleteOrthogonalDecomposition ( )
*/
CompleteOrthogonalDecomposition ( Index rows , Index cols )
: m_cpqr ( rows , cols ) , m_zCoeffs ( ( std : : min ) ( rows , cols ) ) , m_temp ( cols ) { }
/** \brief Constructs a complete orthogonal decomposition from a given
* matrix .
*
* This constructor computes the complete orthogonal decomposition of the
* matrix \ a matrix by calling the method compute ( ) . The default
* threshold for rank determination will be used . It is a short cut for :
*
* \ code
* CompleteOrthogonalDecomposition < MatrixType > cod ( matrix . rows ( ) ,
* matrix . cols ( ) ) ;
* cod . setThreshold ( Default ) ;
* cod . compute ( matrix ) ;
* \ endcode
*
* \ sa compute ( )
*/
template < typename InputType >
explicit CompleteOrthogonalDecomposition ( const EigenBase < InputType > & matrix )
: m_cpqr ( matrix . rows ( ) , matrix . cols ( ) ) ,
m_zCoeffs ( ( std : : min ) ( matrix . rows ( ) , matrix . cols ( ) ) ) ,
2016-07-04 15:13:35 +02:00
m_temp ( matrix . cols ( ) )
{
2016-02-06 16:32:00 -08:00
compute ( matrix . derived ( ) ) ;
}
2016-07-04 15:13:35 +02:00
/** \brief Constructs a complete orthogonal decomposition from a given matrix
*
2016-07-04 17:18:26 +02:00
* This overloaded constructor is provided for \ link InplaceDecomposition inplace decomposition \ endlink when \ c MatrixType is a Eigen : : Ref .
2016-07-04 15:13:35 +02:00
*
* \ sa CompleteOrthogonalDecomposition ( const EigenBase & )
*/
template < typename InputType >
explicit CompleteOrthogonalDecomposition ( EigenBase < InputType > & matrix )
: m_cpqr ( matrix . derived ( ) ) ,
m_zCoeffs ( ( std : : min ) ( matrix . rows ( ) , matrix . cols ( ) ) ) ,
m_temp ( matrix . cols ( ) )
{
computeInPlace ( ) ;
2019-01-17 01:17:39 +01:00
}
2016-07-04 15:13:35 +02:00
2019-01-17 01:17:39 +01:00
# ifdef EIGEN_PARSED_BY_DOXYGEN
2016-02-06 16:32:00 -08:00
/** This method computes the minimum-norm solution X to a least squares
2016-07-27 09:55:39 +02:00
* problem \ f [ \ mathrm { minimize } \ | A X - B \ | , \ f ] where \ b A is the matrix of
2016-02-06 16:32:00 -08:00
* which \ c * this is the complete orthogonal decomposition .
*
2017-01-04 23:27:33 +01:00
* \ param b the right - hand sides of the problem to solve .
2016-02-06 16:32:00 -08:00
*
* \ returns a solution .
*
*/
template < typename Rhs >
inline const Solve < CompleteOrthogonalDecomposition , Rhs > solve (
2019-01-17 01:17:39 +01:00
const MatrixBase < Rhs > & b ) const ;
# endif
2016-02-06 16:32:00 -08:00
HouseholderSequenceType householderQ ( void ) const ;
HouseholderSequenceType matrixQ ( void ) const { return m_cpqr . householderQ ( ) ; }
/** \returns the matrix \b Z.
*/
MatrixType matrixZ ( ) const {
MatrixType Z = MatrixType : : Identity ( m_cpqr . cols ( ) , m_cpqr . cols ( ) ) ;
2019-01-17 01:17:39 +01:00
applyZOnTheLeftInPlace < false > ( Z ) ;
return Z ;
2016-02-06 16:32:00 -08:00
}
/** \returns a reference to the matrix where the complete orthogonal
* decomposition is stored
*/
const MatrixType & matrixQTZ ( ) const { return m_cpqr . matrixQR ( ) ; }
/** \returns a reference to the matrix where the complete orthogonal
* decomposition is stored .
* \ warning The strict lower part and \ code cols ( ) - rank ( ) \ endcode right
* columns of this matrix contains internal values .
* Only the upper triangular part should be referenced . To get it , use
* \ code matrixT ( ) . template triangularView < Upper > ( ) \ endcode
* For rank - deficient matrices , use
* \ code
* matrixR ( ) . topLeftCorner ( rank ( ) , rank ( ) ) . template triangularView < Upper > ( )
* \ endcode
*/
const MatrixType & matrixT ( ) const { return m_cpqr . matrixQR ( ) ; }
template < typename InputType >
2016-07-04 15:13:35 +02:00
CompleteOrthogonalDecomposition & compute ( const EigenBase < InputType > & matrix ) {
// Compute the column pivoted QR factorization A P = Q R.
m_cpqr . compute ( matrix ) ;
computeInPlace ( ) ;
return * this ;
}
2016-02-06 16:32:00 -08:00
/** \returns a const reference to the column permutation matrix */
const PermutationType & colsPermutation ( ) const {
return m_cpqr . colsPermutation ( ) ;
}
/** \returns the absolute value of the determinant of the matrix of which
* * this is the complete orthogonal decomposition . It has only linear
* complexity ( that is , O ( n ) where n is the dimension of the square matrix )
* as the complete orthogonal decomposition has already been computed .
*
* \ note This is only for square matrices .
*
* \ warning a determinant can be very big or small , so for matrices
* of large enough dimension , there is a risk of overflow / underflow .
* One way to work around that is to use logAbsDeterminant ( ) instead .
*
* \ sa logAbsDeterminant ( ) , MatrixBase : : determinant ( )
*/
typename MatrixType : : RealScalar absDeterminant ( ) const ;
/** \returns the natural log of the absolute value of the determinant of the
* matrix of which * this is the complete orthogonal decomposition . It has
* only linear complexity ( that is , O ( n ) where n is the dimension of the
* square matrix ) as the complete orthogonal decomposition has already been
* computed .
*
* \ note This is only for square matrices .
*
* \ note This method is useful to work around the risk of overflow / underflow
* that ' s inherent to determinant computation .
*
* \ sa absDeterminant ( ) , MatrixBase : : determinant ( )
*/
typename MatrixType : : RealScalar logAbsDeterminant ( ) const ;
/** \returns the rank of the matrix of which *this is the complete orthogonal
* decomposition .
*
* \ note This method has to determine which pivots should be considered
* nonzero . For that , it uses the threshold value that you can control by
* calling setThreshold ( const RealScalar & ) .
*/
inline Index rank ( ) const { return m_cpqr . rank ( ) ; }
/** \returns the dimension of the kernel of the matrix of which *this is the
* complete orthogonal decomposition .
*
* \ note This method has to determine which pivots should be considered
* nonzero . For that , it uses the threshold value that you can control by
* calling setThreshold ( const RealScalar & ) .
*/
inline Index dimensionOfKernel ( ) const { return m_cpqr . dimensionOfKernel ( ) ; }
/** \returns true if the matrix of which *this is the decomposition represents
* an injective linear map , i . e . has trivial kernel ; false otherwise .
*
* \ note This method has to determine which pivots should be considered
* nonzero . For that , it uses the threshold value that you can control by
* calling setThreshold ( const RealScalar & ) .
*/
inline bool isInjective ( ) const { return m_cpqr . isInjective ( ) ; }
/** \returns true if the matrix of which *this is the decomposition represents
* a surjective linear map ; false otherwise .
*
* \ note This method has to determine which pivots should be considered
* nonzero . For that , it uses the threshold value that you can control by
* calling setThreshold ( const RealScalar & ) .
*/
inline bool isSurjective ( ) const { return m_cpqr . isSurjective ( ) ; }
/** \returns true if the matrix of which *this is the complete orthogonal
* decomposition is invertible .
*
* \ note This method has to determine which pivots should be considered
* nonzero . For that , it uses the threshold value that you can control by
* calling setThreshold ( const RealScalar & ) .
*/
inline bool isInvertible ( ) const { return m_cpqr . isInvertible ( ) ; }
2016-02-09 20:35:20 -08:00
/** \returns the pseudo-inverse of the matrix of which *this is the complete
2016-02-06 16:32:00 -08:00
* orthogonal decomposition .
2016-02-10 13:03:07 -08:00
* \ warning : Do not compute \ c this - > pseudoInverse ( ) * rhs to solve a linear systems .
2016-02-09 20:35:20 -08:00
* It is more efficient and numerically stable to call \ c this - > solve ( rhs ) .
2016-02-06 16:32:00 -08:00
*/
2016-02-10 13:03:07 -08:00
inline const Inverse < CompleteOrthogonalDecomposition > pseudoInverse ( ) const
2016-02-09 20:35:20 -08:00
{
2019-01-17 01:17:39 +01:00
eigen_assert ( m_cpqr . m_isInitialized & & " CompleteOrthogonalDecomposition is not initialized. " ) ;
2016-02-09 20:35:20 -08:00
return Inverse < CompleteOrthogonalDecomposition > ( * this ) ;
}
2016-02-06 16:32:00 -08:00
inline Index rows ( ) const { return m_cpqr . rows ( ) ; }
inline Index cols ( ) const { return m_cpqr . cols ( ) ; }
/** \returns a const reference to the vector of Householder coefficients used
* to represent the factor \ c Q .
*
* For advanced uses only .
*/
inline const HCoeffsType & hCoeffs ( ) const { return m_cpqr . hCoeffs ( ) ; }
/** \returns a const reference to the vector of Householder coefficients
* used to represent the factor \ c Z .
*
* For advanced uses only .
*/
const HCoeffsType & zCoeffs ( ) const { return m_zCoeffs ; }
/** Allows to prescribe a threshold to be used by certain methods, such as
* rank ( ) , who need to determine when pivots are to be considered nonzero .
* Most be called before calling compute ( ) .
*
* When it needs to get the threshold value , Eigen calls threshold ( ) . By
* default , this uses a formula to automatically determine a reasonable
* threshold . Once you have called the present method
* setThreshold ( const RealScalar & ) , your value is used instead .
*
* \ param threshold The new value to use as the threshold .
*
* A pivot will be considered nonzero if its absolute value is strictly
* greater than
* \ f $ \ vert pivot \ vert \ leqslant threshold \ times \ vert maxpivot \ vert \ f $
* where maxpivot is the biggest pivot .
*
* If you want to come back to the default behavior , call
* setThreshold ( Default_t )
*/
CompleteOrthogonalDecomposition & setThreshold ( const RealScalar & threshold ) {
m_cpqr . setThreshold ( threshold ) ;
return * this ;
}
/** Allows to come back to the default behavior, letting Eigen use its default
* formula for determining the threshold .
*
* You should pass the special object Eigen : : Default as parameter here .
* \ code qr . setThreshold ( Eigen : : Default ) ; \ endcode
*
* See the documentation of setThreshold ( const RealScalar & ) .
*/
CompleteOrthogonalDecomposition & setThreshold ( Default_t ) {
m_cpqr . setThreshold ( Default ) ;
return * this ;
}
/** Returns the threshold that will be used by certain methods such as rank().
*
* See the documentation of setThreshold ( const RealScalar & ) .
*/
RealScalar threshold ( ) const { return m_cpqr . threshold ( ) ; }
/** \returns the number of nonzero pivots in the complete orthogonal
2016-02-08 09:01:43 -08:00
* decomposition . Here nonzero is meant in the exact sense , not in a
* fuzzy sense . So that notion isn ' t really intrinsically interesting ,
* but it is still useful when implementing algorithms .
2016-02-06 16:32:00 -08:00
*
* \ sa rank ( )
*/
inline Index nonzeroPivots ( ) const { return m_cpqr . nonzeroPivots ( ) ; }
/** \returns the absolute value of the biggest pivot, i.e. the biggest
* diagonal coefficient of R .
*/
inline RealScalar maxPivot ( ) const { return m_cpqr . maxPivot ( ) ; }
/** \brief Reports whether the complete orthogonal decomposition was
2018-03-11 10:01:44 -04:00
* successful .
2016-02-06 16:32:00 -08:00
*
* \ note This function always returns \ c Success . It is provided for
* compatibility
* with other factorization routines .
* \ returns \ c Success
*/
ComputationInfo info ( ) const {
eigen_assert ( m_cpqr . m_isInitialized & & " Decomposition is not initialized. " ) ;
return Success ;
}
# ifndef EIGEN_PARSED_BY_DOXYGEN
template < typename RhsType , typename DstType >
2017-02-28 11:57:00 -08:00
void _solve_impl ( const RhsType & rhs , DstType & dst ) const ;
2019-01-17 01:17:39 +01:00
template < bool Conjugate , typename RhsType , typename DstType >
void _solve_impl_transposed ( const RhsType & rhs , DstType & dst ) const ;
2016-02-06 16:32:00 -08:00
# endif
protected :
static void check_template_parameters ( ) {
EIGEN_STATIC_ASSERT_NON_INTEGER ( Scalar ) ;
}
2019-01-17 01:17:39 +01:00
template < bool Transpose_ , typename Rhs >
void _check_solve_assertion ( const Rhs & b ) const {
2019-01-18 10:41:14 +01:00
EIGEN_ONLY_USED_FOR_DEBUG ( b ) ;
2019-01-17 01:17:39 +01:00
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 " ) ;
}
2016-07-04 15:13:35 +02:00
void computeInPlace ( ) ;
2019-01-17 01:17:39 +01:00
/** 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 ;
2016-02-08 09:01:43 -08:00
/** Overwrites \b rhs with \f$ \mathbf{Z}^* * \mathbf{rhs} \f$.
*/
template < typename Rhs >
void applyZAdjointOnTheLeftInPlace ( Rhs & rhs ) const ;
2016-02-06 16:32:00 -08:00
ColPivHouseholderQR < MatrixType > m_cpqr ;
HCoeffsType m_zCoeffs ;
RowVectorType m_temp ;
} ;
template < typename MatrixType >
typename MatrixType : : RealScalar
CompleteOrthogonalDecomposition < MatrixType > : : absDeterminant ( ) const {
return m_cpqr . absDeterminant ( ) ;
}
template < typename MatrixType >
typename MatrixType : : RealScalar
CompleteOrthogonalDecomposition < MatrixType > : : logAbsDeterminant ( ) const {
return m_cpqr . logAbsDeterminant ( ) ;
}
/** Performs the complete orthogonal decomposition of the given matrix \a
* matrix . The result of the factorization is stored into \ c * this , and a
* reference to \ c * this is returned .
*
* \ sa class CompleteOrthogonalDecomposition ,
* CompleteOrthogonalDecomposition ( const MatrixType & )
*/
template < typename MatrixType >
2016-07-04 15:13:35 +02:00
void CompleteOrthogonalDecomposition < MatrixType > : : computeInPlace ( )
{
2016-02-06 16:32:00 -08:00
check_template_parameters ( ) ;
// the column permutation is stored as int indices, so just to be sure:
2016-07-04 15:13:35 +02:00
eigen_assert ( m_cpqr . cols ( ) < = NumTraits < int > : : highest ( ) ) ;
2016-02-06 16:32:00 -08:00
const Index rank = m_cpqr . rank ( ) ;
2016-07-04 15:13:35 +02:00
const Index cols = m_cpqr . cols ( ) ;
const Index rows = m_cpqr . rows ( ) ;
2016-04-21 16:49:28 -07:00
m_zCoeffs . resize ( ( std : : min ) ( rows , cols ) ) ;
m_temp . resize ( cols ) ;
2016-02-06 16:32:00 -08:00
if ( rank < cols ) {
// We have reduced the (permuted) matrix to the form
// [R11 R12]
// [ 0 R22]
// where R11 is r-by-r (r = rank) upper triangular, R12 is
// r-by-(n-r), and R22 is empty or the norm of R22 is negligible.
// We now compute the complete orthogonal decomposition by applying
// Householder transformations from the right to the upper trapezoidal
// matrix X = [R11 R12] to zero out R12 and obtain the factorization
// [R11 R12] = [T11 0] * Z, where T11 is r-by-r upper triangular and
// Z = Z(0) * Z(1) ... Z(r-1) is an n-by-n orthogonal matrix.
// We store the data representing Z in R12 and m_zCoeffs.
for ( Index k = rank - 1 ; k > = 0 ; - - k ) {
if ( k ! = rank - 1 ) {
// Given the API for Householder reflectors, it is more convenient if
// we swap the leading parts of columns k and r-1 (zero-based) to form
// the matrix X_k = [X(0:k, k), X(0:k, r:n)]
m_cpqr . m_qr . col ( k ) . head ( k + 1 ) . swap (
m_cpqr . m_qr . col ( rank - 1 ) . head ( k + 1 ) ) ;
}
// Construct Householder reflector Z(k) to zero out the last row of X_k,
// i.e. choose Z(k) such that
// [X(k, k), X(k, r:n)] * Z(k) = [beta, 0, .., 0].
RealScalar beta ;
m_cpqr . m_qr . row ( k )
. tail ( cols - rank + 1 )
. makeHouseholderInPlace ( m_zCoeffs ( k ) , beta ) ;
m_cpqr . m_qr ( k , rank - 1 ) = beta ;
if ( k > 0 ) {
// Apply Z(k) to the first k rows of X_k
m_cpqr . m_qr . topRightCorner ( k , cols - rank + 1 )
. applyHouseholderOnTheRight (
2018-04-15 10:15:28 +02:00
m_cpqr . m_qr . row ( k ) . tail ( cols - rank ) . adjoint ( ) , m_zCoeffs ( k ) ,
2016-02-06 16:32:00 -08:00
& m_temp ( 0 ) ) ;
}
if ( k ! = rank - 1 ) {
// Swap X(0:k,k) back to its proper location.
m_cpqr . m_qr . col ( k ) . head ( k + 1 ) . swap (
m_cpqr . m_qr . col ( rank - 1 ) . head ( k + 1 ) ) ;
}
}
}
}
2019-01-17 01:17:39 +01:00
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 ) ) ;
}
}
}
2016-02-06 16:32:00 -08:00
template < typename MatrixType >
template < typename Rhs >
void CompleteOrthogonalDecomposition < MatrixType > : : applyZAdjointOnTheLeftInPlace (
Rhs & rhs ) const {
const Index cols = this - > cols ( ) ;
const Index nrhs = rhs . cols ( ) ;
const Index rank = this - > rank ( ) ;
2019-01-17 01:17:39 +01:00
Matrix < typename Rhs : : Scalar , Dynamic , 1 > temp ( ( std : : max ) ( cols , nrhs ) ) ;
2016-02-06 16:32:00 -08:00
for ( Index k = 0 ; k < rank ; + + 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 ) . adjoint ( ) , zCoeffs ( ) ( k ) ,
& temp ( 0 ) ) ;
if ( k ! = rank - 1 ) {
rhs . row ( k ) . swap ( rhs . row ( rank - 1 ) ) ;
}
}
}
# ifndef EIGEN_PARSED_BY_DOXYGEN
2021-08-04 22:41:52 +00:00
template < typename MatrixType_ >
2016-02-06 16:32:00 -08:00
template < typename RhsType , typename DstType >
2021-08-04 22:41:52 +00:00
void CompleteOrthogonalDecomposition < MatrixType_ > : : _solve_impl (
2016-02-06 16:32:00 -08:00
const RhsType & rhs , DstType & dst ) const {
const Index rank = this - > rank ( ) ;
if ( rank = = 0 ) {
dst . setZero ( ) ;
return ;
}
// Compute c = Q^* * rhs
2016-02-08 08:50:34 -08:00
typename RhsType : : PlainObject c ( rhs ) ;
2018-04-15 10:15:28 +02:00
c . applyOnTheLeft ( matrixQ ( ) . setLength ( rank ) . adjoint ( ) ) ;
2016-02-06 16:32:00 -08:00
// Solve T z = c(1:rank, :)
dst . topRows ( rank ) = matrixT ( )
. topLeftCorner ( rank , rank )
. template triangularView < Upper > ( )
. solve ( c . topRows ( rank ) ) ;
const Index cols = this - > cols ( ) ;
if ( rank < cols ) {
// Compute y = Z^* * [ z ]
// [ 0 ]
dst . bottomRows ( cols - rank ) . setZero ( ) ;
applyZAdjointOnTheLeftInPlace ( dst ) ;
}
// Undo permutation to get x = P^{-1} * y.
dst = colsPermutation ( ) * dst ;
}
2019-01-17 01:17:39 +01:00
2021-08-04 22:41:52 +00:00
template < typename MatrixType_ >
2019-01-17 01:17:39 +01:00
template < bool Conjugate , typename RhsType , typename DstType >
2021-08-04 22:41:52 +00:00
void CompleteOrthogonalDecomposition < MatrixType_ > : : _solve_impl_transposed ( const RhsType & rhs , DstType & dst ) const
2019-01-17 01:17:39 +01:00
{
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 > ( ) ) ;
}
2016-02-06 16:32:00 -08:00
# endif
2016-02-09 20:35:20 -08:00
namespace internal {
2019-11-13 21:16:53 +01:00
template < typename MatrixType >
struct traits < Inverse < CompleteOrthogonalDecomposition < MatrixType > > >
: traits < typename Transpose < typename MatrixType : : PlainObject > : : PlainObject >
{
enum { Flags = 0 } ;
} ;
2016-07-20 15:13:44 +02:00
template < typename DstXprType , typename MatrixType >
struct Assignment < DstXprType , Inverse < CompleteOrthogonalDecomposition < MatrixType > > , internal : : assign_op < typename DstXprType : : Scalar , typename CompleteOrthogonalDecomposition < MatrixType > : : Scalar > , Dense2Dense >
2016-02-09 20:35:20 -08:00
{
typedef CompleteOrthogonalDecomposition < MatrixType > CodType ;
typedef Inverse < CodType > SrcXprType ;
2016-07-20 15:13:44 +02:00
static void run ( DstXprType & dst , const SrcXprType & src , const internal : : assign_op < typename DstXprType : : Scalar , typename CodType : : Scalar > & )
2016-02-09 20:35:20 -08:00
{
2019-11-13 21:16:53 +01:00
typedef Matrix < typename CodType : : Scalar , CodType : : RowsAtCompileTime , CodType : : RowsAtCompileTime , 0 , CodType : : MaxRowsAtCompileTime , CodType : : MaxRowsAtCompileTime > IdentityMatrixType ;
dst = src . nestedExpression ( ) . solve ( IdentityMatrixType : : Identity ( src . cols ( ) , src . cols ( ) ) ) ;
2016-02-09 20:35:20 -08:00
}
} ;
} // end namespace internal
2016-02-06 16:32:00 -08:00
/** \returns the matrix Q as a sequence of householder transformations */
template < typename MatrixType >
typename CompleteOrthogonalDecomposition < MatrixType > : : HouseholderSequenceType
CompleteOrthogonalDecomposition < MatrixType > : : householderQ ( ) const {
return m_cpqr . householderQ ( ) ;
}
/** \return the complete orthogonal decomposition of \c *this.
*
* \ sa class CompleteOrthogonalDecomposition
*/
template < typename Derived >
const CompleteOrthogonalDecomposition < typename MatrixBase < Derived > : : PlainObject >
MatrixBase < Derived > : : completeOrthogonalDecomposition ( ) const {
return CompleteOrthogonalDecomposition < PlainObject > ( eval ( ) ) ;
}
} // end namespace Eigen
# endif // EIGEN_COMPLETEORTHOGONALDECOMPOSITION_H