/* $Header: /var/lib/cvs/dynare_cpp/sylv/cc/QuasiTriangular.cpp,v 1.1.1.1 2004/06/04 13:00:31 kamenik Exp $ */ /* Tag $Name: $ */ #include "QuasiTriangular.h" #include "SylvException.h" #include "SchurDecomp.h" #include #include #include using namespace std; double DiagonalBlock::getDeterminant() const { return (*alpha)*(*alpha) + getSBeta(); } double DiagonalBlock::getSBeta() const { return -(*beta1)*(*beta2); } double DiagonalBlock::getSize() const { if (real) return abs(*alpha); else return sqrt(getDeterminant()); } // this function makes Diagonal inconsistent, it should only be used // on temorary matrices, which will not be used any more, e.g. in // QuasiTriangular::solve (we need fast performance) void DiagonalBlock::setReal() { *beta1 = 0; *beta2 = 0; real = true; } void DiagonalBlock::checkBlock(const double* d, int d_size) { const double* a1 = d + jbar*d_size+jbar; const double* b1 = a1 + d_size; const double* b2 = a1 + 1; const double* a2 = b1 + 1; if (a1 != alpha.a1) throw SYLV_MES_EXCEPTION("Bad alpha1."); if (!real && b1 != beta1) throw SYLV_MES_EXCEPTION("Bad beta1."); if (!real && b2 != beta2) throw SYLV_MES_EXCEPTION("Bad beta2."); if (!real && a2 != alpha.a2) throw SYLV_MES_EXCEPTION("Bad alpha2."); } Diagonal::Diagonal(double* data, int d_size) { int nc = getNumComplex(data, d_size); // return nc <= d_size/2 num_all = d_size - nc; num_real = d_size - 2*nc; int jbar = 0; int j = 0; while (j < num_all) { int id = jbar*d_size + jbar; // index of diagonal block in data int ill = id + 1; // index of element below the diagonal int iur = id + d_size; // index of element right to diagonal int idd = id + d_size + 1; // index of element next on diagonal if ((jbar < d_size-1) && !isZero(data[ill])) { // it is not last column and we have nonzero below diagonal DiagonalBlock b(jbar, false, &data[id], &data[idd], &data[iur], &data[ill]); blocks.push_back(b); jbar++; } else { // it is last column or we have zero below diagonal DiagonalBlock b(jbar, true, &data[id], &data[id], NULL, NULL); blocks.push_back(b); } jbar++; j++; } } Diagonal::Diagonal(double* data, const Diagonal& d) { num_all = d.num_all; num_real = d.num_real; int d_size = d.getSize(); for (const_diag_iter it = d.begin(); it != d.end(); ++it) { const DiagonalBlock& dit = *it; double* beta1 = NULL; double* beta2 = NULL; int id = dit.getIndex()*(d_size+1); int idd = id; if (! dit.isReal()) { beta1 = &data[id+d_size]; beta2 = &data[id+1]; idd = id + d_size + 1; } DiagonalBlock b(dit.getIndex(), dit.isReal(), &data[id], &data[idd], beta1, beta2); blocks.push_back(b); } } void Diagonal::copy(const Diagonal& d) { num_all = d.num_all; num_real = d.num_real; blocks = d.blocks; } int Diagonal::getNumComplex(const double* data, int d_size) { int num_complex = 0; int in = 1; for (int i = 0; i < d_size-1; i++, in = in + d_size + 1) { if (! isZero(data[in])) { num_complex++; if (in < d_size - 2 && ! isZero(data[in + d_size +1])) { throw SYLV_MES_EXCEPTION("Matrix is not quasi-triangular"); } } } return num_complex; } void Diagonal::changeBase(double* p) { int d_size = getSize(); for (diag_iter it = begin(); it != end(); ++it) { const DiagonalBlock& b = *it; int jbar = b.getIndex(); int base = d_size*jbar + jbar; if (b.isReal()) { DiagonalBlock bnew(jbar, true, &p[base], &p[base], NULL, NULL); *it = bnew; } else { DiagonalBlock bnew(jbar, false, &p[base], &p[base+d_size+1], &p[base+d_size], &p[base+1]); *it = bnew; } } } void Diagonal::getEigenValues(Vector& eig) const { int d_size = getSize(); if (eig.length() != 2*d_size) { char mes[500]; sprintf(mes, "Wrong length of vector for eigenvalues len=%d, should be=%d.\n", eig.length(), 2*d_size); throw SYLV_MES_EXCEPTION(mes); } for (const_diag_iter it = begin(); it != end(); ++it) { const DiagonalBlock& b = *it; int ind = b.getIndex(); eig[2*ind] = *(b.getAlpha()); if (b.isReal()) { eig[2*ind+1] = 0.0; } else { double beta = sqrt(b.getSBeta()); eig[2*ind+1] = beta; eig[2*ind+2] = eig[2*ind]; eig[2*ind+3] = -beta; } } } /* swaps logically blocks 'it', and '++it'. remember to move also * addresses, alpha, beta1, beta2. This is a dirty (but most * effective) way how to do it. */ void Diagonal::swapLogically(diag_iter it) { diag_iter itp = it; ++itp; if ((*it).isReal() && !(*itp).isReal()) { // first is real, second is complex double* d1 = (*it).alpha.a1; double* d2 = (*itp).alpha.a1; double* d3 = (*itp).alpha.a2; // swap DiagonalBlock new_it((*it).jbar, d1, d2); *it = new_it; DiagonalBlock new_itp((*itp).jbar+1, d3); *itp = new_itp; } else if (!(*it).isReal() && (*itp).isReal()) { // first is complex, second is real double* d1 = (*it).alpha.a1; double* d2 = (*it).alpha.a2; double* d3 = (*itp).alpha.a1; // swap DiagonalBlock new_it((*it).jbar, d1); *it = new_it; DiagonalBlock new_itp((*itp).jbar-1, d2, d3); *itp = new_itp; } } void Diagonal::checkConsistency(diag_iter it) { if (!(*it).isReal() && isZero((*it).getBeta2())) { (*it).getBeta2() = 0.0; // put exact zero int jbar = (*it).getIndex(); double* d2 = (*it).alpha.a2; (*it).alpha.a2 = (*it).alpha.a1; (*it).real = true; (*it).beta1 = 0; (*it).beta2 = 0; DiagonalBlock b(jbar+1, d2); blocks.insert((++it).iter(), b); num_real += 2; num_all++; } } double Diagonal::getAverageSize(diag_iter start, diag_iter end) { double res = 0; int num = 0; for (diag_iter run = start; run != end; ++run) { num++; res += (*run).getSize(); } if (num > 0) res = res/num; return res; } Diagonal::diag_iter Diagonal::findClosestBlock(diag_iter start, diag_iter end, double a) { diag_iter closest = start; double minim = 1.0e100; for (diag_iter run = start; run != end; ++run) { double dist = abs(a - (*run).getSize()); if (dist < minim) { minim = dist; closest = run; } } return closest; } Diagonal::diag_iter Diagonal::findNextLargerBlock(diag_iter start, diag_iter end, double a) { diag_iter closest = start; double minim = 1.0e100; for (diag_iter run = start; run != end; ++run) { double dist = (*run).getSize() - a; if ((0 <= dist) && (dist < minim)) { minim = dist; closest = run; } } return closest; } void Diagonal::print() const { printf("Num real: %d, num complex: %d\n",getNumReal(), getNumComplex()); for (const_diag_iter it = begin(); it != end(); ++it) { if ((*it).isReal()) { printf("real: jbar=%d, alpha=%f\n", (*it).getIndex(), *((*it).getAlpha())); } else { printf("complex: jbar=%d, alpha=%f, beta1=%f, beta2=%f\n", (*it).getIndex(), *((*it).getAlpha()), (*it).getBeta1(), (*it).getBeta2()); } } } double Diagonal::EPS = 1.0e-300; bool Diagonal::isZero(double p) { return (abs(p)