template<typename MatrixType> void schur(int size = MatrixType::ColsAtCompileTime) { typedef typename ComplexSchur<MatrixType>::ComplexScalar ComplexScalar; typedef typename ComplexSchur<MatrixType>::ComplexMatrixType ComplexMatrixType; // Test basic functionality: T is triangular and A = U T U* for(int counter = 0; counter < g_repeat; ++counter) { MatrixType A = MatrixType::Random(size, size); ComplexSchur<MatrixType> schurOfA(A); VERIFY_IS_EQUAL(schurOfA.info(), Success); ComplexMatrixType U = schurOfA.matrixU(); ComplexMatrixType T = schurOfA.matrixT(); for(int row = 1; row < size; ++row) { for(int col = 0; col < row; ++col) { VERIFY(T(row,col) == (typename MatrixType::Scalar)0); } } VERIFY_IS_APPROX(A.template cast<ComplexScalar>(), U * T * U.adjoint()); } // Test asserts when not initialized ComplexSchur<MatrixType> csUninitialized; VERIFY_RAISES_ASSERT(csUninitialized.matrixT()); VERIFY_RAISES_ASSERT(csUninitialized.matrixU()); VERIFY_RAISES_ASSERT(csUninitialized.info()); // Test whether compute() and constructor returns same result MatrixType A = MatrixType::Random(size, size); ComplexSchur<MatrixType> cs1; cs1.compute(A); ComplexSchur<MatrixType> cs2(A); VERIFY_IS_EQUAL(cs1.info(), Success); VERIFY_IS_EQUAL(cs2.info(), Success); VERIFY_IS_EQUAL(cs1.matrixT(), cs2.matrixT()); VERIFY_IS_EQUAL(cs1.matrixU(), cs2.matrixU()); // Test computation of only T, not U ComplexSchur<MatrixType> csOnlyT(A, false); VERIFY_IS_EQUAL(csOnlyT.info(), Success); VERIFY_IS_EQUAL(cs1.matrixT(), csOnlyT.matrixT()); VERIFY_RAISES_ASSERT(csOnlyT.matrixU()); if (size > 1) { // Test matrix with NaN A(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN(); ComplexSchur<MatrixType> csNaN(A); VERIFY_IS_EQUAL(csNaN.info(), NoConvergence); } }
void krylov(const ComplexSparseMatrixType &A, ComplexVectorType &Vec, const ComplexType Prefactor, const size_t Kmax) { // INFO(A); const RealType beta_err = 1.0E-12; if (DEBUG) assert( Kmax > 2 ); RealType alpha; RealType beta = 1.0; ComplexMatrixType Vm = ComplexMatrixType::Zero(Vec.size(), Kmax); std::vector<RealType> Alphas; std::vector<RealType> Betas; int cntK = 0; //NOTE: normalized Vec Vec.normalize(); Vm.col(cntK) = Vec; while ( cntK < Kmax ) { ComplexVectorType work = A * Vm.col(cntK); if( cntK > 0 ) work -= beta * Vm.col(cntK-1); ComplexType alpha_c = work.dot( Vm.col(cntK) ); alpha = alpha_c.real(); work -= alpha * Vm.col(cntK); beta = work.norm(); Alphas.push_back(alpha); if( DEBUG > 4 ){ INFO("@ " << cntK << " alpha is " << alpha << " beta is " << beta); } if( beta > beta_err ){ work.normalize(); if( cntK+1 < Kmax ) { Vm.col(cntK+1) = work; Betas.push_back(beta); } cntK++; } else{ cntK++; break; } } if ( DEBUG ) { assert( Alphas.size() == cntK ); assert( Betas.size() == cntK - 1 ); if ( DEBUG > 5 ) { ComplexMatrixType tmpVm = Vm; tmpVm.adjointInPlace(); INFO( "Vm^H * Vm " << std::endl << tmpVm * Vm); } } int Kused = cntK; if ( Kused == 1 ){ /* NOTE: This is a special case that input vector is eigenvector */ Vec = exp(Prefactor * Alphas.at(0)) * Vec; } else{ /* NOTE: The floowing codes use Eigen to solve the tri-diagonal matrix. If we use this, we need the Eigen header in this file. */ // RealMatrixType TriDiag = RealMatrixType::Zero(Kused, Kused); // for (size_t cnt = 0; cnt < Kused; cnt++) { // TriDiag(cnt, cnt) = Alphas.at(cnt); // if (cnt > 0) { // TriDiag(cnt, cnt-1) = Betas.at(cnt - 1); // TriDiag(cnt-1, cnt) = Betas.at(cnt - 1); // } // } // Eigen::SelfAdjointEigenSolver<RealMatrixType> es; // es.compute(TriDiag); // RealVectorType Dvec = es.eigenvalues(); // ComplexMatrixType Dmat = ComplexMatrixType::Zero(Kused, Kused); // for (size_t cnt = 0; cnt < Kused; cnt++) { // Dmat(cnt,cnt) = exp( Prefactor * Dvec(cnt) ); // } // RealMatrixType Kmat = es.eigenvectors(); /* NOTE: The floowing codes use MKL Lapack to solve the tri-diagonal matrix */ RealType* d = &Alphas[0]; RealType* e = &Betas[0]; RealType* z = (RealType*)malloc(Kused * Kused * sizeof(RealType)); RealType* work = (RealType*)malloc(4 * Kused * sizeof(RealType)); int info; //dstev - LAPACK dstev((char*)"V", &Kused, d, e, z, &Kused, work, &info); Eigen::Map<RealMatrixType> Kmat(z, Kused, Kused); Kmat.transposeInPlace(); ComplexMatrixType Dmat = ComplexMatrixType::Zero(Kused, Kused); for (size_t cnt = 0; cnt < Kused; cnt++) { Dmat(cnt,cnt) = exp( Prefactor * d[cnt] ); } if(info != 0){ INFO("Lapack INFO = " << info); RUNTIME_ERROR("Error in Lapack function 'dstev'"); } /* NOTE: After Solving tri-diagonal matrix, we need Kmat and Dmat to proceed further. */ if ( DEBUG > 4 ) { RealMatrixType tmpKmat = Kmat; tmpKmat.transposeInPlace(); INFO( Kmat * Dmat * tmpKmat ); } ComplexMatrixType Otmp = Vm.block(0, 0, Vec.size(), Kused) * Kmat; Vec = ( Otmp * Dmat ) * ( Otmp.adjoint() * Vec ); } }
template<typename MatrixType> void schur(int size = MatrixType::ColsAtCompileTime) { typedef typename ComplexSchur<MatrixType>::ComplexScalar ComplexScalar; typedef typename ComplexSchur<MatrixType>::ComplexMatrixType ComplexMatrixType; // Test basic functionality: T is triangular and A = U T U* for(int counter = 0; counter < g_repeat; ++counter) { MatrixType A = MatrixType::Random(size, size); ComplexSchur<MatrixType> schurOfA(A); VERIFY_IS_EQUAL(schurOfA.info(), Success); ComplexMatrixType U = schurOfA.matrixU(); ComplexMatrixType T = schurOfA.matrixT(); for(int row = 1; row < size; ++row) { for(int col = 0; col < row; ++col) { VERIFY(T(row,col) == (typename MatrixType::Scalar)0); } } VERIFY_IS_APPROX(A.template cast<ComplexScalar>(), U * T * U.adjoint()); } // Test asserts when not initialized ComplexSchur<MatrixType> csUninitialized; VERIFY_RAISES_ASSERT(csUninitialized.matrixT()); VERIFY_RAISES_ASSERT(csUninitialized.matrixU()); VERIFY_RAISES_ASSERT(csUninitialized.info()); // Test whether compute() and constructor returns same result MatrixType A = MatrixType::Random(size, size); ComplexSchur<MatrixType> cs1; cs1.compute(A); ComplexSchur<MatrixType> cs2(A); VERIFY_IS_EQUAL(cs1.info(), Success); VERIFY_IS_EQUAL(cs2.info(), Success); VERIFY_IS_EQUAL(cs1.matrixT(), cs2.matrixT()); VERIFY_IS_EQUAL(cs1.matrixU(), cs2.matrixU()); // Test maximum number of iterations ComplexSchur<MatrixType> cs3; cs3.setMaxIterations(ComplexSchur<MatrixType>::m_maxIterationsPerRow * size).compute(A); VERIFY_IS_EQUAL(cs3.info(), Success); VERIFY_IS_EQUAL(cs3.matrixT(), cs1.matrixT()); VERIFY_IS_EQUAL(cs3.matrixU(), cs1.matrixU()); cs3.setMaxIterations(1).compute(A); VERIFY_IS_EQUAL(cs3.info(), size > 1 ? NoConvergence : Success); VERIFY_IS_EQUAL(cs3.getMaxIterations(), 1); MatrixType Atriangular = A; Atriangular.template triangularView<StrictlyLower>().setZero(); cs3.setMaxIterations(1).compute(Atriangular); // triangular matrices do not need any iterations VERIFY_IS_EQUAL(cs3.info(), Success); VERIFY_IS_EQUAL(cs3.matrixT(), Atriangular.template cast<ComplexScalar>()); VERIFY_IS_EQUAL(cs3.matrixU(), ComplexMatrixType::Identity(size, size)); // Test computation of only T, not U ComplexSchur<MatrixType> csOnlyT(A, false); VERIFY_IS_EQUAL(csOnlyT.info(), Success); VERIFY_IS_EQUAL(cs1.matrixT(), csOnlyT.matrixT()); VERIFY_RAISES_ASSERT(csOnlyT.matrixU()); if (size > 1 && size < 20) { // Test matrix with NaN A(0,0) = std::numeric_limits<typename MatrixType::RealScalar>::quiet_NaN(); ComplexSchur<MatrixType> csNaN(A); VERIFY_IS_EQUAL(csNaN.info(), NoConvergence); } }