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