93 lines
2.6 KiB
C++
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;
|
|
}
|
|
}
|