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