ROL
ROL_SandiaSGMGADef.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ************************************************************************
3 //
4 // Rapid Optimization Library (ROL) Package
5 // Copyright (2014) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact lead developers:
38 // Drew Kouri (dpkouri@sandia.gov) and
39 // Denis Ridzal (dridzal@sandia.gov)
40 //
41 // ************************************************************************
42 // @HEADER
43 
44 
45 namespace ROL {
46 
47 //****************************************************************************80
48 
50 (
51  double alpha_max,
52  int dim_num,
53  double level_weight[]
54 )
55 
56 //****************************************************************************80
57 //
58 // Purpose:
59 //
60 // SGMGA_ANISO_BALANCE "balances" an anisotropic weight vector.
61 //
62 // Discussion:
63 //
64 // The entries in LEVEL_WEIGHT are essentially arbitrary nonnegative numbers.
65 //
66 // The ratio between two entries indicates their relative importance.
67 // For instance,
68 //
69 // LEVEL_WEIGHT(1) / LEVEL_WEIGHT(2) = 10
70 //
71 // means that variable 2 is 10 times more important than variable 1.
72 // Here, being 10 times more important means that we will generate 10 levels
73 // of sparse grid in direction 2 as we generate 1 level in direction 1.
74 //
75 // Under this interpretation, a ratio of 10 already indicates an extreme
76 // imbalanace in the variables, since 10 sparse grid levels in the second
77 // variable corresponds roughly to approximating x^1 only, and
78 // all of y^1 through y^10. A ratio higher than this seems unreasonable.
79 //
80 // Therefore, this function tries to take a somewhat arbitrary level weight
81 // vector, and produce a "balanced" level weight vector with the properties
82 // that the mininum entry is 1 (representing the item of most importance)
83 // and the maximum entry is ALPHA_MAX. A reasonable value of ALPHA_MAX
84 // might be 10 or even 5.
85 //
86 // Licensing:
87 //
88 // This code is distributed under the GNU LGPL license.
89 //
90 // Modified:
91 //
92 // 03 February 2010
93 //
94 // Author:
95 //
96 // John Burkardt
97 //
98 // Reference:
99 //
100 // Fabio Nobile, Raul Tempone, Clayton Webster,
101 // A Sparse Grid Stochastic Collocation Method for Partial Differential
102 // Equations with Random Input Data,
103 // SIAM Journal on Numerical Analysis,
104 // Volume 46, Number 5, 2008, pages 2309-2345.
105 //
106 // Fabio Nobile, Raul Tempone, Clayton Webster,
107 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
108 // Differential Equations with Random Input Data,
109 // SIAM Journal on Numerical Analysis,
110 // Volume 46, Number 5, 2008, pages 2411-2442.
111 //
112 // Parameters:
113 //
114 // Input, double ALPHA_MAX, the maximum legal value of
115 // LEVEL_WEIGHT, after all entries have been divided by the minimum
116 // nonzero entry. 1 <= ALPHA_MAX.
117 //
118 // Input, int DIM_NUM, the spatial dimension.
119 //
120 // Input, double LEVEL_WEIGHT[DIM_NUM], the anisotropic weights.
121 // The values must be positive.
122 //
123 // Output, double SGMGA_ANISO_BALANCE[DIM_NUM], the balanced
124 // anisotropic weights. The smallest nonzero entry is 1.0 and
125 // no entry is greater than ALPHA_MAX.
126 //
127 {
128  int dim;
129  double *level_weight2;
130  double level_weight_min;
131  int nonzero_num;
132 
133  if ( alpha_max < 1.0 )
134  {
135  std::cerr << "\n";
136  std::cerr << "SGMGA_ANISO_BALANCE - Fatal error!\n";
137  std::cerr << " ALPHA_MAX < 1.0\n";
138  std::exit ( 1 );
139  }
140 //
141 // Find the smallest nonzero entry.
142 //
143  level_weight_min = webbur->r8_huge ( );
144  nonzero_num = 0;
145 
146  for ( dim = 0; dim < dim_num; dim++ )
147  {
148  if ( 0.0 < level_weight[dim] )
149  {
150  if ( level_weight[dim] < level_weight_min )
151  {
152  level_weight_min = level_weight[dim];
153  nonzero_num = nonzero_num + 1;
154  }
155  }
156  }
157 
158  if ( nonzero_num == 0 )
159  {
160  std::cerr << "\n";
161  std::cerr << "SGMGA_ANISO_BALANCE - Fatal error!\n";
162  std::cerr << " Could not find a positive entry in LEVEL_WEIGHT.\n";
163  std::exit ( 1 );
164  }
165 //
166 // Rescale so the smallest nonzero entry is 1.
167 //
168  level_weight2 = new double[dim_num];
169  for ( dim = 0; dim < dim_num; dim++ )
170  {
171  level_weight2[dim] = level_weight[dim] / level_weight_min;
172  }
173 //
174 // Set the maximum entry to no more than ALPHA_MAX.
175 //
176  for ( dim = 0; dim < dim_num; dim++ )
177  {
178  level_weight2[dim] = webbur->r8_min ( alpha_max, level_weight2[dim] );
179  }
180  return level_weight2;
181 }
182 //****************************************************************************80
183 
185 (
186  int option,
187  int dim_num,
188  double level_weight[]
189 )
190 
191 //****************************************************************************80
192 //
193 // Purpose:
194 //
195 // SGMGA_ANISO_NORMALIZE normalizes the anisotropic weight vector.
196 //
197 // Discussion:
198 //
199 // It is convenient for the user to initialize the anisotropic weight
200 // vector with any set of positive values. These values are to be used
201 // as coefficients of the 1D levels, to evaluate an expression which
202 // determines which 1D levels will be included in a given rule.
203 //
204 // This means that a relatively LARGE coefficient forces the corresponding
205 // level to be relatively SMALL. This is perhaps the opposite of what
206 // a user might expect. If a user wishes to use an importance vector,
207 // so that a relatively large importance should correspond to more levels,
208 // and hence more points, in that dimension, then the function
209 // SGMGA_IMPORTANCE_TO_ANISO should be called first!
210 //
211 // Since the weights only represent the relative importance of the
212 // components, they may be multiplied by any (positive) scale factor.
213 // Nonetheless, it may be convenient to choose a particular normalization
214 // for the weights.
215 //
216 // Licensing:
217 //
218 // This code is distributed under the GNU LGPL license.
219 //
220 // Modified:
221 //
222 // 27 November 2009
223 //
224 // Author:
225 //
226 // John Burkardt
227 //
228 // Reference:
229 //
230 // Fabio Nobile, Raul Tempone, Clayton Webster,
231 // A Sparse Grid Stochastic Collocation Method for Partial Differential
232 // Equations with Random Input Data,
233 // SIAM Journal on Numerical Analysis,
234 // Volume 46, Number 5, 2008, pages 2309-2345.
235 //
236 // Fabio Nobile, Raul Tempone, Clayton Webster,
237 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
238 // Differential Equations with Random Input Data,
239 // SIAM Journal on Numerical Analysis,
240 // Volume 46, Number 5, 2008, pages 2411-2442.
241 //
242 // Parameters:
243 //
244 // Input, int OPTION, the normalization option.
245 // 0, no scaling is applied.
246 // 1, the weights are scaled so that the minimum nonzero entry is 1.
247 // 2, the weights are scaled so that they sum to DIM_NUM.
248 //
249 // Input, int DIM_NUM, the spatial dimension.
250 //
251 // Input/output, double LEVEL_WEIGHT[DIM_NUM], the anisotropic
252 // weights. The input values must be strictly positive.
253 // On output, these have been normalized.
254 //
255 {
256  int dim;
257  int found;
258  double level_weight_min;
259  double level_weight_sum;
260 //
261 // Option 0, no normalization.
262 //
263  if ( option == 0 )
264  {
265  }
266 //
267 // Option 1, the minimum nonzero entry is 1.
268 //
269  else if ( option == 1 )
270  {
271  level_weight_min = webbur->r8_huge ( );
272  found = 0;
273  for ( dim = 0; dim < dim_num; dim++ )
274  {
275  if ( 0.0 < level_weight[dim] )
276  {
277  if ( level_weight[dim] < level_weight_min )
278  {
279  level_weight_min = level_weight[dim];
280  found = found + 1;
281  }
282  }
283  }
284 
285  if ( found == 0 )
286  {
287  std::cerr << "\n";
288  std::cerr << "SGMGA_ANISO_NORMALIZE - Fatal error!\n";
289  std::cerr << " Could not find a positive entry in LEVEL_WEIGHT.\n";
290  std::exit ( 1 );
291  }
292 
293  for ( dim = 0; dim < dim_num; dim++ )
294  {
295  level_weight[dim] = level_weight[dim] / level_weight_min;
296  }
297  }
298 //
299 // Option 2, rescale so sum of weights is DIM_NUM.
300 //
301  else if ( option == 2 )
302  {
303  level_weight_sum = webbur->r8vec_sum ( dim_num, level_weight );
304 
305  if ( level_weight_sum <= 0.0 )
306  {
307  std::cerr << "\n";
308  std::cerr << "SGMGA_ANISO_NORMALIZE - Fatal error!\n";
309  std::cerr << " Sum of level weights is not positive.\n";
310  std::exit ( 1 );
311  }
312  for ( dim = 0; dim < dim_num; dim++ )
313  {
314  level_weight[dim] = ( ( double ) ( dim_num ) * level_weight[dim] )
315  / level_weight_sum;
316  }
317  }
318 
319  return;
320 }
321 //****************************************************************************80
322 
324 (
325  int dim_num,
326  double importance[],
327  double level_weight[]
328 )
329 
330 //****************************************************************************80
331 //
332 // Purpose:
333 //
334 // SGMGA_IMPORTANCE_TO_ANISO: importance to anisotropic weight.
335 //
336 // Discussion:
337 //
338 // To specify the anisotropy of a multidimensional problem, the user is
339 // allowed to specify an "importance vector". This vector can contain
340 // any set of positive values. These values represent the relative
341 // importance of each dimension. These values, with a suitable normalization,
342 // will be used to evaluate a constraint of the following form:
343 //
344 // QMIN < Level(1) / Importance(1) + Level(2) / Importance(2) + ...
345 // Level(N) / Importance(N) <= QMAX
346 //
347 // and a set of levels that satisfies this constraint will then be included
348 // in a given anistotropic sparse grid rule. Thus, increasing the
349 // importance value of a particular dimension allows larger level values
350 // in that dimension to satisfy the constraint.
351 //
352 // The program actually works with coefficients LEVEL_WEIGHT that are
353 // the inverse of the importance vector entries, with a suitable
354 // normalization. This function is supplied to convert between the
355 // more natural "importance vector" and the internally useful
356 // "level_weight" vector.
357 //
358 // This function converts the importance vector to an unnormalized
359 // anisotropy weight vector.
360 //
361 // Note that some (but not all) of the IMPORTANCE vector entries may be zero.
362 // This indicates that the corresponding dimension is of "zero" or
363 // rather "minimal" importance. In such a case, only a one-point quadrature
364 // rule will be applied for that dimension, no matter what sparse grid
365 // level is requested for the overall problem.
366 //
367 // Licensing:
368 //
369 // This code is distributed under the GNU LGPL license.
370 //
371 // Modified:
372 //
373 // 13 November 2009
374 //
375 // Author:
376 //
377 // John Burkardt
378 //
379 // Reference:
380 //
381 // Fabio Nobile, Raul Tempone, Clayton Webster,
382 // A Sparse Grid Stochastic Collocation Method for Partial Differential
383 // Equations with Random Input Data,
384 // SIAM Journal on Numerical Analysis,
385 // Volume 46, Number 5, 2008, pages 2309-2345.
386 //
387 // Fabio Nobile, Raul Tempone, Clayton Webster,
388 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
389 // Differential Equations with Random Input Data,
390 // SIAM Journal on Numerical Analysis,
391 // Volume 46, Number 5, 2008, pages 2411-2442.
392 //
393 // Parameters:
394 //
395 // Input, int DIM_NUM, the spatial dimension.
396 //
397 // Input, double IMPORTANCE[DIM_NUM], the importance vector.
398 // All entries must be nonnegative, and at least one must be positive.
399 //
400 // Output, double LEVEL_WEIGHT[DIM_NUM], the anisotropic
401 // weights.
402 //
403 {
404  int dim;
405  int found;
406  //double level_weight_norm;
407 
408  for ( dim = 0; dim < dim_num; dim++ )
409  {
410  if ( importance[dim] < 0.0 )
411  {
412  std::cerr << "\n";
413  std::cerr << "SGMGA_IMPORTANCE_TO_ANISO - Fatal error!\n";
414  std::cerr << " Some IMPORTANCE entries are not positive.\n";
415  std::exit ( 1 );
416  }
417  }
418 
419  found = 0;
420 
421  for ( dim = 0; dim < dim_num; dim++ )
422  {
423  if ( 0.0 < importance[dim] )
424  {
425  level_weight[dim] = 1.0 / importance[dim];
426  found = found + 1;
427  }
428  else
429  {
430  level_weight[dim] = 0.0;
431  }
432  }
433 
434  if ( found == 0 )
435  {
436  std::cerr << "\n";
437  std::cerr << "SGMGA_IMPORTANCE_TO_ANISO - Fatal error!\n";
438  std::cerr << " No importance entry is positive.\n";
439  std::exit ( 1 );
440  }
441 
442  return;
443 }
444 //****************************************************************************80
445 
447 (
448  int dim_num,
449  double level_weight[],
450  int level_max,
451  int point_num,
452  int point_total_num,
453  int sparse_unique_index[],
454  int growth,
455  int ( SandiaRules::*gw_compute_order[] ) ( int level, int growth ),
456  int sparse_order[],
457  int sparse_index[]
458 )
459 
460 //****************************************************************************80
461 //
462 // Purpose:
463 //
464 // SGMGA_INDEX indexes an SGMGA grid.
465 //
466 // Discussion:
467 //
468 // For each "unique" point in the sparse grid, we return its INDEX and ORDER.
469 //
470 // That is, for the I-th unique point P, we determine the product grid which
471 // first generated this point, and and we return in SPARSE_ORDER the orders
472 // of the 1D rules in that grid, and and in SPARSE_INDEX the component
473 // indexes in those rules that generated this specific point.
474 //
475 // For instance, say P was first generated by a rule which was a 3D product
476 // of a 9th order CC rule and and a 15th order GL rule, and and that to
477 // generate P, we used the 7-th point of the CC rule and and the 3rh point
478 // of the GL rule. Then the SPARSE_ORDER information would be (9,15) and
479 // the SPARSE_INDEX information would be (7,3). This, combined with the
480 // information in RULE, is enough to regenerate the value of P.
481 //
482 // The user must preallocate space for the output arrays SPARSE_ORDER and
483 // SPARSE_INDEX.
484 //
485 // Licensing:
486 //
487 // This code is distributed under the GNU LGPL license.
488 //
489 // Modified:
490 //
491 // 13 January 2012
492 //
493 // Author:
494 //
495 // John Burkardt
496 //
497 // Reference:
498 //
499 // Fabio Nobile, Raul Tempone, Clayton Webster,
500 // A Sparse Grid Stochastic Collocation Method for Partial Differential
501 // Equations with Random Input Data,
502 // SIAM Journal on Numerical Analysis,
503 // Volume 46, Number 5, 2008, pages 2309-2345.
504 //
505 // Fabio Nobile, Raul Tempone, Clayton Webster,
506 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
507 // Differential Equations with Random Input Data,
508 // SIAM Journal on Numerical Analysis,
509 // Volume 46, Number 5, 2008, pages 2411-2442.
510 //
511 // Parameters:
512 //
513 // Input, int DIM_NUM, the spatial dimension.
514 //
515 // Input, double LEVEL_WEIGHT[DIM_NUM], the anisotropic weights.
516 //
517 // Input, int LEVEL_MAX, the maximum value of LEVEL.
518 //
519 // Input, int POINT_NUM, the number of unique points
520 // in the grid.
521 //
522 // Input, int POINT_TOTAL_NUM, the total number of points in the grid.
523 //
524 // Input, int SPARSE_UNIQUE_INDEX[POINT_TOTAL_NUM], associates each
525 // point in the grid with its unique representative.
526 //
527 // Input, int GROWTH, the growth rule.
528 // 0, slow;
529 // 1, moderate;
530 // 2, full.
531 //
532 // Input, int ( *GW_COMPUTE_ORDER[] ) ( int level, int growth ),
533 // an array of pointers to functions which return the order of the
534 // 1D quadrature rule of a given level and growth rule.
535 //
536 // Output, int SPARSE_ORDER[DIM_NUM*POINT_NUM], lists,
537 // for each point, the order of the 1D rules used in the grid that
538 // generated it.
539 //
540 // Output, int SPARSE_INDEX[DIM_NUM*POINT_NUM)] lists, for
541 // each point, its index in each of the 1D rules in the grid that generated
542 // it. The indices are 1-based.
543 //
544 {
545  double coef;
546  int dim;
547  int *level_1d;
548  int *level_1d_max;
549  double level_weight_min_pos;
550  bool more_grids;
551  bool more_points;
552  int *order_1d;
553  int point;
554  int point_count;
555  int *point_index;
556  int point_unique;
557  double q_max;
558  double q_min;
559 
560 //
561 // Special cases.
562 //
563  if ( level_max < 0 )
564  {
565  return;
566  }
567 
568  if ( level_max == 0 )
569  {
570  point = 0;
571  for ( dim = 0; dim < dim_num; dim++ )
572  {
573  sparse_order[dim+point*dim_num] = 1;
574  sparse_index[dim+point*dim_num] = 1;
575  }
576  return;
577  }
578 //
579 // Initialize the INDEX and ORDER arrays to -1 to help catch errors.
580 //
581  for ( point = 0; point < point_num; point++ )
582  {
583  for ( dim = 0; dim < dim_num; dim++ )
584  {
585  sparse_order[dim+point*dim_num] = -1;
586  sparse_index[dim+point*dim_num] = -1;
587  }
588  }
589 
590  point_count = 0;
591 
592  level_1d = new int[dim_num];
593  level_1d_max = new int[dim_num];
594  order_1d = new int[dim_num];
595  point_index = new int[dim_num];
596 //
597 // Initialization for SGMGA_VCN_ORDERED.
598 //
599  level_weight_min_pos = webbur->r8vec_min_pos ( dim_num, level_weight );
600  q_min = ( double ) ( level_max ) * level_weight_min_pos
601  - webbur->r8vec_sum ( dim_num, level_weight );
602  q_max = ( double ) ( level_max ) * level_weight_min_pos;
603  for ( dim = 0; dim < dim_num; dim++ )
604  {
605  if ( 0.0 < level_weight[dim] )
606  {
607  level_1d_max[dim] = ( int )( webbur->r8_floor ( q_max / level_weight[dim] ) ) + 1;
608  if ( q_max <= ( level_1d_max[dim] - 1 ) * level_weight[dim] )
609  {
610  level_1d_max[dim] = level_1d_max[dim] - 1;
611  }
612  }
613  else
614  {
615  level_1d_max[dim] = 0;
616  }
617  }
618  more_grids = false;
619 //
620 // Seek all vectors LEVEL_1D which satisfy the constraint:
621 //
622 // LEVEL_MAX * LEVEL_WEIGHT_MIN_POS - sum ( LEVEL_WEIGHT )
623 // < sum ( 0 <= I < DIM_NUM ) LEVEL_WEIGHT[I] * LEVEL_1D[I]
624 // <= LEVEL_MAX * LEVEL_WEIGHT_MIN_POS.
625 //
626  for ( ; ; )
627  {
628  sgmga_vcn_ordered ( dim_num, level_weight, level_1d_max,
629  level_1d, q_min, q_max, &more_grids );
630 
631  if ( !more_grids )
632  {
633  break;
634  }
635 //
636 // Compute the combinatorial coefficient.
637 //
638  coef = sgmga_vcn_coef ( dim_num, level_weight, level_1d,
639  q_max );
640 
641  if ( coef == 0.0 )
642  {
643  continue;
644  }
645 //
646 // Transform each 1D level to a corresponding 1D order.
647 //
648  for ( dim = 0; dim < dim_num; dim++ )
649  {
650  order_1d[dim] = ((*webbur).*gw_compute_order[dim])(level_1d[dim],growth);
651  }
652 //
653 // The inner loop generates a POINT of the GRID of the LEVEL.
654 //
655  more_points = false;
656 
657  for ( ; ; )
658  {
659  webbur->vec_colex_next3 ( dim_num, order_1d, point_index, &more_points );
660 
661  if ( !more_points )
662  {
663  break;
664  }
665  point_unique = sparse_unique_index[point_count];
666  for ( dim = 0; dim < dim_num; dim++ )
667  {
668  sparse_order[dim+point_unique*dim_num] = order_1d[dim];
669  }
670  for ( dim = 0; dim < dim_num; dim++ )
671  {
672  sparse_index[dim+point_unique*dim_num] = point_index[dim];
673  }
674  point_count = point_count + 1;
675  }
676  }
677 
678  delete [] level_1d;
679  delete [] level_1d_max;
680  delete [] order_1d;
681  delete [] point_index;
682 
683  return;
684 }
685 //****************************************************************************80
686 
688 (
689  int dim_num,
690  double level_weight[],
691  int level_max,
692  void ( SandiaRules2::*gw_compute_points[] ) ( int order, int dim, double x[] ),
693  int point_num,
694  int sparse_order[],
695  int sparse_index[],
696  int growth,
697  int ( SandiaRules::*gw_compute_order[] ) ( int level, int growth ),
698  double sparse_point[]
699 )
700 
701 //****************************************************************************80
702 //
703 // Purpose:
704 //
705 // SGMGA_POINT computes the points of an SGMGA rule.
706 //
707 // Discussion:
708 //
709 // The sparse grid is the logical sum of low degree product rules.
710 //
711 // Each product rule is the product of 1D factor rules.
712 //
713 // The user specifies:
714 // * the spatial dimension of the quadrature region,
715 // * the level that defines the Smolyak grid.
716 // * the quadrature rules.
717 // * the number of points.
718 //
719 // The user must preallocate space for the output array SPARSE_POINT.
720 //
721 // Licensing:
722 //
723 // This code is distributed under the GNU LGPL license.
724 //
725 // Modified:
726 //
727 // 13 January 2012
728 //
729 // Author:
730 //
731 // John Burkardt
732 //
733 // Reference:
734 //
735 // Fabio Nobile, Raul Tempone, Clayton Webster,
736 // A Sparse Grid Stochastic Collocation Method for Partial Differential
737 // Equations with Random Input Data,
738 // SIAM Journal on Numerical Analysis,
739 // Volume 46, Number 5, 2008, pages 2309-2345.
740 //
741 // Fabio Nobile, Raul Tempone, Clayton Webster,
742 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
743 // Differential Equations with Random Input Data,
744 // SIAM Journal on Numerical Analysis,
745 // Volume 46, Number 5, 2008, pages 2411-2442.
746 //
747 // Parameters:
748 //
749 // Input, int DIM_NUM, the spatial dimension.
750 //
751 // Input, double LEVEL_WEIGHT[DIM_NUM], the anisotropic weights.
752 //
753 // Input, int LEVEL_MAX, controls the size of the final sparse grid.
754 //
755 // Input, void ( *GW_COMPUTE_POINTS[] ) ( int order, int dim, double x[] ),
756 // an array of pointers to functions which return the 1D quadrature points
757 // associated with each spatial dimension for which a Golub Welsch rule
758 // is used.
759 //
760 // Input, int POINT_NUM, the number of points in the grid,
761 // as determined by SGMGA_SIZE.
762 //
763 // Input, int SPARSE_ORDER[DIM_NUM*POINT_NUM], lists, for each point,
764 // the order of the 1D rules used in the grid that generated it.
765 //
766 // Input, int SPARSE_INDEX[DIM_NUM*POINT_NUM], lists, for each point,
767 // its index in each of the 1D rules in the grid that generated it.
768 // The indices are 1-based.
769 //
770 // Input, int GROWTH, the growth rule.
771 // 0, slow;
772 // 1, moderate;
773 // 2, full.
774 //
775 // Input, int ( *GW_COMPUTE_ORDER[] ) ( int level, int growth ),
776 // an array of pointers to functions which return the order of the
777 // 1D quadrature rule of a given level and growth rule.
778 //
779 // Output, double SPARSE_POINT[DIM_NUM*POINT_NUM], the points.
780 //
781 {
782  int dim;
783  int level;
784  int *level_1d_max;
785  double level_weight_min_pos;
786  int order;
787  int point;
788  double *points;
789  double q_max;
790 
791  for ( point = 0; point < point_num; point++ )
792  {
793  for ( dim = 0; dim < dim_num; dim++ )
794  {
795  sparse_point[dim+point*dim_num] = - webbur->r8_huge ( );
796  }
797  }
798 //
799 // Compute the point coordinates.
800 //
801  level_1d_max = new int[dim_num];
802  level_weight_min_pos = webbur->r8vec_min_pos ( dim_num, level_weight );
803  q_max = ( double ) ( level_max ) * level_weight_min_pos;
804 
805  for ( dim = 0; dim < dim_num; dim++ )
806  {
807  if ( 0.0 < level_weight[dim] )
808  {
809  level_1d_max[dim] = ( int ) ( webbur->r8_floor ( q_max / level_weight[dim] ) ) + 1;
810  if ( q_max <= ( level_1d_max[dim] - 1 ) * level_weight[dim] )
811  {
812  level_1d_max[dim] = level_1d_max[dim] - 1;
813  }
814  }
815  else
816  {
817  level_1d_max[dim] = 0;
818  }
819 
820  for ( level = 0; level <= level_1d_max[dim]; level++ )
821  {
822  order = ((*webbur).*gw_compute_order[dim]) ( level, growth );
823 
824  points = new double[order];
825 
826  ((*webbur2).*gw_compute_points[dim]) ( order, dim, points );
827 
828  for ( point = 0; point < point_num; point++ )
829  {
830  if ( sparse_order[dim+point*dim_num] == order )
831  {
832  sparse_point[dim+point*dim_num] =
833  points[sparse_index[dim+point*dim_num]-1];
834  }
835  }
836  delete [] points;
837  }
838  }
839 //
840 // Check to see if we missed any points.
841 //
842  for ( point = 0; point < point_num; point++ )
843  {
844  for ( dim = 0; dim < dim_num; dim++ )
845  {
846  if ( sparse_point[dim+point*dim_num] == - webbur-> r8_huge ( ) )
847  {
848  std::cerr << "\n";
849  std::cerr << "SGMGA_POINT - Fatal error!\n";
850  std::cerr << " At least one point component was not assigned.\n";
851  std::cerr << " POINT = " << point << "\n";
852  std::cerr << " DIM = " << dim << "\n";
853  std::cerr << " SPARSE_ORDER(DIM,POINT) = "
854  << sparse_order[dim+point*dim_num] << "\n";
855  std::cerr << " LEVEL_WEIGHT(DIM) = " << level_weight[dim] << "\n";
856  std::exit ( 1 );
857  }
858  }
859  }
860 
861  delete [] level_1d_max;
862 
863  return;
864 }
865 //****************************************************************************80
866 
868 (
869  int dim_num,
870  int order_1d[],
871  int order_nd,
872  void ( SandiaRules2::*gw_compute_weights[] ) ( int order, int dim, double w[] ),
873  double weight_nd[]
874 )
875 
876 //****************************************************************************80
877 //
878 // Purpose:
879 //
880 // SGMGA_PRODUCT_WEIGHT computes the weights of a mixed product rule.
881 //
882 // Discussion:
883 //
884 // This routine computes the weights for a quadrature rule which is
885 // a product of 1D rules of varying order and kind.
886 //
887 // The user must preallocate space for the output array WEIGHT_ND.
888 //
889 // Licensing:
890 //
891 // This code is distributed under the GNU LGPL license.
892 //
893 // Modified:
894 //
895 // 24 November 2011
896 //
897 // Author:
898 //
899 // John Burkardt
900 //
901 // Reference:
902 //
903 // Fabio Nobile, Raul Tempone, Clayton Webster,
904 // A Sparse Grid Stochastic Collocation Method for Partial Differential
905 // Equations with Random Input Data,
906 // SIAM Journal on Numerical Analysis,
907 // Volume 46, Number 5, 2008, pages 2309-2345.
908 //
909 // Fabio Nobile, Raul Tempone, Clayton Webster,
910 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
911 // Differential Equations with Random Input Data,
912 // SIAM Journal on Numerical Analysis,
913 // Volume 46, Number 5, 2008, pages 2411-2442.
914 //
915 // Parameters:
916 //
917 // Input, int DIM_NUM, the spatial dimension.
918 //
919 // Input, int ORDER_1D[DIM_NUM], the order of the 1D rules.
920 //
921 // Input, int ORDER_ND, the order of the product rule.
922 //
923 // Input, void ( *GW_COMPUTE_WEIGHTS[] ) ( int order, int dim, double w[] ),
924 // an array of pointers to functions which return the 1D quadrature weights
925 // associated with each spatial dimension for which a Golub Welsch rule
926 // is used.
927 //
928 // Output, double WEIGHT_ND[ORDER_ND], the product rule weights.
929 //
930 {
931  int dim;
932  int i;
933  double *weight_1d;
934 
935  for ( i = 0; i < order_nd; i++ )
936  {
937  weight_nd[i] = 1.0;
938  }
939 
940  for ( dim = 0; dim < dim_num; dim++ )
941  {
942  weight_1d = new double[order_1d[dim]];
943 
944  ((*webbur2).*gw_compute_weights[dim]) ( order_1d[dim], dim, weight_1d );
945 
946  webbur->r8vec_direct_product2 ( dim, order_1d[dim], weight_1d, dim_num,
947  order_nd, weight_nd );
948 
949  delete [] weight_1d;
950  }
951  return;
952 }
953 //****************************************************************************80
954 
956 (
957  int dim_num,
958  double level_weight[],
959  int level_max,
960  void ( SandiaRules2::*gw_compute_points[] ) ( int order, int dim, double x[] ),
961  double tol,
962  int growth,
963  int ( SandiaRules::*gw_compute_order[] ) ( int level, int growth )
964 )
965 
966 //****************************************************************************80
967 //
968 // Purpose:
969 //
970 // SGMGA_SIZE sizes an SGMGA grid, discounting duplicates.
971 //
972 // Discussion:
973 //
974 // The sparse grid is the logical sum of product grids that satisfy
975 // a particular constraint.
976 //
977 // Depending on the 1D rules involved, there may be many duplicate points
978 // in the sparse grid.
979 //
980 // This function counts the unique points in the sparse grid. It does this
981 // in a straightforward way, by actually generating all the points, and
982 // comparing them, with a tolerance for equality.
983 //
984 // This function has been modified to automatically omit points for which
985 // the "combinatorial coefficient" is zero, since such points would have
986 // a weight of zero in the grid.
987 //
988 // Licensing:
989 //
990 // This code is distributed under the GNU LGPL license.
991 //
992 // Modified:
993 //
994 // 13 January 2012
995 //
996 // Author:
997 //
998 // John Burkardt
999 //
1000 // Reference:
1001 //
1002 // Fabio Nobile, Raul Tempone, Clayton Webster,
1003 // A Sparse Grid Stochastic Collocation Method for Partial Differential
1004 // Equations with Random Input Data,
1005 // SIAM Journal on Numerical Analysis,
1006 // Volume 46, Number 5, 2008, pages 2309-2345.
1007 //
1008 // Fabio Nobile, Raul Tempone, Clayton Webster,
1009 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
1010 // Differential Equations with Random Input Data,
1011 // SIAM Journal on Numerical Analysis,
1012 // Volume 46, Number 5, 2008, pages 2411-2442.
1013 //
1014 // Parameters:
1015 //
1016 // Input, int DIM_NUM, the spatial dimension.
1017 //
1018 // Input, double LEVEL_WEIGHT[DIM_NUM], the anisotropic weights.
1019 //
1020 // Input, int LEVEL_MAX, the maximum value of LEVEL.
1021 //
1022 // Input, void ( *GW_COMPUTE_POINTS[] ) ( int order, int dim, double x[] ),
1023 // an array of pointers to functions which return the 1D quadrature points
1024 // associated with each spatial dimension for which a Golub Welsch rule
1025 // is used.
1026 //
1027 // Input, double TOL, a tolerance for point equality.
1028 //
1029 // Input, int GROWTH, the growth rule.
1030 // 0, slow;
1031 // 1, moderate;
1032 // 2, full.
1033 //
1034 // Input, int ( *GW_COMPUTE_ORDER[] ) ( int level, int growth ),
1035 // an array of pointers to functions which return the order of the
1036 // 1D quadrature rule of a given level and growth rule.
1037 //
1038 // Output, int SGMGA_SIZE, the number of unique points.
1039 //
1040 {
1041  double coef;
1042  int dim;
1043  int level;
1044  int *level_1d;
1045  int *level_1d_max;
1046  double level_weight_min_pos;
1047  bool more_grids;
1048  bool more_points;
1049  int order;
1050  int *order_1d;
1051  int point;
1052  int *point_index;
1053  int point_num;
1054  int point_total_num;
1055  int point_total_num2;
1056  double *points;
1057  double q_max;
1058  double q_min;
1059  int seed;
1060  int *sparse_total_index;
1061  int *sparse_total_order;
1062  double *sparse_total_point;
1063 //
1064 // Special cases.
1065 //
1066  if ( level_max < 0 )
1067  {
1068  point_num = -1;
1069  return point_num;
1070  }
1071 
1072  if ( level_max == 0 )
1073  {
1074  point_num = 1;
1075  return point_num;
1076  }
1077 //
1078 // Get total number of points, including duplicates.
1079 //
1080  point_total_num = sgmga_size_total ( dim_num, level_weight,
1081  level_max, growth, gw_compute_order );
1082 //
1083 // Generate SPARSE_TOTAL_ORDER and SPARSE_TOTAL_INDEX arrays
1084 // for the TOTAL set of points.
1085 //
1086  sparse_total_order = new int[dim_num*point_total_num];
1087  sparse_total_index = new int[dim_num*point_total_num];
1088 
1089  point_total_num2 = 0;
1090 
1091  level_1d = new int[dim_num];
1092  level_1d_max = new int[dim_num];
1093  order_1d = new int[dim_num];
1094  point_index = new int[dim_num];
1095 //
1096 // Initialization for SGMGA_VCN_ORDERED.
1097 //
1098  level_weight_min_pos = webbur->r8vec_min_pos ( dim_num, level_weight );
1099  q_min = ( double ) ( level_max ) * level_weight_min_pos
1100  - webbur->r8vec_sum ( dim_num, level_weight );
1101  q_max = ( double ) ( level_max ) * level_weight_min_pos;
1102  for ( dim = 0; dim < dim_num; dim++ )
1103  {
1104  if ( 0.0 < level_weight[dim] )
1105  {
1106  level_1d_max[dim] = ( int ) ( webbur->r8_floor ( q_max / level_weight[dim] ) ) + 1;
1107  if ( q_max <= ( level_1d_max[dim] - 1 ) * level_weight[dim] )
1108  {
1109  level_1d_max[dim] = level_1d_max[dim] - 1;
1110  }
1111  }
1112  else
1113  {
1114  level_1d_max[dim] = 0;
1115  }
1116  }
1117  more_grids = false;
1118 //
1119 // Seek all vectors LEVEL_1D which satisfy the constraint:
1120 //
1121 // LEVEL_MAX * LEVEL_WEIGHT_MIN_POS - sum ( LEVEL_WEIGHT )
1122 // < sum ( 0 <= I < DIM_NUM ) LEVEL_WEIGHT[I] * LEVEL_1D[I]
1123 // <= LEVEL_MAX * LEVEL_WEIGHT_MIN_POS.
1124 //
1125  for ( ; ; )
1126  {
1127  sgmga_vcn_ordered ( dim_num, level_weight, level_1d_max,
1128  level_1d, q_min, q_max, &more_grids );
1129 
1130  if ( !more_grids )
1131  {
1132  break;
1133  }
1134 //
1135 // Compute the combinatorial coefficient.
1136 //
1137  coef = sgmga_vcn_coef ( dim_num, level_weight, level_1d,
1138  q_max );
1139 
1140  if ( coef == 0.0 )
1141  {
1142  continue;
1143  }
1144 //
1145 // Transform each 1D level to a corresponding 1D order.
1146 //
1147  for ( dim = 0; dim < dim_num; dim++ )
1148  {
1149  order_1d[dim] = ((*webbur).*gw_compute_order[dim])(level_1d[dim],growth);
1150  }
1151 //
1152 // The inner loop generates a POINT of the GRID of the LEVEL.
1153 //
1154  more_points = false;
1155 
1156  for ( ; ; )
1157  {
1158  webbur->vec_colex_next3 ( dim_num, order_1d, point_index, &more_points );
1159 
1160  if ( !more_points )
1161  {
1162  break;
1163  }
1164  for ( dim = 0; dim < dim_num; dim++ )
1165  {
1166  sparse_total_order[dim+point_total_num2*dim_num] = order_1d[dim];
1167  }
1168  for ( dim = 0; dim < dim_num; dim++ )
1169  {
1170  sparse_total_index[dim+point_total_num2*dim_num] = point_index[dim];
1171  }
1172  point_total_num2 = point_total_num2 + 1;
1173  }
1174  }
1175  delete [] level_1d;
1176  delete [] order_1d;
1177  delete [] point_index;
1178 //
1179 // Now compute the coordinates of the TOTAL set of points.
1180 //
1181  sparse_total_point = new double[dim_num*point_total_num];
1182 
1183  for ( point = 0; point < point_total_num; point++ )
1184  {
1185  for ( dim = 0; dim < dim_num; dim++ )
1186  {
1187  sparse_total_point[dim+point*dim_num] = webbur->r8_huge ( );
1188  }
1189  }
1190 //
1191 // Compute the point coordinates.
1192 //
1193  level_1d_max = new int[dim_num];
1194  level_weight_min_pos = webbur->r8vec_min_pos ( dim_num, level_weight );
1195  q_max = ( double ) ( level_max ) * level_weight_min_pos;
1196 
1197  for ( dim = 0; dim < dim_num; dim++ )
1198  {
1199  if ( 0.0 < level_weight[dim] )
1200  {
1201  level_1d_max[dim] = ( int ) ( webbur->r8_floor ( q_max / level_weight[dim] ) ) + 1;
1202  if ( q_max <= ( level_1d_max[dim] - 1 ) * level_weight[dim] )
1203  {
1204  level_1d_max[dim] = level_1d_max[dim] - 1;
1205  }
1206  }
1207  else
1208  {
1209  level_1d_max[dim] = 0;
1210  }
1211 
1212  for ( level = 0; level <= level_1d_max[dim]; level++ )
1213  {
1214  order = ((*webbur).*gw_compute_order[dim]) ( level, growth );
1215 
1216  points = new double[order];
1217 
1218  ((*webbur2).*gw_compute_points[dim]) ( order, dim, points );
1219 
1220  for ( point = 0; point < point_total_num; point++ )
1221  {
1222  if ( sparse_total_order[dim+point*dim_num] == order )
1223  {
1224  sparse_total_point[dim+point*dim_num] =
1225  points[sparse_total_index[dim+point*dim_num]-1];
1226  }
1227  }
1228  delete [] points;
1229  }
1230  }
1231 //
1232 // Count the tolerably unique columns.
1233 //
1234  seed = 123456789;
1235 
1236  point_num = webbur->point_radial_tol_unique_count ( dim_num, point_total_num,
1237  sparse_total_point, tol, &seed );
1238 
1239  delete [] level_1d_max;
1240  delete [] sparse_total_index;
1241  delete [] sparse_total_order;
1242  delete [] sparse_total_point;
1243 
1244  return point_num;
1245 }
1246 //****************************************************************************80
1247 
1249 (
1250  int dim_num,
1251  double level_weight[],
1252  int level_max,
1253  int growth,
1254  int ( SandiaRules::*gw_compute_order[] ) ( int level, int growth )
1255 )
1256 
1257 //****************************************************************************80
1258 //
1259 // Purpose:
1260 //
1261 // SGMGA_SIZE_TOTAL sizes an SGMGA grid, counting duplicates.
1262 //
1263 // Discussion:
1264 //
1265 // This routine returns the total point count for an SGMGA
1266 // ( Sparse Grid of Mixed type with Growth rule and Anisotropic weights).
1267 //
1268 // The sparse grid is the logical sum of product grids.
1269 //
1270 // The sparse grid has an associated integer index LEVEL_MAX, whose lowest
1271 // value is 0. LEVEL_MAX = 0 indicates the sparse grid made up of one product
1272 // grid, which in turn is the product of 1D factor grids of the lowest level.
1273 // This usually means the sparse grid with LEVEL_MAX equal to 0 is a
1274 // one point grid.
1275 //
1276 // We can assign a level to each factor grid, and hence a LEVEL vector
1277 // to the corresponding product grid, and a weighted index
1278 // LEVEL_GRID (which will in general be a real number):
1279 //
1280 // LEVEL_GRID = sum ( 1 <= I <= DIM_NUM ) LEVEL_WEIGHT(I) * LEVEL(I)
1281 //
1282 // The product grid will participate in the formation of the sparse grid
1283 // if it satisfies the following weighted constraint:
1284 //
1285 // LEVEL_MAX - DIM_NUM < LEVEL_GRID <= LEVEL_MAX
1286 //
1287 // This routine determines the total number of abscissas in all the
1288 // product rules used to form the SGMGA associated with the index LEVEL_MAX.
1289 // The count disregards duplication. If the same multidimensional abcsissa
1290 // occurs in two different product rules that are part of the SGMGA, then
1291 // that single abcissa is counted twice.
1292 //
1293 // This computation is useful in cases where the entire set of abscissas
1294 // is going to be generated, preparatory to compression to finding, indexing
1295 // and merging the duplicate abcissass.
1296 //
1297 // Licensing:
1298 //
1299 // This code is distributed under the GNU LGPL license.
1300 //
1301 // Modified:
1302 //
1303 // 13 January 2012
1304 //
1305 // Author:
1306 //
1307 // John Burkardt
1308 //
1309 // Reference:
1310 //
1311 // Fabio Nobile, Raul Tempone, Clayton Webster,
1312 // A Sparse Grid Stochastic Collocation Method for Partial Differential
1313 // Equations with Random Input Data,
1314 // SIAM Journal on Numerical Analysis,
1315 // Volume 46, Number 5, 2008, pages 2309-2345.
1316 //
1317 // Fabio Nobile, Raul Tempone, Clayton Webster,
1318 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
1319 // Differential Equations with Random Input Data,
1320 // SIAM Journal on Numerical Analysis,
1321 // Volume 46, Number 5, 2008, pages 2411-2442.
1322 //
1323 // Parameters:
1324 //
1325 // Input, int DIM_NUM, the spatial dimension.
1326 //
1327 // Input, double LEVEL_WEIGHT[DIM_NUM], the anisotropic weights.
1328 //
1329 // Input, int LEVEL_MAX, the maximum value of LEVEL.
1330 //
1331 // Input, int GROWTH, the growth rule.
1332 // 0, slow;
1333 // 1, moderate;
1334 // 2, full.
1335 //
1336 // Input, int ( *GW_COMPUTE_ORDER[] ) ( int level, int growth ),
1337 // an array of pointers to functions which return the order of the
1338 // 1D quadrature rule of a given level and growth rule.
1339 //
1340 // Output, int SGMGA_SIZE_TOTAL, the number of points
1341 // including repetitions.
1342 //
1343 {
1344  double coef;
1345  int dim;
1346  int *level_1d;
1347  int *level_1d_max;
1348  double level_weight_min_pos;
1349  bool more_grids;
1350  int *order_1d;
1351  int point_total_num;
1352  double q_max;
1353  double q_min;
1354 //
1355 // Special case.
1356 //
1357  if ( level_max == 0 )
1358  {
1359  point_total_num = 1;
1360  return point_total_num;
1361  }
1362 
1363  point_total_num = 0;
1364 
1365  level_1d = new int[dim_num];
1366  level_1d_max = new int[dim_num];
1367  order_1d = new int[dim_num];
1368 //
1369 // Initialization for SGMGA_VCN_ORDERED.
1370 //
1371  level_weight_min_pos = webbur->r8vec_min_pos ( dim_num, level_weight );
1372  q_min = ( double ) ( level_max ) * level_weight_min_pos
1373  - webbur->r8vec_sum ( dim_num, level_weight );
1374  q_max = ( double ) ( level_max ) * level_weight_min_pos;
1375  for ( dim = 0; dim < dim_num; dim++ )
1376  {
1377  if ( 0.0 < level_weight[dim] )
1378  {
1379  level_1d_max[dim] = ( int ) ( webbur->r8_floor ( q_max / level_weight[dim] ) ) + 1;
1380  if ( q_max <= ( level_1d_max[dim] - 1 ) * level_weight[dim] )
1381  {
1382  level_1d_max[dim] = level_1d_max[dim] - 1;
1383  }
1384  }
1385  else
1386  {
1387  level_1d_max[dim] = 0;
1388  }
1389  }
1390  more_grids = false;
1391 //
1392 // Seek all vectors LEVEL_1D which satisfy the constraint:
1393 //
1394 // LEVEL_MAX * LEVEL_WEIGHT_MIN_POS - sum ( LEVEL_WEIGHT )
1395 // < sum ( 0 <= I < DIM_NUM ) LEVEL_WEIGHT[I] * LEVEL_1D[I]
1396 // <= LEVEL_MAX * LEVEL_WEIGHT_MIN_POS.
1397 //
1398  for ( ; ; )
1399  {
1400  sgmga_vcn_ordered ( dim_num, level_weight, level_1d_max,
1401  level_1d, q_min, q_max, &more_grids );
1402 
1403  if ( !more_grids )
1404  {
1405  break;
1406  }
1407 //
1408 // Compute the combinatorial coefficient.
1409 //
1410  coef = sgmga_vcn_coef ( dim_num, level_weight, level_1d,
1411  q_max );
1412 
1413  if ( coef == 0.0 )
1414  {
1415  continue;
1416  }
1417 //
1418 // Transform each 1D level to a corresponding 1D order.
1419 //
1420  for ( dim = 0; dim < dim_num; dim++ )
1421  {
1422  order_1d[dim] = ((*webbur).*gw_compute_order[dim])(level_1d[dim],growth);
1423  }
1424  point_total_num = point_total_num + webbur->i4vec_product ( dim_num,
1425  order_1d );
1426  }
1427  delete [] level_1d;
1428  delete [] level_1d_max;
1429  delete [] order_1d;
1430 
1431  return point_total_num;
1432 }
1433 //****************************************************************************80
1434 
1436 (
1437  int dim_num,
1438  double level_weight[],
1439  int level_max,
1440  void ( SandiaRules2::*gw_compute_points[] ) ( int order, int dim, double x[] ),
1441  double tol,
1442  int point_num,
1443  int point_total_num,
1444  int growth,
1445  int ( SandiaRules::*gw_compute_order[] ) ( int level, int growth ),
1446  int sparse_unique_index[]
1447 )
1448 
1449 //****************************************************************************80
1450 //
1451 // Purpose:
1452 //
1453 // SGMGA_UNIQUE_INDEX maps nonunique to unique points.
1454 //
1455 // Discussion:
1456 //
1457 // The sparse grid usually contains many points that occur in more
1458 // than one product grid.
1459 //
1460 // When generating the point locations, it is easy to realize that a point
1461 // has already been generated.
1462 //
1463 // But when it's time to compute the weights of the sparse grids, it is
1464 // necessary to handle situations in which weights corresponding to
1465 // the same point generated in multiple grids must be collected together.
1466 //
1467 // This routine generates ALL the points, including their multiplicities,
1468 // and figures out a mapping from them to the collapsed set of unique points.
1469 //
1470 // This mapping can then be used during the weight calculation so that
1471 // a contribution to the weight gets to the right place.
1472 //
1473 // The user must preallocate space for the output array SPARSE_UNIQUE_INDEX.
1474 //
1475 // Licensing:
1476 //
1477 // This code is distributed under the GNU LGPL license.
1478 //
1479 // Modified:
1480 //
1481 // 13 January 2012
1482 //
1483 // Author:
1484 //
1485 // John Burkardt
1486 //
1487 // Reference:
1488 //
1489 // Fabio Nobile, Raul Tempone, Clayton Webster,
1490 // A Sparse Grid Stochastic Collocation Method for Partial Differential
1491 // Equations with Random Input Data,
1492 // SIAM Journal on Numerical Analysis,
1493 // Volume 46, Number 5, 2008, pages 2309-2345.
1494 //
1495 // Fabio Nobile, Raul Tempone, Clayton Webster,
1496 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
1497 // Differential Equations with Random Input Data,
1498 // SIAM Journal on Numerical Analysis,
1499 // Volume 46, Number 5, 2008, pages 2411-2442.
1500 //
1501 // Parameters:
1502 //
1503 // Input, int DIM_NUM, the spatial dimension.
1504 //
1505 // Input, int LEVEL_MAX, the maximum value of LEVEL.
1506 //
1507 // Input, double LEVEL_WEIGHT[DIM_NUM], the anisotropic weights.
1508 //
1509 // Input, void ( *GW_COMPUTE_POINTS[] ) ( int order, int dim, double x[] ),
1510 // an array of pointers to functions which return the 1D quadrature points
1511 // associated with each spatial dimension for which a Golub Welsch rule
1512 // is used.
1513 //
1514 // Input, double TOL, a tolerance for point equality.
1515 //
1516 // Input, int POINT_NUM, the number of unique points
1517 // in the grid.
1518 //
1519 // Input, int POINT_TOTAL_NUM, the total number of points
1520 // in the grid.
1521 //
1522 // Input, int GROWTH, the growth rule.
1523 // 0, slow;
1524 // 1, moderate;
1525 // 2, full.
1526 //
1527 // Input, int ( *GW_COMPUTE_ORDER[] ) ( int level, int growth ),
1528 // an array of pointers to functions which return the order of the
1529 // 1D quadrature rule of a given level and growth rule.
1530 // Output, int SPARSE UNIQUE_INDEX[POINT_TOTAL_NUM], lists,
1531 // for each (nonunique) point, the corresponding index of the same point in
1532 // the unique listing.
1533 //
1534 {
1535  double coef;
1536  int dim;
1537  int level;
1538  int *level_1d;
1539  int *level_1d_max;
1540  double level_weight_min_pos;
1541  bool more_grids;
1542  bool more_points;
1543  int order;
1544  int *order_1d;
1545  int point;
1546  int *point_index;
1547  //int point_num2;
1548  int point_total_num2;
1549  double *points;
1550  double q_max;
1551  double q_min;
1552  int rep;
1553  int seed;
1554  int *sparse_total_index;
1555  int *sparse_total_order;
1556  double *sparse_total_point;
1557  int *undx;
1558 //
1559 // Special cases.
1560 //
1561  if ( level_max < 0 )
1562  {
1563  return;
1564  }
1565 
1566  if ( level_max == 0 )
1567  {
1568  sparse_unique_index[0] = 0;
1569  return;
1570  }
1571 //
1572 // Generate SPARSE_TOTAL_ORDER and SPARSE_TOTAL_INDEX arrays
1573 // for the TOTAL set of points.
1574 //
1575  sparse_total_order = new int[dim_num*point_total_num];
1576  sparse_total_index = new int[dim_num*point_total_num];
1577 
1578  level_1d = new int[dim_num];
1579  level_1d_max = new int[dim_num];
1580  order_1d = new int[dim_num];
1581  point_index = new int[dim_num];
1582 
1583  point_total_num2 = 0;
1584 //
1585 // Initialization for SGMGA_VCN_ORDERED.
1586 //
1587  level_weight_min_pos = webbur->r8vec_min_pos ( dim_num, level_weight );
1588  q_min = ( double ) ( level_max ) * level_weight_min_pos
1589  - webbur->r8vec_sum ( dim_num, level_weight );
1590  q_max = ( double ) ( level_max ) * level_weight_min_pos;
1591  for ( dim = 0; dim < dim_num; dim++ )
1592  {
1593  if ( 0.0 < level_weight[dim] )
1594  {
1595  level_1d_max[dim] = ( int ) ( webbur->r8_floor ( q_max / level_weight[dim] ) ) + 1;
1596  if ( q_max <= ( level_1d_max[dim] - 1 ) * level_weight[dim] )
1597  {
1598  level_1d_max[dim] = level_1d_max[dim] - 1;
1599  }
1600  }
1601  else
1602  {
1603  level_1d_max[dim] = 0;
1604  }
1605  }
1606  more_grids = false;
1607 //
1608 // Seek all vectors LEVEL_1D which satisfy the constraint:
1609 //
1610 // LEVEL_MAX * LEVEL_WEIGHT_MIN_POS - sum ( LEVEL_WEIGHT )
1611 // < sum ( 0 <= I < DIM_NUM ) LEVEL_WEIGHT[I] * LEVEL_1D[I]
1612 // <= LEVEL_MAX * LEVEL_WEIGHT_MIN_POS.
1613 //
1614  for ( ; ; )
1615  {
1616  sgmga_vcn_ordered ( dim_num, level_weight, level_1d_max,
1617  level_1d, q_min, q_max, &more_grids );
1618 
1619  if ( !more_grids )
1620  {
1621  break;
1622  }
1623 //
1624 // Compute the combinatorial coefficient.
1625 //
1626  coef = sgmga_vcn_coef ( dim_num, level_weight, level_1d,
1627  q_max );
1628 
1629  if ( coef == 0.0 )
1630  {
1631  continue;
1632  }
1633 //
1634 // Transform each 1D level to a corresponding 1D order.
1635 //
1636  for ( dim = 0; dim < dim_num; dim++ )
1637  {
1638  order_1d[dim] = ((*webbur).*gw_compute_order[dim])(level_1d[dim],growth);
1639  }
1640 //
1641 // The inner loop generates a POINT of the GRID of the LEVEL.
1642 //
1643  more_points = false;
1644 
1645  for ( ; ; )
1646  {
1647  webbur->vec_colex_next3 ( dim_num, order_1d, point_index, &more_points );
1648 
1649  if ( !more_points )
1650  {
1651  break;
1652  }
1653  for ( dim = 0; dim < dim_num; dim++ )
1654  {
1655  sparse_total_order[dim+point_total_num2*dim_num] = order_1d[dim];
1656  }
1657  for ( dim = 0; dim < dim_num; dim++ )
1658  {
1659  sparse_total_index[dim+point_total_num2*dim_num] = point_index[dim];
1660  }
1661  point_total_num2 = point_total_num2 + 1;
1662  }
1663  }
1664  delete [] level_1d;
1665  delete [] level_1d_max;
1666  delete [] order_1d;
1667  delete [] point_index;
1668 //
1669 // Now compute the coordinates of the TOTAL set of points.
1670 //
1671  sparse_total_point = new double[dim_num*point_total_num];
1672 
1673  for ( point = 0; point < point_total_num; point++ )
1674  {
1675  for ( dim = 0; dim < dim_num; dim++ )
1676  {
1677  sparse_total_point[dim+point*dim_num] = webbur->r8_huge ( );
1678  }
1679  }
1680 //
1681 // Compute the point coordinates.
1682 //
1683  level_1d_max = new int[dim_num];
1684  level_weight_min_pos = webbur->r8vec_min_pos ( dim_num, level_weight );
1685  q_max = ( double ) ( level_max ) * level_weight_min_pos;
1686 
1687  for ( dim = 0; dim < dim_num; dim++ )
1688  {
1689  if ( 0.0 < level_weight[dim] )
1690  {
1691  level_1d_max[dim] = ( int ) ( webbur->r8_floor ( q_max / level_weight[dim] ) ) + 1;
1692  if ( q_max <= ( level_1d_max[dim] - 1 ) * level_weight[dim] )
1693  {
1694  level_1d_max[dim] = level_1d_max[dim] - 1;
1695  }
1696  }
1697  else
1698  {
1699  level_1d_max[dim] = 0;
1700  }
1701 
1702  for ( level = 0; level <= level_1d_max[dim]; level++ )
1703  {
1704  order = ((*webbur).*gw_compute_order[dim]) ( level, growth );
1705 
1706  points = new double[order];
1707 
1708  ((*webbur2).*gw_compute_points[dim]) ( order, dim, points );
1709 
1710  for ( point = 0; point < point_total_num; point++ )
1711  {
1712  if ( sparse_total_order[dim+point*dim_num] == order )
1713  {
1714  sparse_total_point[dim+point*dim_num] =
1715  points[sparse_total_index[dim+point*dim_num]-1];
1716  }
1717  }
1718  delete [] points;
1719  }
1720  }
1721 //
1722 // Merge points that are too close.
1723 //
1724  seed = 123456789;
1725 
1726  undx = new int[point_num];
1727 
1728  //point_num2 = webbur->point_radial_tol_unique_index ( dim_num, point_total_num,
1729  // sparse_total_point, tol, &seed, undx, sparse_unique_index );
1730  webbur->point_radial_tol_unique_index ( dim_num, point_total_num,
1731  sparse_total_point, tol, &seed, undx, sparse_unique_index );
1732 
1733  for ( point = 0; point < point_total_num; point++ )
1734  {
1735  rep = undx[sparse_unique_index[point]];
1736  if ( point != rep )
1737  {
1738  for ( dim = 0; dim < dim_num; dim++ )
1739  {
1740  sparse_total_point[dim+point*dim_num] = sparse_total_point[dim+rep*dim_num];
1741  }
1742  }
1743  }
1744 //
1745 // Construct an index that indicates the "rank" of the unique points.
1746 //
1747  webbur->point_unique_index ( dim_num, point_total_num, sparse_total_point,
1748  point_num, undx, sparse_unique_index );
1749 
1750  delete [] sparse_total_index;
1751  delete [] sparse_total_order;
1752  delete [] sparse_total_point;
1753  delete [] undx;
1754 
1755  return;
1756 }
1757 //****************************************************************************80
1758 
1760 (
1761  int n,
1762  double w[],
1763  int x[],
1764  double q_min,
1765  double q_max,
1766  bool *more
1767 )
1768 
1769 //****************************************************************************80
1770 //
1771 // Purpose:
1772 //
1773 // SGMGA_VCN returns the next constrained vector.
1774 //
1775 // Discussion:
1776 //
1777 // This function is intended to replace the "naive" version, now called
1778 // SGMGA_VCN_NAIVE, which is too slow for high dimensional problems.
1779 //
1780 // For nonnegative vectors X of dimension N, and nonnegative
1781 // weights W, we define:
1782 //
1783 // Q = sum ( 1 <= I <= N ) W(I) * X(I)
1784 //
1785 // and seek X satisfying the constraint:
1786 //
1787 // Q_MIN < Q <= Q_MAX
1788 //
1789 // This routine returns, one at a time exactly those X which satisfy
1790 // the constraint. No attempt is made to return the X values in
1791 // any particular order as far as Q goes.
1792 //
1793 // Example:
1794 //
1795 // W 4.0 3.0 5.0
1796 // MIN 16.0 0 0 0
1797 // --- ---- -----------
1798 // 1 20.0 5 0 0
1799 // 2 19.0 4 1 0
1800 // 3 18.0 3 2 0
1801 // 4 17.0 2 3 0
1802 // 5 20.0 2 4 0
1803 // 6 19.0 1 5 0
1804 // 7 18.0 0 6 0
1805 // 8 17.0 3 0 1
1806 // 9 20.0 3 1 1
1807 // 10 19.0 2 2 1
1808 // 11 18.0 1 3 1
1809 // 12 17.0 0 4 1
1810 // 13 20.0 0 5 1
1811 // 14 18.0 2 0 2
1812 // 15 17.0 1 1 2
1813 // 16 20.0 1 2 2
1814 // 17 19.0 0 3 2
1815 // 18 19.0 1 0 3
1816 // 19 18.0 0 1 3
1817 // 20 20.0 0 0 4
1818 // --- ---- ----------
1819 // MAX 20.0 6 7 5
1820 //
1821 // Licensing:
1822 //
1823 // This code is distributed under the GNU LGPL license.
1824 //
1825 // Modified:
1826 //
1827 // 21 May 2010
1828 //
1829 // Author:
1830 //
1831 // John Burkardt
1832 //
1833 // Reference:
1834 //
1835 // Fabio Nobile, Raul Tempone, Clayton Webster,
1836 // A Sparse Grid Stochastic Collocation Method for Partial Differential
1837 // Equations with Random Input Data,
1838 // SIAM Journal on Numerical Analysis,
1839 // Volume 46, Number 5, 2008, pages 2309-2345.
1840 //
1841 // Fabio Nobile, Raul Tempone, Clayton Webster,
1842 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
1843 // Differential Equations with Random Input Data,
1844 // SIAM Journal on Numerical Analysis,
1845 // Volume 46, Number 5, 2008, pages 2411-2442.
1846 //
1847 // Parameters:
1848 //
1849 // Input, int N, the dimension of the vector.
1850 //
1851 // Input, double W[N], the weights, which should be nonnegative.
1852 // At least one weight must be positive.
1853 //
1854 // Input/output, int X[N]. On first call, with
1855 // MORE = FALSE, the input value of X is not important. On subsequent calls,
1856 // the input value of X should be the output value from the previous call.
1857 // On output, (with MORE = TRUE), the value of X will be the "next"
1858 // vector in the reverse lexicographical list of vectors that satisfy
1859 // the condition. However, on output with MORE = FALSE, the vector
1860 // X is meaningless, because there are no more vectors in the list.
1861 //
1862 // Input, double Q_MIN, Q_MAX, the lower and upper limits on the sum.
1863 //
1864 // Input/output, bool *MORE. On input, if the user has set MORE
1865 // FALSE, the user is requesting the initiation of a new sequence
1866 // of values. If MORE is TRUE, then the user is requesting "more"
1867 // values in the current sequence. On output, if MORE is TRUE,
1868 // then another value was found and returned in X, but if MORE is
1869 // FALSE, then there are no more values in the sequence, and X is
1870 // NOT the next value.
1871 //
1872 {
1873  static int dir;
1874  int i;
1875  static int n2;
1876  static int nstart;
1877  double t;
1878  static int *xmax;
1879  static int xmin;
1880 //
1881 // Initialization for first call.
1882 //
1883 // Allocate XMAX to remember the currently maximum possible value for each X.
1884 //
1885 // Locate NSTART, the index of the first nonzero weight.
1886 // The algorithm is easier to program if the last index we look at
1887 // has a nonzero weight, so that it can always make up the remainder.
1888 //
1889  if ( !(*more) )
1890  {
1891  xmax = new int[n];
1892 
1893  nstart = - 1;
1894 
1895  for ( i = 0; i < n; i++ )
1896  {
1897  if ( 0.0 < w[i] )
1898  {
1899  nstart = i;
1900  break;
1901  }
1902  }
1903 //
1904 // Theoretically, we could even handle the case where all weights are zero.
1905 // That case is ruled out elsewhere in this software, so I will not try
1906 // to deal with it here for now.
1907 //
1908  if ( nstart == - 1 )
1909  {
1910  std::cerr << "\n";
1911  std::cerr << " SGMGA_VCN - Fatal error!\n";
1912  std::cerr << " No weight is positive.\n";
1913  std::exit ( 1 );
1914  }
1915 //
1916 // Initialize X to zero, even the indices we ignore.
1917 //
1918  for ( i = 0; i < n; i++ )
1919  {
1920  x[i] = 0;
1921  }
1922 //
1923 // N2 points to our current index of interest.
1924 //
1925  n2 = n;
1926  dir = - 1;
1927 
1928  *more = true;
1929  }
1930 //
1931 // Look for the next solution vector X.
1932 //
1933  for ( ; ; )
1934  {
1935 //
1936 // If no more, the search is terminated.
1937 //
1938  if ( !(*more) )
1939  {
1940  break;
1941  }
1942 //
1943 // DIR = -1, decrement N2, and, if possible, set X[N2] to XMIN.
1944 // DIR = 0, hold N2 at current value, and see if we can increment X[N2].
1945 //
1946  else if ( dir == - 1 || dir == 0 )
1947  {
1948  if ( dir == - 1 )
1949  {
1950  n2 = n2 - 1;
1951  }
1952 
1953  if ( w[n2] == 0.0 )
1954  {
1955  xmin = 0;
1956  xmax[n2] = 0;
1957  }
1958  else if ( nstart < n2 )
1959  {
1960  xmin = 0;
1961  t = q_max;
1962  for ( i = n2 + 1; i < n; i++ )
1963  {
1964  t = t - w[i] * ( double ) x[i];
1965  }
1966  xmax[n2] = ( int ) ( webbur->r8_floor ( t / w[n2] ) );
1967  }
1968  else if ( n2 == nstart && dir == - 1 )
1969  {
1970  t = q_min;
1971  for ( i = n2 + 1; i < n; i++ )
1972  {
1973  t = t - w[i] * ( double ) x[i];
1974  }
1975  xmin = ( int ) ( webbur->r8_ceiling ( t / w[n2] ) );
1976  if ( xmin < 0 )
1977  {
1978  xmin = 0;
1979  }
1980  t = 0.0;
1981  for ( i = 0; i < n2; i++ )
1982  {
1983  t = t + w[i] * ( double ) x[i];
1984  }
1985  t = t + w[n2] * xmin;
1986  for ( i = n2 + 1; i < n; i++ )
1987  {
1988  t = t + w[i] * ( double ) x[i];
1989  }
1990  if ( t <= q_min )
1991  {
1992  xmin = xmin + 1;
1993  }
1994  x[n2] = xmin;
1995  t = q_max;
1996  for ( i = n2 + 1; i < n; i++ )
1997  {
1998  t = t - w[i] * ( double ) x[i];
1999  }
2000  xmax[n2] = ( int ) ( webbur->r8_floor ( t / w[n2] ) );
2001  }
2002 
2003  if ( xmax[n2] < xmin )
2004  {
2005  dir = + 1;
2006  }
2007  else
2008  {
2009  if ( n2 == nstart )
2010  {
2011  if ( dir == - 1 )
2012  {
2013  dir = 0;
2014  break;
2015  }
2016  else if ( dir == 0 )
2017  {
2018  x[n2] = x[n2] + 1;
2019  if ( x[n2] <= xmax[n2] )
2020  {
2021  break;
2022  }
2023  else
2024  {
2025  dir = + 1;
2026  }
2027  }
2028  }
2029  else
2030  {
2031  x[n2] = xmin;
2032  }
2033  }
2034  }
2035 //
2036 // DIR = + 1:
2037 // Try moving backwards to find an index N2 whose X we can increment.
2038 //
2039  else if ( dir == + 1 )
2040  {
2041  for ( ; ; )
2042  {
2043  if ( n2 == n - 1 )
2044  {
2045  dir = 0;
2046  *more = false;
2047  delete [] xmax;
2048  break;
2049  }
2050 
2051  n2 = n2 + 1;
2052 
2053  if ( 0.0 < w[n2] )
2054  {
2055  if ( x[n2] < xmax[n2] )
2056  {
2057  x[n2] = x[n2] + 1;
2058  dir = - 1;
2059  break;
2060  }
2061  }
2062  }
2063  }
2064  }
2065  return;
2066 }
2067 //****************************************************************************80
2068 
2070 (
2071  int dim_num,
2072  double level_weight[],
2073  int x[],
2074  double q_max
2075 )
2076 
2077 //****************************************************************************80
2078 //
2079 // Purpose:
2080 //
2081 // SGMGA_VCN_COEF returns the "next" constrained vector's coefficient.
2082 //
2083 // Discussion:
2084 //
2085 // The related code "SGMGA_VCN_COEF_NAIVE" represents a "naive"
2086 // approach to this calculation. This code carries out the same calculation, but tries
2087 // to avoid the potential explosion in work that is exponential in the
2088 // spatial dimension for the naive approach.
2089 //
2090 // We are considering integer vectors X of dimension DIM_NUM for which
2091 // the functional
2092 //
2093 // Q(X) = sum ( 1 <= I <= DIM_NUM ) LEVEL_WEIGHT(I) * X(I)
2094 //
2095 // satisfies the "Q" constraint:
2096 //
2097 // Q_MIN < Q(X) <= Q_MAX
2098 //
2099 // where LEVEL_WEIGHT is a vector of (essentially) positive weights.
2100 // Some, but not all of the entries of LEVEL_WEIGHT might be zero;
2101 // in that case, the corresponding values of X never vary, and do not
2102 // play a part in the following computation.
2103 //
2104 // Supposing we have a suitable vector X, we now wish to count the
2105 // number of distinct vectors Y which also satisfy the Q constraint
2106 // as well as the following "binary" constraint:
2107 //
2108 // Y(I) = X(I) + B(I)
2109 //
2110 // where every entry of B is 0 or 1.
2111 //
2112 // Clearly, there are 2^DIM_NUM vectors Y which satisfy the binary
2113 // constraint, and a naive calculation would simply generate each
2114 // possible Y, evaluate Q(Y), and if Y satisfies the Q constraint,
2115 // add it to the count.
2116 //
2117 // But if we are considering even moderately large values of DIM_NUM,
2118 // say 20 <= DIM_NUM, then the mere task of generating all possible
2119 // Y vectors is burdensome. If there are in fact likely to be only
2120 // a few satisfactory Y vectors, (which depends on the values of
2121 // Q_MAX and LEVEL_WEIGHT, of course) then it may be possible to
2122 // find and count them more rapidly.
2123 //
2124 // This function attempts a more rapid computation by carrying out the
2125 // search in a particular order, and realizing that, in certain cases,
2126 // if a particular value Y* does not satisfy the Q constraint, then
2127 // a consecutive sequence of Y's following Y* also cannot satisfy the
2128 // constraint, and hence the search can jump over them.
2129 //
2130 // Example:
2131 //
2132 // DIM_NUM = 3
2133 // LEVEL_WEIGHT 3.0 2.0 1.0
2134 // Q_MAX 6.0
2135 //
2136 // U = unsigned count
2137 // S = signed count returned as COEF
2138 //
2139 // # U S X1 X2 X3
2140 //
2141 // 1 8 0 0 0 0
2142 // 2 7 1 0 0 1
2143 // 3 6 0 0 0 2
2144 // 4 5 -1 0 0 3
2145 // 5 3 -1 0 0 4
2146 // 6 2 0 0 0 5
2147 // 7 1 1 0 0 6
2148 // 8 6 0 0 1 0
2149 // 9 5 -1 0 1 1
2150 // 10 3 -1 0 1 2
2151 // 11 2 0 0 1 3
2152 // 12 1 1 0 1 4
2153 // 13 3 -1 0 2 0
2154 // 14 2 0 0 2 1
2155 // 15 1 1 0 2 2
2156 // 16 1 1 0 3 0
2157 // 17 5 -1 1 0 0
2158 // 18 3 -1 1 0 1
2159 // 19 2 0 1 0 2
2160 // 20 1 1 1 0 3
2161 // 21 2 0 1 1 0
2162 // 22 1 1 1 1 1
2163 // 23 1 1 2 0 0
2164 //
2165 // Licensing:
2166 //
2167 // This code is distributed under the GNU LGPL license.
2168 //
2169 // Modified:
2170 //
2171 // 15 May 2010
2172 //
2173 // Author:
2174 //
2175 // John Burkardt
2176 //
2177 // Reference:
2178 //
2179 // Fabio Nobile, Raul Tempone, Clayton Webster,
2180 // A Sparse Grid Stochastic Collocation Method for Partial Differential
2181 // Equations with Random Input Data,
2182 // SIAM Journal on Numerical Analysis,
2183 // Volume 46, Number 5, 2008, pages 2309-2345.
2184 //
2185 // Fabio Nobile, Raul Tempone, Clayton Webster,
2186 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
2187 // Differential Equations with Random Input Data,
2188 // SIAM Journal on Numerical Analysis,
2189 // Volume 46, Number 5, 2008, pages 2411-2442.
2190 //
2191 // Parameters:
2192 //
2193 // Input, int DIM_NUM, the spatial dimension.
2194 //
2195 // Input, double LEVEL_WEIGHT[DIM_NUM], the weights.
2196 //
2197 // Input, int X[DIM_NUM], satisfies the Q constraint.
2198 //
2199 // Input, double Q_MAX, the Q constraint maximum.
2200 //
2201 // Output, double SGMGA_VCN_COEF, the combinatorial coefficient.
2202 //
2203 {
2204  int *b;
2205  int b_sum;
2206  int c;
2207  double coef;
2208  int i;
2209  int j;
2210  double q;
2211 
2212  c = 0;
2213  b = new int[dim_num];
2214 
2215  for ( i = 0; i < dim_num; i++ )
2216  {
2217  b[i] = 0;
2218  }
2219 
2220  for ( ; ; )
2221  {
2222 //
2223 // Generate the next binary perturbation.
2224 //
2225  i = - 1;
2226 
2227  while ( i < dim_num - 1 )
2228  {
2229  i = i + 1;
2230 //
2231 // If LEVEL_WEIGHT(I) == 0, B(I) is fixed at 0. Next I.
2232 //
2233  if ( level_weight[i] == 0.0 )
2234  {
2235  }
2236 //
2237 // If B(I) is 1, set it to 0. Next I.
2238 //
2239  else if ( b[i] == 1 )
2240  {
2241  b[i] = 0;
2242  }
2243 //
2244 // B(I) is 0. Convert it to 1.
2245 //
2246  else
2247  {
2248  b[i] = 1;
2249 
2250  for ( ; ; )
2251  {
2252 //
2253 // Does X + B satisfy the Q_MAX constraint?
2254 //
2255  q = 0.0;
2256  for ( j = 0; j < dim_num; j++ )
2257  {
2258  q = q + level_weight[j] * ( double ) ( x[j] + b[j] );
2259  }
2260  if ( q <= q_max )
2261  {
2262  break;
2263  }
2264 //
2265 // If Q(X+B) now exceeds QMAX, B is rejected. But we can also skip
2266 // all perturbations which agree with B through the I-th position.
2267 // To skip to the next "interesting" candidate, we essentially carry
2268 // out binary addition between B and a vector B' which has a single 1
2269 // in the I-th position.
2270 //
2271  b[i] = 0;
2272 
2273  while ( i < dim_num - 1 )
2274  {
2275  i = i + 1;
2276 
2277  if ( level_weight[i] == 0.0 )
2278  {
2279  }
2280  else if ( b[i] == 1 )
2281  {
2282  b[i] = 0;
2283  }
2284  else
2285  {
2286  b[i] = 1;
2287  break;
2288  }
2289  }
2290  }
2291  break;
2292  }
2293  }
2294  b_sum = 0;
2295  for ( j = 0; j < dim_num; j++ )
2296  {
2297  b_sum = b_sum + b[j];
2298  }
2299 //
2300 // X+B is another solution to be counted.
2301 //
2302  c = c + 1 - 2 * ( b_sum % 2 );
2303 //
2304 // We're done if we've got back to 0.
2305 //
2306  if ( b_sum == 0 )
2307  {
2308  break;
2309  }
2310  }
2311  coef = ( double ) ( c );
2312  delete [] b;
2313 
2314  return coef;
2315 }
2316 //****************************************************************************80
2317 
2320  int dim_num,
2321  double level_weight[],
2322  int x_max[],
2323  int x[],
2324  double q_min,
2325  double q_max
2326 )
2327 
2328 //****************************************************************************80
2329 //
2330 // Purpose:
2331 //
2332 // SGMGA_VCN_COEF_NAIVE: "next" constrained vector's coefficient.
2333 //
2334 // Discussion:
2335 //
2336 // This function uses a naive approach to the computation, resulting in
2337 // a set of 2^DIM_NUM tasks. Hence it is not suitable for cases where
2338 // DIM_NUM is moderately large. The function SGMGA_VCN_COEF carries out
2339 // a more complicated but more efficient algorithm for the same computation.
2340 //
2341 // We are given a vector X of dimension DIM_NUM which satisfies:
2342 // the following constraint:
2343 //
2344 // sum ( 1 <= I <= DIM_NUM ) LEVEL_WEIGHT(I) * X(I) <= Q_MAX
2345 //
2346 // This routine computes the appropriate coefficient for X in the
2347 // anisotropic sparse grid scheme.
2348 //
2349 // The coefficient is calculated as follows:
2350 //
2351 // Let B be a binary vector of length DIM_NUM, and let ||B|| represent
2352 // the sum of the entries of B.
2353 //
2354 // Coef = sum ( all B such that X+B satisfies constraints ) (-1)^||B||
2355 //
2356 // Since X+0 satisfies the constraint, there is always at least one
2357 // summand.
2358 //
2359 // Licensing:
2360 //
2361 // This code is distributed under the GNU LGPL license.
2362 //
2363 // Modified:
2364 //
2365 // 15 May 2010
2366 //
2367 // Author:
2368 //
2369 // John Burkardt
2370 //
2371 // Reference:
2372 //
2373 // Fabio Nobile, Raul Tempone, Clayton Webster,
2374 // A Sparse Grid Stochastic Collocation Method for Partial Differential
2375 // Equations with Random Input Data,
2376 // SIAM Journal on Numerical Analysis,
2377 // Volume 46, Number 5, 2008, pages 2309-2345.
2378 //
2379 // Fabio Nobile, Raul Tempone, Clayton Webster,
2380 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
2381 // Differential Equations with Random Input Data,
2382 // SIAM Journal on Numerical Analysis,
2383 // Volume 46, Number 5, 2008, pages 2411-2442.
2384 //
2385 // Parameters:
2386 //
2387 // Input, int DIM_NUM, the number of components in the vector.
2388 //
2389 // Input, double LEVEL_WEIGHT[DIM_NUM], the anisotropic weights.
2390 //
2391 // Input, int X_MAX[DIM_NUM], the maximum values allowed in each component.
2392 //
2393 // Input, int X[DIM_NUM], a point which satisifies the constraints.
2394 //
2395 // Input, double Q_MIN, Q_MAX, the lower and upper limits on the sum.
2396 //
2397 // Output, double SGMGA_VCN_COEF_NAIVE, the combinatorial coefficient.
2398 //
2399 {
2400  int *b;
2401  int b_sum;
2402  double coef;
2403  int i;
2404  double q;
2405  bool too_big;
2406 
2407  b = new int[dim_num];
2408 
2409  for ( i = 0; i < dim_num; i++ )
2410  {
2411  b[i] = 0;
2412  }
2413  coef = 1.0;
2414 
2415  for ( ; ; )
2416  {
2417 //
2418 // Generate the next binary perturbation.
2419 //
2420  webbur->binary_vector_next ( dim_num, b );
2421  b_sum = webbur->i4vec_sum ( dim_num, b );
2422 //
2423 // We're done if we've got back to 0.
2424 //
2425  if ( b_sum == 0 )
2426  {
2427  break;
2428  }
2429 //
2430 // Does it satisfy the XMAX constraint?
2431 // (THIS CHECK IS SURPRISINGLY NECESSARY, PARTLY BECAUSE OF ZERO WEIGHT).
2432 //
2433  too_big = false;
2434  for ( i = 0; i < dim_num; i++ )
2435  {
2436  if ( x_max[i] < x[i] + b[i] )
2437  {
2438  too_big = true;
2439  break;
2440  }
2441  }
2442  if ( too_big )
2443  {
2444  continue;
2445  }
2446 //
2447 // Does it satisfy the Q_MAX constraint?
2448 //
2449  q = 0.0;
2450  for ( i = 0; i < dim_num; i++ )
2451  {
2452  q = q + level_weight[i] * ( double ) ( x[i] + b[i] );
2453  }
2454 
2455  if ( q <= q_max )
2456  {
2457  coef = coef + webbur->r8_mop ( b_sum );
2458  }
2459  }
2460 
2461  delete [] b;
2462 
2463  return coef;
2464 }
2465 //****************************************************************************80
2466 
2469  int dim_num,
2470  double level_weight[],
2471  int x_max[],
2472  int x[],
2473  double q_min,
2474  double q_max,
2475  bool *more
2476 )
2477 
2478 //****************************************************************************80
2479 //
2480 // Purpose:
2481 //
2482 // SGMGA_VCN_NAIVE returns the next constrained vector.
2483 //
2484 // Discussion:
2485 //
2486 // This function uses a naive algorithm, which quickly becomes unsuitable
2487 // for higher dimensions. The function SGMGA_VCN is an attempt at
2488 // a more efficient calculation of the same quantities.
2489 //
2490 // We consider vectors X of dimension DIM_NUM satisfying:
2491 //
2492 // 0 <= X(1:DIM_NUM) <= X_MAX(1:DIM_NUM).
2493 //
2494 // and define
2495 //
2496 // Q = sum ( 1 <= I <= DIM_NUM ) LEVEL_WEIGHT(I) * X(I)
2497 //
2498 // and seek X satisfying the constraint:
2499 //
2500 // Q_MIN < Q <= Q_MAX
2501 //
2502 // For sparse grid applications, we compute
2503 //
2504 // LEVEL_WEIGHT_MIN_POS = minimum positive entry in LEVEL_WEIGHT
2505 //
2506 // and assume there is an underlying LEVEL used to index the sets of
2507 // constrained vectors, and that
2508 //
2509 // Q_MAX = LEVEL * LEVEL_WEIGHT_MIN_POS
2510 // Q_MIN = LEVEL - LEVEL_WEIGHT_MIN_POS * sum ( LEVEL_WEIGHT(:) )
2511 // X_MAX(I) = LEVEL * LEVEL_WEIGHT_MIN_POS / LEVEL_WEIGHT(I)
2512 //
2513 // This routine returns, one at a time exactly those X which satisfy
2514 // the constraint. No attempt is made to return the X values in
2515 // any particular order as far as Q goes.
2516 //
2517 // Example:
2518 //
2519 // LEVEL_WEIGHT: 1.000000 1.000000
2520 //
2521 // Q_MIN: 0.000000
2522 // Q_MAX: 2.000000
2523 // X_MAX: 2 2
2524 //
2525 // 1 1.000000 1 0
2526 // 2 2.000000 2 0
2527 // 3 1.000000 0 1
2528 // 4 2.000000 1 1
2529 // 5 2.000000 0 2
2530 //
2531 // LEVEL_WEIGHT: 1.000000 2.000000
2532 //
2533 // Q_MIN: -1.000000
2534 // Q_MAX: 2.000000
2535 // X_MAX: 2 1
2536 //
2537 // 1 0.000000 0 0
2538 // 2 1.000000 1 0
2539 // 3 2.000000 2 0
2540 // 4 2.000000 0 1
2541 //
2542 // Licensing:
2543 //
2544 // This code is distributed under the GNU LGPL license.
2545 //
2546 // Modified:
2547 //
2548 // 30 October 2009
2549 //
2550 // Author:
2551 //
2552 // John Burkardt
2553 //
2554 // Reference:
2555 //
2556 // Fabio Nobile, Raul Tempone, Clayton Webster,
2557 // A Sparse Grid Stochastic Collocation Method for Partial Differential
2558 // Equations with Random Input Data,
2559 // SIAM Journal on Numerical Analysis,
2560 // Volume 46, Number 5, 2008, pages 2309-2345.
2561 //
2562 // Fabio Nobile, Raul Tempone, Clayton Webster,
2563 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
2564 // Differential Equations with Random Input Data,
2565 // SIAM Journal on Numerical Analysis,
2566 // Volume 46, Number 5, 2008, pages 2411-2442.
2567 //
2568 // Parameters:
2569 //
2570 // Input, int DIM_NUM, the number of components in the vector.
2571 //
2572 // Input, double LEVEL_WEIGHT[DIM_NUM], the anisotropic weights.
2573 //
2574 // Input, int X_MAX[DIM_NUM], the maximum values allowed in each component.
2575 //
2576 // Input/output, int X[DIM_NUM]. On first call (with MORE = FALSE),
2577 // the input value of X is not important. On subsequent calls, the
2578 // input value of X should be the output value from the previous call.
2579 // On output, (with MORE = TRUE), the value of X will be the "next"
2580 // vector in the reverse lexicographical list of vectors that satisfy
2581 // the condition. However, on output with MORE = FALSE, the vector
2582 // X is meaningless, because there are no more vectors in the list.
2583 //
2584 // Input, double Q_MIN, Q_MAX, the lower and upper
2585 // limits on the sum.
2586 //
2587 // Input/output, bool *MORE. On input, if the user has set MORE
2588 // FALSE, the user is requesting the initiation of a new sequence
2589 // of values. If MORE is TRUE, then the user is requesting "more"
2590 // values in the current sequence. On output, if MORE is TRUE,
2591 // then another value was found and returned in X, but if MORE is
2592 // FALSE, then there are no more values in the sequence, and X is
2593 // NOT the next value.
2594 //
2595 {
2596  int i;
2597  int j;
2598  double q;
2599 
2600  if ( ! ( *more ) )
2601  {
2602  *more = true;
2603  for ( i = 0; i < dim_num; i++ )
2604  {
2605  x[i] = 0;
2606  }
2607 
2608  q = 0.0;
2609  for ( i = 0; i < dim_num; i++ )
2610  {
2611  q = q + level_weight[i] * ( double ) ( x[i] );
2612  }
2613 
2614  if ( q_min < q && q <= q_max )
2615  {
2616  return;
2617  }
2618  }
2619 
2620  for ( ; ; )
2621  {
2622  j = 0;
2623 
2624  for ( ; ; )
2625  {
2626  if ( x[j] < x_max[j] )
2627  {
2628  break;
2629  }
2630 
2631  if ( dim_num - 1 <= j )
2632  {
2633  *more = false;
2634  return;
2635  }
2636  j = j + 1;
2637  }
2638 
2639  x[j] = x[j] + 1;
2640  for ( i = 0; i < j; i++ )
2641  {
2642  x[i] = 0;
2643  }
2644 
2645  q = 0.0;
2646  for ( i = 0; i < dim_num; i++ )
2647  {
2648  q = q + level_weight[i] * ( double ) ( x[i] );
2649  }
2650 
2651  if ( q_min < q && q <= q_max )
2652  {
2653  break;
2654  }
2655  }
2656 
2657  return;
2658 }
2659 //****************************************************************************80
2660 
2663  int dim_num,
2664  double level_weight[],
2665  int x_max[],
2666  int x[],
2667  double q_min,
2668  double q_max,
2669  bool *more
2670 )
2671 
2672 //****************************************************************************80
2673 //
2674 // Purpose:
2675 //
2676 // SGMGA_VCN_ORDERED returns the "next" constrained vector, with ordering.
2677 //
2678 // Discussion:
2679 //
2680 // We consider vectors X of dimension DIM_NUM satisfying:
2681 //
2682 // 0 <= X(1:DIM_NUM) <= X_MAX(1:DIM_NUM).
2683 //
2684 // and define
2685 //
2686 // Q = sum ( 1 <= I <= DIM_NUM ) LEVEL_WEIGHT(I) * X(I)
2687 //
2688 // and seek X's satisfying the constraint:
2689 //
2690 // Q_MIN < Q <= Q_MAX
2691 //
2692 // For sparse grid applications, we compute
2693 //
2694 // LEVEL_WEIGHT_MIN_POS = minimum positive entry in LEVEL_WEIGHT
2695 //
2696 // and assume there is an underlying LEVEL used to index the sets of
2697 // constrained vectors, and that
2698 //
2699 // Q_MAX = LEVEL * LEVEL_WEIGHT_MIN_POS
2700 // Q_MIN = LEVEL - LEVEL_WEIGHT_MIN_POS * sum ( LEVEL_WEIGHT(:) )
2701 // X_MAX(I) = LEVEL * LEVEL_WEIGHT_MIN_POS / LEVEL_WEIGHT(I)
2702 //
2703 // This function returns, one at a time exactly those X which satisfy
2704 // the constraint.
2705 //
2706 // A weak ordering is imposed on the solution vectors. This function
2707 // subdivides the range Q_MIN through Q_MAX into subintervals of width 1, so
2708 // that the X vectors returned are roughly sorted (or at least binned)
2709 // by Q value.
2710 //
2711 // Example:
2712 //
2713 // If the weights are also integral, then the X vectors are in fact SORTED
2714 // by Q value:
2715 //
2716 // LEVEL_WEIGHT: 1.000000 1.000000
2717 // Q_MIN: 0.000000
2718 // Q_MAX: 2.000000
2719 // X_MAX: 2 2
2720 //
2721 // 1 1.000000 1 0
2722 // 2 1.000000 0 1
2723 // 3 2.000000 2 0
2724 // 4 2.000000 1 1
2725 // 5 2.000000 0 2
2726 //
2727 // When the weights are not integral, then the X values are only BINNED
2728 // by Q value, that is, we first get all X's with Q values between Q_MIN
2729 // and Q_MIN+1, then Q_MIN+1 to Q_MIN+2 and so on, as demonstrated here:
2730 //
2731 // LEVEL_WEIGHT: 1.5 1
2732 // Q_MIN: 0.5
2733 // Q_MAX: 3
2734 // X_MAX: 2 3
2735 //
2736 // 1 1.5 1 0
2737 // 2 1 0 1
2738 // 3 2.5 1 1
2739 // 4 2 0 2
2740 // 5 3 2 0
2741 // 6 3 0 3
2742 //
2743 // Licensing:
2744 //
2745 // This code is distributed under the GNU LGPL license.
2746 //
2747 // Modified:
2748 //
2749 // 30 October 2009
2750 //
2751 // Author:
2752 //
2753 // John Burkardt
2754 //
2755 // Reference:
2756 //
2757 // Fabio Nobile, Raul Tempone, Clayton Webster,
2758 // A Sparse Grid Stochastic Collocation Method for Partial Differential
2759 // Equations with Random Input Data,
2760 // SIAM Journal on Numerical Analysis,
2761 // Volume 46, Number 5, 2008, pages 2309-2345.
2762 //
2763 // Fabio Nobile, Raul Tempone, Clayton Webster,
2764 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
2765 // Differential Equations with Random Input Data,
2766 // SIAM Journal on Numerical Analysis,
2767 // Volume 46, Number 5, 2008, pages 2411-2442.
2768 //
2769 // Parameters:
2770 //
2771 // Input, int DIM_NUM, the number of components in the vector.
2772 //
2773 // Input, double LEVEL_WEIGHT[DIM_NUM], the anisotropic weights.
2774 //
2775 // Input, int X_MAX[DIM_NUM], the maximum values allowed in each component.
2776 //
2777 // Input/output, int X[DIM_NUM]. On first call (with MORE = FALSE),
2778 // the input value of X is not important. On subsequent calls, the
2779 // input value of X should be the output value from the previous call.
2780 // On output, (with MORE = TRUE), the value of X will be the "next"
2781 // vector in the reverse lexicographical list of vectors that satisfy
2782 // the condition. However, on output with MORE = FALSE, the vector
2783 // X is meaningless, because there are no more vectors in the list.
2784 //
2785 // Input, double Q_MIN, Q_MAX, the lower and upper
2786 // limits on the sum.
2787 //
2788 // Input/output, bool *MORE. On input, if the user has set MORE
2789 // FALSE, the user is requesting the initiation of a new sequence
2790 // of values. If MORE is TRUE, then the user is requesting "more"
2791 // values in the current sequence. On output, if MORE is TRUE,
2792 // then another value was found and returned in X, but if MORE is
2793 // FALSE, then there are no more values in the sequence, and X is
2794 // NOT the next value.
2795 //
2796 {
2797  //double q;
2798  static double q_max2;
2799  static double q_min2;
2800 //
2801 // On first call, initialize the subrange.
2802 //
2803  if ( !(*more) )
2804  {
2805  q_min2 = q_min;
2806  q_max2 = webbur->r8_min ( q_min + 1.0, q_max );
2807  }
2808 //
2809 // Call a lower level function to search the subrange.
2810 //
2811  for ( ; ; )
2812  {
2813  sgmga_vcn ( dim_num, level_weight, x, q_min2,
2814  q_max2, more );
2815 //
2816 // If another solution was found, return it.
2817 //
2818  if ( *more )
2819  {
2820  return;
2821  }
2822 //
2823 // If the current subrange is exhausted, try to move to the next one.
2824 //
2825  if ( q_max2 < q_max )
2826  {
2827  q_min2 = q_max2;
2828  q_max2 = webbur->r8_min ( q_max2 + 1.0, q_max );
2829  }
2830 //
2831 // If there are no more subranges, we're done.
2832 //
2833  else
2834  {
2835  break;
2836  }
2837  }
2838 
2839  return;
2840 }
2841 //****************************************************************************80
2842 
2845  int dim_num,
2846  double level_weight[],
2847  int x_max[],
2848  int x[],
2849  double q_min,
2850  double q_max,
2851  bool *more
2852 )
2853 
2854 //****************************************************************************80
2855 //
2856 // Purpose:
2857 //
2858 // SGMGA_VCN_ORDERED_NAIVE returns the "next" constrained vector, with ordering.
2859 //
2860 // Discussion:
2861 //
2862 // We consider vectors X of dimension DIM_NUM satisfying:
2863 //
2864 // 0 <= X(1:DIM_NUM) <= X_MAX(1:DIM_NUM).
2865 //
2866 // and define
2867 //
2868 // Q = sum ( 1 <= I <= DIM_NUM ) LEVEL_WEIGHT(I) * X(I)
2869 //
2870 // and seek X's satisfying the constraint:
2871 //
2872 // Q_MIN < Q <= Q_MAX
2873 //
2874 // For sparse grid applications, we compute
2875 //
2876 // LEVEL_WEIGHT_MIN_POS = minimum positive entry in LEVEL_WEIGHT
2877 //
2878 // and assume there is an underlying LEVEL used to index the sets of
2879 // constrained vectors, and that
2880 //
2881 // Q_MAX = LEVEL * LEVEL_WEIGHT_MIN_POS
2882 // Q_MIN = LEVEL - LEVEL_WEIGHT_MIN_POS * sum ( LEVEL_WEIGHT(:) )
2883 // X_MAX(I) = LEVEL * LEVEL_WEIGHT_MIN_POS / LEVEL_WEIGHT(I)
2884 //
2885 // This function returns, one at a time exactly those X which satisfy
2886 // the constraint.
2887 //
2888 // A weak ordering is imposed on the solution vectors. This function
2889 // subdivides the range Q_MIN through Q_MAX into subintervals of width 1, so
2890 // that the X vectors returned are roughly sorted (or at least binned)
2891 // by Q value.
2892 //
2893 // Example:
2894 //
2895 // If the weights are also integral, then the X vectors are in fact SORTED
2896 // by Q value:
2897 //
2898 // LEVEL_WEIGHT: 1.000000 1.000000
2899 // Q_MIN: 0.000000
2900 // Q_MAX: 2.000000
2901 // X_MAX: 2 2
2902 //
2903 // 1 1.000000 1 0
2904 // 2 1.000000 0 1
2905 // 3 2.000000 2 0
2906 // 4 2.000000 1 1
2907 // 5 2.000000 0 2
2908 //
2909 // When the weights are not integral, then the X values are only BINNED
2910 // by Q value, that is, we first get all X's with Q values between Q_MIN
2911 // and Q_MIN+1, then Q_MIN+1 to Q_MIN+2 and so on, as demonstrated here:
2912 //
2913 // LEVEL_WEIGHT: 1.5 1
2914 // Q_MIN: 0.5
2915 // Q_MAX: 3
2916 // X_MAX: 2 3
2917 //
2918 // 1 1.5 1 0
2919 // 2 1 0 1
2920 // 3 2.5 1 1
2921 // 4 2 0 2
2922 // 5 3 2 0
2923 // 6 3 0 3
2924 //
2925 // Licensing:
2926 //
2927 // This code is distributed under the GNU LGPL license.
2928 //
2929 // Modified:
2930 //
2931 // 30 October 2009
2932 //
2933 // Author:
2934 //
2935 // John Burkardt
2936 //
2937 // Reference:
2938 //
2939 // Fabio Nobile, Raul Tempone, Clayton Webster,
2940 // A Sparse Grid Stochastic Collocation Method for Partial Differential
2941 // Equations with Random Input Data,
2942 // SIAM Journal on Numerical Analysis,
2943 // Volume 46, Number 5, 2008, pages 2309-2345.
2944 //
2945 // Fabio Nobile, Raul Tempone, Clayton Webster,
2946 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
2947 // Differential Equations with Random Input Data,
2948 // SIAM Journal on Numerical Analysis,
2949 // Volume 46, Number 5, 2008, pages 2411-2442.
2950 //
2951 // Parameters:
2952 //
2953 // Input, int DIM_NUM, the number of components in the vector.
2954 //
2955 // Input, double LEVEL_WEIGHT[DIM_NUM], the anisotropic weights.
2956 //
2957 // Input, int X_MAX[DIM_NUM], the maximum values allowed in each component.
2958 //
2959 // Input/output, int X[DIM_NUM]. On first call (with MORE = FALSE),
2960 // the input value of X is not important. On subsequent calls, the
2961 // input value of X should be the output value from the previous call.
2962 // On output, (with MORE = TRUE), the value of X will be the "next"
2963 // vector in the reverse lexicographical list of vectors that satisfy
2964 // the condition. However, on output with MORE = FALSE, the vector
2965 // X is meaningless, because there are no more vectors in the list.
2966 //
2967 // Input, double Q_MIN, Q_MAX, the lower and upper
2968 // limits on the sum.
2969 //
2970 // Input/output, bool *MORE. On input, if the user has set MORE
2971 // FALSE, the user is requesting the initiation of a new sequence
2972 // of values. If MORE is TRUE, then the user is requesting "more"
2973 // values in the current sequence. On output, if MORE is TRUE,
2974 // then another value was found and returned in X, but if MORE is
2975 // FALSE, then there are no more values in the sequence, and X is
2976 // NOT the next value.
2977 //
2978 {
2979  //double q;
2980  static double q_max2;
2981  static double q_min2;
2982 //
2983 // On first call, initialize the subrange.
2984 //
2985  if ( !(*more) )
2986  {
2987  q_min2 = q_min;
2988  q_max2 = webbur->r8_min ( q_min + 1.0, q_max );
2989  }
2990 //
2991 // Call a lower level function to search the subrange.
2992 //
2993  for ( ; ; )
2994  {
2995  sgmga_vcn_naive ( dim_num, level_weight, x_max, x, q_min2,
2996  q_max2, more );
2997 //
2998 // If another solution was found, return it.
2999 //
3000  if ( *more )
3001  {
3002  return;
3003  }
3004 //
3005 // If the current subrange is exhausted, try to move to the next one.
3006 //
3007  if ( q_max2 < q_max )
3008  {
3009  q_min2 = q_max2;
3010  q_max2 = webbur->r8_min ( q_max2 + 1.0, q_max );
3011  }
3012 //
3013 // If there are no more subranges, we're done.
3014 //
3015  else
3016  {
3017  break;
3018  }
3019  }
3020 
3021  return;
3022 }
3023 //****************************************************************************80
3024 
3027  int dim_num,
3028  double level_weight[],
3029  int level_max,
3030  void ( SandiaRules2::*gw_compute_weights[] ) ( int order, int dim, double w[] ),
3031  int point_num,
3032  int point_total_num,
3033  int sparse_unique_index[],
3034  int growth,
3035  int ( SandiaRules::*gw_compute_order[] ) ( int level, int growth ),
3036  double sparse_weight[]
3037 )
3038 
3039 //****************************************************************************80
3040 //
3041 // Purpose:
3042 //
3043 // SGMGA_WEIGHT computes weights for an SGMGA grid.
3044 //
3045 // Discussion:
3046 //
3047 // The user must preallocate space for the output array SPARSE_WEIGHT.
3048 //
3049 // Licensing:
3050 //
3051 // This code is distributed under the GNU LGPL license.
3052 //
3053 // Modified:
3054 //
3055 // 13 January 2012
3056 //
3057 // Author:
3058 //
3059 // John Burkardt
3060 //
3061 // Reference:
3062 //
3063 // Fabio Nobile, Raul Tempone, Clayton Webster,
3064 // A Sparse Grid Stochastic Collocation Method for Partial Differential
3065 // Equations with Random Input Data,
3066 // SIAM Journal on Numerical Analysis,
3067 // Volume 46, Number 5, 2008, pages 2309-2345.
3068 //
3069 // Fabio Nobile, Raul Tempone, Clayton Webster,
3070 // An Anisotropic Sparse Grid Stochastic Collocation Method for Partial
3071 // Differential Equations with Random Input Data,
3072 // SIAM Journal on Numerical Analysis,
3073 // Volume 46, Number 5, 2008, pages 2411-2442.
3074 //
3075 // Parameters:
3076 //
3077 // Input, int DIM_NUM, the spatial dimension.
3078 //
3079 // Input, double LEVEL_WEIGHT[DIM_NUM], the anisotropic weights.
3080 //
3081 // Input, int LEVEL_MAX, the maximum value of LEVEL.
3082 //
3083 // Input, void ( *GW_COMPUTE_WEIGHTS[] ) ( int order, int dim, double w[] ),
3084 // an array of pointers to functions which return the 1D quadrature weights
3085 // associated with each spatial dimension for which a Golub Welsch rule
3086 // is used.
3087 //
3088 // Input, int POINT_NUM, the number of unique points
3089 // in the grid.
3090 //
3091 // Input, int POINT_TOTAL_NUM, the total number of points
3092 // in the grid.
3093 //
3094 // Input, int SPARSE UNIQUE_INDEX[POINT_TOTAL_NUM], lists,
3095 // for each (nonunique) point, the corresponding index of the same point in
3096 // the unique listing.
3097 //
3098 // Input, int GROWTH, the growth rule.
3099 // 0, slow;
3100 // 1, moderate;
3101 // 2, full.
3102 //
3103 // Input, int ( *GW_COMPUTE_ORDER[] ) ( int level, int growth ),
3104 // an array of pointers to functions which return the order of the
3105 // 1D quadrature rule of a given level and growth rule.
3106 //
3107 // Output, double SPARSE_WEIGHT[POINT_NUM], the weights
3108 // associated with the sparse grid points.
3109 //
3110 {
3111  double coef;
3112  int dim;
3113  double *grid_weight;
3114  //int level;
3115  int *level_1d;
3116  int *level_1d_max;
3117  double level_weight_min_pos;
3118  bool more_grids;
3119  int order;
3120  int *order_1d;
3121  int order_nd;
3122  int point;
3123  int point_total;
3124  int point_unique;
3125  double q_max;
3126  double q_min;
3127 
3128  for ( point = 0; point < point_num; point++ )
3129  {
3130  sparse_weight[point] = 0.0;
3131  }
3132 
3133  point_total = 0;
3134 
3135  level_1d = new int[dim_num];
3136  order_1d = new int[dim_num];
3137  level_1d_max = new int[dim_num];
3138 //
3139 // Initialization for SGMGA_VCN_ORDERED.
3140 //
3141  level_weight_min_pos = webbur->r8vec_min_pos ( dim_num, level_weight );
3142  q_min = ( double ) ( level_max ) * level_weight_min_pos
3143  - webbur->r8vec_sum ( dim_num, level_weight );
3144  q_max = ( double ) ( level_max ) * level_weight_min_pos;
3145  for ( dim = 0; dim < dim_num; dim++ )
3146  {
3147  if ( 0.0 < level_weight[dim] )
3148  {
3149  level_1d_max[dim] = ( int ) ( webbur->r8_floor ( q_max / level_weight[dim] ) ) + 1;
3150  if ( q_max <= ( level_1d_max[dim] - 1 ) * level_weight[dim] )
3151  {
3152  level_1d_max[dim] = level_1d_max[dim] - 1;
3153  }
3154  }
3155  else
3156  {
3157  level_1d_max[dim] = 0;
3158  }
3159  }
3160  more_grids = false;
3161 //
3162 // Seek all vectors LEVEL_1D which satisfy the constraint:
3163 //
3164 // LEVEL_MAX * LEVEL_WEIGHT_MIN_POS - sum ( LEVEL_WEIGHT )
3165 // < sum ( 0 <= I < DIM_NUM ) LEVEL_WEIGHT[I] * LEVEL_1D[I]
3166 // <= LEVEL_MAX * LEVEL_WEIGHT_MIN_POS.
3167 //
3168  for ( ; ; )
3169  {
3170  sgmga_vcn_ordered ( dim_num, level_weight, level_1d_max,
3171  level_1d, q_min, q_max, &more_grids );
3172 
3173  if ( !more_grids )
3174  {
3175  break;
3176  }
3177 //
3178 // Compute the combinatorial coefficient.
3179 //
3180  coef = sgmga_vcn_coef ( dim_num, level_weight, level_1d,
3181  q_max );
3182 
3183  if ( coef == 0.0 )
3184  {
3185  continue;
3186  }
3187 //
3188 // Transform each 1D level to a corresponding 1D order.
3189 //
3190  for ( dim = 0; dim < dim_num; dim++ )
3191  {
3192  order_1d[dim] = ((*webbur).*gw_compute_order[dim])(level_1d[dim],growth);
3193  }
3194 //
3195 // The product of the 1D orders gives us the number of points in this grid.
3196 //
3197  order_nd = webbur->i4vec_product ( dim_num, order_1d );
3198 //
3199 // Compute the weights for this grid.
3200 //
3201 // The correct transfer of data from the product grid to the sparse grid
3202 // depends on the fact that the product rule weights are stored under colex
3203 // order of the points, and this is the same ordering implicitly used in
3204 // generating the SPARSE_UNIQUE_INDEX array.
3205 //
3206  grid_weight = new double[order_nd];
3207 
3208  sgmga_product_weight ( dim_num, order_1d, order_nd,
3209  gw_compute_weights, grid_weight );
3210 //
3211 // Add these weights to the rule.
3212 //
3213  for ( order = 0; order < order_nd; order++ )
3214  {
3215  point_unique = sparse_unique_index[point_total];
3216 
3217  point_total = point_total + 1;
3218 
3219  sparse_weight[point_unique] = sparse_weight[point_unique]
3220  + coef * grid_weight[order];
3221  }
3222 
3223  delete [] grid_weight;
3224  }
3225 
3226  delete [] level_1d;
3227  delete [] level_1d_max;
3228  delete [] order_1d;
3229 
3230  return;
3231 }
3232 
3233 } // namespace ROL
double sgmga_vcn_coef_naive(int n, double level_weight[], int x_max[], int x[], double q_min, double q_max)
void sgmga_weight(int dim_num, double level_weight[], int level_max, void(SandiaRules2::*gw_compute_weights[])(int order, int dim, double w[]), int point_num, int point_total_num, int sparse_unique_index[], int growth, int(SandiaRules::*gw_compute_order[])(int level, int growth), double sparse_weight[])
void sgmga_product_weight(int dim_num, int order_1d[], int order_nd, void(SandiaRules2::*gw_compute_weights[])(int order, int dim, double w[]), double weight_nd[])
int sgmga_size_total(int dim_num, double level_weight[], int level_max, int growth, int(SandiaRules::*gw_compute_order[])(int level, int growth))
void sgmga_vcn_ordered(int dim_num, double level_weight[], int x_max[], int x[], double q_min, double q_max, bool *more)
void sgmga_point(int dim_num, double level_weight[], int level_max, void(SandiaRules2::*gw_compute_points[])(int order, int dim, double x[]), int point_num, int sparse_order[], int sparse_index[], int growth, int(SandiaRules::*gw_compute_order[])(int level, int growth), double sparse_point[])
double * sgmga_aniso_balance(double alpha_max, int dim_num, double level_weight[])
void sgmga_vcn(int n, double level_weight[], int x[], double q_min, double q_max, bool *more)
int sgmga_size(int dim_num, double level_weight[], int level_max, void(SandiaRules2::*gw_compute_points[])(int order, int dim, double x[]), double tol, int growth, int(SandiaRules::*gw_compute_order[])(int level, int growth))
double sgmga_vcn_coef(int n, double level_weight[], int x[], double q_max)
void sgmga_vcn_ordered_naive(int dim_num, double level_weight[], int x_max[], int x[], double q_min, double q_max, bool *more)
void sgmga_unique_index(int dim_num, double level_weight[], int level_max, void(SandiaRules2::*gw_compute_points[])(int order, int dim, double x[]), double tol, int point_num, int point_total_num, int growth, int(SandiaRules::*gw_compute_order[])(int level, int growth), int sparse_unique_index[])
void sgmga_importance_to_aniso(int dim_num, double importance[], double level_weight[])
void sgmga_index(int dim_num, double level_weight[], int level_max, int point_num, int point_total_num, int sparse_unique_index[], int growth, int(SandiaRules::*gw_compute_order[])(int level, int growth), int sparse_order[], int sparse_index[])
void sgmga_vcn_naive(int n, double level_weight[], int x_max[], int x[], double q_min, double q_max, bool *more)
void sgmga_aniso_normalize(int option, int dim_num, double level_weight[])