Thyra Version of the Day
Loading...
Searching...
No Matches
Thyra_DefaultMultipliedLinearOp_def.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_DEFAULT_MULTIPLIED_LINEAR_OP_DEF_HPP
11#define THYRA_DEFAULT_MULTIPLIED_LINEAR_OP_DEF_HPP
12
13#include "Thyra_DefaultMultipliedLinearOp_decl.hpp"
14#include "Thyra_AssertOp.hpp"
15
16
17namespace Thyra {
18
19
20// Inline members only used in implementation
21
22
23template<class Scalar>
24inline
25void DefaultMultipliedLinearOp<Scalar>::assertInitialized() const
26{
27#ifdef TEUCHOS_DEBUG
28 TEUCHOS_TEST_FOR_EXCEPT( !( numOps() > 0 ) );
29#endif
30}
31
32
33template<class Scalar>
34inline
35std::string DefaultMultipliedLinearOp<Scalar>::getClassName() const
36{
38}
39
40
41template<class Scalar>
42inline
43Ordinal DefaultMultipliedLinearOp<Scalar>::getRangeDim() const
44{
45 return (numOps() > 0 ? this->range()->dim() : 0);
46}
47
48
49template<class Scalar>
50inline
51Ordinal DefaultMultipliedLinearOp<Scalar>::getDomainDim() const
52{
53 return (numOps() > 0 ? this->domain()->dim() : 0);
54}
55
56
57// Constructors/initializers/accessors
58
59
60template<class Scalar>
63
64
65template<class Scalar>
67 const ArrayView<const RCP<LinearOpBase<Scalar> > > &Ops )
68{
69 const int nOps = Ops.size();
70 Ops_.resize(nOps);
71 for( int k = 0; k < nOps; ++k )
72 Ops_[k].initialize(Ops[k]);
73 validateOps();
74 setupDefaultObjectLabel();
75}
76
77
78template<class Scalar>
80 const ArrayView<const RCP<const LinearOpBase<Scalar> > > &Ops )
81{
82 const int nOps = Ops.size();
83 Ops_.resize(nOps);
84 for( int k = 0; k < nOps; ++k )
85 Ops_[k].initialize(Ops[k]);
86 validateOps();
87 setupDefaultObjectLabel();
88}
89
90
91template<class Scalar>
93{
94 Ops_.resize(0);
95 setupDefaultObjectLabel();
96}
97
98
99// Overridden form MultipliedLinearOpBase
100
101
102template<class Scalar>
104{
105 return Ops_.size();
106}
107
108
109template<class Scalar>
111{
112#ifdef TEUCHOS_DEBUG
113 TEUCHOS_TEST_FOR_EXCEPT( !( 0 <= k && k < numOps() ) );
114#endif
115 return Ops_[k].isConst();
116}
117
118
119template<class Scalar>
122{
123#ifdef TEUCHOS_DEBUG
124 TEUCHOS_TEST_FOR_EXCEPT( !( 0 <= k && k < numOps() ) );
125#endif
126 return Ops_[k].getNonconstObj();
127}
128
129
130template<class Scalar>
133{
134#ifdef TEUCHOS_DEBUG
135 TEUCHOS_TEST_FOR_EXCEPT( !( 0 <= k && k < numOps() ) );
136#endif
137 return Ops_[k];
138}
139
140
141// Overridden from LinearOpBase
142
143
144template<class Scalar>
147{
148 if (numOps()) {
149 return getOp(0)->range();
150 }
151 return Teuchos::null;
152}
153
154
155template<class Scalar>
158{
159 if (numOps()) {
160 return getOp(numOps()-1)->domain();
161 }
162 return Teuchos::null;
163}
164
165
166template<class Scalar>
169{
170 return Teuchos::null; // Not supported yet but could be!
171}
172
173
174// Overridden from Teuchos::Describable
175
176
177template<class Scalar>
179{
180 std::ostringstream oss;
181 oss << getClassName() << "{numOps="<<numOps()
182 <<",rangeDim=" << getRangeDim()
183 << ",domainDim="<< getDomainDim() <<"}";
184 return oss.str();
185}
186
187template<class Scalar>
189 Teuchos::FancyOStream &out_arg,
190 const Teuchos::EVerbosityLevel verbLevel
191 ) const
192{
194 using Teuchos::OSTab;
195 RCP<FancyOStream> out = rcp(&out_arg,false);
196 OSTab tab(out);
197 const int nOps = Ops_.size();
198 switch(verbLevel) {
201 *out << this->description() << std::endl;
202 break;
206 {
207 *out << this->description() << std::endl;
208 OSTab tab2(out);
209 *out
210 << "Constituent LinearOpBase objects for M = Op[0]*...*Op[numOps-1]:\n";
211 OSTab tab3(out);
212 for( int k = 0; k < nOps; ++k ) {
213 *out << "Op["<<k<<"] = " << Teuchos::describe(*getOp(k),verbLevel);
214 }
215 break;
216 }
217 default:
218 TEUCHOS_TEST_FOR_EXCEPT(true); // Should never get here!
219 }
220}
221
222
223// protected
224
225
226// Overridden from LinearOpBase
227
228
229template<class Scalar>
231{
232 bool overallOpSupported = true;
233 for( int k = 0; k < static_cast<int>(Ops_.size()); ++k )
234 if(!Thyra::opSupported(*getOp(k),M_trans)) overallOpSupported = false;
235 return overallOpSupported;
236 // ToDo: Cache these?
237}
238
239template<class Scalar>
241 const int nOps = Ops_.size();
242 if ((T_k_.size() != Teuchos::as<size_t>(nOps+1)) || ((nOps > 0) && (T_k_[0]->domain()->dim() != dim))) {
243 // op[0]->range
244 // op[0]->domain == op[1]->range
245 // ...
246 // op[nOps-2]->domain == op[nOps-1]->range
247 // op[nOps-1]->domain
248 T_k_.resize(0);
249 for( int k = 0; k < nOps; ++k ) {
250 T_k_.push_back(createMembers(getOp(k)->range(), dim));
251 }
252 T_k_.push_back(createMembers(getOp(nOps-1)->domain(), dim));
253 }
254}
255
256
257template<class Scalar>
259 const EOpTransp M_trans,
261 const Ptr<MultiVectorBase<Scalar> > &Y,
262 const Scalar alpha,
263 const Scalar beta
264 ) const
265{
266 using Teuchos::rcpFromPtr;
267 using Teuchos::rcpFromRef;
268#ifdef TEUCHOS_DEBUG
270 getClassName()+"::apply(...)", *this, M_trans, X, &*Y
271 );
272#endif // TEUCHOS_DEBUG
273 const int nOps = Ops_.size();
274 const Ordinal m = X.domain()->dim();
275 allocateVecs(m);
276 if( real_trans(M_trans)==NOTRANS ) {
277 //
278 // Y = alpha * M * X + beta*Y
279 // =>
280 // Y = alpha * op(Op[0]) * op(Op[1]) * ... * op(Op[numOps-1]) * X + beta*Y
281 //
282 RCP<MultiVectorBase<Scalar> > T_kp1, T_k; // Temporary propagated between loops
283 for( int k = nOps-1; k >= 0; --k ) {
286 if(k==0) Y_k = rcpFromPtr(Y); else Y_k = T_k = T_k_[k];
287 if(k==nOps-1) X_k = rcpFromRef(X); else X_k = T_kp1;
288 if( k > 0 )
289 Thyra::apply(*getOp(k), M_trans, *X_k, Y_k.ptr());
290 else
291 Thyra::apply(*getOp(k), M_trans, *X_k, Y_k.ptr(), alpha, beta);
292 T_kp1 = T_k;
293 }
294 }
295 else {
296 //
297 // Y = alpha * M' * X + beta*Y
298 // =>
299 // Y = alpha * Op[numOps-1]' * Op[1]' * ... * Op[0]' * X + beta * Y
300 //
301 RCP<MultiVectorBase<Scalar> > T_km1, T_k; // Temporary propagated between loops
302 for( int k = 0; k <= nOps-1; ++k ) {
305 if(k==nOps-1) Y_k = rcpFromPtr(Y); else Y_k = T_k = T_k_[k+1];
306 if(k==0) X_k = rcpFromRef(X); else X_k = T_km1;
307 if( k < nOps-1 )
308 Thyra::apply(*getOp(k), M_trans, *X_k, Y_k.ptr());
309 else
310 Thyra::apply(*getOp(k), M_trans, *X_k, Y_k.ptr(), alpha, beta);
311 T_km1 = T_k;
312 }
313 }
314}
315
316
317// private
318
319
320template<class Scalar>
322{
323 using Teuchos::toString;
324#ifdef TEUCHOS_DEBUG
325 try {
326 const int nOps = Ops_.size();
327 for( int k = 0; k < nOps; ++k ) {
328 TEUCHOS_TEST_FOR_EXCEPT( Ops_[k]().get() == NULL );
329 if( k < nOps-1 ) {
331 getClassName()+"::initialize(...)"
332 ,*Ops_[k],NOTRANS,("Ops["+toString(k)+"]")
333 ,*Ops_[k+1],NOTRANS,("Ops["+toString(k+1)+"]")
334 );
335 }
336 }
337 }
338 catch(...) {
339 uninitialize();
340 throw;
341 }
342#endif
343}
344
345
346template<class Scalar>
347void DefaultMultipliedLinearOp<Scalar>::setupDefaultObjectLabel()
348{
349 std::ostringstream label;
350 const int nOps = Ops_.size();
351 for( int k = 0; k < nOps; ++k ) {
352 std::string Op_k_label = Ops_[k]->getObjectLabel();
353 if (Op_k_label.length() == 0)
354 Op_k_label = "ANYM";
355 if (k > 0)
356 label << "*";
357 label << "("<<Op_k_label<<")";
358 }
359 this->setObjectLabel(label.str());
360 validateOps();
361}
362
363
364} // end namespace Thyra
365
366
367//
368// Nonmember implementations
369//
370
371template<class Scalar>
373Thyra::nonconstMultiply(
374 const RCP<LinearOpBase<Scalar> > &A,
375 const RCP<LinearOpBase<Scalar> > &B,
376 const std::string &M_label
377 )
378{
379 using Teuchos::tuple;
380 RCP<DefaultMultipliedLinearOp<Scalar> > multOp =
381 defaultMultipliedLinearOp<Scalar>(tuple(A, B)());
382 if(M_label.length())
383 multOp->setObjectLabel(M_label);
384 return multOp;
385}
386
387
388template<class Scalar>
390Thyra::multiply(
391 const RCP<const LinearOpBase<Scalar> > &A,
392 const RCP<const LinearOpBase<Scalar> > &B,
393 const std::string &M_label
394 )
395{
396 using Teuchos::tuple;
397 RCP<DefaultMultipliedLinearOp<Scalar> > multOp =
398 defaultMultipliedLinearOp<Scalar>(tuple(A, B)());
399 if(M_label.length())
400 multOp->setObjectLabel(M_label);
401 return multOp;
402}
403
404
405template<class Scalar>
407Thyra::multiply(
408 const RCP<const LinearOpBase<Scalar> > &A,
409 const RCP<const LinearOpBase<Scalar> > &B,
410 const RCP<const LinearOpBase<Scalar> > &C,
411 const std::string &M_label
412 )
413{
414 using Teuchos::tuple;
415 RCP<DefaultMultipliedLinearOp<Scalar> > multOp =
416 defaultMultipliedLinearOp<Scalar>(tuple(A, B, C)());
417 if(M_label.length())
418 multOp->setObjectLabel(M_label);
419 return multOp;
420}
421
422
423//
424// Explicit instantiation macro
425//
426// Must be expanded from within the Thyra namespace!
427//
428
429
430#define THYRA_DEFAULT_MULTIPLIED_LINEAR_OP_INSTANT(SCALAR) \
431 \
432 template class DefaultMultipliedLinearOp<SCALAR >; \
433 \
434 template RCP<LinearOpBase<SCALAR > > \
435 nonconstMultiply( \
436 const RCP<LinearOpBase<SCALAR > > &A, \
437 const RCP<LinearOpBase<SCALAR > > &B, \
438 const std::string &M_label \
439 ); \
440 \
441 template RCP<const LinearOpBase<SCALAR > > \
442 multiply( \
443 const RCP<const LinearOpBase<SCALAR > > &A, \
444 const RCP<const LinearOpBase<SCALAR > > &B, \
445 const std::string &M_label \
446 ); \
447 \
448 template RCP<const LinearOpBase<SCALAR > > \
449 multiply( \
450 const RCP<const LinearOpBase<SCALAR > > &A, \
451 const RCP<const LinearOpBase<SCALAR > > &B, \
452 const RCP<const LinearOpBase<SCALAR > > &C, \
453 const std::string &M_label \
454 ); \
455
456
457#endif // THYRA_DEFAULT_MULTIPLIED_LINEAR_OP_DEF_HPP
virtual std::string description() const
Ptr< T > ptr() const
Concrete composite LinearOpBase subclass that creates an implicitly multiplied linear operator out of...
RCP< const LinearOpBase< Scalar > > getOp(const int k) const
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
Prints the details about the constituent linear operators.
RCP< const VectorSpaceBase< Scalar > > range() const
Returns this->getOp(0).range() if <t>this->numOps() > 0 and returns Teuchos::null otherwise.
void initialize(const ArrayView< const RCP< LinearOpBase< Scalar > > > &Ops)
Initialize given a list of non-const linear operators.
RCP< const VectorSpaceBase< Scalar > > domain() const
Returns this->getOp(this->numOps()-1).domain() if <t>this->numOps() > 0 and returns Teuchos::null oth...
std::string description() const
Prints just the name DefaultMultipliedLinearOp along with the overall dimensions and the number of co...
RCP< const LinearOpBase< Scalar > > clone() const
RCP< LinearOpBase< Scalar > > getNonconstOp(const int k)
bool opSupportedImpl(EOpTransp M_trans) const
Returns true only if all constituent operators support M_trans.
void applyImpl(const EOpTransp M_trans, const MultiVectorBase< Scalar > &X, const Ptr< MultiVectorBase< Scalar > > &Y, const Scalar alpha, const Scalar beta) const
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.
Interface for a collection of column vectors called a multi-vector.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
#define THYRA_ASSERT_LINEAR_OP_TIMES_LINEAR_OP_SPACES_NAMES(FUNC_NAME, M1, M1_T, M1_N, M2, M2_T, M2_N)
Assert that a linear operator multiplication matches up.
#define THYRA_ASSERT_LINEAR_OP_MULTIVEC_APPLY_SPACES(FUNC_NAME, M, M_T, X, Y)
This is a very useful macro that should be used to validate that the spaces for the multi-vector vers...
EOpTransp
Enumeration for determining how a linear operator is applied. `*.
Teuchos::Ordinal Ordinal
Type for the dimension of a vector space. `*.
const char * toString(EConj conj)
Return a string name for a EOpTransp value. `*.
EOpTransp real_trans(EOpTransp transp)
Return NOTRANS or TRANS for real scalar valued operators and this also is used for determining struct...
@ NOTRANS
Use the non-transposed operator.
T_To & dyn_cast(T_From &from)
std::string toString(const T &t)