/* $Header: /var/lib/cvs/dynare_cpp/sylv/cc/TriangularSylvester.cpp,v 1.1.1.1 2004/06/04 13:00:59 kamenik Exp $ */ /* Tag $Name: $ */ #include "TriangularSylvester.h" #include "QuasiTriangularZero.h" #include "KronUtils.h" #include "BlockDiagonal.h" #include #include double TriangularSylvester::diag_zero = 1.e-15; double TriangularSylvester::diag_zero_sq = 1.e-30; TriangularSylvester::TriangularSylvester(const QuasiTriangular& k, const QuasiTriangular& f) : SylvesterSolver(k, f), matrixKK(matrixK->clone(2, *matrixK)), matrixFF(new QuasiTriangular(2, *matrixF)) { } TriangularSylvester::TriangularSylvester(const SchurDecompZero& kdecomp, const SchurDecomp& fdecomp) : SylvesterSolver(kdecomp, fdecomp), matrixKK(matrixK->clone(2, *matrixK)), matrixFF(new QuasiTriangular(2, *matrixF)) { } TriangularSylvester::TriangularSylvester(const SchurDecompZero& kdecomp, const SimilarityDecomp& fdecomp) : SylvesterSolver(kdecomp, fdecomp), matrixKK(matrixK->clone(2, *matrixK)), matrixFF(new BlockDiagonal(2, *matrixF)) { } TriangularSylvester::~TriangularSylvester() { delete matrixKK; delete matrixFF; } void TriangularSylvester::print() const { printf("matrix K (%d):\n",matrixK->getDiagonal().getSize()); matrixK->print(); printf("matrix F (%d):\n",matrixF->getDiagonal().getSize()); matrixF->print(); } void TriangularSylvester::solve(SylvParams& pars, KronVector& d) const { double eig_min = 1e30; solvi(1., d, eig_min); pars.eig_min = sqrt(eig_min); } void TriangularSylvester::solvi(double r, KronVector& d, double& eig_min) const { if (d.getDepth() == 0) { QuasiTriangular* t = matrixK->clone(r); t->solvePre(d, eig_min); delete t; } else { for (const_diag_iter di = matrixF->diag_begin(); di != matrixF->diag_end(); ++di) { if ((*di).isReal()) { solviRealAndEliminate(r, di, d, eig_min); } else { solviComplexAndEliminate(r, di, d, eig_min); } } } } void TriangularSylvester::solvii(double alpha, double beta1, double beta2, KronVector& d1, KronVector& d2, double& eig_min) const { KronVector d1tmp(d1); KronVector d2tmp(d2); linEval(alpha, beta1, beta2, d1, d2, d1tmp, d2tmp); solviip(alpha, beta1*beta2, d1, eig_min); solviip(alpha, beta1*beta2, d2, eig_min); } void TriangularSylvester::solviip(double alpha, double betas, KronVector& d, double& eig_min) const { // quick exit to solvi if betas is small if (betas < diag_zero_sq) { solvi(alpha, d, eig_min); solvi(alpha, d, eig_min); return; } if (d.getDepth() == 0) { double aspbs = alpha*alpha+betas; QuasiTriangular* t= matrixK->clone(2*alpha, aspbs, *matrixKK); t->solvePre(d, eig_min); delete t; } else { const_diag_iter di = matrixF->diag_begin(); const_diag_iter dsi = matrixFF->diag_begin(); for (; di != matrixF->diag_end(); ++di, ++dsi) { if ((*di).isReal()) { solviipRealAndEliminate(alpha, betas, di, dsi, d, eig_min); } else { solviipComplexAndEliminate(alpha, betas, di, dsi, d, eig_min); } } } } void TriangularSylvester::solviRealAndEliminate(double r, const_diag_iter di, KronVector& d, double& eig_min) const { // di is real int jbar = (*di).getIndex(); double f = *((*di).getAlpha()); KronVector dj(d, jbar); // solve system if (abs(r*f) > diag_zero) { solvi(r*f, dj, eig_min); } // calculate y KronVector y((const KronVector&)dj); KronUtils::multKron(*matrixF, *matrixK, y); y.mult(r); double divisor = 1.0; solviEliminateReal(di, d, y, divisor); } void TriangularSylvester::solviEliminateReal(const_diag_iter di, KronVector& d, const KronVector& y, double divisor) const { for (const_row_iter ri = matrixF->row_begin(*di); ri != matrixF->row_end(*di); ++ri) { KronVector dk(d, ri.getCol()); dk.add(-(*ri)/divisor, y); } } void TriangularSylvester::solviComplexAndEliminate(double r, const_diag_iter di, KronVector& d, double& eig_min) const { // di is complex int jbar = (*di).getIndex(); // pick data double alpha = *(*di).getAlpha(); double beta1 = (*di).getBeta2(); double beta2 = -(*di).getBeta1(); double aspbs = (*di).getDeterminant(); KronVector dj(d, jbar); KronVector djj(d, jbar+1); // solve if (r*r*aspbs > diag_zero_sq) { solvii(r*alpha, r*beta1, r*beta2, dj, djj, eig_min); } KronVector y1(dj); KronVector y2(djj); KronUtils::multKron(*matrixF, *matrixK, y1); KronUtils::multKron(*matrixF, *matrixK, y2); y1.mult(r); y2.mult(r); double divisor = 1.0; solviEliminateComplex(di, d, y1, y2, divisor); } void TriangularSylvester::solviEliminateComplex(const_diag_iter di, KronVector& d, const KronVector& y1, const KronVector& y2, double divisor) const { for (const_row_iter ri = matrixF->row_begin(*di); ri != matrixF->row_end(*di); ++ri) { KronVector dk(d, ri.getCol()); dk.add(-ri.a()/divisor, y1); dk.add(-ri.b()/divisor, y2); } } void TriangularSylvester::solviipRealAndEliminate(double alpha, double betas, const_diag_iter di, const_diag_iter dsi, KronVector& d, double& eig_min) const { // di, and dsi are real int jbar = (*di).getIndex(); double aspbs = alpha*alpha+betas; // pick data double f = *((*di).getAlpha()); double fs = f*f; KronVector dj(d, jbar); // solve if (fs*aspbs > diag_zero_sq) { solviip(f*alpha, fs*betas, dj, eig_min); } KronVector y1((const KronVector&)dj); KronVector y2((const KronVector&)dj); KronUtils::multKron(*matrixF, *matrixK, y1); y1.mult(2*alpha); KronUtils::multKron(*matrixFF, *matrixKK, y2); y2.mult(aspbs); double divisor = 1.0; double divisor2 = 1.0; solviipEliminateReal(di, dsi, d, y1, y2, divisor, divisor2); } void TriangularSylvester::solviipEliminateReal(const_diag_iter di, const_diag_iter dsi, KronVector& d, const KronVector& y1, const KronVector& y2, double divisor, double divisor2) const { const_row_iter ri = matrixF->row_begin(*di); const_row_iter rsi = matrixFF->row_begin(*dsi); for (; ri != matrixF->row_end(*di); ++ri, ++rsi) { KronVector dk(d, ri.getCol()); dk.add(-(*ri)/divisor, y1); dk.add(-(*rsi)/divisor2, y2); } } void TriangularSylvester::solviipComplexAndEliminate(double alpha, double betas, const_diag_iter di, const_diag_iter dsi, KronVector& d, double& eig_min) const { // di, and dsi are complex int jbar = (*di).getIndex(); double aspbs = alpha*alpha+betas; // pick data double gamma = *((*di).getAlpha()); double delta1 = (*di).getBeta2(); // swap because of transpose double delta2 = -(*di).getBeta1(); double gspds = (*di).getDeterminant(); KronVector dj(d, jbar); KronVector djj(d, jbar+1); if (gspds*aspbs > diag_zero_sq) { solviipComplex(alpha, betas, gamma, delta1, delta2, dj, djj, eig_min); } // here dj, djj is solution, set y1, y2, y11, y22 // y1 KronVector y1((const KronVector&) dj); KronUtils::multKron(*matrixF, *matrixK, y1); y1.mult(2*alpha); // y11 KronVector y11((const KronVector&) djj); KronUtils::multKron(*matrixF, *matrixK, y11); y11.mult(2*alpha); // y2 KronVector y2((const KronVector&) dj); KronUtils::multKron(*matrixFF, *matrixKK, y2); y2.mult(aspbs); // y22 KronVector y22((const KronVector&) djj); KronUtils::multKron(*matrixFF, *matrixKK, y22); y22.mult(aspbs); double divisor = 1.0; solviipEliminateComplex(di, dsi, d, y1, y11, y2, y22, divisor); } void TriangularSylvester::solviipComplex(double alpha, double betas, double gamma, double delta1, double delta2, KronVector& d1, KronVector& d2, double& eig_min) const { KronVector d1tmp(d1); KronVector d2tmp(d2); quaEval(alpha, betas, gamma, delta1, delta2, d1, d2, d1tmp, d2tmp); double delta = sqrt(delta1*delta2); double beta = sqrt(betas); double a1 = alpha*gamma - beta*delta; double b1 = alpha*delta + gamma*beta; double a2 = alpha*gamma + beta*delta; double b2 = alpha*delta - gamma*beta; solviip(a2, b2*b2, d1, eig_min); solviip(a1, b1*b1, d1, eig_min); solviip(a2, b2*b2, d2, eig_min); solviip(a1, b1*b1, d2, eig_min); } void TriangularSylvester::solviipEliminateComplex(const_diag_iter di, const_diag_iter dsi, KronVector& d, const KronVector& y1, const KronVector& y11, const KronVector& y2, const KronVector& y22, double divisor) const { const_row_iter ri = matrixF->row_begin(*di); const_row_iter rsi = matrixFF->row_begin(*dsi); for (; ri != matrixF->row_end(*di); ++ri, ++rsi) { KronVector dk(d, ri.getCol()); dk.add(-ri.a()/divisor, y1); dk.add(-ri.b()/divisor, y11); dk.add(-rsi.a()/divisor, y2); dk.add(-rsi.b()/divisor, y22); } } void TriangularSylvester::linEval(double alpha, double beta1, double beta2, KronVector& x1, KronVector& x2, const ConstKronVector& d1, const ConstKronVector& d2) const { KronVector d1tmp(d1); // make copy KronVector d2tmp(d2); // make copy KronUtils::multKron(*matrixF, *matrixK, d1tmp); KronUtils::multKron(*matrixF, *matrixK, d2tmp); x1 = d1; x2 = d2; Vector::mult2a(alpha, beta1, -beta2, x1, x2, d1tmp, d2tmp); } void TriangularSylvester::quaEval(double alpha, double betas, double gamma, double delta1, double delta2, KronVector& x1, KronVector& x2, const ConstKronVector& d1, const ConstKronVector& d2) const { KronVector d1tmp(d1); // make copy KronVector d2tmp(d2); // make copy KronUtils::multKron(*matrixF, *matrixK, d1tmp); KronUtils::multKron(*matrixF, *matrixK, d2tmp); x1 = d1; x2 = d2; Vector::mult2a(2*alpha*gamma, 2*alpha*delta1, -2*alpha*delta2, x1, x2, d1tmp, d2tmp); d1tmp = d1; // restore to d1 d2tmp = d2; // restore to d2 KronUtils::multKron(*matrixFF, *matrixKK, d1tmp); KronUtils::multKron(*matrixFF, *matrixKK, d2tmp); double aspbs = alpha*alpha + betas; double gspds = gamma*gamma - delta1*delta2; Vector::mult2a(aspbs*gspds, 2*aspbs*gamma*delta1, -2*aspbs*gamma*delta2, x1, x2, d1tmp, d2tmp); } double TriangularSylvester::getEigSep(int depth) const { int f_size = matrixF->getDiagonal().getSize(); Vector feig(2*f_size); matrixF->getDiagonal().getEigenValues(feig); int k_size = matrixK->getDiagonal().getSize(); Vector keig(2*k_size); matrixK->getDiagonal().getEigenValues(keig); KronVector eig(f_size, 2*k_size, depth); multEigVector(eig, feig, keig); double min = 1.0e20; for (int i = 0; i < eig.length()/2; i++) { double alpha = eig[2*i]; double beta = eig[2*i+1]; double ss = (alpha+1)*(alpha+1)+beta*beta; if (min > ss) min = ss; } return min; } void TriangularSylvester::multEigVector(KronVector& eig, const Vector& feig, const Vector& keig) { int depth = eig.getDepth(); int m = eig.getM(); int n = eig.getN(); if (depth == 0) { eig = keig; } else { KronVector aux(m, n, depth-1); multEigVector(aux, feig, keig); for (int i = 0; i < m; i++) { KronVector eigi(eig, i); eigi.zeros(); eigi.add(&feig[2*i], aux); } } } // Local Variables: // mode:C++ // End: