Thyra Version of the Day
Thyra_LinearOpTester_def.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 // 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 (bartlettra@ornl.gov) 
00038 // 
00039 // ***********************************************************************
00040 // @HEADER
00041 
00042 #ifndef THYRA_LINEAR_OP_TESTER_DEF_HPP
00043 #define THYRA_LINEAR_OP_TESTER_DEF_HPP
00044 
00045 #include "Thyra_LinearOpTester_decl.hpp"
00046 #include "Thyra_LinearOpBase.hpp"
00047 #include "Thyra_DefaultScaledAdjointLinearOp.hpp"
00048 #include "Thyra_describeLinearOp.hpp"
00049 #include "Thyra_VectorStdOps.hpp"
00050 #include "Thyra_TestingTools.hpp"
00051 #include "Thyra_UniversalMultiVectorRandomizer.hpp"
00052 #include "Teuchos_TestingHelpers.hpp"
00053 
00054 
00055 namespace Thyra {
00056 
00057 
00058 template<class Scalar>
00059 class SymmetricLinearOpTester {
00060 public:
00061   typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType ScalarMag;
00062   static void checkSymmetry(
00063     const LinearOpBase<Scalar> &op,
00064     const Ptr<MultiVectorRandomizerBase<Scalar> > &dRand,
00065     Teuchos::FancyOStream &testOut,
00066     const int num_rhs,
00067     const int num_random_vectors,
00068     const Teuchos::EVerbosityLevel verbLevel,
00069     const bool dump_all,
00070     const ScalarMag &symmetry_error_tol,
00071     const ScalarMag &symmetry_warning_tol,
00072     const Ptr<bool> &these_results
00073     )
00074     {
00075 
00076       using std::endl;
00077 
00078       bool result;
00079       using Teuchos::OSTab;
00080       typedef Teuchos::ScalarTraits<Scalar> ST;
00081       const Scalar half = Scalar(0.4)*ST::one();
00082       RCP<const VectorSpaceBase<Scalar> > domain = op.domain();
00083       
00084       testOut << endl << "op.domain()->isCompatible(*op.range()) == true : ";
00085       result = op.domain()->isCompatible(*op.range());
00086       if(!result) *these_results = false;
00087       testOut << passfail(result) << endl;
00088       
00089       if(result) {
00090         
00091         testOut
00092           << endl << "Checking that the operator is symmetric as:\n"
00093           << endl << "  <0.5*op*v2,v1> == <v2,0.5*op*v1>"
00094           << endl << "   \\_______/            \\_______/"
00095           << endl << "      v4                    v3"
00096           << endl << ""
00097           << endl << "         <v4,v1> == <v2,v3>"
00098           << endl << std::flush;
00099         
00100         for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors; ++rand_vec_i ) {
00101           
00102           testOut << endl << "Random vector tests = " << rand_vec_i << endl;
00103 
00104           OSTab tab(testOut);
00105 
00106           if(dump_all) testOut << endl << "v1 = randomize(-1,+1); ...\n" ;
00107           RCP<MultiVectorBase<Scalar> > v1 = createMembers(domain,num_rhs);
00108           dRand->randomize(v1.ptr());
00109           if(dump_all) testOut << endl << "v1 =\n" << describe(*v1,verbLevel);
00110           
00111           if(dump_all) testOut << endl << "v2 = randomize(-1,+1); ...\n" ;
00112           RCP<MultiVectorBase<Scalar> > v2 = createMembers(domain,num_rhs);
00113           dRand->randomize(v2.ptr());
00114           if(dump_all) testOut << endl << "v2 =\n" << describe(*v2,verbLevel);
00115           
00116           if(dump_all) testOut << endl << "v3 = 0.5*op*v1 ...\n" ;
00117           RCP<MultiVectorBase<Scalar> > v3 = createMembers(domain,num_rhs);
00118           apply( op, NOTRANS, *v1, v3.ptr(), half );
00119           if(dump_all) testOut << endl << "v3 =\n" << describe(*v3,verbLevel);
00120           
00121           if(dump_all) testOut << endl << "v4 = 0.5*op*v2 ...\n" ;
00122           RCP<MultiVectorBase<Scalar> > v4 = createMembers(domain,num_rhs);
00123           apply( op, NOTRANS, *v2, v4.ptr(), half );
00124           if(dump_all) testOut << endl << "v4 =\n" << describe(*v4,verbLevel);
00125 
00126           Array<Scalar> prod1(num_rhs), prod2(num_rhs);
00127           domain->scalarProds(*v4, *v1, prod1());
00128           domain->scalarProds(*v2, *v3, prod2());
00129           
00130           result = testRelErrors<Scalar, Scalar, ScalarMag>(
00131             "<v4,v1>", prod1(),
00132             "<v2,v3>", prod2(),
00133             "symmetry_error_tol()", symmetry_error_tol,
00134             "symmetry_warning_tol()", symmetry_warning_tol,
00135             inOutArg(testOut)
00136             );
00137           if(!result) *these_results = false;
00138         
00139         }
00140       }
00141       else {
00142         testOut << endl << "Range and domain spaces are different, skipping check!\n";
00143       }
00144     }
00145 };
00146 
00147 
00148 //
00149 // LinearOpTester
00150 //
00151 
00152 
00153 template<class Scalar>
00154 LinearOpTester<Scalar>::LinearOpTester()
00155   :check_linear_properties_(true),
00156    linear_properties_warning_tol_(-1.0),
00157    linear_properties_error_tol_(-1.0),
00158    check_adjoint_(true),
00159    adjoint_warning_tol_(-1.0),
00160    adjoint_error_tol_(-1.0),
00161    check_for_symmetry_(false),
00162    symmetry_warning_tol_(-1.0),
00163    symmetry_error_tol_(-1.0),
00164    num_random_vectors_(1),
00165    show_all_tests_(false),
00166    dump_all_(false),
00167    num_rhs_(1)
00168 {
00169   setDefaultTols();
00170 }
00171 
00172 
00173 template<class Scalar>
00174 void LinearOpTester<Scalar>::enable_all_tests( const bool enable_all_tests_in )
00175 {
00176   check_linear_properties_ = enable_all_tests_in;
00177   check_adjoint_ = enable_all_tests_in;
00178   check_for_symmetry_ = enable_all_tests_in;
00179 }
00180 
00181 
00182 template<class Scalar>
00183 void LinearOpTester<Scalar>::set_all_warning_tol( const ScalarMag warning_tol_in )
00184 {
00185   linear_properties_warning_tol_ = warning_tol_in;
00186   adjoint_warning_tol_ = warning_tol_in;
00187   symmetry_warning_tol_ = warning_tol_in;
00188 }
00189 
00190 
00191 template<class Scalar>
00192 void LinearOpTester<Scalar>::set_all_error_tol( const ScalarMag error_tol_in )
00193 {
00194   linear_properties_error_tol_ = error_tol_in;
00195   adjoint_error_tol_ = error_tol_in;
00196   symmetry_error_tol_ = error_tol_in;
00197 }
00198 
00199 
00200 template<class Scalar>
00201 bool LinearOpTester<Scalar>::check(
00202   const LinearOpBase<Scalar> &op,
00203   const Ptr<MultiVectorRandomizerBase<Scalar> > &rangeRandomizer,
00204   const Ptr<MultiVectorRandomizerBase<Scalar> > &domainRandomizer,
00205   const Ptr<Teuchos::FancyOStream> &out_inout
00206   ) const
00207 {
00208 
00209   using std::endl;
00210   using Teuchos::as;
00211   using Teuchos::rcp;
00212   using Teuchos::rcpFromPtr;
00213   using Teuchos::rcpFromRef;
00214   using Teuchos::outArg;
00215   using Teuchos::inoutArg;
00216   using Teuchos::fancyOStream;
00217   using Teuchos::FancyOStream;
00218   using Teuchos::OSTab;
00219   typedef Teuchos::ScalarTraits<Scalar> ST;
00220 
00221   bool success = true, result;
00222   const int loc_num_rhs = this->num_rhs();
00223   const Scalar r_one  = ST::one();
00224   const Scalar d_one  = ST::one();
00225   const Scalar r_half = as<Scalar>(0.5)*r_one;
00226   const Scalar d_half = as<Scalar>(0.5)*d_one;
00227 
00228   RCP<FancyOStream> out;
00229   if (!is_null(out_inout))
00230     out = Teuchos::rcpFromPtr(out_inout);
00231   else
00232     out = Teuchos::fancyOStream(rcp(new Teuchos::oblackholestream));
00233 
00234   const Teuchos::EVerbosityLevel verbLevel =
00235     (dump_all()?Teuchos::VERB_EXTREME:Teuchos::VERB_MEDIUM);
00236 
00237   OSTab tab2(out,1,"THYRA");
00238 
00239   // ToDo 04/28/2005:
00240   // * Test the MultiVectorBase apply() function and output to the VectorBase apply() function!
00241 
00242   *out << endl << "*** Entering LinearOpTester<"<<ST::name()<<","<<ST::name()<<">::check(op,...) ...\n";
00243   if(show_all_tests()) {
00244     *out << endl << "describe op:\n" << Teuchos::describe(op,verbLevel);
00245 /*
00246   if(op.applyTransposeSupports(CONJ_ELE) && verbLevel==Teuchos::VERB_EXTREME) {
00247   *out << endl << "describe adjoint op:\n";
00248   describeLinearOp(*adjoint(Teuchos::rcp(&op,false)),*out,verbLevel);
00249   }
00250 */
00251   }
00252   else {
00253     *out << endl << "describe op: " << Teuchos::describe(op, Teuchos::VERB_LOW);
00254   }
00255 
00256   RCP< MultiVectorRandomizerBase<Scalar> >  rRand;
00257   if (!is_null(rangeRandomizer))
00258     rRand = rcpFromPtr(rangeRandomizer);
00259   else
00260     rRand = universalMultiVectorRandomizer<Scalar>();
00261   RCP< MultiVectorRandomizerBase<Scalar> > dRand;
00262   if (!is_null(domainRandomizer))
00263     dRand = rcpFromPtr(domainRandomizer);
00264   else
00265     dRand = universalMultiVectorRandomizer<Scalar>();
00266   
00267   *out << endl << "Checking the domain and range spaces ... ";
00268 
00269   RCP<const VectorSpaceBase<Scalar> >  range  = op.range();
00270   RCP<const VectorSpaceBase<Scalar> > domain = op.domain();
00271   
00272   {
00273 
00274     TestResultsPrinter testResultsPrinter(out, show_all_tests());
00275     const RCP<FancyOStream> testOut = testResultsPrinter.getTestOStream();
00276 
00277     bool these_results = true;
00278 
00279     *testOut << endl << "op.domain().get() != NULL ? ";
00280     result = domain.get() != NULL;
00281     if(!result) these_results = false;
00282     *testOut << passfail(result) << endl;
00283     
00284     *testOut << endl << "op.range().get() != NULL ? ";
00285     result = range.get() != NULL;
00286     if(!result) these_results = false;
00287     *testOut << passfail(result) << endl;
00288 
00289     testResultsPrinter.printTestResults(these_results, inoutArg(success));
00290 
00291   }
00292 
00293   if( check_linear_properties() ) {
00294 
00295     *out << endl << "this->check_linear_properties()==true:"
00296          << "Checking the linear properties of the forward linear operator ... ";
00297 
00298     TestResultsPrinter testResultsPrinter(out, show_all_tests());
00299     const RCP<FancyOStream> testOut = testResultsPrinter.getTestOStream();
00300 
00301     bool these_results = true;
00302 
00303     TEUCHOS_TEST_EQUALITY_CONST( op.opSupported(NOTRANS), true, *testOut, these_results );
00304 
00305     if(result) {
00306     
00307       *testOut
00308         << endl << "Checking that the forward operator is truly linear:\n"
00309         << endl << "  0.5*op*(v1 + v2) == 0.5*op*v1 + 0.5*op*v2"
00310         << endl << "          \\_____/         \\___/"
00311         << endl << "             v3            v5"
00312         << endl << "  \\_____________/     \\___________________/"
00313         << endl << "         v4                    v5"
00314         << endl << ""
00315         << endl << "           sum(v4) == sum(v5)"
00316         << endl << std::flush;
00317       
00318       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00319         
00320         *testOut << endl << "Random vector tests = " << rand_vec_i << endl;
00321 
00322         OSTab tab3(testOut);
00323         
00324         *testOut << endl << "v1 = randomize(-1,+1); ...\n" ;
00325         RCP<MultiVectorBase<Scalar> > v1 = createMembers(domain,loc_num_rhs);
00326         dRand->randomize(v1.ptr());
00327         if(dump_all()) *testOut << endl << "v1 =\n" << describe(*v1,verbLevel);
00328         
00329         *testOut << endl << "v2 = randomize(-1,+1); ...\n" ;
00330         RCP<MultiVectorBase<Scalar> > v2 = createMembers(domain,loc_num_rhs);
00331         dRand->randomize(v2.ptr());
00332         if(dump_all()) *testOut << endl << "v2 =\n" << describe(*v2,verbLevel);
00333         
00334         *testOut << endl << "v3 = v1 + v2 ...\n" ;
00335         RCP<MultiVectorBase<Scalar> > v3 = createMembers(domain,loc_num_rhs);
00336         V_VpV(v3.ptr(),*v1,*v2);
00337         if(dump_all()) *testOut << endl << "v3 =\n" << describe(*v3,verbLevel);
00338         
00339         *testOut << endl << "v4 = 0.5*op*v3 ...\n" ;
00340         RCP<MultiVectorBase<Scalar> > v4 = createMembers(range,loc_num_rhs);
00341         apply( op, NOTRANS, *v3, v4.ptr(), r_half );
00342         if(dump_all()) *testOut << endl << "v4 =\n" << describe(*v4,verbLevel);
00343         
00344         *testOut << endl << "v5 = op*v1 ...\n" ;
00345         RCP<MultiVectorBase<Scalar> > v5 = createMembers(range,loc_num_rhs);
00346         apply( op, NOTRANS, *v1, v5.ptr() );
00347         if(dump_all()) *testOut << endl << "v5 =\n" << describe(*v5,verbLevel);
00348         
00349         *testOut << endl << "v5 = 0.5*op*v2 + 0.5*v5 ...\n" ;
00350         apply( op, NOTRANS, *v2, v5.ptr(), r_half, r_half );
00351         if(dump_all()) *testOut << endl << "v5 =\n" << describe(*v5,verbLevel);
00352 
00353         Array<Scalar> sum_v4(loc_num_rhs), sum_v5(loc_num_rhs);
00354         sums(*v4, sum_v4());
00355         sums(*v5, sum_v5());
00356         
00357         result = testRelErrors<Scalar, Scalar, ScalarMag>(
00358           "sum(v4)", sum_v4(),
00359           "sum(v5)", sum_v5(),
00360           "linear_properties_error_tol()", linear_properties_error_tol(),
00361           "linear_properties_warning_tol()", linear_properties_warning_tol(),
00362           testOut.ptr()
00363           );
00364         if(!result) these_results = false;
00365         
00366       }
00367     }
00368     else {
00369       *testOut << endl << "Forward operator not supported, skipping check!\n";
00370     }
00371 
00372     testResultsPrinter.printTestResults(these_results, inoutArg(success));
00373 
00374   }
00375   else {
00376     *out << endl << "this->check_linear_properties()==false: Skipping the check of the linear properties of the forward operator!\n";
00377   }
00378 
00379   if( check_linear_properties() && check_adjoint() ) {
00380 
00381     *out << endl << "(this->check_linear_properties()&&this->check_adjoint())==true:"
00382          << " Checking the linear properties of the adjoint operator ... ";
00383 
00384 
00385     TestResultsPrinter testResultsPrinter(out, show_all_tests());
00386     const RCP<FancyOStream> testOut = testResultsPrinter.getTestOStream();
00387 
00388     bool these_results = true;
00389 
00390     TEUCHOS_TEST_EQUALITY_CONST( op.opSupported(CONJTRANS), true, *testOut, these_results );
00391 
00392     if(result) {
00393     
00394       *testOut
00395         << endl << "Checking that the adjoint operator is truly linear:\n"
00396         << endl << "  0.5*op'*(v1 + v2) == 0.5*op'*v1 + 0.5*op'*v2"
00397         << endl << "           \\_____/         \\____/"
00398         << endl << "              v3             v5"
00399         << endl << "  \\_______________/    \\_____________________/"
00400         << endl << "         v4                      v5"
00401         << endl << ""
00402         << endl << "           sum(v4) == sum(v5)"
00403         << endl << std::flush;
00404       
00405       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00406         
00407         *testOut << endl << "Random vector tests = " << rand_vec_i << endl;
00408 
00409         OSTab tab(testOut);
00410         
00411         *testOut << endl << "v1 = randomize(-1,+1); ...\n" ;
00412         RCP<MultiVectorBase<Scalar> > v1 = createMembers(range,loc_num_rhs);
00413         rRand->randomize(v1.ptr());
00414         if(dump_all()) *testOut << endl << "v1 =\n" << describe(*v1,verbLevel);
00415         
00416         *testOut << endl << "v2 = randomize(-1,+1); ...\n" ;
00417         RCP<MultiVectorBase<Scalar> > v2 = createMembers(range,loc_num_rhs);
00418         rRand->randomize(v2.ptr());
00419         if(dump_all()) *testOut << endl << "v2 =\n" << describe(*v2,verbLevel);
00420         
00421         *testOut << endl << "v3 = v1 + v2 ...\n" ;
00422         RCP<MultiVectorBase<Scalar> > v3 = createMembers(range,loc_num_rhs);
00423         V_VpV(v3.ptr(),*v1,*v2);
00424         if(dump_all()) *testOut << endl << "v3 =\n" << describe(*v3,verbLevel);
00425         
00426         *testOut << endl << "v4 = 0.5*op'*v3 ...\n" ;
00427         RCP<MultiVectorBase<Scalar> > v4 = createMembers(domain,loc_num_rhs);
00428         apply( op, CONJTRANS, *v3, v4.ptr(), d_half );
00429         if(dump_all()) *testOut << endl << "v4 =\n" << describe(*v4,verbLevel);
00430         
00431         *testOut << endl << "v5 = op'*v1 ...\n" ;
00432         RCP<MultiVectorBase<Scalar> > v5 = createMembers(domain,loc_num_rhs);
00433         apply( op, CONJTRANS, *v1, v5.ptr() );
00434         if(dump_all()) *testOut << endl << "v5 =\n" << describe(*v5,verbLevel);
00435         
00436         *testOut << endl << "v5 = 0.5*op'*v2 + 0.5*v5 ...\n" ;
00437         apply( op, CONJTRANS, *v2, v5.ptr(), d_half, d_half );
00438         if(dump_all()) *testOut << endl << "v5 =\n" << describe(*v5,verbLevel);
00439 
00440         Array<Scalar> sum_v4(loc_num_rhs), sum_v5(loc_num_rhs);
00441         sums(*v4, sum_v4());
00442         sums(*v5, sum_v5());
00443         
00444         result = testRelErrors<Scalar, Scalar, ScalarMag>(
00445           "sum(v4)", sum_v4(),
00446           "sum(v5)", sum_v5(),
00447           "linear_properties_error_tol()", linear_properties_error_tol(),
00448           "linear_properties_warning_tol()", linear_properties_warning_tol(),
00449           testOut.ptr()
00450           );
00451         if(!result) these_results = false;
00452         
00453       }
00454     }
00455     else {
00456       *testOut << endl << "Adjoint operator not supported, skipping check!\n";
00457     }
00458 
00459     testResultsPrinter.printTestResults(these_results, inoutArg(success));
00460 
00461   }
00462   else {
00463     *out << endl << "(this->check_linear_properties()&&this->check_adjoint())==false: Skipping the check of the linear properties of the adjoint operator!\n";
00464   }
00465   
00466   if( check_adjoint() ) {
00467 
00468     *out << endl << "this->check_adjoint()==true:"
00469          << " Checking the agreement of the adjoint and forward operators ... ";
00470 
00471     TestResultsPrinter testResultsPrinter(out, show_all_tests());
00472     const RCP<FancyOStream> testOut = testResultsPrinter.getTestOStream();
00473 
00474     bool these_results = true;
00475 
00476     TEUCHOS_TEST_EQUALITY_CONST( op.opSupported(CONJTRANS), true, *testOut, these_results );
00477 
00478     if(result) {
00479     
00480       *testOut
00481         << endl << "Checking that the adjoint agrees with the non-adjoint operator as:\n"
00482         << endl << "  <0.5*op'*v2,v1> == <v2,0.5*op*v1>"
00483         << endl << "   \\________/            \\_______/"
00484         << endl << "       v4                   v3"
00485         << endl << ""
00486         << endl << "         <v4,v1>  == <v2,v3>"
00487         << endl << std::flush;
00488     
00489       for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00490       
00491         *testOut << endl << "Random vector tests = " << rand_vec_i << endl;
00492 
00493         OSTab tab(testOut);
00494       
00495         *testOut << endl << "v1 = randomize(-1,+1); ...\n" ;
00496         RCP<MultiVectorBase<Scalar> > v1 = createMembers(domain,loc_num_rhs);
00497         dRand->randomize(v1.ptr());
00498         if(dump_all()) *testOut << endl << "v1 =\n" << describe(*v1,verbLevel);
00499       
00500         *testOut << endl << "v2 = randomize(-1,+1); ...\n" ;
00501         RCP<MultiVectorBase<Scalar> > v2 = createMembers(range,loc_num_rhs);
00502         rRand->randomize(v2.ptr());
00503         if(dump_all()) *testOut << endl << "v2 =\n" << describe(*v2,verbLevel);
00504       
00505         *testOut << endl << "v3 = 0.5*op*v1 ...\n" ;
00506         RCP<MultiVectorBase<Scalar> > v3 = createMembers(range,loc_num_rhs);
00507         apply( op, NOTRANS, *v1, v3.ptr(), r_half );
00508         if(dump_all()) *testOut << endl << "v3 =\n" << describe(*v3,verbLevel);
00509       
00510         *testOut << endl << "v4 = 0.5*op'*v2 ...\n" ;
00511         RCP<MultiVectorBase<Scalar> > v4 = createMembers(domain,loc_num_rhs);
00512         apply( op, CONJTRANS, *v2, v4.ptr(), d_half );
00513         if(dump_all()) *testOut << endl << "v4 =\n" << describe(*v4,verbLevel);
00514 
00515         Array<Scalar> prod_v4_v1(loc_num_rhs);
00516         domain->scalarProds(*v4, *v1, prod_v4_v1());
00517         Array<Scalar> prod_v2_v3(loc_num_rhs);
00518         range->scalarProds(*v2, *v3, prod_v2_v3());
00519         
00520         result = testRelErrors<Scalar, Scalar, ScalarMag>(
00521           "<v4,v1>", prod_v4_v1(),
00522           "<v2,v3>", prod_v2_v3(),
00523           "adjoint_error_tol()", adjoint_error_tol(),
00524           "adjoint_warning_tol()", adjoint_warning_tol(),
00525           testOut.ptr()
00526           );
00527         if(!result) these_results = false;
00528         
00529       }
00530     }
00531     else {
00532       *testOut << endl << "Adjoint operator not supported, skipping check!\n";
00533     }
00534 
00535     testResultsPrinter.printTestResults(these_results, inoutArg(success));
00536 
00537   }
00538   else {
00539     *out << endl << "this->check_adjoint()==false:"
00540          << " Skipping check for the agreement of the adjoint and forward operators!\n";
00541   }
00542 
00543 
00544   if( check_for_symmetry() ) {
00545 
00546     *out << endl << "this->check_for_symmetry()==true: Performing check of symmetry ... ";
00547 
00548     TestResultsPrinter testResultsPrinter(out, show_all_tests());
00549     const RCP<FancyOStream> testOut = testResultsPrinter.getTestOStream();
00550 
00551     bool these_results = true;
00552     
00553     SymmetricLinearOpTester<Scalar>::checkSymmetry(
00554       op, dRand.ptr(), *testOut, loc_num_rhs,num_random_vectors(), verbLevel,dump_all(),
00555       symmetry_error_tol(), symmetry_warning_tol(),
00556       outArg(these_results)
00557       );
00558     
00559     testResultsPrinter.printTestResults(these_results, inoutArg(success));
00560     
00561   }
00562   else {
00563     *out << endl << "this->check_for_symmetry()==false: Skipping check of symmetry ...\n";
00564   }
00565   
00566   if(success)
00567     *out << endl <<"Congratulations, this LinearOpBase object seems to check out!\n";
00568   else
00569     *out << endl <<"Oh no, at least one of the tests performed with this LinearOpBase object failed (see above failures)!\n";
00570   *out << endl << "*** Leaving LinearOpTester<"<<ST::name()<<","<<ST::name()<<">::check(...)\n";
00571 
00572   return success;
00573 
00574 }
00575 
00576 
00577 template<class Scalar>
00578 bool LinearOpTester<Scalar>::check(
00579   const LinearOpBase<Scalar> &op,
00580   const Ptr<Teuchos::FancyOStream> &out
00581   ) const
00582 {
00583   using Teuchos::null;
00584   return check(op, null, null, out);
00585 }
00586 
00587 
00588 template<class Scalar>
00589 bool LinearOpTester<Scalar>::compare(
00590   const LinearOpBase<Scalar> &op1,
00591   const LinearOpBase<Scalar> &op2,
00592   const Ptr<MultiVectorRandomizerBase<Scalar> > &domainRandomizer,
00593   const Ptr<Teuchos::FancyOStream> &out_arg
00594   ) const
00595 {
00596 
00597   using std::endl;
00598   using Teuchos::rcpFromPtr;
00599   using Teuchos::inoutArg;
00600   using Teuchos::FancyOStream;
00601   using Teuchos::OSTab;
00602   typedef Teuchos::ScalarTraits<Scalar> ST;
00603   bool success = true, result;
00604   const int loc_num_rhs = this->num_rhs();
00605   const Scalar  r_half = Scalar(0.5)*ST::one();
00606   const RCP<FancyOStream> out = rcpFromPtr(out_arg);
00607   const Teuchos::EVerbosityLevel verbLevel = (dump_all()?Teuchos::VERB_EXTREME:Teuchos::VERB_MEDIUM);
00608 
00609   OSTab tab(out,1,"THYRA");
00610 
00611   if(out.get()) {
00612     *out
00613       << endl << "*** Entering LinearOpTester<"<<ST::name()<<","<<ST::name()<<">::compare(op1,op2,...) ...\n";
00614     if(show_all_tests())
00615       *out << endl << "describe op1:\n" << Teuchos::describe(op1,verbLevel);
00616     else
00617       *out << endl << "describe op1: " << op1.description() << endl;
00618     if(show_all_tests())
00619       *out << endl << "describe op2:\n" << Teuchos::describe(op2,verbLevel);
00620     else
00621       *out << endl << "describe op2: " << op2.description() << endl;
00622   }
00623 
00624   RCP<MultiVectorRandomizerBase<Scalar> > dRand;
00625   if (nonnull(domainRandomizer)) dRand = rcpFromPtr(domainRandomizer);
00626   else dRand = universalMultiVectorRandomizer<Scalar>();
00627 
00628   RCP<const VectorSpaceBase<Scalar> >  range  = op1.range();
00629   RCP<const VectorSpaceBase<Scalar> > domain = op1.domain();
00630 
00631   if(out.get()) *out << endl << "Checking that range and domain spaces are compatible ... ";
00632 
00633   {
00634 
00635     TestResultsPrinter testResultsPrinter(out, show_all_tests());
00636     const RCP<FancyOStream> testOut = testResultsPrinter.getTestOStream();
00637 
00638     bool these_results = true;
00639 
00640     *testOut << endl << "op1.domain()->isCompatible(*op2.domain()) ? ";
00641     result = op1.domain()->isCompatible(*op2.domain());
00642     if(!result) these_results = false;
00643     *testOut << passfail(result) << endl;
00644     
00645     *testOut << endl << "op1.range()->isCompatible(*op2.range()) ? ";
00646     result = op1.range()->isCompatible(*op2.range());
00647     if(!result) these_results = false;
00648     *testOut << passfail(result) << endl;
00649 
00650     testResultsPrinter.printTestResults(these_results, inoutArg(success));
00651 
00652   }
00653 
00654   if(!success) {
00655     if(out.get()) *out << endl << "Skipping further checks since operators are not compatible!\n";
00656     return success;
00657   }
00658 
00659   if(out.get()) *out << endl << "Checking that op1 == op2 ... ";
00660 
00661   {
00662 
00663     TestResultsPrinter testResultsPrinter(out, show_all_tests());
00664     const RCP<FancyOStream> testOut = testResultsPrinter.getTestOStream();
00665 
00666     bool these_results = true;
00667 
00668     *testOut
00669       << endl << "Checking that op1 and op2 produce the same results:\n"
00670       << endl << "  0.5*op1*v1 == 0.5*op2*v1"
00671       << endl << "  \\________/    \\________/"
00672       << endl << "      v2            v3"
00673       << endl << ""
00674       << endl << "   norm(v2-v3) ~= 0"
00675       // << endl << "   |sum(v2)| == |sum(v3)|"
00676       << endl << std::flush;
00677 
00678     for( int rand_vec_i = 1; rand_vec_i <= num_random_vectors(); ++rand_vec_i ) {
00679       
00680       *testOut << endl << "Random vector tests = " << rand_vec_i << endl;
00681 
00682       OSTab tab2(testOut);
00683       
00684       if(dump_all()) *testOut << endl << "v1 = randomize(-1,+1); ...\n" ;
00685       RCP<MultiVectorBase<Scalar> > v1 = createMembers(domain,loc_num_rhs);
00686       dRand->randomize(v1.ptr());
00687       if(dump_all()) *testOut << endl << "v1 =\n" << *v1;
00688       
00689       if(dump_all()) *testOut << endl << "v2 = 0.5*op1*v1 ...\n" ;
00690       RCP<MultiVectorBase<Scalar> > v2 = createMembers(range,loc_num_rhs);
00691       apply( op1, NOTRANS, *v1, v2.ptr(), r_half );
00692       if(dump_all()) *testOut << endl << "v2 =\n" << *v2;
00693       
00694       if(dump_all()) *testOut << endl << "v3 = 0.5*op2*v1 ...\n" ;
00695       RCP<MultiVectorBase<Scalar> > v3 = createMembers(range,loc_num_rhs);
00696       apply( op2, NOTRANS, *v1, v3.ptr(), r_half );
00697       if(dump_all()) *testOut << endl << "v3 =\n" << *v3;
00698       
00699       // check error in each column
00700       for(int col_id=0;col_id < v1->domain()->dim();col_id++) {
00701          std::stringstream ss;
00702          ss << ".col[" << col_id << "]";
00703 
00704          result = Thyra::testRelNormDiffErr(
00705            "v2"+ss.str(),*v2->col(col_id),
00706            "v3"+ss.str(),*v3->col(col_id),
00707            "linear_properties_error_tol()", linear_properties_error_tol(),
00708            "linear_properties_warning_tol()", linear_properties_warning_tol(),
00709            &*testOut);
00710          if(!result) these_results = false;
00711       }
00712       /*
00713       Array<Scalar> sum_v2(loc_num_rhs), sum_v3(loc_num_rhs);
00714       sums(*v2,&sum_v2[0]);
00715       sums(*v3,&sum_v3[0]);
00716       
00717       result = testRelErrors(
00718         loc_num_rhs
00719         ,"sum(v2)", &sum_v2[0]
00720         ,"sum(v3)", &sum_v3[0]
00721         ,"linear_properties_error_tol()", linear_properties_error_tol()
00722         ,"linear_properties_warning_tol()", linear_properties_warning_tol()
00723         ,inOutArg(testOut)
00724         );
00725       */
00726       if(!result) these_results = false;
00727       
00728     }
00729 
00730     testResultsPrinter.printTestResults(these_results, inoutArg(success));
00731 
00732   }
00733   
00734   if(out.get()) {
00735     if(success)
00736       *out << endl <<"Congratulations, these two LinearOpBase objects seem to be the same!\n";
00737     else
00738       *out << endl <<"Oh no, these two LinearOpBase objects seem to be different (see above failures)!\n";
00739     *out << endl << "*** Leaving LinearOpTester<"<<ST::name()<<","<<ST::name()<<">::compare(...)\n";
00740   }
00741 
00742   return success;
00743 
00744 }
00745 
00746 
00747 template<class Scalar>
00748 bool LinearOpTester<Scalar>::compare(
00749   const LinearOpBase<Scalar> &op1,
00750   const LinearOpBase<Scalar> &op2,
00751   const Ptr<Teuchos::FancyOStream> &out_arg
00752   ) const
00753 {
00754   return compare(op1, op2, Teuchos::null, out_arg);
00755 }
00756 
00757 
00758 // private
00759 
00760 
00761 // Nonmember helper
00762 template<class ScalarMag>
00763 inline
00764 void setDefaultTol(const ScalarMag &defaultDefaultTol,
00765     ScalarMag &defaultTol)
00766 {
00767   typedef ScalarTraits<ScalarMag> SMT;
00768   if (defaultTol < SMT::zero()) {
00769     defaultTol = defaultDefaultTol;
00770   }
00771 }
00772 
00773 
00774 template<class Scalar>
00775 void LinearOpTester<Scalar>::setDefaultTols()
00776 {
00777   typedef ScalarTraits<ScalarMag> SMT;
00778   const ScalarMag defaultWarningTol = 1e+2 * SMT::eps();
00779   const ScalarMag defaultErrorTol = 1e+4 * SMT::eps();
00780   setDefaultTol(defaultWarningTol, linear_properties_warning_tol_);
00781   setDefaultTol(defaultErrorTol, linear_properties_error_tol_);
00782   setDefaultTol(defaultWarningTol, adjoint_warning_tol_);
00783   setDefaultTol(defaultErrorTol, adjoint_error_tol_);
00784   setDefaultTol(defaultWarningTol, symmetry_warning_tol_);
00785   setDefaultTol(defaultErrorTol, symmetry_error_tol_);
00786 }
00787 
00788 
00789 } // namespace Thyra
00790 
00791 
00792 #endif // THYRA_LINEAR_OP_TESTER_DEF_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines