Anasazi  Version of the Day
AnasaziTraceMinBaseSolMgr.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Anasazi: Block Eigensolvers Package
5 // Copyright 2004 Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
8 // the U.S. Government retains certain rights in this software.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #ifndef ANASAZI_TraceMinBase_SOLMGR_HPP
43 #define ANASAZI_TraceMinBase_SOLMGR_HPP
44 
51 #include "AnasaziBasicSort.hpp"
52 #include "AnasaziConfigDefs.hpp"
53 #include "AnasaziEigenproblem.hpp"
55 #include "AnasaziSolverManager.hpp"
56 #include "AnasaziSolverUtils.hpp"
60 #include "AnasaziStatusTestSpecTrans.hpp"
63 #include "AnasaziTraceMinBase.hpp"
64 #include "AnasaziTraceMinTypes.hpp"
65 #include "AnasaziTypes.hpp"
66 
67 #include "Teuchos_TimeMonitor.hpp"
68 #ifdef TEUCHOS_DEBUG
69 # include <Teuchos_FancyOStream.hpp>
70 #endif
71 #ifdef HAVE_MPI
72 #include <mpi.h>
73 #endif
74 
75 using Teuchos::RCP;
76 using Teuchos::rcp;
77 
78 namespace Anasazi {
79 namespace Experimental {
80 
81 
114 template<class ScalarType, class MV, class OP>
115 class TraceMinBaseSolMgr : public SolverManager<ScalarType,MV,OP> {
116 
117  private:
120  typedef Teuchos::ScalarTraits<ScalarType> SCT;
121  typedef typename Teuchos::ScalarTraits<ScalarType>::magnitudeType MagnitudeType;
122  typedef Teuchos::ScalarTraits<MagnitudeType> MT;
123 
124  public:
125 
127 
128 
172  Teuchos::ParameterList &pl );
173 
175  virtual ~TraceMinBaseSolMgr() {};
177 
179 
180 
183  return *problem_;
184  }
185 
187  int getNumIters() const {
188  return numIters_;
189  }
190 
198  Teuchos::Array<RCP<Teuchos::Time> > getTimers() const {
199  return Teuchos::tuple(_timerSolve, _timerRestarting, _timerLocking);
200  }
201 
203 
205 
206 
230  ReturnType solve();
231 
233  void setGlobalStatusTest(const RCP< StatusTest<ScalarType,MV,OP> > &global);
234 
236  const RCP< StatusTest<ScalarType,MV,OP> > & getGlobalStatusTest() const;
237 
239  void setLockingStatusTest(const RCP< StatusTest<ScalarType,MV,OP> > &locking);
240 
242  const RCP< StatusTest<ScalarType,MV,OP> > & getLockingStatusTest() const;
243 
245  void setDebugStatusTest(const RCP< StatusTest<ScalarType,MV,OP> > &debug);
246 
248  const RCP< StatusTest<ScalarType,MV,OP> > & getDebugStatusTest() const;
249 
251 
252  protected:
253  RCP<Eigenproblem<ScalarType,MV,OP> > problem_;
254 
255  int numIters_;
256 
257  // Block variables
258  int blockSize_, numBlocks_, numRestartBlocks_;
259 
260  // Output variables
261  RCP<BasicOutputManager<ScalarType> > printer_;
262 
263  // Convergence variables
264  MagnitudeType convTol_;
265  bool relConvTol_;
266  enum ResType convNorm_;
267 
268  // Locking variables
269  MagnitudeType lockTol_;
270  int maxLocked_, lockQuorum_;
271  bool useLocking_, relLockTol_;
272  enum ResType lockNorm_;
273 
274  // Shifting variables
275  enum WhenToShiftType whenToShift_;
276  MagnitudeType traceThresh_, shiftTol_;
277  enum HowToShiftType howToShift_;
278  bool useMultipleShifts_, relShiftTol_, considerClusters_;
279  std::string shiftNorm_;
280 
281  // Other variables
282  int maxKrylovIter_;
283  std::string ortho_, which_;
284  enum SaddleSolType saddleSolType_;
285  bool projectAllVecs_, projectLockedVecs_, computeAllRes_, useRHSR_, useHarmonic_, noSort_;
286  MagnitudeType alpha_;
287 
288  // Timers
289  RCP<Teuchos::Time> _timerSolve, _timerRestarting, _timerLocking;
290 
291  // Status tests
292  RCP<StatusTest<ScalarType,MV,OP> > globalTest_;
293  RCP<StatusTest<ScalarType,MV,OP> > lockingTest_;
294  RCP<StatusTest<ScalarType,MV,OP> > debugTest_;
295 
296  // TraceMin specific functions
297  void copyPartOfState(const TraceMinBaseState<ScalarType,MV>& oldState, TraceMinBaseState<ScalarType,MV>& newState, const std::vector<int> indToCopy) const;
298 
299  void setParameters(Teuchos::ParameterList &pl) const;
300 
301  void printParameters(std::ostream &os) const;
302 
303  virtual RCP< TraceMinBase<ScalarType,MV,OP> > createSolver(
304  const RCP<SortManager<typename Teuchos::ScalarTraits<ScalarType>::magnitudeType> > &sorter,
305  const RCP<StatusTest<ScalarType,MV,OP> > &outputtest,
306  const RCP<MatOrthoManager<ScalarType,MV,OP> > &ortho,
307  Teuchos::ParameterList &plist
308  ) =0;
309 
310  virtual bool needToRestart(const RCP< TraceMinBase<ScalarType,MV,OP> > solver) =0;
311 
312  virtual bool performRestart(int &numRestarts, RCP< TraceMinBase<ScalarType,MV,OP> > solver) =0;
313 };
314 
315 
318 // Constructor
319 template<class ScalarType, class MV, class OP>
321  const RCP<Eigenproblem<ScalarType,MV,OP> > &problem,
322  Teuchos::ParameterList &pl ) :
323  problem_(problem)
324 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
325  , _timerSolve(Teuchos::TimeMonitor::getNewTimer("Anasazi: TraceMinBaseSolMgr::solve()")),
326  _timerRestarting(Teuchos::TimeMonitor::getNewTimer("Anasazi: TraceMinBaseSolMgr restarting")),
327  _timerLocking(Teuchos::TimeMonitor::getNewTimer("Anasazi: TraceMinBaseSolMgr locking"))
328 #endif
329 {
330  TEUCHOS_TEST_FOR_EXCEPTION(problem_ == Teuchos::null, std::invalid_argument, "Problem not given to solver manager.");
331  TEUCHOS_TEST_FOR_EXCEPTION(!problem_->isProblemSet(), std::invalid_argument, "Problem not set.");
332  TEUCHOS_TEST_FOR_EXCEPTION(!problem_->isHermitian(), std::invalid_argument, "Problem not symmetric.");
333  TEUCHOS_TEST_FOR_EXCEPTION(problem_->getInitVec() == Teuchos::null,std::invalid_argument, "Problem does not contain initial vectors to clone from.");
334 
335  std::string strtmp;
336 
338  // Block parameters
339 
340  // TODO: the default is different for TraceMin and TraceMin-Davidson
341  // block size: default is nev()
342 // blockSize_ = pl.get("Block Size",problem_->getNEV());
343 // TEUCHOS_TEST_FOR_EXCEPTION(blockSize_ <= 0, std::invalid_argument,
344 // "Anasazi::TraceMinBaseSolMgr: \"Block Size\" must be strictly positive.");
345 
346  // TODO: add Num Blocks as a parameter to both child classes, since they have different default values
347 // numBlocks_ = pl.get("Num Blocks",5);
348 // TEUCHOS_TEST_FOR_EXCEPTION(numBlocks_ < 2, std::invalid_argument,
349 // "Anasazi::TraceMinBaseSolMgr: \"Num Blocks\" must be >= 2.");
350 
352  // Output parameters
353 
354  // output stream
355  std::string fntemplate = "";
356  bool allProcs = false;
357  if (pl.isParameter("Output on all processors")) {
358  if (Teuchos::isParameterType<bool>(pl,"Output on all processors")) {
359  allProcs = pl.get("Output on all processors",allProcs);
360  } else {
361  allProcs = ( Teuchos::getParameter<int>(pl,"Output on all processors") != 0 );
362  }
363  }
364  fntemplate = pl.get("Output filename template",fntemplate);
365  int MyPID;
366 # ifdef HAVE_MPI
367  // Initialize MPI
368  int mpiStarted = 0;
369  MPI_Initialized(&mpiStarted);
370  if (mpiStarted) MPI_Comm_rank(MPI_COMM_WORLD, &MyPID);
371  else MyPID=0;
372 # else
373  MyPID = 0;
374 # endif
375  if (fntemplate != "") {
376  std::ostringstream MyPIDstr;
377  MyPIDstr << MyPID;
378  // replace %d in fntemplate with MyPID
379  int pos, start=0;
380  while ( (pos = fntemplate.find("%d",start)) != -1 ) {
381  fntemplate.replace(pos,2,MyPIDstr.str());
382  start = pos+2;
383  }
384  }
385  RCP<ostream> osp;
386  if (fntemplate != "") {
387  osp = rcp( new std::ofstream(fntemplate.c_str(),std::ios::out | std::ios::app) );
388  if (!*osp) {
389  osp = Teuchos::rcpFromRef(std::cout);
390  std::cout << "Anasazi::TraceMinBaseSolMgr::constructor(): Could not open file for write: " << fntemplate << std::endl;
391  }
392  }
393  else {
394  osp = Teuchos::rcpFromRef(std::cout);
395  }
396  // Output manager
397  int verbosity = Anasazi::Errors;
398  if (pl.isParameter("Verbosity")) {
399  if (Teuchos::isParameterType<int>(pl,"Verbosity")) {
400  verbosity = pl.get("Verbosity", verbosity);
401  } else {
402  verbosity = (int)Teuchos::getParameter<Anasazi::MsgType>(pl,"Verbosity");
403  }
404  }
405  if (allProcs) {
406  // print on all procs
407  printer_ = rcp( new BasicOutputManager<ScalarType>(verbosity,osp,MyPID) );
408  }
409  else {
410  // print only on proc 0
411  printer_ = rcp( new BasicOutputManager<ScalarType>(verbosity,osp,0) );
412  }
413 
414  // TODO: Add restart parameters to TraceMin-Davidson
415 
417  // Convergence parameters
418  convTol_ = pl.get("Convergence Tolerance",MT::prec());
419  TEUCHOS_TEST_FOR_EXCEPTION(convTol_ < 0, std::invalid_argument,
420  "Anasazi::TraceMinBaseSolMgr: \"Convergence Tolerance\" must be nonnegative.");
421 
422  relConvTol_ = pl.get("Relative Convergence Tolerance",true);
423  strtmp = pl.get("Convergence Norm",std::string("2"));
424  if (strtmp == "2") {
425  convNorm_ = RES_2NORM;
426  }
427  else if (strtmp == "M") {
428  convNorm_ = RES_ORTH;
429  }
430  else {
431  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
432  "Anasazi::TraceMinBaseSolMgr: Invalid Convergence Norm.");
433  }
434 
436  // Locking parameters
437  useLocking_ = pl.get("Use Locking",true);
438  relLockTol_ = pl.get("Relative Locking Tolerance",true);
439  lockTol_ = pl.get("Locking Tolerance",convTol_/10);
440 
441  TEUCHOS_TEST_FOR_EXCEPTION(relConvTol_ != relLockTol_, std::invalid_argument,
442  "Anasazi::TraceMinBaseSolMgr: \"Relative Convergence Tolerance\" and \"Relative Locking Tolerance\" have different values. If you set one, you should always set the other.");
443 
444  TEUCHOS_TEST_FOR_EXCEPTION(lockTol_ < 0, std::invalid_argument,
445  "Anasazi::TraceMinBaseSolMgr: \"Locking Tolerance\" must be nonnegative.");
446 
447  strtmp = pl.get("Locking Norm",std::string("2"));
448  if (strtmp == "2") {
449  lockNorm_ = RES_2NORM;
450  }
451  else if (strtmp == "M") {
452  lockNorm_ = RES_ORTH;
453  }
454  else {
455  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
456  "Anasazi::TraceMinBaseSolMgr: Invalid Locking Norm.");
457  }
458 
459  // max locked: default is nev(), must satisfy maxLocked_ + blockSize_ >= nev
460  if (useLocking_) {
461  maxLocked_ = pl.get("Max Locked",problem_->getNEV());
462  TEUCHOS_TEST_FOR_EXCEPTION(maxLocked_ <= 0, std::invalid_argument,
463  "Anasazi::TraceMinBaseSolMgr: \"Max Locked\" must be strictly positive.");
464  }
465  else {
466  maxLocked_ = 0;
467  }
468 
469  if (useLocking_) {
470  lockQuorum_ = pl.get("Locking Quorum",1);
471  TEUCHOS_TEST_FOR_EXCEPTION(lockQuorum_ <= 0, std::invalid_argument,
472  "Anasazi::TraceMinBaseSolMgr: \"Locking Quorum\" must be strictly positive.");
473  }
474 
476  // Ritz shift parameters
477 
478  // When to shift - what triggers a shift?
479  strtmp = pl.get("When To Shift", "Always");
480 
481  if(strtmp == "Never")
482  whenToShift_ = NEVER_SHIFT;
483  else if(strtmp == "After Trace Levels")
484  whenToShift_ = SHIFT_WHEN_TRACE_LEVELS;
485  else if(strtmp == "Residual Becomes Small")
486  whenToShift_ = SHIFT_WHEN_RESID_SMALL;
487  else if(strtmp == "Always")
488  whenToShift_ = ALWAYS_SHIFT;
489  else
490  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
491  "Anasazi::TraceMinBaseSolMgr: Invalid value for \"When To Shift\"; valid options are \"Never\", \"After Trace Levels\", \"Residual Becomes Small\", \"Always\".");
492 
493 
494  // How small does the % change in trace have to get before shifting?
495  traceThresh_ = pl.get("Trace Threshold", 0.02);
496 
497  TEUCHOS_TEST_FOR_EXCEPTION(traceThresh_ < 0, std::invalid_argument,
498  "Anasazi::TraceMinBaseSolMgr: \"Trace Threshold\" must be nonnegative.");
499 
500  // Shift threshold - if the residual of an eigenpair is less than this, then shift
501  shiftTol_ = pl.get("Shift Tolerance", 0.1);
502 
503  TEUCHOS_TEST_FOR_EXCEPTION(shiftTol_ < 0, std::invalid_argument,
504  "Anasazi::TraceMinBaseSolMgr: \"Shift Tolerance\" must be nonnegative.");
505 
506  // Use relative convergence tolerance - scale by eigenvalue?
507  relShiftTol_ = pl.get("Relative Shift Tolerance", true);
508 
509  // Which norm to use in determining whether to shift
510  shiftNorm_ = pl.get("Shift Norm", "2");
511 
512  TEUCHOS_TEST_FOR_EXCEPTION(shiftNorm_ != "2" && shiftNorm_ != "M", std::invalid_argument,
513  "Anasazi::TraceMinBaseSolMgr: Invalid value for \"Shift Norm\"; valid options are \"2\" and \"M\".");
514 
515  noSort_ = pl.get("No Sorting", false);
516 
517  // How to choose shift
518  strtmp = pl.get("How To Choose Shift", "Adjusted Ritz Values");
519 
520  if(strtmp == "Largest Converged")
521  howToShift_ = LARGEST_CONVERGED_SHIFT;
522  else if(strtmp == "Adjusted Ritz Values")
523  howToShift_ = ADJUSTED_RITZ_SHIFT;
524  else if(strtmp == "Ritz Values")
525  howToShift_ = RITZ_VALUES_SHIFT;
526  else if(strtmp == "Experimental Shift")
527  howToShift_ = EXPERIMENTAL_SHIFT;
528  else
529  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
530  "Anasazi::TraceMinBaseSolMgr: Invalid value for \"How To Choose Shift\"; valid options are \"Largest Converged\", \"Adjusted Ritz Values\", \"Ritz Values\".");
531 
532  // Consider clusters - if all eigenvalues are in one cluster, it's not expecially safe to shift
533  considerClusters_ = pl.get("Consider Clusters", true);
534 
535  // Use multiple shifts
536  useMultipleShifts_ = pl.get("Use Multiple Shifts", true);
537 
539  // Other parameters
540 
541  // which orthogonalization to use
542  ortho_ = pl.get("Orthogonalization", "SVQB");
543  TEUCHOS_TEST_FOR_EXCEPTION(ortho_ != "DGKS" && ortho_ != "SVQB" && ortho_ != "ICGS", std::invalid_argument,
544  "Anasazi::TraceMinBaseSolMgr: Invalid value for \"Orthogonalization\"; valid options are \"DGKS\", \"SVQB\", \"ICGS\".");
545 
546  strtmp = pl.get("Saddle Solver Type", "Projected Krylov");
547 
548  if(strtmp == "Projected Krylov")
549  saddleSolType_ = PROJECTED_KRYLOV_SOLVER;
550  else if(strtmp == "Schur Complement")
551  saddleSolType_ = SCHUR_COMPLEMENT_SOLVER;
552  else if(strtmp == "Block Diagonal Preconditioned Minres")
553  saddleSolType_ = BD_PREC_MINRES;
554  else if(strtmp == "HSS Preconditioned Gmres")
555  saddleSolType_ = HSS_PREC_GMRES;
556  else
557  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
558  "Anasazi::TraceMinBaseSolMgr: Invalid value for \"Saddle Solver Type\"; valid options are \"Projected Krylov\", \"Schur Complement\", and \"Block Diagonal Preconditioned Minres\".");
559 
560  projectAllVecs_ = pl.get("Project All Vectors", true);
561  projectLockedVecs_ = pl.get("Project Locked Vectors", true);
562  computeAllRes_ = pl.get("Compute All Residuals", true);
563  useRHSR_ = pl.get("Use Residual as RHS", false);
564  alpha_ = pl.get("HSS: alpha", 1.0);
565 
566  TEUCHOS_TEST_FOR_EXCEPTION(projectLockedVecs_ && ! projectAllVecs_, std::invalid_argument,
567  "Anasazi::TraceMinBaseSolMgr: If you want to project out the locked vectors, you should really project out ALL the vectors of X.");
568 
569  // Maximum number of inner iterations
570  maxKrylovIter_ = pl.get("Maximum Krylov Iterations", 200);
571  TEUCHOS_TEST_FOR_EXCEPTION(maxKrylovIter_ < 1, std::invalid_argument,
572  "Anasazi::TraceMinBaseSolMgr: \"Maximum Krylov Iterations\" must be greater than 0.");
573 
574  // Which eigenvalues we want to get
575  which_ = pl.get("Which", "SM");
576  TEUCHOS_TEST_FOR_EXCEPTION(which_ != "SM" && which_ != "LM", std::invalid_argument,
577  "Anasazi::TraceMinBaseSolMgr: Invalid value for \"Which\"; valid options are \"SM\" and \"LM\".");
578 
579  // Test whether we are shifting without an operator K
580  // This is a really bad idea
581  TEUCHOS_TEST_FOR_EXCEPTION(problem_->getOperator() == Teuchos::null && whenToShift_ != NEVER_SHIFT, std::invalid_argument,
582  "Anasazi::TraceMinBaseSolMgr: It is an exceptionally bad idea to use Ritz shifts when finding the largest eigenpairs of a standard eigenvalue problem. If we don't use Ritz shifts, it may take extra iterations to converge, but we NEVER have to solve a single linear system. Using Ritz shifts forces us to solve systems of the form (I + sigma A)x=f, and it probably doesn't benefit us enough to outweigh the extra cost. We may add support for this feature in the future, but for now, please set \"When To Shift\" to \"Never\".");
583 
584 #ifdef BELOS_PSEUDO_BLOCK_GMRES_SOLMGR_HPP
585  // Test whether we are using a projected preconditioner with multiple Ritz shifts
586  // We can't currently do this for reasons that are complicated and are explained in the user manual
587  TEUCHOS_TEST_FOR_EXCEPTION(problem_->getPrec() != Teuchos::null && saddleSolType_ == PROJECTED_KRYLOV_SOLVER && useMultipleShifts_, std::invalid_argument,
588  "Anasazi::TraceMinBaseSolMgr: When you use the projected Krylov solver with preconditioning, the preconditioner must be projected as well. In theory, if the preconditioner is SPD, the projected preconditioner will be SPSD, but in practice, it can have small negative eigenvalues, presumably due to machine arithmetic. This means we can't use TraceMin's built-in MINRES, and we are forced to use Belos for now. When you use multiple Ritz shifts, you are essentially using a different operator to solve each linear system. Belos can't handle this right now, but we're working on a solution. For now, please set \"Use Multiple Shifts\" to false.");
589 #else
590  // Test whether we are using a projected preconditioner without Belos.
591  // P Prec P should be positive definite if Prec is positive-definite,
592  // but it tends not to be in practice, presumably due to machine arithmetic
593  // As a result, we have to use pseudo-block gmres for now.
594  // Make sure it's available.
595  TEUCHOS_TEST_FOR_EXCEPTION(problem_->getPrec() != Teuchos::null && saddleSolType_ == PROJECTED_KRYLOV_SOLVER, std::invalid_argument,
596  "Anasazi::TraceMinBaseSolMgr: When you use the projected Krylov solver with preconditioning, the preconditioner must be projected as well. In theory, if the preconditioner is SPD, the projected preconditioner will be SPSD, but in practice, it can have small negative eigenvalues, presumably due to machine arithmetic. This means we can't use TraceMin's built-in MINRES, and we are forced to use Belos for now. You didn't install Belos. You have three options to correct this problem:\n1. Reinstall Trilinos with Belos enabled\n2. Don't use a preconditioner\n3. Choose a different method for solving the saddle-point problem (Recommended)");
597 
598 
599 #endif
600 
601 
602 }
603 
604 
607 // solve()
608 template<class ScalarType, class MV, class OP>
609 ReturnType
611 {
612  typedef SolverUtils<ScalarType,MV,OP> msutils;
613 
614  const int nev = problem_->getNEV();
615 
616 #ifdef TEUCHOS_DEBUG
617  RCP<Teuchos::FancyOStream>
618  out = Teuchos::getFancyOStream(Teuchos::rcpFromRef(printer_->stream(Debug)));
619  out->setShowAllFrontMatter(false).setShowProcRank(true);
620  *out << "Entering Anasazi::TraceMinBaseSolMgr::solve()\n";
621 #endif
622 
624  // Sort manager
625  RCP<BasicSort<MagnitudeType> > sorter = rcp( new BasicSort<MagnitudeType>("SM") );
626 
628  // Handle the spectral transformation if necessary
629  // TODO: Make sure we undo this before returning...
630  if(which_ == "LM")
631  {
632  RCP<const OP> swapHelper = problem_->getOperator();
633  problem_->setOperator(problem_->getM());
634  problem_->setM(swapHelper);
635  problem_->setProblem();
636  }
637 
639  // Status tests
640  //
641  // convergence
642  RCP<StatusTest<ScalarType,MV,OP> > convtest;
643  if (globalTest_ == Teuchos::null) {
644  if(which_ == "SM")
645  convtest = rcp( new StatusTestResNorm<ScalarType,MV,OP>(convTol_,nev,convNorm_,relConvTol_) );
646  else
647  convtest = rcp( new StatusTestSpecTrans<ScalarType,MV,OP>(convTol_,nev,convNorm_,relConvTol_,true,problem_->getOperator()) );
648  }
649  else {
650  convtest = globalTest_;
651  }
652  RCP<StatusTestWithOrdering<ScalarType,MV,OP> > ordertest
653  = rcp( new StatusTestWithOrdering<ScalarType,MV,OP>(convtest,sorter,nev) );
654  // locking
655  RCP<StatusTest<ScalarType,MV,OP> > locktest;
656  if (useLocking_) {
657  if (lockingTest_ == Teuchos::null) {
658  if(which_ == "SM")
659  locktest = rcp( new StatusTestResNorm<ScalarType,MV,OP>(lockTol_,lockQuorum_,lockNorm_,relLockTol_) );
660  else
661  locktest = rcp( new StatusTestSpecTrans<ScalarType,MV,OP>(lockTol_,lockQuorum_,lockNorm_,relLockTol_,true,problem_->getOperator()) );
662  }
663  else {
664  locktest = lockingTest_;
665  }
666  }
667  // for a non-short-circuited OR test, the order doesn't matter
668  Teuchos::Array<RCP<StatusTest<ScalarType,MV,OP> > > alltests;
669  alltests.push_back(ordertest);
670  if (locktest != Teuchos::null) alltests.push_back(locktest);
671  if (debugTest_ != Teuchos::null) alltests.push_back(debugTest_);
672 
673  RCP<StatusTestCombo<ScalarType,MV,OP> > combotest
675  // printing StatusTest
676  RCP<StatusTestOutput<ScalarType,MV,OP> > outputtest;
677  if ( printer_->isVerbosity(Debug) ) {
678  outputtest = rcp( new StatusTestOutput<ScalarType,MV,OP>( printer_,combotest,1,Passed+Failed+Undefined ) );
679  }
680  else {
681  outputtest = rcp( new StatusTestOutput<ScalarType,MV,OP>( printer_,combotest,1,Passed ) );
682  }
683 
685  // Orthomanager
686  RCP<MatOrthoManager<ScalarType,MV,OP> > ortho;
687  if (ortho_=="SVQB") {
688  ortho = rcp( new SVQBOrthoManager<ScalarType,MV,OP>(problem_->getM()) );
689  } else if (ortho_=="DGKS") {
690  ortho = rcp( new BasicOrthoManager<ScalarType,MV,OP>(problem_->getM()) );
691  } else if (ortho_=="ICGS") {
692  ortho = rcp( new ICGSOrthoManager<ScalarType,MV,OP>(problem_->getM()) );
693  } else {
694  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"Anasazi::TraceMinBaseSolMgr::solve(): Invalid orthogonalization type.");
695  }
696 
698  // Parameter list
699  Teuchos::ParameterList plist;
700  setParameters(plist);
701 
703  // TraceMinBase solver
704  RCP<TraceMinBase<ScalarType,MV,OP> > tm_solver
705  = createSolver(sorter,outputtest,ortho,plist);
706  // set any auxiliary vectors defined in the problem
707  RCP< const MV > probauxvecs = problem_->getAuxVecs();
708  if (probauxvecs != Teuchos::null) {
709  tm_solver->setAuxVecs( Teuchos::tuple< RCP<const MV> >(probauxvecs) );
710  }
711 
713  // Storage
714  //
715  // lockvecs will contain eigenvectors that have been determined "locked" by the status test
716  int curNumLocked = 0;
717  RCP<MV> lockvecs;
718  // lockvecs is used to hold the locked eigenvectors, as well as for temporary storage when locking.
719  // when locking, we will lock some number of vectors numnew, where numnew <= maxlocked - curlocked
720  // we will produce numnew random vectors, which will go into the space with the new basis.
721  // we will also need numnew storage for the image of these random vectors under A and M;
722  // columns [curlocked+1,curlocked+numnew] will be used for this storage
723  if (maxLocked_ > 0) {
724  lockvecs = MVT::Clone(*problem_->getInitVec(),maxLocked_);
725  }
726  std::vector<MagnitudeType> lockvals;
727  //
728  // Restarting occurs under two scenarios: when the basis is full and after locking.
729  //
730  // For the former, a new basis of size blockSize*numRestartBlocks is generated using the current basis
731  // and the most significant primitive Ritz vectors (projected eigenvectors).
732  // [S,L] = eig(KK)
733  // S = [Sr St] // some for "r"estarting, some are "t"runcated
734  // newV = V*Sr
735  // KK_new = newV'*K*newV = Sr'*V'*K*V*Sr = Sr'*KK*Sr
736  // Therefore, the only multivector operation needed is for the generation of newV.
737  //
738  // * If the multiplication is explicit, it requires a workspace of blockSize*numRestartBlocks vectors.
739  // This space must be specifically allocated for that task, as we don't have any space of that size.
740  // It (workMV) will be allocated at the beginning of solve()
741  // * Optionally, the multiplication can be performed implicitly, via a Householder QR factorization of
742  // Sr. This can be done in situ, using the basis multivector contained in the solver. This requires
743  // that we cast away the const on the multivector returned from getState(). Workspace for this approach
744  // is a single vector. the solver's internal storage must be preserved (X,MX,KX,R), requiring us to
745  // allocate this vector.
746  //
747  // For the latter (restarting after locking), the new basis is the same size as existing basis. If numnew
748  // vectors are locked, they are deflated from the current basis and replaced with randomly generated
749  // vectors.
750  // [S,L] = eig(KK)
751  // S = [Sl Su] // partitioned: "l"ocked and "u"nlocked
752  // newL = V*Sl = X(locked)
753  // defV = V*Su
754  // augV = rand(numnew) // orthogonal to oldL,newL,defV,auxvecs
755  // newV = [defV augV]
756  // Kknew = newV'*K*newV = [Su'*KK*Su defV'*K*augV]
757  // [augV'*K*defV augV'*K*augV]
758  // locked = [oldL newL]
759  // Clearly, this operation is more complicated than the previous.
760  // Here is a list of the significant computations that need to be performed:
761  // - newL will be put into space in lockvecs, but will be copied from getState().X at the end
762  // - defV,augV will be stored in workspace the size of the current basis.
763  // - M*augV and K*augV are needed; they will be stored in lockvecs. As a result, newL will
764  // not be put into lockvecs until the end.
765  //
766  // Therefore, we must allocate workMV when ((maxRestarts_ > 0) || (useLocking_ == true)) && inSituRestart == false
767  // It will be allocated to size (numBlocks-1)*blockSize
768  //
769 
770  // some consts and utils
771  const ScalarType ONE = SCT::one();
772  const ScalarType ZERO = SCT::zero();
773 
774  // go ahead and initialize the solution to nothing in case we throw an exception
776  sol.numVecs = 0;
777  problem_->setSolution(sol);
778 
779  int numRestarts = 0;
780 
781  // enter solve() iterations
782  {
783 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
784  Teuchos::TimeMonitor slvtimer(*_timerSolve);
785 #endif
786 
787  // tell tm_solver to iterate
788  while (1) {
789  try {
790  tm_solver->iterate();
791 
793  //
794  //
796  if (debugTest_ != Teuchos::null && debugTest_->getStatus() == Passed) {
797  throw AnasaziError("Anasazi::TraceMinBaseSolMgr::solve(): User-specified debug status test returned Passed.");
798  }
800  //
801  // check convergence next
802  //
804  else if (ordertest->getStatus() == Passed ) {
805  // we have convergence
806  // ordertest->whichVecs() tells us which vectors from lockvecs and solver state are the ones we want
807  // ordertest->howMany() will tell us how many
808  break;
809  }
811  //
812  // check locking if we didn't converge or restart
813  //
815  else if (locktest != Teuchos::null && locktest->getStatus() == Passed) {
816 
817 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
818  Teuchos::TimeMonitor lcktimer(*_timerLocking);
819 #endif
820 
821  //
822  // get current state
823  TraceMinBaseState<ScalarType,MV> state = tm_solver->getState();
824  const int curdim = state.curDim;
825 
826  //
827  // get number,indices of vectors to be locked
828  TEUCHOS_TEST_FOR_EXCEPTION(locktest->howMany() <= 0,std::logic_error,
829  "Anasazi::TraceMinBaseSolMgr::solve(): status test mistake: howMany() non-positive.");
830  TEUCHOS_TEST_FOR_EXCEPTION(locktest->howMany() != (int)locktest->whichVecs().size(),std::logic_error,
831  "Anasazi::TraceMinBaseSolMgr::solve(): status test mistake: howMany() not consistent with whichVecs().");
832  // we should have room to lock vectors; otherwise, locking should have been deactivated
833  TEUCHOS_TEST_FOR_EXCEPTION(curNumLocked == maxLocked_,std::logic_error,
834  "Anasazi::TraceMinBaseSolMgr::solve(): status test mistake: locking not deactivated.");
835  //
836  // don't lock more than maxLocked_; we didn't allocate enough space.
837  std::vector<int> tmp_vector_int;
838  if (curNumLocked + locktest->howMany() > maxLocked_) {
839  // just use the first of them
840  for(int i=0; i<maxLocked_-curNumLocked; i++)
841  tmp_vector_int.push_back(locktest->whichVecs()[i]);
842 // tmp_vector_int.insert(tmp_vector_int.begin(),locktest->whichVecs().begin(),locktest->whichVecs().begin()+maxLocked_-curNumLocked);
843  }
844  else {
845  tmp_vector_int = locktest->whichVecs();
846  }
847 
848  const std::vector<int> lockind(tmp_vector_int);
849  const int numNewLocked = lockind.size();
850  //
851  // generate indices of vectors left unlocked
852  // curind = [0,...,curdim-1] = UNION( lockind, unlockind )
853  const int numUnlocked = curdim-numNewLocked;
854  tmp_vector_int.resize(curdim);
855  for (int i=0; i<curdim; i++) tmp_vector_int[i] = i;
856  const std::vector<int> curind(tmp_vector_int); // curind = [0 ... curdim-1]
857  tmp_vector_int.resize(numUnlocked);
858  std::set_difference(curind.begin(),curind.end(),lockind.begin(),lockind.end(),tmp_vector_int.begin());
859  const std::vector<int> unlockind(tmp_vector_int); // unlockind = [0 ... curdim-1] - lockind
860  tmp_vector_int.clear();
861 
862  //
863  // debug printing
864  if (printer_->isVerbosity(Debug)) {
865  printer_->print(Debug,"Locking vectors: ");
866  for (unsigned int i=0; i<lockind.size(); i++) {printer_->stream(Debug) << " " << lockind[i];}
867  printer_->print(Debug,"\n");
868  printer_->print(Debug,"Not locking vectors: ");
869  for (unsigned int i=0; i<unlockind.size(); i++) {printer_->stream(Debug) << " " << unlockind[i];}
870  printer_->print(Debug,"\n");
871  }
872 
873  // Copy eigenvalues we want to lock into lockvals
874  std::vector<Value<ScalarType> > allvals = tm_solver->getRitzValues();
875  for(unsigned int i=0; i<allvals.size(); i++)
876  printer_->stream(Debug) << "Ritz value[" << i << "] = " << allvals[i].realpart << std::endl;
877  for (int i=0; i<numNewLocked; i++) {
878  lockvals.push_back(allvals[lockind[i]].realpart);
879  }
880 
881  // Copy vectors we want to lock into lockvecs
882  RCP<const MV> newLocked = MVT::CloneView(*tm_solver->getRitzVectors(),lockind);
883  std::vector<int> indlock(numNewLocked);
884  for (int i=0; i<numNewLocked; i++) indlock[i] = curNumLocked+i;
885  if(useHarmonic_)
886  {
887  RCP<MV> tempMV = MVT::CloneCopy(*newLocked);
888  ortho->normalizeMat(*tempMV);
889  MVT::SetBlock(*tempMV,indlock,*lockvecs);
890  }
891  else
892  {
893  MVT::SetBlock(*newLocked,indlock,*lockvecs);
894  }
895 
896  // Tell the StatusTestWithOrdering that things have been locked
897  // This is VERY important
898  // If this set of lines is removed, the code does not terminate correctly
899  if(noSort_)
900  {
901  for(unsigned int aliciaInd=0; aliciaInd<lockvals.size(); aliciaInd++)
902  {
903  lockvals[aliciaInd] = 0.0;
904  }
905  }
906  ordertest->setAuxVals(lockvals);
907 
908  // Set the auxiliary vectors so that we remain orthogonal to the ones we locked
909  // Remember to include any aux vecs provided by the user
910  curNumLocked += numNewLocked;
911 
912  if(ordertest->getStatus() == Passed) break;
913 
914  std::vector<int> curlockind(curNumLocked);
915  for (int i=0; i<curNumLocked; i++) curlockind[i] = i;
916  RCP<const MV> curlocked = MVT::CloneView(*lockvecs,curlockind);
917 
918  Teuchos::Array< RCP<const MV> > aux;
919  if (probauxvecs != Teuchos::null) aux.push_back(probauxvecs);
920  aux.push_back(curlocked);
921  tm_solver->setAuxVecs(aux);
922 
923  // Disable locking if we have locked the maximum number of things
924  printer_->stream(Debug) << "curNumLocked: " << curNumLocked << std::endl;
925  printer_->stream(Debug) << "maxLocked: " << maxLocked_ << std::endl;
926  if (curNumLocked == maxLocked_) {
927  // disabled locking now
928  combotest->removeTest(locktest);
929  locktest = Teuchos::null;
930  printer_->stream(Debug) << "Removed locking test\n";
931  }
932 
933  int newdim = numRestartBlocks_*blockSize_;
935  if(newdim <= numUnlocked)
936  {
937  if(useHarmonic_)
938  {
939  std::vector<int> desiredSubscripts(newdim);
940  for(int i=0; i<newdim; i++)
941  {
942  desiredSubscripts[i] = unlockind[i];
943  printer_->stream(Debug) << "H desiredSubscripts[" << i << "] = " << desiredSubscripts[i] << std::endl;
944  }
945  newstate.V = MVT::CloneView(*tm_solver->getRitzVectors(),desiredSubscripts);
946  newstate.curDim = newdim;
947  }
948  else
949  {
950  std::vector<int> desiredSubscripts(newdim);
951  for(int i=0; i<newdim; i++)
952  {
953  desiredSubscripts[i] = unlockind[i];
954  printer_->stream(Debug) << "desiredSubscripts[" << i << "] = " << desiredSubscripts[i] << std::endl;
955  }
956 
957  copyPartOfState(state, newstate, desiredSubscripts);
958  }
959  }
960  else
961  {
962  // TODO: Come back to this and make it more efficient
963 
964  // Replace the converged eigenvectors with random ones
965  int nrandom = newdim-numUnlocked;
966 
967  RCP<const MV> helperMV;
968  RCP<MV> totalV = MVT::Clone(*tm_solver->getRitzVectors(),newdim);
969 
970  // Holds old things that we're keeping
971  tmp_vector_int.resize(numUnlocked);
972  for(int i=0; i<numUnlocked; i++) tmp_vector_int[i] = i;
973  RCP<MV> oldV = MVT::CloneViewNonConst(*totalV,tmp_vector_int);
974 
975  // Copy over the old things
976  if(useHarmonic_)
977  helperMV = MVT::CloneView(*tm_solver->getRitzVectors(),unlockind);
978  else
979  helperMV = MVT::CloneView(*state.V,unlockind);
980  MVT::Assign(*helperMV,*oldV);
981 
982  // Holds random vectors we're generating
983  tmp_vector_int.resize(nrandom);
984  for(int i=0; i<nrandom; i++) tmp_vector_int[i] = i+numUnlocked;
985  RCP<MV> newV = MVT::CloneViewNonConst(*totalV,tmp_vector_int);
986 
987  // Create random things
988  MVT::MvRandom(*newV);
989 
990  newstate.V = totalV;
991  newstate.curDim = newdim;
992 
993  // Copy Ritz shifts
994  RCP< std::vector<ScalarType> > helperRS = rcp( new std::vector<ScalarType>(blockSize_) );
995  for(unsigned int i=0; i<(unsigned int)blockSize_; i++)
996  {
997  if(i < unlockind.size() && unlockind[i] < blockSize_)
998  (*helperRS)[i] = (*state.ritzShifts)[unlockind[i]];
999  else
1000  (*helperRS)[i] = ZERO;
1001  }
1002  newstate.ritzShifts = helperRS;
1003  }
1004 
1005  // Determine the largest safe shift
1006  newstate.largestSafeShift = std::abs(lockvals[0]);
1007  for(size_t i=0; i<lockvals.size(); i++)
1008  newstate.largestSafeShift = std::max(std::abs(lockvals[i]), newstate.largestSafeShift);
1009 
1010  // Prepare new state, removing converged vectors
1011  // TODO: Init will perform some unnecessary calculations; look into it
1012  // TODO: The residual norms should be part of the state
1013  newstate.NEV = state.NEV - numNewLocked;
1014  tm_solver->initialize(newstate);
1015  } // end of locking
1017  //
1018  // check for restarting before locking: if we need to lock, it will happen after the restart
1019  //
1021  else if ( needToRestart(tm_solver) ) {
1022  // if performRestart returns false, we exceeded the maximum number of restarts
1023  if(performRestart(numRestarts, tm_solver) == false)
1024  break;
1025  } // end of restarting
1027  //
1028  // we returned from iterate(), but none of our status tests Passed.
1029  // something is wrong, and it is probably our fault.
1030  //
1032  else {
1033  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"Anasazi::TraceMinBaseSolMgr::solve(): Invalid return from tm_solver::iterate().");
1034  }
1035  }
1036  catch (const AnasaziError &err) {
1037  printer_->stream(Errors)
1038  << "Anasazi::TraceMinBaseSolMgr::solve() caught unexpected exception from Anasazi::TraceMinBase::iterate() at iteration " << tm_solver->getNumIters() << std::endl
1039  << err.what() << std::endl
1040  << "Anasazi::TraceMinBaseSolMgr::solve() returning Unconverged with no solutions." << std::endl;
1041  return Unconverged;
1042  }
1043  }
1044 
1045  sol.numVecs = ordertest->howMany();
1046  if (sol.numVecs > 0) {
1047  sol.Evecs = MVT::Clone(*problem_->getInitVec(),sol.numVecs);
1048  sol.Espace = sol.Evecs;
1049  sol.Evals.resize(sol.numVecs);
1050  std::vector<MagnitudeType> vals(sol.numVecs);
1051 
1052  // copy them into the solution
1053  std::vector<int> which = ordertest->whichVecs();
1054  // indices between [0,blockSize) refer to vectors/values in the solver
1055  // indices between [-curNumLocked,-1] refer to locked vectors/values [0,curNumLocked)
1056  // everything has already been ordered by the solver; we just have to partition the two references
1057  std::vector<int> inlocked(0), insolver(0);
1058  for (unsigned int i=0; i<which.size(); i++) {
1059  if (which[i] >= 0) {
1060  TEUCHOS_TEST_FOR_EXCEPTION(which[i] >= blockSize_,std::logic_error,"Anasazi::TraceMinBaseSolMgr::solve(): positive indexing mistake from ordertest.");
1061  insolver.push_back(which[i]);
1062  }
1063  else {
1064  // sanity check
1065  TEUCHOS_TEST_FOR_EXCEPTION(which[i] < -curNumLocked,std::logic_error,"Anasazi::TraceMinBaseSolMgr::solve(): negative indexing mistake from ordertest.");
1066  inlocked.push_back(which[i] + curNumLocked);
1067  }
1068  }
1069 
1070  TEUCHOS_TEST_FOR_EXCEPTION(insolver.size() + inlocked.size() != (unsigned int)sol.numVecs,std::logic_error,"Anasazi::TraceMinBaseSolMgr::solve(): indexing mistake.");
1071 
1072  // set the vecs,vals in the solution
1073  if (insolver.size() > 0) {
1074  // set vecs
1075  int lclnum = insolver.size();
1076  std::vector<int> tosol(lclnum);
1077  for (int i=0; i<lclnum; i++) tosol[i] = i;
1078  RCP<const MV> v = MVT::CloneView(*tm_solver->getRitzVectors(),insolver);
1079  MVT::SetBlock(*v,tosol,*sol.Evecs);
1080  // set vals
1081  std::vector<Value<ScalarType> > fromsolver = tm_solver->getRitzValues();
1082  for (unsigned int i=0; i<insolver.size(); i++) {
1083  vals[i] = fromsolver[insolver[i]].realpart;
1084  }
1085  }
1086 
1087  // get the vecs,vals from locked storage
1088  if (inlocked.size() > 0) {
1089  int solnum = insolver.size();
1090  // set vecs
1091  int lclnum = inlocked.size();
1092  std::vector<int> tosol(lclnum);
1093  for (int i=0; i<lclnum; i++) tosol[i] = solnum + i;
1094  RCP<const MV> v = MVT::CloneView(*lockvecs,inlocked);
1095  MVT::SetBlock(*v,tosol,*sol.Evecs);
1096  // set vals
1097  for (unsigned int i=0; i<inlocked.size(); i++) {
1098  vals[i+solnum] = lockvals[inlocked[i]];
1099  }
1100  }
1101 
1102  // undo the spectral transformation if necessary
1103  // if we really passed the solver Bx = \lambda A x, invert the eigenvalues
1104  if(which_ == "LM")
1105  {
1106  for(size_t i=0; i<vals.size(); i++)
1107  vals[i] = ONE/vals[i];
1108  }
1109 
1110  // sort the eigenvalues and permute the eigenvectors appropriately
1111  {
1112  std::vector<int> order(sol.numVecs);
1113  sorter->sort(vals,Teuchos::rcpFromRef(order),sol.numVecs);
1114  // store the values in the Eigensolution
1115  for (int i=0; i<sol.numVecs; i++) {
1116  sol.Evals[i].realpart = vals[i];
1117  sol.Evals[i].imagpart = MT::zero();
1118  }
1119  // now permute the eigenvectors according to order
1120  msutils::permuteVectors(sol.numVecs,order,*sol.Evecs);
1121  }
1122 
1123  // setup sol.index, remembering that all eigenvalues are real so that index = {0,...,0}
1124  sol.index.resize(sol.numVecs,0);
1125  }
1126  }
1127 
1128  // print final summary
1129  tm_solver->currentStatus(printer_->stream(FinalSummary));
1130 
1131  printParameters(printer_->stream(FinalSummary));
1132 
1133  // print timing information
1134 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
1135  if ( printer_->isVerbosity( TimingDetails ) ) {
1136  Teuchos::TimeMonitor::summarize( printer_->stream( TimingDetails ) );
1137  }
1138 #endif
1139 
1140  problem_->setSolution(sol);
1141  printer_->stream(Debug) << "Returning " << sol.numVecs << " eigenpairs to eigenproblem." << std::endl;
1142 
1143  // get the number of iterations taken for this call to solve().
1144  numIters_ = tm_solver->getNumIters();
1145 
1146  if (sol.numVecs < nev) {
1147  return Unconverged; // return from TraceMinBaseSolMgr::solve()
1148  }
1149  return Converged; // return from TraceMinBaseSolMgr::solve()
1150 }
1151 
1152 
1153 template <class ScalarType, class MV, class OP>
1154 void
1156  const RCP< StatusTest<ScalarType,MV,OP> > &global)
1157 {
1158  globalTest_ = global;
1159 }
1160 
1161 template <class ScalarType, class MV, class OP>
1162 const RCP< StatusTest<ScalarType,MV,OP> > &
1164 {
1165  return globalTest_;
1166 }
1167 
1168 template <class ScalarType, class MV, class OP>
1169 void
1171  const RCP< StatusTest<ScalarType,MV,OP> > &debug)
1172 {
1173  debugTest_ = debug;
1174 }
1175 
1176 template <class ScalarType, class MV, class OP>
1177 const RCP< StatusTest<ScalarType,MV,OP> > &
1179 {
1180  return debugTest_;
1181 }
1182 
1183 template <class ScalarType, class MV, class OP>
1184 void
1186  const RCP< StatusTest<ScalarType,MV,OP> > &locking)
1187 {
1188  lockingTest_ = locking;
1189 }
1190 
1191 template <class ScalarType, class MV, class OP>
1192 const RCP< StatusTest<ScalarType,MV,OP> > &
1194 {
1195  return lockingTest_;
1196 }
1197 
1198 template <class ScalarType, class MV, class OP>
1199 void TraceMinBaseSolMgr<ScalarType,MV,OP>::copyPartOfState(const TraceMinBaseState<ScalarType,MV>& oldState, TraceMinBaseState<ScalarType,MV>& newState, const std::vector<int> indToCopy) const
1200 {
1201  const ScalarType ONE = Teuchos::ScalarTraits<MagnitudeType>::one();
1202  const ScalarType ZERO = Teuchos::ScalarTraits<MagnitudeType>::zero();
1203 
1204  newState.curDim = indToCopy.size();
1205  std::vector<int> fullIndices(oldState.curDim);
1206  for(int i=0; i<oldState.curDim; i++) fullIndices[i] = i;
1207 
1208  // Initialize with X.
1209  // Note that we didn't compute enough vectors of X, but we can very easily using the Ritz vectors.
1210  // That's why they're part of the state.
1211  // Note that there will ALWAYS be enough vectors
1212 
1213  // Helpful vectors for computing views and whatnot
1214  std::vector<int> oldIndices;
1215  std::vector<int> newIndices;
1216  for(int i=0; i<newState.curDim; i++)
1217  {
1218  if(indToCopy[i] < blockSize_)
1219  oldIndices.push_back(indToCopy[i]);
1220  else
1221  newIndices.push_back(indToCopy[i]);
1222  }
1223 
1224  int olddim = oldIndices.size();
1225  int newdim = newIndices.size();
1226 
1227  // If there are no new vectors being copied
1228  if(computeAllRes_)
1229  {
1230  newState.V = MVT::CloneView(*oldState.X, indToCopy);
1231  newState.R = MVT::CloneView(*oldState.R, indToCopy);
1232  newState.X = newState.V;
1233 
1234  if(problem_->getOperator() != Teuchos::null)
1235  {
1236  newState.KV = MVT::CloneView(*oldState.KX, indToCopy);
1237  newState.KX = newState.KV;
1238  }
1239  else
1240  {
1241  newState.KV = Teuchos::null;
1242  newState.KX = Teuchos::null;
1243  }
1244 
1245  if(problem_->getM() != Teuchos::null)
1246  {
1247  newState.MopV = MVT::CloneView(*oldState.MX, indToCopy);
1248  newState.MX = newState.MopV;
1249  }
1250  else
1251  {
1252  newState.MopV = Teuchos::null;
1253  newState.MX = Teuchos::null;
1254  }
1255  }
1256  else if(newdim == 0)
1257  {
1258  std::vector<int> blockind(blockSize_);
1259  for(int i=0; i<blockSize_; i++)
1260  blockind[i] = i;
1261 
1262  // Initialize with X
1263  newState.V = MVT::CloneView(*oldState.X, blockind);
1264  newState.KV = MVT::CloneView(*oldState.KX, blockind);
1265  newState.R = MVT::CloneView(*oldState.R, blockind);
1266  newState.X = MVT::CloneView(*newState.V, blockind);
1267  newState.KX = MVT::CloneView(*newState.KV, blockind);
1268 
1269  if(problem_->getM() != Teuchos::null)
1270  {
1271  newState.MopV = MVT::CloneView(*oldState.MX, blockind);
1272  newState.MX = MVT::CloneView(*newState.MopV, blockind);
1273  }
1274  else
1275  {
1276  newState.MopV = Teuchos::null;
1277  newState.MX = Teuchos::null;
1278  }
1279  }
1280  else
1281  {
1282  // More helpful vectors
1283  std::vector<int> oldPart(olddim);
1284  for(int i=0; i<olddim; i++) oldPart[i] = i;
1285  std::vector<int> newPart(newdim);
1286  for(int i=0; i<newdim; i++) newPart[i] = olddim+i;
1287 
1288  // Helpful multivectors for views and whatnot
1289  RCP<MV> helper = MVT::Clone(*oldState.V,newState.curDim);
1290  RCP<MV> oldHelper = MVT::CloneViewNonConst(*helper,oldPart);
1291  RCP<MV> newHelper = MVT::CloneViewNonConst(*helper,newPart);
1292  RCP<const MV> viewHelper;
1293 
1294  // Get the parts of the Ritz vectors we are interested in.
1295  Teuchos::SerialDenseMatrix<int,ScalarType> newRV(oldState.curDim,newdim);
1296  for(int r=0; r<oldState.curDim; r++)
1297  {
1298  for(int c=0; c<newdim; c++)
1299  newRV(r,c) = (*oldState.RV)(r,newIndices[c]);
1300  }
1301 
1302  // We're going to compute X as V*RitzVecs
1303  viewHelper = MVT::CloneView(*oldState.V,fullIndices);
1304  MVT::MvTimesMatAddMv(ONE,*viewHelper,newRV,ZERO,*newHelper);
1305  viewHelper = MVT::CloneView(*oldState.X,oldIndices);
1306  MVT::Assign(*viewHelper,*oldHelper);
1307  newState.V = MVT::CloneCopy(*helper);
1308 
1309  // Also compute KX as KV*RitzVecs
1310  viewHelper = MVT::CloneView(*oldState.KV,fullIndices);
1311  MVT::MvTimesMatAddMv(ONE,*viewHelper,newRV,ZERO,*newHelper);
1312  viewHelper = MVT::CloneView(*oldState.KX,oldIndices);
1313  MVT::Assign(*viewHelper,*oldHelper);
1314  newState.KV = MVT::CloneCopy(*helper);
1315 
1316  // Do the same with MX if necessary
1317  if(problem_->getM() != Teuchos::null)
1318  {
1319  viewHelper = MVT::CloneView(*oldState.MopV,fullIndices);
1320  MVT::MvTimesMatAddMv(ONE,*viewHelper,newRV,ZERO,*newHelper);
1321  viewHelper = MVT::CloneView(*oldState.MX,oldIndices);
1322  MVT::Assign(*viewHelper,*oldHelper);
1323  newState.MopV = MVT::CloneCopy(*helper);
1324  }
1325  else
1326  newState.MopV = newState.V;
1327 
1328  // Get X, MX, KX
1329  std::vector<int> blockVec(blockSize_);
1330  for(int i=0; i<blockSize_; i++) blockVec[i] = i;
1331  newState.X = MVT::CloneView(*newState.V,blockVec);
1332  newState.KX = MVT::CloneView(*newState.KV,blockVec);
1333  newState.MX = MVT::CloneView(*newState.MopV,blockVec);
1334 
1335  // Update the residuals
1336  if(blockSize_-oldIndices.size() > 0)
1337  {
1338  // There are vectors we have not computed the residual for yet
1339  newPart.resize(blockSize_-oldIndices.size());
1340  helper = MVT::Clone(*oldState.V,blockSize_);
1341  oldHelper = MVT::CloneViewNonConst(*helper,oldPart);
1342  newHelper = MVT::CloneViewNonConst(*helper,newPart);
1343 
1344  RCP<MV> scaledMV = MVT::CloneCopy(*newState.MX,newPart);
1345  RCP<const MV> localKV = MVT::CloneView(*newState.KX,newPart);
1346  std::vector<ScalarType> scalarVec(blockSize_-oldIndices.size());
1347  for(unsigned int i=0; i<(unsigned int)blockSize_-oldIndices.size(); i++) scalarVec[i] = (*oldState.T)[newPart[i]];
1348  MVT::MvScale(*scaledMV,scalarVec);
1349 
1350  helper = MVT::Clone(*oldState.V,blockSize_);
1351  oldHelper = MVT::CloneViewNonConst(*helper,oldPart);
1352  newHelper = MVT::CloneViewNonConst(*helper,newPart);
1353  MVT::MvAddMv(ONE,*localKV,-ONE,*scaledMV,*newHelper);
1354  viewHelper = MVT::CloneView(*oldState.R,oldIndices);
1355  MVT::Assign(*viewHelper,*oldHelper);
1356  newState.R = MVT::CloneCopy(*helper);
1357  }
1358  else
1359  newState.R = oldState.R;
1360  }
1361 
1362  // Since we are setting V:=X, V is orthonormal
1363  newState.isOrtho = true;
1364 
1365  // Get the first eigenvalues
1366  RCP< std::vector<ScalarType> > helperT = rcp( new std::vector<ScalarType>(newState.curDim) );
1367  for(int i=0; i<newState.curDim; i++) (*helperT)[i] = (*oldState.T)[indToCopy[i]];
1368  newState.T = helperT;
1369 
1370  // X'KX is diag(T)
1371  RCP< Teuchos::SerialDenseMatrix<int,ScalarType> > newKK = rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>(newState.curDim,newState.curDim) );
1372  for(int i=0; i<newState.curDim; i++)
1373  (*newKK)(i,i) = (*newState.T)[i];
1374  newState.KK = newKK;
1375 
1376  // The associated Ritz vectors are I
1377  RCP< Teuchos::SerialDenseMatrix<int,ScalarType> > newRV = rcp( new Teuchos::SerialDenseMatrix<int,ScalarType>(newState.curDim,newState.curDim) );
1378  for(int i=0; i<newState.curDim; i++)
1379  (*newRV)(i,i) = ONE;
1380  newState.RV = newRV;
1381 
1382  // Get the Ritz shifts
1383  RCP< std::vector<ScalarType> > helperRS = rcp( new std::vector<ScalarType>(blockSize_) );
1384  for(int i=0; i<blockSize_; i++)
1385  {
1386  if(indToCopy[i] < blockSize_)
1387  (*helperRS)[i] = (*oldState.ritzShifts)[indToCopy[i]];
1388  else
1389  (*helperRS)[i] = ZERO;
1390  }
1391  newState.ritzShifts = helperRS;
1392 }
1393 
1394 
1395 template <class ScalarType, class MV, class OP>
1396 void TraceMinBaseSolMgr<ScalarType,MV,OP>::setParameters(Teuchos::ParameterList &pl) const
1397 {
1398  pl.set("Block Size", blockSize_);
1399  pl.set("Num Blocks", numBlocks_);
1400  pl.set("Num Restart Blocks", numRestartBlocks_);
1401  pl.set("When To Shift", whenToShift_);
1402  pl.set("Trace Threshold", traceThresh_);
1403  pl.set("Shift Tolerance", shiftTol_);
1404  pl.set("Relative Shift Tolerance", relShiftTol_);
1405  pl.set("Shift Norm", shiftNorm_);
1406  pl.set("How To Choose Shift", howToShift_);
1407  pl.set("Consider Clusters", considerClusters_);
1408  pl.set("Use Multiple Shifts", useMultipleShifts_);
1409  pl.set("Saddle Solver Type", saddleSolType_);
1410  pl.set("Project All Vectors", projectAllVecs_);
1411  pl.set("Project Locked Vectors", projectLockedVecs_);
1412  pl.set("Compute All Residuals", computeAllRes_);
1413  pl.set("Use Residual as RHS", useRHSR_);
1414  pl.set("Use Harmonic Ritz Values", useHarmonic_);
1415  pl.set("Maximum Krylov Iterations", maxKrylovIter_);
1416  pl.set("HSS: alpha", alpha_);
1417 }
1418 
1419 
1420 template <class ScalarType, class MV, class OP>
1421 void TraceMinBaseSolMgr<ScalarType,MV,OP>::printParameters(std::ostream &os) const
1422 {
1423  os << "\n\n\n";
1424  os << "========================================\n";
1425  os << "========= TraceMin parameters ==========\n";
1426  os << "========================================\n";
1427  os << "=========== Block parameters ===========\n";
1428  os << "Block Size: " << blockSize_ << std::endl;
1429  os << "Num Blocks: " << numBlocks_ << std::endl;
1430  os << "Num Restart Blocks: " << numRestartBlocks_ << std::endl;
1431  os << "======== Convergence parameters ========\n";
1432  os << "Convergence Tolerance: " << convTol_ << std::endl;
1433  os << "Relative Convergence Tolerance: " << relConvTol_ << std::endl;
1434  os << "========== Locking parameters ==========\n";
1435  os << "Use Locking: " << useLocking_ << std::endl;
1436  os << "Locking Tolerance: " << lockTol_ << std::endl;
1437  os << "Relative Locking Tolerance: " << relLockTol_ << std::endl;
1438  os << "Max Locked: " << maxLocked_ << std::endl;
1439  os << "Locking Quorum: " << lockQuorum_ << std::endl;
1440  os << "========== Shifting parameters =========\n";
1441  os << "When To Shift: ";
1442  if(whenToShift_ == NEVER_SHIFT) os << "Never\n";
1443  else if(whenToShift_ == SHIFT_WHEN_TRACE_LEVELS) os << "After Trace Levels\n";
1444  else if(whenToShift_ == SHIFT_WHEN_RESID_SMALL) os << "Residual Becomes Small\n";
1445  else if(whenToShift_ == ALWAYS_SHIFT) os << "Always\n";
1446  os << "Consider Clusters: " << considerClusters_ << std::endl;
1447  os << "Trace Threshohld: " << traceThresh_ << std::endl;
1448  os << "Shift Tolerance: " << shiftTol_ << std::endl;
1449  os << "Relative Shift Tolerance: " << relShiftTol_ << std::endl;
1450  os << "How To Choose Shift: ";
1451  if(howToShift_ == LARGEST_CONVERGED_SHIFT) os << "Largest Converged\n";
1452  else if(howToShift_ == ADJUSTED_RITZ_SHIFT) os << "Adjusted Ritz Values\n";
1453  else if(howToShift_ == RITZ_VALUES_SHIFT) os << "Ritz Values\n";
1454  os << "Use Multiple Shifts: " << useMultipleShifts_ << std::endl;
1455  os << "=========== Other parameters ===========\n";
1456  os << "Orthogonalization: " << ortho_ << std::endl;
1457  os << "Saddle Solver Type: ";
1458  if(saddleSolType_ == PROJECTED_KRYLOV_SOLVER) os << "Projected Krylov\n";
1459  else if(saddleSolType_ == SCHUR_COMPLEMENT_SOLVER) os << "Schur Complement\n";
1460  os << "Project All Vectors: " << projectAllVecs_ << std::endl;
1461  os << "Project Locked Vectors: " << projectLockedVecs_ << std::endl;
1462  os << "Compute All Residuals: " << computeAllRes_ << std::endl;
1463  os << "========================================\n\n\n";
1464 }
1465 
1466 
1467 }} // end Anasazi namespace
1468 
1469 #endif /* ANASAZI_TraceMinBase_SOLMGR_HPP */
Pure virtual base class which describes the basic interface for a solver manager. ...
static void MvRandom(MV &mv)
Replace the vectors in mv with random vectors.
static void MvTimesMatAddMv(const ScalarType alpha, const MV &A, const Teuchos::SerialDenseMatrix< int, ScalarType > &B, const ScalarType beta, MV &mv)
Update mv with .
std::vector< Value< ScalarType > > Evals
The computed eigenvalues.
Abstract base class for trace minimization eigensolvers.
int NEV
Number of unconverged eigenvalues.
TraceMinBaseSolMgr(const RCP< Eigenproblem< ScalarType, MV, OP > > &problem, Teuchos::ParameterList &pl)
Basic constructor for TraceMinBaseSolMgr.
const RCP< StatusTest< ScalarType, MV, OP > > & getGlobalStatusTest() const
Get the status test defining global convergence.
ResType
Enumerated type used to specify which residual norm used by residual norm status tests.
RCP< const MV > X
The current eigenvectors.
A special StatusTest for printing other status tests.
This class defines the interface required by an eigensolver and status test class to compute solution...
Structure to contain pointers to TraceMinBase state variables.
An implementation of the Anasazi::SortManager that performs a collection of common sorting techniques...
RCP< const MV > V
The current basis.
RCP< const MV > MopV
The image of V under M, or Teuchos::null if M was not specified.
Virtual base class which defines basic traits for the operator type.
Teuchos::RCP< MV > Evecs
The computed eigenvectors.
An implementation of the Anasazi::GenOrthoManager that performs orthogonalization using iterated clas...
Status test for forming logical combinations of other status tests.
The Anasazi::SolverManager is a templated virtual base class that defines the basic interface that an...
void setGlobalStatusTest(const RCP< StatusTest< ScalarType, MV, OP > > &global)
Set the status test defining global convergence.
Basic implementation of the Anasazi::SortManager class.
An implementation of the Anasazi::MatOrthoManager that performs orthogonalization using the SVQB iter...
static void Assign(const MV &A, MV &mv)
mv := A
An exception class parent to all Anasazi exceptions.
bool isOrtho
Whether V has been projected and orthonormalized already.
Namespace Anasazi contains the classes, structs, enums and utilities used by the Anasazi package...
A status test for testing the norm of the eigenvectors residuals along with a set of auxiliary eigenv...
Anasazi&#39;s templated, static class providing utilities for the solvers.
ReturnType solve()
This method performs possibly repeated calls to the underlying eigensolver&#39;s iterate() routine until ...
int numVecs
The number of computed eigenpairs.
Basic output manager for sending information of select verbosity levels to the appropriate output str...
Anasazi&#39;s templated virtual class for providing routines for orthogonalization and orthonormalization...
Teuchos::RCP< MV > Espace
An orthonormal basis for the computed eigenspace.
Anasazi&#39;s basic output manager for sending information of select verbosity levels to the appropriate ...
Abstract base class which defines the interface required by an eigensolver and status test class to c...
ReturnType
Enumerated type used to pass back information from a solver manager.
const RCP< StatusTest< ScalarType, MV, OP > > & getDebugStatusTest() const
Get the status test for debugging.
A status test for testing the norm of the eigenvectors residuals.
Traits class which defines basic operations on multivectors.
static Teuchos::RCP< MV > CloneCopy(const MV &mv)
Creates a new MV and copies contents of mv into the new vector (deep copy).
std::vector< int > index
An index into Evecs to allow compressed storage of eigenvectors for real, non-Hermitian problems...
static void MvScale(MV &mv, const ScalarType alpha)
Scale each element of the vectors in mv with alpha.
int curDim
The current dimension of the solver.
RCP< const MV > KV
The image of V under K.
Anasazi header file which uses auto-configuration information to include necessary C++ headers...
Orthogonalization manager based on the SVQB technique described in "A Block Orthogonalization Procedu...
static Teuchos::RCP< MV > CloneViewNonConst(MV &mv, const std::vector< int > &index)
Creates a new MV that shares the selected contents of mv (shallow copy).
Struct for storing an eigenproblem solution.
RCP< const MV > MX
The image of the current eigenvectors under M, or Teuchos::null if M was not specified.
The Anasazi::TraceMinBaseSolMgr provides an abstract base class for the TraceMin series of solver man...
RCP< const Teuchos::SerialDenseMatrix< int, ScalarType > > RV
The current Ritz vectors.
static Teuchos::RCP< const MV > CloneView(const MV &mv, const std::vector< int > &index)
Creates a new const MV that shares the selected contents of mv (shallow copy).
static void SetBlock(const MV &A, const std::vector< int > &index, MV &mv)
Copy the vectors in A to a set of vectors in mv indicated by the indices given in index...
ScalarType largestSafeShift
Largest safe shift.
RCP< const std::vector< typename Teuchos::ScalarTraits< ScalarType >::magnitudeType > > T
The current Ritz values. This vector is a copy of the internal data.
static void MvAddMv(const ScalarType alpha, const MV &A, const ScalarType beta, const MV &B, MV &mv)
Replace mv with .
RCP< const std::vector< ScalarType > > ritzShifts
Current Ritz shifts.
Teuchos::Array< RCP< Teuchos::Time > > getTimers() const
Return the timers for this object.
Special StatusTest for printing status tests.
A status test for testing the norm of the eigenvectors residuals along with a set of auxiliary eigenv...
RCP< const MV > KX
The image of the current eigenvectors under K.
RCP< const MV > R
The current residual vectors.
RCP< const Teuchos::SerialDenseMatrix< int, ScalarType > > KK
The current projected K matrix.
void setLockingStatusTest(const RCP< StatusTest< ScalarType, MV, OP > > &locking)
Set the status test defining locking.
Status test for forming logical combinations of other status tests.
An implementation of the Anasazi::MatOrthoManager that performs orthogonalization using (potentially)...
Types and exceptions used within Anasazi solvers and interfaces.
int getNumIters() const
Get the iteration count for the most recent call to solve().
const RCP< StatusTest< ScalarType, MV, OP > > & getLockingStatusTest() const
Get the status test defining locking.
This is an abstract base class for the trace minimization eigensolvers.
void setDebugStatusTest(const RCP< StatusTest< ScalarType, MV, OP > > &debug)
Set the status test for debugging.
Anasazi&#39;s templated pure virtual class for managing the sorting of approximate eigenvalues computed b...
const Eigenproblem< ScalarType, MV, OP > & getProblem() const
Return the eigenvalue problem.
Common interface of stopping criteria for Anasazi&#39;s solvers.
A status test for testing the norm of the eigenvectors residuals.
Basic implementation of the Anasazi::OrthoManager class.
Basic implementation of the Anasazi::OrthoManager class.
static Teuchos::RCP< MV > Clone(const MV &mv, const int numvecs)
Creates a new empty MV containing numvecs columns.
Class which provides internal utilities for the Anasazi solvers.