Thyra Version of the Day
Loading...
Searching...
No Matches
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
53namespace Thyra {
54
55
56/* Utility struct for dumping vector space names, dimension etc.
57 */
58template<class Scalar>
59struct dump_vec_spaces_t {
60public:
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 */
79template<class Scalar>
80inline 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 */
98template<class Scalar>
99std::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 */
118enum EM_VS { VS_RANGE, VS_DOMAIN };
119
120
125template<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)\
189THYRA_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
265namespace Thyra {
266
267
268template<class Scalar>
269void 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
307template<class Scalar>
308void 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
Base class for all linear operators.
virtual RCP< const VectorSpaceBase< Scalar > > range() const =0
Return a smart pointer for the range space for this operator.
virtual RCP< const VectorSpaceBase< Scalar > > domain() const =0
Return a smart pointer for the domain space for this operator.
Abstract interface for objects that represent a space for vectors.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
#define THYRA_ASSERT_VEC_SPACES_NAMES(FUNC_NAME, VS1, VS1_NAME, VS2, VS2_NAME)
Helper assertion macro.
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.
EOpTransp
Enumeration for determining how a linear operator is applied. `*.
EOpTransp real_trans(EOpTransp transp)
Return NOTRANS or TRANS for real scalar valued operators and this also is used for determining struct...
@ TRANS
Use the transposed operator.
@ NOTRANS
Use the non-transposed operator.
basic_OSTab< char > OSTab
std::ostream & operator<<(std::ostream &out, const SerialBandDenseMatrixPrinter< OrdinalType, ScalarType > printer)