Stratimikos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BelosThyraAdapter.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Stratimikos: Thyra-based strategies for linear solvers
4 //
5 // Copyright 2006 NTESS and the Stratimikos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
20 #ifndef BELOS_THYRA_ADAPTER_HPP
21 #define BELOS_THYRA_ADAPTER_HPP
22 
23 #include "Stratimikos_Config.h"
24 #include "BelosConfigDefs.hpp"
25 #include "BelosMultiVecTraits.hpp"
26 #include "BelosOperatorTraits.hpp"
27 
28 #include <Thyra_DetachedMultiVectorView.hpp>
29 #include <Thyra_MultiVectorBase.hpp>
30 #include <Thyra_MultiVectorStdOps.hpp>
31 #ifdef HAVE_BELOS_TSQR
32 # include <Thyra_TsqrAdaptor.hpp>
33 #endif // HAVE_BELOS_TSQR
34 
35 #ifdef HAVE_STRATIMIKOS_BELOS_TIMERS
36 # include <Teuchos_TimeMonitor.hpp>
37 
38 # define STRATIMIKOS_TIME_MONITOR(NAME) \
39  Teuchos::TimeMonitor tM(*Teuchos::TimeMonitor::getNewTimer(std::string(NAME)))
40 
41 #else
42 
43 # define STRATIMIKOS_TIME_MONITOR(NAME)
44 
45 #endif
46 
47 namespace Belos {
48 
50  //
51  // Implementation of the Belos::MultiVecTraits for Thyra::MultiVectorBase
52  //
54 
61  template<class ScalarType>
62  class MultiVecTraits< ScalarType, Thyra::MultiVectorBase<ScalarType> >
63  {
64  private:
65  typedef Thyra::MultiVectorBase<ScalarType> TMVB;
67  typedef typename ST::magnitudeType magType;
68 
69  public:
70 
73 
78  static Teuchos::RCP<TMVB> Clone( const TMVB& mv, const int numvecs )
79  {
80  Teuchos::RCP<TMVB> c = Thyra::createMembers( mv.range(), numvecs );
81  return c;
82  }
83 
88  static Teuchos::RCP<TMVB> CloneCopy( const TMVB& mv )
89  {
90  int numvecs = mv.domain()->dim();
91  // create the new multivector
92  Teuchos::RCP< TMVB > cc = Thyra::createMembers( mv.range(), numvecs );
93  // copy the data from the source multivector to the new multivector
94  Thyra::assign(cc.ptr(), mv);
95  return cc;
96  }
97 
103  static Teuchos::RCP<TMVB> CloneCopy( const TMVB& mv, const std::vector<int>& index )
104  {
105  int numvecs = index.size();
106  // create the new multivector
107  Teuchos::RCP<TMVB> cc = Thyra::createMembers( mv.range(), numvecs );
108  // create a view to the relevant part of the source multivector
109  Teuchos::RCP<const TMVB> view = mv.subView(index);
110  // copy the data from the relevant view to the new multivector
111  Thyra::assign(cc.ptr(), *view);
112  return cc;
113  }
114 
115  static Teuchos::RCP<TMVB>
116  CloneCopy (const TMVB& mv, const Teuchos::Range1D& index)
117  {
118  const int numVecs = index.size();
119  // Create the new multivector
120  Teuchos::RCP<TMVB> cc = Thyra::createMembers (mv.range(), numVecs);
121  // Create a view to the relevant part of the source multivector
122  Teuchos::RCP<const TMVB> view = mv.subView (index);
123  // Copy the data from the view to the new multivector.
124  Thyra::assign (cc.ptr(), *view);
125  return cc;
126  }
127 
133  static Teuchos::RCP<TMVB> CloneViewNonConst( TMVB& mv, const std::vector<int>& index )
134  {
135  int numvecs = index.size();
136 
137  // We do not assume that the indices are sorted, nor do we check that
138  // index.size() > 0. This code is fail-safe, in the sense that a zero
139  // length index std::vector will pass the error on the Thyra.
140 
141  // Thyra has two ways to create an indexed View:
142  // * contiguous (via a range of columns)
143  // * indexed (via a std::vector of column indices)
144  // The former is significantly more efficient than the latter, in terms of
145  // computations performed with/against the created view.
146  // We will therefore check to see if the given indices are contiguous, and
147  // if so, we will use the contiguous view creation method.
148 
149  int lb = index[0];
150  bool contig = true;
151  for (int i=0; i<numvecs; i++) {
152  if (lb+i != index[i]) contig = false;
153  }
154 
156  if (contig) {
157  const Thyra::Range1D rng(lb,lb+numvecs-1);
158  // create a contiguous view to the relevant part of the source multivector
159  cc = mv.subView(rng);
160  }
161  else {
162  // create an indexed view to the relevant part of the source multivector
163  cc = mv.subView(index);
164  }
165  return cc;
166  }
167 
168  static Teuchos::RCP<TMVB>
170  {
171  // We let Thyra be responsible for checking that the index range
172  // is nonempty.
173  //
174  // Create and return a contiguous view to the relevant part of
175  // the source multivector.
176  return mv.subView (index);
177  }
178 
179 
185  static Teuchos::RCP<const TMVB> CloneView( const TMVB& mv, const std::vector<int>& index )
186  {
187  int numvecs = index.size();
188 
189  // We do not assume that the indices are sorted, nor do we check that
190  // index.size() > 0. This code is fail-safe, in the sense that a zero
191  // length index std::vector will pass the error on the Thyra.
192 
193  // Thyra has two ways to create an indexed View:
194  // * contiguous (via a range of columns)
195  // * indexed (via a std::vector of column indices)
196  // The former is significantly more efficient than the latter, in terms of
197  // computations performed with/against the created view.
198  // We will therefore check to see if the given indices are contiguous, and
199  // if so, we will use the contiguous view creation method.
200 
201  int lb = index[0];
202  bool contig = true;
203  for (int i=0; i<numvecs; i++) {
204  if (lb+i != index[i]) contig = false;
205  }
206 
208  if (contig) {
209  const Thyra::Range1D rng(lb,lb+numvecs-1);
210  // create a contiguous view to the relevant part of the source multivector
211  cc = mv.subView(rng);
212  }
213  else {
214  // create an indexed view to the relevant part of the source multivector
215  cc = mv.subView(index);
216  }
217  return cc;
218  }
219 
221  CloneView (const TMVB& mv, const Teuchos::Range1D& index)
222  {
223  // We let Thyra be responsible for checking that the index range
224  // is nonempty.
225  //
226  // Create and return a contiguous view to the relevant part of
227  // the source multivector.
228  return mv.subView (index);
229  }
230 
232 
235 
237  static ptrdiff_t GetGlobalLength( const TMVB& mv ) {
238  return Teuchos::as<ptrdiff_t>(mv.range()->dim());
239  }
240 
242  static int GetNumberVecs( const TMVB& mv )
243  { return mv.domain()->dim(); }
244 
246 
249 
252  static void MvTimesMatAddMv( const ScalarType alpha, const TMVB& A,
254  const ScalarType beta, TMVB& mv )
255  {
256  using Teuchos::arrayView; using Teuchos::arcpFromArrayView;
257  STRATIMIKOS_TIME_MONITOR("Belos::MVT::MvTimesMatAddMv");
258 
259  const int m = B.numRows();
260  const int n = B.numCols();
261  // Check if B is 1-by-1, in which case we can just call MvAddMv()
262  if ((m == 1) && (n == 1)) {
263  using Teuchos::tuple; using Teuchos::ptrInArg; using Teuchos::inoutArg;
264  const ScalarType alphaNew = alpha * B(0, 0);
265  Thyra::linear_combination<ScalarType>(tuple(alphaNew)(), tuple(ptrInArg(A))(), beta, inoutArg(mv));
266  } else {
267  // perform the operation via A: mv <- alpha*A*B_thyra + beta*mv
268  auto vs = A.domain();
269  // Create a view of the B object!
271  B_thyra = vs->createCachedMembersView(
273  0, m, 0, n,
274  arcpFromArrayView(arrayView(&B(0,0), B.stride()*B.numCols())), B.stride()
275  )
276  );
277  Thyra::apply<ScalarType>(A, Thyra::NOTRANS, *B_thyra, Teuchos::outArg(mv), alpha, beta);
278  }
279  }
280 
283  static void MvAddMv( const ScalarType alpha, const TMVB& A,
284  const ScalarType beta, const TMVB& B, TMVB& mv )
285  {
286  using Teuchos::tuple; using Teuchos::ptrInArg; using Teuchos::inoutArg;
287  STRATIMIKOS_TIME_MONITOR("Belos::MVT::MvAddMv");
288 
289  Thyra::linear_combination<ScalarType>(
290  tuple(alpha, beta)(), tuple(ptrInArg(A), ptrInArg(B))(), Teuchos::ScalarTraits<ScalarType>::zero(), inoutArg(mv));
291  }
292 
295  static void MvScale ( TMVB& mv, const ScalarType alpha )
296  {
297  STRATIMIKOS_TIME_MONITOR("Belos::MVT::MvScale");
298 
299  Thyra::scale(alpha, Teuchos::inoutArg(mv));
300  }
301 
304  static void MvScale (TMVB& mv, const std::vector<ScalarType>& alpha)
305  {
306  STRATIMIKOS_TIME_MONITOR("Belos::MVT::MvScale");
307 
308  for (unsigned int i=0; i<alpha.size(); i++) {
309  Thyra::scale<ScalarType> (alpha[i], mv.col(i).ptr());
310  }
311  }
312 
315  static void MvTransMv( const ScalarType alpha, const TMVB& A, const TMVB& mv,
317  {
318  using Teuchos::arrayView; using Teuchos::arcpFromArrayView;
319  STRATIMIKOS_TIME_MONITOR("Belos::MVT::MvTransMv");
320 
321  // Create a multivector to hold the result (m by n)
322  int m = A.domain()->dim();
323  int n = mv.domain()->dim();
324  auto vs = A.domain();
325  // Create a view of the B object!
327  B_thyra = vs->createCachedMembersView(
329  0, m, 0, n,
330  arcpFromArrayView(arrayView(&B(0,0), B.stride()*B.numCols())), B.stride()
331  ),
332  false
333  );
334  Thyra::apply<ScalarType>(A, Thyra::CONJTRANS, mv, B_thyra.ptr(), alpha);
335  }
336 
340  static void MvDot( const TMVB& mv, const TMVB& A, std::vector<ScalarType>& b )
341  {
342  STRATIMIKOS_TIME_MONITOR("Belos::MVT::MvDot");
343 
344  Thyra::dots(mv, A, Teuchos::arrayViewFromVector(b));
345  }
346 
348 
351 
355  static void MvNorm( const TMVB& mv, std::vector<magType>& normvec,
356  NormType type = TwoNorm ) {
357  STRATIMIKOS_TIME_MONITOR("Belos::MVT::MvNorm");
358 
359  if(type == TwoNorm)
360  Thyra::norms_2(mv, Teuchos::arrayViewFromVector(normvec));
361  else if(type == OneNorm)
362  Thyra::norms_1(mv, Teuchos::arrayViewFromVector(normvec));
363  else if(type == InfNorm)
364  Thyra::norms_inf(mv, Teuchos::arrayViewFromVector(normvec));
365  else
366  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
367  "Belos::MultiVecTraits::MvNorm (Thyra specialization): "
368  "invalid norm type. Must be either TwoNorm, OneNorm or InfNorm");
369  }
370 
372 
375 
378  static void SetBlock( const TMVB& A, const std::vector<int>& index, TMVB& mv )
379  {
380  // Extract the "numvecs" columns of mv indicated by the index std::vector.
381  int numvecs = index.size();
382  std::vector<int> indexA(numvecs);
383  int numAcols = A.domain()->dim();
384  for (int i=0; i<numvecs; i++) {
385  indexA[i] = i;
386  }
387  // Thyra::assign requires that both arguments have the same number of
388  // vectors. Enforce this, by shrinking one to match the other.
389  if ( numAcols < numvecs ) {
390  // A does not have enough columns to satisfy index_plus. Shrink
391  // index_plus.
392  numvecs = numAcols;
393  }
394  else if ( numAcols > numvecs ) {
395  numAcols = numvecs;
396  indexA.resize( numAcols );
397  }
398  // create a view to the relevant part of the source multivector
399  Teuchos::RCP< const TMVB > relsource = A.subView(indexA);
400  // create a view to the relevant part of the destination multivector
401  Teuchos::RCP< TMVB > reldest = mv.subView(index);
402  // copy the data to the destination multivector subview
403  Thyra::assign(reldest.ptr(), *relsource);
404  }
405 
406  static void
407  SetBlock (const TMVB& A, const Teuchos::Range1D& index, TMVB& mv)
408  {
409  const int numColsA = A.domain()->dim();
410  const int numColsMv = mv.domain()->dim();
411  // 'index' indexes into mv; it's the index set of the target.
412  const bool validIndex = index.lbound() >= 0 && index.ubound() < numColsMv;
413  // We can't take more columns out of A than A has.
414  const bool validSource = index.size() <= numColsA;
415 
416  if (! validIndex || ! validSource)
417  {
418  std::ostringstream os;
419  os << "Belos::MultiVecTraits<Scalar, Thyra::MultiVectorBase<Scalar> "
420  ">::SetBlock(A, [" << index.lbound() << ", " << index.ubound()
421  << "], mv): ";
422  TEUCHOS_TEST_FOR_EXCEPTION(index.lbound() < 0, std::invalid_argument,
423  os.str() << "Range lower bound must be nonnegative.");
424  TEUCHOS_TEST_FOR_EXCEPTION(index.ubound() >= numColsMv, std::invalid_argument,
425  os.str() << "Range upper bound must be less than "
426  "the number of columns " << numColsA << " in the "
427  "'mv' output argument.");
428  TEUCHOS_TEST_FOR_EXCEPTION(index.size() > numColsA, std::invalid_argument,
429  os.str() << "Range must have no more elements than"
430  " the number of columns " << numColsA << " in the "
431  "'A' input argument.");
432  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Should never get here!");
433  }
434 
435  // View of the relevant column(s) of the target multivector mv.
436  // We avoid view creation overhead by only creating a view if
437  // the index range is different than [0, (# columns in mv) - 1].
438  Teuchos::RCP<TMVB> mv_view;
439  if (index.lbound() == 0 && index.ubound()+1 == numColsMv)
440  mv_view = Teuchos::rcpFromRef (mv); // Non-const, non-owning RCP
441  else
442  mv_view = mv.subView (index);
443 
444  // View of the relevant column(s) of the source multivector A.
445  // If A has fewer columns than mv_view, then create a view of
446  // the first index.size() columns of A.
448  if (index.size() == numColsA)
449  A_view = Teuchos::rcpFromRef (A); // Const, non-owning RCP
450  else
451  A_view = A.subView (Teuchos::Range1D(0, index.size()-1));
452 
453  // Copy the data to the destination multivector.
454  Thyra::assign(mv_view.ptr(), *A_view);
455  }
456 
457  static void
458  Assign (const TMVB& A, TMVB& mv)
459  {
460  STRATIMIKOS_TIME_MONITOR("Belos::MVT::Assign");
461 
462  const int numColsA = A.domain()->dim();
463  const int numColsMv = mv.domain()->dim();
464  if (numColsA > numColsMv)
465  {
466  std::ostringstream os;
467  os << "Belos::MultiVecTraits<Scalar, Thyra::MultiVectorBase<Scalar>"
468  " >::Assign(A, mv): ";
469  TEUCHOS_TEST_FOR_EXCEPTION(numColsA > numColsMv, std::invalid_argument,
470  os.str() << "Input multivector 'A' has "
471  << numColsA << " columns, but output multivector "
472  "'mv' has only " << numColsMv << " columns.");
473  TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Should never get here!");
474  }
475  // Copy the data to the destination multivector.
476  if (numColsA == numColsMv) {
477  Thyra::assign (Teuchos::outArg (mv), A);
478  } else {
479  Teuchos::RCP<TMVB> mv_view =
480  CloneViewNonConst (mv, Teuchos::Range1D(0, numColsA-1));
481  Thyra::assign (mv_view.ptr(), A);
482  }
483  }
484 
487  static void MvRandom( TMVB& mv )
488  {
489  // Thyra::randomize generates via a uniform distribution on [l,u]
490  // We will use this to generate on [-1,1]
491  Thyra::randomize<ScalarType>(
494  Teuchos::outArg(mv));
495  }
496 
498  static void
499  MvInit (TMVB& mv, ScalarType alpha = Teuchos::ScalarTraits<ScalarType>::zero())
500  {
501  Thyra::assign (Teuchos::outArg (mv), alpha);
502  }
503 
505 
508 
511  static void MvPrint( const TMVB& mv, std::ostream& os )
512  { os << describe(mv,Teuchos::VERB_EXTREME); }
513 
515 
516 #ifdef HAVE_BELOS_TSQR
517  typedef Thyra::TsqrAdaptor< ScalarType > tsqr_adaptor_type;
523 #endif // HAVE_BELOS_TSQR
524  };
525 
527  //
528  // Implementation of the Belos::OperatorTraits for Thyra::LinearOpBase
529  //
531 
539  template<class ScalarType>
540  class OperatorTraits <ScalarType,
541  Thyra::MultiVectorBase<ScalarType>,
542  Thyra::LinearOpBase<ScalarType> >
543  {
544  private:
545  typedef Thyra::MultiVectorBase<ScalarType> TMVB;
546  typedef Thyra::LinearOpBase<ScalarType> TLOB;
547 
548  public:
564  static void
565  Apply (const TLOB& Op,
566  const TMVB& x,
567  TMVB& y,
568  ETrans trans = NOTRANS)
569  {
570  Thyra::EOpTransp whichOp;
571 
572  // We don't check here whether the operator implements the
573  // requested operation. Call HasApplyTranspose() to check.
574  // Thyra::LinearOpBase implementations are not required to
575  // implement NOTRANS. However, Belos needs NOTRANS
576  // (obviously!), so we assume that Op implements NOTRANS.
577  if (trans == NOTRANS)
578  whichOp = Thyra::NOTRANS;
579  else if (trans == TRANS)
580  whichOp = Thyra::TRANS;
581  else if (trans == CONJTRANS)
582  whichOp = Thyra::CONJTRANS;
583  else
584  TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
585  "Belos::OperatorTraits::Apply (Thyra specialization): "
586  "'trans' argument must be neither NOTRANS=" << NOTRANS
587  << ", TRANS=" << TRANS << ", or CONJTRANS=" << CONJTRANS
588  << ", but instead has an invalid value of " << trans << ".");
589  Thyra::apply<ScalarType>(Op, whichOp, x, Teuchos::outArg(y));
590  }
591 
593  static bool HasApplyTranspose (const TLOB& Op)
594  {
596 
597  // Thyra::LinearOpBase's interface lets you check whether the
598  // operator implements any of all four possible combinations of
599  // conjugation and transpose. Belos only needs transpose
600  // (TRANS) if the operator is real; in that case, Apply() does
601  // the same thing with trans = CONJTRANS or TRANS. If the
602  // operator is complex, Belos needs both transpose and conjugate
603  // transpose (CONJTRANS) if the operator is complex.
604  return Op.opSupported (Thyra::TRANS) &&
605  (! STS::isComplex || Op.opSupported (Thyra::CONJTRANS));
606  }
607  };
608 
609 } // end of Belos namespace
610 
611 #endif
612 // end of file BELOS_THYRA_ADAPTER_HPP
static int GetNumberVecs(const TMVB &mv)
Obtain the number of vectors in mv.
static ptrdiff_t GetGlobalLength(const TMVB &mv)
Obtain the std::vector length of mv.
static void MvPrint(const TMVB &mv, std::ostream &os)
Print the mv multi-std::vector to the os output stream.
Stub adaptor from Thyra::MultiVectorBase to TSQR.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
static Teuchos::RCP< TMVB > CloneCopy(const TMVB &mv, const std::vector< int > &index)
Creates a new MultiVectorBase and copies the selected contents of mv into the new std::vector (deep c...
static void MvTransMv(const ScalarType alpha, const TMVB &A, const TMVB &mv, Teuchos::SerialDenseMatrix< int, ScalarType > &B)
Compute a dense matrix B through the matrix-matrix multiply .
static void MvScale(TMVB &mv, const std::vector< ScalarType > &alpha)
Scale each element of the i-th vector in *this with alpha[i].
static void MvDot(const TMVB &mv, const TMVB &A, std::vector< ScalarType > &b)
Compute a std::vector b where the components are the individual dot-products of the i-th columns of A...
Ordinal ubound() const
static Teuchos::RCP< TMVB > CloneCopy(const TMVB &mv)
Creates a new MultiVectorBase and copies contents of mv into the new std::vector (deep copy)...
static void MvScale(TMVB &mv, const ScalarType alpha)
Scale each element of the vectors in *this with alpha.
static void MvTimesMatAddMv(const ScalarType alpha, const TMVB &A, const Teuchos::SerialDenseMatrix< int, ScalarType > &B, const ScalarType beta, TMVB &mv)
Update mv with .
Ptr< T > ptr() const
static Teuchos::RCP< const TMVB > CloneView(const TMVB &mv, const std::vector< int > &index)
Creates a new const MultiVectorBase that shares the selected contents of mv (shallow copy)...
static Teuchos::RCP< TMVB > CloneCopy(const TMVB &mv, const Teuchos::Range1D &index)
static void Apply(const TLOB &Op, const TMVB &x, TMVB &y, ETrans trans=NOTRANS)
Apply Op to x, storing the result in y.
static void MvRandom(TMVB &mv)
Replace the vectors in mv with random vectors.
static Teuchos::RCP< TMVB > CloneViewNonConst(TMVB &mv, const Teuchos::Range1D &index)
Ordinal lbound() const
OrdinalType numCols() const
static void SetBlock(const TMVB &A, const std::vector< int > &index, TMVB &mv)
Copy the vectors in A to a set of vectors in mv indicated by the indices given in index...
static void SetBlock(const TMVB &A, const Teuchos::Range1D &index, TMVB &mv)
Ordinal size() const
static void MvNorm(const TMVB &mv, std::vector< magType > &normvec, NormType type=TwoNorm)
Compute the 2-norm of each individual std::vector of mv. Upon return, normvec[i] holds the value of ...
static bool HasApplyTranspose(const TLOB &Op)
Whether the operator implements applying the transpose.
static Teuchos::RCP< TMVB > CloneViewNonConst(TMVB &mv, const std::vector< int > &index)
Creates a new MultiVectorBase that shares the selected contents of mv (shallow copy).
static Teuchos::RCP< const TMVB > CloneView(const TMVB &mv, const Teuchos::Range1D &index)
int n
OrdinalType stride() const
static Teuchos::RCP< TMVB > Clone(const TMVB &mv, const int numvecs)
Creates a new empty MultiVectorBase containing numvecs columns.
static void MvAddMv(const ScalarType alpha, const TMVB &A, const ScalarType beta, const TMVB &B, TMVB &mv)
Replace mv with .
OrdinalType numRows() const
#define STRATIMIKOS_TIME_MONITOR(NAME)