2019-01-08 17:12:05 +01:00
|
|
|
/* $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.hh"
|
|
|
|
#include "SylvException.hh"
|
|
|
|
#include "SchurDecomp.hh"
|
|
|
|
|
|
|
|
#include <dynblas.h>
|
|
|
|
|
|
|
|
#include <cmath>
|
2019-01-16 17:52:16 +01:00
|
|
|
#include <iostream>
|
|
|
|
#include <sstream>
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
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
|
2019-01-09 16:25:31 +01:00
|
|
|
DiagonalBlock b(jbar, true, &data[id], &data[id], nullptr, nullptr);
|
2019-01-08 17:12:05 +01:00
|
|
|
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();
|
2019-01-09 15:44:26 +01:00
|
|
|
for (const auto & dit : d)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-01-09 16:25:31 +01:00
|
|
|
double *beta1 = nullptr;
|
|
|
|
double *beta2 = nullptr;
|
2019-01-08 17:12:05 +01:00
|
|
|
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]))
|
2019-01-16 17:52:16 +01:00
|
|
|
throw SYLV_MES_EXCEPTION("Matrix is not quasi-triangular");
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return num_complex;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Diagonal::changeBase(double *p)
|
|
|
|
{
|
|
|
|
int d_size = getSize();
|
2019-01-09 15:44:26 +01:00
|
|
|
for (auto & it : *this)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-01-09 15:44:26 +01:00
|
|
|
const DiagonalBlock &b = it;
|
2019-01-08 17:12:05 +01:00
|
|
|
int jbar = b.getIndex();
|
|
|
|
int base = d_size*jbar + jbar;
|
|
|
|
if (b.isReal())
|
|
|
|
{
|
|
|
|
DiagonalBlock bnew(jbar, true, &p[base], &p[base],
|
2019-01-09 16:25:31 +01:00
|
|
|
nullptr, nullptr);
|
2019-01-09 15:44:26 +01:00
|
|
|
it = bnew;
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DiagonalBlock bnew(jbar, false, &p[base], &p[base+d_size+1],
|
|
|
|
&p[base+d_size], &p[base+1]);
|
2019-01-09 15:44:26 +01:00
|
|
|
it = bnew;
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Diagonal::getEigenValues(Vector &eig) const
|
|
|
|
{
|
|
|
|
int d_size = getSize();
|
|
|
|
if (eig.length() != 2*d_size)
|
|
|
|
{
|
2019-01-16 17:52:16 +01:00
|
|
|
ostringstream mes;
|
|
|
|
mes << "Wrong length of vector for eigenvalues len=" << eig.length()
|
|
|
|
<< ", should be=" << 2*d_size << '.' << std::endl;
|
|
|
|
throw SYLV_MES_EXCEPTION(mes.str());
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
2019-01-09 15:44:26 +01:00
|
|
|
for (const auto & b : *this)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
int ind = b.getIndex();
|
|
|
|
eig[2*ind] = *(b.getAlpha());
|
|
|
|
if (b.isReal())
|
2019-01-16 17:52:16 +01:00
|
|
|
eig[2*ind+1] = 0.0;
|
2019-01-08 17:12:05 +01:00
|
|
|
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;
|
2019-01-09 16:25:31 +01:00
|
|
|
(*it).beta1 = nullptr;
|
|
|
|
(*it).beta2 = nullptr;
|
2019-01-08 17:12:05 +01:00
|
|
|
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
|
|
|
|
{
|
2019-01-16 17:52:16 +01:00
|
|
|
auto ff = std::cout.flags();
|
|
|
|
std::cout << "Num real: " << getNumReal() << ", num complex: " << getNumComplex() << std::endl
|
|
|
|
<< std::fixed;
|
2019-01-09 15:44:26 +01:00
|
|
|
for (const auto & it : *this)
|
2019-01-16 17:52:16 +01:00
|
|
|
if (it.isReal())
|
|
|
|
std::cout << "real: jbar=" << it.getIndex() << ", alpha=" << *(it.getAlpha()) << std::endl;
|
|
|
|
else
|
|
|
|
std::cout << "complex: jbar=" << it.getIndex()
|
|
|
|
<< ", alpha=" << *(it.getAlpha())
|
|
|
|
<< ", beta1=" << it.getBeta1()
|
|
|
|
<< ", beta2=" << it.getBeta2() << std::endl;
|
|
|
|
std::cout.flags(ff);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
Diagonal::isZero(double p)
|
|
|
|
{
|
|
|
|
return (abs(p) < EPS);
|
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::const_col_iter
|
|
|
|
QuasiTriangular::col_begin(const DiagonalBlock &b) const
|
|
|
|
{
|
|
|
|
int jbar = b.getIndex();
|
|
|
|
int d_size = diagonal.getSize();
|
|
|
|
return const_col_iter(&getData()[jbar*d_size], d_size, b.isReal(), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::col_iter
|
|
|
|
QuasiTriangular::col_begin(const DiagonalBlock &b)
|
|
|
|
{
|
|
|
|
int jbar = b.getIndex();
|
|
|
|
int d_size = diagonal.getSize();
|
|
|
|
return col_iter(&getData()[jbar*d_size], d_size, b.isReal(), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::const_row_iter
|
|
|
|
QuasiTriangular::row_begin(const DiagonalBlock &b) const
|
|
|
|
{
|
|
|
|
int jbar = b.getIndex();
|
|
|
|
int d_size = diagonal.getSize();
|
|
|
|
int off = jbar*d_size+jbar+d_size;
|
|
|
|
int col = jbar+1;
|
|
|
|
if (!b.isReal())
|
|
|
|
{
|
|
|
|
off = off + d_size;
|
|
|
|
col++;
|
|
|
|
}
|
|
|
|
return const_row_iter(&getData()[off], d_size, b.isReal(), col);
|
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::row_iter
|
|
|
|
QuasiTriangular::row_begin(const DiagonalBlock &b)
|
|
|
|
{
|
|
|
|
int jbar = b.getIndex();
|
|
|
|
int d_size = diagonal.getSize();
|
|
|
|
int off = jbar*d_size+jbar+d_size;
|
|
|
|
int col = jbar+1;
|
|
|
|
if (!b.isReal())
|
|
|
|
{
|
|
|
|
off = off + d_size;
|
|
|
|
col++;
|
|
|
|
}
|
|
|
|
return row_iter(&getData()[off], d_size, b.isReal(), col);
|
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::const_col_iter
|
|
|
|
QuasiTriangular::col_end(const DiagonalBlock &b) const
|
|
|
|
{
|
|
|
|
int jbar = b.getIndex();
|
|
|
|
int d_size = diagonal.getSize();
|
|
|
|
return const_col_iter(getData().base()+jbar*d_size+jbar, d_size, b.isReal(),
|
|
|
|
jbar);
|
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::col_iter
|
|
|
|
QuasiTriangular::col_end(const DiagonalBlock &b)
|
|
|
|
{
|
|
|
|
int jbar = b.getIndex();
|
|
|
|
int d_size = diagonal.getSize();
|
|
|
|
return col_iter(&getData()[jbar*d_size+jbar], d_size, b.isReal(), jbar);
|
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::const_row_iter
|
|
|
|
QuasiTriangular::row_end(const DiagonalBlock &b) const
|
|
|
|
{
|
|
|
|
int jbar = b.getIndex();
|
|
|
|
int d_size = diagonal.getSize();
|
|
|
|
return const_row_iter(&getData()[d_size*d_size+jbar], d_size, b.isReal(),
|
|
|
|
d_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::row_iter
|
|
|
|
QuasiTriangular::row_end(const DiagonalBlock &b)
|
|
|
|
{
|
|
|
|
int jbar = b.getIndex();
|
|
|
|
int d_size = diagonal.getSize();
|
|
|
|
return row_iter(&getData()[d_size*d_size+jbar], d_size, b.isReal(), d_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::QuasiTriangular(double r, const QuasiTriangular &t)
|
|
|
|
: SqSylvMatrix(t.numRows()), diagonal(getData().base(), t.diagonal)
|
|
|
|
{
|
|
|
|
setMatrix(r, t);
|
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::QuasiTriangular(double r, const QuasiTriangular &t,
|
|
|
|
double rr, const QuasiTriangular &tt)
|
|
|
|
: SqSylvMatrix(t.numRows()), diagonal(getData().base(), t.diagonal)
|
|
|
|
{
|
|
|
|
setMatrix(r, t);
|
|
|
|
addMatrix(rr, tt);
|
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::QuasiTriangular(const QuasiTriangular &t)
|
|
|
|
: SqSylvMatrix(t), diagonal(getData().base(), t.diagonal)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
Dynare++ / sylvester equation solver: refactor Vector and ConstVector classes
- these classes now encapsulate a std::shared_ptr<{const, }double>, so that
they do not perform memory management, and several {Const,}Vector instances
can transparently share the same underlying data
- make converting constructor from ConstVector to Vector explicit, since that
entails memory allocation (but the reverse conversion is almost costless, so
keep it implicit); do the same for GeneralMatrix/ConstGeneralMatrix,
TwoDMatrix/ConstTwoDMatrix
- remove the constructors that were extracting a row/column from a matrix, and
replace them by getRow() and getCol() methods on {Const,}GeneralMatrix
- rename and change the API of the complex version Vector::add(), so that it is
explicit that it deals with complex numbers
- add constructors that take a MATLAB mxArray
2019-01-22 16:07:44 +01:00
|
|
|
QuasiTriangular::QuasiTriangular(const ConstVector &d, int d_size)
|
2019-01-24 15:22:36 +01:00
|
|
|
: SqSylvMatrix(Vector{d}, d_size), diagonal(getData().base(), d_size)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::QuasiTriangular(int p, const QuasiTriangular &t)
|
|
|
|
: SqSylvMatrix(t.numRows()), diagonal(getData().base(), t.diagonal)
|
|
|
|
{
|
|
|
|
Vector aux(t.getData());
|
|
|
|
blas_int d_size = diagonal.getSize();
|
|
|
|
double alpha = 1.0;
|
|
|
|
double beta = 0.0;
|
2019-01-24 13:08:05 +01:00
|
|
|
blas_int lda = t.getLD(), ldb = t.getLD(), ldc = ld;
|
2019-01-08 17:12:05 +01:00
|
|
|
dgemm("N", "N", &d_size, &d_size, &d_size, &alpha, aux.base(),
|
2019-01-24 13:08:05 +01:00
|
|
|
&lda, t.getData().base(), &ldb, &beta, getData().base(), &ldc);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::QuasiTriangular(const SchurDecomp &decomp)
|
|
|
|
: SqSylvMatrix(decomp.getT()),
|
|
|
|
diagonal(getData().base(), decomp.getDim())
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
/* this pads matrix with intial columns with zeros */
|
|
|
|
QuasiTriangular::QuasiTriangular(const SchurDecompZero &decomp)
|
|
|
|
: SqSylvMatrix(decomp.getDim())
|
|
|
|
{
|
|
|
|
// nullify first decomp.getZeroCols() columns
|
|
|
|
int zeros = decomp.getZeroCols()*decomp.getDim();
|
|
|
|
Vector zv(getData(), 0, zeros);
|
|
|
|
zv.zeros();
|
|
|
|
// fill right upper part with decomp.getRU()
|
|
|
|
for (int i = 0; i < decomp.getRU().numRows(); i++)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < decomp.getRU().numCols(); j++)
|
|
|
|
{
|
|
|
|
getData()[(j+decomp.getZeroCols())*decomp.getDim()+i] = decomp.getRU().get(i, j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// fill right lower part with decomp.getT()
|
|
|
|
for (int i = 0; i < decomp.getT().numRows(); i++)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < decomp.getT().numCols(); j++)
|
|
|
|
{
|
|
|
|
getData()[(j+decomp.getZeroCols())*decomp.getDim()+decomp.getZeroCols()+i]
|
|
|
|
= decomp.getT().get(i, j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// construct diagonal
|
2019-01-15 18:55:09 +01:00
|
|
|
diagonal = Diagonal{getData().base(), decomp.getDim()};
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::setMatrix(double r, const QuasiTriangular &t)
|
|
|
|
{
|
|
|
|
getData().zeros();
|
|
|
|
getData().add(r, t.getData());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::setMatrixViaIter(double r, const QuasiTriangular &t)
|
|
|
|
{
|
|
|
|
register double rr = r;
|
|
|
|
diag_iter dil = diag_begin();
|
|
|
|
const_diag_iter dir = t.diag_begin();
|
|
|
|
for (; dil != diag_end(); ++dil, ++dir)
|
|
|
|
{
|
|
|
|
(*dil).getAlpha() = rr*(*(*dir).getAlpha());
|
|
|
|
if (!(*dil).isReal())
|
|
|
|
{
|
|
|
|
(*dil).getBeta1() = rr*(*dir).getBeta1();
|
|
|
|
(*dil).getBeta2() = rr*(*dir).getBeta2();
|
|
|
|
}
|
|
|
|
col_iter cil = col_begin(*dil);
|
|
|
|
const_col_iter cir = t.col_begin(*dir);
|
|
|
|
for (; cil != col_end(*dil); ++cil, ++cir)
|
|
|
|
{
|
|
|
|
if ((*dil).isReal())
|
|
|
|
{
|
|
|
|
*cil = rr*(*cir);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cil.a() = rr*cir.a();
|
|
|
|
cil.b() = rr*cir.b();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::addMatrix(double r, const QuasiTriangular &t)
|
|
|
|
{
|
|
|
|
getData().add(r, t.getData());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::addMatrixViaIter(double r, const QuasiTriangular &t)
|
|
|
|
{
|
|
|
|
register double rr = r;
|
|
|
|
diag_iter dil = diag_begin();
|
|
|
|
const_diag_iter dir = t.diag_begin();
|
|
|
|
for (; dil != diag_end(); ++dil, ++dir)
|
|
|
|
{
|
|
|
|
(*dil).getAlpha() = (*(*dil).getAlpha()) + rr*(*(*dir).getAlpha());
|
|
|
|
if (!(*dil).isReal())
|
|
|
|
{
|
|
|
|
(*dil).getBeta1() += rr*(*dir).getBeta1();
|
|
|
|
(*dil).getBeta2() += rr*(*dir).getBeta2();
|
|
|
|
}
|
|
|
|
col_iter cil = col_begin(*dil);
|
|
|
|
const_col_iter cir = t.col_begin(*dir);
|
|
|
|
for (; cil != col_end(*dil); ++cil, ++cir)
|
|
|
|
{
|
|
|
|
if ((*dil).isReal())
|
|
|
|
{
|
|
|
|
*cil += rr*(*cir);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cil.a() += rr*cir.a();
|
|
|
|
cil.b() += rr*cir.b();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::addUnit()
|
|
|
|
{
|
|
|
|
for (diag_iter di = diag_begin(); di != diag_end(); ++di)
|
|
|
|
{
|
|
|
|
(*di).getAlpha() = *((*di).getAlpha()) + 1.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::solve(Vector &x, const ConstVector &b, double &eig_min)
|
|
|
|
{
|
|
|
|
x = b;
|
|
|
|
solvePre(x, eig_min);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::solveTrans(Vector &x, const ConstVector &b, double &eig_min)
|
|
|
|
{
|
|
|
|
x = b;
|
|
|
|
solvePreTrans(x, eig_min);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::solvePre(Vector &x, double &eig_min)
|
|
|
|
{
|
|
|
|
addUnit();
|
|
|
|
for (diag_iter di = diag_begin(); di != diag_end(); ++di)
|
|
|
|
{
|
|
|
|
double eig_size;
|
|
|
|
if (!(*di).isReal())
|
|
|
|
{
|
|
|
|
eig_size = (*di).getDeterminant();
|
|
|
|
eliminateLeft((*di).getIndex()+1, (*di).getIndex(), x);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eig_size = *(*di).getAlpha()*(*(*di).getAlpha());
|
|
|
|
}
|
|
|
|
if (eig_size < eig_min)
|
|
|
|
eig_min = eig_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
blas_int nn = diagonal.getSize();
|
2019-01-24 13:08:05 +01:00
|
|
|
blas_int lda = ld;
|
2019-01-08 17:12:05 +01:00
|
|
|
blas_int incx = x.skip();
|
|
|
|
dtrsv("U", "N", "N", &nn, getData().base(), &lda, x.base(), &incx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::solvePreTrans(Vector &x, double &eig_min)
|
|
|
|
{
|
|
|
|
addUnit();
|
|
|
|
for (diag_iter di = diag_begin(); di != diag_end(); ++di)
|
|
|
|
{
|
|
|
|
double eig_size;
|
|
|
|
if (!(*di).isReal())
|
|
|
|
{
|
|
|
|
eig_size = (*di).getDeterminant();
|
|
|
|
eliminateRight((*di).getIndex()+1, (*di).getIndex(), x);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eig_size = *(*di).getAlpha()*(*(*di).getAlpha());
|
|
|
|
}
|
|
|
|
if (eig_size < eig_min)
|
|
|
|
eig_min = eig_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
blas_int nn = diagonal.getSize();
|
2019-01-24 13:08:05 +01:00
|
|
|
blas_int lda = ld;
|
2019-01-08 17:12:05 +01:00
|
|
|
blas_int incx = x.skip();
|
|
|
|
dtrsv("U", "T", "N", &nn, getData().base(), &lda, x.base(), &incx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculates x = Tb */
|
|
|
|
void
|
|
|
|
QuasiTriangular::multVec(Vector &x, const ConstVector &b) const
|
|
|
|
{
|
|
|
|
x = b;
|
|
|
|
blas_int nn = diagonal.getSize();
|
2019-01-24 13:08:05 +01:00
|
|
|
blas_int lda = ld;
|
2019-01-08 17:12:05 +01:00
|
|
|
blas_int incx = x.skip();
|
|
|
|
dtrmv("U", "N", "N", &nn, getData().base(), &lda, x.base(), &incx);
|
|
|
|
for (const_diag_iter di = diag_begin(); di != diag_end(); ++di)
|
|
|
|
{
|
|
|
|
if (!(*di).isReal())
|
|
|
|
{
|
|
|
|
int jbar = (*di).getIndex();
|
|
|
|
x[jbar+1] += (*di).getBeta2()*(b[jbar]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::multVecTrans(Vector &x, const ConstVector &b) const
|
|
|
|
{
|
|
|
|
x = b;
|
|
|
|
blas_int nn = diagonal.getSize();
|
2019-01-24 13:08:05 +01:00
|
|
|
blas_int lda = ld;
|
2019-01-08 17:12:05 +01:00
|
|
|
blas_int incx = x.skip();
|
|
|
|
dtrmv("U", "T", "N", &nn, getData().base(), &lda, x.base(), &incx);
|
|
|
|
for (const_diag_iter di = diag_begin(); di != diag_end(); ++di)
|
|
|
|
{
|
|
|
|
if (!(*di).isReal())
|
|
|
|
{
|
|
|
|
int jbar = (*di).getIndex();
|
|
|
|
x[jbar] += (*di).getBeta2()*b[jbar+1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::multaVec(Vector &x, const ConstVector &b) const
|
|
|
|
{
|
|
|
|
Vector tmp((const Vector &)x); // new copy
|
|
|
|
multVec(x, b);
|
|
|
|
x.add(1.0, tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::multaVecTrans(Vector &x, const ConstVector &b) const
|
|
|
|
{
|
|
|
|
Vector tmp((const Vector &)x); // new copy
|
|
|
|
multVecTrans(x, b);
|
|
|
|
x.add(1.0, tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculates x=x+(T\otimes I)b, where size of I is given by b (KronVector) */
|
|
|
|
void
|
|
|
|
QuasiTriangular::multaKron(KronVector &x, const ConstKronVector &b) const
|
|
|
|
{
|
|
|
|
int id = b.getN()*power(b.getM(), b.getDepth()-1);
|
Dynare++ / sylvester equation solver: refactor Vector and ConstVector classes
- these classes now encapsulate a std::shared_ptr<{const, }double>, so that
they do not perform memory management, and several {Const,}Vector instances
can transparently share the same underlying data
- make converting constructor from ConstVector to Vector explicit, since that
entails memory allocation (but the reverse conversion is almost costless, so
keep it implicit); do the same for GeneralMatrix/ConstGeneralMatrix,
TwoDMatrix/ConstTwoDMatrix
- remove the constructors that were extracting a row/column from a matrix, and
replace them by getRow() and getCol() methods on {Const,}GeneralMatrix
- rename and change the API of the complex version Vector::add(), so that it is
explicit that it deals with complex numbers
- add constructors that take a MATLAB mxArray
2019-01-22 16:07:44 +01:00
|
|
|
ConstGeneralMatrix b_resh(b, id, b.getM());
|
|
|
|
GeneralMatrix x_resh(x, id, b.getM());
|
2019-01-08 17:12:05 +01:00
|
|
|
x_resh.multAndAdd(b_resh, ConstGeneralMatrix(*this), "trans");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculates x=x+(T'\otimes I)b, where size of I is given by b (KronVector) */
|
|
|
|
void
|
|
|
|
QuasiTriangular::multaKronTrans(KronVector &x, const ConstKronVector &b) const
|
|
|
|
{
|
|
|
|
int id = b.getN()*power(b.getM(), b.getDepth()-1);
|
Dynare++ / sylvester equation solver: refactor Vector and ConstVector classes
- these classes now encapsulate a std::shared_ptr<{const, }double>, so that
they do not perform memory management, and several {Const,}Vector instances
can transparently share the same underlying data
- make converting constructor from ConstVector to Vector explicit, since that
entails memory allocation (but the reverse conversion is almost costless, so
keep it implicit); do the same for GeneralMatrix/ConstGeneralMatrix,
TwoDMatrix/ConstTwoDMatrix
- remove the constructors that were extracting a row/column from a matrix, and
replace them by getRow() and getCol() methods on {Const,}GeneralMatrix
- rename and change the API of the complex version Vector::add(), so that it is
explicit that it deals with complex numbers
- add constructors that take a MATLAB mxArray
2019-01-22 16:07:44 +01:00
|
|
|
ConstGeneralMatrix b_resh(b, id, b.getM());
|
|
|
|
GeneralMatrix x_resh(x, id, b.getM());
|
2019-01-08 17:12:05 +01:00
|
|
|
x_resh.multAndAdd(b_resh, ConstGeneralMatrix(*this));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::multKron(KronVector &x) const
|
|
|
|
{
|
|
|
|
KronVector b((const KronVector &)x); // make copy
|
|
|
|
x.zeros();
|
|
|
|
multaKron(x, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::multKronTrans(KronVector &x) const
|
|
|
|
{
|
|
|
|
KronVector b((const KronVector &)x); // make copy
|
|
|
|
x.zeros();
|
|
|
|
multaKronTrans(x, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::multLeftOther(GeneralMatrix &a) const
|
|
|
|
{
|
|
|
|
a.multLeft(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::multLeftOtherTrans(GeneralMatrix &a) const
|
|
|
|
{
|
|
|
|
a.multLeftTrans(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::swapDiagLogically(diag_iter it)
|
|
|
|
{
|
|
|
|
diagonal.swapLogically(it);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
QuasiTriangular::checkDiagConsistency(diag_iter it)
|
|
|
|
{
|
|
|
|
diagonal.checkConsistency(it);
|
|
|
|
}
|
|
|
|
|
|
|
|
double
|
|
|
|
QuasiTriangular::getAverageDiagSize(diag_iter start, diag_iter end)
|
|
|
|
{
|
|
|
|
return diagonal.getAverageSize(start, end);
|
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::diag_iter
|
|
|
|
QuasiTriangular::findClosestDiagBlock(diag_iter start, diag_iter end, double a)
|
|
|
|
{
|
|
|
|
return diagonal.findClosestBlock(start, end, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
QuasiTriangular::diag_iter
|
|
|
|
QuasiTriangular::findNextLargerBlock(diag_iter start, diag_iter end, double a)
|
|
|
|
{
|
|
|
|
return diagonal.findNextLargerBlock(start, end, a);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
QuasiTriangular::getNumOffdiagonal() const
|
|
|
|
{
|
|
|
|
return diagonal.getSize()*(diagonal.getSize()-1)/2 - diagonal.getNumComplex();
|
|
|
|
}
|