RBGen  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
RBGen_StSVD_RTR.cpp
1 #include "RBGen_StSVD_RTR.h"
2 #include "AnasaziSVQBOrthoManager.hpp"
3 #include "AnasaziBasicOrthoManager.hpp"
6 #include "Epetra_SerialDenseMatrix.h"
7 #include "Epetra_LAPACK.h"
8 #include "Epetra_LocalMap.h"
9 #include "Epetra_Comm.h"
10 #include "Epetra_Vector.h"
11 
12 namespace RBGen {
13 
15  isInitialized_(false),
16  sigma_(0),
17  tol_(1e-12),
18  timerComp_("Total Elapsed Time"),
19  debug_(false),
20  verbLevel_(0),
21  maxScaledNorm_(0.0),
22  Delta0_(0.0),
23  Delta_(0.0),
24  Delta_bar_(0.0),
25  etaLen_(0.0),
26  rhoPrime_(0.1),
27  normGrad0_(0.0),
28  iter_(0),
29  maxOuterIters_(10),
30  maxInnerIters_(-1),
31  conv_kappa_(0.1),
32  conv_theta_(1.0),
33  rho_(0.0),
34  fx_(0.0),
35  m_(0),
36  n_(0),
37  rank_(0),
38  localV_(true),
39  initElem_(false)
40  {
41  // set up array of stop reasons
42  stopReasons_.push_back("n/a");
43  stopReasons_.push_back("maximum iterations");
44  stopReasons_.push_back("negative curvature");
45  stopReasons_.push_back("exceeded TR");
46  stopReasons_.push_back("kappa convergence");
47  stopReasons_.push_back("theta convergence");
48  stopReasons_.push_back("");
49  }
50 
52  {
53  if (isInitialized_ == false) {
54  return Teuchos::null;
55  }
56  return U_;
57  }
58 
60  {
61  if (isInitialized_ == false) {
62  return Teuchos::null;
63  }
64  return V_;
65  }
66 
67  std::vector<double> StSVDRTR::getSingularValues() const
68  {
69  return sigma_;
70  }
71 
75  {
76  using Teuchos::rcp;
77 
78  // Get the "Reduced Basis Method" sublist.
79  Teuchos::ParameterList rbmethod_params = params->sublist( "Reduced Basis Method" );
80 
81  // Get rank
82  rank_ = rbmethod_params.get("Basis Size",(int)5);
83 
84  // Get convergence tolerance
85  tol_ = rbmethod_params.get<double>("Convergence Tolerance",tol_);
86 
87  // Get debugging flag
88  debug_ = rbmethod_params.get<bool>("StSVD Debug",debug_);
89 
90  // Get verbosity level
91  verbLevel_ = rbmethod_params.get<int>("StSVD Verbosity Level",verbLevel_);
92 
93  // Get maximum number of outer iterations
94  maxOuterIters_ = rbmethod_params.get<int>("StSVD Max Outer Iters",maxOuterIters_);
95 
96  // Get maximum number of inner iterations
97  maxInnerIters_ = rbmethod_params.get<int>("StSVD Max Inner Iters",maxInnerIters_);
98 
99  // Get initial trust-region radius
100  Delta0_ = rbmethod_params.get<double>("StSVD Delta0",sqrt(3.0)*rank_);
101 
102  // Is V local or distributed
103  localV_ = rbmethod_params.get<bool>("StSVD Local V",localV_);
104 
105  rhoPrime_ = rbmethod_params.get<double>("StSVD Rho Prime",rhoPrime_);
106  TEUCHOS_TEST_FOR_EXCEPTION(rhoPrime_ <= 0.0 || rhoPrime_ >= .25,
107  std::invalid_argument,
108  "RBGen::StSVDRTR:: Rho Prime must be in (0,1/4)");
109 
110  initElem_ = rbmethod_params.get<bool>("StSVD Init Elementary",initElem_);
111 
112  // Get an Anasazi orthomanager
113  if (rbmethod_params.isType<
114  Teuchos::RCP< Anasazi::OrthoManager<double,Epetra_MultiVector> >
115  >("Ortho Manager")
116  )
117  {
118  ortho_ = rbmethod_params.get<
120  >("Ortho Manager");
121  TEUCHOS_TEST_FOR_EXCEPTION(ortho_ == Teuchos::null,std::invalid_argument,"RBGen::StSVDRTR::User specified null ortho manager.");
122  }
123  else {
124  /*
125  std::string omstr = rbmethod_params.get("Ortho Manager","DGKS");
126  if (omstr == "SVQB") {
127  ortho_ = rcp( new Anasazi::SVQBOrthoManager<double,Epetra_MultiVector,Epetra_Operator>() );
128  }
129  else { // if omstr == "DGKS"
130  ortho_ = rcp( new Anasazi::BasicOrthoManager<double,Epetra_MultiVector,Epetra_Operator>() );
131  }
132  */
133  ortho_ = rcp( new Anasazi::BasicOrthoManager<double,Epetra_MultiVector,Epetra_Operator>() );
134  }
135 
136  // Save the pointer to the snapshot matrix
137  TEUCHOS_TEST_FOR_EXCEPTION(ss == Teuchos::null,std::invalid_argument,"Input snapshot matrix cannot be null.");
138  A_ = ss;
139  // Save dimensions
140  m_ = A_->GlobalLength();
141  n_ = A_->NumVectors();
142 
143  // initialize data structures
144  initialize();
145  }
146 
147  // private initialize
148  void StSVDRTR::initialize()
149  {
150  if (isInitialized_) return;
151 
152  using Teuchos::rcp;
153 
154  // Allocate space for the factorization
155  sigma_.resize( rank_ );
156  U_ = Teuchos::null;
157  V_ = Teuchos::null;
158  U_ = rcp( new Epetra_MultiVector(A_->Map(),rank_,false) );
159  if (localV_) {
160  Epetra_LocalMap lclmap(A_->NumVectors(),0,A_->Comm());
161  V_ = rcp( new Epetra_MultiVector(lclmap,rank_,false) );
162  }
163  else {
164  Epetra_Map vmap(A_->NumVectors(),0,A_->Comm());
165  V_ = rcp( new Epetra_MultiVector(vmap,rank_,false) );
166  }
167  resNorms_.resize(rank_);
168  resUNorms_.resize(rank_);
169  resVNorms_.resize(rank_);
170  // initialize U,V to canonical basis vectors or to random?
171  if (initElem_)
172  {
173  // set to zero
174  U_->PutScalar(0.0);
175  V_->PutScalar(0.0);
176  for (int j=0; j<rank_; j++)
177  {
178  int lid;
179  // set (j,j) to 1
180  // U
181  lid = U_->Map().LID(j);
182  if (lid >= 0) {
183  (*U_)[j][lid] = 1.0;
184  }
185  // V
186  lid = V_->Map().LID(j);
187  if (lid >= 0) {
188  (*V_)[j][lid] = 1.0;
189  }
190  }
191  }
192  else
193  {
194  U_->Random();
195  V_->Random();
196  }
197 
198  // allocate and set N_
199  N_.resize(rank_);
200  for (int j=0; j<rank_; j++) {
201  N_[j] = rank_-j;
202  }
203 
204  // allocate working multivectors
205  // size of U_
206  RU_ = rcp( new Epetra_MultiVector(U_->Map(),rank_,false) );
207  AV_ = rcp( new Epetra_MultiVector(U_->Map(),rank_,false) );
208  etaU_ = rcp( new Epetra_MultiVector(U_->Map(),rank_,false) );
209  HeU_ = rcp( new Epetra_MultiVector(U_->Map(),rank_,false) );
210  deltaU_ = rcp( new Epetra_MultiVector(U_->Map(),rank_,false) );
211  HdU_ = rcp( new Epetra_MultiVector(U_->Map(),rank_,false) );
212  // size of V_
213  RV_ = rcp( new Epetra_MultiVector(V_->Map(),rank_,false) );
214  AU_ = rcp( new Epetra_MultiVector(V_->Map(),rank_,false) );
215  etaV_ = rcp( new Epetra_MultiVector(V_->Map(),rank_,false) );
216  HeV_ = rcp( new Epetra_MultiVector(V_->Map(),rank_,false) );
217  deltaV_ = rcp( new Epetra_MultiVector(V_->Map(),rank_,false) );
218  HdV_ = rcp( new Epetra_MultiVector(V_->Map(),rank_,false) );
219 
220  // allocate working space for DGESVD, UAVNsym, VAUNsym
221  {
222  Epetra_LocalMap lclmap(rank_,0,A_->Comm());
223  dgesvd_A_ = rcp( new Epetra_MultiVector(lclmap,rank_,false) );
224  UAVNsym_ = rcp( new Epetra_MultiVector(lclmap,rank_,false) );
225  VAUNsym_ = rcp( new Epetra_MultiVector(lclmap,rank_,false) );
226  }
227  // finish: get the optimal block size for this
228  dgesvd_work_.resize(5*rank_);
229 
230  // Perform initial factorization
231  // Make U,V orthonormal
232  int ret = ortho_->normalize(*U_);
233  TEUCHOS_TEST_FOR_EXCEPTION(ret != rank_,std::runtime_error,"Initial U basis construction failed.");
234  ret = ortho_->normalize(*V_);
235  TEUCHOS_TEST_FOR_EXCEPTION(ret != rank_,std::runtime_error,"Initial V basis construction failed.");
236  //
237  // StSVD minimizers trace(U'*A*V*N)
238  // and therefore computes (-U,V), where (U,V) are
239  // left/right singular vectors
240  // Use SVD of initial U'*A*V to compute maximal
241  // basis for these subspaces, then flip signs of V
242  // to derive minimal bases for these subspaces
243  {
244  //
245  // Compute U'*A*V via A'*U
246  int info;
247  info = AU_->Multiply('T','N',1.0,*A_,*U_,0.0);
248  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
249  "RBGen::StSVD::initialize(): Error calling Epetra_MultiVector::Muliply.");
250  //
251  // compute (U'*A)*V
252  info = dgesvd_A_->Multiply('T','N',1.0,*AU_,*V_,0.0);
253  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
254  "RBGen::StSVD::initialize(): Error calling Epetra_MultiVector::Muliply.");
255  Epetra_LocalMap lclmap(rank_,0,A_->Comm());
256  Epetra_MultiVector VV(lclmap,rank_);
257  TEUCHOS_TEST_FOR_EXCEPTION(VV.ConstantStride() == false,
258  std::logic_error, "RBGen::StSVD/RTR::initialize(): VV should have constant stride.");
259  //
260  // compute the singular vectors of U'*A*V
261  // note, this computes U (into A) and V^T (into VV)
262  lapack.GESVD('O','A',rank_,rank_,dgesvd_A_->Values(),dgesvd_A_->Stride(),&sigma_[0],
263  NULL,rank_,VV.Values(),VV.Stride(),&dgesvd_work_[0],dgesvd_work_.size(),NULL,&info);
264  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
265  "RBGen::StSVD::initialize(): Error calling GESVD.");
266  Epetra_MultiVector UCopy(*U_), VCopy(*V_);
267  info = U_->Multiply('N','N',-1.0,UCopy,*dgesvd_A_,0.0);
268  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
269  "RBGen::StSVD::initialize(): Error calling Epetra_MultiVector::Muliply.");
270  // recall, VV stores V^T, not V
271  info = V_->Multiply('N','T',1.0,VCopy,VV,0.0);
272  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
273  "RBGen::StSVD::initialize(): Error calling Epetra_MultiVector::Muliply.");
274  }
275 
276  // compute proper AV and AU now
277  {
278  int info;
279  info = AU_->Multiply('T','N',1.0,*A_,*U_,0.0);
280  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
281  "RBGen::StSVD::initialize(): Error calling Epetra_MultiVector::Muliply.");
282  info = AV_->Multiply('N','N',1.0,*A_,*V_,0.0);
283  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
284  "RBGen::StSVD::initialize(): Error calling Epetra_MultiVector::Muliply.");
285  }
286 
287  // compute sigmas, f(x) and UAVNsym,VAUNsym from U,V,AU,AV
288  updateF();
289 
290  // compute residuals
291  updateResiduals();
292 
293  //
294  // we are now initialized, albeit with null rank
295  isInitialized_ = true;
296 
297  if (debug_) {
298  CheckList chk;
299  chk.checkSigma = true;
300  chk.checkUV = true;
301  chk.checkRes = true;
302  chk.checkSyms = true;
303  chk.checkF = true;
304  Debug(chk,", after updateF().");
305  }
306  }
307 
308 
309 
311  // reset with a new snapshot matrix
313  {
314  // Reset the pointer for the snapshot matrix
315  // Note: We will not assume that it is non-null; user could be resetting our
316  // pointer in order to delete the original snapshot set
317  A_ = new_ss;
318  isInitialized_ = false;
319  }
320 
321 
322 
323 
325  // main loop
327  {
328  using std::cout;
329  using std::setprecision;
330  using std::vector;
331  using std::scientific;
332  using std::setw;
333 
334  //
335  // perform enough incremental updates to consume the entire snapshot set
336  Teuchos::TimeMonitor lcltimer(timerComp_);
337 
338  // check that we have a valid snapshot set: user may have cleared
339  // it using Reset()
340  TEUCHOS_TEST_FOR_EXCEPTION(A_ == Teuchos::null,std::logic_error,
341  "computeBasis() requires non-null snapshot set.");
342 
343  //
344  // check that we are initialized, i.e., data structures match the data set
345  initialize();
346 
347  Delta_ = Delta0_;
348  etaLen_ = 0.0;
349  iter_ = 0;
350  numInner_ = -1;
351  rho_ = 0.0;
352  innerStop_ = NOTHING;
353  tradjust_ = "n/a";
354  tiny_rhonum_ = false;
355  zero_rhoden_ = false;
356  neg_rho_ = false;
357 
358  // print initial status
359  printStatus();
360 
361  while ( (maxScaledNorm_ > tol_) && (iter_ < maxOuterIters_) ) {
362 
363  // inc counter
364  ++iter_;
365 
366  // minimize model subproblem
367  //
368  solveTRSubproblem();
369 
370  // debug output from tr subproblem
371  if (debug_) {
372  CheckList chk;
373  chk.checkR = true;
374  chk.checkE = true;
375  chk.checkHE = true;
376  chk.checkElen = true;
377  chk.checkRlen = true;
378  chk.checkEHR = true;
379  Debug(chk,", after call to solveTRSubproblem.");
380  }
381 
382  // some pointers to keep names friendly
383  Teuchos::RCP<Epetra_MultiVector> newU, newV, newAU;
384  // new iterates are stored in deltaU,deltaV
385  // A'*deltaU goes into HdV_
386  newU = deltaU_;
387  newV = deltaV_;
388  newAU = HdV_;
389 
390  // compute proposed point
391  // R_U(eta) = qf(U+eta)
392  // we will store this in deltaU,deltaV
393  *newU = *etaU_;
394  *newV = *etaV_;
395  try {
396  retract(*U_,*V_,*newU,*newV);
397  }
398  catch (std::runtime_error oops) {
399  TEUCHOS_TEST_FOR_EXCEPTION(true,std::runtime_error,
400  "RBGen::StSVD::computeBasis(): Retraction of eta failed.");
401  }
402 
403  //
404  // evaluate rho
405  // f(x) - f(R_x(eta))
406  // rho = -------------------
407  // m_x(eta) - m_x(eta)
408  //
409  // f(x) - f(R_x(eta))
410  // = ------------------------------------
411  // - <eta,Proj(AV,A'U)> - .5 <eta,Heta>
412  //
413  // f(x) - f(R_x(eta))
414  // = --------------------------------
415  // - <eta,(AV,A'U)> - .5 <eta,Heta>
416  //
417  // compute A'*newU into newAU
418  // we don't need A*newV yet
419  {
420  int info;
421  info = newAU->Multiply('T','N',1.0,*A_,*newU,0.0);
422  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
423  "RBGen::StSVD::computeBasis(): Error calling Epetra_MultiVector::Muliply.");
424  }
425  // compute fxnew and rhonum
426  // we don't need sigmas, only trace(newU'*A*newV*N)
427  // trace(newU'*A*newV*N) = sum_i (newU'*A*newV)_ii N[i]
428  // = sum_i <newV[i],(A'newU)[i]> N[i]
429  tiny_rhonum_ = neg_rho_ = zero_rhoden_ = false;
430  double fxnew;
431  {
432  std::vector<double> dots(rank_);
433  newV->Dot(*newAU,&dots[0]);
434  fxnew = 0.0;
435  for (int i=0; i<rank_; i++) {
436  fxnew += dots[i]*N_[i];
437  }
438  }
439  if (debug_) {
440  std::cout << " >> newfx: " << setw(18) << scientific << setprecision(10) << fxnew << std::endl;
441  }
442  rhonum_ = fx_ - fxnew;
443  // tiny rhonum means small decrease in f (maybe even negative small)
444  // this usually happens near the end of convergence;
445  // this is usually not bad; we will pretend it is very good
446  if ( SCT::magnitude(rhonum_/fx_) < 1e-12 ) {
447  tiny_rhonum_ = true;
448  rho_ = 1.0;
449  }
450  else {
451  // compute rhoden
452  // - <eta,(AVN,A'UN)> - .5 <eta,Heta>
453  std::vector<double> ips(rank_);
454  rhoden_ = 0.0;
455  etaU_->Dot(*AV_,&ips[0]);
456  for (int i=0; i<rank_; i++) rhoden_ += -1.0*ips[i]*N_[i];
457  etaV_->Dot(*AU_,&ips[0]);
458  for (int i=0; i<rank_; i++) rhoden_ += -1.0*ips[i]*N_[i];
459  rhoden_ = rhoden_ - 0.5*innerProduct(*etaU_,*etaV_,*HeU_,*HeV_);
460  if (debug_) {
461  std::cout << " >> rhonum: " << rhonum_ << std::endl;
462  std::cout << " >> rhoden: " << rhoden_ << std::endl;
463  }
464  if (rhoden_ == 0) {
465  // this is bad
466  zero_rhoden_ = true;
467  rho_ = -1.0;
468  }
469  else {
470  rho_ = rhonum_ / rhoden_;
471  }
472  }
473  if (rho_ < 0.0) {
474  // this is also bad
475  neg_rho_ = true;
476  }
477 
478  //
479  // accept/reject
480  if (rho_ >= rhoPrime_) {
481  accepted_ = true;
482  // put newx data into x data: U,V,AU,AV,fx,UAVNsym,VAUNsym,sigma
483 
484  // etaU,etaV get thrown away
485  // newU,newV go into U_,V_
486  *U_ = *newU;
487  *V_ = *newV;
488 
489  // newAU goes into AU_
490  // A*V_ gets computed into AV_
491  *AU_ = *newAU;
492  {
493  int info;
494  info = AV_->Multiply('N','N',1.0,*A_,*V_,0.0);
495  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
496  "RBGen::StSVD::computeBasis(): Error calling Epetra_MultiVector::Muliply.");
497  }
498 
499  // compute new sigmas, new f(x) and UAVNsym,VAUNsym from U,V,AU,AV
500  updateF();
501 
502  if (debug_) {
503  // check that new fx_ is equal to fxnew
504  std::cout << " >> new f(x): " << setw(18) << scientific << setprecision(10) << fx_ << std::endl;
505  }
506 
507  // clear those unneeded pointers
508  newU = Teuchos::null;
509  newV = Teuchos::null;
510  newAU = Teuchos::null;
511  }
512  else {
513  accepted_ = false;
514  }
515 
516  //
517  // modify trust-region radius
518  tradjust_ = " ";
519  if (this->rho_ < .25) {
520  Delta_ = .25 * Delta_;
521  tradjust_ = "TR-";
522  }
523  else if (this->rho_ > .75 && (innerStop_ == NEGATIVE_CURVATURE || innerStop_ == EXCEEDED_TR)) {
524  Delta_ = 2.0*Delta_;
525  tradjust_ = "TR+";
526  }
527 
528  //
529  // compute new residuals and norms
530  // this happens whether we accepted or not, because the trust-region solve
531  // destroyed the residual that was in RU,RV
532  updateResiduals();
533 
534  // print status
535  printStatus();
536 
537  // debug checking
538  if (debug_) {
539  CheckList chk;
540  chk.checkSigma = true;
541  chk.checkUV = true;
542  chk.checkRes = true;
543  chk.checkSyms = true;
544  chk.checkF = true;
545  Debug(chk,", in computeBasis().");
546  }
547 
548  } // while (not converged)
549 
550 
551  if (verbLevel_ > 1) {
552  std::cout << "----------------------------------------------------------------" << std::endl;
553  }
554  }
555 
556 
558  // update sigmas, f(x), UAVNsym, VAUNsym
559  // this function assumes that U,V,AU,AV are correct
560  void StSVDRTR::updateF()
561  {
562  //
563  // compute (U'*A)*V
564  {
565  int info;
566  info = dgesvd_A_->Multiply('T','N',1.0,*AU_,*V_,0.0);
567  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
568  "RBGen::StSVD::initialize(): Error calling Epetra_MultiVector::Muliply.");
569  }
570 
571  //
572  // U'*A*V in dgesvd_A_ will be destroyed by GESVD; first, save it
573  // set UAVNsym_ = dgesvd_A_ * N
574  // set VAUNsym_ = dgesvd_A_' * N
575  for (int j=0; j<rank_; j++)
576  {
577  for (int i=0; i<rank_; i++)
578  {
579  (*UAVNsym_)[j][i] = (*dgesvd_A_)[j][i];
580  (*VAUNsym_)[j][i] = (*dgesvd_A_)[i][j];
581  }
582  (*UAVNsym_)(j)->Scale(N_[j]);
583  (*VAUNsym_)(j)->Scale(N_[j]);
584  }
585  // call Sym on both of these
586  Sym(*UAVNsym_);
587  Sym(*VAUNsym_);
588 
589  //
590  // compute f(U,V) = trace(U'*A*V*N) before destroying dgesvd_A_
591  fx_ = 0.0;
592  for (int j=0; j<rank_; j++)
593  {
594  fx_ += (*dgesvd_A_)[j][j] * N_[j];
595  }
596 
597  //
598  // compute the singular values of U'*A*V
599  {
600  int info;
601  lapack.GESVD('N','N',rank_,rank_,dgesvd_A_->Values(),dgesvd_A_->Stride(),&sigma_[0],
602  NULL,rank_,NULL,rank_,&dgesvd_work_[0],dgesvd_work_.size(),NULL,&info);
603  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
604  "RBGen::StSVD::initialize(): Error calling Epetra_MultiVector::Muliply.");
605  }
606  }
607 
608 
609 
611  // update the residuals and norms
612  // this function assumes that U,V,AU,AV,sigma are all coherent
613  void StSVDRTR::updateResiduals()
614  {
615  using std::setw;
616  using std::setprecision;
617  using std::scientific;
618 
619  //
620  // Compute residual norms
621  //
622  // For each singular value, we have two direct residuals:
623  // ru_i = A v_i - u_i s_i
624  // and
625  // rv_i = A' u_i - v_i s_i
626  //
627  // However, recall that StSVD computes (-U,V), so that
628  // our direct residuals are actually
629  // ru_i = A v_i + u_i s_i
630  // and
631  // rv_i = A' u_i + v_i s_i
632  //
633  // If we have a singular triplet, these will both be zero
634  //
635  // We will take the norm of the i-th residual to be
636  // |r_i| = sqrt(|ru_i|^2 + |rv_i|^2)
637  //
638  // We will scale it by the i-th singular value
639  //
640 
641  //
642  // compute residuals: RU = A *V + U*S
643  // RV = A'*U + V*S
644  for (int i=0; i<rank_; i++) {
645  (*RU_)(i)->Update( 1.0, *(*AV_)(i), sigma_[i], *(*U_)(i), 0.0 );
646  (*RV_)(i)->Update( 1.0, *(*AU_)(i), sigma_[i], *(*V_)(i), 0.0 );
647  }
648  //
649  // compute 2-norms of these res. vectors
650  RU_->Norm2(&resUNorms_[0]);
651  RV_->Norm2(&resVNorms_[0]);
652  //
653  // scale by sigmas
654  for (int i=0; i<rank_; i++) {
655  // sigma_ must be >= 0, because it is a singular value
656  // ergo, sigma_ != 0 is equivalent to sigma_ > 0
657  // check sigma_ > 0 instead of sigma_ != 0, so the compiler won't complain
658  // about floating point comparisons
659  if (sigma_[i] > 0.0) {
660  resUNorms_[i] /= sigma_[i];
661  resVNorms_[i] /= sigma_[i];
662  }
663  }
664  if (debug_) {
665  std::cout << " >> Residual norms " << std::endl
666  << " >> U V" << std::endl;
667  // --------------- ---------------
668  for (int i=0; i<rank_; i++) {
669  std::cout << " >> " << setw(15) << scientific << setprecision(6) << resUNorms_[i]
670  << " " << setw(15) << scientific << setprecision(6) << resVNorms_[i]
671  << std::endl;
672  }
673  }
674  maxScaledNorm_ = 0;
675  for (int i=0; i<rank_; i++) {
676  resNorms_[i] = SCT::squareroot(resUNorms_[i]*resUNorms_[i] + resVNorms_[i]*resVNorms_[i]);
677  maxScaledNorm_ = EPETRA_MAX(resNorms_[i],maxScaledNorm_);
678  }
679  }
680 
681 
682 
684  // update the basis with new snapshots: not supported
686  {
687  // perform enough incremental updates to consume the new snapshots
688  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,
689  "RBGen::StSVDRTR::updateBasis(): this routine not yet supported.");
690  }
691 
692 
694  // return residual norms
695  std::vector<double> StSVDRTR::getResNorms()
696  {
697  if (isInitialized_) {
698  return resNorms_;
699  }
700  else {
701  return std::vector<double>(rank_,-1);
702  }
703  }
704 
705 
707  // TR subproblem solver
708  void StSVDRTR::solveTRSubproblem()
709  {
710  // return one of:
711  // MAXIMUM_ITERATIONS
712  // NEGATIVE_CURVATURE
713  // EXCEEDED_TR
714  // KAPPA_CONVERGENCE
715  // THETA_CONVERGENCE
716 
717  using std::cout;
718  using std::endl;
719  using std::setw;
720  using std::setprecision;
721  innerStop_ = MAXIMUM_ITERATIONS;
722 
723  int dim = (n_-rank_)*rank_ + (m_-rank_)*rank_ + (rank_-1)*rank_;
724  if (maxInnerIters_ != -1 && maxInnerIters_ < dim) {
725  dim = maxInnerIters_;
726  }
727  const double D2 = Delta_*Delta_;
728 
729  // CG terms
730  double d_Hd, alpha, beta, r_r, rold_rold;
731  // terms for monitoring the norm of eta
732  double e_e, e_d, d_d, e_e_new;
733  // initial residual norm, used for stopping criteria
734  double r0_norm;
735 
736  // set eta to zero
737  etaU_->PutScalar(0.0);
738  etaV_->PutScalar(0.0);
739  HeU_->PutScalar(0.0);
740  HeV_->PutScalar(0.0);
741  etaLen_ = e_e = 0.0;
742 
743  //
744  // We have two residuals: RU = A *V + U*S
745  // and RV = A'*U + V*S
746  // [see updateResiduals() for more info on this]
747  //
748  // Multiply the residuals in RU and RV by N, yielding
749  // RU = A *V*N + U*S*N
750  // RV = A'*U*N + V*S*N
751  // Note that grad(U,V) = {proj(A *V*N)} = {proj(RU*N)}
752  // {proj(A'*U*N)} = {proj(RV*N)}
753  // because
754  // proj(U*S*N) = 0
755  // proj(V*S*N) = 0
756  // So project RU*N and RV*N (in situ) to yield the gradient
757  // RU = Proj(A *V*N + U*S*N) = Proj(A *V*N)
758  // RV = Proj(A'*U*N + V*S*N) = Proj(A'*U*N)
759  //
760  for (int j=0; j<rank_; j++)
761  {
762  (*RU_)(j)->Scale(N_[j]);
763  (*RV_)(j)->Scale(N_[j]);
764  }
765  Proj(*U_,*V_,*RU_,*RV_);
766 
767  r_r = innerProduct(*RU_,*RV_);
768  d_d = r_r;
769  r0_norm = SCT::squareroot(r_r);
770  // if first outer iteration, save r0_norm as normGrad0_
771  if (iter_ == 0) {
772  normGrad0_ = r0_norm;
773  }
774 
775  // delta = -r
776  deltaU_->Update(-1.0,*RU_,0.0);
777  deltaV_->Update(-1.0,*RV_,0.0);
778  e_d = 0.0; // because eta = 0
779 
780  if (debug_) {
781  CheckList chk;
782  chk.checkR = true;
783  chk.checkD = true;
784  chk.checkElen = true;
785  chk.checkRlen = true;
786  chk.checkEHR = true;
787  chk.checkDHR = true;
788  Debug(chk,", before loop in solveTRSubproblem.");
789  }
790 
791  // the loop
792  numInner_ = 0;
793  for (int i=0; i<dim; ++i) {
794 
795  ++numInner_;
796 
797  // Hdelta = Hess*d
798  Hess(*U_,*V_,*deltaU_,*deltaV_,*HdU_,*HdV_);
799  d_Hd = innerProduct(*deltaU_,*deltaV_,*HdU_,*HdV_);
800 
801  // compute update step
802  alpha = r_r/d_Hd;
803 
804  if (debug_) {
805  double Hd_d = innerProduct(*HdU_,*HdV_,*deltaU_,*deltaV_);
806  std::cout
807  << " >> Inner iteration " << i << std::endl
808  << " >> (r,r) : " << r_r << std::endl
809  << " >> (d,Hd) : " << d_Hd << std::endl
810  << " >> (Hd,d) : " << Hd_d << std::endl
811  << " >> alpha : " << alpha << std::endl;
812  }
813 
814  // <neweta,neweta> = <eta,eta> + 2*alpha*<eta,delta> + alpha*alpha*<delta,delta>
815  e_e_new = e_e + 2.0*alpha*e_d + alpha*alpha*d_d;
816 
817  // check truncation criteria: negative curvature or exceeded trust-region
818  if (d_Hd <= 0 || e_e_new >= D2) {
819  double tau = (-e_d + SCT::squareroot(e_d*e_d + d_d*(D2-e_e))) / d_d;
820  if (debug_) {
821  std::cout << " >> tau : " << tau << std::endl;
822  }
823  // eta = eta + tau*delta
824  etaU_->Update(tau,*deltaU_,1.0);
825  etaV_->Update(tau,*deltaV_,1.0);
826  HeU_->Update(tau,*HdU_,1.0);
827  HeV_->Update(tau,*HdV_,1.0);
828  // if debugging, go ahead and update the residual of the model
829  if (debug_) {
830  RU_->Update(tau,*HdU_,1.0);
831  RV_->Update(tau,*HdV_,1.0);
832  Proj(*U_,*V_,*RU_,*RV_);
833  }
834  if (d_Hd <= 0) {
835  innerStop_ = NEGATIVE_CURVATURE;
836  }
837  else {
838  innerStop_ = EXCEEDED_TR;
839  }
840  etaLen_ = SCT::squareroot(e_e + 2.0*tau*e_d + tau*tau*d_d);
841  break;
842  }
843 
844  // compute new eta == eta + alpha*delta
845  etaU_->Update(alpha,*deltaU_,1.0);
846  etaV_->Update(alpha,*deltaV_,1.0);
847  HeU_->Update(alpha,*HdU_,1.0);
848  HeV_->Update(alpha,*HdV_,1.0);
849  // update its length
850  e_e = e_e_new;
851  etaLen_ = SCT::squareroot(e_e);
852 
853  // update gradient of model
854  RU_->Update(alpha,*HdU_,1.0);
855  RV_->Update(alpha,*HdV_,1.0);
856  Proj(*U_,*V_,*RU_,*RV_);
857 
858  rold_rold = r_r;
859  r_r = innerProduct(*RU_,*RV_);
860  double r_norm = SCT::squareroot(r_r);
861 
862  //
863  // check local convergece
864  //
865  // kappa (linear) convergence
866  // theta (superlinear) convergence
867  //
868  double kconv = r0_norm * conv_kappa_;
869  // some scaling of r0_norm so that it will be less than zero
870  // and theta convergence may actually take over from kappa convergence
871  //double tconv = r0_norm * SCT::pow(r0_norm/normGrad0_,conv_theta_);
872  double tconv = r0_norm * SCT::pow(r0_norm,conv_theta_);
873  double conv = kconv < tconv ? kconv : tconv;
874  if ( r_norm <= conv ) {
875  if (conv == tconv) {
876  innerStop_ = THETA_CONVERGENCE;
877  }
878  else {
879  innerStop_ = KAPPA_CONVERGENCE;
880  }
881  break;
882  }
883 
884  // compute new search direction
885  beta = r_r/rold_rold;
886  deltaU_->Update(-1.0,*RU_,beta);
887  deltaV_->Update(-1.0,*RV_,beta);
888  // update new norms and dots
889  e_d = beta*(e_d + alpha*d_d);
890  d_d = r_r + beta*beta*d_d;
891 
892  if (debug_) {
893  std::cout << " >> computed e_e: " << setw(15) << setprecision(6) << innerProduct(*etaU_,*etaV_)
894  << " e_d: " << setw(15) << setprecision(6) << innerProduct(*etaU_,*etaV_,*deltaU_,*deltaV_)
895  << " d_d: " << setw(15) << setprecision(6) << innerProduct(*deltaU_,*deltaV_) << std::endl;
896  std::cout << " >> cached e_e: " << setw(15) << setprecision(6) << e_e
897  << " e_d: " << setw(15) << setprecision(6) << e_d
898  << " d_d: " << setw(15) << setprecision(6) << d_d << std::endl;
899  CheckList chk;
900  chk.checkR = true;
901  chk.checkD = true;
902  chk.checkE = true;
903  chk.checkHE = true;
904  chk.checkElen = true;
905  chk.checkRlen = true;
906  chk.checkEHR = true;
907  chk.checkDHR = true;
908  Debug(chk,", end of loop in solveTRSubproblem.");
909  }
910 
911  } // end of the inner iteration loop
912 
913  } // end of solveTRSubproblem
914 
915 
917  // routine for doing sym(S) in situ
918  //
919  // sym(S) is .5 (S + S')
920  //
921  void StSVDRTR::Sym( Epetra_MultiVector &S ) const
922  {
923  // set strictly upper tri part of S to 0.5*(S+S')
924  for (int j=0; j < rank_; j++) {
925  for (int i=0; i < j; i++) {
926  S[j][i] += S[i][j];
927  S[j][i] /= 2.0;
928  }
929  }
930  // set lower tri part of S to upper tri part of S
931  for (int j=0; j < rank_-1; j++) {
932  for (int i=j+1; i < rank_; i++) {
933  S[j][i] = S[i][j];
934  }
935  }
936  }
937 
938 
940  // Projection onto tangent plane
941  void StSVDRTR::Proj( const Epetra_MultiVector &xU,
942  const Epetra_MultiVector &xV,
943  Epetra_MultiVector &etaU,
944  Epetra_MultiVector &etaV ) const
945  {
946  // perform etaU = Proj_U etaU
947  // and etaV = Proj_V etaV
948  // where
949  // Proj_X E = (I - X X') E + X skew(X' E)
950  // = E - X (X' E) + .5 X (X' E - E' X)
951  // = E - .5 X (S + S')
952  // and S = X' E
953  int info;
954  static Epetra_LocalMap lclmap(rank_,0,A_->Comm());
955  static Epetra_MultiVector S(lclmap,rank_);
956  info = S.Multiply('T','N',1.0,xU,etaU,0.0);
957  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
958  "RBGen::StSVD::Proj(): Error calling Epetra_MultiVector::Muliply.");
959  // set S = .5 (S + S')
960  Sym(S);
961  // E = E - .5 U (S + S')
962  info = etaU.Multiply('N','N',-1.0,xU,S,1.0);
963  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
964  "RBGen::StSVD::Proj(): Error calling Epetra_MultiVector::Muliply.");
965 
966  info = S.Multiply('T','N',1.0,xV,etaV,0.0);
967  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
968  "RBGen::StSVD::Proj(): Error calling Epetra_MultiVector::Muliply.");
969  // set S = .5(S + S')
970  Sym(S);
971  // E = E - .5 V (S + S')
972  info = etaV.Multiply('N','N',-1.0,xV,S,1.0);
973  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
974  "RBGen::StSVD::Proj(): Error calling Epetra_MultiVector::Muliply.");
975  }
976 
978  // g(eta,eta)
979  double StSVDRTR::innerProduct(
980  const Epetra_MultiVector &etaU,
981  const Epetra_MultiVector &etaV ) const
982  {
983  // g( (etaU,etaV), (etaU,etaV) ) = trace(etaU'*etaU) + trace(etaV'*etaV)
984  std::vector<double> norms(rank_);
985  double ip = 0.0;
986  etaU.Norm2(&norms[0]);
987  for (int i=0; i<rank_; i++) ip += norms[i]*norms[i];
988  etaV.Norm2(&norms[0]);
989  for (int i=0; i<rank_; i++) ip += norms[i]*norms[i];
990  return ip;
991  }
992 
994  // g(eta,zeta)
995  double StSVDRTR::innerProduct(
996  const Epetra_MultiVector &etaU,
997  const Epetra_MultiVector &etaV,
998  const Epetra_MultiVector &zetaU,
999  const Epetra_MultiVector &zetaV ) const
1000  {
1001  // g( (etaU,etaV), (etaU,etaV) ) = trace(etaU'*etaU) + trace(etaV'*etaV)
1002  std::vector<double> ips(rank_);
1003  double ip = 0.0;
1004  etaU.Dot(zetaU,&ips[0]);
1005  for (int i=0; i<rank_; i++) ip += ips[i];
1006  etaV.Dot(zetaV,&ips[0]);
1007  for (int i=0; i<rank_; i++) ip += ips[i];
1008  return ip;
1009  }
1010 
1012  // Retraction, in situ
1013  // R_U(E) = qf(U+E)
1014  void StSVDRTR::retract(
1015  const Epetra_MultiVector &xU,
1016  const Epetra_MultiVector &xV,
1017  Epetra_MultiVector &etaU,
1018  Epetra_MultiVector &etaV ) const
1019  {
1021  if (debug_) {
1022  UR = Teuchos::rcp( new Teuchos::SerialDenseMatrix<int,double>(rank_,rank_) );
1023  VR = Teuchos::rcp( new Teuchos::SerialDenseMatrix<int,double>(rank_,rank_) );
1024  }
1025  int ret;
1026 
1027  etaU.Update(1.0,xU,1.0);
1028  ret = ortho_->normalize(etaU,UR);
1029  TEUCHOS_TEST_FOR_EXCEPTION(ret != rank_,std::runtime_error,
1030  "RBGen::StSVD::retract(): Ortho failure in retraction.");
1031 
1032  etaV.Update(1.0,xV,1.0);
1033  ret = ortho_->normalize(etaV,VR);
1034  TEUCHOS_TEST_FOR_EXCEPTION(ret != rank_,std::runtime_error,
1035  "RBGen::StSVD::retract(): Ortho failure in retraction.");
1036 
1037  if (debug_)
1038  {
1039  // check that this was a QR factorization, and that R has positive diagonals
1040  bool positive;
1041  double tril;
1042 
1043  // check tril(UR)
1044  tril = 0.0;
1045  for (int j=0; j<rank_; j++)
1046  {
1047  for (int i=j+1; i<rank_; i++)
1048  {
1049  tril += SCT::magnitude( (*UR)(i,j) );
1050  }
1051  }
1052  std::cout << " >> norm(tril(UR)): " << tril << std::endl;
1053  // check diag(UR)
1054  positive = true;
1055  for (int j=0; j<rank_; j++) {
1056  if ( (*UR)(j,j) < 0.0 )
1057  {
1058  positive = false;
1059  break;
1060  }
1061  }
1062  std::cout << " >> positive(UR): " << (positive ? "yes" : "no ") << std::endl;
1063 
1064  // check tril(VR)
1065  tril = 0.0;
1066  for (int j=0; j<rank_; j++)
1067  {
1068  for (int i=j+1; i<rank_; i++)
1069  {
1070  tril += SCT::magnitude( (*VR)(i,j) );
1071  }
1072  }
1073  std::cout << " >> norm(tril(VR)): " << tril << std::endl;
1074  // check diag(VR)
1075  positive = true;
1076  for (int j=0; j<rank_; j++) {
1077  if ( (*VR)(j,j) < 0.0 )
1078  {
1079  positive = false;
1080  break;
1081  }
1082  }
1083  std::cout << " >> positive(VR): " << (positive ? "yes" : "no ") << std::endl;
1084  }
1085  }
1086 
1088  // Apply Hessian
1089  //
1090  // The Hessian can be applied as follows
1091  // Hess f_{U,V}(eU,eV) = Proj [ A eV N - eU sym(U' A V N) ]
1092  // [ A' eU N - eV sym(V' A' U N) ]
1093  // We will apply the former as follows:
1094  // 1) Apply A eV into HeU and A' eU into HeV
1095  // 2) Scale HeU and HeV by N
1096  // 3) Compute sym(U' A V N) and sym(V' A' U N) from U' A V (
1097  //
1098  void StSVDRTR::Hess(
1099  const Epetra_MultiVector &xU,
1100  const Epetra_MultiVector &xV,
1101  const Epetra_MultiVector &etaU,
1102  const Epetra_MultiVector &etaV,
1103  Epetra_MultiVector &HetaU,
1104  Epetra_MultiVector &HetaV ) const
1105  {
1106  // HetaU = A etaV
1107  {
1108  int info = HetaU.Multiply('N','N',1.0,*A_,etaV,0.0);
1109  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
1110  "RBGen::StSVD::Hess(): Error calling Epetra_MultiVector::Muliply.");
1111  }
1112  // HetaU = A etaV N
1113  for (int i=0; i<rank_; i++) {
1114  HetaU(i)->Scale(N_[i]);
1115  }
1116  // HetaU = A etaV N - etaU sym(U' A V N)
1117  {
1118  int info = HetaU.Multiply('N','N',-1.0,etaU,*UAVNsym_,1.0);
1119  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
1120  "RBGen::StSVD::Hess(): Error calling Epetra_MultiVector::Muliply.");
1121  }
1122  // HetaV = A' etaU
1123  {
1124  int info = HetaV.Multiply('T','N',1.0,*A_,etaU,0.0);
1125  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
1126  "RBGen::StSVD::Hess(): Error calling Epetra_MultiVector::Muliply.");
1127  }
1128  // HetaV = A' etaU N
1129  for (int i=0; i<rank_; i++) {
1130  HetaV(i)->Scale(N_[i]);
1131  }
1132  // HetaV = A' etaU N - etaV sym(V' A' U N)
1133  {
1134  int info = HetaV.Multiply('N','N',-1.0,etaV,*VAUNsym_,1.0);
1135  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,
1136  "RBGen::StSVD::Hess(): Error calling Epetra_MultiVector::Muliply.");
1137  }
1138  // project
1139  Proj(xU,xV,HetaU,HetaV);
1140  }
1141 
1143  // Debugging checks
1144  //
1145  // check all code invariants
1146  // this is gonna hurt.
1147  //
1148  // checkUV
1149  // U'*U==I, V'*V==I
1150  // checkRes
1151  // RU == A*V - U*S
1152  // RV == A'*U - V*S
1153  // checkSyms
1154  // UAVNSym == sym(U'*A*V*N)
1155  // VAUNSym == sym(V'*A'*U*N)
1156  // checkF
1157  // fx = trace(U'*A*V*N)
1158  // checkSigma
1159  // sigma = svd(U'*A*V)
1160  //
1161  // checkE
1162  // Proj(E) = E
1163  // checkD
1164  // Proj(E) = E
1165  // checkHD
1166  // Proj(HD) = HD
1167  // Hess(D) == HD
1168  // checkR
1169  // Proj(R) = R
1170  // R == Hess(E) + Grad(E)
1171  // checkElen
1172  // sqrt(innerProduct(E,E)) == etaLen
1173  // checkRlen
1174  // print sqrt(innerProduct(R,R))
1175  // checkEHR
1176  // 0 == innerProd(E,R)
1177  // checkDHR
1178  // 0 == innerProd(D,R)
1179  //
1180  void StSVDRTR::Debug(const CheckList &chk, std::string where) const
1181  {
1182  using std::setw;
1183  using std::setprecision;
1184  std::stringstream os;
1185  os.precision(2);
1186  os.setf(std::ios::scientific, std::ios::floatfield);
1187  double tmp;
1188  int info;
1189  Epetra_LocalMap lclmap(rank_,0,A_->Comm());
1190  Epetra_MultiVector AV(*U_);
1191  Epetra_MultiVector AU(*V_);
1192 
1193  os << " >> Debugging checks: iteration " << iter_ << where << std::endl;
1194 
1195  info = AV.Multiply('N','N',1.0,*A_,*V_,0.0);
1196  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error, "RBGen::StSVDRTR::Debug(): error calling Epetra_MultiVector::Multiply for AU.");
1197  info = AU.Multiply('T','N',1.0,*A_,*U_,0.0);
1198  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error, "RBGen::StSVDRTR::Debug(): error calling Epetra_MultiVector::Multiply for AU.");
1199 
1200  if (chk.checkUV) {
1201  tmp = ortho_->orthonormError(*U_);
1202  os << " >> Error in U^H M U == I : " << tmp << std::endl;
1203  tmp = ortho_->orthonormError(*V_);
1204  os << " >> Error in V^H M V == I : " << tmp << std::endl;
1205  // check A products
1206  tmp = Utils::errorEquality(*AV_,AV);
1207  os << " >> Error in A V == AV : " << tmp << std::endl;
1208  tmp = Utils::errorEquality(*AU_,AU);
1209  os << " >> Error in A' U == AU : " << tmp << std::endl;
1210  }
1211 
1212  if (chk.checkSigma) {
1213  Epetra_MultiVector S(lclmap,rank_);
1214  std::vector<double> work(5*rank_), sigma(rank_);
1215  info = S.Multiply('T','N',1.0,*U_,AV,0.0);
1216  TEUCHOS_TEST_FOR_EXCEPTION(info != 0, std::logic_error, "RBGen::StSVDRTR::Debug(): error calling Epetra_MultiVector::Multiply for U'*A*V.");
1217  lapack.GESVD('N','N',rank_,rank_,S.Values(),S.Stride(),&sigma[0],
1218  NULL,rank_,NULL,rank_,&work[0],work.size(),NULL,&info);
1219  TEUCHOS_TEST_FOR_EXCEPTION(info != 0,std::logic_error,"RBGen::StSVDRTR::Debug(): error calling DGESVD.");
1220  os << " >> Stored Sigma Computed Sigma" << std::endl;
1221  for (int i=0; i<rank_; i++) {
1222  os << " >> " << setw(15) << setprecision(6) << sigma_[i] << " "
1223  << setw(15) << setprecision(6) << sigma[i] << std::endl;
1224  }
1225  }
1226 
1227  if (chk.checkSyms) {
1228  }
1229 
1230  if (chk.checkF) {
1231  // finish
1232  }
1233 
1234  if (chk.checkRes) {
1235  // finish
1236  }
1237 
1238  if (chk.checkElen) {
1239  // finish
1240  }
1241 
1242  if (chk.checkRlen) {
1243  // finish
1244  }
1245 
1246  if (chk.checkEHR) {
1247  // finish
1248  }
1249 
1250  if (chk.checkDHR) {
1251  // finish
1252  }
1253 
1254  if (chk.checkE) {
1255  Epetra_MultiVector PiU(*etaU_), PiV(*etaV_);
1256  // check tangency
1257  Proj(*U_,*V_,PiU,PiV);
1258  tmp = Utils::errorEquality(*etaU_,PiU);
1259  os << " >> Error in Pi E_U == E_U : " << tmp << std::endl;
1260  tmp = Utils::errorEquality(*etaV_,PiV);
1261  os << " >> Error in Pi E_V == E_V : " << tmp << std::endl;
1262  }
1263 
1264  if (chk.checkHE) {
1265  Epetra_MultiVector PiU(*HeU_), PiV(*HeV_);
1266  Epetra_MultiVector HU(*HeU_), HV(*HeV_);
1267  // check tangency
1268  Proj(*U_,*V_,PiU,PiV);
1269  tmp = Utils::errorEquality(*HeU_,PiU);
1270  os << " >> Error in Pi H E_U == H E_U : " << tmp << std::endl;
1271  tmp = Utils::errorEquality(*HeV_,PiV);
1272  os << " >> Error in Pi H E_V == H E_V : " << tmp << std::endl;
1273  // check value
1274  Hess(*U_,*V_,*etaU_,*etaV_,HU,HV);
1275  tmp = Utils::errorEquality(*HeU_,HU);
1276  os << " >> Error in H D_U == HD_U : " << tmp << std::endl;
1277  tmp = Utils::errorEquality(*HeV_,HV);
1278  os << " >> Error in H D_V == HD_V : " << tmp << std::endl;
1279  }
1280 
1281  if (chk.checkD) {
1282  Epetra_MultiVector PiU(*deltaU_), PiV(*deltaV_);
1283  // check tangency
1284  Proj(*U_,*V_,PiU,PiV);
1285  tmp = Utils::errorEquality(*deltaU_,PiU);
1286  os << " >> Error in Pi D_U == D_U : " << tmp << std::endl;
1287  tmp = Utils::errorEquality(*deltaV_,PiV);
1288  os << " >> Error in Pi D_V == D_V : " << tmp << std::endl;
1289  }
1290 
1291  if (chk.checkHD) {
1292  Epetra_MultiVector PiU(*HdU_), PiV(*HdV_);
1293  Epetra_MultiVector HU(*HdU_), HV(*HdV_);
1294  // check tangency
1295  Proj(*U_,*V_,PiU,PiV);
1296  tmp = Utils::errorEquality(*HdU_,PiU);
1297  os << " >> Error in Pi H D_U == H D_U : " << tmp << std::endl;
1298  tmp = Utils::errorEquality(*HdV_,PiV);
1299  os << " >> Error in Pi H D_V == H D_V : " << tmp << std::endl;
1300  // check value
1301  Hess(*U_,*V_,*deltaU_,*deltaV_,HU,HV);
1302  tmp = Utils::errorEquality(*HdU_,HU);
1303  os << " >> Error in H D_U == HD_U : " << tmp << std::endl;
1304  tmp = Utils::errorEquality(*HdV_,HV);
1305  os << " >> Error in H D_V == HD_V : " << tmp << std::endl;
1306  // minor check of symmetry
1307  double d_Hd, Hd_d;
1308  Hd_d = innerProduct(*HdU_,*HdV_,*deltaU_,*deltaV_);
1309  d_Hd = innerProduct(*deltaU_,*deltaV_,*HdU_,*HdV_);
1310  os << " >> Hd_d : " << Hd_d
1311  << " \t\t d_Hd : " << d_Hd << std::endl;
1312  }
1313 
1314  if (chk.checkR) {
1315  Epetra_MultiVector PiU(*RU_), PiV(*RV_);
1316  Epetra_MultiVector GU(AV), GV(AU);
1317  Epetra_MultiVector HU(*RU_), HV(*RV_);
1318  // check tangency
1319  Proj(*U_,*V_,PiU,PiV);
1320  tmp = Utils::errorEquality(*RU_,PiU);
1321  os << " >> Error in Pi R_U == R_U : " << tmp << std::endl;
1322  tmp = Utils::errorEquality(*RV_,PiV);
1323  os << " >> Error in Pi R_V == R_V : " << tmp << std::endl;
1324  // check value: R = grad + H[eta]
1325  // compute H[eta]
1326  Hess(*U_,*V_,*etaU_,*etaV_,HU,HV);
1327  // compute grad
1328  for (int j=0; j<rank_; j++) {
1329  GU(j)->Scale(N_[j]);
1330  GV(j)->Scale(N_[j]);
1331  }
1332  Proj(*U_,*V_,GU,GV);
1333  // add them
1334  GU.Update(1.0,HU,1.0);
1335  GV.Update(1.0,HV,1.0);
1336  // check against RU,RV
1337  tmp = Utils::errorEquality(*RU_,GU);
1338  os << " >> Error in (model res)_U == R_U : " << tmp << std::endl;
1339  tmp = Utils::errorEquality(*RV_,GV);
1340  os << " >> Error in (model res)_V == R_V : " << tmp << std::endl;
1341  }
1342 
1343  std::cout << os.str() << std::endl;
1344  }
1345 
1346  void StSVDRTR::printStatus() const
1347  {
1348  using std::cout;
1349  using std::setprecision;
1350  using std::vector;
1351  using std::scientific;
1352  using std::setw;
1353 
1354  // status printing
1355  if (verbLevel_ == 1) {
1356  // one line
1357  // acc TR+ k: %5d num_inner: %5d f: %e |grad|: %e stop_reason
1358  if (iter_) {
1359  std::cout << (accepted_ ? "accept" : "REJECT");
1360  }
1361  else {
1362  std::cout << "<init>";
1363  }
1364  std::cout << " " << tradjust_
1365  << " k: " << setw(5) << iter_
1366  << " num_inner: ";
1367  if (numInner_ == -1) {
1368  std::cout << " n/a";
1369  }
1370  else {
1371  std::cout << setw(5) << numInner_;
1372  }
1373  std::cout << " f(x): " << setw(18) << scientific << setprecision(10) << fx_
1374  << " |res|: " << setw(18) << scientific << setprecision(10) << maxScaledNorm_
1375  << " " << stopReasons_[innerStop_] << std::endl;
1376  }
1377  else if (verbLevel_ > 1) {
1378  std::cout << "----------------------------------------------------------------" << std::endl;
1379  // multiline
1380  // 1:acc TR+ k: %5d num_inner: %5d stop_reason
1381  if (iter_) {
1382  std::cout << (accepted_ ? "accept" : "REJECT");
1383  }
1384  else {
1385  std::cout << "<init>";
1386  }
1387  std::cout << " " << tradjust_
1388  << " k: " << setw(5) << iter_
1389  << " num_inner: ";
1390  if (numInner_ == -1) {
1391  std::cout << " n/a ";
1392  }
1393  else {
1394  std::cout << setw(5) << numInner_;
1395  }
1396  std::cout << " " << stopReasons_[innerStop_] << std::endl;
1397  // 2: f(x) : %e |res| : %e
1398  std::cout << " f(x) : " << setw(18) << scientific << setprecision(10) << fx_
1399  << " |res|: " << setw(18) << scientific << setprecision(10) << maxScaledNorm_ << std::endl;
1400  // 3: Delta : %e |eta| : %e
1401  std::cout << " Delta : " << setw(18) << scientific << setprecision(10) << Delta_
1402  << " |eta| : " << setw(18) << scientific << setprecision(10) << etaLen_ << std::endl;
1403  if (neg_rho_) {
1404  // 4: NEGATIVE rho : %e
1405  std::cout << " NEGATIVE rho : " << setw(18) << scientific << setprecision(10) << rho_ << std::endl;
1406  }
1407  else if (tiny_rhonum_) {
1408  // 4: VERY SMALL rho_num : %e
1409  std::cout << " VERY SMALL rho_num : " << setw(18) << scientific << setprecision(10) << rhonum_ << std::endl;
1410  }
1411  else if (zero_rhoden_) {
1412  // 4: ZERO rho_den : %e
1413  std::cout << " ZERO rho_den : " << setw(18) << scientific << setprecision(10) << rhoden_ << std::endl;
1414  }
1415  else {
1416  // 4: rho : %e
1417  std::cout << " rho : " << setw(18) << scientific << setprecision(10) << rho_ << std::endl;
1418  }
1419  }
1420  }
1421 
1422 } // end of RBGen namespace
std::vector< double > getSingularValues() const
Return the singular values.
T & get(const std::string &name, T def_value)
void updateBasis(const Teuchos::RCP< Epetra_MultiVector > &update_ss)
Update the current basis using a new set of snapshots.
static T squareroot(T x)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
std::vector< double > getResNorms()
Return the scaled residual norms.
static T pow(T x, T y)
void Reset(const Teuchos::RCP< Epetra_MultiVector > &new_ss)
Reset the snapshot set used to compute the reduced basis.
StSVDRTR()
Default constructor.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void GESVD(const char JOBU, const char JOBVT, const OrdinalType m, const OrdinalType n, ScalarType *A, const OrdinalType lda, MagnitudeType *S, ScalarType *U, const OrdinalType ldu, ScalarType *V, const OrdinalType ldv, ScalarType *WORK, const OrdinalType lwork, MagnitudeType *RWORK, OrdinalType *info) const
void computeBasis()
Computes bases for the left and (optionally) right singular subspaces, along with singular vaues...
static magnitudeType magnitude(T a)
bool isType(const std::string &name) const
ParameterList & sublist(const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
Teuchos::RCP< const Epetra_MultiVector > getRightBasis() const
Return a basis for the right singular subspace.
Teuchos::RCP< const Epetra_MultiVector > getBasis() const
Return a basis for the left singular subspace.
void Initialize(const Teuchos::RCP< Teuchos::ParameterList > &params, const Teuchos::RCP< const Epetra_MultiVector > &init, const Teuchos::RCP< RBGen::FileIOHandler< Epetra_Operator > > &fileio=Teuchos::null)
Initialize the method with the given parameter list and snapshot set.