466 lines
16 KiB
C++
466 lines
16 KiB
C++
// @HEADER
|
|
// ***********************************************************************
|
|
//
|
|
// Anasazi: Block Eigensolvers Package
|
|
// Copyright (2004) Sandia Corporation
|
|
//
|
|
// Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
|
|
// license for use of this work by or on behalf of the U.S. Government.
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as
|
|
// published by the Free Software Foundation; either version 2.1 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful, but
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
// USA
|
|
// Questions? Contact Michael A. Heroux (maherou@sandia.gov)
|
|
//
|
|
// ***********************************************************************
|
|
// @HEADER
|
|
|
|
/*! \file AnasaziBasicSort.hpp
|
|
\brief Basic implementation of the Anasazi::SortManager class
|
|
*/
|
|
|
|
#ifndef ANASAZI_BASIC_SORT_HPP
|
|
#define ANASAZI_BASIC_SORT_HPP
|
|
|
|
/*! \class Anasazi::BasicSort
|
|
\brief An implementation of the Anasazi::SortManager that performs a collection
|
|
of common sorting techniques.
|
|
|
|
\author Chris Baker, Ulrich Hetmaniuk, Rich Lehoucq, and Heidi Thornquist
|
|
*/
|
|
|
|
#include "AnasaziConfigDefs.hpp"
|
|
#include "AnasaziSortManager.hpp"
|
|
#include "Teuchos_LAPACK.hpp"
|
|
#include "Teuchos_ScalarTraits.hpp"
|
|
|
|
namespace Anasazi {
|
|
|
|
template<class ScalarType, class MV, class OP>
|
|
class BasicSort : public SortManager<ScalarType,MV,OP> {
|
|
|
|
public:
|
|
|
|
//! Constructor
|
|
/**
|
|
@param which [in] The eigenvalues of interest for this eigenproblem.
|
|
<ul>
|
|
<li> "LM" - Largest Magnitude [ default ]
|
|
<li> "SM" - Smallest Magnitude
|
|
<li> "LR" - Largest Real
|
|
<li> "SR" - Smallest Real
|
|
<li> "LI" - Largest Imaginary
|
|
<li> "SI" - Smallest Imaginary
|
|
</ul>
|
|
*/
|
|
BasicSort( const std::string which = "LM" ) {
|
|
setSortType(which);
|
|
}
|
|
|
|
//! Destructor
|
|
virtual ~BasicSort() {};
|
|
|
|
//! Set sort type
|
|
/**
|
|
@param which [in] The eigenvalues of interest for this eigenproblem.
|
|
<ul>
|
|
<li> "LM" - Largest Magnitude [ default ]
|
|
<li> "SM" - Smallest Magnitude
|
|
<li> "LR" - Largest Real
|
|
<li> "SR" - Smallest Real
|
|
<li> "LI" - Largest Imaginary
|
|
<li> "SI" - Smallest Imaginary
|
|
</ul>
|
|
*/
|
|
void setSortType( const std::string which ) {
|
|
which_ = which;
|
|
TEST_FOR_EXCEPTION(which_.compare("LM") && which_.compare("SM") &&
|
|
which_.compare("LR") && which_.compare("SR") &&
|
|
which_.compare("LI") && which_.compare("SI"), std::invalid_argument,
|
|
"Anasazi::BasicSort::sort(): sorting order is not valid");
|
|
};
|
|
|
|
//! Sort the vector of eigenvalues, optionally returning the permutation vector.
|
|
/**
|
|
@param solver [in] Eigensolver that is calling the sorting routine
|
|
|
|
@param n [in] Number of values in evals to be sorted.
|
|
|
|
@param evals [in/out] Vector of length n containing the eigenvalues to be sorted
|
|
|
|
@param perm [out] Vector of length n to store the permutation index (optional)
|
|
*/
|
|
void sort(Eigensolver<ScalarType,MV,OP>* solver, const int n, std::vector<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType> &evals, std::vector<int> *perm = 0) const;
|
|
|
|
/*! \brief Sort the vectors of eigenpairs, optionally returning the permutation vector.
|
|
|
|
This routine takes two vectors, one for each part of a complex
|
|
eigenvalue. This is helpful for solving real, non-symmetric eigenvalue
|
|
problems.
|
|
|
|
@param solver [in] Eigensolver that is calling the sorting routine
|
|
|
|
@param n [in] Number of values in r_evals,i_evals to be sorted.
|
|
|
|
@param r_evals [in/out] Vector of length n containing the real part of the eigenvalues to be sorted
|
|
|
|
@param i_evals [in/out] Vector of length n containing the imaginary part of the eigenvalues to be sorted
|
|
|
|
@param perm [out] Vector of length n to store the permutation index (optional)
|
|
*/
|
|
void sort(Eigensolver<ScalarType,MV,OP>* solver,
|
|
const int n,
|
|
std::vector<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType> &r_evals,
|
|
std::vector<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType> &i_evals,
|
|
std::vector<int> *perm = 0) const;
|
|
|
|
protected:
|
|
|
|
//! Sorting type
|
|
/*! \note Sorting choices:
|
|
<ul>
|
|
<li> "LM" - Largest Magnitude [ default ]
|
|
<li> "SM" - Smallest Magnitude
|
|
<li> "LR" - Largest Real
|
|
<li> "SR" - Smallest Real
|
|
<li> "LI" - Largest Imaginary
|
|
<li> "SI" - Smallest Imaginary
|
|
</ul>
|
|
*/
|
|
std::string which_;
|
|
|
|
};
|
|
|
|
template<class ScalarType, class MV, class OP>
|
|
void BasicSort<ScalarType,MV,OP>::sort(Eigensolver<ScalarType,MV,OP>* solver, const int n,
|
|
std::vector<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType> &evals,
|
|
std::vector<int> *perm) const
|
|
{
|
|
int i=0,j=0;
|
|
|
|
TEST_FOR_EXCEPTION(evals.size() < (unsigned int) n,
|
|
std::invalid_argument, "Anasazi::BasicSort:sort(): eigenvalue vector size isn't consistent with n.");
|
|
if (perm) {
|
|
TEST_FOR_EXCEPTION(perm->size() < (unsigned int) n,
|
|
std::invalid_argument, "Anasazi::BasicSort:sort(): permutation vector size isn't consistent with n.");
|
|
}
|
|
|
|
// Temp integer for swapping the index of the permutation, used in all sorting types.
|
|
int tempord=0;
|
|
|
|
typedef typename Teuchos::ScalarTraits<ScalarType>::magnitudeType MagnitudeType;
|
|
typedef Teuchos::ScalarTraits<MagnitudeType> MT;
|
|
|
|
// Temp variable for swapping the eigenvalue used in all sorting types.
|
|
MagnitudeType temp;
|
|
|
|
Teuchos::LAPACK<int,MagnitudeType> lapack;
|
|
|
|
//
|
|
// Reset the permutation if it is required.
|
|
//
|
|
if (perm) {
|
|
for (i=0; i < n; i++) {
|
|
(*perm)[i] = i;
|
|
}
|
|
}
|
|
//
|
|
// These methods use an insertion sort method to circumvent recursive calls.
|
|
//---------------------------------------------------------------
|
|
// Sort eigenvalues in increasing order of magnitude
|
|
//---------------------------------------------------------------
|
|
if (!which_.compare("SM")) {
|
|
for (j=1; j < n; j++) {
|
|
temp = evals[j];
|
|
if (perm) {
|
|
tempord = (*perm)[j];
|
|
}
|
|
MagnitudeType temp2 = MT::magnitude(evals[j]);
|
|
for (i=j-1; i >=0 && MT::magnitude(evals[i]) > temp2; i--) {
|
|
evals[i+1] = evals[i];
|
|
if (perm) {
|
|
(*perm)[i+1]=(*perm)[i];
|
|
}
|
|
}
|
|
evals[i+1] = temp;
|
|
if (perm) {
|
|
(*perm)[i+1] = tempord;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
//---------------------------------------------------------------
|
|
// Sort eigenvalues in increasing order of real part
|
|
//---------------------------------------------------------------
|
|
if (!which_.compare("SR")) {
|
|
for (j=1; j < n; j++) {
|
|
temp = evals[j];
|
|
if (perm) {
|
|
tempord = (*perm)[j];
|
|
}
|
|
for (i=j-1; i >= 0 && evals[i] > temp; i--) {
|
|
evals[i+1]=evals[i];
|
|
if (perm) {
|
|
(*perm)[i+1]=(*perm)[i];
|
|
}
|
|
}
|
|
evals[i+1] = temp;
|
|
if (perm) {
|
|
(*perm)[i+1] = tempord;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
//---------------------------------------------------------------
|
|
// Sort eigenvalues in increasing order of imaginary part
|
|
// NOTE: There is no implementation for this since this sorting
|
|
// method assumes only real eigenvalues.
|
|
//---------------------------------------------------------------
|
|
TEST_FOR_EXCEPTION(!which_.compare("SI"), SortManagerError,
|
|
"Anasazi::BasicSort::sort() with one arg assumes real eigenvalues");
|
|
//---------------------------------------------------------------
|
|
// Sort eigenvalues in decreasing order of magnitude
|
|
//---------------------------------------------------------------
|
|
if (!which_.compare("LM")) {
|
|
for (j=1; j < n; j++) {
|
|
temp = evals[j];
|
|
if (perm) {
|
|
tempord = (*perm)[j];
|
|
}
|
|
MagnitudeType temp2 = MT::magnitude(evals[j]);
|
|
for (i=j-1; i >= 0 && MT::magnitude(evals[i]) < temp2; i--) {
|
|
evals[i+1]=evals[i];
|
|
if (perm) {
|
|
(*perm)[i+1]=(*perm)[i];
|
|
}
|
|
}
|
|
evals[i+1] = temp;
|
|
if (perm) {
|
|
(*perm)[i+1] = tempord;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
//---------------------------------------------------------------
|
|
// Sort eigenvalues in decreasing order of real part
|
|
//---------------------------------------------------------------
|
|
if (!which_.compare("LR")) {
|
|
for (j=1; j < n; j++) {
|
|
temp = evals[j];
|
|
if (perm) {
|
|
tempord = (*perm)[j];
|
|
}
|
|
for (i=j-1; i >= 0 && evals[i]<temp; i--) {
|
|
evals[i+1]=evals[i];
|
|
if (perm) {
|
|
(*perm)[i+1]=(*perm)[i];
|
|
}
|
|
}
|
|
evals[i+1] = temp;
|
|
if (perm) {
|
|
(*perm)[i+1] = tempord;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
//---------------------------------------------------------------
|
|
// Sort eigenvalues in decreasing order of imaginary part
|
|
// NOTE: There is no implementation for this since this templating
|
|
// assumes only real eigenvalues.
|
|
//---------------------------------------------------------------
|
|
TEST_FOR_EXCEPTION(!which_.compare("LI"), SortManagerError,
|
|
"Anasazi::BasicSort::sort() with one arg assumes real eigenvalues");
|
|
|
|
// The character string held by this class is not valid.
|
|
TEST_FOR_EXCEPTION(true, std::logic_error,
|
|
"Anasazi::BasicSort::sort(): sorting order is not valid");
|
|
}
|
|
|
|
|
|
template<class ScalarType, class MV, class OP>
|
|
void BasicSort<ScalarType,MV,OP>::sort(Eigensolver<ScalarType,MV,OP>* solver,
|
|
const int n,
|
|
std::vector<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType> &r_evals,
|
|
std::vector<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType> &i_evals,
|
|
std::vector<int> *perm) const
|
|
{
|
|
typedef typename Teuchos::ScalarTraits<ScalarType>::magnitudeType MagnitudeType;
|
|
typedef Teuchos::ScalarTraits<MagnitudeType> MT;
|
|
|
|
TEST_FOR_EXCEPTION(r_evals.size() < (unsigned int) n || i_evals.size() < (unsigned int) n,
|
|
std::invalid_argument, "Anasazi::BasicSort:sort(): real and imaginary vector sizes aren't consistent with n.");
|
|
if (perm) {
|
|
TEST_FOR_EXCEPTION(perm->size() < (unsigned int) n,
|
|
std::invalid_argument, "Anasazi::BasicSort:sort(): permutation vector size isn't consistent with n.");
|
|
}
|
|
int i=0,j=0;
|
|
int tempord=0;
|
|
|
|
MagnitudeType temp, tempr, tempi;
|
|
Teuchos::LAPACK<int,MagnitudeType> lapack;
|
|
//
|
|
// Reset the index
|
|
//
|
|
if (perm) {
|
|
for (i=0; i < n; i++) {
|
|
(*perm)[i] = i;
|
|
}
|
|
}
|
|
//
|
|
// These methods use an insertion sort method to circumvent recursive calls.
|
|
//---------------------------------------------------------------
|
|
// Sort eigenvalues in increasing order of magnitude
|
|
//---------------------------------------------------------------
|
|
if (!which_.compare("SM")) {
|
|
for (j=1; j < n; j++) {
|
|
tempr = r_evals[j]; tempi = i_evals[j];
|
|
if (perm) {
|
|
tempord = (*perm)[j];
|
|
}
|
|
temp=lapack.LAPY2(r_evals[j],i_evals[j]);
|
|
for (i=j-1; i>=0 && lapack.LAPY2(r_evals[i],i_evals[i]) > temp; i--) {
|
|
r_evals[i+1]=r_evals[i]; i_evals[i+1]=i_evals[i];
|
|
if (perm) {
|
|
(*perm)[i+1]=(*perm)[i];
|
|
}
|
|
}
|
|
r_evals[i+1] = tempr; i_evals[i+1] = tempi;
|
|
if (perm) {
|
|
(*perm)[i+1] = tempord;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
//---------------------------------------------------------------
|
|
// Sort eigenvalues in increasing order of real part
|
|
//---------------------------------------------------------------
|
|
if (!which_.compare("SR")) {
|
|
for (j=1; j < n; j++) {
|
|
tempr = r_evals[j]; tempi = i_evals[j];
|
|
if (perm) {
|
|
tempord = (*perm)[j];
|
|
}
|
|
for (i=j-1; i>=0 && r_evals[i]>tempr; i--) {
|
|
r_evals[i+1]=r_evals[i]; i_evals[i+1]=i_evals[i];
|
|
if (perm) {
|
|
(*perm)[i+1]=(*perm)[i];
|
|
}
|
|
}
|
|
r_evals[i+1] = tempr; i_evals[i+1] = tempi;
|
|
if (perm) {
|
|
(*perm)[i+1] = tempord;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
//---------------------------------------------------------------
|
|
// Sort eigenvalues in increasing order of imaginary part
|
|
//---------------------------------------------------------------
|
|
if (!which_.compare("SI")) {
|
|
for (j=1; j < n; j++) {
|
|
tempr = r_evals[j]; tempi = i_evals[j];
|
|
if (perm) {
|
|
tempord = (*perm)[j];
|
|
}
|
|
for (i=j-1; i>=0 && i_evals[i]>tempi; i--) {
|
|
r_evals[i+1]=r_evals[i]; i_evals[i+1]=i_evals[i];
|
|
if (perm) {
|
|
(*perm)[i+1]=(*perm)[i];
|
|
}
|
|
}
|
|
r_evals[i+1] = tempr; i_evals[i+1] = tempi;
|
|
if (perm) {
|
|
(*perm)[i+1] = tempord;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
//---------------------------------------------------------------
|
|
// Sort eigenvalues in decreasing order of magnitude
|
|
//---------------------------------------------------------------
|
|
if (!which_.compare("LM")) {
|
|
for (j=1; j < n; j++) {
|
|
tempr = r_evals[j]; tempi = i_evals[j];
|
|
if (perm) {
|
|
tempord = (*perm)[j];
|
|
}
|
|
temp=lapack.LAPY2(r_evals[j],i_evals[j]);
|
|
for (i=j-1; i>=0 && lapack.LAPY2(r_evals[i],i_evals[i])<temp; i--) {
|
|
r_evals[i+1]=r_evals[i]; i_evals[i+1]=i_evals[i];
|
|
if (perm) {
|
|
(*perm)[i+1]=(*perm)[i];
|
|
}
|
|
}
|
|
r_evals[i+1] = tempr; i_evals[i+1] = tempi;
|
|
if (perm) {
|
|
(*perm)[i+1] = tempord;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
//---------------------------------------------------------------
|
|
// Sort eigenvalues in decreasing order of real part
|
|
//---------------------------------------------------------------
|
|
if (!which_.compare("LR")) {
|
|
for (j=1; j < n; j++) {
|
|
tempr = r_evals[j]; tempi = i_evals[j];
|
|
if (perm) {
|
|
tempord = (*perm)[j];
|
|
}
|
|
for (i=j-1; i>=0 && r_evals[i]<tempr; i--) {
|
|
r_evals[i+1]=r_evals[i]; i_evals[i+1]=i_evals[i];
|
|
if (perm) {
|
|
(*perm)[i+1]=(*perm)[i];
|
|
}
|
|
}
|
|
r_evals[i+1] = tempr; i_evals[i+1] = tempi;
|
|
if (perm) {
|
|
(*perm)[i+1] = tempord;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
//---------------------------------------------------------------
|
|
// Sort eigenvalues in decreasing order of imaginary part
|
|
//---------------------------------------------------------------
|
|
if (!which_.compare("LI")) {
|
|
for (j=1; j < n; j++) {
|
|
tempr = r_evals[j]; tempi = i_evals[j];
|
|
if (perm) {
|
|
tempord = (*perm)[j];
|
|
}
|
|
for (i=j-1; i>=0 && i_evals[i]<tempi; i--) {
|
|
r_evals[i+1]=r_evals[i]; i_evals[i+1]=i_evals[i];
|
|
if (perm) {
|
|
(*perm)[i+1]=(*perm)[i];
|
|
}
|
|
}
|
|
r_evals[i+1] = tempr; i_evals[i+1] = tempi;
|
|
if (perm) {
|
|
(*perm)[i+1] = tempord;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
TEST_FOR_EXCEPTION(true, std::logic_error,
|
|
"Anasazi::BasicSort::sort(): sorting order is not valid");
|
|
}
|
|
|
|
|
|
} // namespace Anasazi
|
|
|
|
#endif // ANASAZI_BASIC_SORT_HPP
|
|
|