Stratimikos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
BelosThyraAdapter.hpp
Go to the documentation of this file.
00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 //         Stratimikos: Thyra-based strategies for linear solvers
00005 //                Copyright (2006) Sandia Corporation
00006 // 
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 // 
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Roscoe A. Bartlett (rabartl@sandia.gov) 
00038 // 
00039 // ***********************************************************************
00040 // @HEADER
00041 
00052 #ifndef BELOS_THYRA_ADAPTER_HPP
00053 #define BELOS_THYRA_ADAPTER_HPP
00054 
00055 #include "BelosConfigDefs.hpp"
00056 #include "BelosMultiVecTraits.hpp"
00057 #include "BelosOperatorTraits.hpp"
00058 
00059 #include <Thyra_DetachedMultiVectorView.hpp>
00060 #include <Thyra_MultiVectorBase.hpp>
00061 #include <Thyra_MultiVectorStdOps.hpp>
00062 #ifdef HAVE_BELOS_TSQR
00063 #  include <Thyra_TsqrAdaptor.hpp>
00064 #endif // HAVE_BELOS_TSQR
00065 
00066 namespace Belos {
00067 
00069   //
00070   // Implementation of the Belos::MultiVecTraits for Thyra::MultiVectorBase
00071   //
00073 
00080   template<class ScalarType>
00081   class MultiVecTraits< ScalarType, Thyra::MultiVectorBase<ScalarType> >
00082   {
00083   private:
00084     typedef Thyra::MultiVectorBase<ScalarType> TMVB;
00085     typedef Teuchos::ScalarTraits<ScalarType> ST;
00086     typedef typename ST::magnitudeType magType;
00087 
00088   public:
00089 
00092 
00097     static Teuchos::RCP<TMVB> Clone( const TMVB& mv, const int numvecs )
00098     {
00099       Teuchos::RCP<TMVB> c = Thyra::createMembers( mv.range(), numvecs );
00100       return c;
00101     }
00102 
00107     static Teuchos::RCP<TMVB> CloneCopy( const TMVB& mv )
00108     {
00109       int numvecs = mv.domain()->dim();
00110       // create the new multivector
00111       Teuchos::RCP< TMVB > cc = Thyra::createMembers( mv.range(), numvecs );
00112       // copy the data from the source multivector to the new multivector
00113       Thyra::assign(cc.ptr(), mv);
00114       return cc;
00115     }
00116 
00122     static Teuchos::RCP<TMVB> CloneCopy( const TMVB& mv, const std::vector<int>& index )
00123     {
00124       int numvecs = index.size();
00125       // create the new multivector
00126       Teuchos::RCP<TMVB> cc = Thyra::createMembers( mv.range(), numvecs );
00127       // create a view to the relevant part of the source multivector
00128       Teuchos::RCP<const TMVB> view = mv.subView(index);
00129       // copy the data from the relevant view to the new multivector
00130       Thyra::assign(cc.ptr(), *view);
00131       return cc;
00132     }
00133 
00134     static Teuchos::RCP<TMVB>
00135     CloneCopy (const TMVB& mv, const Teuchos::Range1D& index)
00136     {
00137       const int numVecs = index.size();
00138       // Create the new multivector
00139       Teuchos::RCP<TMVB> cc = Thyra::createMembers (mv.range(), numVecs);
00140       // Create a view to the relevant part of the source multivector
00141       Teuchos::RCP<const TMVB> view = mv.subView (index);
00142       // Copy the data from the view to the new multivector.
00143       Thyra::assign (cc.ptr(), *view);
00144       return cc;
00145     }
00146 
00152     static Teuchos::RCP<TMVB> CloneViewNonConst( TMVB& mv, const std::vector<int>& index )
00153     {
00154       int numvecs = index.size();
00155 
00156       // We do not assume that the indices are sorted, nor do we check that
00157       // index.size() > 0. This code is fail-safe, in the sense that a zero
00158       // length index std::vector will pass the error on the Thyra.
00159 
00160       // Thyra has two ways to create an indexed View:
00161       // * contiguous (via a range of columns)
00162       // * indexed (via a std::vector of column indices)
00163       // The former is significantly more efficient than the latter, in terms of
00164       // computations performed with/against the created view.
00165       // We will therefore check to see if the given indices are contiguous, and
00166       // if so, we will use the contiguous view creation method.
00167 
00168       int lb = index[0];
00169       bool contig = true;
00170       for (int i=0; i<numvecs; i++) {
00171         if (lb+i != index[i]) contig = false;
00172       }
00173 
00174       Teuchos::RCP< TMVB > cc;
00175       if (contig) {
00176         const Thyra::Range1D rng(lb,lb+numvecs-1);
00177         // create a contiguous view to the relevant part of the source multivector
00178         cc = mv.subView(rng);
00179       }
00180       else {
00181         // create an indexed view to the relevant part of the source multivector
00182         cc = mv.subView(index);
00183       }
00184       return cc;
00185     }
00186 
00187     static Teuchos::RCP<TMVB>
00188     CloneViewNonConst (TMVB& mv, const Teuchos::Range1D& index)
00189     {
00190       // We let Thyra be responsible for checking that the index range
00191       // is nonempty.
00192       //
00193       // Create and return a contiguous view to the relevant part of
00194       // the source multivector.
00195       return mv.subView (index);
00196     }
00197 
00198 
00204     static Teuchos::RCP<const TMVB> CloneView( const TMVB& mv, const std::vector<int>& index )
00205     {
00206       int numvecs = index.size();
00207 
00208       // We do not assume that the indices are sorted, nor do we check that
00209       // index.size() > 0. This code is fail-safe, in the sense that a zero
00210       // length index std::vector will pass the error on the Thyra.
00211 
00212       // Thyra has two ways to create an indexed View:
00213       // * contiguous (via a range of columns)
00214       // * indexed (via a std::vector of column indices)
00215       // The former is significantly more efficient than the latter, in terms of
00216       // computations performed with/against the created view.
00217       // We will therefore check to see if the given indices are contiguous, and
00218       // if so, we will use the contiguous view creation method.
00219 
00220       int lb = index[0];
00221       bool contig = true;
00222       for (int i=0; i<numvecs; i++) {
00223         if (lb+i != index[i]) contig = false;
00224       }
00225 
00226       Teuchos::RCP< const TMVB > cc;
00227       if (contig) {
00228         const Thyra::Range1D rng(lb,lb+numvecs-1);
00229         // create a contiguous view to the relevant part of the source multivector
00230         cc = mv.subView(rng);
00231       }
00232       else {
00233         // create an indexed view to the relevant part of the source multivector
00234         cc = mv.subView(index);
00235       }
00236       return cc;
00237     }
00238 
00239     static Teuchos::RCP<const TMVB>
00240     CloneView (const TMVB& mv, const Teuchos::Range1D& index)
00241     {
00242       // We let Thyra be responsible for checking that the index range
00243       // is nonempty.
00244       //
00245       // Create and return a contiguous view to the relevant part of
00246       // the source multivector.
00247       return mv.subView (index);
00248     }
00249 
00251 
00254 
00256     static int GetVecLength( const TMVB& mv )
00257     { return mv.range()->dim(); }
00258 
00260     static int GetNumberVecs( const TMVB& mv )
00261     { return mv.domain()->dim(); }
00262 
00264 
00267 
00270     static void MvTimesMatAddMv( const ScalarType alpha, const TMVB& A,
00271          const Teuchos::SerialDenseMatrix<int,ScalarType>& B,
00272          const ScalarType beta, TMVB& mv )
00273     {
00274       using Teuchos::arrayView; using Teuchos::arcpFromArrayView;
00275       const int m = B.numRows();
00276       const int n = B.numCols();
00277       // Create a view of the B object!
00278       Teuchos::RCP< const TMVB >
00279         B_thyra = Thyra::createMembersView(
00280           A.domain(),
00281           RTOpPack::ConstSubMultiVectorView<ScalarType>(
00282             0, m, 0, n,
00283             arcpFromArrayView(arrayView(&B(0,0), B.stride()*B.numCols())), B.stride()
00284             )
00285           );
00286       // perform the operation via A: mv <- alpha*A*B_thyra + beta*mv
00287       Thyra::apply<ScalarType>(A, Thyra::NOTRANS, *B_thyra, Teuchos::outArg(mv), alpha, beta);
00288     }
00289 
00292     static void MvAddMv( const ScalarType alpha, const TMVB& A,
00293                          const ScalarType beta,  const TMVB& B, TMVB& mv )
00294     {
00295       typedef Teuchos::ScalarTraits<ScalarType> ST;
00296       using Teuchos::tuple; using Teuchos::ptrInArg; using Teuchos::inoutArg;
00297 
00298       Thyra::linear_combination<ScalarType>(
00299         tuple(alpha, beta)(), tuple(ptrInArg(A), ptrInArg(B))(), ST::zero(), inoutArg(mv));
00300     }
00301 
00304     static void MvScale ( TMVB& mv, const ScalarType alpha )
00305       { Thyra::scale(alpha, Teuchos::inoutArg(mv)); }
00306 
00309     static void MvScale (TMVB& mv, const std::vector<ScalarType>& alpha)
00310     {
00311       for (unsigned int i=0; i<alpha.size(); i++) {
00312         Thyra::scale<ScalarType> (alpha[i], mv.col(i).ptr());
00313       }
00314     }
00315 
00318     static void MvTransMv( const ScalarType alpha, const TMVB& A, const TMVB& mv,
00319       Teuchos::SerialDenseMatrix<int,ScalarType>& B )
00320     {
00321       using Teuchos::arrayView; using Teuchos::arcpFromArrayView;
00322       // Create a multivector to hold the result (m by n)
00323       int m = A.domain()->dim();
00324       int n = mv.domain()->dim();
00325       // Create a view of the B object!
00326       Teuchos::RCP< TMVB >
00327         B_thyra = Thyra::createMembersView(
00328           A.domain(),
00329           RTOpPack::SubMultiVectorView<ScalarType>(
00330             0, m, 0, n,
00331             arcpFromArrayView(arrayView(&B(0,0), B.stride()*B.numCols())), B.stride()
00332             )
00333           );
00334       Thyra::apply<ScalarType>(A, Thyra::CONJTRANS, mv, B_thyra.ptr(), alpha);
00335     }
00336 
00340     static void MvDot( const TMVB& mv, const TMVB& A, std::vector<ScalarType>& b )
00341       { Thyra::dots(mv, A, Teuchos::arrayViewFromVector(b)); }
00342 
00344 
00347 
00351     static void MvNorm( const TMVB& mv, std::vector<magType>& normvec,
00352       NormType type = TwoNorm )
00353       { Thyra::norms_2(mv, Teuchos::arrayViewFromVector(normvec)); }
00354 
00356 
00359 
00362     static void SetBlock( const TMVB& A, const std::vector<int>& index, TMVB& mv )
00363     {
00364       // Extract the "numvecs" columns of mv indicated by the index std::vector.
00365       int numvecs = index.size();
00366       std::vector<int> indexA(numvecs);
00367       int numAcols = A.domain()->dim();
00368       for (int i=0; i<numvecs; i++) {
00369         indexA[i] = i;
00370       }
00371       // Thyra::assign requires that both arguments have the same number of
00372       // vectors. Enforce this, by shrinking one to match the other.
00373       if ( numAcols < numvecs ) {
00374         // A does not have enough columns to satisfy index_plus. Shrink
00375         // index_plus.
00376         numvecs = numAcols;
00377       }
00378       else if ( numAcols > numvecs ) {
00379         numAcols = numvecs;
00380         indexA.resize( numAcols );
00381       }
00382       // create a view to the relevant part of the source multivector
00383       Teuchos::RCP< const TMVB > relsource = A.subView(indexA);
00384       // create a view to the relevant part of the destination multivector
00385       Teuchos::RCP< TMVB > reldest = mv.subView(index);
00386       // copy the data to the destination multivector subview
00387       Thyra::assign(reldest.ptr(), *relsource);
00388     }
00389 
00390     static void
00391     SetBlock (const TMVB& A, const Teuchos::Range1D& index, TMVB& mv)
00392     {
00393       const int numColsA = A.domain()->dim();
00394       const int numColsMv = mv.domain()->dim();
00395       // 'index' indexes into mv; it's the index set of the target.
00396       const bool validIndex = index.lbound() >= 0 && index.ubound() < numColsMv;
00397       // We can't take more columns out of A than A has.
00398       const bool validSource = index.size() <= numColsA;
00399 
00400       if (! validIndex || ! validSource)
00401         {
00402           std::ostringstream os;
00403           os << "Belos::MultiVecTraits<Scalar, Thyra::MultiVectorBase<Scalar> "
00404             ">::SetBlock(A, [" << index.lbound() << ", " << index.ubound()
00405              << "], mv): ";
00406           TEUCHOS_TEST_FOR_EXCEPTION(index.lbound() < 0, std::invalid_argument,
00407                              os.str() << "Range lower bound must be nonnegative.");
00408           TEUCHOS_TEST_FOR_EXCEPTION(index.ubound() >= numColsMv, std::invalid_argument,
00409                              os.str() << "Range upper bound must be less than "
00410                              "the number of columns " << numColsA << " in the "
00411                              "'mv' output argument.");
00412           TEUCHOS_TEST_FOR_EXCEPTION(index.size() > numColsA, std::invalid_argument,
00413                              os.str() << "Range must have no more elements than"
00414                              " the number of columns " << numColsA << " in the "
00415                              "'A' input argument.");
00416           TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Should never get here!");
00417         }
00418 
00419       // View of the relevant column(s) of the target multivector mv.
00420       // We avoid view creation overhead by only creating a view if
00421       // the index range is different than [0, (# columns in mv) - 1].
00422       Teuchos::RCP<TMVB> mv_view;
00423       if (index.lbound() == 0 && index.ubound()+1 == numColsMv)
00424         mv_view = Teuchos::rcpFromRef (mv); // Non-const, non-owning RCP
00425       else
00426         mv_view = mv.subView (index);
00427 
00428       // View of the relevant column(s) of the source multivector A.
00429       // If A has fewer columns than mv_view, then create a view of
00430       // the first index.size() columns of A.
00431       Teuchos::RCP<const TMVB> A_view;
00432       if (index.size() == numColsA)
00433         A_view = Teuchos::rcpFromRef (A); // Const, non-owning RCP
00434       else
00435         A_view = A.subView (Teuchos::Range1D(0, index.size()-1));
00436 
00437       // Copy the data to the destination multivector.
00438       Thyra::assign(mv_view.ptr(), *A_view);
00439     }
00440 
00441     static void
00442     Assign (const TMVB& A, TMVB& mv)
00443     {
00444       const int numColsA = A.domain()->dim();
00445       const int numColsMv = mv.domain()->dim();
00446       if (numColsA > numColsMv)
00447         {
00448           std::ostringstream os;
00449           os << "Belos::MultiVecTraits<Scalar, Thyra::MultiVectorBase<Scalar>"
00450             " >::Assign(A, mv): ";
00451           TEUCHOS_TEST_FOR_EXCEPTION(numColsA > numColsMv, std::invalid_argument,
00452                              os.str() << "Input multivector 'A' has "
00453                              << numColsA << " columns, but output multivector "
00454                              "'mv' has only " << numColsMv << " columns.");
00455           TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "Should never get here!");
00456         }
00457       // Copy the data to the destination multivector.
00458       if (numColsA == numColsMv) {
00459         Thyra::assign (Teuchos::outArg (mv), A);
00460       } else {
00461         Teuchos::RCP<TMVB> mv_view =
00462           CloneViewNonConst (mv, Teuchos::Range1D(0, numColsA-1));
00463         Thyra::assign (mv_view.ptr(), A);
00464       }
00465     }
00466 
00469     static void MvRandom( TMVB& mv )
00470     {
00471       // Thyra::randomize generates via a uniform distribution on [l,u]
00472       // We will use this to generate on [-1,1]
00473       Thyra::randomize<ScalarType>(
00474         -Teuchos::ScalarTraits<ScalarType>::one(),
00475         Teuchos::ScalarTraits<ScalarType>::one(),
00476         Teuchos::outArg(mv));
00477     }
00478 
00480     static void
00481     MvInit (TMVB& mv, ScalarType alpha = Teuchos::ScalarTraits<ScalarType>::zero())
00482     {
00483       Thyra::assign (Teuchos::outArg (mv), alpha);
00484     }
00485 
00487 
00490 
00493     static void MvPrint( const TMVB& mv, std::ostream& os )
00494       { os << describe(mv,Teuchos::VERB_EXTREME); }
00495 
00497 
00498 #ifdef HAVE_BELOS_TSQR
00499 
00500 
00501 
00502 
00503 
00504     typedef Thyra::TsqrAdaptor< ScalarType > tsqr_adaptor_type;
00505 #endif // HAVE_BELOS_TSQR
00506   };
00507 
00509   //
00510   // Implementation of the Belos::OperatorTraits for Thyra::LinearOpBase
00511   //
00513 
00521   template<class ScalarType>
00522   class OperatorTraits <ScalarType,
00523                         Thyra::MultiVectorBase<ScalarType>,
00524                         Thyra::LinearOpBase<ScalarType> >
00525   {
00526   private:
00527     typedef Thyra::MultiVectorBase<ScalarType> TMVB;
00528     typedef Thyra::LinearOpBase<ScalarType>    TLOB;
00529 
00530   public:
00546     static void
00547     Apply (const TLOB& Op,
00548            const TMVB& x,
00549            TMVB& y,
00550            ETrans trans = NOTRANS)
00551     {
00552       Thyra::EOpTransp whichOp;
00553 
00554       // We don't check here whether the operator implements the
00555       // requested operation.  Call HasApplyTranspose() to check.
00556       // Thyra::LinearOpBase implementations are not required to
00557       // implement NOTRANS.  However, Belos needs NOTRANS
00558       // (obviously!), so we assume that Op implements NOTRANS.
00559       if (trans == NOTRANS)
00560         whichOp = Thyra::NOTRANS;
00561       else if (trans == TRANS)
00562         whichOp = Thyra::TRANS;
00563       else if (trans == CONJTRANS)
00564         whichOp = Thyra::CONJTRANS;
00565       else
00566         TEUCHOS_TEST_FOR_EXCEPTION(true, std::invalid_argument,
00567                            "Belos::OperatorTraits::Apply (Thyra specialization): "
00568                            "'trans' argument must be neither NOTRANS=" << NOTRANS
00569                            << ", TRANS=" << TRANS << ", or CONJTRANS=" << CONJTRANS
00570                            << ", but instead has an invalid value of " << trans << ".");
00571       Thyra::apply<ScalarType>(Op, whichOp, x, Teuchos::outArg(y));
00572     }
00573 
00575     static bool HasApplyTranspose (const TLOB& Op)
00576     {
00577       typedef Teuchos::ScalarTraits<ScalarType> STS;
00578 
00579       // Thyra::LinearOpBase's interface lets you check whether the
00580       // operator implements any of all four possible combinations of
00581       // conjugation and transpose.  Belos only needs transpose
00582       // (TRANS) if the operator is real; in that case, Apply() does
00583       // the same thing with trans = CONJTRANS or TRANS.  If the
00584       // operator is complex, Belos needs both transpose and conjugate
00585       // transpose (CONJTRANS) if the operator is complex.
00586       return Op.opSupported (Thyra::TRANS) &&
00587         (! STS::isComplex || Op.opSupported (Thyra::CONJTRANS));
00588     }
00589   };
00590 
00591   // Partial specialization for MV=Thyra::MultiVectorBase. This supports 64-bit types
00592   template<class ScalarType>
00593   class MultiVecTraitsExt<ScalarType, Thyra::MultiVectorBase<ScalarType> > {
00594   public: 
00595     typedef Thyra::MultiVectorBase<ScalarType> MV; 
00596     static ptrdiff_t GetGlobalLength( const MV& mv ) { 
00597       return Teuchos::as<ptrdiff_t>(mv.range()->dim());
00598     } 
00599   };
00600 
00601 } // end of Belos namespace
00602 
00603 #endif
00604 // end of file BELOS_THYRA_ADAPTER_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines