Thyra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Thyra_AssertOp.hpp
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Thyra: Interfaces and Support for Abstract Numerical Algorithms
5 // Copyright (2004) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Roscoe A. Bartlett (bartlettra@ornl.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #ifndef THYRA_ASSERT_OP_HPP
43 #define THYRA_ASSERT_OP_HPP
44 
45 
46 #include "Thyra_OperatorVectorTypes.hpp"
47 #include "Thyra_VectorSpaceBase.hpp"
48 #include "Thyra_VectorBase.hpp"
49 #include "Thyra_LinearOpBase.hpp"
50 #include "Teuchos_Assert.hpp"
51 
52 
53 namespace Thyra {
54 
55 
56 /* Utility struct for dumping vector space names, dimension etc.
57  */
58 template<class Scalar>
59 struct dump_vec_spaces_t {
60 public:
61  dump_vec_spaces_t(
62  const Thyra::VectorSpaceBase<Scalar>& _vec_space1,
63  const std::string &_vec_space1_name,
64  const Thyra::VectorSpaceBase<Scalar>& _vec_space2,
65  const std::string &_vec_space2_name
66  )
67  :vec_space1(_vec_space1),vec_space1_name(_vec_space1_name)
68  ,vec_space2(_vec_space2),vec_space2_name(_vec_space2_name)
69  {}
70  const Thyra::VectorSpaceBase<Scalar> &vec_space1;
71  const std::string vec_space1_name;
72  const Thyra::VectorSpaceBase<Scalar> &vec_space2;
73  const std::string vec_space2_name;
74 }; // end dum_vec_spaces
75 
76 
77 /* Utility function for dumping vector space names, dimension etc.
78  */
79 template<class Scalar>
80 inline dump_vec_spaces_t<Scalar> dump_vec_spaces(
81  const Thyra::VectorSpaceBase<Scalar>& vec_space1,
82  const std::string &vec_space1_name,
83  const Thyra::VectorSpaceBase<Scalar>& vec_space2,
84  const std::string &vec_space2_name
85  )
86 {
87  return dump_vec_spaces_t<Scalar>(
88  vec_space1,vec_space1_name,vec_space2,vec_space2_name);
89 }
90 
91 
92 // Notice!!!!!!! Place a breakpoint in following function in order to halt the
93 // program just before an exception is thrown!
94 
95 
96 /* Utility ostream operator for dumping vector space names, dimension etc.
97  */
98 template<class Scalar>
99 std::ostream& operator<<( std::ostream& o, const dump_vec_spaces_t<Scalar>& d )
100 {
101 
102  using Teuchos::OSTab;
104  o << "Error, the following vector spaces are not compatible:\n\n";
105  OSTab(o).o()
106  << d.vec_space1_name << " : "
107  << Teuchos::describe(d.vec_space1,verbLevel);
108  o << "\n";
109  OSTab(o).o()
110  << d.vec_space2_name << " : "
111  << Teuchos::describe(d.vec_space2,verbLevel);
112  return o;
113 }
114 
115 
116 /* Utility enum for selecting domain or range spaces
117  */
118 enum EM_VS { VS_RANGE, VS_DOMAIN };
119 
120 
125 template<class Scalar>
128  Thyra::EOpTransp M_trans,
129  EM_VS M_VS
130  )
131 {
132  if(real_trans(M_trans) == NOTRANS && M_VS == VS_RANGE)
133  return *M.range();
134  if(real_trans(M_trans) == TRANS && M_VS == VS_RANGE)
135  return *M.domain();
136  if(real_trans(M_trans) == NOTRANS && M_VS == VS_DOMAIN)
137  return *M.domain();
138  // real_trans(M_trans) == TRANS && M_VS == VS_DOMAIN
139  return *M.range();
140 }
141 
142 
143 } // end namespace Thyra
144 
145 
150 #define THYRA_ASSERT_LHS_ARG(FUNC_NAME,LHS_ARG) \
151  TEUCHOS_TEST_FOR_EXCEPTION( \
152  (&*LHS_ARG) == NULL, std::invalid_argument, \
153  FUNC_NAME << " : Error!" \
154  );
155 
156 
157 // Notice!!!!!!! Setting a breakpoint at the line number that is printed by this macro
158 // and then trying to set the condition !isCompatible does not work (at least not
159 // in gdb).
160 
161 
166 #define THYRA_ASSERT_VEC_SPACES_NAMES(FUNC_NAME,VS1,VS1_NAME,VS2,VS2_NAME) \
167 { \
168  const bool l_isCompatible = (VS1).isCompatible(VS2); \
169  TEUCHOS_TEST_FOR_EXCEPTION( \
170  !l_isCompatible, ::Thyra::Exceptions::IncompatibleVectorSpaces, \
171  FUNC_NAME << "\n\n" \
172  << ::Thyra::dump_vec_spaces(VS1,VS1_NAME,VS2,VS2_NAME) \
173  ) \
174 }
175 
176 
188 #define THYRA_ASSERT_VEC_SPACES(FUNC_NAME,VS1,VS2)\
189 THYRA_ASSERT_VEC_SPACES_NAMES(FUNC_NAME,VS1,#VS1,VS2,#VS2)
190 
191 
199 #define THYRA_ASSERT_MAT_VEC_SPACES(FUNC_NAME,M,M_T,M_VS,VS) \
200 { \
201  std::ostringstream M_VS_name; \
202  M_VS_name << "(" #M << ( (M_T) == Thyra::NOTRANS ? "" : "^T" ) << ")" \
203  << "." << ( (M_VS) == Thyra::VS_RANGE ? "range()" : "domain()" ); \
204  THYRA_ASSERT_VEC_SPACES_NAMES( \
205  FUNC_NAME, \
206  ::Thyra::linear_op_op(M,M_T,M_VS),M_VS_name.str().c_str(), \
207  (VS),#VS \
208  ) \
209 }
210 
211 
224 #define THYRA_ASSERT_LINEAR_OP_VEC_APPLY_SPACES(FUNC_NAME,M,M_T,X,Y) \
225  { \
226  std::ostringstream headeross; \
227  headeross \
228  << FUNC_NAME << ":\n" \
229  << "Spaces check failed for " \
230  << #M << ( (M_T) == Thyra::NOTRANS ? "" : "^T" ) << " * " \
231  << #X << " and " << #Y; \
232  const std::string &header = headeross.str(); \
233  THYRA_ASSERT_MAT_VEC_SPACES(header,M,M_T,::Thyra::VS_RANGE,*(Y)->space()); \
234  THYRA_ASSERT_MAT_VEC_SPACES(header,M,M_T,::Thyra::VS_DOMAIN,*(X).space()); \
235  }
236 
237 
250 #define THYRA_ASSERT_LINEAR_OP_MULTIVEC_APPLY_SPACES(FUNC_NAME,M,M_T,X,Y) \
251  { \
252  std::ostringstream headeross; \
253  headeross \
254  << FUNC_NAME << ":\n\n" \
255  << "Spaces check failed for " \
256  << #M << ( (M_T) == Thyra::NOTRANS ? "" : "^T" ) << " * " \
257  << #X << " and " << #Y << ":\n\n"; \
258  const std::string &header = headeross.str(); \
259  THYRA_ASSERT_VEC_SPACES(header,*(X).domain(),*(Y)->domain()); \
260  THYRA_ASSERT_MAT_VEC_SPACES(header,M,M_T,::Thyra::VS_RANGE,*(Y)->range()); \
261  THYRA_ASSERT_MAT_VEC_SPACES(header,M,M_T,::Thyra::VS_DOMAIN,*(X).range()); \
262  }
263 
264 
265 namespace Thyra {
266 
267 
268 template<class Scalar>
269 void assertLinearOpPlusLinearOpNames(
270  const std::string &funcName,
271  const LinearOpBase<Scalar> &M1, const EOpTransp M1_trans_in, const std::string &M1_name,
272  const LinearOpBase<Scalar> &M2, const EOpTransp M2_trans_in, const std::string &M2_name
273  )
274 {
275  const EOpTransp M1_trans = real_trans(M1_trans_in);
276  const EOpTransp M2_trans = real_trans(M2_trans_in);
277  std::ostringstream headeross;
278  headeross
279  << funcName << ":\n\n"
280  << "Spaces check failed for "
281  << "(" << M1_name << ")" << ( M1_trans == NOTRANS ? "" : "^T" )
282  << " + "
283  << "(" << M2_name << ")" << ( M2_trans == NOTRANS ? "" : "^T" )
284  << " where:\n\n"
285  << " " << M1_name << ": " << M1.description() << "\n\n"
286  << " " << M2_name << ": " << M2.description();
287  const std::string &header = headeross.str();
288  if ( M1_trans == M2_trans ) {
290  *M1.range(), M1_name + ".range()",
291  *M2.range(), M2_name + ".range()" );
293  *M1.domain(), M1_name + ".domain()",
294  *M2.domain(), M2_name + ".domain()" );
295  }
296  else { // M1_trans != M2_trans
298  *M1.domain(), M1_name + ".domain()",
299  *M2.range(), M2_name + ".range()" );
301  *M1.range(), M1_name + ".range()",
302  *M2.domain(), M2_name + ".domain()" );
303  }
304 }
305 
306 
307 template<class Scalar>
308 void assertLinearOpTimesLinearOpNames(
309  const std::string &funcName,
310  const LinearOpBase<Scalar> &M1, const EOpTransp M1_trans_in, const std::string &M1_name,
311  const LinearOpBase<Scalar> &M2, const EOpTransp M2_trans_in, const std::string &M2_name
312  )
313 {
314  const EOpTransp M1_trans = real_trans(M1_trans_in);
315  const EOpTransp M2_trans = real_trans(M2_trans_in);
316  std::ostringstream headeross;
317  headeross
318  << funcName << ":\n\n"
319  << "Spaces check failed for "
320  << "(" << M1_name << ")" << ( M1_trans == NOTRANS ? "" : "^T" )
321  << " * "
322  << "(" << M2_name << ")" << ( M2_trans == NOTRANS ? "" : "^T" )
323  << " where:\n\n"
324  << " " << M1_name << ": " << M1.description() << "\n\n"
325  << " " << M2_name << ": " << M2.description();
326  const std::string &header = headeross.str();
327  if ( M1_trans == NOTRANS && M2_trans == NOTRANS ) {
329  *M1.domain(), M1_name + ".domain()",
330  *M2.range(), M2_name + ".range()" );
331  }
332  else if ( M1_trans == NOTRANS && M2_trans == TRANS ) {
334  *M1.domain(), M1_name + ".domain()",
335  *M2.domain(), M2_name + ".domain()" );
336  }
337  else if ( M1_trans == TRANS && M2_trans == NOTRANS ) {
339  *M1.domain(), M1_name + ".range()",
340  *M2.range(), M2_name + ".range()" );
341  }
342  else if ( M1_trans == TRANS && M2_trans == TRANS ) {
344  *M1.domain(), M1_name + ".range()",
345  *M2.range(), M2_name + ".domain()" );
346  }
347  else {
348  TEUCHOS_TEST_FOR_EXCEPTION( true, std::logic_error,
349  header << "\n\n" << "Error, invalid value for trasponse enums!" );
350  }
351 }
352 
353 
354 } // namespace Thyra
355 
356 
361 #define THYRA_ASSERT_LINEAR_OP_PLUS_LINEAR_OP_SPACES_NAMES(FUNC_NAME,M1,M1_T,M1_N,M2,M2_T,M2_N) \
362  ::Thyra::assertLinearOpPlusLinearOpNames(FUNC_NAME,M1,M1_T,M1_N,M2,M2_T,M2_N)
363 
364 
369 #define THYRA_ASSERT_LINEAR_OP_TIMES_LINEAR_OP_SPACES_NAMES(FUNC_NAME,M1,M1_T,M1_N,M2,M2_T,M2_N) \
370  ::Thyra::assertLinearOpTimesLinearOpNames(FUNC_NAME,M1,M1_T,M1_N,M2,M2_T,M2_N)
371 
372 
379 #define THYRA_ASSERT_MAT_MAT_SPACES(FUNC_NAME,M1,M1_T,M1_VS,M2,M2_T,M2_VS) \
380  { \
381  std::ostringstream headeross; \
382  headeross \
383  << FUNC_NAME << "\n" \
384  << "Spaces check failed for " \
385  << #M1 << ( (M1_T) == Thyra::NOTRANS ? "" : "^T" ) << " and " \
386  << #M2 << ( (M2_T) == Thyra::NOTRANS ? "" : "^T" ); \
387  const std::string &header = headeross.str(); \
388  std::ostringstream M1_VS_name, M2_VS_name; \
389  M1_VS_name << "(" #M1 << ( M1_T == ::Thyra::NOTRANS ? "" : "^T" ) << ")" \
390  << "." << ( M1_VS == ::Thyra::VS_RANGE ? "range()" : "domain()" ); \
391  M2_VS_name << "(" #M2 << ( M2_T == ::Thyra::NOTRANS ? "" : "^T" ) << ")" \
392  << "." << ( M2_VS == ::Thyra::VS_RANGE ? "range()" : "domain()" ); \
393  THYRA_ASSERT_VEC_SPACES_NAMES( \
394  header, \
395  ::Thyra::linear_op_op(M1,M1_T,M1_VS),M1_VS_name.str().c_str() \
396  ::Thyra::linear_op_op(M2,M2_T,M2_VS),M2_VS_name.str().c_str() \
397  ); \
398  }
399 
400 
401 #endif // THYRA_ASSERT_OP_HPP
virtual RCP< const VectorSpaceBase< Scalar > > range() const =0
Return a smart pointer for the range space for this operator.
EOpTransp
Enumeration for determining how a linear operator is applied. `*.
basic_OSTab< char > OSTab
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Use the non-transposed operator.
EOpTransp real_trans(EOpTransp transp)
Return NOTRANS or TRANS for real scalar valued operators and this also is used for determining struct...
Abstract interface for objects that represent a space for vectors.
Use the transposed operator.
const Thyra::VectorSpaceBase< Scalar > & linear_op_op(const Thyra::LinearOpBase< Scalar > &M, Thyra::EOpTransp M_trans, EM_VS M_VS)
Utility function for selecting domain or range spaces.
Base class for all linear operators.
virtual RCP< const VectorSpaceBase< Scalar > > domain() const =0
Return a smart pointer for the domain space for this operator.
#define THYRA_ASSERT_VEC_SPACES_NAMES(FUNC_NAME, VS1, VS1_NAME, VS2, VS2_NAME)
Helper assertion macro.