00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef EIGEN_TRIDIAGONALIZATION_H
00026 #define EIGEN_TRIDIAGONALIZATION_H
00027
00042 template<typename _MatrixType> class Tridiagonalization
00043 {
00044 public:
00045
00046 typedef _MatrixType MatrixType;
00047 typedef typename MatrixType::Scalar Scalar;
00048 typedef typename NumTraits<Scalar>::Real RealScalar;
00049 typedef typename ei_packet_traits<Scalar>::type Packet;
00050
00051 enum {
00052 Size = MatrixType::RowsAtCompileTime,
00053 SizeMinusOne = MatrixType::RowsAtCompileTime==Dynamic
00054 ? Dynamic
00055 : MatrixType::RowsAtCompileTime-1,
00056 PacketSize = ei_packet_traits<Scalar>::size
00057 };
00058
00059 typedef Matrix<Scalar, SizeMinusOne, 1> CoeffVectorType;
00060 typedef Matrix<RealScalar, Size, 1> DiagonalType;
00061 typedef Matrix<RealScalar, SizeMinusOne, 1> SubDiagonalType;
00062
00063 typedef typename NestByValue<DiagonalCoeffs<MatrixType> >::RealReturnType DiagonalReturnType;
00064
00065 typedef typename NestByValue<DiagonalCoeffs<
00066 NestByValue<Block<MatrixType,SizeMinusOne,SizeMinusOne> > > >::RealReturnType SubDiagonalReturnType;
00067
00071 Tridiagonalization(int size = Size==Dynamic ? 2 : Size)
00072 : m_matrix(size,size), m_hCoeffs(size-1)
00073 {}
00074
00075 Tridiagonalization(const MatrixType& matrix)
00076 : m_matrix(matrix),
00077 m_hCoeffs(matrix.cols()-1)
00078 {
00079 _compute(m_matrix, m_hCoeffs);
00080 }
00081
00086 void compute(const MatrixType& matrix)
00087 {
00088 m_matrix = matrix;
00089 m_hCoeffs.resize(matrix.rows()-1, 1);
00090 _compute(m_matrix, m_hCoeffs);
00091 }
00092
00098 inline CoeffVectorType householderCoefficients(void) const { return m_hCoeffs; }
00099
00116 inline const MatrixType& packedMatrix(void) const { return m_matrix; }
00117
00118 MatrixType matrixQ(void) const;
00119 MatrixType matrixT(void) const;
00120 const DiagonalReturnType diagonal(void) const;
00121 const SubDiagonalReturnType subDiagonal(void) const;
00122
00123 static void decomposeInPlace(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ = true);
00124
00125 private:
00126
00127 static void _compute(MatrixType& matA, CoeffVectorType& hCoeffs);
00128
00129 static void _decomposeInPlace3x3(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ = true);
00130
00131 protected:
00132 MatrixType m_matrix;
00133 CoeffVectorType m_hCoeffs;
00134 };
00135
00137 template<typename MatrixType>
00138 const typename Tridiagonalization<MatrixType>::DiagonalReturnType
00139 Tridiagonalization<MatrixType>::diagonal(void) const
00140 {
00141 return m_matrix.diagonal().nestByValue().real();
00142 }
00143
00145 template<typename MatrixType>
00146 const typename Tridiagonalization<MatrixType>::SubDiagonalReturnType
00147 Tridiagonalization<MatrixType>::subDiagonal(void) const
00148 {
00149 int n = m_matrix.rows();
00150 return Block<MatrixType,SizeMinusOne,SizeMinusOne>(m_matrix, 1, 0, n-1,n-1)
00151 .nestByValue().diagonal().nestByValue().real();
00152 }
00153
00159 template<typename MatrixType>
00160 typename Tridiagonalization<MatrixType>::MatrixType
00161 Tridiagonalization<MatrixType>::matrixT(void) const
00162 {
00163
00164
00165 int n = m_matrix.rows();
00166 MatrixType matT = m_matrix;
00167 matT.corner(TopRight,n-1, n-1).diagonal() = subDiagonal().template cast<Scalar>().conjugate();
00168 if (n>2)
00169 {
00170 matT.corner(TopRight,n-2, n-2).template part<UpperTriangular>().setZero();
00171 matT.corner(BottomLeft,n-2, n-2).template part<LowerTriangular>().setZero();
00172 }
00173 return matT;
00174 }
00175
00176 #ifndef EIGEN_HIDE_HEAVY_CODE
00177
00190 template<typename MatrixType>
00191 void Tridiagonalization<MatrixType>::_compute(MatrixType& matA, CoeffVectorType& hCoeffs)
00192 {
00193 assert(matA.rows()==matA.cols());
00194 int n = matA.rows();
00195
00196 for (int i = 0; i<n-2; ++i)
00197 {
00198
00199
00200
00201
00202 RealScalar v1norm2 = matA.col(i).end(n-(i+2)).squaredNorm();
00203
00204
00205 if (ei_isMuchSmallerThan(v1norm2,static_cast<Scalar>(1)))
00206 {
00207 hCoeffs.coeffRef(i) = 0.;
00208 }
00209 else
00210 {
00211 Scalar v0 = matA.col(i).coeff(i+1);
00212 RealScalar beta = ei_sqrt(ei_abs2(v0)+v1norm2);
00213 if (ei_real(v0)>=0.)
00214 beta = -beta;
00215 matA.col(i).end(n-(i+2)) *= (Scalar(1)/(v0-beta));
00216 matA.col(i).coeffRef(i+1) = beta;
00217 Scalar h = (beta - v0) / beta;
00218
00219
00220
00221
00222
00223 matA.col(i).coeffRef(i+1) = 1;
00224
00225
00226
00227
00228 #ifdef EIGEN_NEVER_DEFINED
00229
00230 hCoeffs.end(n-i-1) = (matA.corner(BottomRight,n-i-1,n-i-1).template part<LowerTriangular|SelfAdjoint>()
00231 * (h * matA.col(i).end(n-i-1))).lazy();
00232
00233 hCoeffs.end(n-i-1) += (h * Scalar(-0.5) * matA.col(i).end(n-i-1).dot(hCoeffs.end(n-i-1)))
00234 * matA.col(i).end(n-i-1);
00235
00236
00237 matA.corner(BottomRight,n-i-1,n-i-1).template part<LowerTriangular>() -=
00238 (matA.col(i).end(n-i-1) * hCoeffs.end(n-i-1).adjoint()).lazy()
00239 + (hCoeffs.end(n-i-1) * matA.col(i).end(n-i-1).adjoint()).lazy();
00240 #endif
00241
00242
00243
00244
00245
00246
00247 #ifdef EIGEN_NEVER_DEFINED
00248 int n4 = (std::max(0,n-4)/4)*4;
00249 hCoeffs.end(n-i-1).setZero();
00250 for (int b=i+1; b<n4; b+=4)
00251 {
00252
00253 hCoeffs.end(b-4) +=
00254 Block<MatrixType,Dynamic,4>(matA,b+4,b,n-b-4,4) * matA.template block<4,1>(b,i);
00255
00256 Block<CoeffVectorType,4,1>(hCoeffs, b, 0, 4,1) +=
00257 Block<MatrixType,Dynamic,4>(matA,b+4,b,n-b-4,4).adjoint() * Block<MatrixType,Dynamic,1>(matA,b+4,i,n-b-4,1);
00258
00259 Block<CoeffVectorType,4,1>(hCoeffs, b, 0, 4,1) +=
00260 (Block<MatrixType,4,4>(matA,b,b,4,4).template part<LowerTriangular|SelfAdjoint>()
00261 * (h * Block<MatrixType,4,1>(matA,b,i,4,1))).lazy();
00262 }
00263 #endif
00264
00265
00266
00267
00268
00269
00270 #ifdef EIGEN_NEVER_DEFINED
00271 for (int j1=i+1; j1<n; ++j1)
00272 for (int i1=j1; i1<n; ++i1)
00273 matA.coeffRef(i1,j1) -= matA.coeff(i1,i)*ei_conj(hCoeffs.coeff(j1-1))
00274 + hCoeffs.coeff(i1-1)*ei_conj(matA.coeff(j1,i));
00275 #endif
00276
00277
00278
00279
00280
00281
00282
00283
00284 hCoeffs.end(n-i-1) = (matA.corner(BottomRight,n-i-1,n-i-1) * (h * matA.col(i).end(n-i-1))).lazy();
00285
00286
00287 hCoeffs.end(n-i-1) += (h * Scalar(-0.5) * matA.col(i).end(n-i-1).dot(hCoeffs.end(n-i-1)))
00288 * matA.col(i).end(n-i-1);
00289
00290 const Scalar* EIGEN_RESTRICT pb = &matA.coeffRef(0,i);
00291 const Scalar* EIGEN_RESTRICT pa = (&hCoeffs.coeffRef(0)) - 1;
00292 for (int j1=i+1; j1<n; ++j1)
00293 {
00294 int starti = i+1;
00295 int alignedEnd = starti;
00296 if (PacketSize>1 && (int(MatrixType::Flags)&RowMajor) == 0)
00297 {
00298 int alignedStart = (starti) + ei_alignmentOffset(&matA.coeffRef(starti,j1), n-starti);
00299 alignedEnd = alignedStart + ((n-alignedStart)/PacketSize)*PacketSize;
00300
00301 for (int i1=starti; i1<alignedStart; ++i1)
00302 matA.coeffRef(i1,j1) -= matA.coeff(i1,i)*ei_conj(hCoeffs.coeff(j1-1))
00303 + hCoeffs.coeff(i1-1)*ei_conj(matA.coeff(j1,i));
00304
00305 Packet tmp0 = ei_pset1(hCoeffs.coeff(j1-1));
00306 Packet tmp1 = ei_pset1(matA.coeff(j1,i));
00307 Scalar* pc = &matA.coeffRef(0,j1);
00308 for (int i1=alignedStart ; i1<alignedEnd; i1+=PacketSize)
00309 ei_pstore(pc+i1,ei_psub(ei_pload(pc+i1),
00310 ei_padd(ei_pmul(tmp0, ei_ploadu(pb+i1)),
00311 ei_pmul(tmp1, ei_ploadu(pa+i1)))));
00312 }
00313 for (int i1=alignedEnd; i1<n; ++i1)
00314 matA.coeffRef(i1,j1) -= matA.coeff(i1,i)*ei_conj(hCoeffs.coeff(j1-1))
00315 + hCoeffs.coeff(i1-1)*ei_conj(matA.coeff(j1,i));
00316 }
00317
00318
00319
00320
00321 matA.col(i).coeffRef(i+1) = beta;
00322
00323 hCoeffs.coeffRef(i) = h;
00324 }
00325 }
00326 if (NumTraits<Scalar>::IsComplex)
00327 {
00328
00329 int i = n-2;
00330 Scalar v0 = matA.col(i).coeff(i+1);
00331 RealScalar beta = ei_abs(v0);
00332 if (ei_real(v0)>=0.)
00333 beta = -beta;
00334 matA.col(i).coeffRef(i+1) = beta;
00335 if(ei_isMuchSmallerThan(beta, Scalar(1))) hCoeffs.coeffRef(i) = Scalar(0);
00336 else hCoeffs.coeffRef(i) = (beta - v0) / beta;
00337 }
00338 else
00339 {
00340 hCoeffs.coeffRef(n-2) = 0;
00341 }
00342 }
00343
00345 template<typename MatrixType>
00346 typename Tridiagonalization<MatrixType>::MatrixType
00347 Tridiagonalization<MatrixType>::matrixQ(void) const
00348 {
00349 int n = m_matrix.rows();
00350 MatrixType matQ = MatrixType::Identity(n,n);
00351 for (int i = n-2; i>=0; i--)
00352 {
00353 Scalar tmp = m_matrix.coeff(i+1,i);
00354 m_matrix.const_cast_derived().coeffRef(i+1,i) = 1;
00355
00356 matQ.corner(BottomRight,n-i-1,n-i-1) -=
00357 ((m_hCoeffs.coeff(i) * m_matrix.col(i).end(n-i-1)) *
00358 (m_matrix.col(i).end(n-i-1).adjoint() * matQ.corner(BottomRight,n-i-1,n-i-1)).lazy()).lazy();
00359
00360 m_matrix.const_cast_derived().coeffRef(i+1,i) = tmp;
00361 }
00362 return matQ;
00363 }
00364
00366 template<typename MatrixType>
00367 void Tridiagonalization<MatrixType>::decomposeInPlace(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ)
00368 {
00369 int n = mat.rows();
00370 ei_assert(mat.cols()==n && diag.size()==n && subdiag.size()==n-1);
00371 if (n==3 && (!NumTraits<Scalar>::IsComplex) )
00372 {
00373 _decomposeInPlace3x3(mat, diag, subdiag, extractQ);
00374 }
00375 else
00376 {
00377 Tridiagonalization tridiag(mat);
00378 diag = tridiag.diagonal();
00379 subdiag = tridiag.subDiagonal();
00380 if (extractQ)
00381 mat = tridiag.matrixQ();
00382 }
00383 }
00384
00389 template<typename MatrixType>
00390 void Tridiagonalization<MatrixType>::_decomposeInPlace3x3(MatrixType& mat, DiagonalType& diag, SubDiagonalType& subdiag, bool extractQ)
00391 {
00392 diag[0] = ei_real(mat(0,0));
00393 RealScalar v1norm2 = ei_abs2(mat(0,2));
00394 if (v1norm2==RealScalar(0))
00395 {
00396 diag[1] = ei_real(mat(1,1));
00397 diag[2] = ei_real(mat(2,2));
00398 subdiag[0] = ei_real(mat(0,1));
00399 subdiag[1] = ei_real(mat(1,2));
00400 if (extractQ)
00401 mat.setIdentity();
00402 }
00403 else
00404 {
00405 RealScalar beta = ei_sqrt(ei_abs2(mat(0,1))+v1norm2);
00406 RealScalar invBeta = RealScalar(1)/beta;
00407 Scalar m01 = mat(0,1) * invBeta;
00408 Scalar m02 = mat(0,2) * invBeta;
00409 Scalar q = RealScalar(2)*m01*mat(1,2) + m02*(mat(2,2) - mat(1,1));
00410 diag[1] = ei_real(mat(1,1) + m02*q);
00411 diag[2] = ei_real(mat(2,2) - m02*q);
00412 subdiag[0] = beta;
00413 subdiag[1] = ei_real(mat(1,2) - m01 * q);
00414 if (extractQ)
00415 {
00416 mat(0,0) = 1;
00417 mat(0,1) = 0;
00418 mat(0,2) = 0;
00419 mat(1,0) = 0;
00420 mat(1,1) = m01;
00421 mat(1,2) = m02;
00422 mat(2,0) = 0;
00423 mat(2,1) = m02;
00424 mat(2,2) = -m01;
00425 }
00426 }
00427 }
00428
00429 #endif // EIGEN_HIDE_HEAVY_CODE
00430
00431 #endif // EIGEN_TRIDIAGONALIZATION_H