Thyra_LinearOpWithSolveTester.hpp

00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 //    Thyra: Interfaces and Support for Abstract Numerical Algorithms
00005 //                 Copyright (2004) 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 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //  
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //  
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 
00025 // 
00026 // ***********************************************************************
00027 // @HEADER
00028 
00029 
00030 #ifndef THYRA_LINEAR_OP_WITH_SOLVE_TESTER_HPP
00031 #define THYRA_LINEAR_OP_WITH_SOLVE_TESTER_HPP
00032 
00033 
00034 #include "Thyra_LinearOpWithSolveTesterDecl.hpp"
00035 #include "Thyra_LinearOpWithSolveBase.hpp"
00036 #include "Thyra_DefaultScaledAdjointLinearOp.hpp"
00037 #include "Thyra_describeLinearOp.hpp"
00038 #include "Thyra_VectorStdOps.hpp"
00039 #include "Thyra_MultiVectorStdOps.hpp"
00040 #include "Thyra_TestingTools.hpp"
00041 #include "Teuchos_Time.hpp"
00042 
00043 
00044 namespace Thyra {
00045 
00046 
00047 // Constructors/initializers
00048 
00049 
00050 template<class RangeScalar, class DomainScalar>
00051 LinearOpWithSolveTester<RangeScalar,DomainScalar>::LinearOpWithSolveTester()
00052   :check_forward_default_(check_forward_default_default_),
00053    forward_default_residual_warning_tol_(warning_tol_default_),
00054    forward_default_residual_error_tol_(error_tol_default_),
00055    forward_default_solution_error_warning_tol_(warning_tol_default_),
00056    forward_default_solution_error_error_tol_(error_tol_default_),
00057    check_forward_residual_(check_forward_residual_default_),
00058    forward_residual_solve_tol_(solve_tol_default_),
00059    forward_residual_slack_warning_tol_(slack_warning_tol_default_),
00060    forward_residual_slack_error_tol_(slack_error_tol_default_),
00061    check_adjoint_default_(check_adjoint_default_default_),
00062    adjoint_default_residual_warning_tol_(warning_tol_default_),
00063    adjoint_default_residual_error_tol_(error_tol_default_),
00064    adjoint_default_solution_error_warning_tol_(warning_tol_default_),
00065    adjoint_default_solution_error_error_tol_(error_tol_default_),
00066    check_adjoint_residual_(check_adjoint_residual_default_),
00067    adjoint_residual_solve_tol_(solve_tol_default_),
00068    adjoint_residual_slack_warning_tol_(slack_warning_tol_default_),
00069    adjoint_residual_slack_error_tol_(slack_error_tol_default_),
00070    num_random_vectors_(num_random_vectors_default_),
00071    show_all_tests_(show_all_tests_default_),
00072    dump_all_(dump_all_default_),
00073    num_rhs_(num_rhs_default_)
00074 {}
00075 
00076 
00077 template<class RangeScalar, class DomainScalar>
00078 void LinearOpWithSolveTester<RangeScalar,DomainScalar>::turn_off_all_tests()
00079 {
00080   check_forward_default_ = false;
00081   check_forward_residual_ = false;
00082   check_adjoint_default_ = false;
00083   check_adjoint_residual_ = false;
00084 }
00085 
00086 
00087 template<class RangeScalar, class DomainScalar>
00088 void
00089 LinearOpWithSolveTester<RangeScalar,DomainScalar>::set_all_solve_tol(
00090   const ScalarMag solve_tol )
00091 {
00092   forward_residual_solve_tol_ = solve_tol;
00093   forward_residual_solve_tol_ = solve_tol;
00094   adjoint_residual_solve_tol_ = solve_tol;
00095 }
00096 
00097 
00098 template<class RangeScalar, class DomainScalar>
00099 void
00100 LinearOpWithSolveTester<RangeScalar,DomainScalar>::set_all_slack_warning_tol(
00101   const ScalarMag slack_warning_tol )
00102 {
00103   forward_default_residual_warning_tol_ = slack_warning_tol;
00104   forward_default_solution_error_warning_tol_ = slack_warning_tol;
00105   forward_residual_slack_warning_tol_ = slack_warning_tol;
00106   adjoint_default_residual_warning_tol_ = slack_warning_tol;
00107   adjoint_default_solution_error_warning_tol_ = slack_warning_tol;
00108   adjoint_residual_slack_warning_tol_ = slack_warning_tol;
00109 }
00110 
00111 
00112 template<class RangeScalar, class DomainScalar>
00113 void
00114 LinearOpWithSolveTester<RangeScalar,DomainScalar>::set_all_slack_error_tol(
00115   const ScalarMag slack_error_tol )
00116 {
00117   forward_default_residual_error_tol_ = slack_error_tol;
00118   forward_default_solution_error_error_tol_ = slack_error_tol;
00119   forward_residual_slack_error_tol_ = slack_error_tol;
00120   adjoint_default_residual_error_tol_ = slack_error_tol;
00121   adjoint_default_solution_error_error_tol_ = slack_error_tol;
00122   adjoint_residual_slack_error_tol_ = slack_error_tol;
00123 }
00124 
00125 
00126 // Overridden from ParameterListAcceptor
00127 
00128 
00129 template<class RangeScalar, class DomainScalar>
00130 void LinearOpWithSolveTester<RangeScalar,DomainScalar>::setParameterList(
00131   const RCP<ParameterList>& paramList )
00132 {
00133   using Teuchos::getParameter;
00134   ParameterList &pl = *paramList;
00135   this->setMyParamList(paramList);
00136   paramList->validateParametersAndSetDefaults(*getValidParameters());
00137   set_all_solve_tol(getParameter<ScalarMag>(pl, AllSolveTol_name_));
00138   set_all_slack_warning_tol(getParameter<ScalarMag>(pl, AllSlackWarningTol_name_));
00139   set_all_slack_error_tol(getParameter<ScalarMag>(pl, AllSlackErrorTol_name_));
00140   show_all_tests(getParameter<bool>(pl, ShowAllTests_name_));
00141   dump_all(getParameter<bool>(pl, DumpAll_name_));
00142   // ToDo: Add more parameters as you need them
00143 }
00144 
00145 
00146 template<class RangeScalar, class DomainScalar>
00147 RCP<const ParameterList>
00148 LinearOpWithSolveTester<RangeScalar,DomainScalar>::getValidParameters() const
00149 {
00150   static RCP<const ParameterList> validPL;
00151   if (is_null(validPL) ) {
00152     RCP<ParameterList> pl = Teuchos::parameterList();
00153     pl->set(AllSolveTol_name_, solve_tol_default_,
00154       "Sets all of the solve tolerances to the same value.  Note: This option\n"
00155       "is applied before any specific tolerance which may override it.");
00156     pl->set(AllSlackWarningTol_name_, slack_warning_tol_default_,
00157       "Sets all of the slack warning values to the same value.  Note: This option\n"
00158       "is applied before any specific tolerance which may override it.");
00159     pl->set(AllSlackErrorTol_name_, slack_error_tol_default_,
00160       "Sets all of the slack error values to the same value.  Note: This option\n"
00161       "is applied before any specific tolerance which may override it.");
00162     pl->set(ShowAllTests_name_, false,
00163       "If true, then all tests be traced to the output stream.");
00164     pl->set(DumpAll_name_, false,
00165       "If true, then all qualtities will be dumped to the output stream.  Warning!\n"
00166       "only do this to debug smaller problems as this can create a lot of output");
00167     // ToDo: Add more parameters as you need them (don't forget to test them)
00168     validPL = pl;
00169   }
00170   return validPL;
00171 }
00172 
00173 
00174 // LOWS testing
00175 
00176 
00177 template<class RangeScalar, class DomainScalar>
00178 bool LinearOpWithSolveTester<RangeScalar,DomainScalar>::check(
00179   const LinearOpWithSolveBase<RangeScalar,DomainScalar> &op,
00180   Teuchos::FancyOStream *out_arg ) const
00181 {
00182 
00183   using std::endl;
00184   using Teuchos::arrayArg;
00185   using Teuchos::FancyOStream;
00186   using Teuchos::OSTab;
00187   typedef Teuchos::VerboseObjectTempState<LinearOpWithSolveBase<RangeScalar,DomainScalar> > VOTS;
00188   typedef Teuchos::ScalarTraits<Scalar>        ST;
00189   typedef Teuchos::ScalarTraits<RangeScalar>   DST;
00190   typedef Teuchos::ScalarTraits<DomainScalar>  RST;
00191   bool success = true, result;
00192   const int num_rhs = this->num_rhs();
00193   Teuchos::RCP<FancyOStream> out = Teuchos::rcp(out_arg,false);
00194   const Teuchos::EVerbosityLevel verbLevel = (dump_all()?Teuchos::VERB_EXTREME:Teuchos::VERB_MEDIUM);
00195   Teuchos::Time timer("");
00196 
00197   OSTab tab(out,1,"THYRA");
00198 
00199   if(out.get()) {
00200     *out <<endl<< "*** Entering LinearOpWithSolveTester<"<<ST::name()<<">::check(op,...) ...\n";
00201     if(show_all_tests()) {
00202       *out <<endl<< "describe forward op:\n" << Teuchos::describe(op,verbLevel);
00203       if(op.applyTransposeSupports(CONJ_ELE) && verbLevel==Teuchos::VERB_EXTREME) {
00204         *out <<endl<< "describe adjoint op:\n";
00205         describeLinearOp<RangeScalar,DomainScalar>(
00206           *adjoint(Teuchos::rcp_implicit_cast< const LinearOpBase<RangeScalar,DomainScalar> >(Teuchos::rcp(&op,false)))
00207           ,*out,verbLevel
00208           );
00209       }
00210     }
00211     else {
00212       *out <<endl<< "describe op: " << op.description() << endl;
00213     }
00214   }
00215   
00216   Teuchos::RCP<const VectorSpaceBase<RangeScalar> >   range  = op.range();
00217   Teuchos::RCP<const VectorSpaceBase<DomainScalar> >  domain = op.domain();
00218   
00219   if( check_forward_default() ) {
00220 
00221     if(out.get()) *out <<endl<< "this->check_forward_default()==true: Checking the default forward solve ... ";
00222 
00223     std::ostringstream ossStore;
00224     Teuchos::RCP<FancyOStream> oss = Teuchos::rcp(new FancyOStream(Teuchos::rcp(&ossStore,false)));
00225     if(out.get()) ossStore.copyfmt(*out);
00226     bool these_results = true;
00227 
00228     *oss <<endl<< "op.solveSupportsConj(NONCONJ_ELE) == true ? ";
00229     result = op.solveSupportsConj(NONCONJ_ELE);
00230     if(!result) these_results = false;
00231     *oss << passfail(result) << endl;
00232 
00233     if(result) {
00234     
00235       *oss
00236         <<endl<< "Checking that the forward default solve matches the forward operator:\n"
00237         <<endl<< "  inv(Op)*Op*v1 == v1"
00238         <<endl<< "          \\___/"
00239         <<endl<< "           v2"
00240         <<endl<< "  \\___________/"
00241         <<endl<< "         v3"
00242         <<endl<< ""
00243         <<endl<< "  v4 = v3-v1"
00244         <<endl<< "  v5 = Op*v3-v2"
00245         <<endl<< ""
00246         <<endl<< "  norm(v4)/norm(v1) <= forward_default_solution_error_error_tol()"
00247         <<endl<< "  norm(v5)/norm(v2) <= forward_default_residual_error_tol()"
00248         <<endl;
00249 
00250       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00251 
00252         OSTab tab(oss);
00253 
00254         *oss <<endl<< "Random vector tests = " << rand_vec_i << endl;
00255 
00256         tab.incrTab();
00257       
00258         *oss <<endl<< "v1 = randomize(-1,+1); ...\n" ;
00259         Teuchos::RCP<MultiVectorBase<DomainScalar> > v1 = createMembers(domain,num_rhs);
00260         Thyra::randomize( DomainScalar(-1.0), DomainScalar(+1.0), &*v1 );
00261         if(dump_all()) *oss <<endl<< "v1 =\n" << describe(*v1,verbLevel);
00262       
00263         *oss <<endl<< "v2 = Op*v1 ...\n" ;
00264         Teuchos::RCP<MultiVectorBase<RangeScalar> > v2 = createMembers(range,num_rhs);
00265         timer.start(true);
00266         op.apply(NONCONJ_ELE,*v1,&*v2);
00267         timer.stop();
00268         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00269         if(dump_all()) *oss <<endl<< "v2 =\n" << describe(*v2,verbLevel);
00270 
00271         *oss <<endl<< "v3 = inv(Op)*v2 ...\n" ;
00272         Teuchos::RCP<MultiVectorBase<DomainScalar> > v3 = createMembers(domain,num_rhs);
00273         assign(&*v3,DST::zero());
00274         SolveStatus<Scalar> solveStatus;
00275         {
00276           VOTS lowsTempState(Teuchos::rcp(&op,false),oss,verbLevel);
00277           timer.start(true);
00278           solveStatus = solve(op,NONCONJ_ELE,*v2,&*v3,static_cast<const SolveCriteria<Scalar>*>(0));
00279           timer.stop();
00280           OSTab(oss).o() <<"\n=> Solve time = "<<timer.totalElapsedTime()<<" sec\n";
00281         }
00282         if(dump_all()) *oss <<endl<< "v3 =\n" << describe(*v3,verbLevel);
00283         *oss
00284           <<endl<< "solve status:\n";
00285         OSTab(oss).o() << solveStatus;
00286 
00287         *oss <<endl<< "v4 = v3 - v1 ...\n" ;
00288         Teuchos::RCP<MultiVectorBase<RangeScalar> > v4 = createMembers(domain,num_rhs);
00289         V_VmV( &*v4, *v3, *v1 );
00290         if(dump_all()) *oss <<endl<< "v4 =\n" << describe(*v4,verbLevel);
00291       
00292         *oss <<endl<< "v5 = Op*v3 - v2 ...\n" ;
00293         Teuchos::RCP<MultiVectorBase<RangeScalar> > v5 = createMembers(range,num_rhs);
00294         assign( &*v5, *v2 );
00295         timer.start(true);
00296         op.apply(NONCONJ_ELE,*v3,&*v5,Scalar(1.0),Scalar(-1.0));
00297         timer.stop();
00298         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00299         if(dump_all()) *oss <<endl<< "v5 =\n" << describe(*v5,verbLevel);
00300 
00301         std::vector<DomainScalarMag> norms_v1(num_rhs), norms_v4(num_rhs), norms_v4_norms_v1(num_rhs);
00302         norms(*v1,&norms_v1[0]);
00303         norms(*v4,&norms_v4[0]);
00304         std::transform(
00305           norms_v4.begin(),norms_v4.end(),norms_v1.begin(),norms_v4_norms_v1.begin()
00306           ,std::divides<DomainScalarMag>()
00307           );
00308 
00309         result = testMaxErrors(
00310           num_rhs, "norm(v4)/norm(v1)", &norms_v4_norms_v1[0]
00311           ,"forward_default_solution_error_error_tol()", forward_default_solution_error_error_tol()
00312           ,"forward_default_solution_error_warning_tol()", forward_default_solution_error_warning_tol()
00313           ,&*oss
00314           );
00315         if(!result) these_results = false;
00316 
00317         std::vector<RangeScalarMag> norms_v2(num_rhs), norms_v5(num_rhs), norms_v5_norms_v2(num_rhs);
00318         norms(*v2,&norms_v2[0]);
00319         norms(*v5,&norms_v5[0]);
00320         std::transform(
00321           norms_v5.begin(),norms_v5.end(),norms_v2.begin(),norms_v5_norms_v2.begin()
00322           ,std::divides<RangeScalarMag>()
00323           );
00324 
00325         result = testMaxErrors(
00326           num_rhs, "norm(v5)/norm(v2)", &norms_v5_norms_v2[0]
00327           ,"forward_default_residual_error_tol()", forward_default_residual_error_tol()
00328           ,"forward_default_residual_warning_tol()", forward_default_residual_warning_tol()
00329           ,&*oss
00330           );
00331         if(!result) these_results = false;
00332         
00333       }
00334     }
00335     else {
00336       *oss <<endl<< "Forward operator not supported, skipping check!\n";
00337     }
00338 
00339     printTestResults(these_results,ossStore.str(),show_all_tests(),&success,OSTab(out).get());
00340 
00341   }
00342   else {
00343     if(out.get()) *out <<endl<< "this->check_forward_default()==false: Skipping the check of the default forward solve!\n";
00344   }
00345   
00346   if( check_forward_residual() ) {
00347 
00348     if(out.get()) *out <<endl<< "this->check_forward_residual()==true: Checking the forward solve with a tolerance on the residual ... ";
00349 
00350     std::ostringstream ossStore;
00351     Teuchos::RCP<FancyOStream> oss = Teuchos::rcp(new FancyOStream(Teuchos::rcp(&ossStore,false)));
00352     if(out.get()) ossStore.copyfmt(*out);
00353     bool these_results = true;
00354 
00355     *oss <<endl<< "op.solveSupportsConj(NONCONJ_ELE) == true ? ";
00356     result = op.solveSupportsConj(NONCONJ_ELE);
00357     if(!result) these_results = false;
00358     *oss << passfail(result) << endl;
00359 
00360     if(result) {
00361     
00362       *oss
00363         <<endl<< "Checking that the forward solve matches the forward operator to a residual tolerance:\n"
00364         <<endl<< "  v3 = inv(Op)*Op*v1"
00365         <<endl<< "               \\___/"
00366         <<endl<< "                 v2"
00367         <<endl<< ""
00368         <<endl<< "  v4 = Op*v3-v2"
00369         <<endl<< ""
00370         <<endl<< "  norm(v4)/norm(v2) <= forward_residual_solve_tol() + forward_residual_slack_error_tol()"
00371         <<endl;
00372 
00373       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00374 
00375         OSTab tab(oss);
00376 
00377         *oss <<endl<< "Random vector tests = " << rand_vec_i << endl;
00378 
00379         tab.incrTab();
00380       
00381         *oss <<endl<< "v1 = randomize(-1,+1); ...\n" ;
00382         Teuchos::RCP<MultiVectorBase<DomainScalar> > v1 = createMembers(domain,num_rhs);
00383         Thyra::randomize( DomainScalar(-1.0), DomainScalar(+1.0), &*v1 );
00384         if(dump_all()) *oss <<endl<< "v1 =\n" << describe(*v1,verbLevel);
00385       
00386         *oss <<endl<< "v2 = Op*v1 ...\n" ;
00387         Teuchos::RCP<MultiVectorBase<RangeScalar> > v2 = createMembers(range,num_rhs);
00388         timer.start(true);
00389         op.apply(NONCONJ_ELE,*v1,&*v2);
00390         timer.stop();
00391         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00392         if(dump_all()) *oss <<endl<< "v2 =\n" << describe(*v2,verbLevel);
00393 
00394         *oss <<endl<< "v3 = inv(Op)*v2 ...\n" ;
00395         Teuchos::RCP<MultiVectorBase<DomainScalar> > v3 = createMembers(domain,num_rhs);
00396         SolveCriteria<Scalar> solveCriteria(
00397           SolveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL,SOLVE_MEASURE_NORM_RHS)
00398           ,forward_residual_solve_tol()
00399           );
00400         assign(&*v3,DST::zero());
00401         SolveStatus<Scalar> solveStatus;
00402         {
00403           VOTS lowsTempState(Teuchos::rcp(&op,false),oss,verbLevel);
00404           timer.start(true);
00405           solveStatus = solve<RangeScalar,DomainScalar>(op,NONCONJ_ELE,*v2,&*v3,&solveCriteria);
00406           timer.stop();
00407           OSTab(oss).o() <<"\n=> Solve time = "<<timer.totalElapsedTime()<<" sec\n";
00408         }
00409         if(dump_all()) *oss <<endl<< "v3 =\n" << describe(*v3,verbLevel);
00410         *oss
00411           <<endl<< "solve status:\n";
00412         OSTab(oss).o() << solveStatus;
00413         result = solveStatus.solveStatus==SOLVE_STATUS_CONVERGED;
00414         if(!result) these_results = false;
00415         *oss
00416           <<endl<< "check: solveStatus = " << toString(solveStatus.solveStatus) << " == SOLVE_STATUS_CONVERGED : "
00417           << passfail(result)<<endl;
00418       
00419         *oss <<endl<< "v4 = Op*v3 - v2 ...\n" ;
00420         Teuchos::RCP<MultiVectorBase<RangeScalar> > v4 = createMembers(range,num_rhs);
00421         assign( &*v4, *v2 );
00422         timer.start(true);
00423         op.apply(NONCONJ_ELE,*v3,&*v4,Scalar(1.0),Scalar(-1.0));
00424         timer.stop();
00425         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00426         if(dump_all()) *oss <<endl<< "v4 =\n" << describe(*v4,verbLevel);
00427 
00428         std::vector<DomainScalarMag> norms_v2(num_rhs), norms_v4(num_rhs), norms_v4_norms_v2(num_rhs);
00429         norms(*v2,&norms_v2[0]);
00430         norms(*v4,&norms_v4[0]);
00431         std::transform(
00432           norms_v4.begin(),norms_v4.end(),norms_v2.begin(),norms_v4_norms_v2.begin()
00433           ,std::divides<DomainScalarMag>()
00434           );
00435 
00436         result = testMaxErrors(
00437           num_rhs, "norm(v4)/norm(v2)", &norms_v4_norms_v2[0]
00438           ,"forward_residual_solve_tol()+forward_residual_slack_error_tol()", DomainScalarMag(forward_residual_solve_tol()+forward_residual_slack_error_tol())
00439           ,"forward_residual_solve_tol()_slack_warning_tol()", DomainScalarMag(forward_residual_solve_tol()+forward_residual_slack_warning_tol())
00440           ,&*oss
00441           );
00442         if(!result) these_results = false;
00443 
00444       }
00445     }
00446     else {
00447       *oss <<endl<< "Forward operator not supported, skipping check!\n";
00448     }
00449 
00450     printTestResults(these_results,ossStore.str(),show_all_tests(),&success,OSTab(out).get());
00451 
00452   }
00453   else {
00454     if(out.get()) *out <<endl<< "this->check_forward_residual()==false: Skipping the check of the forward solve with a tolerance on the residual!\n";
00455   }
00456   
00457   if( check_adjoint_default() ) {
00458 
00459     if(out.get()) *out <<endl<< "this->check_adjoint_default()==true: Checking the default adjoint solve ... ";
00460 
00461     std::ostringstream ossStore;
00462     Teuchos::RCP<FancyOStream> oss = Teuchos::rcp(new FancyOStream(Teuchos::rcp(&ossStore,false)));
00463     if(out.get()) ossStore.copyfmt(*out);
00464     bool these_results = true;
00465 
00466     *oss <<endl<< "op.solveTransposeSupportsConj(CONJ_ELE) == true ? ";
00467     result = op.solveTransposeSupportsConj(CONJ_ELE);
00468     if(!result) these_results = false;
00469     *oss << passfail(result) << endl;
00470 
00471     if(result) {
00472     
00473       *oss
00474         <<endl<< "Checking that the adjoint default solve matches the adjoint operator:\n"
00475         <<endl<< "  inv(Op')*Op'*v1 == v1"
00476         <<endl<< "           \\____/"
00477         <<endl<< "             v2"
00478         <<endl<< "  \\_____________/"
00479         <<endl<< "         v3"
00480         <<endl<< ""
00481         <<endl<< "  v4 = v3-v1"
00482         <<endl<< "  v5 = Op'*v3-v2"
00483         <<endl<< ""
00484         <<endl<< "  norm(v4)/norm(v1) <= adjoint_default_solution_error_error_tol()"
00485         <<endl<< "  norm(v5)/norm(v2) <= adjoint_default_residual_error_tol()"
00486         <<endl;
00487 
00488       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00489 
00490         OSTab tab(oss);
00491 
00492         *oss <<endl<< "Random vector tests = " << rand_vec_i << endl;
00493         
00494         tab.incrTab();
00495       
00496         *oss <<endl<< "v1 = randomize(-1,+1); ...\n" ;
00497         Teuchos::RCP<MultiVectorBase<RangeScalar> > v1 = createMembers(range,num_rhs);
00498         Thyra::randomize( RangeScalar(-1.0), RangeScalar(+1.0), &*v1 );
00499         if(dump_all()) *oss <<endl<< "v1 =\n" << describe(*v1,verbLevel);
00500       
00501         *oss <<endl<< "v2 = Op'*v1 ...\n" ;
00502         Teuchos::RCP<MultiVectorBase<DomainScalar> > v2 = createMembers(domain,num_rhs);
00503         timer.start(true);
00504         op.applyTranspose(CONJ_ELE,*v1,&*v2);
00505         timer.stop();
00506         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00507         if(dump_all()) *oss <<endl<< "v2 =\n" << describe(*v2,verbLevel);
00508 
00509         *oss <<endl<< "v3 = inv(Op')*v2 ...\n" ;
00510         Teuchos::RCP<MultiVectorBase<RangeScalar> > v3 = createMembers(range,num_rhs);
00511         assign(&*v3,DST::zero());
00512         SolveStatus<Scalar> solveStatus;
00513         {
00514           VOTS lowsTempState(Teuchos::rcp(&op,false),oss,verbLevel);
00515           timer.start(true);
00516           solveStatus = solveTranspose(op,CONJ_ELE,*v2,&*v3,static_cast<const SolveCriteria<Scalar>*>(0));
00517           timer.stop();
00518           OSTab(oss).o() <<"\n=> Solve time = "<<timer.totalElapsedTime()<<" sec\n";
00519         }
00520         if(dump_all()) *oss <<endl<< "v3 =\n" << describe(*v3,verbLevel);
00521         *oss
00522           <<endl<< "solve status:\n";
00523         OSTab(oss).o() << solveStatus;
00524 
00525         *oss <<endl<< "v4 = v3 - v1 ...\n" ;
00526         Teuchos::RCP<MultiVectorBase<RangeScalar> > v4 = createMembers(range,num_rhs);
00527         V_VmV( &*v4, *v3, *v1 );
00528         if(dump_all()) *oss <<endl<< "v4 =\n" << describe(*v4,verbLevel);
00529       
00530         *oss <<endl<< "v5 = Op'*v3 - v2 ...\n" ;
00531         Teuchos::RCP<MultiVectorBase<DomainScalar> > v5 = createMembers(domain,num_rhs);
00532         assign( &*v5, *v2 );
00533         timer.start(true);
00534         op.applyTranspose(CONJ_ELE,*v3,&*v5,Scalar(1.0),Scalar(-1.0));
00535         timer.stop();
00536         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00537         if(dump_all()) *oss <<endl<< "v5 =\n" << describe(*v5,verbLevel);
00538 
00539         std::vector<RangeScalarMag> norms_v1(num_rhs), norms_v4(num_rhs), norms_v4_norms_v1(num_rhs);
00540         norms(*v1,&norms_v1[0]);
00541         norms(*v4,&norms_v4[0]);
00542         std::transform(
00543           norms_v4.begin(),norms_v4.end(),norms_v1.begin(),norms_v4_norms_v1.begin()
00544           ,std::divides<RangeScalarMag>()
00545           );
00546 
00547         result = testMaxErrors(
00548           num_rhs, "norm(v4)/norm(v1)", &norms_v4_norms_v1[0]
00549           ,"adjoint_default_solution_error_error_tol()", adjoint_default_solution_error_error_tol()
00550           ,"adjoint_default_solution_error_warning_tol()", adjoint_default_solution_error_warning_tol()
00551           ,&*oss
00552           );
00553         if(!result) these_results = false;
00554 
00555         std::vector<DomainScalarMag> norms_v2(num_rhs), norms_v5(num_rhs), norms_v5_norms_v2(num_rhs);
00556         norms(*v2,&norms_v2[0]);
00557         norms(*v5,&norms_v5[0]);
00558         std::transform(
00559           norms_v5.begin(),norms_v5.end(),norms_v2.begin(),norms_v5_norms_v2.begin()
00560           ,std::divides<DomainScalarMag>()
00561           );
00562 
00563         result = testMaxErrors(
00564           num_rhs, "norm(v5)/norm(v2)", &norms_v5_norms_v2[0]
00565           ,"adjoint_default_residual_error_tol()", adjoint_default_residual_error_tol()
00566           ,"adjoint_default_residual_warning_tol()", adjoint_default_residual_warning_tol()
00567           ,&*oss
00568           );
00569         if(!result) these_results = false;
00570 
00571       }
00572     }
00573     else {
00574       *oss <<endl<< "Adjoint operator not supported, skipping check!\n";
00575     }
00576 
00577     printTestResults(these_results,ossStore.str(),show_all_tests(),&success,OSTab(out).get());
00578 
00579   }
00580   else {
00581     if(out.get()) *out <<endl<< "this->check_adjoint_default()==false: Skipping the check of the adjoint solve with a default tolerance!\n";
00582   }
00583   
00584   if( check_adjoint_residual() ) {
00585 
00586     if(out.get()) *out <<endl<< "this->check_adjoint_residual()==true: Checking the adjoint solve with a tolerance on the residual ... ";
00587     
00588     std::ostringstream ossStore;
00589     Teuchos::RCP<FancyOStream> oss = Teuchos::rcp(new FancyOStream(Teuchos::rcp(&ossStore,false)));
00590     if(out.get()) ossStore.copyfmt(*out);
00591     bool these_results = true;
00592 
00593     *oss <<endl<< "op.solveTransposeSupportsConj(CONJ_ELE) == true ? ";
00594     result = op.solveTransposeSupportsConj(CONJ_ELE);
00595     if(!result) these_results = false;
00596     *oss << passfail(result) << endl;
00597 
00598     if(result) {
00599     
00600       *oss
00601         <<endl<< "Checking that the adjoint solve matches the adjoint operator to a residual tolerance:\n"
00602         <<endl<< "  v3 = inv(Op')*Op'*v1"
00603         <<endl<< "                \\____/"
00604         <<endl<< "                  v2"
00605         <<endl<< ""
00606         <<endl<< "  v4 = Op'*v3-v2"
00607         <<endl<< ""
00608         <<endl<< "  norm(v4)/norm(v2) <= adjoint_residual_solve_tol() + adjoint_residual_slack_error_tol()"
00609         <<endl;
00610 
00611       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00612 
00613         OSTab tab(oss);
00614 
00615         *oss <<endl<< "Random vector tests = " << rand_vec_i << endl;
00616 
00617         tab.incrTab();
00618       
00619         *oss <<endl<< "v1 = randomize(-1,+1); ...\n" ;
00620         Teuchos::RCP<MultiVectorBase<RangeScalar> > v1 = createMembers(range,num_rhs);
00621         Thyra::randomize( RangeScalar(-1.0), RangeScalar(+1.0), &*v1 );
00622         if(dump_all()) *oss <<endl<< "v1 =\n" << describe(*v1,verbLevel);
00623       
00624         *oss <<endl<< "v2 = Op'*v1 ...\n" ;
00625         Teuchos::RCP<MultiVectorBase<DomainScalar> > v2 = createMembers(domain,num_rhs);
00626         timer.start(true);
00627         op.applyTranspose(CONJ_ELE,*v1,&*v2);
00628         timer.stop();
00629         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00630         if(dump_all()) *oss <<endl<< "v2 =\n" << describe(*v2,verbLevel);
00631 
00632         *oss <<endl<< "v3 = inv(Op')*v2 ...\n" ;
00633         Teuchos::RCP<MultiVectorBase<RangeScalar> > v3 = createMembers(range,num_rhs);
00634         SolveCriteria<Scalar> solveCriteria(
00635           SolveMeasureType(SOLVE_MEASURE_NORM_RESIDUAL,SOLVE_MEASURE_NORM_RHS)
00636           ,adjoint_residual_solve_tol()
00637           );
00638         assign(&*v3,RST::zero());
00639         SolveStatus<Scalar> solveStatus;
00640         {
00641           VOTS lowsTempState(Teuchos::rcp(&op,false),oss,verbLevel);
00642           timer.start(true);
00643           solveStatus = solveTranspose(op,CONJ_ELE,*v2,&*v3,&solveCriteria);
00644           timer.stop();
00645           OSTab(oss).o() <<"\n=> Solve time = "<<timer.totalElapsedTime()<<" sec\n";
00646         }
00647         if(dump_all()) *oss <<endl<< "v3 =\n" << describe(*v3,verbLevel);
00648         *oss
00649           <<endl<< "solve status:\n";
00650         OSTab(oss).o() << solveStatus;
00651         result = solveStatus.solveStatus==SOLVE_STATUS_CONVERGED;
00652         if(!result) these_results = false;
00653         *oss
00654           <<endl<< "check: solveStatus = " << toString(solveStatus.solveStatus) << " == SOLVE_STATUS_CONVERGED : "
00655           << passfail(result)<<endl;
00656         if(solveStatus.achievedTol==SolveStatus<RangeScalar>::unknownTolerance())
00657           *oss <<endl<<"achievedTol==unknownTolerance(): Setting achievedTol = adjoint_residual_solve_tol() = "<<adjoint_residual_solve_tol()<<endl;
00658       
00659         *oss <<endl<< "v4 = Op'*v3 - v2 ...\n" ;
00660         Teuchos::RCP<MultiVectorBase<DomainScalar> > v4 = createMembers(domain,num_rhs);
00661         assign( &*v4, *v2 );
00662         timer.start(true);
00663         op.applyTranspose(CONJ_ELE,*v3,&*v4,Scalar(1.0),Scalar(-1.0));
00664         timer.stop();
00665         OSTab(oss).o() <<"\n=> Apply time = "<<timer.totalElapsedTime()<<" sec\n";
00666         if(dump_all()) *oss <<endl<< "v4 =\n" << describe(*v4,verbLevel);
00667 
00668         std::vector<RangeScalarMag> norms_v2(num_rhs), norms_v4(num_rhs), norms_v4_norms_v2(num_rhs);
00669         norms(*v2,&norms_v2[0]);
00670         norms(*v4,&norms_v4[0]);
00671         std::transform(
00672           norms_v4.begin(),norms_v4.end(),norms_v2.begin(),norms_v4_norms_v2.begin()
00673           ,std::divides<RangeScalarMag>()
00674           );
00675 
00676         result = testMaxErrors(
00677           num_rhs, "norm(v4)/norm(v2)", &norms_v4_norms_v2[0],
00678           "adjoint_residual_solve_tol()+adjoint_residual_slack_error_tol()",
00679           RangeScalarMag(adjoint_residual_solve_tol()+adjoint_residual_slack_error_tol()),
00680           "adjoint_residual_solve_tol()_slack_warning_tol()",
00681           RangeScalarMag(adjoint_residual_solve_tol()+adjoint_residual_slack_warning_tol()),
00682           &*oss
00683           );
00684         if(!result) these_results = false;
00685 
00686       }
00687     }
00688     else {
00689       *oss <<endl<< "Adjoint operator not supported, skipping check!\n";
00690     }
00691 
00692     printTestResults(these_results,ossStore.str(),show_all_tests(),&success,OSTab(out).get());
00693 
00694   }
00695   else {
00696     if(out.get())
00697       *out <<endl<< "this->check_adjoint_residual()==false: Skipping the check of the adjoint solve with a tolerance on the residual!\n";
00698   }
00699   
00700   if(out.get()) {
00701     if(success)
00702       *out <<endl<<"Congratulations, this LinearOpWithSolveBase object seems to check out!\n";
00703     else
00704       *out <<endl<<"Oh no, at least one of the tests performed with this LinearOpWithSolveBase object failed (see above failures)!\n";
00705     *out <<endl<< "*** Leaving LinearOpWithSolveTester<"<<ST::name()<<">::check(...)\n";
00706   }
00707   
00708   return success;
00709   
00710 }
00711 
00712 
00713 // private static members
00714 
00715 
00716 // Define local macros used in the next few lines and then undefined
00717 
00718 #define LOWST_DEFINE_RAW_STATIC_MEMBER( DATA_TYPE, MEMBER_NAME, DEFAULT_VALUE ) \
00719 template<class RangeScalar, class DomainScalar> \
00720 const DATA_TYPE \
00721 LinearOpWithSolveTester<RangeScalar,DomainScalar>::MEMBER_NAME = DEFAULT_VALUE
00722 
00723 #define LOWST_DEFINE_MTD_STATIC_MEMBER( DATA_TYPE, MEMBER_NAME, DEFAULT_VALUE ) \
00724 template<class RangeScalar, class DomainScalar> \
00725 const typename LinearOpWithSolveTester<RangeScalar,DomainScalar>::DATA_TYPE \
00726 LinearOpWithSolveTester<RangeScalar,DomainScalar>::MEMBER_NAME = DEFAULT_VALUE
00727 
00728 LOWST_DEFINE_RAW_STATIC_MEMBER(bool, check_forward_default_default_, true);
00729 LOWST_DEFINE_RAW_STATIC_MEMBER(bool, check_forward_residual_default_, true);
00730 LOWST_DEFINE_RAW_STATIC_MEMBER(bool, check_adjoint_default_default_, true);
00731 LOWST_DEFINE_RAW_STATIC_MEMBER(bool, check_adjoint_residual_default_, true);
00732 
00733 LOWST_DEFINE_MTD_STATIC_MEMBER(ScalarMag, warning_tol_default_, 1e-6);
00734 LOWST_DEFINE_MTD_STATIC_MEMBER(ScalarMag, error_tol_default_, 1e-5);
00735 LOWST_DEFINE_MTD_STATIC_MEMBER(ScalarMag, solve_tol_default_, 1e-5);
00736 LOWST_DEFINE_MTD_STATIC_MEMBER(ScalarMag, slack_warning_tol_default_, 1e-6);
00737 LOWST_DEFINE_MTD_STATIC_MEMBER(ScalarMag, slack_error_tol_default_, 1e-5);
00738 
00739 LOWST_DEFINE_RAW_STATIC_MEMBER(int, num_random_vectors_default_, 1);
00740 LOWST_DEFINE_RAW_STATIC_MEMBER(bool, show_all_tests_default_, false);
00741 LOWST_DEFINE_RAW_STATIC_MEMBER(bool, dump_all_default_, false);
00742 LOWST_DEFINE_RAW_STATIC_MEMBER(int, num_rhs_default_, 1);
00743 
00744 LOWST_DEFINE_RAW_STATIC_MEMBER(std::string, AllSolveTol_name_, "All Solve Tol");
00745 LOWST_DEFINE_RAW_STATIC_MEMBER(std::string, AllSlackWarningTol_name_, "All Slack Warning Tol");
00746 LOWST_DEFINE_RAW_STATIC_MEMBER(std::string, AllSlackErrorTol_name_, "All Slack Error Tol");
00747 LOWST_DEFINE_RAW_STATIC_MEMBER(std::string, ShowAllTests_name_, "Show All Tests");
00748 LOWST_DEFINE_RAW_STATIC_MEMBER(std::string, DumpAll_name_, "Dump All");
00749 
00750 #undef LOWST_DEFINE_MTD_STATIC_MEMBER
00751 
00752 #undef LOWST_DEFINE_RAW_STATIC_MEMBER
00753 
00754 
00755 } // namespace Thyra
00756 
00757 
00758 #endif // THYRA_LINEAR_OP_WITH_SOLVE_TESTER_HPP

Generated on Wed May 12 21:27:14 2010 for Thyra Operator Solve Support by  doxygen 1.4.7