| Re: [eigen] Specialized QR |
[ Thread Index | Date Index | More lists.tuxfamily.org/eigen Archives ]
| I did a mistake with my benchmark. My class isn't 4 times faster as the QR class! In facts, the performance of the two classes was almost the same. I used only dynamically-sized matriced, but in theory thereis no difference between dynamic and fixed (the function is exactly the same). I made four graphics, which explain where QR_Givens is faster than QR. I noticed that for almost square matrices Givens is faster, but for MxN matrices, where M>2*N, Householder is far better. For complex ones, Givens is only faster with sizes up to 10x10; then it becomes far slower. In facts this topic isn't very well-named. I wrote a new class, I didn't any specialization. The benchmark shows that Givens is actually faster for small-sized (and real) matrices, but in the general case Householder is better. I think that we should try with Gram-Schmidt for small-sized matrices with many rows. I think that this behaviour is more general. Do you agree? Andrea Arteaga |
Attachment:
PerformanceComplex.png
Description: PNG image
Attachment:
PerformanceReal.png
Description: PNG image
Attachment:
TimeComplex.png
Description: PNG image
Attachment:
TimeReal.png
Description: PNG image
// 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 QR_GIVENS_H
#define QR_GIVENS_H
/**
* QR_Givens
*
* QR decomposition of a matrix
*
* MatrixType is the type of the matrix of which we are computing the QR decomposition
*
* This class performs a QR decomposition using Givens rotations.
*/
template<class MatrixType>
class QR_Givens
{
public:
typedef typename MatrixType::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
enum {
Rows = MatrixType::RowsAtCompileTime,
Cols = MatrixType::ColsAtCompileTime,
isDynamic = (MatrixType::RowsAtCompileTime == Dynamic) ? 1 : 0,
isComplex = NumTraits<Scalar>::IsComplex,
q_Cols = Cols < Rows ? Cols : Rows-1,
m_Cols = Cols < Rows ? (Cols*Rows - Cols*(Cols+1)/2) : (Rows*(Rows-1)/2)
};
typedef Matrix<Scalar, Rows, Rows> MatrixQType;
typedef Matrix<Scalar, Rows, Cols> MatrixRType;
QR_Givens(const MatrixType& matrix) {
m_R = matrix;
compute_();
}
/** Returns the upper triangular matrix.
*
* Dimensions are the same as the matrix of which *this is the QR decomposition.
*/
MatrixRType matrixR() const;
/** Returns the orthogonal matrix.
*
* This is a quadratic matrix with the same number of rows as the matrix of which *this
* is the QR decomposition.
*/
MatrixQType matrixQ() const;
/** Returns the rank of the matrix of which *this is the QR decomposition.
*
* This method is not stable yet.
*/
int rank() const;
private:
inline void compute_();
Matrix<Scalar, Rows, Cols> m_R;
MatrixQType m_Q;
};
template<class MatrixType>
inline void QR_Givens<MatrixType>::compute_()
{
Scalar a, b, o1, o2, tmp;
RealScalar r;
const int rows = m_R.rows(), cols = m_R.cols();
const int q_cols = cols < rows ? cols : rows-1;
m_Q.resize(rows, rows);
m_Q.setIdentity();
for(int k1 = 0; k1 < q_cols; ++k1) {
for (int k2 = rows - 1; k2 > k1; --k2) {
b = m_R.coeff(k2, k1);
a = m_R.coeff(k1, k1);
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;
}
}
}
}
template<class MatrixType>
typename QR_Givens<MatrixType>::MatrixRType
QR_Givens<MatrixType>::matrixR() const
{
return Part<MatrixRType, UpperTriangular>(m_R);
}
template<class MatrixType>
typename QR_Givens<MatrixType>::MatrixQType
QR_Givens<MatrixType>::matrixQ() const
{
return m_Q;
}
#endif // QR_GIVENS_H
| Mail converted by MHonArc 2.6.19+ | http://listengine.tuxfamily.org/ |