1 /*  _______________________________________________________________________
2 
3     PECOS: Parallel Environment for Creation Of Stochastics
4     Copyright (c) 2011, Sandia National Laboratories.
5     This software is distributed under the GNU Lesser General Public License.
6     For more information, see the README file in the top Pecos directory.
7     _______________________________________________________________________ */
8 
9 //- Class:	 SparseGridDriver
10 //- Description: Wrapper class for C++ code from packages/quadrature/sparse_grid
11 //- Owner:       Mike Eldred
12 //- Revised by:
13 //- Version:
14 
15 #ifndef SPARSE_GRID_DRIVER_HPP
16 #define SPARSE_GRID_DRIVER_HPP
17 
18 #include "IntegrationDriver.hpp"
19 #include "sandia_rules.hpp"
20 
21 namespace Pecos {
22 
23 
24 /// Derived integration driver class that generates N-dimensional
25 /// Smolyak sparse grids for numerical evaluation of expectation
26 /// integrals over independent standard random variables.
27 
28 /** This class is used by Dakota::NonDSparseGrid, but could also be
29     used for general numerical integration of moments.  It employs 1-D
30     Clenshaw-Curtis, Newton-Cotes, and Gaussian quadrature rules
31     within Smolyak sparse grids. */
32 
33 class SparseGridDriver: public IntegrationDriver
34 {
35 public:
36 
37   //
38   //- Heading: Constructors and destructor
39   //
40 
41   /// default constructor
42   SparseGridDriver();
43   /// constructor
44   SparseGridDriver(unsigned short ssg_level, const RealVector& dim_pref,
45 		   short growth_rate, short refine_control);
46   /// destructor
47   ~SparseGridDriver();
48 
49   //
50   //- Heading: New virtual functions
51   //
52 
53   /// initializes old/active/evaluation sets for use within the
54   /// generalized sparse grid procedure
55   virtual void initialize_sets();
56   /// update smolyakMultiIndex with a new trial set for use within the
57   /// generalized sparse grid procedure
58   virtual void increment_smolyak_multi_index(const UShortArray& set);
59 
60   /// determine whether trial set is available for restoration (by push)
61   virtual bool push_trial_available(const UShortArray& key,
62 				    const UShortArray& tr_set);
63   /// determine whether trial set is available for restoration (by push
64   virtual bool push_trial_available(const UShortArray& key);
65   /// determine whether trial set is available for restoration (by push
66   virtual bool push_trial_available();
67 
68   /// determine index of trial set for restoration (by push)
69   virtual size_t push_trial_index(const UShortArray& key,
70 				  const UShortArray& tr_set);
71   /// determine index of trial set for restoration (by push)
72   virtual size_t push_trial_index(const UShortArray& key);
73   /// determine index of trial set for restoration (by push)
74   virtual size_t push_trial_index();
75 
76   /// return pushIndex (cached lookup result in derived Driver classes),
77   /// which may be combined (flattened) or hierarchical (level-specific) index
78   virtual size_t push_index(const UShortArray& key) const;
79   /// map pushIndex to consistent (flattened) representation
80   virtual size_t restore_index(const UShortArray& key) const;
81   /// return consistent (flattened) index
82   virtual size_t finalize_index(size_t i, const UShortArray& key) const;
83 
84   /// update collocKey, collocIndices, and uniqueIndexMapping based on
85   /// restoration of previous trial to smolyakMultiIndex
86   virtual void push_set();
87   /// remove the previously pushed trial set from smolyakMultiIndex
88   /// during the course of the generalized sparse grid procedure
89   virtual void pop_set();
90   /// accept all remaining trial sets within the generalized sparse
91   /// grid procedure
92   virtual void finalize_sets(bool output_sets, bool converged_within_tol,
93 			     bool reverted);
94 
95   /// computes the tensor grid for the trial index set used in
96   /// increment_smolyak_multi_index()
97   virtual void compute_trial_grid(RealMatrix& var_sets);
98 
99   /// computes a grid increment and evaluates the new parameter sets
100   virtual void compute_increment(RealMatrix& var_sets);
101   /// restores a previously computed grid increment (no new evaluations)
102   virtual void push_increment();
103   /// removes a previously computed grid increment
104   virtual void pop_increment();
105   /// merges a grid increment into the reference grid
106   virtual void merge_unique();
107 
108   /// update derived reference data, if required
109   virtual void update_reference();
110 
111   /// return the trial index set used in increment_smolyak_multi_index()
112   /// that corresponds to key
113   virtual const UShortArray& trial_set(const UShortArray& key) const;
114   /// return the trial index set used in increment_smolyak_multi_index()
115   /// that corresponds to activeKey
116   virtual const UShortArray& trial_set() const;
117 
118   /// return the number of unique collocation points in the trial index set
119   virtual int unique_trial_points() const;
120 
121   /// update smolyakMultiIndex and smolyakCoeffs while adapting grid
122   virtual void update_smolyak_arrays();
123   /// print smolyakMultiIndex
124   virtual void print_smolyak_multi_index() const = 0;
125 
126   /// update active iterators based on activeKey
127   virtual void update_active_iterators();
128 
129   //
130   //- Heading: virtual function redefinitions
131   //
132 
133   void active_key(const UShortArray& key);
134   void clear_inactive();
135   void clear_keys();
136   void reset();
137   void initialize_grid_parameters(const MultivariateDistribution& mv_dist);
138 
139   //
140   //- Heading: Member functions
141   //
142 
143   /// return number of collocation points in active grid
144   int collocation_points() const;
145 
146   /// initialize all sparse grid settings except for distribution params
147   void initialize_grid(unsigned short ssg_level, const RealVector& dim_pref,
148     const MultivariateDistribution& u_dist,
149     const ExpansionConfigOptions& ec_options, BasisConfigOptions& bc_options,
150     short growth_rate = MODERATE_RESTRICTED_GROWTH);
151 
152   /// set flag indicating that grid details have changed and the size
153   /// calculation requires updating
154   void clear_size();
155 
156   /// return pushIndex (cached lookup result in derived Driver classes)
157   size_t push_index() const;
158 
159   /// precompute quadrature rules to the maximum current order for each basis
160   /// polynomial (efficiency optimization when rules are expensive to compute)
161   void precompute_rules();
162 
163   // initialize collocPts1D and type{1,2}CollocWts1D
164   //void assign_1d_collocation_points_weights();
165   /// expand and update collocPts1D and type{1,2}CollocWts1D
166   void update_1d_collocation_points_weights();
167   /// reset collocPts1D and type{1,2}CollocWts1D for variables with a
168   /// distribution parameter change
169   void reset_1d_collocation_points_weights();
170 
171   /// update axisLowerBounds
172   void update_axis_lower_bounds();
173 
174   /// accept the best of several trial sets and update old/active
175   /// within the generalized sparse grid procedure
176   void update_sets(const UShortArray& set_star);
177   /// update activeMultiIndex from the passed trial set for use within
178   /// the generalized sparse grid procedure
179   void add_active_neighbors(const UShortArray& set, bool frontier);
180 
181   /// converts an array of sparse grid levels to an array of
182   /// quadrature orders based on apiIntegrationRules/apiGrowthRules
183   void level_to_order(size_t i, unsigned short level,
184 		      unsigned short& order);
185   /// converts an array of sparse grid levels to an array of
186   /// quadrature orders based on apiIntegrationRules/apiGrowthRules
187   void level_to_order(const UShortArray& levels, UShortArray& orders);
188 
189   /// set active ssgLevel
190   void level(unsigned short ssg_level);
191   /// return active ssgLevel
192   unsigned short level() const;
193 
194   /// convert dimension preference and set anisoLevelWts
195   void dimension_preference(const RealVector& dim_pref);
196   /// set anisoLevelWts
197   void anisotropic_weights(const RealVector& aniso_wts);
198   /// return anisoLevelWts
199   const RealVector& anisotropic_weights() const;
200   /// indicates isotropic (empty) weights on sparse grid dimension levels
201   bool isotropic() const;
202 
203   /// set growthRate
204   void growth_rate(short growth_rate);
205   /// get growthRate
206   short growth_rate() const;
207 
208   // get refineType
209   //short refinement_type()    const;
210   /// set refineControl
211   void refinement_control(short cntl);
212   /// get refineControl
213   short refinement_control() const;
214 
215   /// return entry from activeMultiIndex corresponding to key
216   const UShortArraySet& active_multi_index(const UShortArray& key) const;
217   /// return entry from activeMultiIndex corresponding to activeKey
218   const UShortArraySet& active_multi_index() const;
219 
220 protected:
221 
222   //
223   //- Heading: Convenience functions
224   //
225 
226   /// level to order mapping for interpolation with nested Genz-Keister rules
227   static int level_to_order_exp_hgk_interp(int level, int growth);
228   /// level to order mapping for interpolation with nested closed rules
229   static int level_to_order_exp_closed_interp(int level, int growth);
230   /// level to order mapping for interpolation with nested open rules
231   static int level_to_order_exp_open_interp(int level, int growth);
232 
233   /// print an index set
234   void print_index_set(std::ostream& s, const UShortArray& mi) const;
235 
236   //
237   //- Heading: Data
238   //
239 
240   /// Smolyak sparse grid levels for each active key
241   std::map<UShortArray, unsigned short> ssgLevel;
242   /// iterator to the active Smolyak sparse grid level
243   std::map<UShortArray, unsigned short>::iterator ssgLevIter;
244 
245   /// weighting vector for dimension anisotropic grids
246   std::map<UShortArray, RealVector> anisoLevelWts;
247   /// weighting vector for dimension anisotropic grids
248   std::map<UShortArray, RealVector>::iterator anisoWtsIter;
249 
250   /// enumeration for rate of exponential growth in nested rules
251   short growthRate;
252 
253   // type of expansion refinement
254   //short refineType;
255   /// algorithm control governing expansion refinement
256   short refineControl;
257 
258   /// the number of unique points in each grid
259   std::map<UShortArray, int> numCollocPts;
260   /// iterator to the number of unique points in the active grid
261   std::map<UShortArray, int>::iterator numPtsIter;
262 
263   /// old reference index sets for generalized sparse grids.  Use std::set
264   /// for efficient lookups in add_active_neighbors().
265   std::map<UShortArray, UShortArraySet> oldMultiIndex;
266   /// active index sets under current consideration for inclusion in a
267   /// generalized sparse grid.  Use std::set for ordering of candidates.
268   std::map<UShortArray, UShortArraySet> activeMultiIndex;
269   /// subset of active trial sets that have been evaluated but not selected.
270   /// Use std::deque to retain append ordering (mirroring SurrogateData).
271   std::map<UShortArray, UShortArrayDeque> poppedTrialSets;
272 
273   /// database key indicating the currently active integration configuration.
274   /// the key is a multi-index managing multiple modeling dimensions such as
275   /// model form, discretization level, etc.
276   UShortArray activeKey;
277 
278 private:
279 
280   //
281   //- Heading: Convenience functions
282   //
283 
284   /// reset collocPts1D[*][i] and type{1,2}CollocWts1D[*][i] for all levels
285   void reset_1d_collocation_points_weights(size_t i);
286   /// resize arrays: collocPts1D,type1CollocWts1D,type2CollocWts1D
287   void resize_1d_collocation_points_weights();
288 
289   //
290   //- Heading: Data
291   //
292 
293   /// refinement constraints that ensure that level/anisotropic weight updates
294   /// contain all previous multi-index sets
295   std::map<UShortArray, RealVector> axisLowerBounds;
296   // iterator to the active set of axis lower bounds
297   //std::map<UShortArray, RealVector>::iterator axisLBndsIter;
298 };
299 
300 
SparseGridDriver()301 inline SparseGridDriver::SparseGridDriver():
302   IntegrationDriver(BaseConstructor()), growthRate(MODERATE_RESTRICTED_GROWTH),
303   //ssgLevel(0), numCollocPts(0),
304   refineControl(NO_CONTROL)//, refineType(NO_REFINEMENT)
305 {
306   std::pair<UShortArray, unsigned short> us_pair(activeKey, 0);
307   ssgLevIter = ssgLevel.insert(us_pair).first;
308 
309   std::pair<UShortArray, int> ui_pair(activeKey, 0);
310   numPtsIter = numCollocPts.insert(ui_pair).first;
311 }
312 
313 
314 inline SparseGridDriver::
SparseGridDriver(unsigned short ssg_level,const RealVector & dim_pref,short growth_rate,short refine_control)315 SparseGridDriver(unsigned short ssg_level, const RealVector& dim_pref,
316 		 short growth_rate, short refine_control):
317   IntegrationDriver(BaseConstructor()), growthRate(growth_rate),
318   //ssgLevel(ssg_level), numCollocPts(0),
319   refineControl(refine_control) //refineType(NO_REFINEMENT)
320 {
321   std::pair<UShortArray, unsigned short> us_pair(activeKey, ssg_level);
322   ssgLevIter = ssgLevel.insert(us_pair).first;
323 
324   std::pair<UShortArray, int> ui_pair(activeKey, 0);
325   numPtsIter = numCollocPts.insert(ui_pair).first; // count to be updated
326 
327   if (!dim_pref.empty()) {
328     numVars = dim_pref.length(); // unit length option not supported
329     dimension_preference(dim_pref);
330   }
331 }
332 
333 
~SparseGridDriver()334 inline SparseGridDriver::~SparseGridDriver()
335 { }
336 
337 
active_key(const UShortArray & key)338 inline void SparseGridDriver::active_key(const UShortArray& key)
339 {
340   if (activeKey != key) {
341     activeKey = key;
342     update_active_iterators();
343   }
344 }
345 
346 
update_active_iterators()347 inline void SparseGridDriver::update_active_iterators()
348 {
349   ssgLevIter = ssgLevel.find(activeKey);
350   if (ssgLevIter == ssgLevel.end()) {
351     std::pair<UShortArray, unsigned short> us_pair(activeKey, 0);
352     ssgLevIter = ssgLevel.insert(us_pair).first;
353   }
354   numPtsIter = numCollocPts.find(activeKey);
355   if (numPtsIter == numCollocPts.end()) {
356     // assign special value for grid_size() (instead of 1 pt for ssgLev 0)
357     std::pair<UShortArray, int> ui_pair(activeKey, 0);
358     numPtsIter = numCollocPts.insert(ui_pair).first;
359   }
360   anisoWtsIter = anisoLevelWts.find(activeKey);
361   if (anisoWtsIter == anisoLevelWts.end()) {
362     std::pair<UShortArray, RealVector> urv_pair(activeKey, RealVector());
363     anisoWtsIter = anisoLevelWts.insert(urv_pair).first;
364   }
365   /*
366   axisLBndsIter = axisLowerBounds.find(activeKey);
367   if (axisLBndsIter == axisLowerBounds.end()) {
368     std::pair<UShortArray, RealVector> urv_pair(activeKey, RealVector());
369     axisLBndsIter = axisLowerBounds.insert(urv_pair).first;
370   }
371   */
372 }
373 
374 
clear_keys()375 inline void SparseGridDriver::clear_keys()
376 {
377   activeKey.clear();
378 
379   ssgLevel.clear();          ssgLevIter    =        ssgLevel.end();
380   numCollocPts.clear();      numPtsIter    =    numCollocPts.end();
381   anisoLevelWts.clear();     anisoWtsIter  =   anisoLevelWts.end();
382   axisLowerBounds.clear(); //axisLBndsIter = axisLowerBounds.end();
383 
384   oldMultiIndex.clear();  activeMultiIndex.clear();  poppedTrialSets.clear();
385 
386   // this database is shared among all keys
387   clear_1d_collocation_points_weights();
388 }
389 
390 
collocation_points() const391 inline int SparseGridDriver::collocation_points() const
392 { return numPtsIter->second; }
393 
394 
clear_size()395 inline void SparseGridDriver::clear_size()
396 { numPtsIter->second = 0; } // special value indicating a grid update is reqd
397 
398 
reset()399 inline void SparseGridDriver::reset()
400 { IntegrationDriver::reset(); clear_size(); }
401 
402 
push_index() const403 inline size_t SparseGridDriver::push_index() const
404 { return push_index(activeKey); }
405 
406 
level() const407 inline unsigned short SparseGridDriver::level() const
408 { return ssgLevIter->second; }
409 
410 
level(unsigned short ssg_level)411 inline void SparseGridDriver::level(unsigned short ssg_level)
412 {
413   if (ssgLevIter->second != ssg_level) {
414     ssgLevIter->second = ssg_level;
415     clear_size();
416   }
417 }
418 
419 
anisotropic_weights() const420 inline const RealVector& SparseGridDriver::anisotropic_weights() const
421 { return anisoWtsIter->second; }
422 
423 
isotropic() const424 inline bool SparseGridDriver::isotropic() const
425 { return anisoWtsIter->second.empty(); }
426 
427 
428 //inline short SparseGridDriver::refinement_type() const
429 //{ return refineType; }
430 
431 
refinement_control(short cntl)432 inline void SparseGridDriver::refinement_control(short cntl)
433 { refineControl = cntl; }
434 
435 
refinement_control() const436 inline short SparseGridDriver::refinement_control() const
437 { return refineControl; }
438 
439 
growth_rate(short growth_rate)440 inline void SparseGridDriver::growth_rate(short growth_rate)
441 { growthRate = growth_rate; }
442 
443 
growth_rate() const444 inline short SparseGridDriver::growth_rate() const
445 { return growthRate; }
446 
447 
448 inline const UShortArraySet& SparseGridDriver::
active_multi_index(const UShortArray & key) const449 active_multi_index(const UShortArray& key) const
450 {
451   std::map<UShortArray, UShortArraySet>::const_iterator cit
452     = activeMultiIndex.find(key);
453   if (cit == activeMultiIndex.end()) {
454     PCerr << "Error: active key not found in SparseGridDriver::"
455 	  << "active_multi_index()." << std::endl;
456     abort_handler(-1);
457   }
458   return cit->second;
459 }
460 
461 
active_multi_index() const462 inline const UShortArraySet& SparseGridDriver::active_multi_index() const
463 { return active_multi_index(activeKey); }
464 
465 
466 inline void SparseGridDriver::
level_to_order(size_t i,unsigned short level,unsigned short & order)467 level_to_order(size_t i, unsigned short level, unsigned short& order)
468 {
469   //int ilevel = level, iorder;
470   //webbur::level_growth_to_order(1, &ilevel, &apiIntegrationRules[i],
471   //				  &apiGrowthRules[i], &iorder);
472   //order = iorder;
473 
474   // if INTERPOLATION_MODE, use mappings that synchronize on the number of
475   // interpolated points.  For INTEGRATION_MODE or DEFAULT_MODE, use mappings
476   // that synchronize on integrand precision.
477   switch (collocRules[i]) {
478   case GAUSS_PATTERSON:
479     order = (driverMode == INTERPOLATION_MODE) ?
480       level_to_order_exp_open_interp(level, growthRate) :
481       webbur::level_to_order_exp_gp(level, growthRate);          break;
482   case GENZ_KEISTER:
483     order = (driverMode == INTERPOLATION_MODE) ?
484       level_to_order_exp_hgk_interp(level, growthRate) :
485       webbur::level_to_order_exp_hgk(level, growthRate);         break;
486   case CLENSHAW_CURTIS: case NEWTON_COTES:
487     order = (driverMode == INTERPOLATION_MODE) ?
488       level_to_order_exp_closed_interp(level, growthRate) :
489       webbur::level_to_order_exp_cc(level, growthRate);          break;
490   case FEJER2:
491     order = (driverMode == INTERPOLATION_MODE) ?
492       level_to_order_exp_open_interp(level, growthRate) :
493       webbur::level_to_order_exp_f2(level, growthRate);          break;
494   case GAUSS_HERMITE: case GAUSS_LEGENDRE: // weakly nested Gaussian
495     order = webbur::level_to_order_linear_wn(level, growthRate); break;
496   default:                                 // non-nested Gaussian
497     order = webbur::level_to_order_linear_nn(level, growthRate); break;
498   }
499 }
500 
501 
502 inline void SparseGridDriver::
level_to_order(const UShortArray & levels,UShortArray & orders)503 level_to_order(const UShortArray& levels, UShortArray& orders)
504 {
505   size_t i, num_lev = levels.size();
506   if (orders.size() != num_lev)
507     orders.resize(num_lev);
508   for (i=0; i<num_lev; ++i)
509     level_to_order(i, levels[i], orders[i]);
510 }
511 
512 
513 inline void SparseGridDriver::
print_index_set(std::ostream & s,const UShortArray & mi) const514 print_index_set(std::ostream& s, const UShortArray& mi) const
515 {
516   size_t j, num_mi = mi.size();
517   for (j=0; j<num_mi; ++j)
518     s << std::setw(5) << mi[j];
519   s << '\n';
520 }
521 
522 } // namespace Pecos
523 
524 #endif
525