Belos Version of the Day
Loading...
Searching...
No Matches
BelosOrthoManagerTest.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Belos: Block Linear Solvers Package
4//
5// Copyright 2004-2016 NTESS and the Belos contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
13
14#include <BelosConfigDefs.hpp>
19#include <BelosMVOPTester.hpp>
20#include <Teuchos_StandardCatchMacros.hpp>
21#include <Teuchos_TimeMonitor.hpp>
22#include <iostream>
23#include <stdexcept>
24
25using std::endl;
26
27namespace Belos {
28 namespace Test {
29
34 template<class Scalar, class MV, class DM>
36 private:
37 typedef Scalar scalar_type;
38 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType magnitude_type;
41
42 public:
52 static void
53 baseline (const Teuchos::RCP<const MV>& X,
54 const int numCols,
55 const int numBlocks,
56 const int numTrials)
57 {
58 using Teuchos::Array;
59 using Teuchos::RCP;
60 using Teuchos::rcp;
61 using Teuchos::Time;
62 using Teuchos::TimeMonitor;
63
64 // Make some blocks to "orthogonalize." Fill with random
65 // data. We only need X so that we can make clones (it knows
66 // its data distribution).
68 for (int k = 0; k < numBlocks; ++k) {
69 V[k] = MVT::Clone (*X, numCols);
70 MVT::MvRandom (*V[k]);
71 }
72
73 // Make timers with informative labels
74 RCP<Time> timer = TimeMonitor::getNewCounter ("Baseline for OrthoManager benchmark");
75
76 // Baseline benchmark just copies data. It's sort of a lower
77 // bound proxy for the volume of data movement done by a real
78 // OrthoManager.
79 {
81 for (int trial = 0; trial < numTrials; ++trial) {
82 for (int k = 0; k < numBlocks; ++k) {
83 for (int j = 0; j < k; ++j)
84 MVT::Assign (*V[j], *V[k]);
85 MVT::Assign (*X, *V[k]);
86 }
87 }
88 }
89 }
90
122 static void
124 const std::string& orthoManName,
125 const std::string& normalization,
126 const Teuchos::RCP<const MV>& X,
127 const int numCols,
128 const int numBlocks,
129 const int numTrials,
130 const Teuchos::RCP<OutputManager<Scalar> >& outMan,
131 std::ostream& resultStream,
132 const bool displayResultsCompactly=false)
133 {
134 using Teuchos::Array;
135 using Teuchos::ArrayView;
136 using Teuchos::RCP;
137 using Teuchos::rcp;
138 using Teuchos::Time;
139 using Teuchos::TimeMonitor;
140 using std::endl;
141
142 TEUCHOS_TEST_FOR_EXCEPTION(orthoMan.is_null(), std::invalid_argument,
143 "orthoMan is null");
144 TEUCHOS_TEST_FOR_EXCEPTION(X.is_null(), std::invalid_argument,
145 "X is null");
146 TEUCHOS_TEST_FOR_EXCEPTION(numCols < 1, std::invalid_argument,
147 "numCols = " << numCols << " < 1");
148 TEUCHOS_TEST_FOR_EXCEPTION(numBlocks < 1, std::invalid_argument,
149 "numBlocks = " << numBlocks << " < 1");
150 TEUCHOS_TEST_FOR_EXCEPTION(numTrials < 1, std::invalid_argument,
151 "numTrials = " << numTrials << " < 1");
152 // Debug output stream
153 std::ostream& debugOut = outMan->stream(Debug);
154
155 // If you like, you can add the "baseline" as an approximate
156 // lower bound for orthogonalization performance. It may be
157 // useful as a sanity check to make sure that your
158 // orthogonalizations are really computing something, though
159 // testing accuracy can help with that too.
160 //
161 //baseline (X, numCols, numBlocks, numTrials);
162
163 // Make space to put the projection and normalization
164 // coefficients.
166 for (int k = 0; k < numBlocks; ++k) {
167 C[k] = DMT::Create(numCols, numCols);
168 }
169 RCP<DM> B = DMT::Create(numCols, numCols);
170
171 // Make some blocks to orthogonalize. Fill with random data.
172 // We won't be orthogonalizing X, or even modifying X. We
173 // only need X so that we can make clones (since X knows its
174 // data distribution).
176 for (int k = 0; k < numBlocks; ++k) {
177 V[k] = MVT::Clone (*X, numCols);
178 MVT::MvRandom (*V[k]);
179 }
180
181 // Make timers with informative labels. We time an additional
182 // first run to measure the startup costs, if any, of the
183 // OrthoManager instance.
185 {
186 std::ostringstream os;
187 os << "OrthoManager: " << orthoManName << " first run";
188 firstRunTimer = TimeMonitor::getNewCounter (os.str());
189 }
191 {
192 std::ostringstream os;
193 os << "OrthoManager: " << orthoManName << " total over "
194 << numTrials << " trials (excluding first run above)";
195 timer = TimeMonitor::getNewCounter (os.str());
196 }
197 // The first run lets us measure the startup costs, if any, of
198 // the OrthoManager instance, without these costs influencing
199 // the following timing runs.
200 {
202 {
203 (void) orthoMan->normalize (*V[0], B);
204 for (int k = 1; k < numBlocks; ++k) {
205 // k is the number of elements in the ArrayView. We
206 // have to assign first to an ArrayView-of-RCP-of-MV,
207 // rather than to an ArrayView-of-RCP-of-const-MV, since
208 // the latter requires a reinterpret cast. Don't you
209 // love C++ type inference?
210 ArrayView<RCP<MV> > V_0k_nonconst = V.view (0, k);
212 Teuchos::av_reinterpret_cast<RCP<const MV> > (V_0k_nonconst);
213 (void) orthoMan->projectAndNormalize (*V[k], C, B, V_0k);
214 }
215 }
216 // "Test" that the trial run actually orthogonalized
217 // correctly. Results are printed to the OutputManager's
218 // Belos::Debug output stream, so depending on the
219 // OutputManager's chosen verbosity level, you may or may
220 // not see the results of the test.
221 //
222 // NOTE (mfh 22 Jan 2011) For now, these results have to be
223 // inspected visually. We should add a simple automatic
224 // test.
225 debugOut << "Orthogonality of V[0:" << (numBlocks-1)
226 << "]:" << endl;
227 for (int k = 0; k < numBlocks; ++k) {
228 // Orthogonality of each block
229 debugOut << "For block V[" << k << "]:" << endl;
230 debugOut << " ||<V[" << k << "], V[" << k << "]> - I|| = "
231 << orthoMan->orthonormError(*V[k]) << endl;
232 // Relative orthogonality with the previous blocks
233 for (int j = 0; j < k; ++j) {
234 debugOut << " ||< V[" << j << "], V[" << k << "] >|| = "
235 << orthoMan->orthogError(*V[j], *V[k]) << endl;
236 }
237 }
238 }
239
240 // Run the benchmark for numTrials trials. Time all trials as
241 // a single run.
242 {
244
245 for (int trial = 0; trial < numTrials; ++trial) {
246 (void) orthoMan->normalize (*V[0], B);
247 for (int k = 1; k < numBlocks; ++k) {
248 ArrayView<RCP<MV> > V_0k_nonconst = V.view (0, k);
250 Teuchos::av_reinterpret_cast<RCP<const MV> > (V_0k_nonconst);
251 (void) orthoMan->projectAndNormalize (*V[k], C, B, V_0k);
252 }
253 }
254 }
255
256 // Report timing results.
258 {
259 // The "compact" format is suitable for automatic parsing,
260 // using a CSV (Comma-Delimited Values) parser. The first
261 // "comment" line may be parsed to extract column
262 // ("field") labels; the second line contains the actual
263 // data, in ASCII comma-delimited format.
264 using std::endl;
265 resultStream << "#orthoManName"
266 << ",normalization"
267 << ",numRows"
268 << ",numCols"
269 << ",numBlocks"
270 << ",firstRunTimeInSeconds"
271 << ",timeInSeconds"
272 << ",numTrials"
273 << endl;
275 << "," << (orthoManName=="Simple" ? normalization : "N/A")
276 << "," << MVT::GetGlobalLength(*X)
277 << "," << numCols
278 << "," << numBlocks
279 << "," << firstRunTimer->totalElapsedTime()
280 << "," << timer->totalElapsedTime()
281 << "," << numTrials
282 << endl;
283 }
284 else {
285 TimeMonitor::summarize (resultStream);
286 }
287 }
288 };
289
293 template<class Scalar, class MV, class DM>
295 private:
296 typedef typename Teuchos::Array<Teuchos::RCP<MV> >::size_type size_type;
297
298 public:
300 typedef Teuchos::ScalarTraits<scalar_type> SCT;
301 typedef typename SCT::magnitudeType magnitude_type;
302 typedef Teuchos::ScalarTraits<magnitude_type> SMT;
305
322 static int
324 const bool isRankRevealing,
325 const Teuchos::RCP<MV>& S,
326 const int sizeX1,
327 const int sizeX2,
328 const Teuchos::RCP<OutputManager<Scalar> >& MyOM)
329 {
330 using Teuchos::Array;
331 using Teuchos::null;
332 using Teuchos::RCP;
333 using Teuchos::rcp;
334 using Teuchos::rcp_dynamic_cast;
335 using Teuchos::tuple;
336
337 // Number of tests that have failed thus far.
338 int numFailed = 0;
339
340 // Relative tolerance against which all tests are performed.
341 const magnitude_type TOL = 1.0e-12;
342 // Absolute tolerance constant
343 //const magnitude_type ATOL = 10;
344
345 const scalar_type ZERO = SCT::zero();
346 const scalar_type ONE = SCT::one();
347
348 // Debug output stream
349 std::ostream& debugOut = MyOM->stream(Debug);
350
351 // Number of columns in the input "prototype" multivector S.
352 const int sizeS = MVT::GetNumberVecs (*S);
353
354 // Create multivectors X1 and X2, using the same map as multivector
355 // S. Then, test orthogonalizing X2 against X1. After doing so, X1
356 // and X2 should each be M-orthonormal, and should be mutually
357 // M-orthogonal.
358 debugOut << "Generating X1,X2 for testing... ";
359 RCP< MV > X1 = MVT::Clone (*S, sizeX1);
360 RCP< MV > X2 = MVT::Clone (*S, sizeX2);
361 debugOut << "done." << endl;
362 {
364
365 //
366 // Fill X1 with random values, and test the normalization error.
367 //
368 debugOut << "Filling X1 with random values... ";
369 MVT::MvRandom(*X1);
370 debugOut << "done." << endl
371 << "Calling normalize() on X1... ";
372 // The Anasazi and Belos OrthoManager interfaces differ.
373 // For example, Anasazi's normalize() method accepts either
374 // one or two arguments, whereas Belos' normalize() requires
375 // two arguments.
376 const int initialX1Rank = OM->normalize(*X1, Teuchos::null);
378 std::runtime_error,
379 "normalize(X1) returned rank "
380 << initialX1Rank << " from " << sizeX1
381 << " vectors. Cannot continue.");
382 debugOut << "done." << endl
383 << "Calling orthonormError() on X1... ";
384 err = OM->orthonormError(*X1);
385 TEUCHOS_TEST_FOR_EXCEPTION(err > TOL, std::runtime_error,
386 "After normalize(X1), orthonormError(X1) = "
387 << err << " > TOL = " << TOL);
388 debugOut << "done: ||<X1,X1> - I|| = " << err << endl;
389
390 //
391 // Fill X2 with random values, project against X1 and normalize,
392 // and test the orthogonalization error.
393 //
394 debugOut << "Filling X2 with random values... ";
395 MVT::MvRandom(*X2);
396 debugOut << "done." << endl
397 << "Calling projectAndNormalize(X2, C, B, tuple(X1))... "
398 << std::flush;
399 int initialX2Rank;
400 {
401 Array<RCP<DM> > C (1);
402 RCP<DM> B = Teuchos::null;
404 OM->projectAndNormalize (*X2, C, B, tuple<RCP<const MV> >(X1));
405 }
407 std::runtime_error,
408 "projectAndNormalize(X2,X1) returned rank "
409 << initialX2Rank << " from " << sizeX2
410 << " vectors. Cannot continue.");
411 debugOut << "done." << endl
412 << "Calling orthonormError() on X2... ";
413 err = OM->orthonormError (*X2);
415 std::runtime_error,
416 "projectAndNormalize(X2,X1) did not meet tolerance: "
417 "orthonormError(X2) = " << err << " > TOL = " << TOL);
418 debugOut << "done: || <X2,X2> - I || = " << err << endl
419 << "Calling orthogError(X2, X1)... ";
420 err = OM->orthogError (*X2, *X1);
422 std::runtime_error,
423 "projectAndNormalize(X2,X1) did not meet tolerance: "
424 "orthogError(X2,X1) = " << err << " > TOL = " << TOL);
425 debugOut << "done: || <X2,X1> || = " << err << endl;
426 }
427
428#ifdef HAVE_BELOS_TSQR
429 //
430 // If OM is an OutOfPlaceNormalizerMixin, exercise the
431 // out-of-place normalization routines.
432 //
435 if (! tsqr.is_null())
436 {
438 debugOut << endl
439 << "=== OutOfPlaceNormalizerMixin tests ==="
440 << endl << endl;
441 //
442 // Fill X1_in with random values, and test the normalization
443 // error with normalizeOutOfPlace().
444 //
445 // Don't overwrite X1, else you'll mess up the tests that
446 // follow!
447 //
448 RCP<MV> X1_in = MVT::CloneCopy (*X1);
449 debugOut << "Filling X1_in with random values... ";
450 MVT::MvRandom(*X1_in);
451 debugOut << "done." << endl;
452 debugOut << "Filling X1_out with different random values...";
453 RCP<MV> X1_out = MVT::Clone(*X1_in, MVT::GetNumberVecs(*X1_in));
454 MVT::MvRandom(*X1_out);
455 debugOut << "done." << endl
456 << "Calling normalizeOutOfPlace(*X1_in, *X1_out, null)... ";
457 const int initialX1Rank =
458 tsqr->normalizeOutOfPlace(*X1_in, *X1_out, Teuchos::null);
459 TEUCHOS_TEST_FOR_EXCEPTION(initialX1Rank != sizeX1, std::runtime_error,
460 "normalizeOutOfPlace(*X1_in, *X1_out, null) "
461 "returned rank " << initialX1Rank << " from "
462 << sizeX1 << " vectors. Cannot continue.");
463 debugOut << "done." << endl
464 << "Calling orthonormError() on X1_out... ";
465 err = OM->orthonormError(*X1_out);
466 TEUCHOS_TEST_FOR_EXCEPTION(err > TOL, std::runtime_error,
467 "After calling normalizeOutOfPlace(*X1_in, "
468 "*X1_out, null), orthonormError(X1) = "
469 << err << " > TOL = " << TOL);
470 debugOut << "done: ||<X1_out,X1_out> - I|| = " << err << endl;
471
472 //
473 // Fill X2_in with random values, project against X1_out
474 // and normalize via projectAndNormalizeOutOfPlace(), and
475 // test the orthogonalization error.
476 //
477 // Don't overwrite X2, else you'll mess up the tests that
478 // follow!
479 //
480 RCP<MV> X2_in = MVT::CloneCopy (*X2);
481 debugOut << "Filling X2_in with random values... ";
482 MVT::MvRandom(*X2_in);
483 debugOut << "done." << endl
484 << "Filling X2_out with different random values...";
485 RCP<MV> X2_out = MVT::Clone(*X2_in, MVT::GetNumberVecs(*X2_in));
486 MVT::MvRandom(*X2_out);
487 debugOut << "done." << endl
488 << "Calling projectAndNormalizeOutOfPlace(X2_in, X2_out, "
489 << "C, B, X1_out)...";
490 int initialX2Rank;
491 {
492 Array<RCP<DM> > C (1);
493 RCP<DM> B = Teuchos::null;
495 tsqr->projectAndNormalizeOutOfPlace (*X2_in, *X2_out, C, B,
497 }
499 std::runtime_error,
500 "projectAndNormalizeOutOfPlace(*X2_in, "
501 "*X2_out, C, B, tuple(X1_out)) returned rank "
502 << initialX2Rank << " from " << sizeX2
503 << " vectors. Cannot continue.");
504 debugOut << "done." << endl
505 << "Calling orthonormError() on X2_out... ";
506 err = OM->orthonormError (*X2_out);
507 TEUCHOS_TEST_FOR_EXCEPTION(err > TOL, std::runtime_error,
508 "projectAndNormalizeOutOfPlace(*X2_in, *X2_out, "
509 "C, B, tuple(X1_out)) did not meet tolerance: "
510 "orthonormError(X2_out) = "
511 << err << " > TOL = " << TOL);
512 debugOut << "done: || <X2_out,X2_out> - I || = " << err << endl
513 << "Calling orthogError(X2_out, X1_out)... ";
514 err = OM->orthogError (*X2_out, *X1_out);
515 TEUCHOS_TEST_FOR_EXCEPTION(err > TOL, std::runtime_error,
516 "projectAndNormalizeOutOfPlace(*X2_in, *X2_out, "
517 "C, B, tuple(X1_out)) did not meet tolerance: "
518 "orthogError(X2_out, X1_out) = "
519 << err << " > TOL = " << TOL);
520 debugOut << "done: || <X2_out,X1_out> || = " << err << endl;
521 debugOut << endl
522 << "=== Done with OutOfPlaceNormalizerMixin tests ==="
523 << endl << endl;
524 }
525#endif // HAVE_BELOS_TSQR
526
527 {
528 //
529 // Test project() on a random multivector S, by projecting S
530 // against various combinations of X1 and X2.
531 //
532 MVT::MvRandom(*S);
533
534 debugOut << "Testing project() by projecting a random multivector S "
535 "against various combinations of X1 and X2 " << endl;
536 const int thisNumFailed = testProject(OM,S,X1,X2,MyOM);
538 if (thisNumFailed > 0)
539 debugOut << " *** " << thisNumFailed
540 << (thisNumFailed > 1 ? " tests" : " test")
541 << " failed." << endl;
542 }
543
544 {
545 //
546 // Test normalize() for various deficient cases
547 //
548 debugOut << "Testing normalize() on bad multivectors " << endl;
549 const int thisNumFailed = testNormalize(OM,S,MyOM);
551 }
552
553 if (isRankRevealing)
554 {
555 // run a X1,Y2 range multivector against P_{X1,X1} P_{Y2,Y2}
556 // note, this is allowed under the restrictions on project(),
557 // because <X1,Y2> = 0
558 // also, <Y2,Y2> = I, but <X1,X1> != I, so biOrtho must be set to false
559 // it should require randomization, as
560 // P_{X1,X1} P_{Y2,Y2} (X1*C1 + Y2*C2) = P_{X1,X1} X1*C1 = 0
561 RCP<DM> C1 = DMT::Create(sizeX1,sizeS), C2 = DMT::Create(sizeX2,sizeS);
564 // S := X1*C1
565 MVT::MvTimesMatAddMv(ONE,*X1,*C1,ZERO,*S);
566 // S := S + X2*C2
567 MVT::MvTimesMatAddMv(ONE,*X2,*C2,ONE,*S);
568
569 debugOut << "Testing project() by projecting [X1 X2]-range multivector "
570 "against P_X1 P_X2 " << endl;
571 const int thisNumFailed = testProject(OM,S,X1,X2,MyOM);
573 if (thisNumFailed > 0)
574 debugOut << " *** " << thisNumFailed
575 << (thisNumFailed > 1 ? " tests" : " test")
576 << " failed." << endl;
577 }
578
579 // This test is only distinct from the rank-1 multivector test
580 // (below) if S has at least 3 columns.
581 if (isRankRevealing && sizeS > 2)
582 {
583 MVT::MvRandom(*S);
584 RCP<MV> mid = MVT::Clone(*S,1);
585 RCP<DM> c = DMT::Create(sizeS,1);
586 MVT::MvTimesMatAddMv(ONE,*S,*c,ZERO,*mid);
587 std::vector<int> ind(1);
588 ind[0] = sizeS-1;
589 MVT::SetBlock(*mid,ind,*S);
590
591 debugOut << "Testing normalize() on a rank-deficient multivector " << endl;
592 const int thisNumFailed = testNormalizeRankReveal(OM,S,MyOM);
594 if (thisNumFailed > 0)
595 debugOut << " *** " << thisNumFailed
596 << (thisNumFailed > 1 ? " tests" : " test")
597 << " failed." << endl;
598 }
599
600 // This test will only exercise rank deficiency if S has at least 2
601 // columns.
602 if (isRankRevealing && sizeS > 1)
603 {
604 // rank-1
605 RCP<MV> one = MVT::Clone(*S,1);
606 MVT::MvRandom(*one);
607 RCP<DM> scaleS = DMT::Create(sizeS,1);
609 // put multiple of column 0 in columns 0:sizeS-1
610 for (int i=0; i<sizeS; i++)
611 {
612 std::vector<int> ind(1);
613 ind[0] = i;
614 RCP<MV> Si = MVT::CloneViewNonConst(*S,ind);
615 MVT::MvAddMv(DMT::ValueConst(*scaleS,i,0),*one,ZERO,*one,*Si);
616 }
617 debugOut << "Testing normalize() on a rank-1 multivector " << endl;
618 const int thisNumFailed = testNormalizeRankReveal(OM,S,MyOM);
620 if (thisNumFailed > 0)
621 debugOut << " *** " << thisNumFailed
622 << (thisNumFailed > 1 ? " tests" : " test")
623 << " failed." << endl;
624 }
625
626 {
627 std::vector<int> ind(1);
628 MVT::MvRandom(*S);
629
630 debugOut << "Testing projectAndNormalize() on a random multivector " << endl;
631 const int thisNumFailed = testProjectAndNormalize(OM,S,X1,X2,MyOM);
633 if (thisNumFailed > 0)
634 debugOut << " *** " << thisNumFailed
635 << (thisNumFailed > 1 ? " tests" : " test")
636 << " failed." << endl;
637 }
638
639 if (isRankRevealing)
640 {
641 // run a X1,X2 range multivector against P_X1 P_X2
642 // this is allowed as <X1,X2> == 0
643 // it should require randomization, as
644 // P_X1 P_X2 (X1*C1 + X2*C2) = P_X1 X1*C1 = 0
645 // and
646 // P_X2 P_X1 (X2*C2 + X1*C1) = P_X2 X2*C2 = 0
647 RCP<DM> C1 = DMT::Create(sizeX1,sizeS), C2 = DMT::Create(sizeX2,sizeS);
650 MVT::MvTimesMatAddMv(ONE,*X1,*C1,ZERO,*S);
651 MVT::MvTimesMatAddMv(ONE,*X2,*C2,ONE,*S);
652
653 debugOut << "Testing projectAndNormalize() by projecting [X1 X2]-range "
654 "multivector against P_X1 P_X2 " << endl;
655 const int thisNumFailed = testProjectAndNormalize(OM,S,X1,X2,MyOM);
657 if (thisNumFailed > 0)
658 debugOut << " *** " << thisNumFailed
659 << (thisNumFailed > 1 ? " tests" : " test")
660 << " failed." << endl;
661 }
662
663 // This test is only distinct from the rank-1 multivector test
664 // (below) if S has at least 3 columns.
665 if (isRankRevealing && sizeS > 2)
666 {
667 MVT::MvRandom(*S);
668 RCP<MV> mid = MVT::Clone(*S,1);
669 RCP<DM> c = DMT::Create(sizeS,1);
670 MVT::MvTimesMatAddMv(ONE,*S,*c,ZERO,*mid);
671 std::vector<int> ind(1);
672 ind[0] = sizeS-1;
673 MVT::SetBlock(*mid,ind,*S);
674
675 debugOut << "Testing projectAndNormalize() on a rank-deficient "
676 "multivector " << endl;
677 const int thisNumFailed = testProjectAndNormalize(OM,S,X1,X2,MyOM);
679 if (thisNumFailed > 0)
680 debugOut << " *** " << thisNumFailed
681 << (thisNumFailed > 1 ? " tests" : " test")
682 << " failed." << endl;
683 }
684
685 // This test will only exercise rank deficiency if S has at least 2
686 // columns.
687 if (isRankRevealing && sizeS > 1)
688 {
689 // rank-1
690 RCP<MV> one = MVT::Clone(*S,1);
691 MVT::MvRandom(*one);
692 RCP<DM> scaleS = DMT::Create(sizeS,1);
694 // Put a multiple of column 0 in columns 0:sizeS-1.
695 for (int i=0; i<sizeS; i++)
696 {
697 std::vector<int> ind(1);
698 ind[0] = i;
699 RCP<MV> Si = MVT::CloneViewNonConst(*S,ind);
700 MVT::MvAddMv(DMT::ValueConst(*scaleS,i,0),*one,ZERO,*one,*Si);
701 }
702 debugOut << "Testing projectAndNormalize() on a rank-1 multivector " << endl;
703 bool constantStride = true;
704 if (! MVT::HasConstantStride(*S)) {
705 debugOut << "-- S does not have constant stride" << endl;
706 constantStride = false;
707 }
708 if (! MVT::HasConstantStride(*X1)) {
709 debugOut << "-- X1 does not have constant stride" << endl;
710 constantStride = false;
711 }
712 if (! MVT::HasConstantStride(*X2)) {
713 debugOut << "-- X2 does not have constant stride" << endl;
714 constantStride = false;
715 }
716 if (! constantStride) {
717 debugOut << "-- Skipping this test, since TSQR does not work on "
718 "multivectors with nonconstant stride" << endl;
719 }
720 else {
721 const int thisNumFailed = testProjectAndNormalize(OM,S,X1,X2,MyOM);
723 if (thisNumFailed > 0) {
724 debugOut << " *** " << thisNumFailed
725 << (thisNumFailed > 1 ? " tests" : " test")
726 << " failed." << endl;
727 }
728 }
729 }
730
731 if (numFailed != 0) {
732 MyOM->stream(Errors) << numFailed << " total test failures." << endl;
733 }
734 return numFailed;
735 }
736
737 private:
738
743 static magnitude_type
744 MVDiff (const MV& X, const MV& Y)
745 {
746 using Teuchos::RCP;
747
748 const scalar_type ONE = SCT::one();
749 const int numCols = MVT::GetNumberVecs(X);
750 TEUCHOS_TEST_FOR_EXCEPTION( (MVT::GetNumberVecs(Y) != numCols),
751 std::logic_error,
752 "MVDiff: X and Y should have the same number of columns."
753 " X has " << numCols << " column(s) and Y has "
754 << MVT::GetNumberVecs(Y) << " columns." );
755 // Resid := X
756 RCP< MV > Resid = MVT::CloneCopy(X);
757 // Resid := Resid - Y
758 MVT::MvAddMv (-ONE, Y, ONE, *Resid, *Resid);
759
760 return frobeniusNorm (*Resid);
761 }
762
763
767 static magnitude_type
768 frobeniusNorm (const MV& X)
769 {
770 using Teuchos::RCP;
771
772 const scalar_type ONE = SCT::one();
773 const int numCols = MVT::GetNumberVecs(X);
774 RCP<DM> C = DMT::Create(numCols, numCols);
775
776 // $C := X^* X$
777 MVT::MvTransMv (ONE, X, X, *C);
778 DMT::SyncDeviceToHost( *C );
779
781 for (int i = 0; i < numCols; ++i)
782 err += SCT::magnitude (DMT::ValueConst(*C,i,i));
783
784 return SCT::magnitude (SCT::squareroot (err));
785 }
786
787
788 static int
789 testProjectAndNormalize (const Teuchos::RCP< Belos::OrthoManager< Scalar, MV, DM > > OM,
790 const Teuchos::RCP< const MV >& S,
791 const Teuchos::RCP< const MV >& X1,
792 const Teuchos::RCP< const MV >& X2,
793 const Teuchos::RCP< Belos::OutputManager< Scalar > >& MyOM)
794 {
795 return testProjectAndNormalizeNew (OM, S, X1, X2, MyOM);
796 }
797
802 static int
803 testProjectAndNormalizeOld (const Teuchos::RCP< Belos::OrthoManager< Scalar, MV, DM > >& OM,
804 const Teuchos::RCP< const MV >& S,
805 const Teuchos::RCP< const MV >& X1,
806 const Teuchos::RCP< const MV >& X2,
807 const Teuchos::RCP< Belos::OutputManager< Scalar > >& MyOM)
808 {
809 using Teuchos::Array;
810 using Teuchos::null;
811 using Teuchos::RCP;
812 using Teuchos::rcp;
813 using Teuchos::tuple;
814
815 const scalar_type ONE = SCT::one();
816 const magnitude_type ZERO = SCT::magnitude(SCT::zero());
817
818 // Relative tolerance against which all tests are performed.
819 const magnitude_type TOL = 1.0e-12;
820 // Absolute tolerance constant
821 const magnitude_type ATOL = 10;
822
823 const int sizeS = MVT::GetNumberVecs(*S);
824 const int sizeX1 = MVT::GetNumberVecs(*X1);
825 const int sizeX2 = MVT::GetNumberVecs(*X2);
826 int numerr = 0;
827 std::ostringstream sout;
828
829 //
830 // output tests:
831 // <S_out,S_out> = I
832 // <S_out,X1> = 0
833 // <S_out,X2> = 0
834 // S_in = S_out B + X1 C1 + X2 C2
835 //
836 // we will loop over an integer specifying the test combinations
837 // the bit pattern for the different tests is listed in parenthesis
838 //
839 // for the projectors, test the following combinations:
840 // none (00)
841 // P_X1 (01)
842 // P_X2 (10)
843 // P_X1 P_X2 (11)
844 // P_X2 P_X1 (11)
845 // the latter two should be tested to give the same answer
846 //
847 // for each of these, we should test with C1, C2 and B
848 //
849 // if hasM:
850 // with and without MX1 (1--)
851 // with and without MX2 (1---)
852 // with and without MS (1----)
853 //
854 // as hasM controls the upper level bits, we need only run test cases 0-3 if hasM==false
855 // otherwise, we run test cases 0-31
856 //
857
858 int numtests = 4;
859
860 // test ortho error before orthonormalizing
861 if (X1 != null) {
862 magnitude_type err = OM->orthogError(*S,*X1);
863 sout << " || <S,X1> || before : " << err << endl;
864 }
865 if (X2 != null) {
866 magnitude_type err = OM->orthogError(*S,*X2);
867 sout << " || <S,X2> || before : " << err << endl;
868 }
869
870 for (int t=0; t<numtests; t++) {
871
872 Array< RCP< const MV > > theX;
873 RCP<DM> B = DMT::Create( sizeS,sizeS );
874 Array<RCP< DM > > C;
875 if ( (t % 3) == 0 ) {
876 // neither <X1,Y1> nor <X2,Y2>
877 // C, theX and theY are already empty
878 }
879 else if ( (t % 3) == 1 ) {
880 // X1
881 theX = tuple(X1);
882 C = tuple( DMT::Create(sizeX1,sizeS) );
883 }
884 else if ( (t % 3) == 2 ) {
885 // X2
886 theX = tuple(X2);
887 C = tuple( DMT::Create(sizeX2,sizeS) );
888 }
889 else {
890 // X1 and X2, and the reverse.
891 theX = tuple(X1,X2);
892 C = tuple( DMT::Create(sizeX1,sizeS),
893 DMT::Create(sizeX2,sizeS) );
894 }
895
896 // We wrap up all the OrthoManager calls in a try-catch
897 // block, in order to check whether any of the methods throw
898 // an exception. For the tests we perform, every thrown
899 // exception is a failure.
900 try {
901 // call routine
902 // if (t && 3) == 3, {
903 // call with reversed input: X2 X1
904 // }
905 // test all outputs for correctness
906 // test all outputs for equivalence
907
908 // here is where the outputs go
909 Array<RCP<MV> > S_outs;
910 Array<Array<RCP<DM > > > C_outs;
911 Array<RCP<DM > > B_outs;
912 RCP<MV> Scopy;
913 Array<int> ret_out;
914
915 // copies of S,MS
916 Scopy = MVT::CloneCopy(*S);
917 // randomize this data, it should be overwritten
918 RandomSyncedMpiMatrix<Scalar,DM>(*B);
919 for (size_type i=0; i<C.size(); i++) {
920 RandomSyncedMpiMatrix<Scalar,DM>(*C[i]);
921 }
922 // Run test. Since S was specified by the caller and
923 // Scopy is a copy of S, we don't know what rank to expect
924 // here -- though we do require that S have rank at least
925 // one.
926 //
927 // Note that Anasazi and Belos differ, among other places,
928 // in the order of arguments to projectAndNormalize().
929 int ret = OM->projectAndNormalize(*Scopy,C,B,theX);
930 sout << "projectAndNormalize() returned rank " << ret << endl;
931 if (ret == 0) {
932 sout << " *** Error: returned rank is zero, cannot continue tests" << endl;
933 numerr++;
934 break;
935 }
936 ret_out.push_back(ret);
937 // projectAndNormalize() is only required to return a
938 // basis of rank "ret"
939 // this is what we will test:
940 // the first "ret" columns in Scopy
941 // the first "ret" rows in B
942 // save just the parts that we want
943 // we allocate S and MS for each test, so we can save these as views
944 // however, save copies of the C and B
945 if (ret < sizeS) {
946 std::vector<int> ind(ret);
947 for (int i=0; i<ret; i++) {
948 ind[i] = i;
949 }
950 S_outs.push_back( MVT::CloneViewNonConst(*Scopy,ind) );
951 B_outs.push_back( DMT::SubviewCopy(*B,ret,sizeS) );
952 }
953 else {
954 S_outs.push_back( Scopy );
955 B_outs.push_back( DMT::CreateCopy( *B ) );
956 }
957 C_outs.push_back( Array<RCP<DM> >(0) );
958 if (C.size() > 0) {
959 C_outs.back().push_back( DMT::CreateCopy( *C[0] ) );
960 }
961 if (C.size() > 1) {
962 C_outs.back().push_back( DMT::CreateCopy( *C[1]) );
963 }
964
965 // do we run the reversed input?
966 if ( (t % 3) == 3 ) {
967 // copies of S,MS
968 Scopy = MVT::CloneCopy(*S);
969
970 // Fill the B and C[i] matrices with random data. The
971 // data will be overwritten by projectAndNormalize().
972 // Filling these matrices here is only to catch some
973 // bugs in projectAndNormalize().
974 RandomSyncedMpiMatrix<Scalar,DM>(*B);
975 for (size_type i=0; i<C.size(); i++) {
976 RandomSyncedMpiMatrix<Scalar,DM>(*C[i]);
977 }
978 // flip the inputs
979 theX = tuple( theX[1], theX[0] );
980 // Run test.
981 // Note that Anasazi and Belos differ, among other places,
982 // in the order of arguments to projectAndNormalize().
983 ret = OM->projectAndNormalize(*Scopy,C,B,theX);
984 sout << "projectAndNormalize() returned rank " << ret << endl;
985 if (ret == 0) {
986 sout << " *** Error: returned rank is zero, cannot continue tests" << endl;
987 numerr++;
988 break;
989 }
990 ret_out.push_back(ret);
991 // projectAndNormalize() is only required to return a
992 // basis of rank "ret"
993 // this is what we will test:
994 // the first "ret" columns in Scopy
995 // the first "ret" rows in B
996 // save just the parts that we want
997 // we allocate S and MS for each test, so we can save these as views
998 // however, save copies of the C and B
999 if (ret < sizeS) {
1000 std::vector<int> ind(ret);
1001 for (int i=0; i<ret; i++) {
1002 ind[i] = i;
1003 }
1004 S_outs.push_back( MVT::CloneViewNonConst(*Scopy,ind) );
1005 B_outs.push_back( DMT::SubviewCopy( *B,ret,sizeS) );
1006 }
1007 else {
1008 S_outs.push_back( Scopy );
1009 B_outs.push_back( DMT::CreateCopy( *B ) );
1010 }
1011 C_outs.push_back( Array<RCP<DM> >() );
1012 // reverse the Cs to compensate for the reverse projectors
1013 C_outs.back().push_back( DMT::CreateCopy(*C[1]) );
1014 C_outs.back().push_back( DMT::CreateCopy(*C[0]) );
1015 // flip the inputs back
1016 theX = tuple( theX[1], theX[0] );
1017 }
1018
1019
1020 // test all outputs for correctness
1021 for (size_type o=0; o<S_outs.size(); o++) {
1022 // S^T M S == I
1023 {
1024 magnitude_type err = OM->orthonormError(*S_outs[o]);
1025 if (err > TOL) {
1026 sout << endl
1027 << " *** Test (number " << (t+1) << " of " << numtests
1028 << " total tests) failed: Tolerance exceeded! Error = "
1029 << err << " > TOL = " << TOL << "."
1030 << endl << endl;
1031 numerr++;
1032 }
1033 sout << " || <S,S> - I || after : " << err << endl;
1034 }
1035 // S_in = X1*C1 + C2*C2 + S_out*B
1036 {
1037 RCP<MV> tmp = MVT::Clone(*S,sizeS);
1038 MVT::MvTimesMatAddMv(ONE,*S_outs[o],*B_outs[o],ZERO,*tmp);
1039 if (C_outs[o].size() > 0) {
1040 MVT::MvTimesMatAddMv(ONE,*X1,*C_outs[o][0],ONE,*tmp);
1041 if (C_outs[o].size() > 1) {
1042 MVT::MvTimesMatAddMv(ONE,*X2,*C_outs[o][1],ONE,*tmp);
1043 }
1044 }
1045 magnitude_type err = MVDiff(*tmp,*S);
1046 if (err > ATOL*TOL) {
1047 sout << endl
1048 << " *** Test (number " << (t+1) << " of " << numtests
1049 << " total tests) failed: Tolerance exceeded! Error = "
1050 << err << " > ATOL*TOL = " << (ATOL*TOL) << "."
1051 << endl << endl;
1052 numerr++;
1053 }
1054 sout << " " << t << "|| S_in - X1*C1 - X2*C2 - S_out*B || : " << err << endl;
1055 }
1056 // <X1,S> == 0
1057 if (theX.size() > 0 && theX[0] != null) {
1058 magnitude_type err = OM->orthogError(*theX[0],*S_outs[o]);
1059 if (err > TOL) {
1060 sout << endl
1061 << " *** Test (number " << (t+1) << " of " << numtests
1062 << " total tests) failed: Tolerance exceeded! Error = "
1063 << err << " > TOL = " << TOL << "."
1064 << endl << endl;
1065 numerr++;
1066 }
1067 sout << " " << t << "|| <X[0],S> || after : " << err << endl;
1068 }
1069 // <X2,S> == 0
1070 if (theX.size() > 1 && theX[1] != null) {
1071 magnitude_type err = OM->orthogError(*theX[1],*S_outs[o]);
1072 if (err > TOL) {
1073 sout << endl
1074 << " *** Test (number " << (t+1) << " of " << numtests
1075 << " total tests) failed: Tolerance exceeded! Error = "
1076 << err << " > TOL = " << TOL << "."
1077 << endl << endl;
1078 numerr++;
1079 }
1080 sout << " " << t << "|| <X[1],S> || after : " << err << endl;
1081 }
1082 }
1083 }
1084 catch (Belos::OrthoError& e) {
1085 sout << " *** Error: OrthoManager threw exception: " << e.what() << endl;
1086 numerr++;
1087 }
1088
1089 } // test for
1090
1091 // NOTE (mfh 05 Nov 2010) Since Belos::MsgType is an enum,
1092 // doing bitwise logical computations on Belos::MsgType values
1093 // (such as "Debug | Errors") and passing the result into
1094 // MyOM->stream() confuses the compiler. As a result, we have
1095 // to do some type casts to make it work.
1096 const int msgType = (numerr > 0) ?
1097 (static_cast<int>(Debug) | static_cast<int>(Errors)) :
1098 static_cast<int>(Debug);
1099
1100 // We report debug-level messages always. We also report
1101 // errors if at least one test failed.
1102 MyOM->stream(static_cast< MsgType >(msgType)) << sout.str() << endl;
1103 return numerr;
1104 }
1105
1110 static int
1111 testNormalize (const Teuchos::RCP< Belos::OrthoManager< Scalar, MV, DM > >& OM,
1112 const Teuchos::RCP< const MV >& S,
1113 const Teuchos::RCP< Belos::OutputManager< Scalar > >& MyOM)
1114 {
1115 using Teuchos::RCP;
1116
1117 int numFailures = 0;
1118 const scalar_type ZERO = SCT::zero();
1119
1120 const int msgType = (static_cast<int>(Debug) | static_cast<int>(Errors));
1121
1122 // Check that the orthogonalization gracefully handles zero vectors.
1123 RCP<MV> zeroVec = MVT::Clone(*S,1);
1124 RCP<DM> bZero = DMT::Create(1,1);
1125 std::vector< magnitude_type > zeroNorm( 1 );
1126
1127 MVT::MvInit( *zeroVec, ZERO );
1128 OM->normalize( *zeroVec, bZero );
1129 MVT::MvNorm( *zeroVec, zeroNorm );
1130 // Check if the number is a NaN, this orthogonalization fails if it is.
1131 if ( zeroNorm[0] != ZERO )
1132 {
1133 MyOM->stream(static_cast< MsgType >(msgType)) << " --> Normalization of zero vector FAILED!" << std::endl;
1134 numFailures++;
1135 }
1136
1137 return numFailures;
1138 }
1139
1144 static int
1145 testNormalizeRankReveal (const Teuchos::RCP< Belos::OrthoManager< Scalar, MV, DM > >& OM,
1146 const Teuchos::RCP< const MV >& S,
1147 const Teuchos::RCP< Belos::OutputManager< Scalar > >& MyOM)
1148 {
1149 using Teuchos::Array;
1150 using Teuchos::RCP;
1151 using Teuchos::rcp;
1152 using Teuchos::tuple;
1153
1154 const scalar_type ONE = SCT::one();
1155 std::ostringstream sout;
1156 // Total number of failed tests in this call of this routine.
1157 int numerr = 0;
1158
1159 // Relative tolerance against which all tests are performed.
1160 // We are measuring things in the Frobenius norm $\| \cdot \|_F$.
1161 // The following bounds hold for all $m \times n$ matrices $A$:
1162 // \[
1163 // \|A\|_2 \leq \|A\|_F \leq \sqrt{r} \|A\|_2,
1164 // \]
1165 // where $r$ is the (column) rank of $A$. We bound this above
1166 // by the number of columns in $A$.
1167 //
1168 // An accurate normalization in the Euclidean norm of a matrix
1169 // $A$ with at least as many rows m as columns n, should
1170 // produce orthogonality $\|Q^* Q - I\|_2$ less than a factor
1171 // of machine precision times a low-order polynomial in m and
1172 // n, and residual $\|A - Q B\|_2$ (where $A = Q B$ is the
1173 // computed normalization) less than that bound times the norm
1174 // of $A$.
1175 //
1176 // Since we are measuring both of these quantitites in the
1177 // Frobenius norm instead, we should scale this bound by
1178 // $\sqrt{n}$.
1179
1180 const int numRows = MVT::GetGlobalLength(*S);
1181 const int numCols = MVT::GetNumberVecs(*S);
1182 const int sizeS = MVT::GetNumberVecs(*S);
1183
1184 // A good heuristic is to scale the bound by the square root
1185 // of the number of floating-point operations. One could
1186 // perhaps support this theoretically, since we are using
1187 // uniform random test problems.
1188 const magnitude_type fudgeFactor =
1189 SMT::squareroot(magnitude_type(numRows) *
1190 magnitude_type(numCols) *
1191 magnitude_type(numCols));
1192 const magnitude_type TOL = SMT::eps() * fudgeFactor *
1193 SMT::squareroot(magnitude_type(numCols));
1194
1195 // Absolute tolerance scaling: the Frobenius norm of the test
1196 // matrix S. TOL*ATOL is the absolute tolerance for the
1197 // residual $\|A - Q*B\|_F$.
1198 const magnitude_type ATOL = frobeniusNorm (*S);
1199
1200 sout << "The test matrix S has Frobenius norm " << ATOL
1201 << ", and the relative error tolerance is TOL = "
1202 << TOL << "." << endl;
1203
1204 const int numtests = 1;
1205 for (int t = 0; t < numtests; ++t) {
1206
1207 try {
1208 // call routine
1209 // test all outputs for correctness
1210
1211 // S_copy gets a copy of S; we normalize in place, so we
1212 // need a copy to check whether the normalization
1213 // succeeded.
1214 RCP< MV > S_copy = MVT::CloneCopy (*S);
1215
1216 // Matrix of coefficients from the normalization.
1217 RCP< DM > B = DMT::Create(sizeS, sizeS);
1218 // The contents of B will be overwritten, but fill with
1219 // random data just to make sure that the normalization
1220 // operated on all the elements of B on which it should
1221 // operate.
1222 RandomSyncedMpiMatrix<Scalar,DM>(*B);
1223
1224 const int reportedRank = OM->normalize (*S_copy, B);
1225 sout << "normalize() returned rank " << reportedRank << endl;
1226 if (reportedRank == 0) {
1227 sout << " *** Error: Cannot continue, since normalize() "
1228 "reports that S has rank 0" << endl;
1229 numerr++;
1230 break;
1231 }
1232 //
1233 // We don't know in this routine whether the input
1234 // multivector S has full rank; it is only required to
1235 // have nonzero rank. Thus, we extract the first
1236 // reportedRank columns of S_copy and the first
1237 // reportedRank rows of B, and perform tests on them.
1238 //
1239
1240 // Construct S_view, a view of the first reportedRank
1241 // columns of S_copy.
1242 std::vector<int> indices (reportedRank);
1243 for (int j = 0; j < reportedRank; ++j)
1244 indices[j] = j;
1245 RCP< MV > S_view = MVT::CloneViewNonConst (*S_copy, indices);
1246 // Construct B_top, a copy of the first reportedRank rows
1247 // of B.
1248 //
1249 // NOTE: We create this as a copy and not a view, because
1250 // otherwise it would not be safe with respect to RCPs.
1251 RCP< DM > B_top = DMT::SubviewCopy(*B, reportedRank, sizeS);
1252
1253 // Check ||<S_view,S_view> - I||
1254 {
1255 const magnitude_type err = OM->orthonormError(*S_view);
1256 if (err > TOL) {
1257 sout << " *** Error: Tolerance exceeded: err = "
1258 << err << " > TOL = " << TOL << endl;
1259 numerr++;
1260 }
1261 sout << " || <S,S> - I || after : " << err << endl;
1262 }
1263 // Check the residual ||Residual|| = ||S_view * B_top -
1264 // S_orig||, where S_orig is a view of the first
1265 // reportedRank columns of S.
1266 {
1267 // Residual is allocated with reportedRank columns. It
1268 // will contain the result of testing the residual error
1269 // of the normalization (i.e., $\|S - S_in*B\|$). It
1270 // should have the dimensions of S. Its initial value
1271 // is a copy of the first reportedRank columns of S.
1272 RCP< MV > Residual = MVT::CloneCopy (*S);
1273
1274 // Residual := Residual - S_view * B_view
1275 MVT::MvTimesMatAddMv (-ONE, *S_view, *B_top, ONE, *Residual);
1276
1277 // Compute ||Residual||
1278 const magnitude_type err = frobeniusNorm (*Residual);
1279 if (err > ATOL*TOL) {
1280 sout << " *** Error: Tolerance exceeded: err = "
1281 << err << " > ATOL*TOL = " << (ATOL*TOL) << endl;
1282 numerr++;
1283 }
1284 sout << " " << t << "|| S - Q*B || : " << err << endl;
1285 }
1286 }
1287 catch (Belos::OrthoError& e) {
1288 sout << " *** Error: the OrthoManager's normalize() method "
1289 "threw an exception: " << e.what() << endl;
1290 numerr++;
1291 }
1292
1293 } // test for
1294
1295 const MsgType type = (numerr == 0) ? Debug : static_cast<MsgType> (static_cast<int>(Errors) | static_cast<int>(Debug));
1296 MyOM->stream(type) << sout.str();
1297 MyOM->stream(type) << endl;
1298
1299 return numerr;
1300 }
1301
1306 static int
1307 testProjectAndNormalizeNew (const Teuchos::RCP< Belos::OrthoManager< Scalar, MV, DM > > OM,
1308 const Teuchos::RCP< const MV >& S,
1309 const Teuchos::RCP< const MV >& X1,
1310 const Teuchos::RCP< const MV >& X2,
1311 const Teuchos::RCP< Belos::OutputManager< Scalar > >& MyOM)
1312 {
1313 using Teuchos::Array;
1314 using Teuchos::null;
1315 using Teuchos::RCP;
1316 using Teuchos::rcp;
1317 using Teuchos::tuple;
1318
1319 // We collect all the output in this string wrapper, and print
1320 // it at the end.
1321 std::ostringstream sout;
1322 // Total number of failed tests in this call of this routine.
1323 int numerr = 0;
1324
1325 const int numRows = MVT::GetGlobalLength(*S);
1326 const int numCols = MVT::GetNumberVecs(*S);
1327 const int sizeS = MVT::GetNumberVecs(*S);
1328
1329 // Relative tolerance against which all tests are performed.
1330 // We are measuring things in the Frobenius norm $\| \cdot \|_F$.
1331 // The following bounds hold for all $m \times n$ matrices $A$:
1332 // \[
1333 // \|A\|_2 \leq \|A\|_F \leq \sqrt{r} \|A\|_2,
1334 // \]
1335 // where $r$ is the (column) rank of $A$. We bound this above
1336 // by the number of columns in $A$.
1337 //
1338 // Since we are measuring both of these quantitites in the
1339 // Frobenius norm instead, we scale all error tests by
1340 // $\sqrt{n}$.
1341 //
1342 // A good heuristic is to scale the bound by the square root
1343 // of the number of floating-point operations. One could
1344 // perhaps support this theoretically, since we are using
1345 // uniform random test problems.
1346 const magnitude_type fudgeFactor =
1347 SMT::squareroot(magnitude_type(numRows) *
1348 magnitude_type(numCols) *
1349 magnitude_type(numCols));
1350 const magnitude_type TOL = SMT::eps() * fudgeFactor *
1351 SMT::squareroot(magnitude_type(numCols));
1352
1353 // Absolute tolerance scaling: the Frobenius norm of the test
1354 // matrix S. TOL*ATOL is the absolute tolerance for the
1355 // residual $\|A - Q*B\|_F$.
1356 const magnitude_type ATOL = frobeniusNorm (*S);
1357
1358 sout << "-- The test matrix S has Frobenius norm " << ATOL
1359 << ", and the relative error tolerance is TOL = "
1360 << TOL << "." << endl;
1361
1362 // Q will contain the result of projectAndNormalize() on S.
1363 RCP< MV > Q = MVT::CloneCopy(*S);
1364 // We use this for collecting the residual error components
1365 RCP< MV > Residual = MVT::CloneCopy(*S);
1366 // Number of elements in the X array of blocks against which
1367 // to project S.
1368 const int num_X = 2;
1369 Array< RCP< const MV > > X (num_X);
1370 X[0] = MVT::CloneCopy(*X1);
1371 X[1] = MVT::CloneCopy(*X2);
1372
1373 // Coefficients for the normalization
1374 RCP< DM > B = DMT::Create( sizeS, sizeS );
1375
1376 // Array of coefficients matrices from the projection.
1377 // For our first test, we allocate each of these matrices
1378 // with the proper dimensions.
1379 Array< RCP< DM > > C (num_X);
1380 for (int k = 0; k < num_X; ++k)
1381 {
1382 C[k] = DMT::Create( MVT::GetNumberVecs(*X[k]), sizeS );
1383 RandomSyncedMpiMatrix<Scalar,DM>(*C[k]); // will be overwritten
1384 }
1385 try {
1386 // Q*B := (I - X X^*) S
1387 const int reportedRank = OM->projectAndNormalize (*Q, C, B, X);
1388
1389 // Pick out the first reportedRank columns of Q.
1390 std::vector<int> indices (reportedRank);
1391 for (int j = 0; j < reportedRank; ++j)
1392 indices[j] = j;
1393 RCP< const MV > Q_left = MVT::CloneView (*Q, indices);
1394
1395 // Test whether the first reportedRank columns of Q are
1396 // orthogonal.
1397 {
1398 const magnitude_type orthoError = OM->orthonormError (*Q_left);
1399 sout << "-- ||Q(1:" << reportedRank << ")^* Q(1:" << reportedRank
1400 << ") - I||_F = " << orthoError << endl;
1401 if (orthoError > TOL)
1402 {
1403 sout << " *** Error: ||Q(1:" << reportedRank << ")^* Q(1:"
1404 << reportedRank << ") - I||_F = " << orthoError
1405 << " > TOL = " << TOL << "." << endl;
1406 numerr++;
1407 }
1408 }
1409
1410 // Compute the residual: if successful, S = Q*B +
1411 // X (X^* S =: C) in exact arithmetic. So, the residual is
1412 // S - Q*B - X1 C1 - X2 C2.
1413 //
1414 // Residual := S
1415 MVT::MvAddMv (SCT::one(), *S, SCT::zero(), *Residual, *Residual);
1416 {
1417 // Pick out the first reportedRank rows of B. Make a deep
1418 // copy, since DM is not safe with respect
1419 // to RCP-based memory management (it uses raw pointers
1420 // inside).
1421 RCP< const DM > B_top = DMT::SubviewCopy( *B, reportedRank, DMT::GetNumCols(*B) );
1422 // Residual := Residual - Q(:, 1:reportedRank) * B(1:reportedRank, :)
1423 MVT::MvTimesMatAddMv (-SCT::one(), *Q_left, *B_top, SCT::one(), *Residual);
1424 }
1425 // Residual := Residual - X[k]*C[k]
1426 for (int k = 0; k < num_X; ++k)
1427 MVT::MvTimesMatAddMv (-SCT::one(), *X[k], *C[k], SCT::one(), *Residual);
1428 const magnitude_type residErr = frobeniusNorm (*Residual);
1429 sout << "-- ||S - Q(:, 1:" << reportedRank << ")*B(1:"
1430 << reportedRank << ", :) - X1*C1 - X2*C2||_F = "
1431 << residErr << endl;
1432 if (residErr > ATOL * TOL)
1433 {
1434 sout << " *** Error: ||S - Q(:, 1:" << reportedRank
1435 << ")*B(1:" << reportedRank << ", :) "
1436 << "- X1*C1 - X2*C2||_F = " << residErr
1437 << " > ATOL*TOL = " << (ATOL*TOL) << "." << endl;
1438 numerr++;
1439 }
1440 // Verify that Q(1:reportedRank) is orthogonal to X[k], for
1441 // all k. This test only makes sense if reportedRank > 0.
1442 if (reportedRank == 0)
1443 {
1444 sout << "-- Reported rank of Q is zero: skipping Q, X[k] "
1445 "orthogonality test." << endl;
1446 }
1447 else
1448 {
1449 for (int k = 0; k < num_X; ++k)
1450 {
1451 // Q should be orthogonal to X[k], for all k.
1452 const magnitude_type projErr = OM->orthogError(*X[k], *Q_left);
1453 sout << "-- ||<Q(1:" << reportedRank << "), X[" << k
1454 << "]>||_F = " << projErr << endl;
1455 if (projErr > ATOL*TOL)
1456 {
1457 sout << " *** Error: ||<Q(1:" << reportedRank << "), X["
1458 << k << "]>||_F = " << projErr << " > ATOL*TOL = "
1459 << (ATOL*TOL) << "." << endl;
1460 numerr++;
1461 }
1462 }
1463 }
1464 } catch (Belos::OrthoError& e) {
1465 sout << " *** Error: The OrthoManager subclass instance threw "
1466 "an exception: " << e.what() << endl;
1467 numerr++;
1468 }
1469
1470 // Print out the collected diagnostic messages, which possibly
1471 // include error messages.
1472 const MsgType type = (numerr == 0) ? Debug : static_cast<MsgType> (static_cast<int>(Errors) | static_cast<int>(Debug));
1473 MyOM->stream(type) << sout.str();
1474 MyOM->stream(type) << endl;
1475
1476 return numerr;
1477 }
1478
1479
1483 static int
1484 testProjectNew (const Teuchos::RCP< Belos::OrthoManager< Scalar, MV, DM > > OM,
1485 const Teuchos::RCP< const MV >& S,
1486 const Teuchos::RCP< const MV >& X1,
1487 const Teuchos::RCP< const MV >& X2,
1488 const Teuchos::RCP< Belos::OutputManager< Scalar > >& MyOM)
1489 {
1490 using Teuchos::Array;
1491 using Teuchos::null;
1492 using Teuchos::RCP;
1493 using Teuchos::rcp;
1494 using Teuchos::tuple;
1495
1496 // We collect all the output in this string wrapper, and print
1497 // it at the end.
1498 std::ostringstream sout;
1499 // Total number of failed tests in this call of this routine.
1500 int numerr = 0;
1501
1502 const int numRows = MVT::GetGlobalLength(*S);
1503 const int numCols = MVT::GetNumberVecs(*S);
1504 const int sizeS = MVT::GetNumberVecs(*S);
1505
1506 // Relative tolerance against which all tests are performed.
1507 // We are measuring things in the Frobenius norm $\| \cdot \|_F$.
1508 // The following bounds hold for all $m \times n$ matrices $A$:
1509 // \[
1510 // \|A\|_2 \leq \|A\|_F \leq \sqrt{r} \|A\|_2,
1511 // \]
1512 // where $r$ is the (column) rank of $A$. We bound this above
1513 // by the number of columns in $A$.
1514 //
1515 // Since we are measuring both of these quantitites in the
1516 // Frobenius norm instead, we scale all error tests by
1517 // $\sqrt{n}$.
1518 //
1519 // A good heuristic is to scale the bound by the square root
1520 // of the number of floating-point operations. One could
1521 // perhaps support this theoretically, since we are using
1522 // uniform random test problems.
1523 const magnitude_type fudgeFactor =
1524 SMT::squareroot(magnitude_type(numRows) *
1525 magnitude_type(numCols) *
1526 magnitude_type(numCols));
1527 const magnitude_type TOL = SMT::eps() * fudgeFactor *
1528 SMT::squareroot(magnitude_type(numCols));
1529
1530 // Absolute tolerance scaling: the Frobenius norm of the test
1531 // matrix S. TOL*ATOL is the absolute tolerance for the
1532 // residual $\|A - Q*B\|_F$.
1533 const magnitude_type ATOL = frobeniusNorm (*S);
1534
1535 sout << "The test matrix S has Frobenius norm " << ATOL
1536 << ", and the relative error tolerance is TOL = "
1537 << TOL << "." << endl;
1538
1539 // Make some copies of S, X1, and X2. The OrthoManager's
1540 // project() method shouldn't modify X1 or X2, but this is a a
1541 // test and we don't know that it doesn't!
1542 RCP< MV > S_copy = MVT::CloneCopy(*S);
1543 RCP< MV > Residual = MVT::CloneCopy(*S);
1544 const int num_X = 2;
1545 Array< RCP< const MV > > X (num_X);
1546 X[0] = MVT::CloneCopy(*X1);
1547 X[1] = MVT::CloneCopy(*X2);
1548
1549 // Array of coefficients matrices from the projection.
1550 // For our first test, we allocate each of these matrices
1551 // with the proper dimensions.
1552 Array< RCP< DM > > C (num_X);
1553 for (int k = 0; k < num_X; ++k)
1554 {
1555 C[k] = DMT::Create( MVT::GetNumberVecs(*X[k]), sizeS );
1556 RandomSyncedMpiMatrix<Scalar,DM>(*C[k]); // will be overwritten
1557 }
1558 try {
1559 // Compute the projection: S_copy := (I - X X^*) S
1560 OM->project(*S_copy, C, X);
1561
1562 // Compute the residual: if successful, S = S_copy + X (X^*
1563 // S =: C) in exact arithmetic. So, the residual is
1564 // S - S_copy - X1 C1 - X2 C2.
1565 //
1566 // Residual := S - S_copy
1567 MVT::MvAddMv (SCT::one(), *S, -SCT::one(), *S_copy, *Residual);
1568 // Residual := Residual - X[k]*C[k]
1569 for (int k = 0; k < num_X; ++k)
1570 MVT::MvTimesMatAddMv (-SCT::one(), *X[k], *C[k], SCT::one(), *Residual);
1571 magnitude_type residErr = frobeniusNorm (*Residual);
1572 sout << " ||S - S_copy - X1*C1 - X2*C2||_F = " << residErr;
1573 if (residErr > ATOL * TOL)
1574 {
1575 sout << " *** Error: ||S - S_copy - X1*C1 - X2*C2||_F = " << residErr
1576 << " > ATOL*TOL = " << (ATOL*TOL) << ".";
1577 numerr++;
1578 }
1579 for (int k = 0; k < num_X; ++k)
1580 {
1581 // S_copy should be orthogonal to X[k] now.
1582 const magnitude_type projErr = OM->orthogError(*X[k], *S_copy);
1583 if (projErr > TOL)
1584 {
1585 sout << " *** Error: S is not orthogonal to X[" << k
1586 << "] by a factor of " << projErr << " > TOL = "
1587 << TOL << ".";
1588 numerr++;
1589 }
1590 }
1591 } catch (Belos::OrthoError& e) {
1592 sout << " *** Error: The OrthoManager subclass instance threw "
1593 "an exception: " << e.what() << endl;
1594 numerr++;
1595 }
1596
1597 // Print out the collected diagnostic messages, which possibly
1598 // include error messages.
1599 const MsgType type = (numerr == 0) ? Debug : static_cast<MsgType> (static_cast<int>(Errors) | static_cast<int>(Debug));
1600 MyOM->stream(type) << sout.str();
1601 MyOM->stream(type) << endl;
1602
1603 return numerr;
1604 }
1605
1606 static int
1607 testProject (const Teuchos::RCP< Belos::OrthoManager< Scalar, MV, DM > > OM,
1608 const Teuchos::RCP< const MV >& S,
1609 const Teuchos::RCP< const MV >& X1,
1610 const Teuchos::RCP< const MV >& X2,
1611 const Teuchos::RCP< Belos::OutputManager< Scalar > >& MyOM)
1612 {
1613 return testProjectNew (OM, S, X1, X2, MyOM);
1614 }
1615
1619 static int
1620 testProjectOld (const Teuchos::RCP< Belos::OrthoManager< Scalar, MV, DM > > OM,
1621 const Teuchos::RCP< const MV >& S,
1622 const Teuchos::RCP< const MV >& X1,
1623 const Teuchos::RCP< const MV >& X2,
1624 const Teuchos::RCP< Belos::OutputManager< Scalar > >& MyOM)
1625 {
1626 using Teuchos::Array;
1627 using Teuchos::null;
1628 using Teuchos::RCP;
1629 using Teuchos::rcp;
1630 using Teuchos::tuple;
1631
1632 const scalar_type ONE = SCT::one();
1633 // We collect all the output in this string wrapper, and print
1634 // it at the end.
1635 std::ostringstream sout;
1636 // Total number of failed tests in this call of this routine.
1637 int numerr = 0;
1638
1639 const int numRows = MVT::GetGlobalLength(*S);
1640 const int numCols = MVT::GetNumberVecs(*S);
1641 const int sizeS = MVT::GetNumberVecs(*S);
1642 const int sizeX1 = MVT::GetNumberVecs(*X1);
1643 const int sizeX2 = MVT::GetNumberVecs(*X2);
1644
1645 // Relative tolerance against which all tests are performed.
1646 // We are measuring things in the Frobenius norm $\| \cdot \|_F$.
1647 // The following bounds hold for all $m \times n$ matrices $A$:
1648 // \[
1649 // \|A\|_2 \leq \|A\|_F \leq \sqrt{r} \|A\|_2,
1650 // \]
1651 // where $r$ is the (column) rank of $A$. We bound this above
1652 // by the number of columns in $A$.
1653 //
1654 // Since we are measuring both of these quantitites in the
1655 // Frobenius norm instead, we scale all error tests by
1656 // $\sqrt{n}$.
1657 //
1658 // A good heuristic is to scale the bound by the square root
1659 // of the number of floating-point operations. One could
1660 // perhaps support this theoretically, since we are using
1661 // uniform random test problems.
1662 const magnitude_type fudgeFactor =
1663 SMT::squareroot(magnitude_type(numRows) *
1664 magnitude_type(numCols) *
1665 magnitude_type(numCols));
1666 const magnitude_type TOL = SMT::eps() * fudgeFactor *
1667 SMT::squareroot(magnitude_type(numCols));
1668
1669 // Absolute tolerance scaling: the Frobenius norm of the test
1670 // matrix S. TOL*ATOL is the absolute tolerance for the
1671 // residual $\|A - Q*B\|_F$.
1672 const magnitude_type ATOL = frobeniusNorm (*S);
1673
1674 sout << "The test matrix S has Frobenius norm " << ATOL
1675 << ", and the relative error tolerance is TOL = "
1676 << TOL << "." << endl;
1677
1678
1679 //
1680 // Output tests:
1681 // <S_out,X1> = 0
1682 // <S_out,X2> = 0
1683 // S_in = S_out + X1 C1 + X2 C2
1684 //
1685 // We will loop over an integer specifying the test combinations.
1686 // The bit pattern for the different tests is listed in parentheses.
1687 //
1688 // For the projectors, test the following combinations:
1689 // none (00)
1690 // P_X1 (01)
1691 // P_X2 (10)
1692 // P_X1 P_X2 (11)
1693 // P_X2 P_X1 (11)
1694 // The latter two should be tested to give the same result.
1695 //
1696 // For each of these, we should test with C1 and C2:
1697 //
1698 // if hasM:
1699 // with and without MX1 (1--)
1700 // with and without MX2 (1---)
1701 // with and without MS (1----)
1702 //
1703 // As hasM controls the upper level bits, we need only run test
1704 // cases 0-3 if hasM==false. Otherwise, we run test cases 0-31.
1705 //
1706
1707 int numtests = 8;
1708
1709 // test ortho error before orthonormalizing
1710 if (X1 != null) {
1711 magnitude_type err = OM->orthogError(*S,*X1);
1712 sout << " || <S,X1> || before : " << err << endl;
1713 }
1714 if (X2 != null) {
1715 magnitude_type err = OM->orthogError(*S,*X2);
1716 sout << " || <S,X2> || before : " << err << endl;
1717 }
1718
1719 for (int t = 0; t < numtests; ++t)
1720 {
1721 Array< RCP< const MV > > theX;
1722 Array< RCP< DM > > C;
1723 if ( (t % 3) == 0 ) {
1724 // neither X1 nor X2
1725 // C and theX are already empty
1726 }
1727 else if ( (t % 3) == 1 ) {
1728 // X1
1729 theX = tuple(X1);
1730 C = tuple( DMT::Create(sizeX1,sizeS) );
1731 }
1732 else if ( (t % 3) == 2 ) {
1733 // X2
1734 theX = tuple(X2);
1735 C = tuple( DMT::Create(sizeX2,sizeS) );
1736 }
1737 else {
1738 // X1 and X2, and the reverse.
1739 theX = tuple(X1,X2);
1740 C = tuple( DMT::Create(sizeX1,sizeS),
1741 DMT::Create(sizeX2,sizeS) );
1742 }
1743
1744 try {
1745 // call routine
1746 // if (t && 3) == 3, {
1747 // call with reversed input: X2 X1
1748 // }
1749 // test all outputs for correctness
1750 // test all outputs for equivalence
1751
1752 // here is where the outputs go
1753 Array< RCP< MV > > S_outs;
1754 Array< Array< RCP< DM > > > C_outs;
1755 RCP< MV > Scopy;
1756
1757 // copies of S,MS
1758 Scopy = MVT::CloneCopy(*S);
1759 // randomize this data, it should be overwritten
1760 for (size_type i = 0; i < C.size(); ++i) {
1761 RandomSyncedMpiMatrix<Scalar,DM>(*C[i]);
1762 }
1763 // Run test.
1764 // Note that Anasazi and Belos differ, among other places,
1765 // in the order of arguments to project().
1766 OM->project(*Scopy,C,theX);
1767 // we allocate S and MS for each test, so we can save these as views
1768 // however, save copies of the C
1769 S_outs.push_back( Scopy );
1770 C_outs.push_back( Array< RCP< DM > >(0) );
1771 if (C.size() > 0) {
1772 C_outs.back().push_back( DMT::CreateCopy( *C[0]) );
1773 }
1774 if (C.size() > 1) {
1775 C_outs.back().push_back( DMT::CreateCopy( *C[1]) );
1776 }
1777
1778 // do we run the reversed input?
1779 if ( (t % 3) == 3 ) {
1780 // copies of S,MS
1781 Scopy = MVT::CloneCopy(*S);
1782 // randomize this data, it should be overwritten
1783 for (size_type i = 0; i < C.size(); ++i) {
1784 RandomSyncedMpiMatrix<Scalar,DM>(*C[i]);
1785 }
1786 // flip the inputs
1787 theX = tuple( theX[1], theX[0] );
1788 // Run test.
1789 // Note that Anasazi and Belos differ, among other places,
1790 // in the order of arguments to project().
1791 OM->project(*Scopy,C,theX);
1792 // we allocate S and MS for each test, so we can save these as views
1793 // however, save copies of the C
1794 S_outs.push_back( Scopy );
1795 // we are in a special case: P_X1 and P_X2, so we know we applied
1796 // two projectors, and therefore have two C[i]
1797 C_outs.push_back( Array<RCP<DM> >() );
1798 // reverse the Cs to compensate for the reverse projectors
1799 C_outs.back().push_back( DMT::CreateCopy(*C[1]) );
1800 C_outs.back().push_back( DMT::CreateCopy(*C[0]) );
1801 // flip the inputs back
1802 theX = tuple( theX[1], theX[0] );
1803 }
1804
1805 // test all outputs for correctness
1806 for (size_type o = 0; o < S_outs.size(); ++o) {
1807 // S_in = X1*C1 + C2*C2 + S_out
1808 {
1809 RCP<MV> tmp = MVT::CloneCopy(*S_outs[o]);
1810 if (C_outs[o].size() > 0) {
1811 MVT::MvTimesMatAddMv(ONE,*X1,*C_outs[o][0],ONE,*tmp);
1812 if (C_outs[o].size() > 1) {
1813 MVT::MvTimesMatAddMv(ONE,*X2,*C_outs[o][1],ONE,*tmp);
1814 }
1815 }
1816 magnitude_type err = MVDiff(*tmp,*S);
1817 if (err > ATOL*TOL) {
1818 sout << " vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv tolerance exceeded! test failed!" << endl;
1819 numerr++;
1820 }
1821 sout << " " << t << "|| S_in - X1*C1 - X2*C2 - S_out || : " << err << endl;
1822 }
1823 // <X1,S> == 0
1824 if (theX.size() > 0 && theX[0] != null) {
1825 magnitude_type err = OM->orthogError(*theX[0],*S_outs[o]);
1826 if (err > TOL) {
1827 sout << " vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv tolerance exceeded! test failed!" << endl;
1828 numerr++;
1829 }
1830 sout << " " << t << "|| <X[0],S> || after : " << err << endl;
1831 }
1832 // <X2,S> == 0
1833 if (theX.size() > 1 && theX[1] != null) {
1834 magnitude_type err = OM->orthogError(*theX[1],*S_outs[o]);
1835 if (err > TOL) {
1836 sout << " vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv tolerance exceeded! test failed!" << endl;
1837 numerr++;
1838 }
1839 sout << " " << t << "|| <X[1],S> || after : " << err << endl;
1840 }
1841 }
1842
1843 // test all outputs for equivalence
1844 // check all combinations:
1845 // output 0 == output 1
1846 // output 0 == output 2
1847 // output 1 == output 2
1848 for (size_type o1=0; o1<S_outs.size(); o1++) {
1849 for (size_type o2=o1+1; o2<S_outs.size(); o2++) {
1850 // don't need to check MS_outs because we check
1851 // S_outs and MS_outs = M*S_outs
1852 // don't need to check C_outs either
1853 //
1854 // check that S_outs[o1] == S_outs[o2]
1855 magnitude_type err = MVDiff(*S_outs[o1],*S_outs[o2]);
1856 if (err > TOL) {
1857 sout << " vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv tolerance exceeded! test failed!" << endl;
1858 numerr++;
1859 }
1860 }
1861 }
1862
1863 }
1864 catch (Belos::OrthoError& e) {
1865 sout << " ------------------------------------------- project() threw exception" << endl;
1866 sout << " Error: " << e.what() << endl;
1867 numerr++;
1868 }
1869 } // test for
1870
1871 MsgType type = Debug;
1872 if (numerr>0) type = Errors;
1873 MyOM->stream(type) << sout.str();
1874 MyOM->stream(type) << endl;
1875
1876 return numerr;
1877 }
1878
1879
1880 };
1881
1882
1883
1884 } // namespace Test
1885} // namespace Belos
1886
1887
Belos header file which uses auto-configuration information to include necessary C++ headers.
Test routines for MultiVecTraits and OperatorTraits conformity.
Declaration of basic traits for the multivector type.
Class which manages the output and verbosity of the Belos solvers.
Alternative run-time polymorphic interface for operators.
Exception thrown to signal error in an orthogonalization manager method.
static void baseline(const Teuchos::RCP< const MV > &X, const int numCols, const int numBlocks, const int numTrials)
Establish baseline run time for OrthoManager benchmark.
static void benchmark(const Teuchos::RCP< OrthoManager< Scalar, MV, DM > > &orthoMan, const std::string &orthoManName, const std::string &normalization, const Teuchos::RCP< const MV > &X, const int numCols, const int numBlocks, const int numTrials, const Teuchos::RCP< OutputManager< Scalar > > &outMan, std::ostream &resultStream, const bool displayResultsCompactly=false)
Benchmark the given orthogonalization manager.
Wrapper around OrthoManager test functionality.
MultiVecTraits< scalar_type, MV, DM > MVT
static int runTests(const Teuchos::RCP< OrthoManager< Scalar, MV, DM > > &OM, const bool isRankRevealing, const Teuchos::RCP< MV > &S, const int sizeX1, const int sizeX2, const Teuchos::RCP< OutputManager< Scalar > > &MyOM)
Run all the tests.
Teuchos::ScalarTraits< magnitude_type > SMT
DenseMatTraits< scalar_type, DM > DMT
Teuchos::ScalarTraits< scalar_type > SCT
MsgType
Available message types recognized by the linear solvers.

Generated for Belos by doxygen 1.9.8