Thyra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
17 namespace Thyra {
18 
19 
20 // Inline members only used in implementation
21 
22 
23 template<class Scalar>
24 inline
25 void DefaultMultipliedLinearOp<Scalar>::assertInitialized() const
26 {
27 #ifdef TEUCHOS_DEBUG
28  TEUCHOS_TEST_FOR_EXCEPT( !( numOps() > 0 ) );
29 #endif
30 }
31 
32 
33 template<class Scalar>
34 inline
35 std::string DefaultMultipliedLinearOp<Scalar>::getClassName() const
36 {
38 }
39 
40 
41 template<class Scalar>
42 inline
43 Ordinal DefaultMultipliedLinearOp<Scalar>::getRangeDim() const
44 {
45  return (numOps() > 0 ? this->range()->dim() : 0);
46 }
47 
48 
49 template<class Scalar>
50 inline
51 Ordinal DefaultMultipliedLinearOp<Scalar>::getDomainDim() const
52 {
53  return (numOps() > 0 ? this->domain()->dim() : 0);
54 }
55 
56 
57 // Constructors/initializers/accessors
58 
59 
60 template<class Scalar>
62 {}
63 
64 
65 template<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 
78 template<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 
91 template<class Scalar>
93 {
94  Ops_.resize(0);
95  setupDefaultObjectLabel();
96 }
97 
98 
99 // Overridden form MultipliedLinearOpBase
100 
101 
102 template<class Scalar>
104 {
105  return Ops_.size();
106 }
107 
108 
109 template<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 
119 template<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 
130 template<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 
144 template<class Scalar>
147 {
148  if (numOps()) {
149  return getOp(0)->range();
150  }
151  return Teuchos::null;
152 }
153 
154 
155 template<class Scalar>
158 {
159  if (numOps()) {
160  return getOp(numOps()-1)->domain();
161  }
162  return Teuchos::null;
163 }
164 
165 
166 template<class Scalar>
169 {
170  return Teuchos::null; // Not supported yet but could be!
171 }
172 
173 
174 // Overridden from Teuchos::Describable
175 
176 
177 template<class Scalar>
179 {
180  std::ostringstream oss;
181  oss << getClassName() << "{numOps="<<numOps()
182  <<",rangeDim=" << getRangeDim()
183  << ",domainDim="<< getDomainDim() <<"}";
184  return oss.str();
185 }
186 
187 template<class Scalar>
189  Teuchos::FancyOStream &out_arg,
190  const Teuchos::EVerbosityLevel verbLevel
191  ) const
192 {
193  using Teuchos::FancyOStream;
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) {
200  case Teuchos::VERB_LOW:
201  *out << this->description() << std::endl;
202  break;
204  case Teuchos::VERB_HIGH:
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 
229 template<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 
239 
240 template<class Scalar>
242  const EOpTransp M_trans,
243  const MultiVectorBase<Scalar> &X,
244  const Ptr<MultiVectorBase<Scalar> > &Y,
245  const Scalar alpha,
246  const Scalar beta
247  ) const
248 {
249  using Teuchos::rcpFromPtr;
250  using Teuchos::rcpFromRef;
251 #ifdef TEUCHOS_DEBUG
253  getClassName()+"::apply(...)", *this, M_trans, X, &*Y
254  );
255 #endif // TEUCHOS_DEBUG
256  const int nOps = Ops_.size();
257  const Ordinal m = X.domain()->dim();
258  if( real_trans(M_trans)==NOTRANS ) {
259  //
260  // Y = alpha * M * X + beta*Y
261  // =>
262  // Y = alpha * op(Op[0]) * op(Op[1]) * ... * op(Op[numOps-1]) * X + beta*Y
263  //
264  RCP<MultiVectorBase<Scalar> > T_kp1, T_k; // Temporary propagated between loops
265  for( int k = nOps-1; k >= 0; --k ) {
268  if(k==0) Y_k = rcpFromPtr(Y); else Y_k = T_k = createMembers(getOp(k)->range(), m);
269  if(k==nOps-1) X_k = rcpFromRef(X); else X_k = T_kp1;
270  if( k > 0 )
271  Thyra::apply(*getOp(k), M_trans, *X_k, Y_k.ptr());
272  else
273  Thyra::apply(*getOp(k), M_trans, *X_k, Y_k.ptr(), alpha, beta);
274  T_kp1 = T_k;
275  }
276  }
277  else {
278  //
279  // Y = alpha * M' * X + beta*Y
280  // =>
281  // Y = alpha * Op[numOps-1]' * Op[1]' * ... * Op[0]' * X + beta * Y
282  //
283  RCP<MultiVectorBase<Scalar> > T_km1, T_k; // Temporary propagated between loops
284  for( int k = 0; k <= nOps-1; ++k ) {
287  if(k==nOps-1) Y_k = rcpFromPtr(Y); else Y_k = T_k = createMembers(getOp(k)->domain(), m);
288  if(k==0) X_k = rcpFromRef(X); else X_k = T_km1;
289  if( k < nOps-1 )
290  Thyra::apply(*getOp(k), M_trans, *X_k, Y_k.ptr());
291  else
292  Thyra::apply(*getOp(k), M_trans, *X_k, Y_k.ptr(), alpha, beta);
293  T_km1 = T_k;
294  }
295  }
296 }
297 
298 
299 // private
300 
301 
302 template<class Scalar>
304 {
305  using Teuchos::toString;
306 #ifdef TEUCHOS_DEBUG
307  try {
308  const int nOps = Ops_.size();
309  for( int k = 0; k < nOps; ++k ) {
310  TEUCHOS_TEST_FOR_EXCEPT( Ops_[k]().get() == NULL );
311  if( k < nOps-1 ) {
313  getClassName()+"::initialize(...)"
314  ,*Ops_[k],NOTRANS,("Ops["+toString(k)+"]")
315  ,*Ops_[k+1],NOTRANS,("Ops["+toString(k+1)+"]")
316  );
317  }
318  }
319  }
320  catch(...) {
321  uninitialize();
322  throw;
323  }
324 #endif
325 }
326 
327 
328 template<class Scalar>
329 void DefaultMultipliedLinearOp<Scalar>::setupDefaultObjectLabel()
330 {
331  std::ostringstream label;
332  const int nOps = Ops_.size();
333  for( int k = 0; k < nOps; ++k ) {
334  std::string Op_k_label = Ops_[k]->getObjectLabel();
335  if (Op_k_label.length() == 0)
336  Op_k_label = "ANYM";
337  if (k > 0)
338  label << "*";
339  label << "("<<Op_k_label<<")";
340  }
341  this->setObjectLabel(label.str());
342  validateOps();
343 }
344 
345 
346 } // end namespace Thyra
347 
348 
349 //
350 // Nonmember implementations
351 //
352 
353 template<class Scalar>
355 Thyra::nonconstMultiply(
356  const RCP<LinearOpBase<Scalar> > &A,
357  const RCP<LinearOpBase<Scalar> > &B,
358  const std::string &M_label
359  )
360 {
361  using Teuchos::tuple;
362  RCP<DefaultMultipliedLinearOp<Scalar> > multOp =
363  defaultMultipliedLinearOp<Scalar>(tuple(A, B)());
364  if(M_label.length())
365  multOp->setObjectLabel(M_label);
366  return multOp;
367 }
368 
369 
370 template<class Scalar>
372 Thyra::multiply(
373  const RCP<const LinearOpBase<Scalar> > &A,
374  const RCP<const LinearOpBase<Scalar> > &B,
375  const std::string &M_label
376  )
377 {
378  using Teuchos::tuple;
379  RCP<DefaultMultipliedLinearOp<Scalar> > multOp =
380  defaultMultipliedLinearOp<Scalar>(tuple(A, B)());
381  if(M_label.length())
382  multOp->setObjectLabel(M_label);
383  return multOp;
384 }
385 
386 
387 template<class Scalar>
389 Thyra::multiply(
390  const RCP<const LinearOpBase<Scalar> > &A,
391  const RCP<const LinearOpBase<Scalar> > &B,
392  const RCP<const LinearOpBase<Scalar> > &C,
393  const std::string &M_label
394  )
395 {
396  using Teuchos::tuple;
397  RCP<DefaultMultipliedLinearOp<Scalar> > multOp =
398  defaultMultipliedLinearOp<Scalar>(tuple(A, B, C)());
399  if(M_label.length())
400  multOp->setObjectLabel(M_label);
401  return multOp;
402 }
403 
404 
405 //
406 // Explicit instantiation macro
407 //
408 // Must be expanded from within the Thyra namespace!
409 //
410 
411 
412 #define THYRA_DEFAULT_MULTIPLIED_LINEAR_OP_INSTANT(SCALAR) \
413  \
414  template class DefaultMultipliedLinearOp<SCALAR >; \
415  \
416  template RCP<LinearOpBase<SCALAR > > \
417  nonconstMultiply( \
418  const RCP<LinearOpBase<SCALAR > > &A, \
419  const RCP<LinearOpBase<SCALAR > > &B, \
420  const std::string &M_label \
421  ); \
422  \
423  template RCP<const LinearOpBase<SCALAR > > \
424  multiply( \
425  const RCP<const LinearOpBase<SCALAR > > &A, \
426  const RCP<const LinearOpBase<SCALAR > > &B, \
427  const std::string &M_label \
428  ); \
429  \
430  template RCP<const LinearOpBase<SCALAR > > \
431  multiply( \
432  const RCP<const LinearOpBase<SCALAR > > &A, \
433  const RCP<const LinearOpBase<SCALAR > > &B, \
434  const RCP<const LinearOpBase<SCALAR > > &C, \
435  const std::string &M_label \
436  ); \
437 
438 
439 #endif // THYRA_DEFAULT_MULTIPLIED_LINEAR_OP_DEF_HPP
void initialize(int *argc, char ***argv)
#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.
EOpTransp
Enumeration for determining how a linear operator is applied. `*.
RCP< const VectorSpaceBase< Scalar > > domain() const
Returns this-&gt;getOp(this-&gt;numOps()-1).domain() if &lt;t&gt;this-&gt;numOps() &gt; 0 and returns Teuchos::null oth...
basic_OSTab< char > OSTab
#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...
DefaultMultipliedLinearOp()
Constructs to uninitialized.
basic_FancyOStream< char > FancyOStream
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...
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel) const
Prints the details about the constituent linear operators.
void initialize(const ArrayView< const RCP< LinearOpBase< Scalar > > > &Ops)
Initialize given a list of non-const linear operators.
bool opSupportedImpl(EOpTransp M_trans) const
Returns true only if all constituent operators support M_trans.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Teuchos::Ordinal Ordinal
Type for the dimension of a vector space. `*.
Interface for a collection of column vectors called a multi-vector.
RCP< const LinearOpBase< Scalar > > clone() const
RCP< LinearOpBase< Scalar > > getNonconstOp(const int k)
Ptr< T > ptr() const
Concrete composite LinearOpBase subclass that creates an implicitly multiplied linear operator out of...
virtual std::string description() const
TEUCHOSCORE_LIB_DLL_EXPORT std::string toString(const EVerbosityLevel verbLevel)
Base class for all linear operators.
std::string description() const
Prints just the name DefaultMultipliedLinearOp along with the overall dimensions and the number of co...
virtual RCP< const VectorSpaceBase< Scalar > > domain() const =0
Return a smart pointer for the domain space for this operator.
void applyImpl(const EOpTransp M_trans, const MultiVectorBase< Scalar > &X, const Ptr< MultiVectorBase< Scalar > > &Y, const Scalar alpha, const Scalar beta) const
RCP< const LinearOpBase< Scalar > > getOp(const int k) const
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
RCP< const VectorSpaceBase< Scalar > > range() const
Returns this-&gt;getOp(0).range() if &lt;t&gt;this-&gt;numOps() &gt; 0 and returns Teuchos::null otherwise...
std::string toString(const T &t)