| [eigen] GivensQR |
[ Thread Index | Date Index | More lists.tuxfamily.org/eigen Archives ]
Finally, the Givens QR decomposition class.
Pros:
Cons:
In conclusion: the class is surely not ready to be included in Eigen; but I think it is an acceptable starting point. Cheers. Andrea Arteaga |
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Andrea Arteaga <yo.eres@xxxxxxxxx>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.
#ifndef EIGEN_GIVENS_QR_H
#define EIGEN_GIVENS_QR_H
/** \ingroup QR_Module
* \nonstableyet
*
* \class GivensQR
*
* \brief Givens QR decomposition of a matrix
*
* \param MatrixType the type of the matrix of which we are computing the QR decomposition
*
* This class performs a QR decomposition using Givens rotations.
*
*/
template <typename MatrixType>
class GivensQR
{
private:
enum {
Rows = MatrixType::RowsAtCompileTime,
Cols = MatrixType::ColsAtCompileTime,
isDynamic = (Rows == Dynamic || Cols == Dynamic) ? 1 : 0,
CNum = isDynamic == 1 ? Dynamic : (Rows > Cols) ? (Cols*Rows - (Cols*(Cols+1))/2) : ((Rows-1)*Rows/2)
};
public:
typedef typename NumTraits<typename MatrixType::Scalar>::FloatingPoint Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
typedef Matrix<Scalar, Rows, Rows> MatrixQType;
typedef Matrix<Scalar, Rows, Cols> MatrixRType;
typedef Matrix<Scalar, Rows, Cols> MatrixQReducedType;
typedef Matrix<Scalar, Cols, Cols> MatrixRReducedType;
private:
typedef Matrix<Scalar, 2, CNum> MatrixCType;
public:
/** Constructor: initialize the decomposition, but do not perform any computation.
* Computation is done only if strictly needed.
*
* \param matrix The matrix of which *this is the QR decomposition.
*
*/
GivensQR(const MatrixType& matrix) : m_(matrix) {
m_QisUptodate = false;
m_RisUptodate = false;
m_CisUptodate = false;
if(isDynamic) {
rows = m_.rows();
cols = m_.cols();
cnum = (rows > cols) ? (cols*rows - (cols*(cols+1))/2) : ((rows*(rows-1))/2);
m_Q.resize(rows, rows);
m_R.resize(rows, cols);
m_C.resize(2, cnum);
} else {
rows = Rows;
cols = Cols;
cnum = CNum;
}
}
/** This method computes both Q and R matrix. After a call to compute() no more computation is needed in
* order to return Q or R matrices.
*
*/
inline void compute() const {
compute_QCR();
}
/** This method return the unitary matrix (Q) of the QR decomposition.
*
* \note If you need both Q and R matrix, request the unitary before the upper triangular.
*/
inline const MatrixQType& matrixQ() const {
if (m_QisUptodate)
return m_Q;
compute_QCR();
return m_Q;
}
/** This method return the upper triangular matrix (R) of the QR decomposition.
*/
inline const MatrixRType& matrixR() const {
if (m_RisUptodate)
return m_R;
compute_CR();
return m_R;
};
/** 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.
*
* \param b the right-hand-side of the equation to solve.
*
* \param result a pointer to the vector/matrix in which to store the solution.
* Resized if necessary, so that result->rows()==A.cols() and result->cols()==b.cols().
*
* \note b can be both a vector or a matrix
*
* \sa MatrixBase::solveTriangular(), kernel(), computeKernel(), inverse(), computeInverse()
*/
template<typename OtherDerived, typename ResultType>
bool solve(const MatrixBase<OtherDerived>&, ResultType*) const;
private:
const MatrixType& m_;
int rows, cols, cnum;
mutable MatrixQType m_Q;
mutable MatrixQReducedType m_Qr;
mutable bool m_QisUptodate;
mutable MatrixRType m_R;
mutable MatrixRReducedType m_Rr;
mutable bool m_RisUptodate;
mutable MatrixCType m_C;
mutable bool m_CisUptodate;
private:
void compute_CR() const;
void compute_QCR() const;
};
#ifndef EIGEN_HIDE_HEAVY_CODE
template <typename MatrixType>
void GivensQR<MatrixType>::compute_QCR() const
{
Scalar tmp;
RealScalar r;
const int q_cols = cols < rows ? cols : rows-1;
m_Q.setIdentity();
m_R = m_.template cast<typename MatrixRType::Scalar>();
int j = 0;
for(int k1 = 0; k1 < q_cols; ++k1) {
for (int k2 = rows - 1; k2 > k1; --k2) {
const Scalar& b = m_R.coeffRef(k2, k1);
const Scalar& a = m_R.coeffRef(k1, k1);
Scalar& o1 = m_C.coeffRef(0, j);
Scalar& o2 = m_C.coeffRef(1, j++);
r = ei_sqrt(ei_real(ei_conj(a)*a + ei_conj(b)*b));
o1 = a/r; // FIXME:
o2 = b/r; // what if r == 0 <=> (a==0 && b==0) ?
for (int i = k1; i < cols; ++i){
tmp = m_R.coeff(k1, i);
m_R.coeffRef(k1, i) = ei_conj(o1)*m_R.coeff(k1, i) + ei_conj(o2)*m_R.coeff(k2, i);
m_R.coeffRef(k2, i) = o1*m_R.coeff(k2, i) - o2*tmp;
}
for (int i = 0; i < rows; ++i){
tmp = m_Q.coeff(i, k1);
m_Q.coeffRef(i, k1) = o1*m_Q.coeff(i, k1) + o2*m_Q.coeff(i, k2);
m_Q.coeffRef(i, k2) = ei_conj(o1)*m_Q.coeff(i, k2) - ei_conj(o2)*tmp;
}
}
}
m_Qr = m_Q.block(0, 0, rows, cols);
m_Rr = m_R.block(0, 0, cols, cols);
m_QisUptodate = true;
m_RisUptodate = true;
m_CisUptodate = true;
}
template <typename MatrixType>
void GivensQR<MatrixType>::compute_CR() const
{
Scalar tmp;
RealScalar r;
const int q_cols = cols < rows ? cols : rows-1;
m_R = m_.template cast<typename MatrixRType::Scalar>();
int j = 0;
for(int k1 = 0; k1 < q_cols; ++k1) {
for (int k2 = rows - 1; k2 > k1; --k2) {
const Scalar& b = m_R.coeffRef(k2, k1);
const Scalar& a = m_R.coeffRef(k1, k1);
Scalar& o1 = m_C.coeffRef(0, j);
Scalar& o2 = m_C.coeffRef(1, j++);
r = ei_sqrt(ei_real(ei_conj(a)*a + ei_conj(b)*b));
o1 = a/r; // FIXME:
o2 = b/r; // what if r == 0 <=> (a==0 && b==0) ?
for (int i = k1; i < cols; ++i){
tmp = m_R.coeff(k1, i);
m_R.coeffRef(k1, i) = ei_conj(o1)*m_R.coeff(k1, i) + ei_conj(o2)*m_R.coeff(k2, i);
m_R.coeffRef(k2, i) = o1*m_R.coeff(k2, i) - o2*tmp;
}
}
}
m_Rr = m_R.block(0, 0, cols, cols);
m_RisUptodate = true;
m_CisUptodate = true;
}
template<typename MatrixType>
template<typename OtherDerived, typename ResultType>
bool GivensQR<MatrixType>::solve(const MatrixBase<OtherDerived>& b_, ResultType *result) const
{
OtherDerived b = b_;
Scalar tmp;
int bcols = b.cols();
result->resize(cols, bcols);
if (!m_RisUptodate || !m_CisUptodate){
RealScalar r;
const int q_cols = cols < rows ? cols : rows-1;
m_R = m_.template cast<typename MatrixRType::Scalar>();
int j = 0;
for(int k1 = 0; k1 < q_cols; ++k1) {
for (int k2 = rows - 1; k2 > k1; --k2) {
const Scalar& m2 = m_R.coeffRef(k2, k1);
const Scalar& m1 = m_R.coeffRef(k1, k1);
Scalar& o1 = m_C.coeffRef(0, j);
Scalar& o2 = m_C.coeffRef(1, j++);
r = ei_sqrt(ei_real(ei_conj(m1)*m1 + ei_conj(m2)*m2));
o1 = m1/r; // FIXME:
o2 = m2/r; // what if r == 0 <=> (m1==0 && m2==0) ?
for (int i = k1; i < cols; ++i){
tmp = m_R.coeff(k1, i);
m_R.coeffRef(k1, i) = ei_conj(o1)*m_R.coeff(k1, i) + ei_conj(o2)*m_R.coeff(k2, i);
m_R.coeffRef(k2, i) = o1*m_R.coeff(k2, i) - o2*tmp;
}
for (int i = 0; i < bcols; ++i){
tmp = b.coeff(k1, i);
b.coeffRef(k1, i) = ei_conj(o1)*b.coeff(k1, i) + ei_conj(o2)*b.coeff(k2, i);
b.coeffRef(k2, i) = o1*b.coeff(k2, i) - o2*tmp;
}
}
}
m_Rr = m_R.block(0, 0, cols, cols);
} else {
int k1 = 0, k2 = 1;
for (int j = 0; j < cnum; ++j) {
if (--k2 <= k1){
++k1;
k2 = rows-1;
}
const Scalar& o1 = m_C.coeffRef(0, j);
const Scalar& o2 = m_C.coeffRef(1, j);
for (int i = 0; i < bcols; ++i){
tmp = b.coeff(k1, i);
b.coeffRef(k1, i) = ei_conj(o1)*b.coeff(k1, i) + ei_conj(o2)*b.coeff(k2, i);
b.coeffRef(k2, i) = o1*b.coeff(k2, i) - o2*tmp;
}
}
}
m_Rr.template marked<UpperTriangular>().solveTriangularInPlace(b.block(0, 0, cols, bcols));
*result = b.block(0, 0, cols, bcols);
return true;
}
#endif // EIGEN_HIDE_HEAVY_CODE
#endif // EIGEN_GIVENS_QR_H
| Mail converted by MHonArc 2.6.19+ | http://listengine.tuxfamily.org/ |