Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Stokhos_CompletePolynomialBasisImp.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Stokhos Package
4 //
5 // Copyright 2009 NTESS and the Stokhos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #include "Teuchos_TimeMonitor.hpp"
11 
12 template <typename ordinal_type, typename value_type>
16  const value_type& sparse_tol_,
17  bool use_old_cijk_alg_,
18  const Teuchos::RCP< Teuchos::Array<value_type> >& deriv_coeffs_) :
19  p(0),
20  d(bases_.size()),
21  sz(0),
22  bases(bases_),
23  basis_orders(d),
24  sparse_tol(sparse_tol_),
25  use_old_cijk_alg(use_old_cijk_alg_),
26  deriv_coeffs(deriv_coeffs_),
27  norms(),
28  terms()
29 {
30 
31  // Compute total order
32  for (ordinal_type i=0; i<d; i++) {
33  basis_orders[i] = bases[i]->order();
34  if (basis_orders[i] > p)
35  p = basis_orders[i];
36  }
37 
38  // Compute basis terms
40 
41  // Compute norms
42  norms.resize(sz);
43  value_type nrm;
44  for (ordinal_type k=0; k<sz; k++) {
45  nrm = value_type(1.0);
46  for (ordinal_type i=0; i<d; i++)
47  nrm = nrm * bases[i]->norm_squared(terms[k][i]);
48  norms[k] = nrm;
49  }
50 
51  // Create name
52  name = "Complete polynomial basis (";
53  for (ordinal_type i=0; i<d-1; i++)
54  name += bases[i]->getName() + ", ";
55  name += bases[d-1]->getName() + ")";
56 
57  // Allocate array for basis evaluation
58  basis_eval_tmp.resize(d);
59  for (ordinal_type j=0; j<d; j++)
60  basis_eval_tmp[j].resize(basis_orders[j]+1);
61 
62  // Set up deriv_coeffs
63  if (deriv_coeffs == Teuchos::null) {
65  for (ordinal_type j=0; j<d; j++)
66  (*deriv_coeffs)[j] = value_type(1.0);
67  }
68 }
69 
70 template <typename ordinal_type, typename value_type>
73 {
74 }
75 
76 template <typename ordinal_type, typename value_type>
79 order() const
80 {
81  return p;
82 }
83 
84 template <typename ordinal_type, typename value_type>
87 dimension() const
88 {
89  return d;
90 }
91 
92 template <typename ordinal_type, typename value_type>
95 size() const
96 {
97  return sz;
98 }
99 
100 template <typename ordinal_type, typename value_type>
104 {
105  return norms;
106 }
107 
108 template <typename ordinal_type, typename value_type>
109 const value_type&
112 {
113  return norms[i];
114 }
115 
116 template <typename ordinal_type, typename value_type>
120 {
121 #ifdef STOKHOS_TEUCHOS_TIME_MONITOR
122  TEUCHOS_FUNC_TIME_MONITOR("Stokhos: Total Triple-Product Tensor Fill Time");
123 #endif
124  if (use_old_cijk_alg)
125  return computeTripleProductTensorOld(sz);
126  else
127  return computeTripleProductTensorNew(sz);
128 }
129 
130 template <typename ordinal_type, typename value_type>
134 {
135 #ifdef STOKHOS_TEUCHOS_TIME_MONITOR
136  TEUCHOS_FUNC_TIME_MONITOR("Stokhos: Total Triple-Product Tensor Fill Time");
137 #endif
138  if (use_old_cijk_alg)
139  return computeTripleProductTensorOld(d+1);
140  else
141  return computeTripleProductTensorNew(d+1);
142 }
143 
144 template <typename ordinal_type, typename value_type>
148 {
149  // Compute Cijk = < \Psi_i \Psi_j \Psi_k >
152 
153  // Create 1-D triple products
155  for (ordinal_type i=0; i<d; i++)
156  Cijk_1d[i] = bases[i]->computeTripleProductTensor();
157 
158  for (ordinal_type j=0; j<sz; j++) {
159  for (ordinal_type i=0; i<sz; i++) {
160  for (ordinal_type k=0; k<order; k++) {
161  value_type c = value_type(1.0);
162  for (ordinal_type l=0; l<d; l++)
163  c *= (*Cijk_1d[l])(terms[i][l],terms[j][l],terms[k][l]);
164  if (std::abs(c/norms[i]) > sparse_tol)
165  Cijk->add_term(i,j,k,c);
166  }
167  }
168  }
169 
170  Cijk->fillComplete();
171 
172  return Cijk;
173 }
174 
175 template <typename ordinal_type, typename value_type>
179 {
180  // The algorithm for computing Cijk = < \Psi_i \Psi_j \Psi_k > here works
181  // by factoring
182  // < \Psi_i \Psi_j \Psi_k > =
183  // < \psi^1_{i_1}\psi^1_{j_1}\psi^1_{k_1} >_1 x ... x
184  // < \psi^d_{i_d}\psi^d_{j_d}\psi^d_{k_d} >_d
185  // We compute the sparse triple product < \psi^l_i\psi^l_j\psi^l_k >_l
186  // for each dimension l, and then compute all non-zero products of these
187  // terms. The complexity arises from iterating through all possible
188  // combinations, throwing out terms that aren't in the basis and are beyond
189  // the k-order limit provided
192 
193  // Map the specified order limit to a limit on each dimension
194  // Subtract 1 to get the term for the last order we want to include,
195  // add up the orders for each term to get the total order, then add 1
196  MultiIndex<ordinal_type> term = this->term(order-1);
197  ordinal_type k_lim = 0;
198  for (ordinal_type i=0; i<d; i++)
199  k_lim = k_lim + term[i];
200  k_lim++;
201 
202  // Create 1-D triple products
204  for (ordinal_type i=0; i<d; i++) {
205  if (k_lim <= basis_orders[i]+1)
206  Cijk_1d[i] = bases[i]->computeSparseTripleProductTensor(k_lim);
207  else
208  Cijk_1d[i] = bases[i]->computeSparseTripleProductTensor(basis_orders[i]+1);
209  }
210 
211  // Create i, j, k iterators for each dimension
212  // Note: we have to supply an initializer in the arrays of iterators to
213  // avoid checked-stl errors about singular iterators
215  typedef typename Cijk_type::k_iterator k_iterator;
216  typedef typename Cijk_type::kj_iterator kj_iterator;
217  typedef typename Cijk_type::kji_iterator kji_iterator;
218  Teuchos::Array<k_iterator> k_iterators(d, Cijk_1d[0]->k_begin());
219  Teuchos::Array<kj_iterator > j_iterators(d, Cijk_1d[0]->j_begin(k_iterators[0]));
220  Teuchos::Array<kji_iterator > i_iterators(d, Cijk_1d[0]->i_begin(j_iterators[0]));
221  MultiIndex<ordinal_type> terms_i(d), terms_j(d), terms_k(d);
222  ordinal_type sum_i = 0;
223  ordinal_type sum_j = 0;
224  ordinal_type sum_k = 0;
225  for (ordinal_type dim=0; dim<d; dim++) {
226  k_iterators[dim] = Cijk_1d[dim]->k_begin();
227  j_iterators[dim] = Cijk_1d[dim]->j_begin(k_iterators[dim]);
228  i_iterators[dim] = Cijk_1d[dim]->i_begin(j_iterators[dim]);
229  terms_i[dim] = Stokhos::index(i_iterators[dim]);
230  terms_j[dim] = Stokhos::index(j_iterators[dim]);
231  terms_k[dim] = Stokhos::index(k_iterators[dim]);
232  sum_i += terms_i[dim];
233  sum_j += terms_j[dim];
234  sum_k += terms_k[dim];
235  }
236 
237  ordinal_type I = 0;
238  ordinal_type J = 0;
239  ordinal_type K = 0;
240  bool inc_i = true;
241  bool inc_j = true;
242  bool inc_k = true;
243  bool stop = false;
244  ordinal_type cnt = 0;
245  while (!stop) {
246 
247  // Add term if it is in the basis
248  if (sum_i <= p && sum_j <= p && sum_k <= p) {
249  if (inc_k)
250  K = CPBUtils::compute_index(terms_k, terms, num_terms, p);
251  if (K < order) {
252  if (inc_i)
253  I = CPBUtils::compute_index(terms_i, terms, num_terms, p);
254  if (inc_j)
255  J = CPBUtils::compute_index(terms_j, terms, num_terms, p);
256  value_type c = value_type(1.0);
257  for (ordinal_type dim=0; dim<d; dim++)
258  c *= value(i_iterators[dim]);
259  if (std::abs(c/norms[I]) > sparse_tol)
260  Cijk->add_term(I,J,K,c);
261  }
262  }
263 
264  // Increment iterators to the next valid term
265  ordinal_type cdim = 0;
266  bool inc = true;
267  inc_i = false;
268  inc_j = false;
269  inc_k = false;
270  while (inc && cdim < d) {
271  ordinal_type cur_dim = cdim;
272  ++i_iterators[cdim];
273  inc_i = true;
274  if (i_iterators[cdim] != Cijk_1d[cdim]->i_end(j_iterators[cdim])) {
275  terms_i[cdim] = Stokhos::index(i_iterators[cdim]);
276  sum_i = 0;
277  for (int dim=0; dim<d; dim++)
278  sum_i += terms_i[dim];
279  }
280  if (i_iterators[cdim] == Cijk_1d[cdim]->i_end(j_iterators[cdim]) ||
281  sum_i > p) {
282  ++j_iterators[cdim];
283  inc_j = true;
284  if (j_iterators[cdim] != Cijk_1d[cdim]->j_end(k_iterators[cdim])) {
285  terms_j[cdim] = Stokhos::index(j_iterators[cdim]);
286  sum_j = 0;
287  for (int dim=0; dim<d; dim++)
288  sum_j += terms_j[dim];
289  }
290  if (j_iterators[cdim] == Cijk_1d[cdim]->j_end(k_iterators[cdim]) ||
291  sum_j > p) {
292  ++k_iterators[cdim];
293  inc_k = true;
294  if (k_iterators[cdim] != Cijk_1d[cdim]->k_end()) {
295  terms_k[cdim] = Stokhos::index(k_iterators[cdim]);
296  sum_k = 0;
297  for (int dim=0; dim<d; dim++)
298  sum_k += terms_k[dim];
299  }
300  if (k_iterators[cdim] == Cijk_1d[cdim]->k_end() || sum_k > p) {
301  k_iterators[cdim] = Cijk_1d[cdim]->k_begin();
302  ++cdim;
303  terms_k[cur_dim] = Stokhos::index(k_iterators[cur_dim]);
304  sum_k = 0;
305  for (int dim=0; dim<d; dim++)
306  sum_k += terms_k[dim];
307  }
308  else
309  inc = false;
310  j_iterators[cur_dim] =
311  Cijk_1d[cur_dim]->j_begin(k_iterators[cur_dim]);
312  terms_j[cur_dim] = Stokhos::index(j_iterators[cur_dim]);
313  sum_j = 0;
314  for (int dim=0; dim<d; dim++)
315  sum_j += terms_j[dim];
316  }
317  else
318  inc = false;
319  i_iterators[cur_dim] = Cijk_1d[cur_dim]->i_begin(j_iterators[cur_dim]);
320  terms_i[cur_dim] = Stokhos::index(i_iterators[cur_dim]);
321  sum_i = 0;
322  for (int dim=0; dim<d; dim++)
323  sum_i += terms_i[dim];
324  }
325  else
326  inc = false;
327 
328  if (sum_i > p || sum_j > p || sum_k > p)
329  inc = true;
330  }
331 
332  if (cdim == d)
333  stop = true;
334 
335  cnt++;
336  }
337 
338  Cijk->fillComplete();
339 
340  return Cijk;
341 }
342 
343 template <typename ordinal_type, typename value_type>
349 {
350  // Compute Dijk = < \Psi_i \Psi_j \Psi_k' >
353  for (ordinal_type i=0; i<sz; i++)
354  for (ordinal_type j=0; j<sz; j++)
355  for (ordinal_type k=0; k<sz; k++)
356  (*Dijk)(i,j,k) = value_type(0.0);
357 
358  ordinal_type i,j,m;
359  value_type c;
360  for (ordinal_type k=0; k<sz; k++) {
361  for (typename Cijk_type::k_iterator m_it=Cijk->k_begin();
362  m_it!=Cijk->k_end(); ++m_it) {
363  m = Stokhos::index(m_it);
364  for (typename Cijk_type::kj_iterator j_it = Cijk->j_begin(m_it);
365  j_it != Cijk->j_end(m_it); ++j_it) {
366  j = Stokhos::index(j_it);
367  for (typename Cijk_type::kji_iterator i_it = Cijk->i_begin(j_it);
368  i_it != Cijk->i_end(j_it); ++i_it) {
369  i = Stokhos::index(i_it);
370  c = Stokhos::value(i_it);
371  (*Dijk)(i,j,k) += (*Bij)(m,k)*c/norms[m];
372  }
373  }
374  }
375  }
376 
377  return Dijk;
378 }
379 
380 template <typename ordinal_type, typename value_type>
384 {
385  // Compute Bij = < \Psi_i \Psi_j' >
388  sz));
389 
390  // Create products
392  for (ordinal_type i=0; i<d; i++)
393  Bij_1d[i] = bases[i]->computeDerivDoubleProductTensor();
394 
395  for (ordinal_type i=0; i<sz; i++) {
396  for (ordinal_type k=0; k<sz; k++) {
397  value_type t = value_type(1.0);
398  value_type c = value_type(0.0);
399  for (ordinal_type j=0; j<d; j++) {
400  bool is_zero = false;
401  for (ordinal_type l=0; l<d; l++) {
402  if (l != j && terms[i][l] != terms[k][l])
403  is_zero = true;
404  if (l != j)
405  t *= bases[l]->norm_squared(terms[k][l]);
406  }
407  if (!is_zero)
408  c += t*(*deriv_coeffs)[j]*(*Bij_1d[j])(terms[k][j],terms[i][j]);
409  }
410  (*Bij)(i,k) = c;
411  }
412  }
413 
414  return Bij;
415 }
416 
417 template <typename ordinal_type, typename value_type>
421 {
422  // z = psi_{i_1}(0) * ... * psi_{i_d}(0) where i_1,...,i_d are the basis
423  // terms for coefficient i
424  value_type z = value_type(1.0);
425  for (ordinal_type j=0; j<d; j++)
426  z = z * bases[j]->evaluate(value_type(0.0), terms[i][j]);
427 
428  return z;
429 }
430 
431 template <typename ordinal_type, typename value_type>
432 void
435  Teuchos::Array<value_type>& basis_vals) const
436 {
437  for (ordinal_type j=0; j<d; j++)
438  bases[j]->evaluateBases(point[j], basis_eval_tmp[j]);
439 
440  // Only evaluate basis upto number of terms included in basis_pts
441  for (ordinal_type i=0; i<sz; i++) {
442  value_type t = value_type(1.0);
443  for (ordinal_type j=0; j<d; j++)
444  t *= basis_eval_tmp[j][terms[i][j]];
445  basis_vals[i] = t;
446  }
447 }
448 
449 template <typename ordinal_type, typename value_type>
450 void
452 print(std::ostream& os) const
453 {
454  os << "Complete basis of order " << p << ", dimension " << d
455  << ", and size " << sz << ". Component bases:\n";
456  for (ordinal_type i=0; i<d; i++)
457  os << *bases[i];
458  os << "Basis vector norms (squared):\n\t";
459  for (ordinal_type i=0; i<static_cast<ordinal_type>(norms.size()); i++)
460  os << norms[i] << " ";
461  os << "\n";
462 }
463 
464 template <typename ordinal_type, typename value_type>
468 {
469  return terms[i];
470 }
471 
472 template <typename ordinal_type, typename value_type>
476 {
477  return CPBUtils::compute_index(term, terms, num_terms, p);
478 }
479 
480 template <typename ordinal_type, typename value_type>
481 const std::string&
483 getName() const
484 {
485  return name;
486 }
487 
488 template <typename ordinal_type, typename value_type>
492 {
493  return bases;
494 }
495 
496 template <typename ordinal_type, typename value_type>
500 {
501  MultiIndex<ordinal_type> max_orders(d);
502  for (ordinal_type i=0; i<d; ++i)
503  max_orders[i] = basis_orders[i];
504  return max_orders;
505 }
ordinal_type dimension() const
Return dimension of basis.
#define TEUCHOS_FUNC_TIME_MONITOR(FUNCNAME)
ordinal_type order() const
Return order of basis.
virtual Teuchos::RCP< Teuchos::SerialDenseMatrix< ordinal_type, value_type > > computeDerivDoubleProductTensor() const
Compute double product tensor where represents the derivative of in the direction ...
virtual value_type evaluateZero(ordinal_type i) const
Evaluate basis polynomial i at zero.
virtual void evaluateBases(const Teuchos::ArrayView< const value_type > &point, Teuchos::Array< value_type > &basis_vals) const
Evaluate basis polynomials at given point point.
CompletePolynomialBasis(const Teuchos::Array< Teuchos::RCP< const OneDOrthogPolyBasis< ordinal_type, value_type > > > &bases, const value_type &sparse_tol=1.0e-12, bool use_old_cijk_alg=false, const Teuchos::RCP< Teuchos::Array< value_type > > &deriv_coeffs=Teuchos::null)
Constructor.
virtual Teuchos::RCP< Stokhos::Sparse3Tensor< ordinal_type, value_type > > computeLinearTripleProductTensor() const
Compute linear triple product tensor where k = 0,1,..,d.
Data structure storing a sparse 3-tensor C(i,j,k) in a a compressed format.
Teuchos::Array< ordinal_type > basis_orders
Array storing order of each basis.
ordinal_type d
Total dimension of basis.
Teuchos::Array< Teuchos::RCP< const OneDOrthogPolyBasis< ordinal_type, value_type > > > getCoordinateBases() const
Return coordinate bases.
Teuchos::Array< Teuchos::RCP< const OneDOrthogPolyBasis< ordinal_type, value_type > > > bases
Array of bases.
Teuchos::Array< MultiIndex< ordinal_type > > terms
2-D array of basis terms
virtual Teuchos::RCP< Stokhos::Sparse3Tensor< ordinal_type, value_type > > computeTripleProductTensorNew(ordinal_type order) const
Compute triple product tensor using new algorithm.
Bi-directional iterator for traversing a sparse array.
Teuchos::Array< value_type > norms
Norms.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual Teuchos::RCP< Stokhos::Dense3Tensor< ordinal_type, value_type > > computeDerivTripleProductTensor(const Teuchos::RCP< const Teuchos::SerialDenseMatrix< ordinal_type, value_type > > &Bij, const Teuchos::RCP< const Stokhos::Sparse3Tensor< ordinal_type, value_type > > &Cijk) const
Compute triple product tensor where represents the derivative of in the direction ...
virtual const std::string & getName() const
Return string name of basis.
virtual Teuchos::RCP< Stokhos::Sparse3Tensor< ordinal_type, value_type > > computeTripleProductTensorOld(ordinal_type order) const
Compute triple product tensor using old algorithm.
virtual MultiIndex< ordinal_type > getMaxOrders() const
Return maximum order allowable for each coordinate basis.
virtual Teuchos::RCP< Stokhos::Sparse3Tensor< ordinal_type, value_type > > computeTripleProductTensor() const
Compute triple product tensor.
virtual void print(std::ostream &os) const
Print basis to stream os.
KOKKOS_INLINE_FUNCTION PCE< Storage > abs(const PCE< Storage > &a)
void resize(size_type new_size, const value_type &x=value_type())
virtual ordinal_type index(const MultiIndex< ordinal_type > &term) const
Get index of the multivariate polynomial given orders of each coordinate.
Stokhos::Sparse3Tensor< int, double > Cijk_type
Abstract base class for 1-D orthogonal polynomials.
virtual ordinal_type size() const
Return total size of basis.
Data structure storing a dense 3-tensor C(i,j,k).
virtual const MultiIndex< ordinal_type > & term(ordinal_type i) const
Get orders of each coordinate polynomial given an index i.
Teuchos::RCP< Teuchos::Array< value_type > > deriv_coeffs
Coefficients for derivative.
Teuchos::Array< ordinal_type > num_terms
Number of terms up to each order.
virtual const Teuchos::Array< value_type > & norm_squared() const
Return array storing norm-squared of each basis polynomial.
Teuchos::Array< Teuchos::Array< value_type > > basis_eval_tmp
Temporary array used in basis evaluation.
static ordinal_type compute_terms(ordinal_type p, ordinal_type d, ordinal_type &sz, Teuchos::Array< MultiIndex< ordinal_type > > &terms, Teuchos::Array< ordinal_type > &num_terms)
Compute the 2-D array of basis terms which maps a basis index into the orders for each basis dimensio...