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 // Thyra: Interfaces and Support for Abstract Numerical Algorithms
4 //
5 // Copyright 2004 NTESS and the Thyra contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef THYRA_ASSERT_OP_HPP
11 #define THYRA_ASSERT_OP_HPP
12 
13 
14 #include "Thyra_OperatorVectorTypes.hpp"
15 #include "Thyra_VectorSpaceBase.hpp"
16 #include "Thyra_VectorBase.hpp"
17 #include "Thyra_LinearOpBase.hpp"
18 #include "Teuchos_Assert.hpp"
19 
20 
21 namespace Thyra {
22 
23 
24 /* Utility struct for dumping vector space names, dimension etc.
25  */
26 template<class Scalar>
27 struct dump_vec_spaces_t {
28 public:
29  dump_vec_spaces_t(
30  const Thyra::VectorSpaceBase<Scalar>& _vec_space1,
31  const std::string &_vec_space1_name,
32  const Thyra::VectorSpaceBase<Scalar>& _vec_space2,
33  const std::string &_vec_space2_name
34  )
35  :vec_space1(_vec_space1),vec_space1_name(_vec_space1_name)
36  ,vec_space2(_vec_space2),vec_space2_name(_vec_space2_name)
37  {}
38  const Thyra::VectorSpaceBase<Scalar> &vec_space1;
39  const std::string vec_space1_name;
40  const Thyra::VectorSpaceBase<Scalar> &vec_space2;
41  const std::string vec_space2_name;
42 }; // end dum_vec_spaces
43 
44 
45 /* Utility function for dumping vector space names, dimension etc.
46  */
47 template<class Scalar>
48 inline dump_vec_spaces_t<Scalar> dump_vec_spaces(
49  const Thyra::VectorSpaceBase<Scalar>& vec_space1,
50  const std::string &vec_space1_name,
51  const Thyra::VectorSpaceBase<Scalar>& vec_space2,
52  const std::string &vec_space2_name
53  )
54 {
55  return dump_vec_spaces_t<Scalar>(
56  vec_space1,vec_space1_name,vec_space2,vec_space2_name);
57 }
58 
59 
60 // Notice!!!!!!! Place a breakpoint in following function in order to halt the
61 // program just before an exception is thrown!
62 
63 
64 /* Utility ostream operator for dumping vector space names, dimension etc.
65  */
66 template<class Scalar>
67 std::ostream& operator<<( std::ostream& o, const dump_vec_spaces_t<Scalar>& d )
68 {
69 
70  using Teuchos::OSTab;
72  o << "Error, the following vector spaces are not compatible:\n\n";
73  OSTab(o).o()
74  << d.vec_space1_name << " : "
75  << Teuchos::describe(d.vec_space1,verbLevel);
76  o << "\n";
77  OSTab(o).o()
78  << d.vec_space2_name << " : "
79  << Teuchos::describe(d.vec_space2,verbLevel);
80  return o;
81 }
82 
83 
84 /* Utility enum for selecting domain or range spaces
85  */
86 enum EM_VS { VS_RANGE, VS_DOMAIN };
87 
88 
93 template<class Scalar>
96  Thyra::EOpTransp M_trans,
97  EM_VS M_VS
98  )
99 {
100  if(real_trans(M_trans) == NOTRANS && M_VS == VS_RANGE)
101  return *M.range();
102  if(real_trans(M_trans) == TRANS && M_VS == VS_RANGE)
103  return *M.domain();
104  if(real_trans(M_trans) == NOTRANS && M_VS == VS_DOMAIN)
105  return *M.domain();
106  // real_trans(M_trans) == TRANS && M_VS == VS_DOMAIN
107  return *M.range();
108 }
109 
110 
111 } // end namespace Thyra
112 
113 
118 #define THYRA_ASSERT_LHS_ARG(FUNC_NAME,LHS_ARG) \
119  TEUCHOS_TEST_FOR_EXCEPTION( \
120  (&*LHS_ARG) == NULL, std::invalid_argument, \
121  FUNC_NAME << " : Error!" \
122  );
123 
124 
125 // Notice!!!!!!! Setting a breakpoint at the line number that is printed by this macro
126 // and then trying to set the condition !isCompatible does not work (at least not
127 // in gdb).
128 
129 
134 #define THYRA_ASSERT_VEC_SPACES_NAMES(FUNC_NAME,VS1,VS1_NAME,VS2,VS2_NAME) \
135 { \
136  const bool l_isCompatible = (VS1).isCompatible(VS2); \
137  TEUCHOS_TEST_FOR_EXCEPTION( \
138  !l_isCompatible, ::Thyra::Exceptions::IncompatibleVectorSpaces, \
139  FUNC_NAME << "\n\n" \
140  << ::Thyra::dump_vec_spaces(VS1,VS1_NAME,VS2,VS2_NAME) \
141  ) \
142 }
143 
144 
156 #define THYRA_ASSERT_VEC_SPACES(FUNC_NAME,VS1,VS2)\
157 THYRA_ASSERT_VEC_SPACES_NAMES(FUNC_NAME,VS1,#VS1,VS2,#VS2)
158 
159 
167 #define THYRA_ASSERT_MAT_VEC_SPACES(FUNC_NAME,M,M_T,M_VS,VS) \
168 { \
169  std::ostringstream M_VS_name; \
170  M_VS_name << "(" #M << ( (M_T) == Thyra::NOTRANS ? "" : "^T" ) << ")" \
171  << "." << ( (M_VS) == Thyra::VS_RANGE ? "range()" : "domain()" ); \
172  THYRA_ASSERT_VEC_SPACES_NAMES( \
173  FUNC_NAME, \
174  ::Thyra::linear_op_op(M,M_T,M_VS),M_VS_name.str().c_str(), \
175  (VS),#VS \
176  ) \
177 }
178 
179 
192 #define THYRA_ASSERT_LINEAR_OP_VEC_APPLY_SPACES(FUNC_NAME,M,M_T,X,Y) \
193  { \
194  std::ostringstream headeross; \
195  headeross \
196  << FUNC_NAME << ":\n" \
197  << "Spaces check failed for " \
198  << #M << ( (M_T) == Thyra::NOTRANS ? "" : "^T" ) << " * " \
199  << #X << " and " << #Y; \
200  const std::string &header = headeross.str(); \
201  THYRA_ASSERT_MAT_VEC_SPACES(header,M,M_T,::Thyra::VS_RANGE,*(Y)->space()); \
202  THYRA_ASSERT_MAT_VEC_SPACES(header,M,M_T,::Thyra::VS_DOMAIN,*(X).space()); \
203  }
204 
205 
218 #define THYRA_ASSERT_LINEAR_OP_MULTIVEC_APPLY_SPACES(FUNC_NAME,M,M_T,X,Y) \
219  { \
220  std::ostringstream headeross; \
221  headeross \
222  << FUNC_NAME << ":\n\n" \
223  << "Spaces check failed for " \
224  << #M << ( (M_T) == Thyra::NOTRANS ? "" : "^T" ) << " * " \
225  << #X << " and " << #Y << ":\n\n"; \
226  const std::string &header = headeross.str(); \
227  THYRA_ASSERT_VEC_SPACES(header,*(X).domain(),*(Y)->domain()); \
228  THYRA_ASSERT_MAT_VEC_SPACES(header,M,M_T,::Thyra::VS_RANGE,*(Y)->range()); \
229  THYRA_ASSERT_MAT_VEC_SPACES(header,M,M_T,::Thyra::VS_DOMAIN,*(X).range()); \
230  }
231 
232 
233 namespace Thyra {
234 
235 
236 template<class Scalar>
237 void assertLinearOpPlusLinearOpNames(
238  const std::string &funcName,
239  const LinearOpBase<Scalar> &M1, const EOpTransp M1_trans_in, const std::string &M1_name,
240  const LinearOpBase<Scalar> &M2, const EOpTransp M2_trans_in, const std::string &M2_name
241  )
242 {
243  const EOpTransp M1_trans = real_trans(M1_trans_in);
244  const EOpTransp M2_trans = real_trans(M2_trans_in);
245  std::ostringstream headeross;
246  headeross
247  << funcName << ":\n\n"
248  << "Spaces check failed for "
249  << "(" << M1_name << ")" << ( M1_trans == NOTRANS ? "" : "^T" )
250  << " + "
251  << "(" << M2_name << ")" << ( M2_trans == NOTRANS ? "" : "^T" )
252  << " where:\n\n"
253  << " " << M1_name << ": " << M1.description() << "\n\n"
254  << " " << M2_name << ": " << M2.description();
255  const std::string &header = headeross.str();
256  if ( M1_trans == M2_trans ) {
258  *M1.range(), M1_name + ".range()",
259  *M2.range(), M2_name + ".range()" );
261  *M1.domain(), M1_name + ".domain()",
262  *M2.domain(), M2_name + ".domain()" );
263  }
264  else { // M1_trans != M2_trans
266  *M1.domain(), M1_name + ".domain()",
267  *M2.range(), M2_name + ".range()" );
269  *M1.range(), M1_name + ".range()",
270  *M2.domain(), M2_name + ".domain()" );
271  }
272 }
273 
274 
275 template<class Scalar>
276 void assertLinearOpTimesLinearOpNames(
277  const std::string &funcName,
278  const LinearOpBase<Scalar> &M1, const EOpTransp M1_trans_in, const std::string &M1_name,
279  const LinearOpBase<Scalar> &M2, const EOpTransp M2_trans_in, const std::string &M2_name
280  )
281 {
282  const EOpTransp M1_trans = real_trans(M1_trans_in);
283  const EOpTransp M2_trans = real_trans(M2_trans_in);
284  std::ostringstream headeross;
285  headeross
286  << funcName << ":\n\n"
287  << "Spaces check failed for "
288  << "(" << M1_name << ")" << ( M1_trans == NOTRANS ? "" : "^T" )
289  << " * "
290  << "(" << M2_name << ")" << ( M2_trans == NOTRANS ? "" : "^T" )
291  << " where:\n\n"
292  << " " << M1_name << ": " << M1.description() << "\n\n"
293  << " " << M2_name << ": " << M2.description();
294  const std::string &header = headeross.str();
295  if ( M1_trans == NOTRANS && M2_trans == NOTRANS ) {
297  *M1.domain(), M1_name + ".domain()",
298  *M2.range(), M2_name + ".range()" );
299  }
300  else if ( M1_trans == NOTRANS && M2_trans == TRANS ) {
302  *M1.domain(), M1_name + ".domain()",
303  *M2.domain(), M2_name + ".domain()" );
304  }
305  else if ( M1_trans == TRANS && M2_trans == NOTRANS ) {
307  *M1.domain(), M1_name + ".range()",
308  *M2.range(), M2_name + ".range()" );
309  }
310  else if ( M1_trans == TRANS && M2_trans == TRANS ) {
312  *M1.domain(), M1_name + ".range()",
313  *M2.range(), M2_name + ".domain()" );
314  }
315  else {
316  TEUCHOS_TEST_FOR_EXCEPTION( true, std::logic_error,
317  header << "\n\n" << "Error, invalid value for trasponse enums!" );
318  }
319 }
320 
321 
322 } // namespace Thyra
323 
324 
329 #define THYRA_ASSERT_LINEAR_OP_PLUS_LINEAR_OP_SPACES_NAMES(FUNC_NAME,M1,M1_T,M1_N,M2,M2_T,M2_N) \
330  ::Thyra::assertLinearOpPlusLinearOpNames(FUNC_NAME,M1,M1_T,M1_N,M2,M2_T,M2_N)
331 
332 
337 #define THYRA_ASSERT_LINEAR_OP_TIMES_LINEAR_OP_SPACES_NAMES(FUNC_NAME,M1,M1_T,M1_N,M2,M2_T,M2_N) \
338  ::Thyra::assertLinearOpTimesLinearOpNames(FUNC_NAME,M1,M1_T,M1_N,M2,M2_T,M2_N)
339 
340 
347 #define THYRA_ASSERT_MAT_MAT_SPACES(FUNC_NAME,M1,M1_T,M1_VS,M2,M2_T,M2_VS) \
348  { \
349  std::ostringstream headeross; \
350  headeross \
351  << FUNC_NAME << "\n" \
352  << "Spaces check failed for " \
353  << #M1 << ( (M1_T) == Thyra::NOTRANS ? "" : "^T" ) << " and " \
354  << #M2 << ( (M2_T) == Thyra::NOTRANS ? "" : "^T" ); \
355  const std::string &header = headeross.str(); \
356  std::ostringstream M1_VS_name, M2_VS_name; \
357  M1_VS_name << "(" #M1 << ( M1_T == ::Thyra::NOTRANS ? "" : "^T" ) << ")" \
358  << "." << ( M1_VS == ::Thyra::VS_RANGE ? "range()" : "domain()" ); \
359  M2_VS_name << "(" #M2 << ( M2_T == ::Thyra::NOTRANS ? "" : "^T" ) << ")" \
360  << "." << ( M2_VS == ::Thyra::VS_RANGE ? "range()" : "domain()" ); \
361  THYRA_ASSERT_VEC_SPACES_NAMES( \
362  header, \
363  ::Thyra::linear_op_op(M1,M1_T,M1_VS),M1_VS_name.str().c_str() \
364  ::Thyra::linear_op_op(M2,M2_T,M2_VS),M2_VS_name.str().c_str() \
365  ); \
366  }
367 
368 
369 #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.