dynare/dynare++/sylv/cc/SchurDecompEig.cpp

93 lines
2.6 KiB
C++

#include "SchurDecompEig.h"
#include "SylvException.h"
#include <dynlapack.h>
/* bubble diagonal 1-1, or 2-2 block from position 'from' to position
* 'to'. If an eigenvalue cannot be swapped with its neighbour, the
* neighbour is bubbled also in front. The method returns a new
* position 'to', where the original block pointed by 'to' happens to
* appear at the end. 'from' must be greater than 'to'.
*/
SchurDecompEig::diag_iter
SchurDecompEig::bubbleEigen(diag_iter from, diag_iter to)
{
diag_iter run = from;
while (run != to) {
diag_iter runm = run;
if (!tryToSwap(run, runm) && runm == to) {
++to;
} else {
// bubble all eigenvalues from runm(incl.) to run(excl.),
// this includes either bubbling generated eigenvalues due
// to split, or an eigenvalue which couldn't be swapped
while (runm != run) {
to = bubbleEigen(runm, to);
++runm;
}
}
}
return to;
}
/* this tries to swap two neighbouring eigenvalues, 'it' and '--it',
* and returns 'itadd'. If the blocks can be swapped, new eigenvalues
* can emerge due to possible 2-2 block splits. 'it' then points to
* the last eigenvalue coming from block pointed by 'it' at the
* begining, and 'itadd' points to the first. On swap failure, 'it' is
* not changed, and 'itadd' points to previous eignevalue (which must
* be moved backwards before). In either case, it is necessary to
* resolve eigenvalues from 'itadd' to 'it', before the 'it' can be
* resolved.
* The success is signaled by returned true.
*/
bool SchurDecompEig::tryToSwap(diag_iter& it, diag_iter& itadd)
{
itadd = it;
--itadd;
lapack_int n = getDim();
lapack_int ifst = (*it).getIndex() + 1;
lapack_int ilst = (*itadd).getIndex() + 1;
double* work = new double[n];
lapack_int info;
dtrexc("V", &n, getT().base(), &n, getQ().base(), &n, &ifst, &ilst, work,
&info);
delete [] work;
if (info < 0) {
throw SYLV_MES_EXCEPTION("Wrong argument to dtrexc.");
}
if (info == 0) {
// swap successful
getT().swapDiagLogically(itadd);
//check for 2-2 block splits
getT().checkDiagConsistency(it);
getT().checkDiagConsistency(itadd);
// and go back by 'it' in NEW eigenvalue set
--it;
return true;
}
return false;
}
void SchurDecompEig::orderEigen()
{
diag_iter run = getT().diag_begin();
diag_iter runp = run;
++runp;
double last_size = 0.0;
while (runp != getT().diag_end()) {
diag_iter least = getT().findNextLargerBlock(run, getT().diag_end(),
last_size);
last_size = (*least).getSize();
if (run == least)
++run;
else
run = bubbleEigen(least, run);
runp = run;
++runp;
}
}