Stokhos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cijk_simple_tile.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 
10 #include "Stokhos.hpp"
13 
14 #include <algorithm>
15 #include <fstream>
16 #include <iostream>
17 
18 // sparsity_example
19 //
20 // usage:
21 // sparsity_example [options]
22 //
23 // output:
24 // prints the sparsity of the sparse 3 tensor specified by the basis,
25 // dimension, order, given by summing over the third index, to a matrix
26 // market file. This sparsity pattern yields the sparsity of the block
27 // stochastic Galerkin matrix which can be visualized, e.g., by matlab.
28 // The full/linear flag determines whether the third index ranges over
29 // the full polynomial dimension, or only over the zeroth and first order
30 // terms.
31 
32 // Growth policies
33 const int num_growth_types = 2;
36 const char *growth_type_names[] = { "slow", "moderate" };
37 
38 // Product Basis types
40 const int num_prod_basis_types = 4;
43 const char *prod_basis_type_names[] = {
44  "complete", "tensor", "total", "smolyak" };
45 
46 // Ordering types
48 const int num_ordering_types = 2;
51 const char *ordering_type_names[] = {
52  "total", "lexicographic" };
53 
54 using Teuchos::rcp;
55 using Teuchos::RCP;
57 using Teuchos::Array;
58 
59 struct Coord {
60  int i, j, k;
61  int gid;
62 };
63 
64 template <typename coord_t>
65 struct Tile {
66  int lower, upper;
68 };
69 
73 
74 int main(int argc, char **argv)
75 {
76  try {
77 
78  // Initialize MPI
79 #ifdef HAVE_MPI
80  MPI_Init(&argc,&argv);
81 #endif
82 
83  // Setup command line options
85  CLP.setDocString(
86  "This example generates the sparsity pattern for the block stochastic Galerkin matrix.\n");
87  int d = 3;
88  CLP.setOption("dimension", &d, "Stochastic dimension");
89  int p = 5;
90  CLP.setOption("order", &p, "Polynomial order");
91  double drop = 1.0e-12;
92  CLP.setOption("drop", &drop, "Drop tolerance");
93  std::string file = "A.mm";
94  CLP.setOption("filename", &file, "Matrix Market filename");
95  bool symmetric = true;
96  CLP.setOption("symmetric", "asymmetric", &symmetric,
97  "Use basis polynomials with symmetric PDF");
99  CLP.setOption("growth", &growth_type,
101  "Growth type");
102  ProductBasisType prod_basis_type = TOTAL;
103  CLP.setOption("product_basis", &prod_basis_type,
106  "Product basis type");
107  OrderingType ordering_type = LEXICOGRAPHIC_ORDERING;
108  CLP.setOption("ordering", &ordering_type,
111  "Product basis ordering");
112  int i_tile_size = 128;
113  CLP.setOption("tile_size", &i_tile_size, "Tile size");
114  bool save_3tensor = false;
115  CLP.setOption("save_3tensor", "no-save_3tensor", &save_3tensor,
116  "Save full 3tensor to file");
117  std::string file_3tensor = "Cijk.dat";
118  CLP.setOption("filename_3tensor", &file_3tensor,
119  "Filename to store full 3-tensor");
120 
121  // Parse arguments
122  CLP.parse( argc, argv );
123 
124  // Basis
126  const double alpha = 1.0;
127  const double beta = symmetric ? 1.0 : 2.0 ;
128  for (int i=0; i<d; i++) {
129  bases[i] = rcp(new Stokhos::JacobiBasis<int,double>(
130  p, alpha, beta, true, growth_type));
131  }
135  if (prod_basis_type == COMPLETE)
136  basis =
138  bases, drop));
139  else if (prod_basis_type == TENSOR) {
140  if (ordering_type == TOTAL_ORDERING)
141  basis =
143  bases, drop));
144  else if (ordering_type == LEXICOGRAPHIC_ORDERING)
145  basis =
147  bases, drop));
148  }
149 
150  else if (prod_basis_type == TOTAL) {
151  if (ordering_type == TOTAL_ORDERING)
152  basis =
154  bases, drop));
155  else if (ordering_type == LEXICOGRAPHIC_ORDERING)
156  basis =
158  bases, drop));
159  }
160  else if (prod_basis_type == SMOLYAK) {
161  Stokhos::TotalOrderIndexSet<int> index_set(d, p);
162  if (ordering_type == TOTAL_ORDERING)
163  basis =
165  bases, index_set, drop));
166  else if (ordering_type == LEXICOGRAPHIC_ORDERING)
167  basis =
169  bases, index_set, drop));
170  }
171 
172  // Triple product tensor
174  RCP<Cijk_type> Cijk = basis->computeTripleProductTensor();
175 
176  int basis_size = basis->size();
177  std::cout << "basis size = " << basis_size
178  << " num nonzero Cijk entries = " << Cijk->num_entries()
179  << std::endl;
180 
181  // Build 2-way symmetric Cijk tensor
182  RCP<Cijk_type> Cijk_sym = rcp(new Cijk_type);
183  Cijk_type::i_iterator i_begin = Cijk->i_begin();
184  Cijk_type::i_iterator i_end = Cijk->i_end();
185  for (Cijk_type::i_iterator i_it=i_begin; i_it!=i_end; ++i_it) {
186  int i = index(i_it);
187  Cijk_type::ik_iterator k_begin = Cijk->k_begin(i_it);
188  Cijk_type::ik_iterator k_end = Cijk->k_end(i_it);
189  for (Cijk_type::ik_iterator k_it = k_begin; k_it != k_end; ++k_it) {
190  int k = index(k_it);
191  Cijk_type::ikj_iterator j_begin = Cijk->j_begin(k_it);
192  Cijk_type::ikj_iterator j_end = Cijk->j_end(k_it);
193  for (Cijk_type::ikj_iterator j_it = j_begin; j_it != j_end; ++j_it) {
194  int j = index(j_it);
195  if (k <= j) {
196  double c = value(j_it);
197  Cijk_sym->add_term(i, j, k, c);
198  }
199  }
200  }
201  }
202  Cijk_sym->fillComplete();
203 
204  // First partition based on i
205  int j_tile_size = i_tile_size / 2;
206  int num_i_parts = (basis_size + i_tile_size-1) / i_tile_size;
207  int its = basis_size / num_i_parts;
208  Array<ITile> i_tiles(num_i_parts);
209  for (int i=0; i<num_i_parts; ++i) {
210  i_tiles[i].lower = i*its;
211  i_tiles[i].upper = (i+1)*its;
212  i_tiles[i].parts.resize(1);
213  i_tiles[i].parts[0].lower = basis_size;
214  i_tiles[i].parts[0].upper = 0;
215  }
216 
217  // Next partition j
218  for (Cijk_type::i_iterator i_it=Cijk_sym->i_begin();
219  i_it!=Cijk_sym->i_end(); ++i_it) {
220  int i = index(i_it);
221 
222  // Find which part i belongs to
223  int idx = 0;
224  while (idx < num_i_parts && i >= i_tiles[idx].lower) ++idx;
225  --idx;
226  TEUCHOS_ASSERT(idx >= 0 && idx < num_i_parts);
227 
228  Cijk_type::ik_iterator k_begin = Cijk_sym->k_begin(i_it);
229  Cijk_type::ik_iterator k_end = Cijk_sym->k_end(i_it);
230  for (Cijk_type::ik_iterator k_it = k_begin; k_it != k_end; ++k_it) {
231  int j = index(k_it); // using symmetry to interchange j and k
232 
233  if (j < i_tiles[idx].parts[0].lower)
234  i_tiles[idx].parts[0].lower = j;
235  if (j > i_tiles[idx].parts[0].upper)
236  i_tiles[idx].parts[0].upper = j;
237  }
238  }
239  for (int idx=0; idx<num_i_parts; ++idx) {
240  int lower = i_tiles[idx].parts[0].lower;
241  int upper = i_tiles[idx].parts[0].upper;
242  int range = upper - lower + 1;
243  int num_j_parts = (range + j_tile_size-1) / j_tile_size;
244  int jts = range / num_j_parts;
245  Array<JTile> j_tiles(num_j_parts);
246  for (int j=0; j<num_j_parts; ++j) {
247  j_tiles[j].lower = lower + j*jts;
248  j_tiles[j].upper = lower + (j+1)*jts;
249  j_tiles[j].parts.resize(1);
250  j_tiles[j].parts[0].lower = basis_size;
251  j_tiles[j].parts[0].upper = 0;
252  }
253  i_tiles[idx].parts.swap(j_tiles);
254  }
255 
256  // Now partition k
257  for (Cijk_type::i_iterator i_it=Cijk_sym->i_begin();
258  i_it!=Cijk_sym->i_end(); ++i_it) {
259  int i = index(i_it);
260 
261  // Find which part i belongs to
262  int idx = 0;
263  while (idx < num_i_parts && i >= i_tiles[idx].lower) ++idx;
264  --idx;
265  TEUCHOS_ASSERT(idx >= 0 && idx < num_i_parts);
266 
267  Cijk_type::ik_iterator k_begin = Cijk_sym->k_begin(i_it);
268  Cijk_type::ik_iterator k_end = Cijk_sym->k_end(i_it);
269  for (Cijk_type::ik_iterator k_it = k_begin; k_it != k_end; ++k_it) {
270  int j = index(k_it); // using symmetry to interchange j and k
271 
272  // Find which part j belongs to
273  int num_j_parts = i_tiles[idx].parts.size();
274  int jdx = 0;
275  while (jdx < num_j_parts && j >= i_tiles[idx].parts[jdx].lower) ++jdx;
276  --jdx;
277  TEUCHOS_ASSERT(jdx >= 0 && jdx < num_j_parts);
278 
279  Cijk_type::ikj_iterator j_begin = Cijk_sym->j_begin(k_it);
280  Cijk_type::ikj_iterator j_end = Cijk_sym->j_end(k_it);
281  for (Cijk_type::ikj_iterator j_it = j_begin; j_it != j_end; ++j_it) {
282  int k = index(j_it); // using symmetry to interchange j and k
283 
284  if (k >= j) {
285  Coord coord;
286  coord.i = i; coord.j = j; coord.k = k;
287  i_tiles[idx].parts[jdx].parts[0].parts.push_back(coord);
288  if (k < i_tiles[idx].parts[jdx].parts[0].lower)
289  i_tiles[idx].parts[jdx].parts[0].lower = k;
290  if (k > i_tiles[idx].parts[jdx].parts[0].upper)
291  i_tiles[idx].parts[jdx].parts[0].upper = k;
292  }
293  }
294  }
295  }
296 
297  // Now need to divide up k-parts based on lower/upper bounds
298  int num_parts = 0;
299  int num_coord = 0;
300  for (int idx=0; idx<num_i_parts; ++idx) {
301  int num_j_parts = i_tiles[idx].parts.size();
302  for (int jdx=0; jdx<num_j_parts; ++jdx) {
303  int lower = i_tiles[idx].parts[jdx].parts[0].lower;
304  int upper = i_tiles[idx].parts[jdx].parts[0].upper;
305  int range = upper - lower + 1;
306  int num_k_parts = (range + j_tile_size-1) / j_tile_size;
307  int kts = range / num_k_parts;
308  Array<KTile> k_tiles(num_k_parts);
309  for (int k=0; k<num_k_parts; ++k) {
310  k_tiles[k].lower = lower + k*kts;
311  k_tiles[k].upper = lower + (k+1)*kts;
312  }
313  int num_k = i_tiles[idx].parts[jdx].parts[0].parts.size();
314  for (int l=0; l<num_k; ++l) {
315  int i = i_tiles[idx].parts[jdx].parts[0].parts[l].i;
316  int j = i_tiles[idx].parts[jdx].parts[0].parts[l].j;
317  int k = i_tiles[idx].parts[jdx].parts[0].parts[l].k;
318 
319  // Find which part k belongs to
320  int kdx = 0;
321  while (kdx < num_k_parts && k >= k_tiles[kdx].lower) ++kdx;
322  --kdx;
323  TEUCHOS_ASSERT(kdx >= 0 && kdx < num_k_parts);
324 
325  Coord coord;
326  coord.i = i; coord.j = j; coord.k = k;
327  k_tiles[kdx].parts.push_back(coord);
328  ++num_coord;
329  if (j != k) ++num_coord;
330  }
331 
332  // Eliminate parts with zero size
333  Array<KTile> k_tiles2;
334  for (int k=0; k<num_k_parts; ++k) {
335  if (k_tiles[k].parts.size() > 0)
336  k_tiles2.push_back(k_tiles[k]);
337  }
338  num_parts += k_tiles2.size();
339  i_tiles[idx].parts[jdx].parts.swap(k_tiles2);
340  }
341  }
342  TEUCHOS_ASSERT(num_coord == Cijk->num_entries());
343 
344  std::cout << "num parts requested = " << num_parts << std::endl;
345 
346  // Form list of part IDs
347  Teuchos::Array<int> part_IDs(num_parts);
348  for (int i=0; i<num_parts; ++i)
349  part_IDs[i] = i;
350  std::random_shuffle(part_IDs.begin(), part_IDs.end());
351 
352  // Assign part IDs
353  int pp = 0;
354  for (int idx=0; idx<num_i_parts; ++idx) {
355  int num_j_parts = i_tiles[idx].parts.size();
356  for (int jdx=0; jdx<num_j_parts; ++jdx) {
357  int num_k_parts = i_tiles[idx].parts[jdx].parts.size();
358  for (int kdx=0; kdx<num_k_parts; ++kdx) {
359  int num_k = i_tiles[idx].parts[jdx].parts[kdx].parts.size();
360  for (int l=0; l<num_k; ++l) {
361  i_tiles[idx].parts[jdx].parts[kdx].parts[l].gid = part_IDs[pp];
362  }
363  ++pp;
364  }
365  }
366  }
367 
368  int part = 0;
369  for (int idx=0; idx<num_i_parts; ++idx) {
370  int num_j_parts = i_tiles[idx].parts.size();
371  for (int jdx=0; jdx<num_j_parts; ++jdx) {
372  int num_k_parts = i_tiles[idx].parts[jdx].parts.size();
373  for (int kdx=0; kdx<num_k_parts; ++kdx) {
374  std::cout << part++ << " : ["
375  << i_tiles[idx].lower << ","
376  << i_tiles[idx].upper << ") x ["
377  << i_tiles[idx].parts[jdx].lower << ","
378  << i_tiles[idx].parts[jdx].upper << ") x ["
379  << i_tiles[idx].parts[jdx].parts[kdx].lower << ","
380  << i_tiles[idx].parts[jdx].parts[kdx].upper << ") : "
381  << i_tiles[idx].parts[jdx].parts[kdx].parts.size()
382  << std::endl;
383  }
384  }
385  }
386 
387  // Print full 3-tensor to file
388  std::ofstream cijk_file;
389  if (save_3tensor) {
390  cijk_file.open(file_3tensor.c_str());
391  cijk_file.precision(14);
392  cijk_file.setf(std::ios::scientific);
393  cijk_file << "i, j, k, part" << std::endl;
394  for (int idx=0; idx<num_i_parts; ++idx) {
395  int num_j_parts = i_tiles[idx].parts.size();
396  for (int jdx=0; jdx<num_j_parts; ++jdx) {
397  int num_k_parts = i_tiles[idx].parts[jdx].parts.size();
398  for (int kdx=0; kdx<num_k_parts; ++kdx) {
399  int num_k = i_tiles[idx].parts[jdx].parts[kdx].parts.size();
400  for (int l=0; l<num_k; ++l) {
401  Coord c = i_tiles[idx].parts[jdx].parts[kdx].parts[l];
402  cijk_file << c.i << ", " << c.j << ", " << c.k << ", " << c.gid
403  << std::endl;
404  if (c.j != c.k)
405  cijk_file << c.i << ", " << c.k << ", " << c.j << ", " << c.gid
406  << std::endl;
407  }
408  }
409  }
410  }
411  cijk_file.close();
412  }
413 
414  }
415 
416  catch (std::exception& e) {
417  std::cout << e.what() << std::endl;
418  }
419 
420  return 0;
421 }
const ProductBasisType prod_basis_type_values[]
SparseArrayIterator< index_iterator, value_iterator >::value_type index(const SparseArrayIterator< index_iterator, value_iterator > &it)
Multivariate orthogonal polynomial basis generated from a total order tensor product of univariate po...
const int num_prod_basis_types
GrowthPolicy
Enumerated type for determining Smolyak growth policies.
const char * growth_type_names[]
const OrderingType ordering_type_values[]
const int num_ordering_types
A comparison functor implementing a strict weak ordering based total-order ordering, recursive on the dimension.
OrderingType
ProductBasisType
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void setOption(const char option_true[], const char option_false[], bool *option_val, const char documentation[]=NULL)
const int num_growth_types
Jacobi polynomial basis.
EParseCommandLineReturn parse(int argc, char *argv[], std::ostream *errout=&std::cerr) const
Tile< JTile > ITile
friend friend void swap(Array< T2 > &a1, Array< T2 > &a2)
void resize(size_type new_size, const value_type &x=value_type())
const Stokhos::GrowthPolicy growth_type_values[]
Multivariate orthogonal polynomial basis generated from a Smolyak sparse grid.
iterator end()
Multivariate orthogonal polynomial basis generated from a tensor product of univariate polynomials...
Stokhos::Sparse3Tensor< int, double > Cijk_type
int main(int argc, char **argv)
void push_back(const value_type &x)
An isotropic total order index set.
void setDocString(const char doc_string[])
SparseArrayIterator< index_iterator, value_iterator >::value_reference value(const SparseArrayIterator< index_iterator, value_iterator > &it)
size_type size() const
A comparison functor implementing a strict weak ordering based lexographic ordering.
Array< coord_t > parts
Tile< KTile > JTile
#define TEUCHOS_ASSERT(assertion_test)
const char * ordering_type_names[]
Tile< Coord > KTile
iterator begin()
const char * prod_basis_type_names[]