#include <Tpetra_CrsMatrix.hpp>
#include <Tpetra_DefaultPlatform.hpp>
#include <Tpetra_Map.hpp>
#include <Tpetra_MultiVector.hpp>
#include <Tpetra_Vector.hpp>
#include <Tpetra_Version.hpp>
#include <Teuchos_oblackholestream.hpp>
template <class TpetraOperatorType>
class PowerMethod {
public:
typedef typename TpetraOperatorType::scalar_type scalar_type;
typedef typename TpetraOperatorType::local_ordinal_type local_ordinal_type;
typedef typename TpetraOperatorType::global_ordinal_type global_ordinal_type;
typedef typename TpetraOperatorType::node_type node_type;
global_ordinal_type, node_type> vec_type;
static scalar_type
run (const TpetraOperatorType& A,
const int niters,
const magnitude_type tolerance,
std::ostream& out)
{
using std::endl;
vec_type q (A.getDomainMap ());
vec_type z (A.getRangeMap ());
vec_type resid (A.getRangeMap ());
z.randomize ();
scalar_type lambda = STS::zero ();
magnitude_type normz = STM::zero ();
magnitude_type residual = STM::zero ();
const scalar_type one = STS::one ();
const scalar_type zero = STS::zero ();
const int reportFrequency = 10;
for (int iter = 0; iter < niters; ++iter) {
normz = z.norm2 ();
q.scale (one / normz, z);
A.apply (q, z);
lambda = q.dot (z);
if (iter % reportFrequency == 0 || iter + 1 == niters) {
resid.update (one, z, -lambda, q, zero);
residual = resid.norm2 ();
out << "Iteration " << iter << ":" << endl
<< "- lambda = " << lambda << endl
<< "- ||A*q - lambda*q||_2 = " << residual << endl;
}
if (residual < tolerance) {
out << "Converged after " << iter << " iterations" << endl;
break;
} else if (iter+1 == niters) {
out << "Failed to converge after " << niters << " iterations" << endl;
break;
}
}
return lambda;
}
};
int
main (int argc, char *argv[])
{
using Teuchos::arcp;
using Teuchos::tuple;
using std::cerr;
using std::cout;
using std::endl;
RCP<const Teuchos::Comm<int> > comm =
const size_t myRank = comm->getRank();
std::ostream& out = (myRank == 0) ? std::cout : blackHole;
out << Tpetra::version () << endl << endl;
const global_ordinal_type indexBase = 0;
RCP<const map_type> map =
rcp (
new map_type (numGblIndices, indexBase, comm));
const size_t numMyElements = map->getNodeNumElements ();
out << endl << "Creating the sparse matrix" << endl;
RCP<crs_matrix_type> A (new crs_matrix_type (map, 0));
const scalar_type two = static_cast<scalar_type> (2.0);
const scalar_type negOne = static_cast<scalar_type> (-1.0);
for (local_ordinal_type lclRow = 0;
lclRow < static_cast<local_ordinal_type> (numMyElements);
++lclRow) {
const global_ordinal_type gblRow = map->getGlobalElement (lclRow);
if (gblRow == 0) {
A->insertGlobalValues (gblRow,
tuple<global_ordinal_type> (gblRow, gblRow + 1),
tuple<scalar_type> (two, negOne));
}
else if (static_cast<Tpetra::global_size_t> (gblRow) == numGblIndices - 1) {
A->insertGlobalValues (gblRow,
tuple<global_ordinal_type> (gblRow - 1, gblRow),
tuple<scalar_type> (negOne, two));
}
else {
A->insertGlobalValues (gblRow,
tuple<global_ordinal_type> (gblRow - 1, gblRow, gblRow + 1),
tuple<scalar_type> (negOne, two, negOne));
}
}
A->fillComplete ();
const int niters = 500;
const magnitude_type tolerance = 1.0e-2;
scalar_type lambda =
PowerMethod<crs_matrix_type>::run (*A, niters, tolerance, out);
out << endl << "Estimated max eigenvalue: " << lambda << endl;
out << endl << "Increasing magnitude of A(0,0), solving again" << endl;
A->resumeFill ();
if (A->getRowMap ()->isNodeGlobalElement (0)) {
const global_ordinal_type idOfFirstRow = 0;
size_t numEntriesInRow = A->getNumEntriesInGlobalRow (idOfFirstRow);
Array<scalar_type> rowvals (numEntriesInRow);
Array<global_ordinal_type> rowinds (numEntriesInRow);
A->getGlobalRowCopy (idOfFirstRow, rowinds (), rowvals (), numEntriesInRow);
for (size_t i = 0; i < numEntriesInRow; i++) {
if (rowinds[i] == idOfFirstRow) {
rowvals[i] *= 10.0;
}
}
A->replaceGlobalValues (idOfFirstRow, rowinds (), rowvals ());
}
A->fillComplete ();
lambda = PowerMethod<crs_matrix_type>::run (*A, niters, tolerance, out);
out << endl << "Estimated max eigenvalue: " << lambda << endl;
if (myRank == 0) {
cout << "End Result: TEST PASSED" << endl;
}
return 0;
}