dynare/dynare++/sylv/cc/TriangularSylvester.cpp

393 lines
11 KiB
C++

/* $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 <cstdio>
#include <cmath>
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: