// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2009 Gael Guennebaud // Copyright (C) 2010 Benoit Jacob // // 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 . #ifndef EIGEN_HOUSEHOLDER_SEQUENCE_H #define EIGEN_HOUSEHOLDER_SEQUENCE_H /** \ingroup Householder_Module * \householder_module * \class HouseholderSequence * \brief Represents a sequence of householder reflections with decreasing size * * This class represents a product sequence of householder reflections \f$ H = \Pi_0^{n-1} H_i \f$ * where \f$ H_i \f$ is the i-th householder transformation \f$ I - h_i v_i v_i^* \f$, * \f$ v_i \f$ is the i-th householder vector \f$ [ 1, m_vectors(i+1,i), m_vectors(i+2,i), ...] \f$ * and \f$ h_i \f$ is the i-th householder coefficient \c m_coeffs[i]. * * Typical usages are listed below, where H is a HouseholderSequence: * \code * A.applyOnTheRight(H); // A = A * H * A.applyOnTheLeft(H); // A = H * A * A.applyOnTheRight(H.adjoint()); // A = A * H^* * A.applyOnTheLeft(H.adjoint()); // A = H^* * A * MatrixXd Q = H; // conversion to a dense matrix * \endcode * In addition to the adjoint, you can also apply the inverse (=adjoint), the transpose, and the conjugate. * * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() */ namespace internal { template struct traits > { typedef typename VectorsType::Scalar Scalar; typedef typename VectorsType::Index Index; typedef typename VectorsType::StorageKind StorageKind; enum { RowsAtCompileTime = Side==OnTheLeft ? traits::RowsAtCompileTime : traits::ColsAtCompileTime, ColsAtCompileTime = RowsAtCompileTime, MaxRowsAtCompileTime = Side==OnTheLeft ? traits::MaxRowsAtCompileTime : traits::MaxColsAtCompileTime, MaxColsAtCompileTime = MaxRowsAtCompileTime, Flags = 0 }; }; template struct hseq_side_dependent_impl { typedef Block EssentialVectorType; typedef HouseholderSequence HouseholderSequenceType; typedef typename VectorsType::Index Index; static inline const EssentialVectorType essentialVector(const HouseholderSequenceType& h, Index k) { Index start = k+1+h.m_shift; return Block(h.m_vectors, start, k, h.rows()-start, 1); } }; template struct hseq_side_dependent_impl { typedef Transpose > EssentialVectorType; typedef HouseholderSequence HouseholderSequenceType; typedef typename VectorsType::Index Index; static inline const EssentialVectorType essentialVector(const HouseholderSequenceType& h, Index k) { Index start = k+1+h.m_shift; return Block(h.m_vectors, k, start, 1, h.rows()-start).transpose(); } }; template struct matrix_type_times_scalar_type { typedef typename scalar_product_traits::ReturnType ResultScalar; typedef Matrix Type; }; } // end namespace internal template class HouseholderSequence : public EigenBase > { enum { RowsAtCompileTime = internal::traits::RowsAtCompileTime, ColsAtCompileTime = internal::traits::ColsAtCompileTime, MaxRowsAtCompileTime = internal::traits::MaxRowsAtCompileTime, MaxColsAtCompileTime = internal::traits::MaxColsAtCompileTime }; typedef typename internal::traits::Scalar Scalar; typedef typename VectorsType::Index Index; typedef typename internal::hseq_side_dependent_impl::EssentialVectorType EssentialVectorType; public: typedef HouseholderSequence< VectorsType, typename internal::meta_if::IsComplex, typename internal::cleantype::type, CoeffsType>::ret, Side > ConjugateReturnType; HouseholderSequence(const VectorsType& v, const CoeffsType& h, bool trans = false) : m_vectors(v), m_coeffs(h), m_trans(trans), m_actualVectors(v.diagonalSize()), m_shift(0) { } HouseholderSequence(const VectorsType& v, const CoeffsType& h, bool trans, Index actualVectors, Index shift) : m_vectors(v), m_coeffs(h), m_trans(trans), m_actualVectors(actualVectors), m_shift(shift) { } Index rows() const { return Side==OnTheLeft ? m_vectors.rows() : m_vectors.cols(); } Index cols() const { return rows(); } const EssentialVectorType essentialVector(Index k) const { eigen_assert(k >= 0 && k < m_actualVectors); return internal::hseq_side_dependent_impl::essentialVector(*this, k); } HouseholderSequence transpose() const { return HouseholderSequence(m_vectors, m_coeffs, !m_trans, m_actualVectors, m_shift); } ConjugateReturnType conjugate() const { return ConjugateReturnType(m_vectors, m_coeffs.conjugate(), m_trans, m_actualVectors, m_shift); } ConjugateReturnType adjoint() const { return ConjugateReturnType(m_vectors, m_coeffs.conjugate(), !m_trans, m_actualVectors, m_shift); } ConjugateReturnType inverse() const { return adjoint(); } /** \internal */ template void evalTo(DestType& dst) const { Index vecs = m_actualVectors; // FIXME find a way to pass this temporary if the user want to Matrix temp(rows()); if( internal::is_same_type::type,DestType>::ret && internal::extract_data(dst) == internal::extract_data(m_vectors)) { // in-place dst.diagonal().setOnes(); dst.template triangularView().setZero(); for(Index k = vecs-1; k >= 0; --k) { Index cornerSize = rows() - k - m_shift; if(m_trans) dst.bottomRightCorner(cornerSize, cornerSize) .applyHouseholderOnTheRight(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); else dst.bottomRightCorner(cornerSize, cornerSize) .applyHouseholderOnTheLeft(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); // clear the off diagonal vector dst.col(k).tail(rows()-k-1).setZero(); } // clear the remaining columns if needed for(Index k = 0; k= 0; --k) { Index cornerSize = rows() - k - m_shift; if(m_trans) dst.bottomRightCorner(cornerSize, cornerSize) .applyHouseholderOnTheRight(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); else dst.bottomRightCorner(cornerSize, cornerSize) .applyHouseholderOnTheLeft(essentialVector(k), m_coeffs.coeff(k), &temp.coeffRef(0)); } } } /** \internal */ template inline void applyThisOnTheRight(Dest& dst) const { Matrix temp(dst.rows()); for(Index k = 0; k < m_actualVectors; ++k) { Index actual_k = m_trans ? m_actualVectors-k-1 : k; dst.rightCols(rows()-m_shift-actual_k) .applyHouseholderOnTheRight(essentialVector(actual_k), m_coeffs.coeff(actual_k), &temp.coeffRef(0)); } } /** \internal */ template inline void applyThisOnTheLeft(Dest& dst) const { Matrix temp(dst.cols()); for(Index k = 0; k < m_actualVectors; ++k) { Index actual_k = m_trans ? k : m_actualVectors-k-1; dst.bottomRows(rows()-m_shift-actual_k) .applyHouseholderOnTheLeft(essentialVector(actual_k), m_coeffs.coeff(actual_k), &temp.coeffRef(0)); } } template typename internal::matrix_type_times_scalar_type::Type operator*(const MatrixBase& other) const { typename internal::matrix_type_times_scalar_type::Type res(other.template cast::ResultScalar>()); applyThisOnTheLeft(res); return res; } template friend typename internal::matrix_type_times_scalar_type::Type operator*(const MatrixBase& other, const HouseholderSequence& h) { typename internal::matrix_type_times_scalar_type::Type res(other.template cast::ResultScalar>()); h.applyThisOnTheRight(res); return res; } template friend struct internal::hseq_side_dependent_impl; protected: typename VectorsType::Nested m_vectors; typename CoeffsType::Nested m_coeffs; bool m_trans; Index m_actualVectors; Index m_shift; }; template HouseholderSequence householderSequence(const VectorsType& v, const CoeffsType& h, bool trans=false) { return HouseholderSequence(v, h, trans); } template HouseholderSequence householderSequence (const VectorsType& v, const CoeffsType& h, bool trans, typename VectorsType::Index actualVectors, typename VectorsType::Index shift) { return HouseholderSequence(v, h, trans, actualVectors, shift); } template HouseholderSequence rightHouseholderSequence(const VectorsType& v, const CoeffsType& h, bool trans=false) { return HouseholderSequence(v, h, trans); } template HouseholderSequence rightHouseholderSequence (const VectorsType& v, const CoeffsType& h, bool trans, typename VectorsType::Index actualVectors, typename VectorsType::Index shift) { return HouseholderSequence(v, h, trans, actualVectors, shift); } #endif // EIGEN_HOUSEHOLDER_SEQUENCE_H