Sparse Grids Example 6: adaptive surrogate modeling.
Example 5 demonstrates how to construct a surrogate by processing the samples in batches. The batch construction can facilitate parallel sampling, but the exact number of samples is hard to control since the points from the entire batch are needed at once. Furthermore, if a fixed number of computing nodes is available (e.g., processor cores or MPI ranks) it may be hard to keep all nodes loaded if the batch size does not divide evenly.
The construction procedure offers a more flexible refinement alternative. The batch size can be controlled at a much finer scale to accommodate a fixed budget and occupancy across all parallel resources can be guaranteed (unless the level limits or tolerance are about to be reached, or the initial grid is too coarse). See the documentation for TasGrid::mpiConstructSurrogate() for the MPI variant of this method that differs only in some MPI related parameters.
#endif
cout << "\n---------------------------------------------------------------------------------------------------\n";
cout << std::scientific; cout.precision(4);
cout << "Example 6: interpolate f(x,y) = exp(-x^2) * exp(y) * cos(z), using the rleja rule\n"
<< " employs adaptive construction\n";
int const num_inputs = 3;
int const num_outputs = 1;
auto model = [&](std::vector<double> const &x, std::vector<double> &y, size_t)->
void{
y.resize(num_outputs);
y[0] = std::exp(-x[0] * x[0]) * std::exp(x[1]) * std::cos(x[2]);
};
int const num_test_points = 1000;
std::vector<double> test_points(num_test_points * num_inputs);
std::minstd_rand park_miller(42);
std::uniform_real_distribution<double> domain(-1.0, 1.0);
for(auto &t : test_points) t = domain(park_miller);
std::vector<double> reference_values(num_test_points * num_outputs);
for(int i=0; i<num_test_points; i++){
std::vector<double> y(1);
model(std::vector<double>(test_points.begin() + i * num_inputs,
test_points.begin() + (i+1) * num_inputs),
y, 0);
std::copy(y.begin(), y.end(), reference_values.begin() + i * num_outputs);
}
double{
std::vector<double> result;
grid.evaluateBatch(test_points, result);
double diff = 0.0;
for(int i=0; i<num_test_points; i++)
diff = std::max(diff, std::abs(result[i] - reference_values[i]));
return diff;
};
cout << setw(10) << "points" << setw(20) << "error\n";
int budget = 25;
for(int itr=0; itr<6; itr++){
budget *= 2;
TasGrid::constructSurrogate<mode>(model, budget, 12, 1, grid,
cout << setw(10) << grid.getNumPoints() << setw(20) << test_grid(grid) << "\n";
}
#ifndef __TASMANIAN_DOXYGEN_SKIP
The master-class that represents an instance of a Tasmanian sparse grid.
Definition: TasmanianSparseGrid.hpp:293
@ rule_rleja
Classic sequence rule based on complex analysis, moderate Lebesgue constant growth (theoretically pro...
Definition: tsgEnumerates.hpp:303
@ type_level
Ignoring the polynomial space, use rules with index .
Definition: tsgEnumerates.hpp:209
@ type_iptotal
Total degree polynomial space for interpolation, i.e., the span of .
Definition: tsgEnumerates.hpp:221
constexpr bool mode_sequential
Allows for expressive calls to TasGrid::constructSurrogate().
Definition: tsgConstructSurrogate.hpp:78
TasmanianSparseGrid makeSequenceGrid(int dimensions, int outputs, int depth, TypeDepth type, TypeOneDRule rule, std::vector< int > const &anisotropic_weights=std::vector< int >(), std::vector< int > const &level_limits=std::vector< int >())
Factory method, creates a new grid and calls TasmanianSparseGrid::makeSequenceGrid().
Definition: TasmanianSparseGrid.hpp:2287