Anasazi.cxx
1 // Copyright (C) 2013 Marc DuruflĂ©
2 //
3 // This file is part of the linear-algebra library Seldon,
4 // http://seldon.sourceforge.net/.
5 //
6 // Seldon is free software; you can redistribute it and/or modify it under the
7 // terms of the GNU Lesser General Public License as published by the Free
8 // Software Foundation; either version 2.1 of the License, or (at your option)
9 // any later version.
10 //
11 // Seldon is distributed in the hope that it will be useful, but WITHOUT ANY
12 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
14 // more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public License
17 // along with Seldon. If not, see http://www.gnu.org/licenses/.
18 
19 #ifndef SELDON_FILE_ANASAZI_CXX
20 
21 // not working for latest releases of Trilinos
22 #include "Anasazi.hxx"
23 
24 #include "AnasaziConfigDefs.hpp"
25 #include "AnasaziBasicEigenproblem.hpp"
26 #include "AnasaziLOBPCG.hpp"
27 #include "AnasaziLOBPCGSolMgr.hpp"
28 #include "AnasaziBlockDavidson.hpp"
29 #include "AnasaziBlockDavidsonSolMgr.hpp"
30 #include "AnasaziBlockKrylovSchur.hpp"
31 #include "AnasaziBlockKrylovSchurSolMgr.hpp"
32 #include "AnasaziBasicSort.hpp"
33 #include "AnasaziBasicOutputManager.hpp"
34 #include "Teuchos_CommandLineProcessor.hpp"
35 // #include "AnasaziEpetraAdapter.hpp"
36 #include "AnasaziMVOPTester.hpp"
37 
38 #ifdef SELDON_WITH_MPI
39 //#include "Epetra_MpiComm.h"
40 #else
41 //#include "Epetra_SerialComm.h"
42 #endif
43 
44 // #include "Epetra_Map.h"
45 
46 // templated multivector
47 #include "AnasaziMultiVec.hpp"
48 #include "MyMultiVec.hpp"
49 #include "AnasaziOperator.hpp"
50 #include "Teuchos_BLAS.hpp"
51 
52 namespace Anasazi
53 {
54  using namespace std;
55 
56  template<class EigenPb, class T>
57  class OperatorAnasaziEigen : public Operator<T>
58  {
59  public :
61  EigenPb& var_eig;
64  enum {OPERATOR_A, OPERATOR_M, OPERATOR_OP};
65 
66  OperatorAnasaziEigen(EigenPb& var, int type);
67 
68  void Apply(const MultiVec<T>& X0, MultiVec<T>& Y0) const;
69 
70  };
71 
72 }
73 
74 namespace Anasazi
75 {
76 
78  template<class EigenPb, class T>
80  ::OperatorAnasaziEigen(EigenPb& var, int type) : Operator<T>(), var_eig(var)
81  {
82  type_operator = type;
83  }
84 
85 
87  template<class EigenPb, class T>
89  ::Apply(const MultiVec<T>& X0, MultiVec<T>& Y0) const
90  {
91  const MyMultiVec<T>& X = static_cast<const MyMultiVec<T>& >(X0);
92  MyMultiVec<T>& Y = static_cast<MyMultiVec<T>& >(Y0);
93  int n = X.GetVecLength();
94  int nvecs = X.GetNumberVecs();
95 
96  Seldon::Vector<T> xvec, yvec, xvec0;
97  xvec.Reallocate(n);
98  switch (type_operator)
99  {
100  case OPERATOR_A :
101  case OPERATOR_OP :
102  // loop over vectors
103  for (int p = 0; p < nvecs; p++)
104  {
105  T* y = Y[p];
106  T* x = X[p];
107  xvec0.SetData(n, x);
108  Copy(xvec0, xvec);
109  yvec.SetData(n, y);
110 
111  if (var_eig.DiagonalMass() || var_eig.UseCholeskyFactoForMass())
112  {
113  // standard eigenvalue problem
114  if (var_eig.GetComputationalMode() == var_eig.REGULAR_MODE)
115  {
116  if (var_eig.DiagonalMass())
117  var_eig.MltInvSqrtDiagonalMass(xvec);
118  else
119  var_eig.SolveCholeskyMass(Seldon::SeldonTrans, xvec);
120 
121  var_eig.MltStiffness(xvec, yvec);
122 
123  if (var_eig.DiagonalMass())
124  var_eig.MltInvSqrtDiagonalMass(yvec);
125  else
126  var_eig.SolveCholeskyMass(Seldon::SeldonNoTrans, yvec);
127  }
128  else
129  {
130  if (var_eig.DiagonalMass())
131  var_eig.MltSqrtDiagonalMass(xvec);
132  else
133  var_eig.MltCholeskyMass(Seldon::SeldonNoTrans, xvec);
134 
135  var_eig.ComputeSolution(xvec, yvec);
136 
137  if (var_eig.DiagonalMass())
138  var_eig.MltSqrtDiagonalMass(yvec);
139  else
140  var_eig.MltCholeskyMass(Seldon::SeldonTrans, yvec);
141  }
142  }
143  else
144  {
145  if (var_eig.GetComputationalMode() == var_eig.INVERT_MODE)
146  {
147  if (var_eig.GetTypeSpectrum() != var_eig.CENTERED_EIGENVALUES)
148  {
149  var_eig.MltStiffness(xvec0, xvec);
150  var_eig.ComputeSolution(xvec, yvec);
151  }
152  else
153  {
154  var_eig.MltMass(xvec0, xvec);
155  var_eig.ComputeSolution(xvec, yvec);
156  }
157  }
158  else if (var_eig.GetComputationalMode() == var_eig.REGULAR_MODE)
159  {
160  var_eig.MltStiffness(xvec0, yvec);
161  }
162  else
163  {
164  cout << "not implemented " << endl;
165  abort();
166  }
167  }
168 
169  var_eig.IncrementProdMatVect();
170 
171  xvec0.Nullify();
172  yvec.Nullify();
173  }
174  break;
175  case OPERATOR_M :
176  // loop over vectors
177  for (int p = 0; p < nvecs; p++)
178  {
179  T* y = Y[p];
180  T* x = X[p];
181  xvec.SetData(n, x);
182  yvec.SetData(n, y);
183 
184  if (var_eig.DiagonalMass() || var_eig.UseCholeskyFactoForMass())
185  Copy(xvec, yvec);
186  else
187  {
188  if (var_eig.GetComputationalMode() == var_eig.INVERT_MODE)
189  Copy(xvec, yvec);
190  else
191  var_eig.MltMass(xvec, yvec);
192  }
193 
194  xvec.Nullify();
195  yvec.Nullify();
196  }
197  break;
198  default :
199  {
200  cout << "Unknown operator " << endl;
201  abort();
202  }
203  break;
204  }
205  }
206 
207 }
208 
209 namespace Seldon
210 {
211 
213  template<class T>
214  void SetComplexEigenvalue(const T& x, const T& y, T& z, T& zimag)
215  {
216  z = x; zimag = y;
217  }
218 
219 
221  template<class T>
222  void SetComplexEigenvalue(const T& x, const T& y, complex<T>& z, complex<T>& zimag)
223  {
224  z = complex<T>(x, y);
225  zimag = 0;
226  }
227 
228 
230 
235 #ifdef SELDON_WITH_VIRTUAL
236  template<class T>
237  void FindEigenvaluesAnasazi(EigenProblem_Base<T>& var,
238  Vector<T>& eigen_values,
239  Vector<T>& lambda_imag,
240  Matrix<T, General, ColMajor>& eigen_vectors)
241 #else
242  template<class EigenProblem, class T, class Allocator1,
243  class Allocator2, class Allocator3>
244  void FindEigenvaluesAnasazi(EigenProblem& var,
245  Vector<T, VectFull, Allocator1>& eigen_values,
246  Vector<T, VectFull, Allocator2>& lambda_imag,
248 #endif
249  {
250  int n = var.GetM();
251  string which("LM");
252  switch (var.GetTypeSorting())
253  {
254  case EigenProblem_Base<T>::SORTED_REAL : which = "LR"; break;
255  case EigenProblem_Base<T>::SORTED_IMAG : which = "LI"; break;
256  case EigenProblem_Base<T>::SORTED_MODULUS : which = "LM"; break;
257  }
258 
259  if (var.GetTypeSpectrum() == var.SMALL_EIGENVALUES)
260  {
261  switch (var.GetTypeSorting())
262  {
263  case EigenProblem_Base<T>::SORTED_REAL : which = "SR"; break;
264  case EigenProblem_Base<T>::SORTED_IMAG : which = "SI"; break;
265  case EigenProblem_Base<T>::SORTED_MODULUS : which = "SM"; break;
266  }
267  }
268 
269  // initializaing of computation
270  T shiftr = var.GetShiftValue(), shifti = var.GetImagShiftValue();
271  T zero, one;
272  SetComplexZero(zero);
273  SetComplexOne(one);
274 
275  int print_level = var.GetPrintLevel();
276  AnasaziParam& param = var.GetAnasaziParameters();
277  int solver = param.GetEigensolverType();
278 
279  typedef Anasazi::MultiVec<T> MV;
280 
281  int nev = var.GetNbAskedEigenvalues();
282  int nb_blocks = param.GetNbBlocks();
283  int blockSize = var.GetNbArnoldiVectors();
284  int maxIters = var.GetNbMaximumIterations();
285  int maxRestarts = param.GetNbMaximumRestarts();
286  typename ClassComplexType<T>::Treal tol = var.GetStoppingCriterion();
287 
288  // Create parameter list to pass into solver
289  Teuchos::ParameterList MyPL;
290  MyPL.set("Which", which);
291  MyPL.set("Block Size", blockSize);
292  MyPL.set("Maximum Iterations", maxIters);
293 
294  // orthogonalisation manager : DGKS or SVQB
295  if (param.GetOrthoManager() == param.ORTHO_SVQB)
296  MyPL.set("Orthogonalization", "SVQB");
297  else
298  MyPL.set("Orthogonalization", "DGKS");
299 
300  MyPL.set("Verbosity", print_level);
301  MyPL.set("Convergence Tolerance", tol);
302 
303  // MyPL.set("Relative Convergence Tolerance", tol);
304  // MyPL.set("Convergence Norm", "2");
305  // MyPL.set("Use Locking", useLocking_);
306  // MyPL.set("Relative Locking Tolerance", rellocktol_);
307  // locktol_ = convtol_/10;
308  // MyPL.set("Locking Tolerance", locktol_);
309  // MyPL.set("Locking Norm", "2"));
310  // MyPL.set("Max Locked", maxLocked_);
311  // MyPL.set("Locking Quorum", lockQuorum_);
312  // MyPL.set("Full Ortho",fullOrtho_);
313 
314  // parameters relative to BlockDavidson and BlockKrylovSchur
315  MyPL.set("Num Blocks", nb_blocks);
316  //MyPL.set("Num Restart Blocks", nb_blocks-1);
317  MyPL.set("Maximum Restarts", maxRestarts);
318  //MyPL.set("In Situ Restarting", string());
319 
320  // parameters relative to BlockKrylovSchur
321  // MyPL.set("Extra NEV Blocks", 0);
322  // MyPL.set("Dynamic Extra NEV", string())
323  // MyPL.set("Step Size", 0);
324  // MyPL.get("Orthogonalization Constant", kappa);
325 
326  // Create initial vectors
327  //cout << "Calcul valeurs propres Anasazi" << endl;
328  Teuchos::RCP<MV> ivec = Teuchos::rcp( new Anasazi::MyMultiVec<T>(n, blockSize) );
329  ivec->MvRandom();
330 
332  typedef Anasazi::Operator<T> OP;
333  Teuchos::RCP<const OP> A, M, Op;
334  A = Teuchos::rcp(new Anasazi::OperatorAnasaziEigen
335  <EigenProblem_Base<T>, T>(var, OPsub::OPERATOR_A));
336 
337  M = Teuchos::rcp(new Anasazi::OperatorAnasaziEigen
338  <EigenProblem_Base<T>, T>(var, OPsub::OPERATOR_M));
339 
340  Op = Teuchos::rcp(new Anasazi::OperatorAnasaziEigen
341  <EigenProblem_Base<T>, T>(var, OPsub::OPERATOR_OP));
342 
343  // Create eigenproblem
344  Teuchos::RCP<Anasazi::BasicEigenproblem<T, MV, OP> > MyProblem;
345  if (solver == param.SOLVER_LOBPCG || solver == param.SOLVER_BD)
346  MyProblem = Teuchos::rcp( new Anasazi::BasicEigenproblem<T, MV, OP>(A, M, ivec) );
347  else
348  MyProblem = Teuchos::rcp( new Anasazi::BasicEigenproblem<T, MV, OP>(Op, M, ivec) );
349 
350  // Inform the eigenproblem that the operator A is symmetric
351  bool isherm = var.IsHermitianProblem();
352 
353  // Set the number of eigenvalues requested and the blocksize the solver should use
354  MyProblem->setNEV(nev);
355 
356  if (var.DiagonalMass() || var.UseCholeskyFactoForMass())
357  {
358  // solving a standard eigenvalue problem
359  if (var.DiagonalMass())
360  {
361  // computation of M
362  var.ComputeDiagonalMass();
363 
364  // computation of M^{-1/2}
365  var.FactorizeDiagonalMass();
366  }
367  else
368  {
369  // computation of M for Cholesky factorisation
370  var.ComputeMassForCholesky();
371 
372  // computation of Cholesky factorisation M = L L^T
373  var.FactorizeCholeskyMass();
374  }
375 
376  if (var.GetComputationalMode() == var.REGULAR_MODE)
377  {
378  // computation of the stiffness matrix
379  var.ComputeStiffnessMatrix();
380  }
381  else
382  {
383  // computation and factorization of K - sigma M
384  var.ComputeAndFactorizeStiffnessMatrix(-shiftr, one);
385  }
386  }
387  else
388  {
389  if (var.GetComputationalMode() == var.INVERT_MODE)
390  {
391  // we consider standard problem M^-1 K U = lambda U
392  // drawback : the matrix is non-symmetric even if K and M are symmetric
393  isherm = false;
394  if (var.GetTypeSpectrum() != var.CENTERED_EIGENVALUES)
395  {
396  // large eigenvalues of M^-1 K
397  // computation and factorisation of mass matrix
398  var.ComputeAndFactorizeStiffnessMatrix(one, zero);
399 
400  // computation of stiffness matrix
401  var.ComputeStiffnessMatrix();
402  }
403  else
404  {
405  // large eigenvalues of (K - sigma M)^-1 M
406  // computation and factorization of (K - sigma M)
407  var.ComputeAndFactorizeStiffnessMatrix(-shiftr, one);
408 
409  // computation of M
410  var.ComputeMassMatrix();
411  }
412  }
413  else if (var.GetComputationalMode() == var.REGULAR_MODE)
414  {
415  if (solver == param.SOLVER_BKS)
416  {
417  cout << "generalized eigenproblem not implemented for this solver" << endl;
418  abort();
419  }
420 
421  // factorization of the mass matrix
422  // var.ComputeAndFactorizeStiffnessMatrix(one, zero);
423 
424  // computation of stiffness and mass matrix
425  var.ComputeStiffnessMatrix();
426  var.ComputeMassMatrix();
427 
428  }
429  else
430  {
431  cout << "not implemented " << endl;
432  abort();
433  }
434  }
435 
436  if (!isherm)
437  {
438  if (solver != param.SOLVER_BKS)
439  {
440  cout << "Only Block-Krylov Schur (SOLVER_BKS) "
441  << " can be used for nonsymmetric system" << endl;
442  abort();
443  }
444  }
445 
446  MyProblem->setHermitian(isherm);
447 
448  // Inform the eigenproblem that you are done passing it information
449  bool pb_set = MyProblem->setProblem();
450  if (!pb_set)
451  {
452  cout << "Anasazi::BasicEigenproblem::SetProblem() failed "<< endl;
453  abort();
454  }
455 
456  // Create the eigensolver
457  Teuchos::RCP< Anasazi::SolverManager<T, MV, OP> > MySolver;
458  if (solver == param.SOLVER_LOBPCG)
459  MySolver = Teuchos::rcp( new Anasazi::LOBPCGSolMgr<T, MV, OP>(MyProblem, MyPL));
460  else if (solver == param.SOLVER_BKS)
461  MySolver = Teuchos::rcp( new Anasazi::BlockKrylovSchurSolMgr<T, MV, OP>
462  (MyProblem, MyPL));
463  else if (solver == param.SOLVER_BD)
464  MySolver = Teuchos::rcp( new Anasazi::BlockDavidsonSolMgr<T, MV, OP>
465  (MyProblem, MyPL));
466  else
467  {
468  cout << "Invalid Anasazi solver: " << solver << endl;
469  abort();
470  }
471 
472  // Solve the problem to the specified tolerances or length
473  int returnCode = MySolver->solve();
474  if (returnCode != Anasazi::Converged)
475  {
476  cout << "Anasazi's solver did not converge" << endl;
477  abort();
478  }
479 
480  // Get the eigenvalues and eigenvectors from the eigenproblem
481  const Anasazi::Eigensolution<T, MV>& sol = MyProblem->getSolution();
482 
483  eigen_values.Reallocate(sol.Evals.size());
484  lambda_imag.Reallocate(sol.Evals.size());
485  eigen_vectors.Reallocate(n, sol.Evals.size());
486  typename ClassComplexType<T>::Treal lr, li;
487  //typename ClassComplexType<T>::Tcplx Iwp(0, 1), mu;
488  //typename ClassComplexType<T>::Tcplx shift = shiftr + Iwp*shifti;
489  for (unsigned int i = 0; i < sol.Evals.size(); i++)
490  {
491  lr = realpart(sol.Evals[i].realpart);
492  li = realpart(sol.Evals[i].imagpart);
493 
494  SetComplexEigenvalue(lr, li, eigen_values(i), lambda_imag(i));
495 
496  T* x = static_cast<Anasazi::MyMultiVec<T>& >(*sol.Evecs)[i];
497  for (int j = 0; j < n; j++)
498  eigen_vectors(j, i) = x[j];
499  }
500 
501  // modifies eigenvalues and eigenvectors if needed
502  ApplyScalingEigenvec(var, eigen_values, lambda_imag, eigen_vectors,
503  shiftr, shifti);
504 
505  // clears eigenproblem
506  var.Clear();
507  }
508 
509 }
510 
511 #define SELDON_FILE_ANASAZI_CXX
512 #endif
Anasazi::OperatorAnasaziEigen
Definition: Anasazi.cxx:57
Seldon::Vector< T >
Anasazi::OperatorAnasaziEigen::var_eig
EigenPb & var_eig
reference to the object containing eigenproblem data
Definition: Anasazi.cxx:61
Seldon::Matrix
Definition: SeldonHeader.hxx:226
Seldon::AnasaziParam::GetNbMaximumRestarts
int GetNbMaximumRestarts() const
returns the restart parameter used in blocked solvers
Definition: VirtualEigenvalueSolver.cxx:42
Seldon::FindEigenvaluesAnasazi
void FindEigenvaluesAnasazi(EigenProblem &var, Vector< T, VectFull, Allocator1 > &eigen_values, Vector< T, VectFull, Allocator2 > &lambda_imag, Matrix< T, General, ColMajor, Allocator3 > &eigen_vectors)
computation of eigenvalues and related eigenvectors
Definition: Anasazi.cxx:244
Seldon::SetComplexEigenvalue
void SetComplexEigenvalue(const T &x, const T &y, T &z, T &zimag)
real case, z = x, zimag = y
Definition: Anasazi.cxx:214
Anasazi::MyMultiVec
Simple example of a user's defined Anasazi::MultiVec class.
Definition: MyMultiVec.hpp:19
Seldon::AnasaziParam::GetNbBlocks
int GetNbBlocks() const
returns the number of blocks used in blocked solvers
Definition: VirtualEigenvalueSolver.cxx:28
Seldon::AnasaziParam::GetEigensolverType
int GetEigensolverType() const
returns the solver used in Anasazi
Definition: VirtualEigenvalueSolver.cxx:63
Seldon::AnasaziParam::GetOrthoManager
int GetOrthoManager() const
returns orthogonalization manager set in Anasazi
Definition: VirtualEigenvalueSolver.cxx:56
Seldon::AnasaziParam
Parameters for Anasazi package.
Definition: VirtualEigenvalueSolver.hxx:21
Anasazi::OperatorAnasaziEigen::type_operator
int type_operator
operator stored (M, A, Op)
Definition: Anasazi.cxx:63
Seldon::EigenProblem_Base
Base class to solve an eigenvalue problem.
Definition: EigenvalueSolver.hxx:18
Anasazi::OperatorAnasaziEigen::Apply
void Apply(const MultiVec< T > &X0, MultiVec< T > &Y0) const
computes Y0 = Operator X0
Definition: Anasazi.cxx:89
Seldon::EigenProblem_Base::GetShiftValue
T GetShiftValue() const
returns the shift value used
Definition: EigenvalueSolver.cxx:274
Seldon
Seldon namespace.
Definition: Array.cxx:24
Seldon::ApplyScalingEigenvec
void ApplyScalingEigenvec(EigenPb &var, Vector1 &eigen_values, Vector1 &lambda_imag, Matrix1 &eigen_vectors, const T0 &shiftr, const T0 &shifti)
modification of eigenvectors to take into account scaling by mass matrix
Definition: EigenvalueSolver.cxx:846
Anasazi::OperatorAnasaziEigen::OperatorAnasaziEigen
OperatorAnasaziEigen(EigenPb &var, int type)
constructor with the eigenproblem
Definition: Anasazi.cxx:80