10 #ifndef IFPACK2_POWERMETHOD_HPP
11 #define IFPACK2_POWERMETHOD_HPP
20 #include "Kokkos_ArithTraits.hpp"
21 #include "Teuchos_FancyOStream.hpp"
22 #include "Teuchos_oblackholestream.hpp"
23 #include "Tpetra_Details_residual.hpp"
28 namespace PowerMethod {
35 template <
class OneDViewType,
36 class LocalOrdinal =
typename OneDViewType::size_type>
37 class PositivizeVector {
38 static_assert(Kokkos::is_view<OneDViewType>::value,
39 "OneDViewType must be a 1-D Kokkos::View.");
40 static_assert(static_cast<int>(OneDViewType::rank) == 1,
41 "This functor only works with a 1-D View.");
42 static_assert(std::is_integral<LocalOrdinal>::value,
43 "The second template parameter, LocalOrdinal, "
44 "must be an integer type.");
47 PositivizeVector(
const OneDViewType& x)
50 KOKKOS_INLINE_FUNCTION
void
51 operator()(
const LocalOrdinal& i)
const {
52 typedef typename OneDViewType::non_const_value_type IST;
53 typedef Kokkos::ArithTraits<IST> STS;
54 typedef Kokkos::ArithTraits<typename STS::mag_type> STM;
56 if (STS::real(x_(i)) < STM::zero()) {
86 template <
class OperatorType,
class V>
87 typename V::scalar_type
88 powerMethodWithInitGuess(
const OperatorType& A,
94 const int eigNormalizationFreq = 1,
96 const bool computeSpectralRadius =
true) {
97 typedef typename V::scalar_type ST;
101 bool verbose = (out != Teuchos::null);
105 *out <<
" powerMethodWithInitGuess:" << endl;
108 const ST zero =
static_cast<ST
>(0.0);
109 const ST one =
static_cast<ST
>(1.0);
111 ST lambdaMaxOld = one;
116 "Ifpack2::PowerMethod::powerMethodWithInitGuess: The initial guess "
117 "has zero norm. This could be either because Tpetra::Vector::"
118 "randomize filled the vector with zeros (if that was used to "
119 "compute the initial guess), or because the norm2 method has a "
120 "bug. The first is not impossible, but unlikely.");
123 *out <<
" Original norm1(x): " << x->norm1()
124 <<
", norm2(x): " << norm << endl;
127 x->scale(one / norm);
130 *out <<
" norm1(x.scale(one/norm)): " << x->norm1() << endl;
143 if (computeSpectralRadius) {
147 *out <<
" PowerMethod using spectral radius route" << endl;
149 for (
int iter = 0; iter < numIters - 1; ++iter) {
151 *out <<
" Iteration " << iter << endl;
154 x->elementWiseMultiply(STS::one(), D_inv, *y, STS::zero());
156 if (((iter + 1) % eigNormalizationFreq == 0) && (iter < numIters - 2)) {
160 *out <<
" norm is zero; returning zero" << endl;
161 *out <<
" Power method terminated after " << iter <<
" iterations." << endl;
165 lambdaMaxOld = lambdaMax;
169 *out <<
" lambdaMax: " << lambdaMax << endl;
170 *out <<
" Power method terminated after " << iter <<
" iterations." << endl;
173 }
else if (verbose) {
174 *out <<
" lambdaMaxOld: " << lambdaMaxOld << endl;
175 *out <<
" lambdaMax: " << lambdaMax << endl;
179 x->scale(one / norm);
183 *out <<
" lambdaMax: " << lambdaMax << endl;
189 *out <<
" norm is zero; returning zero" << endl;
190 *out <<
" Power method terminated after " << numIters <<
" iterations." << endl;
194 x->scale(one / norm);
196 y->elementWiseMultiply(STS::one(), D_inv, *y, STS::zero());
197 lambdaMax = y->norm2();
203 *out <<
" PowerMethod using largest eigenvalue route" << endl;
205 for (
int iter = 0; iter < numIters - 1; ++iter) {
207 *out <<
" Iteration " << iter << endl;
210 y->elementWiseMultiply(STS::one(), D_inv, *y, STS::zero());
212 if (((iter + 1) % eigNormalizationFreq == 0) && (iter < numIters - 2)) {
213 xDinvAx = x->dot(*y);
214 if (xDinvAx == zero) {
216 *out <<
" xDinvAx is zero; returning zero" << endl;
217 *out <<
" Power method terminated after " << iter <<
" iterations." << endl;
221 lambdaMaxOld = lambdaMax;
225 *out <<
" lambdaMax: " << lambdaMax << endl;
226 *out <<
" Power method terminated after " << iter <<
" iterations." << endl;
229 }
else if (verbose) {
230 *out <<
" lambdaMaxOld: " << lambdaMaxOld << endl;
231 *out <<
" lambdaMax: " << lambdaMax << endl;
237 x->scale(one / norm);
241 *out <<
" lambdaMax: " << lambdaMax << endl;
247 *out <<
" norm is zero; returning zero" << endl;
248 *out <<
" Power method terminated after " << numIters <<
" iterations." << endl;
252 x->scale(one / norm);
254 y->elementWiseMultiply(STS::one(), D_inv, *y, STS::zero());
255 lambdaMax = y->dot(*x);
259 *out <<
" lambdaMax: " << lambdaMax << endl;
260 *out <<
" Power method terminated after " << numIters <<
" iterations." << endl;
278 void computeInitialGuessForPowerMethod(V& x,
const bool nonnegativeRealParts) {
279 typedef typename V::device_type::execution_space dev_execution_space;
280 typedef typename V::local_ordinal_type LO;
284 if (nonnegativeRealParts) {
285 auto x_lcl = x.getLocalViewDevice(Tpetra::Access::ReadWrite);
286 auto x_lcl_1d = Kokkos::subview(x_lcl, Kokkos::ALL(), 0);
288 const LO lclNumRows =
static_cast<LO
>(x.getLocalLength());
289 Kokkos::RangePolicy<dev_execution_space, LO> range(0, lclNumRows);
290 PositivizeVector<decltype(x_lcl_1d), LO> functor(x_lcl_1d);
291 Kokkos::parallel_for(range, functor);
311 template <
class OperatorType,
class V>
312 typename V::scalar_type
313 powerMethod(
const OperatorType& A,
318 const int eigNormalizationFreq = 1,
320 const bool computeSpectralRadius =
true) {
321 typedef typename V::scalar_type ST;
324 bool verbose = (out != Teuchos::null);
327 *out <<
"powerMethod:" << std::endl;
330 const ST zero =
static_cast<ST
>(0.0);
336 computeInitialGuessForPowerMethod(*x,
false);
338 ST lambdaMax = powerMethodWithInitGuess(A, D_inv, numIters, x, y, tolerance, eigNormalizationFreq, out, computeSpectralRadius);
347 if (STS::real(lambdaMax) < STS::real(zero)) {
349 *out <<
"real(lambdaMax) = " << STS::real(lambdaMax) <<
" < 0; "
350 "try again with a different random initial guess"
360 computeInitialGuessForPowerMethod(*x,
true);
361 lambdaMax = powerMethodWithInitGuess(A, D_inv, numIters, x, y, tolerance, eigNormalizationFreq, out, computeSpectralRadius);
369 #endif // IFPACK2_POWERMETHOD_HPP
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
void swap(RCP< T > &r_ptr)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
static magnitudeType magnitude(T a)