Anasazi  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
AnasaziBasicOrthoManager.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 
47 #ifndef ANASAZI_BASIC_ORTHOMANAGER_HPP
48 #define ANASAZI_BASIC_ORTHOMANAGER_HPP
49 
57 #include "AnasaziConfigDefs.hpp"
61 #include "Teuchos_TimeMonitor.hpp"
62 #include "Teuchos_LAPACK.hpp"
63 #include "Teuchos_BLAS.hpp"
64 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
65 # include <Teuchos_FancyOStream.hpp>
66 #endif
67 
68 namespace Anasazi {
69 
70  template<class ScalarType, class MV, class OP>
71  class BasicOrthoManager : public MatOrthoManager<ScalarType,MV,OP> {
72 
73  private:
74  typedef typename Teuchos::ScalarTraits<ScalarType>::magnitudeType MagnitudeType;
78 
79  public:
80 
82 
83  BasicOrthoManager( Teuchos::RCP<const OP> Op = Teuchos::null,
85  typename Teuchos::ScalarTraits<ScalarType>::magnitudeType kappa = 1.41421356 /* sqrt(2) */,
88 
89 
93 
94 
96 
97 
98 
137  void projectMat (
138  MV &X,
141  = Teuchos::tuple(Teuchos::RCP< Teuchos::SerialDenseMatrix<int,ScalarType> >(Teuchos::null)),
142  Teuchos::RCP<MV> MX = Teuchos::null,
143  Teuchos::Array<Teuchos::RCP<const MV> > MQ = Teuchos::tuple(Teuchos::RCP<const MV>(Teuchos::null))
144  ) const;
145 
146 
185  int normalizeMat (
186  MV &X,
188  Teuchos::RCP<MV> MX = Teuchos::null
189  ) const;
190 
191 
252  MV &X,
255  = Teuchos::tuple(Teuchos::RCP< Teuchos::SerialDenseMatrix<int,ScalarType> >(Teuchos::null)),
257  Teuchos::RCP<MV> MX = Teuchos::null,
258  Teuchos::Array<Teuchos::RCP<const MV> > MQ = Teuchos::tuple(Teuchos::RCP<const MV>(Teuchos::null))
259  ) const;
260 
262 
264 
265 
271  orthonormErrorMat(const MV &X, Teuchos::RCP<const MV> MX = Teuchos::null) const;
272 
278  orthogErrorMat(const MV &X1, const MV &X2, Teuchos::RCP<const MV> MX1, Teuchos::RCP<const MV> MX2) const;
279 
281 
283 
284 
286  void setKappa( typename Teuchos::ScalarTraits<ScalarType>::magnitudeType kappa ) { kappa_ = kappa; }
287 
289  typename Teuchos::ScalarTraits<ScalarType>::magnitudeType getKappa() const { return kappa_; }
290 
292 
293  private:
295  MagnitudeType kappa_;
296  MagnitudeType eps_;
297  MagnitudeType tol_;
298 
299  // ! Routine to find an orthonormal basis
300  int findBasis(MV &X, Teuchos::RCP<MV> MX,
302  bool completeBasis, int howMany = -1 ) const;
303 
304  //
305  // Internal timers
306  //
307  Teuchos::RCP<Teuchos::Time> timerReortho_;
308 
309  };
310 
311 
313  // Constructor
314  template<class ScalarType, class MV, class OP>
319  MatOrthoManager<ScalarType,MV,OP>(Op), kappa_(kappa), eps_(eps), tol_(tol)
320 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
321  , timerReortho_(Teuchos::TimeMonitor::getNewTimer("Anasazi::BasicOrthoManager::Re-orthogonalization"))
322 #endif
323  {
324  TEUCHOS_TEST_FOR_EXCEPTION(eps_ < SCT::magnitude(SCT::zero()),std::invalid_argument,
325  "Anasazi::BasicOrthoManager::BasicOrthoManager(): argument \"eps\" must be non-negative.");
326  if (eps_ == 0) {
328  eps_ = lapack.LAMCH('E');
330  }
332  tol_ < SCT::magnitude(SCT::zero()) || tol_ > SCT::magnitude(SCT::one()),
333  std::invalid_argument,
334  "Anasazi::BasicOrthoManager::BasicOrthoManager(): argument \"tol\" must be in [0,1].");
335  }
336 
337 
338 
340  // Compute the distance from orthonormality
341  template<class ScalarType, class MV, class OP>
344  const ScalarType ONE = SCT::one();
345  int rank = MVT::GetNumberVecs(X);
348  for (int i=0; i<rank; i++) {
349  xTx(i,i) -= ONE;
350  }
351  return xTx.normFrobenius();
352  }
353 
354 
355 
357  // Compute the distance from orthogonality
358  template<class ScalarType, class MV, class OP>
361  int r1 = MVT::GetNumberVecs(X1);
362  int r2 = MVT::GetNumberVecs(X2);
365  return xTx.normFrobenius();
366  }
367 
368 
369 
371  template<class ScalarType, class MV, class OP>
373  MV &X,
376  Teuchos::RCP<MV> MX,
378  ) const {
379  // For the inner product defined by the operator Op or the identity (Op == 0)
380  // -> Orthogonalize X against each Q[i]
381  // Modify MX accordingly
382  //
383  // Note that when Op is 0, MX is not referenced
384  //
385  // Parameter variables
386  //
387  // X : Vectors to be transformed
388  //
389  // MX : Image of the block vector X by the mass matrix
390  //
391  // Q : Bases to orthogonalize against. These are assumed orthonormal, mutually and independently.
392  //
393 
394 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
395  // Get a FancyOStream from out_arg or create a new one ...
397  out = Teuchos::getFancyOStream(Teuchos::rcpFromRef(std::cout));
398  out->setShowAllFrontMatter(false).setShowProcRank(true);
399  *out << "Entering Anasazi::BasicOrthoManager::projectMat(...)\n";
400 #endif
401 
402  ScalarType ONE = SCT::one();
403 
404  int xc = MVT::GetNumberVecs( X );
405  ptrdiff_t xr = MVT::GetGlobalLength( X );
406  int nq = Q.length();
407  std::vector<int> qcs(nq);
408  // short-circuit
409  if (nq == 0 || xc == 0 || xr == 0) {
410 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
411  *out << "Leaving Anasazi::BasicOrthoManager::projectMat(...)\n";
412 #endif
413  return;
414  }
415  ptrdiff_t qr = MVT::GetGlobalLength ( *Q[0] );
416  // if we don't have enough C, expand it with null references
417  // if we have too many, resize to throw away the latter ones
418  // if we have exactly as many as we have Q, this call has no effect
419  C.resize(nq);
420 
421 
422  /****** DO NO MODIFY *MX IF _hasOp == false ******/
423  if (this->_hasOp) {
424 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
425  *out << "Allocating MX...\n";
426 #endif
427  if (MX == Teuchos::null) {
428  // we need to allocate space for MX
429  MX = MVT::Clone(X,MVT::GetNumberVecs(X));
430  OPT::Apply(*(this->_Op),X,*MX);
431  this->_OpCounter += MVT::GetNumberVecs(X);
432  }
433  }
434  else {
435  // Op == I --> MX = X (ignore it if the user passed it in)
436  MX = Teuchos::rcpFromRef(X);
437  }
438  int mxc = MVT::GetNumberVecs( *MX );
439  ptrdiff_t mxr = MVT::GetGlobalLength( *MX );
440 
441  // check size of X and Q w.r.t. common sense
442  TEUCHOS_TEST_FOR_EXCEPTION( xc<0 || xr<0 || mxc<0 || mxr<0, std::invalid_argument,
443  "Anasazi::BasicOrthoManager::projectMat(): MVT returned negative dimensions for X,MX" );
444  // check size of X w.r.t. MX and Q
445  TEUCHOS_TEST_FOR_EXCEPTION( xc!=mxc || xr!=mxr || xr!=qr, std::invalid_argument,
446  "Anasazi::BasicOrthoManager::projectMat(): Size of X not consistent with MX,Q" );
447 
448  // tally up size of all Q and check/allocate C
449  for (int i=0; i<nq; i++) {
450  TEUCHOS_TEST_FOR_EXCEPTION( MVT::GetGlobalLength( *Q[i] ) != qr, std::invalid_argument,
451  "Anasazi::BasicOrthoManager::projectMat(): Q lengths not mutually consistent" );
452  qcs[i] = MVT::GetNumberVecs( *Q[i] );
453  TEUCHOS_TEST_FOR_EXCEPTION( qr < static_cast<ptrdiff_t>(qcs[i]), std::invalid_argument,
454  "Anasazi::BasicOrthoManager::projectMat(): Q has less rows than columns" );
455  // check size of C[i]
456  if ( C[i] == Teuchos::null ) {
458  }
459  else {
460  TEUCHOS_TEST_FOR_EXCEPTION( C[i]->numRows() != qcs[i] || C[i]->numCols() != xc , std::invalid_argument,
461  "Anasazi::BasicOrthoManager::projectMat(): Size of Q not consistent with size of C" );
462  }
463  }
464 
465  // Perform the Gram-Schmidt transformation for a block of vectors
466 
467  // Compute the initial Op-norms
468  std::vector<ScalarType> oldDot( xc );
469  MVT::MvDot( X, *MX, oldDot );
470 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
471  *out << "oldDot = { ";
472  std::copy(oldDot.begin(), oldDot.end(), std::ostream_iterator<ScalarType>(*out, " "));
473  *out << "}\n";
474 #endif
475 
476  MQ.resize(nq);
477  // Define the product Q^T * (Op*X)
478  for (int i=0; i<nq; i++) {
479  // Multiply Q' with MX
480  MatOrthoManager<ScalarType,MV,OP>::innerProdMat(*Q[i],X,*C[i],MQ[i],MX);
481  // Multiply by Q and subtract the result in X
482 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
483  *out << "Applying projector P_Q[" << i << "]...\n";
484 #endif
485  MVT::MvTimesMatAddMv( -ONE, *Q[i], *C[i], ONE, X );
486 
487  // Update MX, with the least number of applications of Op as possible
488  // Update MX. If we have MQ, use it. Otherwise, just multiply by Op
489  if (this->_hasOp) {
490  if (MQ[i] == Teuchos::null) {
491 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
492  *out << "Updating MX via M*X...\n";
493 #endif
494  OPT::Apply( *(this->_Op), X, *MX);
495  this->_OpCounter += MVT::GetNumberVecs(X);
496  }
497  else {
498 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
499  *out << "Updating MX via M*Q...\n";
500 #endif
501  MVT::MvTimesMatAddMv( -ONE, *MQ[i], *C[i], ONE, *MX );
502  }
503  }
504  }
505 
506  // Compute new Op-norms
507  std::vector<ScalarType> newDot(xc);
508  MVT::MvDot( X, *MX, newDot );
509 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
510  *out << "newDot = { ";
511  std::copy(newDot.begin(), newDot.end(), std::ostream_iterator<ScalarType>(*out, " "));
512  *out << "}\n";
513 #endif
514 
515  // determine (individually) whether to do another step of classical Gram-Schmidt
516  for (int j = 0; j < xc; ++j) {
517 
518  if ( SCT::magnitude(kappa_*newDot[j]) < SCT::magnitude(oldDot[j]) ) {
519 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
520  *out << "kappa_*newDot[" <<j<< "] == " << kappa_*newDot[j] << "... another step of Gram-Schmidt.\n";
521 #endif
522 #ifdef ANASAZI_TEUCHOS_TIME_MONITOR
523  Teuchos::TimeMonitor lcltimer( *timerReortho_ );
524 #endif
525  for (int i=0; i<nq; i++) {
526  Teuchos::SerialDenseMatrix<int,ScalarType> C2(C[i]->numRows(), C[i]->numCols());
527 
528  // Apply another step of classical Gram-Schmidt
530  *C[i] += C2;
531 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
532  *out << "Applying projector P_Q[" << i << "]...\n";
533 #endif
534  MVT::MvTimesMatAddMv( -ONE, *Q[i], C2, ONE, X );
535 
536  // Update MX as above
537  if (this->_hasOp) {
538  if (MQ[i] == Teuchos::null) {
539 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
540  *out << "Updating MX via M*X...\n";
541 #endif
542  OPT::Apply( *(this->_Op), X, *MX);
543  this->_OpCounter += MVT::GetNumberVecs(X);
544  }
545  else {
546 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
547  *out << "Updating MX via M*Q...\n";
548 #endif
549  MVT::MvTimesMatAddMv( -ONE, *MQ[i], C2, ONE, *MX );
550  }
551  }
552  }
553  break;
554  } // if (kappa_*newDot[j] < oldDot[j])
555  } // for (int j = 0; j < xc; ++j)
556 
557 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
558  *out << "Leaving Anasazi::BasicOrthoManager::projectMat(...)\n";
559 #endif
560  }
561 
562 
563 
565  // Find an Op-orthonormal basis for span(X), with rank numvectors(X)
566  template<class ScalarType, class MV, class OP>
568  MV &X,
570  Teuchos::RCP<MV> MX) const {
571  // call findBasis(), with the instruction to try to generate a basis of rank numvecs(X)
572  // findBasis() requires MX
573 
574  int xc = MVT::GetNumberVecs(X);
575  ptrdiff_t xr = MVT::GetGlobalLength(X);
576 
577  // if Op==null, MX == X (via pointer)
578  // Otherwise, either the user passed in MX or we will allocated and compute it
579  if (this->_hasOp) {
580  if (MX == Teuchos::null) {
581  // we need to allocate space for MX
582  MX = MVT::Clone(X,xc);
583  OPT::Apply(*(this->_Op),X,*MX);
584  this->_OpCounter += MVT::GetNumberVecs(X);
585  }
586  }
587 
588  // if the user doesn't want to store the coefficients,
589  // allocate some local memory for them
590  if ( B == Teuchos::null ) {
592  }
593 
594  int mxc = (this->_hasOp) ? MVT::GetNumberVecs( *MX ) : xc;
595  ptrdiff_t mxr = (this->_hasOp) ? MVT::GetGlobalLength( *MX ) : xr;
596 
597  // check size of C, B
598  TEUCHOS_TEST_FOR_EXCEPTION( xc == 0 || xr == 0, std::invalid_argument,
599  "Anasazi::BasicOrthoManager::normalizeMat(): X must be non-empty" );
600  TEUCHOS_TEST_FOR_EXCEPTION( B->numRows() != xc || B->numCols() != xc, std::invalid_argument,
601  "Anasazi::BasicOrthoManager::normalizeMat(): Size of X not consistent with size of B" );
602  TEUCHOS_TEST_FOR_EXCEPTION( xc != mxc || xr != mxr, std::invalid_argument,
603  "Anasazi::BasicOrthoManager::normalizeMat(): Size of X not consistent with size of MX" );
604  TEUCHOS_TEST_FOR_EXCEPTION( static_cast<ptrdiff_t>(xc) > xr, std::invalid_argument,
605  "Anasazi::BasicOrthoManager::normalizeMat(): Size of X not feasible for normalization" );
606 
607  return findBasis(X, MX, *B, true );
608  }
609 
610 
611 
613  // Find an Op-orthonormal basis for span(X) - span(W)
614  template<class ScalarType, class MV, class OP>
616  MV &X,
620  Teuchos::RCP<MV> MX,
622  ) const {
623 
624 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
625  // Get a FancyOStream from out_arg or create a new one ...
627  out = Teuchos::getFancyOStream(Teuchos::rcpFromRef(std::cout));
628  out->setShowAllFrontMatter(false).setShowProcRank(true);
629  *out << "Entering Anasazi::BasicOrthoManager::projectAndNormalizeMat(...)\n";
630 #endif
631 
632  int nq = Q.length();
633  int xc = MVT::GetNumberVecs( X );
634  ptrdiff_t xr = MVT::GetGlobalLength( X );
635  int rank;
636 
637  /* if the user doesn't want to store the coefficients,
638  * allocate some local memory for them
639  */
640  if ( B == Teuchos::null ) {
642  }
643 
644  /****** DO NO MODIFY *MX IF _hasOp == false ******/
645  if (this->_hasOp) {
646  if (MX == Teuchos::null) {
647  // we need to allocate space for MX
648 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
649  *out << "Allocating MX...\n";
650 #endif
651  MX = MVT::Clone(X,MVT::GetNumberVecs(X));
652  OPT::Apply(*(this->_Op),X,*MX);
653  this->_OpCounter += MVT::GetNumberVecs(X);
654  }
655  }
656  else {
657  // Op == I --> MX = X (ignore it if the user passed it in)
658  MX = Teuchos::rcpFromRef(X);
659  }
660 
661  int mxc = MVT::GetNumberVecs( *MX );
662  ptrdiff_t mxr = MVT::GetGlobalLength( *MX );
663 
664  TEUCHOS_TEST_FOR_EXCEPTION( xc == 0 || xr == 0, std::invalid_argument, "Anasazi::BasicOrthoManager::projectAndNormalizeMat(): X must be non-empty" );
665 
666  ptrdiff_t numbas = 0;
667  for (int i=0; i<nq; i++) {
668  numbas += MVT::GetNumberVecs( *Q[i] );
669  }
670 
671  // check size of B
672  TEUCHOS_TEST_FOR_EXCEPTION( B->numRows() != xc || B->numCols() != xc, std::invalid_argument,
673  "Anasazi::BasicOrthoManager::projectAndNormalizeMat(): Size of X must be consistent with size of B" );
674  // check size of X and MX
675  TEUCHOS_TEST_FOR_EXCEPTION( xc<0 || xr<0 || mxc<0 || mxr<0, std::invalid_argument,
676  "Anasazi::BasicOrthoManager::projectAndNormalizeMat(): MVT returned negative dimensions for X,MX" );
677  // check size of X w.r.t. MX
678  TEUCHOS_TEST_FOR_EXCEPTION( xc!=mxc || xr!=mxr, std::invalid_argument,
679  "Anasazi::BasicOrthoManager::projectAndNormalizeMat(): Size of X must be consistent with size of MX" );
680  // check feasibility
681  TEUCHOS_TEST_FOR_EXCEPTION( numbas+xc > xr, std::invalid_argument,
682  "Anasazi::BasicOrthoManager::projectAndNormalizeMat(): Orthogonality constraints not feasible" );
683 
684  // orthogonalize all of X against Q
685 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
686  *out << "Orthogonalizing X against Q...\n";
687 #endif
688  projectMat(X,Q,C,MX,MQ);
689 
691  // start working
692  rank = 0;
693  int numTries = 10; // each vector in X gets 10 random chances to escape degeneracy
694  int oldrank = -1;
695  do {
696  int curxsize = xc - rank;
697 
698  // orthonormalize X, but quit if it is rank deficient
699  // we can't let findBasis generated random vectors to complete the basis,
700  // because it doesn't know about Q; we will do this ourselves below
701 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
702  *out << "Attempting to find orthonormal basis for X...\n";
703 #endif
704  rank = findBasis(X,MX,*B,false,curxsize);
705 
706  if (oldrank != -1 && rank != oldrank) {
707  // we had previously stopped before, after operating on vector oldrank
708  // we saved its coefficients, augmented it with a random vector, and
709  // then called findBasis() again, which proceeded to add vector oldrank
710  // to the basis.
711  // now, restore the saved coefficients into B
712  for (int i=0; i<xc; i++) {
713  (*B)(i,oldrank) = oldCoeff(i,0);
714  }
715  }
716 
717  if (rank < xc) {
718  if (rank != oldrank) {
719  // we quit on this vector and will augment it with random below
720  // this is the first time that we have quit on this vector
721  // therefor, (*B)(:,rank) contains the actual coefficients of the
722  // input vectors with respect to the previous vectors in the basis
723  // save these values, as (*B)(:,rank) will be overwritten by our next
724  // call to findBasis()
725  // we will restore it after we are done working on this vector
726  for (int i=0; i<xc; i++) {
727  oldCoeff(i,0) = (*B)(i,rank);
728  }
729  }
730  }
731 
732  if (rank == xc) {
733  // we are done
734 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
735  *out << "Finished computing basis.\n";
736 #endif
737  break;
738  }
739  else {
740  TEUCHOS_TEST_FOR_EXCEPTION( rank < oldrank, OrthoError,
741  "Anasazi::BasicOrthoManager::projectAndNormalizeMat(): basis lost rank; this shouldn't happen");
742 
743  if (rank != oldrank) {
744  // we added a vector to the basis; reset the chance counter
745  numTries = 10;
746  // store old rank
747  oldrank = rank;
748  }
749  else {
750  // has this vector run out of chances to escape degeneracy?
751  if (numTries <= 0) {
752  break;
753  }
754  }
755  // use one of this vector's chances
756  numTries--;
757 
758  // randomize troubled direction
759 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
760  *out << "Randomizing X[" << rank << "]...\n";
761 #endif
762  Teuchos::RCP<MV> curX, curMX;
763  std::vector<int> ind(1);
764  ind[0] = rank;
765  curX = MVT::CloneViewNonConst(X,ind);
766  MVT::MvRandom(*curX);
767  if (this->_hasOp) {
768 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
769  *out << "Applying operator to random vector.\n";
770 #endif
771  curMX = MVT::CloneViewNonConst(*MX,ind);
772  OPT::Apply( *(this->_Op), *curX, *curMX );
773  this->_OpCounter += MVT::GetNumberVecs(*curX);
774  }
775 
776  // orthogonalize against Q
777  // if !this->_hasOp, the curMX will be ignored.
778  // we don't care about these coefficients
779  // on the contrary, we need to preserve the previous coeffs
780  {
782  projectMat(*curX,Q,dummyC,curMX,MQ);
783  }
784  }
785  } while (1);
786 
787  // this should never raise an exception; but our post-conditions oblige us to check
788  TEUCHOS_TEST_FOR_EXCEPTION( rank > xc || rank < 0, std::logic_error,
789  "Anasazi::BasicOrthoManager::projectAndNormalizeMat(): Debug error in rank variable." );
790 
791 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
792  *out << "Leaving Anasazi::BasicOrthoManager::projectAndNormalizeMat(...)\n";
793 #endif
794 
795  return rank;
796  }
797 
798 
799 
801  // Find an Op-orthonormal basis for span(X), with the option of extending the subspace so that
802  // the rank is numvectors(X)
803  template<class ScalarType, class MV, class OP>
805  MV &X, Teuchos::RCP<MV> MX,
807  bool completeBasis, int howMany ) const {
808 
809  // For the inner product defined by the operator Op or the identity (Op == 0)
810  // -> Orthonormalize X
811  // Modify MX accordingly
812  //
813  // Note that when Op is 0, MX is not referenced
814  //
815  // Parameter variables
816  //
817  // X : Vectors to be orthonormalized
818  //
819  // MX : Image of the multivector X under the operator Op
820  //
821  // Op : Pointer to the operator for the inner product
822  //
823 
824 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
825  // Get a FancyOStream from out_arg or create a new one ...
827  out = Teuchos::getFancyOStream(Teuchos::rcpFromRef(std::cout));
828  out->setShowAllFrontMatter(false).setShowProcRank(true);
829  *out << "Entering Anasazi::BasicOrthoManager::findBasis(...)\n";
830 #endif
831 
832  const ScalarType ONE = SCT::one();
833  const MagnitudeType ZERO = SCT::magnitude(SCT::zero());
834 
835  int xc = MVT::GetNumberVecs( X );
836 
837  if (howMany == -1) {
838  howMany = xc;
839  }
840 
841  /*******************************************************
842  * If _hasOp == false, we will not reference MX below *
843  *******************************************************/
844  TEUCHOS_TEST_FOR_EXCEPTION(this->_hasOp == true && MX == Teuchos::null, std::logic_error,
845  "Anasazi::BasicOrthoManager::findBasis(): calling routine did not specify MS.");
846  TEUCHOS_TEST_FOR_EXCEPTION( howMany < 0 || howMany > xc, std::logic_error,
847  "Anasazi::BasicOrthoManager::findBasis(): Invalid howMany parameter" );
848 
849  /* xstart is which column we are starting the process with, based on howMany
850  * columns before xstart are assumed to be Op-orthonormal already
851  */
852  int xstart = xc - howMany;
853 
854  for (int j = xstart; j < xc; j++) {
855 
856  // numX represents the number of currently orthonormal columns of X
857  int numX = j;
858  // j represents the index of the current column of X
859  // these are different interpretations of the same value
860 
861  //
862  // set the lower triangular part of B to zero
863  for (int i=j+1; i<xc; ++i) {
864  B(i,j) = ZERO;
865  }
866 
867  // Get a view of the vector currently being worked on.
868  std::vector<int> index(1);
869  index[0] = j;
870  Teuchos::RCP<MV> Xj = MVT::CloneViewNonConst( X, index );
871  Teuchos::RCP<MV> MXj;
872  if ((this->_hasOp)) {
873  // MXj is a view of the current vector in MX
874  MXj = MVT::CloneViewNonConst( *MX, index );
875  }
876  else {
877  // MXj is a pointer to Xj, and MUST NOT be modified
878  MXj = Xj;
879  }
880 
881  // Get a view of the previous vectors.
882  std::vector<int> prev_idx( numX );
883  Teuchos::RCP<const MV> prevX, prevMX;
884 
885  if (numX > 0) {
886  for (int i=0; i<numX; ++i) prev_idx[i] = i;
887  prevX = MVT::CloneViewNonConst( X, prev_idx );
888  if (this->_hasOp) {
889  prevMX = MVT::CloneViewNonConst( *MX, prev_idx );
890  }
891  }
892 
893  bool rankDef = true;
894  /* numTrials>0 will denote that the current vector was randomized for the purpose
895  * of finding a basis vector, and that the coefficients of that vector should
896  * not be stored in B
897  */
898  for (int numTrials = 0; numTrials < 10; numTrials++) {
899 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
900  *out << "Trial " << numTrials << " for vector " << j << "\n";
901 #endif
902 
903  // Make storage for these Gram-Schmidt iterations.
905  std::vector<MagnitudeType> origNorm(1), newNorm(1), newNorm2(1);
906 
907  //
908  // Save old MXj vector and compute Op-norm
909  //
910  Teuchos::RCP<MV> oldMXj = MVT::CloneCopy( *MXj );
912 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
913  *out << "origNorm = " << origNorm[0] << "\n";
914 #endif
915 
916  if (numX > 0) {
917  // Apply the first step of Gram-Schmidt
918 
919  // product <- prevX^T MXj
920  MatOrthoManager<ScalarType,MV,OP>::innerProdMat(*prevX,*Xj,product,Teuchos::null,MXj);
921 
922  // Xj <- Xj - prevX prevX^T MXj
923  // = Xj - prevX product
924 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
925  *out << "Orthogonalizing X[" << j << "]...\n";
926 #endif
927  MVT::MvTimesMatAddMv( -ONE, *prevX, product, ONE, *Xj );
928 
929  // Update MXj
930  if (this->_hasOp) {
931  // MXj <- Op*Xj_new
932  // = Op*(Xj_old - prevX prevX^T MXj)
933  // = MXj - prevMX product
934 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
935  *out << "Updating MX[" << j << "]...\n";
936 #endif
937  MVT::MvTimesMatAddMv( -ONE, *prevMX, product, ONE, *MXj );
938  }
939 
940  // Compute new Op-norm
942  MagnitudeType product_norm = product.normOne();
943 
944 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
945  *out << "newNorm = " << newNorm[0] << "\n";
946  *out << "prodoct_norm = " << product_norm << "\n";
947 #endif
948 
949  // Check if a correction is needed.
950  if ( product_norm/newNorm[0] >= tol_ || newNorm[0] < eps_*origNorm[0]) {
951 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
952  if (product_norm/newNorm[0] >= tol_) {
953  *out << "product_norm/newNorm == " << product_norm/newNorm[0] << "... another step of Gram-Schmidt.\n";
954  }
955  else {
956  *out << "eps*origNorm == " << eps_*origNorm[0] << "... another step of Gram-Schmidt.\n";
957  }
958 #endif
959  // Apply the second step of Gram-Schmidt
960  // This is the same as above
962  MatOrthoManager<ScalarType,MV,OP>::innerProdMat(*prevX,*Xj,P2,Teuchos::null,MXj);
963  product += P2;
964 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
965  *out << "Orthogonalizing X[" << j << "]...\n";
966 #endif
967  MVT::MvTimesMatAddMv( -ONE, *prevX, P2, ONE, *Xj );
968  if ((this->_hasOp)) {
969 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
970  *out << "Updating MX[" << j << "]...\n";
971 #endif
972  MVT::MvTimesMatAddMv( -ONE, *prevMX, P2, ONE, *MXj );
973  }
974  // Compute new Op-norms
976  product_norm = P2.normOne();
977 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
978  *out << "newNorm2 = " << newNorm2[0] << "\n";
979  *out << "product_norm = " << product_norm << "\n";
980 #endif
981  if ( product_norm/newNorm2[0] >= tol_ || newNorm2[0] < eps_*origNorm[0] ) {
982  // we don't do another GS, we just set it to zero.
983 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
984  if (product_norm/newNorm2[0] >= tol_) {
985  *out << "product_norm/newNorm2 == " << product_norm/newNorm2[0] << "... setting vector to zero.\n";
986  }
987  else if (newNorm[0] < newNorm2[0]) {
988  *out << "newNorm2 > newNorm... setting vector to zero.\n";
989  }
990  else {
991  *out << "eps*origNorm == " << eps_*origNorm[0] << "... setting vector to zero.\n";
992  }
993 #endif
994  MVT::MvInit(*Xj,ZERO);
995  if ((this->_hasOp)) {
996 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
997  *out << "Setting MX[" << j << "] to zero as well.\n";
998 #endif
999  MVT::MvInit(*MXj,ZERO);
1000  }
1001  }
1002  }
1003  } // if (numX > 0) do GS
1004 
1005  // save the coefficients, if we are working on the original vector and not a randomly generated one
1006  if (numTrials == 0) {
1007  for (int i=0; i<numX; i++) {
1008  B(i,j) = product(i,0);
1009  }
1010  }
1011 
1012  // Check if Xj has any directional information left after the orthogonalization.
1014  if ( newNorm[0] != ZERO && newNorm[0] > SCT::sfmin() ) {
1015 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
1016  *out << "Normalizing X[" << j << "], norm(X[" << j << "]) = " << newNorm[0] << "\n";
1017 #endif
1018  // Normalize Xj.
1019  // Xj <- Xj / norm
1020  MVT::MvScale( *Xj, ONE/newNorm[0]);
1021  if (this->_hasOp) {
1022 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
1023  *out << "Normalizing M*X[" << j << "]...\n";
1024 #endif
1025  // Update MXj.
1026  MVT::MvScale( *MXj, ONE/newNorm[0]);
1027  }
1028 
1029  // save it, if it corresponds to the original vector and not a randomly generated one
1030  if (numTrials == 0) {
1031  B(j,j) = newNorm[0];
1032  }
1033 
1034  // We are not rank deficient in this vector. Move on to the next vector in X.
1035  rankDef = false;
1036  break;
1037  }
1038  else {
1039 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
1040  *out << "Not normalizing M*X[" << j << "]...\n";
1041 #endif
1042  // There was nothing left in Xj after orthogonalizing against previous columns in X.
1043  // X is rank deficient.
1044  // reflect this in the coefficients
1045  B(j,j) = ZERO;
1046 
1047  if (completeBasis) {
1048  // Fill it with random information and keep going.
1049 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
1050  *out << "Inserting random vector in X[" << j << "]...\n";
1051 #endif
1052  MVT::MvRandom( *Xj );
1053  if (this->_hasOp) {
1054 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
1055  *out << "Updating M*X[" << j << "]...\n";
1056 #endif
1057  OPT::Apply( *(this->_Op), *Xj, *MXj );
1058  this->_OpCounter += MVT::GetNumberVecs(*Xj);
1059  }
1060  }
1061  else {
1062  rankDef = true;
1063  break;
1064  }
1065  }
1066  } // for (numTrials = 0; numTrials < 10; ++numTrials)
1067 
1068  // if rankDef == true, then quit and notify user of rank obtained
1069  if (rankDef == true) {
1070  TEUCHOS_TEST_FOR_EXCEPTION( rankDef && completeBasis, OrthoError,
1071  "Anasazi::BasicOrthoManager::findBasis(): Unable to complete basis" );
1072 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
1073  *out << "Returning early, rank " << j << " from Anasazi::BasicOrthoManager::findBasis(...)\n";
1074 #endif
1075  return j;
1076  }
1077 
1078  } // for (j = 0; j < xc; ++j)
1079 
1080 #ifdef ANASAZI_BASIC_ORTHO_DEBUG
1081  *out << "Returning " << xc << " from Anasazi::BasicOrthoManager::findBasis(...)\n";
1082 #endif
1083  return xc;
1084  }
1085 
1086 } // namespace Anasazi
1087 
1088 #endif // ANASAZI_BASIC_ORTHOMANAGER_HPP
1089 
Templated virtual class for providing orthogonalization/orthonormalization methods with matrix-based ...
Teuchos::ScalarTraits< ScalarType >::magnitudeType getKappa() const
Return parameter for re-orthogonalization threshold.
Declaration of basic traits for the multivector type.
basic_FancyOStream & setShowProcRank(const bool showProcRank)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Virtual base class which defines basic traits for the operator type.
void innerProdMat(const MV &X, const MV &Y, Teuchos::SerialDenseMatrix< int, ScalarType > &Z, Teuchos::RCP< const MV > MX=Teuchos::null, Teuchos::RCP< const MV > MY=Teuchos::null) const
Provides a matrix-based inner product.
static T pow(T x, T y)
ScalarTraits< ScalarType >::magnitudeType normFrobenius() const
void projectMat(MV &X, Teuchos::Array< Teuchos::RCP< const MV > > Q, Teuchos::Array< Teuchos::RCP< Teuchos::SerialDenseMatrix< int, ScalarType > > > C=Teuchos::tuple(Teuchos::RCP< Teuchos::SerialDenseMatrix< int, ScalarType > >(Teuchos::null)), Teuchos::RCP< MV > MX=Teuchos::null, Teuchos::Array< Teuchos::RCP< const MV > > MQ=Teuchos::tuple(Teuchos::RCP< const MV >(Teuchos::null))) const
Given a list of mutually orthogonal and internally orthonormal bases Q, this method projects a multiv...
Teuchos::ScalarTraits< ScalarType >::magnitudeType orthogErrorMat(const MV &X1, const MV &X2, Teuchos::RCP< const MV > MX1, Teuchos::RCP< const MV > MX2) const
This method computes the error in orthogonality of two multivectors, measured as the Frobenius norm o...
Anasazi&#39;s templated virtual class for providing routines for orthogonalization and orthonormalization...
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void setKappa(typename Teuchos::ScalarTraits< ScalarType >::magnitudeType kappa)
Set parameter for re-orthogonalization threshold.
Traits class which defines basic operations on multivectors.
Virtual base class which defines basic traits for the operator type.
basic_FancyOStream & setShowAllFrontMatter(const bool showAllFrontMatter)
Anasazi header file which uses auto-configuration information to include necessary C++ headers...
int normalizeMat(MV &X, Teuchos::RCP< Teuchos::SerialDenseMatrix< int, ScalarType > > B=Teuchos::null, Teuchos::RCP< MV > MX=Teuchos::null) const
This method takes a multivector X and attempts to compute an orthonormal basis for ...
Exception thrown to signal error in an orthogonalization manager method.
Teuchos::ScalarTraits< ScalarType >::magnitudeType orthonormErrorMat(const MV &X, Teuchos::RCP< const MV > MX=Teuchos::null) const
This method computes the error in orthonormality of a multivector, measured as the Frobenius norm of ...
static magnitudeType magnitude(ScalarTypea)
BasicOrthoManager(Teuchos::RCP< const OP > Op=Teuchos::null, typename Teuchos::ScalarTraits< ScalarType >::magnitudeType kappa=1.41421356, typename Teuchos::ScalarTraits< ScalarType >::magnitudeType eps=0.0, typename Teuchos::ScalarTraits< ScalarType >::magnitudeType tol=0.20)
Constructor specifying re-orthogonalization tolerance.
An implementation of the Anasazi::MatOrthoManager that performs orthogonalization using (potentially)...
int projectAndNormalizeMat(MV &X, Teuchos::Array< Teuchos::RCP< const MV > > Q, Teuchos::Array< Teuchos::RCP< Teuchos::SerialDenseMatrix< int, ScalarType > > > C=Teuchos::tuple(Teuchos::RCP< Teuchos::SerialDenseMatrix< int, ScalarType > >(Teuchos::null)), Teuchos::RCP< Teuchos::SerialDenseMatrix< int, ScalarType > > B=Teuchos::null, Teuchos::RCP< MV > MX=Teuchos::null, Teuchos::Array< Teuchos::RCP< const MV > > MQ=Teuchos::tuple(Teuchos::RCP< const MV >(Teuchos::null))) const
Given a set of bases Q[i] and a multivector X, this method computes an orthonormal basis for ...
ScalarType LAMCH(const char &CMACH) const
void normMat(const MV &X, std::vector< typename Teuchos::ScalarTraits< ScalarType >::magnitudeType > &normvec, Teuchos::RCP< const MV > MX=Teuchos::null) const
Provides the norm induced by the matrix-based inner product.