Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Stokhos_LexicographicTreeBasisUnitTest.cpp
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 
14 
15 #include "Stokhos.hpp"
18 
19 namespace TotalOrderBasisUnitTest {
20 
21  // Common setup for unit tests
22  template <typename OrdinalType, typename ValueType>
23  struct UnitTestSetup {
24  ValueType rtol, atol, sparse_tol;
25  OrdinalType p,d;
26 
28  rtol = 1e-12;
29  atol = 1e-12;
30  sparse_tol = 1e-12;
31  d = 3;
32  p = 5;
33  }
34 
35  };
36 
37  typedef int ordinal_type;
38  typedef double value_type;
40 
41  template <typename ordinal_type>
43  const Teuchos::Array<ordinal_type>& basis_orders,
44  const ordinal_type p,
45  const bool isotropic,
46  Teuchos::FancyOStream& out) {
47  bool success = true;
48 
49  // Build total order basis of dimension d
50  ordinal_type d = basis_orders.size();
52  for (ordinal_type i=0; i<d; i++)
53  bases[i] = Teuchos::rcp(new Stokhos::LegendreBasis<ordinal_type,value_type>(basis_orders[i], true));
57 
58  // Build tree basis
61  Stokhos::build_lexicographic_basis_tree(basis_orders(), p);
62 
63  // Check head block size is equal to the whole basis size
64  TEUCHOS_TEST_EQUALITY(head->block_size, basis->size(), out, success);
65 
66  // Check tree is consistent
69  node_stack.push_back(head);
70  index_stack.push_back(0);
72  ordinal_type child_index;
73  ordinal_type block_size_expected;
74  while (node_stack.size() > 0) {
75  node = node_stack.back();
76  child_index = index_stack.back();
77 
78  // Check block size is the sum of each child's block size
79  // or the number of terms for leaves
80  if (node->children.size() > 0) {
81  block_size_expected = 0;
82  for (ordinal_type i=0; i<node->children.size(); ++i)
83  block_size_expected += node->children[i]->block_size;
84  }
85  else {
86  block_size_expected = node->terms.size();
87  }
88  TEUCHOS_TEST_EQUALITY(node->block_size, block_size_expected,
89  out, success);
90 
91  // Check block size based on formula (only for isotropic)
92  if (isotropic) {
93  ordinal_type sum_prev = 0;
94  Stokhos::MultiIndex<ordinal_type> term_prefix = node->terms[0];
95  for (ordinal_type i=0; i<term_prefix.dimension()-1; ++i)
96  sum_prev += term_prefix[i];
97  ordinal_type d_prev = term_prefix.dimension()-1;
98  ordinal_type my_p = std::min(p-sum_prev,basis_orders[d_prev]);
99  ordinal_type d_left = d - d_prev;
100  ordinal_type block_size_expected2 =
101  Stokhos::n_choose_k(my_p+d_left,d_left);
102  TEUCHOS_TEST_EQUALITY(node->block_size, block_size_expected2,
103  out, success);
104  }
105 
106  if (child_index < node->terms.size() && node->children.size() > 0)
107  out << node->terms[child_index] << " : block_size = "
108  << node->children[child_index]->block_size << std::endl;
109 
110  // Leaf -- check global indices
111  if (node->children.size() == 0) {
112  TEUCHOS_TEST_EQUALITY(node->block_size, node->terms.size(),
113  out, success);
114  for (ordinal_type i=0; i<node->terms.size(); ++i) {
115  Stokhos::MultiIndex<ordinal_type> term = node->terms[i];
116  ordinal_type index = node->index_begin + i;
117  ordinal_type index_expected = basis->index(term);
118 
119  out << term << " : index = " << index
120  << " index expected = " << index_expected << std::endl;
121  TEUCHOS_TEST_EQUALITY(index, index_expected, out, success);
122  }
123  node_stack.pop_back();
124  index_stack.pop_back();
125  }
126 
127  // More children to process -- process them first
128  else if (child_index < node->children.size()) {
129  ++index_stack.back();
130  node = node->children[child_index];
131  node_stack.push_back(node);
132  index_stack.push_back(0);
133  }
134 
135  // No more children
136  else {
137  node_stack.pop_back();
138  index_stack.pop_back();
139  }
140 
141  }
142  return success;
143  }
144 
145  template <typename ordinal_type, typename value_type>
147  const Teuchos::Array<ordinal_type>& basis_orders,
148  const ordinal_type p,
149  const bool symmetric,
150  const value_type sparse_tol,
151  const value_type atol,
152  const value_type rtol,
153  Teuchos::FancyOStream& out) {
154 
155  bool success = true;
156  ordinal_type d = basis_orders.size();
157 
158  // Build tensor product basis
160  if (symmetric)
161  for (ordinal_type i=0; i<d; i++)
162  bases[i] = Teuchos::rcp(new Stokhos::LegendreBasis<ordinal_type,value_type>(basis_orders[i], true));
163  else
164  for (ordinal_type i=0; i<d; i++)
165  bases[i] = Teuchos::rcp(new Stokhos::JacobiBasis<ordinal_type,value_type>(basis_orders[i], 1.0, 2.0, true));
169  Teuchos::rcp(new basis_type(bases, sparse_tol));
170 
171  // Build "standard" Cijk
174 
175  // Build LTB Cijk
177  Teuchos::RCP<Cijk_LTB_type> Cijk_LTB =
178  computeTripleProductTensorLTB(*basis, symmetric);
179 
180  // Check sizes
181  TEUCHOS_TEST_EQUALITY(Cijk->num_entries(), Cijk_LTB->num_entries(),
182  out, success);
183 
184  // Check non-zero structure
185  typedef typename Cijk_LTB_type::CijkNode node_type;
187 
189  Teuchos::Array< ordinal_type > index_stack;
190  node_stack.push_back(Cijk_LTB->getHeadNode());
191  index_stack.push_back(0);
193  ordinal_type child_index;
194  while (node_stack.size() > 0) {
195  node = node_stack.back();
196  child_index = index_stack.back();
197 
198  // Leaf -- check Cijk indices and values
199  if (node->is_leaf) {
200  TEUCHOS_TEST_EQUALITY(node->my_num_entries, node->values.size(),
201  out, success);
202  Cijk_Iterator cijk_iterator(node->p_i, node->p_j, node->p_k, symmetric);
203  ordinal_type idx = 0;
204  bool more = true;
205  while (more) {
206  value_type cijk = node->values[idx];
207  ordinal_type I = node->i_begin + cijk_iterator.i;
208  ordinal_type J = node->j_begin + cijk_iterator.j;
209  ordinal_type K = node->k_begin + cijk_iterator.k;
210  value_type cijk2 = Cijk->getValue(I,J,K);
211 
212  value_type tol = atol + std::abs(cijk2)*rtol;
213  value_type err = std::abs(cijk-cijk2);
214  bool s = err < tol;
215  if (!s) {
216  out << std::endl
217  << "Check: rel_err( C(" << I << "," << J << "," << K << ") )"
218  << " = " << "rel_err( " << cijk << ", " << cijk2 << " ) = "
219  << err << " <= " << tol << " : ";
220  if (s) out << "Passed.";
221  else
222  out << "Failed!";
223  out << std::endl;
224  }
225  success = success && s;
226  more = cijk_iterator.increment();
227  ++idx;
228  }
229  TEUCHOS_TEST_EQUALITY(node->my_num_entries, idx, out, success);
230  node_stack.pop_back();
231  index_stack.pop_back();
232  }
233 
234  // More children to process -- process them first
235  else if (child_index < node->children.size()) {
236  ++index_stack.back();
237  node = node->children[child_index];
238  node_stack.push_back(node);
239  index_stack.push_back(0);
240  }
241 
242  // No more children
243  else {
244  node_stack.pop_back();
245  index_stack.pop_back();
246  }
247 
248  }
249 
250  return success;
251  }
252 
253  template <typename ordinal_type, typename value_type>
255  const Teuchos::Array<ordinal_type>& basis_orders,
256  const ordinal_type p,
257  const bool symmetric,
258  const value_type sparse_tol,
259  const value_type atol,
260  const value_type rtol,
261  Teuchos::FancyOStream& out) {
262 
263  bool success = true;
264  ordinal_type d = basis_orders.size();
265 
266  // Build tensor product basis
268  if (symmetric)
269  for (ordinal_type i=0; i<d; i++)
270  bases[i] = Teuchos::rcp(new Stokhos::LegendreBasis<ordinal_type,value_type>(basis_orders[i], true));
271  else
272  for (ordinal_type i=0; i<d; i++)
273  bases[i] = Teuchos::rcp(new Stokhos::JacobiBasis<ordinal_type,value_type>(basis_orders[i], 1.0, 2.0, true));
277  Teuchos::rcp(new basis_type(bases, sparse_tol));
278 
279  // Build "standard" Cijk
282 
283  // Build LTB Cijk
285  Teuchos::RCP<Cijk_LTB_type> Cijk_LTB =
286  computeTripleProductTensorLTBBlockLeaf(*basis, symmetric);
287 
288  // Check non-zero structure
289  typedef typename Cijk_LTB_type::CijkNode node_type;
290 
292  Teuchos::Array< ordinal_type > index_stack;
293  node_stack.push_back(Cijk_LTB->getHeadNode());
294  index_stack.push_back(0);
296  ordinal_type child_index;
297  while (node_stack.size() > 0) {
298  node = node_stack.back();
299  child_index = index_stack.back();
300 
301  // Leaf -- check Cijk indices and values
302  if (node->is_leaf) {
303  TEUCHOS_TEST_EQUALITY(node->my_num_entries, node->values.size(),
304  out, success);
305  ordinal_type idx = 0;
306  for (ordinal_type i=0; i<=node->p_i; ++i) {
307  for (ordinal_type j=0; j<=node->p_j; ++j) {
308  // ordinal_type k0 = node->parent_j_equals_k ?
309  // std::max(j,std::abs(i-j)) : std::abs(i-j);
310  // if (symmetric && (k0%2 != (i+j)%2)) ++k0;
311  // const ordinal_type k_end = std::min(node->p_k,i+j);
312  // const ordinal_type k_inc = symmetric ? 2 : 1;
313 
314  ordinal_type k0 = node->parent_j_equals_k ? j : 0;
315  if (symmetric && (k0%2 != (i+j)%2)) ++k0;
316  const ordinal_type k_end = node->p_k;
317  const ordinal_type k_inc = symmetric ? 2 : 1;
318  for (ordinal_type k=k0; k<=k_end; k+=k_inc) {
319  value_type cijk = node->values[idx++];
320  ordinal_type I = node->i_begin + i;
321  ordinal_type J = node->j_begin + j;
322  ordinal_type K = node->k_begin + k;
323  if (J == K) cijk *= 2.0;
324  value_type cijk2 = Cijk->getValue(I,J,K);
325 
326  value_type tol = atol + std::abs(cijk2)*rtol;
327  value_type err = std::abs(cijk-cijk2);
328  bool s = err < tol;
329  if (!s) {
330  out << std::endl
331  << "Check: rel_err( C(" << I << "," << J << ","
332  << K << ") )"
333  << " = " << "rel_err( " << cijk << ", " << cijk2 << " ) = "
334  << err << " <= " << tol << " : ";
335  if (s) out << "Passed.";
336  else
337  out << "Failed!";
338  out << std::endl;
339  }
340  success = success && s;
341 
342  value_type cijk3 = Cijk->getValue(I,K,J);
343  value_type tol2 = atol + std::abs(cijk3)*rtol;
344  value_type err2 = std::abs(cijk-cijk3);
345  bool s2 = err2 < tol2;
346  if (!s2) {
347  out << std::endl
348  << "Check: rel_err( C(" << I << "," << J << ","
349  << K << ") )"
350  << " = " << "rel_err( " << cijk << ", " << cijk3 << " ) = "
351  << err << " <= " << tol << " : ";
352  if (s2) out << "Passed.";
353  else
354  out << "Failed!";
355  out << std::endl;
356  }
357  success = success && s2;
358  }
359  }
360  }
361  TEUCHOS_TEST_EQUALITY(node->my_num_entries, idx, out, success);
362  node_stack.pop_back();
363  index_stack.pop_back();
364  }
365 
366  // More children to process -- process them first
367  else if (child_index < node->children.size()) {
368  ++index_stack.back();
369  node = node->children[child_index];
370  node_stack.push_back(node);
371  index_stack.push_back(0);
372  }
373 
374  // No more children
375  else {
376  node_stack.pop_back();
377  index_stack.pop_back();
378  }
379 
380  }
381 
382  return success;
383  }
384 
385  template <typename ordinal_type, typename value_type>
387  const Teuchos::Array<ordinal_type>& basis_orders,
388  const ordinal_type p,
389  const bool symmetric,
390  const value_type sparse_tol,
391  const value_type atol,
392  const value_type rtol,
393  Teuchos::FancyOStream& out) {
394 
395  bool success = true;
396  ordinal_type d = basis_orders.size();
397 
398  // Build tensor product basis
400  if (symmetric)
401  for (ordinal_type i=0; i<d; i++)
402  bases[i] = Teuchos::rcp(new Stokhos::LegendreBasis<ordinal_type,value_type>(basis_orders[i], true));
403  else
404  for (ordinal_type i=0; i<d; i++)
405  bases[i] = Teuchos::rcp(new Stokhos::JacobiBasis<ordinal_type,value_type>(basis_orders[i], 1.0, 2.0, true));
409  Teuchos::rcp(new basis_type(bases, sparse_tol));
410 
411  // Build "standard" Cijk
414 
415  // Build "standard" algebraic expansion
417  basis, Cijk);
418 
419  // Build quadrature expansion for sin/cos
423  basis, Cijk, quad);
424 
425  // Build flat LTB 3 tensor
427  flat_Cijk =
429 
430  // Expansions
432  x(basis), a(basis), b(basis), c1(basis), c2(basis);
433 
434  // Initialize a and b to reasonable values
435  x.term(0, 0) = 1.0;
436  for (ordinal_type i=0; i<d; i++)
437  x.term(i, 1) = 0.1;
438  quad_expn.sin(a,x);
439  quad_expn.cos(b,x);
440 
441  // Do multiplications
442  expn.times(c1,a,b);
443  Stokhos::flatLTB3TensorMultiply<10>(c2, a, b, *flat_Cijk);
444 
445  // Test c1 == c2
446  success = Stokhos::comparePCEs(c1, "c1", c2, "c2", rtol, atol, out);
447 
448  return success;
449  }
450 
451  TEUCHOS_UNIT_TEST( LexicographicTreeCoefficients, Isotropic ) {
452  Teuchos::Array<ordinal_type> basis_orders(setup.d, setup.p);
453  success = test_lexicographic_tree_coeffs(basis_orders, setup.p, true, out);
454  }
455 
456  TEUCHOS_UNIT_TEST( LexicographicTreeCoefficients, Anisotropic ) {
457  Teuchos::Array<ordinal_type> basis_orders(setup.d);
458  for (ordinal_type i=0; i<setup.d; ++i)
459  basis_orders[i] = i+1;
460  success = test_lexicographic_tree_coeffs(basis_orders, setup.d, false, out);
461  }
462 
463  TEUCHOS_UNIT_TEST( LTBSparse3Tensor, Isotropic_Symmetric ) {
464  Teuchos::Array<ordinal_type> basis_orders(setup.d, setup.p);
466  basis_orders, setup.p, true, setup.sparse_tol, setup.atol, setup.rtol,
467  out);
468  }
469 
470  TEUCHOS_UNIT_TEST( LTBSparse3Tensor, Anisotropic_Symmetric ) {
471  Teuchos::Array<ordinal_type> basis_orders(setup.d);
472  for (ordinal_type i=0; i<setup.d; ++i)
473  basis_orders[i] = i+1;
475  basis_orders, setup.p, true, setup.sparse_tol, setup.atol, setup.rtol,
476  out);
477  }
478 
479  TEUCHOS_UNIT_TEST( LTBSparse3Tensor, Isotropic_Asymmetric ) {
480  Teuchos::Array<ordinal_type> basis_orders(setup.d, setup.p);
482  basis_orders, setup.p, false, setup.sparse_tol, setup.atol, setup.rtol,
483  out);
484  }
485 
486  TEUCHOS_UNIT_TEST( LTBSparse3Tensor, Anisotropic_Asymmetric ) {
487  Teuchos::Array<ordinal_type> basis_orders(setup.d);
488  for (ordinal_type i=0; i<setup.d; ++i)
489  basis_orders[i] = i+1;
491  basis_orders, setup.p, false, setup.sparse_tol, setup.atol, setup.rtol,
492  out);
493  }
494 
495  TEUCHOS_UNIT_TEST( LTBSparse3TensorBlock, Isotropic_Symmetric ) {
496  Teuchos::Array<ordinal_type> basis_orders(setup.d, setup.p);
498  basis_orders, setup.p, true, setup.sparse_tol, setup.atol, setup.rtol,
499  out);
500  }
501 
502  TEUCHOS_UNIT_TEST( LTBSparse3TensorBlockMultiply, Isotropic_Symmetric ) {
503  Teuchos::Array<ordinal_type> basis_orders(setup.d, setup.p);
505  basis_orders, setup.p, true, setup.sparse_tol, setup.atol, setup.rtol,
506  out);
507  }
508 
509  TEUCHOS_UNIT_TEST( LTBSparse3TensorBlockMultiply, Isotropic_Asymmetric ) {
510  Teuchos::Array<ordinal_type> basis_orders(setup.d, setup.p);
512  basis_orders, setup.p, false, setup.sparse_tol, setup.atol, setup.rtol,
513  out);
514  }
515 
516  TEUCHOS_UNIT_TEST( LTBSparse3TensorBlockMultiply, Anisotropic_Symmetric ) {
517  Teuchos::Array<ordinal_type> basis_orders(setup.d);
518  for (ordinal_type i=0; i<setup.d; ++i)
519  basis_orders[i] = i+1;
521  basis_orders, setup.p, true, setup.sparse_tol, setup.atol, setup.rtol,
522  out);
523  }
524 
525  TEUCHOS_UNIT_TEST( LTBSparse3TensorBlockMultiply, Anisotropic_Asymmetric ) {
526  Teuchos::Array<ordinal_type> basis_orders(setup.d);
527  for (ordinal_type i=0; i<setup.d; ++i)
528  basis_orders[i] = i+1;
530  basis_orders, setup.p, false, setup.sparse_tol, setup.atol, setup.rtol,
531  out);
532  }
533 }
534 
535 int main( int argc, char* argv[] ) {
536  Teuchos::GlobalMPISession mpiSession(&argc, &argv);
538  return res;
539 }
bool test_lexicographic_tree_sparse_3_tensor_block(const Teuchos::Array< ordinal_type > &basis_orders, const ordinal_type p, const bool symmetric, const value_type sparse_tol, const value_type atol, const value_type rtol, Teuchos::FancyOStream &out)
void sin(OrthogPolyApprox< ordinal_type, value_type, node_type > &c, const OrthogPolyApprox< ordinal_type, value_type, node_type > &a)
Teuchos::RCP< LTBSparse3Tensor< ordinal_type, value_type > > computeTripleProductTensorLTB(const TotalOrderBasis< ordinal_type, value_type, LexographicLess< MultiIndex< ordinal_type > > > &product_basis, bool symmetric=false)
ordinal_type n_choose_k(const ordinal_type &n, const ordinal_type &k)
Compute bionomial coefficient (n ; k) = n!/( k! (n-k)! )
Multivariate orthogonal polynomial basis generated from a total order tensor product of univariate po...
void cos(OrthogPolyApprox< ordinal_type, value_type, node_type > &c, const OrthogPolyApprox< ordinal_type, value_type, node_type > &a)
ordinal_type dimension() const
Dimension.
bool comparePCEs(const PCEType &a1, const std::string &a1_name, const Stokhos::OrthogPolyApprox< OrdinalType, ValueType > &a2, const std::string &a2_name, const ValueType &rel_tol, const ValueType &abs_tol, Teuchos::FancyOStream &out)
bool test_lexicographic_tree_sparse_3_tensor(const Teuchos::Array< ordinal_type > &basis_orders, const ordinal_type p, const bool symmetric, const value_type sparse_tol, const value_type atol, const value_type rtol, Teuchos::FancyOStream &out)
virtual Teuchos::RCP< Stokhos::Dense3Tensor< ordinal_type, value_type > > computeTripleProductTensor() const
Compute triple product tensor.
Orthogonal polynomial expansions limited to algebraic operations.
Teuchos::RCP< LTBSparse3Tensor< ordinal_type, value_type > > computeTripleProductTensorLTBBlockLeaf(const TotalOrderBasis< ordinal_type, value_type, LexographicLess< MultiIndex< ordinal_type > > > &product_basis, bool symmetric=false)
Stokhos::LegendreBasis< int, double > basis_type
KOKKOS_INLINE_FUNCTION PCE< Storage > min(const typename PCE< Storage >::value_type &a, const PCE< Storage > &b)
Kokkos::Serial node_type
Data structure storing a sparse 3-tensor C(i,j,k) in a a tree-based format for lexicographically orde...
TEUCHOS_UNIT_TEST(LexicographicTreeCoefficients, Isotropic)
bool test_lexicographic_tree_coeffs(const Teuchos::Array< ordinal_type > &basis_orders, const ordinal_type p, const bool isotropic, Teuchos::FancyOStream &out)
bool test_lexicographic_tree_sparse_3_tensor_multiply(const Teuchos::Array< ordinal_type > &basis_orders, const ordinal_type p, const bool symmetric, const value_type sparse_tol, const value_type atol, const value_type rtol, Teuchos::FancyOStream &out)
Teuchos::RCP< LexicographicTreeBasisNode< ordinal_type > > build_lexicographic_basis_tree(const Teuchos::ArrayView< const ordinal_type > &basis_orders, const ordinal_type total_order, const ordinal_type index_begin=ordinal_type(0), const ordinal_type order_sum=ordinal_type(0), const Stokhos::MultiIndex< ordinal_type > &term_prefix=Stokhos::MultiIndex< ordinal_type >())
static int runUnitTestsFromMain(int argc, char *argv[])
Teuchos::RCP< FlatLTBSparse3Tensor< ordinal_type, value_type > > computeFlatTripleProductTensorLTB(const TotalOrderBasis< ordinal_type, value_type, LexographicLess< MultiIndex< ordinal_type > > > &product_basis, bool symmetric=false)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Jacobi polynomial basis.
KOKKOS_INLINE_FUNCTION PCE< Storage > abs(const PCE< Storage > &a)
void times(OrthogPolyApprox< ordinal_type, value_type, Stokhos::StandardStorage< ordinal_type, value_type > > &c, const OrthogPolyApprox< ordinal_type, value_type, Stokhos::StandardStorage< ordinal_type, value_type > > &a, const OrthogPolyApprox< ordinal_type, value_type, Stokhos::StandardStorage< ordinal_type, value_type > > &b)
KOKKOS_INLINE_FUNCTION constexpr std::enable_if< is_view_uq_pce< view_type >::value, typename CijkType< view_type >::type >::type cijk(const view_type &view)
Legendre polynomial basis.
int main(int argc, char **argv)
reference back()
void push_back(const value_type &x)
#define TEUCHOS_TEST_EQUALITY(v1, v2, out, success)
size_type size() const
A comparison functor implementing a strict weak ordering based lexographic ordering.
virtual ordinal_type size() const
Return total size of basis (given by order() + 1).
Orthogonal polynomial expansions based on numerical quadrature.
Defines quadrature for a tensor product basis by tensor products of 1-D quadrature rules...
UnitTestSetup< ordinal_type, value_type > setup