Thyra Version of the Day
Thyra_AssertOp.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_ASSERT_OP_HPP
00043 #define THYRA_ASSERT_OP_HPP
00044 
00045 
00046 #include "Thyra_OperatorVectorTypes.hpp"
00047 #include "Thyra_VectorSpaceBase.hpp"
00048 #include "Thyra_VectorBase.hpp"
00049 #include "Thyra_LinearOpBase.hpp"
00050 #include "Teuchos_Assert.hpp"
00051 
00052 
00053 namespace Thyra {
00054 
00055 
00056 /* Utility struct for dumping vector space names, dimension etc.
00057  */
00058 template<class Scalar>
00059 struct dump_vec_spaces_t {
00060 public:
00061   dump_vec_spaces_t(
00062     const Thyra::VectorSpaceBase<Scalar>& _vec_space1,
00063     const std::string &_vec_space1_name,
00064     const Thyra::VectorSpaceBase<Scalar>& _vec_space2,
00065     const std::string &_vec_space2_name
00066     )
00067     :vec_space1(_vec_space1),vec_space1_name(_vec_space1_name)
00068     ,vec_space2(_vec_space2),vec_space2_name(_vec_space2_name)
00069     {}
00070   const Thyra::VectorSpaceBase<Scalar> &vec_space1;
00071   const std::string                    vec_space1_name;
00072   const Thyra::VectorSpaceBase<Scalar> &vec_space2;
00073   const std::string                    vec_space2_name;
00074 }; // end dum_vec_spaces
00075 
00076 
00077 /* Utility function for dumping vector space names, dimension etc.
00078  */
00079 template<class Scalar>
00080 inline dump_vec_spaces_t<Scalar> dump_vec_spaces(
00081   const Thyra::VectorSpaceBase<Scalar>& vec_space1,
00082   const std::string &vec_space1_name,
00083   const Thyra::VectorSpaceBase<Scalar>& vec_space2,
00084   const std::string &vec_space2_name
00085   )
00086 {
00087   return dump_vec_spaces_t<Scalar>(
00088     vec_space1,vec_space1_name,vec_space2,vec_space2_name);
00089 }
00090 
00091 
00092 // Notice!!!!!!!  Place a breakpoint in following function in order to halt the
00093 // program just before an exception is thrown!
00094 
00095 
00096 /* Utility ostream operator for dumping vector space names, dimension etc.
00097  */
00098 template<class Scalar>
00099 std::ostream& operator<<( std::ostream& o, const dump_vec_spaces_t<Scalar>& d )
00100 {
00101 
00102   using Teuchos::OSTab;
00103   const Teuchos::EVerbosityLevel verbLevel = Teuchos::VERB_MEDIUM;
00104   o << "Error, the following vector spaces are not compatible:\n\n";
00105   OSTab(o).o()
00106     << d.vec_space1_name << " : "
00107     << Teuchos::describe(d.vec_space1,verbLevel);
00108   o << "\n";
00109   OSTab(o).o()
00110     << d.vec_space2_name << " : "
00111     << Teuchos::describe(d.vec_space2,verbLevel);
00112   return o;
00113 }
00114 
00115 
00116 /* Utility enum for selecting domain or range spaces
00117  */
00118 enum EM_VS { VS_RANGE, VS_DOMAIN };
00119 
00120 
00125 template<class Scalar>
00126 const Thyra::VectorSpaceBase<Scalar>& linear_op_op(
00127   const Thyra::LinearOpBase<Scalar>& M,
00128   Thyra::EOpTransp M_trans,
00129   EM_VS M_VS
00130   )
00131 {
00132   if(real_trans(M_trans) == NOTRANS && M_VS == VS_RANGE)
00133     return *M.range();
00134   if(real_trans(M_trans) == TRANS && M_VS == VS_RANGE)
00135     return *M.domain();
00136   if(real_trans(M_trans) == NOTRANS && M_VS == VS_DOMAIN)
00137     return *M.domain();
00138   // real_trans(M_trans) == TRANS && M_VS == VS_DOMAIN
00139   return *M.range();
00140 }
00141 
00142 
00143 } // end namespace Thyra
00144 
00145 
00150 #define THYRA_ASSERT_LHS_ARG(FUNC_NAME,LHS_ARG) \
00151   TEUCHOS_TEST_FOR_EXCEPTION( \
00152     (&*LHS_ARG) == NULL, std::invalid_argument, \
00153     FUNC_NAME << " : Error!" \
00154     );
00155 
00156 
00157 // Notice!!!!!!!  Setting a breakpoint at the line number that is printed by this macro
00158 // and then trying to set the condition !isCompatible does not work (at least not
00159 // in gdb).
00160 
00161 
00166 #define THYRA_ASSERT_VEC_SPACES_NAMES(FUNC_NAME,VS1,VS1_NAME,VS2,VS2_NAME) \
00167 { \
00168   const bool l_isCompatible = (VS1).isCompatible(VS2); \
00169   TEUCHOS_TEST_FOR_EXCEPTION( \
00170     !l_isCompatible, ::Thyra::Exceptions::IncompatibleVectorSpaces, \
00171     FUNC_NAME << "\n\n" \
00172     << ::Thyra::dump_vec_spaces(VS1,VS1_NAME,VS2,VS2_NAME) \
00173     ) \
00174 }
00175 
00176 
00188 #define THYRA_ASSERT_VEC_SPACES(FUNC_NAME,VS1,VS2)\
00189 THYRA_ASSERT_VEC_SPACES_NAMES(FUNC_NAME,VS1,#VS1,VS2,#VS2)
00190 
00191 
00199 #define THYRA_ASSERT_MAT_VEC_SPACES(FUNC_NAME,M,M_T,M_VS,VS) \
00200 { \
00201   std::ostringstream M_VS_name; \
00202   M_VS_name << "(" #M << ( (M_T) == Thyra::NOTRANS ? "" : "^T" ) << ")" \
00203             << "." << ( (M_VS) == Thyra::VS_RANGE ? "range()" : "domain()" ); \
00204   THYRA_ASSERT_VEC_SPACES_NAMES( \
00205     FUNC_NAME, \
00206     ::Thyra::linear_op_op(M,M_T,M_VS),M_VS_name.str().c_str(), \
00207     (VS),#VS \
00208     ) \
00209 }
00210 
00211 
00224 #define THYRA_ASSERT_LINEAR_OP_VEC_APPLY_SPACES(FUNC_NAME,M,M_T,X,Y) \
00225   { \
00226     std::ostringstream headeross; \
00227     headeross \
00228       << FUNC_NAME << ":\n" \
00229       << "Spaces check failed for " \
00230       << #M << ( (M_T) == Thyra::NOTRANS ? "" : "^T" ) << " * " \
00231       << #X << " and " << #Y; \
00232     const std::string &header = headeross.str(); \
00233     THYRA_ASSERT_MAT_VEC_SPACES(header,M,M_T,::Thyra::VS_RANGE,*(Y)->space()); \
00234     THYRA_ASSERT_MAT_VEC_SPACES(header,M,M_T,::Thyra::VS_DOMAIN,*(X).space()); \
00235   }
00236 
00237 
00250 #define THYRA_ASSERT_LINEAR_OP_MULTIVEC_APPLY_SPACES(FUNC_NAME,M,M_T,X,Y) \
00251   { \
00252     std::ostringstream headeross; \
00253     headeross \
00254       << FUNC_NAME << ":\n\n" \
00255       << "Spaces check failed for " \
00256       << #M << ( (M_T) == Thyra::NOTRANS ? "" : "^T" ) << " * " \
00257       << #X << " and " << #Y << ":\n\n"; \
00258     const std::string &header = headeross.str(); \
00259     THYRA_ASSERT_VEC_SPACES(header,*(X).domain(),*(Y)->domain()); \
00260     THYRA_ASSERT_MAT_VEC_SPACES(header,M,M_T,::Thyra::VS_RANGE,*(Y)->range()); \
00261     THYRA_ASSERT_MAT_VEC_SPACES(header,M,M_T,::Thyra::VS_DOMAIN,*(X).range()); \
00262   }
00263 
00264 
00265 namespace Thyra {
00266 
00267 
00268 template<class Scalar>
00269 void assertLinearOpPlusLinearOpNames(
00270   const std::string &funcName,
00271   const LinearOpBase<Scalar> &M1, const EOpTransp M1_trans_in, const std::string &M1_name,
00272   const LinearOpBase<Scalar> &M2, const EOpTransp M2_trans_in, const std::string &M2_name
00273   )
00274 {
00275   const EOpTransp M1_trans = real_trans(M1_trans_in);
00276   const EOpTransp M2_trans = real_trans(M2_trans_in);
00277   std::ostringstream headeross;
00278   headeross
00279     << funcName << ":\n\n"
00280     << "Spaces check failed for "
00281     << "(" << M1_name << ")" << ( M1_trans == NOTRANS ? "" : "^T" )
00282     << " + "
00283     << "(" << M2_name << ")" << ( M2_trans == NOTRANS ? "" : "^T" )
00284     << " where:\n\n"
00285     << "  " << M1_name << ": " << M1.description() << "\n\n"
00286     << "  " << M2_name << ": " << M2.description();
00287   const std::string &header = headeross.str();
00288   if ( M1_trans == M2_trans ) {
00289     THYRA_ASSERT_VEC_SPACES_NAMES( header,
00290       *M1.range(), M1_name + ".range()",
00291       *M2.range(), M2_name + ".range()" );
00292     THYRA_ASSERT_VEC_SPACES_NAMES( header,
00293       *M1.domain(), M1_name + ".domain()",
00294       *M2.domain(), M2_name + ".domain()" );
00295   }
00296   else { // M1_trans != M2_trans
00297     THYRA_ASSERT_VEC_SPACES_NAMES( header,
00298       *M1.domain(), M1_name + ".domain()",
00299       *M2.range(), M2_name + ".range()" );
00300     THYRA_ASSERT_VEC_SPACES_NAMES( header,
00301       *M1.range(), M1_name + ".range()",
00302       *M2.domain(), M2_name + ".domain()" );
00303   }
00304 }
00305 
00306 
00307 template<class Scalar>
00308 void assertLinearOpTimesLinearOpNames(
00309   const std::string &funcName,
00310   const LinearOpBase<Scalar> &M1, const EOpTransp M1_trans_in, const std::string &M1_name,
00311   const LinearOpBase<Scalar> &M2, const EOpTransp M2_trans_in, const std::string &M2_name
00312   )
00313 {
00314   const EOpTransp M1_trans = real_trans(M1_trans_in);
00315   const EOpTransp M2_trans = real_trans(M2_trans_in);
00316   std::ostringstream headeross;
00317   headeross
00318     << funcName << ":\n\n"
00319     << "Spaces check failed for "
00320     << "(" << M1_name << ")" << ( M1_trans == NOTRANS ? "" : "^T" )
00321     << " * "
00322     << "(" << M2_name << ")" << ( M2_trans == NOTRANS ? "" : "^T" )
00323     << " where:\n\n"
00324     << "  " << M1_name << ": " << M1.description() << "\n\n"
00325     << "  " << M2_name << ": " << M2.description();
00326   const std::string &header = headeross.str();
00327   if ( M1_trans == NOTRANS &&  M2_trans == NOTRANS ) {
00328     THYRA_ASSERT_VEC_SPACES_NAMES( header,
00329       *M1.domain(), M1_name + ".domain()",
00330       *M2.range(), M2_name + ".range()" );
00331   }
00332   else if ( M1_trans == NOTRANS && M2_trans == TRANS ) {
00333     THYRA_ASSERT_VEC_SPACES_NAMES( header,
00334       *M1.domain(), M1_name + ".domain()",
00335       *M2.domain(), M2_name + ".domain()" );
00336   }
00337   else if ( M1_trans == TRANS &&  M2_trans == NOTRANS ) {
00338     THYRA_ASSERT_VEC_SPACES_NAMES( header,
00339       *M1.domain(), M1_name + ".range()",
00340       *M2.range(), M2_name + ".range()" );
00341   }
00342   else if ( M1_trans == TRANS &&  M2_trans == TRANS ) {
00343     THYRA_ASSERT_VEC_SPACES_NAMES( header,
00344       *M1.domain(), M1_name + ".range()",
00345       *M2.range(), M2_name + ".domain()" );
00346   }
00347   else {
00348     TEUCHOS_TEST_FOR_EXCEPTION( true, std::logic_error,
00349       header << "\n\n" << "Error, invalid value for trasponse enums!" );
00350   }
00351 }
00352 
00353 
00354 } // namespace Thyra
00355 
00356 
00361 #define THYRA_ASSERT_LINEAR_OP_PLUS_LINEAR_OP_SPACES_NAMES(FUNC_NAME,M1,M1_T,M1_N,M2,M2_T,M2_N) \
00362   ::Thyra::assertLinearOpPlusLinearOpNames(FUNC_NAME,M1,M1_T,M1_N,M2,M2_T,M2_N)
00363 
00364 
00369 #define THYRA_ASSERT_LINEAR_OP_TIMES_LINEAR_OP_SPACES_NAMES(FUNC_NAME,M1,M1_T,M1_N,M2,M2_T,M2_N) \
00370   ::Thyra::assertLinearOpTimesLinearOpNames(FUNC_NAME,M1,M1_T,M1_N,M2,M2_T,M2_N)
00371 
00372 
00379 #define THYRA_ASSERT_MAT_MAT_SPACES(FUNC_NAME,M1,M1_T,M1_VS,M2,M2_T,M2_VS) \
00380   { \
00381     std::ostringstream headeross; \
00382     headeross \
00383       << FUNC_NAME << "\n" \
00384       << "Spaces check failed for " \
00385       << #M1 << ( (M1_T) == Thyra::NOTRANS ? "" : "^T" ) << " and " \
00386       << #M2 << ( (M2_T) == Thyra::NOTRANS ? "" : "^T" ); \
00387     const std::string &header = headeross.str(); \
00388     std::ostringstream M1_VS_name, M2_VS_name; \
00389     M1_VS_name << "(" #M1 << ( M1_T == ::Thyra::NOTRANS ? "" : "^T" ) << ")" \
00390                << "." << ( M1_VS == ::Thyra::VS_RANGE ? "range()" : "domain()" ); \
00391     M2_VS_name << "(" #M2 << ( M2_T == ::Thyra::NOTRANS ? "" : "^T" ) << ")" \
00392                << "." << ( M2_VS == ::Thyra::VS_RANGE ? "range()" : "domain()" ); \
00393     THYRA_ASSERT_VEC_SPACES_NAMES( \
00394       header, \
00395       ::Thyra::linear_op_op(M1,M1_T,M1_VS),M1_VS_name.str().c_str() \
00396       ::Thyra::linear_op_op(M2,M2_T,M2_VS),M2_VS_name.str().c_str() \
00397       ); \
00398   }
00399 
00400 
00401 #endif // THYRA_ASSERT_OP_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines