Doxygen 1.9.8
Toolkit for Adaptive Stochastic Modeling and Non-Intrusive ApproximatioN: Tasmanian v8.2
 
Loading...
Searching...
No Matches
tsgExoticQuadrature.hpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2021, Miroslav Stoyanov & William Kong
3 *
4 * This file is part of
5 * Toolkit for Adaptive Stochastic Modeling And Non-Intrusive ApproximatioN: TASMANIAN
6 *
7 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
8 * conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
13 * and the following disclaimer in the documentation and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse
16 * or promote products derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
19 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
22 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 *
26 * UT-BATTELLE, LLC AND THE UNITED STATES GOVERNMENT MAKE NO REPRESENTATIONS AND DISCLAIM ALL WARRANTIES, BOTH EXPRESSED AND
27 * IMPLIED. THERE ARE NO EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, OR THAT THE USE
28 * OF THE SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT, TRADEMARK, OR OTHER PROPRIETARY RIGHTS, OR THAT THE SOFTWARE WILL
29 * ACCOMPLISH THE INTENDED RESULTS OR THAT THE SOFTWARE OR ITS USE WILL NOT RESULT IN INJURY OR DAMAGE. THE USER ASSUMES
30 * RESPONSIBILITY FOR ALL LIABILITIES, PENALTIES, FINES, CLAIMS, CAUSES OF ACTION, AND COSTS AND EXPENSES, CAUSED BY, RESULTING
31 * FROM OR ARISING OUT OF, IN WHOLE OR IN PART THE USE, STORAGE OR DISPOSAL OF THE SOFTWARE.
32 */
33
34#ifndef __TASMANIAN_ADDONS_EXOTICQUADRATURE_HPP
35#define __TASMANIAN_ADDONS_EXOTICQUADRATURE_HPP
36
47#include "tsgAddonsCommon.hpp"
48
81namespace TasGrid {
82
90static int gauss_quadrature_version = 1;
91
100inline double poly_eval(const std::vector<double> &roots, double x) {
101 double eval_value = 1.0;
102 for (auto r : roots) eval_value *= (x - r);
103 return eval_value;
104}
105
117inline double lagrange_eval(size_t idx, const std::vector<double> &roots, double x) {
118 double eval_value = 1.0;
119 for (size_t i=0; i<idx; i++) {
120 eval_value *= (x - roots[i]) / (roots[idx] - roots[i]);
121 }
122 for (size_t i=idx+1; i<roots.size(); i++) {
123 eval_value *= (x - roots[i]) / (roots[idx] - roots[i]);
124 }
125 return eval_value;
126}
127
148template <bool is_symmetric>
149inline void getGaussNodesAndWeights(const int n, const std::vector<double> &ref_points, const std::vector<double> &ref_weights,
150 std::vector<std::vector<double>> &points_cache, std::vector<std::vector<double>> &weights_cache) {
151 #ifndef Tasmanian_ENABLE_BLAS
152 // If BLAS is not enabled, we must use an implementation that does not require it.
153 if (gauss_quadrature_version == 1) {
154 gauss_quadrature_version = 2;
155 }
156 #endif
157 // Compute the roots incrementally.
158 assert(ref_points.size() == ref_weights.size());
159 assert(ref_points.size() > 0);
160 double mu0 = 0.0;
161 for (auto &w : ref_weights) mu0 += w;
162 std::vector<double> poly_m1_vals(ref_points.size(), 0.0), poly_vals(ref_points.size(), 1.0);
163 std::vector<double> diag, offdiag;
164 points_cache.resize(n);
165 weights_cache.resize(n);
166 for (int i=0; i<n; i++) {
167 // Form the diagonal and offdiagonal vectors of the Jacobi matrix.
168 if (is_symmetric) {
169 diag.push_back(0.0);
170 } else {
171 double diag_numr = 0.0;
172 double diag_denm = 0.0;
173 for (size_t j=0; j<ref_points.size(); j++) {
174 diag_numr += ref_points[j] * (poly_vals[j] * poly_vals[j]) * ref_weights[j];
175 diag_denm += (poly_vals[j] * poly_vals[j]) * ref_weights[j];
176 }
177 diag.push_back(diag_numr / diag_denm);
178 }
179 if (i >= 1) {
180 double sqr_offdiag_numr = 0.0;
181 double sqr_offdiag_denm = 0.0;
182 for (size_t j=0; j<ref_points.size(); j++) {
183 sqr_offdiag_numr += (poly_vals[j] * poly_vals[j]) * ref_weights[j];
184 sqr_offdiag_denm += (poly_m1_vals[j] * poly_m1_vals[j]) * ref_weights[j];
185 }
186 offdiag.push_back(std::sqrt(sqr_offdiag_numr / sqr_offdiag_denm));
187 }
188 // Compute the Gauss points and weights.
189 if (gauss_quadrature_version == 1) {
190 // Use LAPACK to obtain the Gauss points, and use the reference points and weights to obtain the Gauss weights.
191 // Note that the matrix is always symmetric even if the weights function is not.
192 points_cache[i] = TasmanianTridiagonalSolver::getSymmetricEigenvalues(i+1, diag, offdiag);
193 if (points_cache[i].size() % 2 == 1 && is_symmetric) {
194 points_cache[i][(points_cache[i].size() - 1) / 2] = 0.0;
195 }
196 weights_cache[i] = std::vector<double>(points_cache[i].size(), 0.0);
197 for (size_t j=0; j<points_cache[i].size(); j++) {
198 // Integrate the function l_j(x) according to the measure induced by the function [weight_fn(x) + shift].
199 for (size_t k=0; k<ref_points.size(); k++) {
200 weights_cache[i][j] += lagrange_eval(j, points_cache[i], ref_points[k]) * ref_weights[k];
201 }
202 }
203 } else if (gauss_quadrature_version == 2) {
204 // Use TasmanianTridiagonalSolver::decompose().
205 std::vector<double> dummy_diag = diag;
206 std::vector<double> dummy_offdiag = offdiag;
207 TasmanianTridiagonalSolver::decompose(dummy_diag, dummy_offdiag, mu0, points_cache[i], weights_cache[i]);
208 } else {
209 throw std::invalid_argument("ERROR: gauss_quadrature_version must be a valid number!");
210 }
211 // Update the values of the polynomials at ref_points.
212 std::swap(poly_m1_vals, poly_vals);
213 std::transform(ref_points.begin(), ref_points.end(), poly_vals.begin(),
214 [&points_cache, i](double x){return poly_eval(points_cache[i], x);});
215 }
216}
217
233inline TasGrid::CustomTabulated getShiftedExoticQuadrature(const int n, const double shift, const std::vector<double> &shifted_weights,
234 const std::vector<double> &ref_points, const char* description,
235 const bool is_symmetric = false) {
236 // Create the set of points (roots) and weights for the first term.
237 assert(shifted_weights.size() == ref_points.size());
238 std::vector<std::vector<double>> points_cache, weights_cache;
239 if (is_symmetric) {
240 getGaussNodesAndWeights<true>(n, ref_points, shifted_weights, points_cache, weights_cache);
241 } else {
242 getGaussNodesAndWeights<false>(n, ref_points, shifted_weights, points_cache, weights_cache);
243 }
244
245 // Create and append the set of correction points and weights for the second term only if the shift is nonzero.
246 if (shift != 0.0) {
247 for (int i=0; i<n; i++) {
248 const size_t init_size = points_cache[i].size();
249 std::vector<double> correction_points, correction_weights;
250 TasGrid::OneDimensionalNodes::getGaussLegendre(static_cast<int>(init_size), correction_weights, correction_points);
251 for (auto &w : correction_weights) w *= -shift;
252 if (correction_points.size() % 2 == 1 && is_symmetric) {
253 // Zero out for stability.
254 correction_points[(correction_points.size() - 1) / 2] = 0.0;
255 }
256 // Account for duplicates up to a certain tolerance.
257 for (size_t j=0; j<correction_points.size(); j++) {
258 long long nonunique_idx = -1;
259 for (size_t k=0; k<init_size; k++) {
260 if (std::abs(correction_points[j] - points_cache[i][k]) <= Maths::num_tol) {
261 nonunique_idx = static_cast<long long>(k);
262 break;
263 }
264 }
265 if (nonunique_idx == -1) {
266 points_cache[i].push_back(correction_points[j]);
267 weights_cache[i].push_back(correction_weights[j]);
268 } else {
269 weights_cache[i][nonunique_idx] += correction_weights[j];
270 }
271 }
272 }
273 }
274
275 // Output to a CustomTabulated instance.
276 std::vector<int> num_nodes(n), precision(n);
277 for (int i=0; i<n; i++) {
278 num_nodes[i] = static_cast<int>(points_cache[i].size());
279 precision[i] = 2 * (i + 1) - 1;
280 }
281 return TasGrid::CustomTabulated(std::move(num_nodes), std::move(precision), std::move(points_cache), std::move(weights_cache),
282 description);
283}
284
298inline void shiftReferenceWeights(std::vector<double> const &vals, double shift, std::vector<double> &ref_weights){
299 assert(ref_weights.size() == vals.size());
300 if (not std::all_of(vals.begin(), vals.end(), [shift](double x){return (x+shift)>=0.0;}))
301 throw std::invalid_argument("ERROR: shift needs to be chosen so that weight_fn(x)+shift is nonnegative!");
302 for (size_t k=0; k<ref_weights.size(); k++)
303 ref_weights[k] *= (vals[k] + shift);
304}
305
335inline TasGrid::CustomTabulated getExoticQuadrature(const int num_levels, const double shift, const TasGrid::TasmanianSparseGrid &grid,
336 const char* description, const bool is_symmetric = false) {
337 if (grid.getNumLoaded() == 0) {
338 throw std::invalid_argument("ERROR: grid needs to contain a nonzero number of loaded points returned by grid.getLoadedPoints()!");
339 }
340 if (grid.getNumDimensions() != 1) {
341 throw std::invalid_argument("ERROR: grid needs to be one dimensional!");
342 }
343 if (grid.getNumOutputs() != 1) {
344 throw std::invalid_argument("ERROR: grid needs to have scalar outputs!");
345 }
346 std::vector<double> ref_points = grid.getLoadedPoints();
347 std::vector<double> shifted_weights = grid.getQuadratureWeights();
348 std::vector<double> weight_fn_vals = std::vector<double>(grid.getLoadedValues(), grid.getLoadedValues() + grid.getNumLoaded());
349 shiftReferenceWeights(weight_fn_vals, shift, shifted_weights);
350 return getShiftedExoticQuadrature(num_levels, shift, shifted_weights, ref_points, description, is_symmetric);
351}
352
362inline TasGrid::CustomTabulated getExoticQuadrature(const int num_levels, const double shift, std::function<double(double)> weight_fn,
363 const int num_ref_points, const char* description, const bool is_symmetric = false) {
364 std::vector<double> shifted_weights, ref_points, weight_fn_vals(num_ref_points);
365 TasGrid::OneDimensionalNodes::getGaussLegendre(num_ref_points, shifted_weights, ref_points);
366 std::transform(ref_points.begin(), ref_points.end(), weight_fn_vals.begin(), weight_fn);
367 shiftReferenceWeights(weight_fn_vals, shift, shifted_weights);
368 return getShiftedExoticQuadrature(num_levels, shift, shifted_weights, ref_points, description, is_symmetric);
369}
370
371} // namespace(TasGrid)
372#endif
Class providing manipulation of custom tabulated rules, file I/O and structured access to the points,...
Definition tsgCoreOneDimensional.hpp:66
The master-class that represents an instance of a Tasmanian sparse grid.
Definition TasmanianSparseGrid.hpp:293
int getNumOutputs() const
Return the outputs of the grid, i.e., number of model outputs.
Definition TasmanianSparseGrid.hpp:644
const double * getLoadedValues() const
Returns the model values that have been loaded in the gird.
Definition TasmanianSparseGrid.hpp:899
std::vector< double > getQuadratureWeights() const
Returns a vector of size getNumPoints() of the quadrature weights of the grid.
Definition TasmanianSparseGrid.hpp:747
int getNumLoaded() const
Return the number of points already associated with model values via loadNeededValues().
Definition TasmanianSparseGrid.hpp:657
std::vector< double > getLoadedPoints() const
Return the points already associated with model values.
Definition TasmanianSparseGrid.hpp:671
int getNumDimensions() const
Return the dimensions of the grid, i.e., number of model inputs.
Definition TasmanianSparseGrid.hpp:642
TasGrid::CustomTabulated getExoticQuadrature(const int num_levels, const double shift, const TasGrid::TasmanianSparseGrid &grid, const char *description, const bool is_symmetric=false)
Constructs an exotic quadrature from a sparse grid object.
Definition tsgExoticQuadrature.hpp:335
double lagrange_eval(size_t idx, const std::vector< double > &roots, double x)
Evaluates a Lagrange basis polynomial at a point x.
Definition tsgExoticQuadrature.hpp:117
void shiftReferenceWeights(std::vector< double > const &vals, double shift, std::vector< double > &ref_weights)
Multiplies the reference quadrature weights by the shifted values of the weight function.
Definition tsgExoticQuadrature.hpp:298
TasGrid::CustomTabulated getShiftedExoticQuadrature(const int n, const double shift, const std::vector< double > &shifted_weights, const std::vector< double > &ref_points, const char *description, const bool is_symmetric=false)
Generate the exotic quadrature points and weights and load them into a TasGrid::CustomTabulated objec...
Definition tsgExoticQuadrature.hpp:233
void getGaussNodesAndWeights(const int n, const std::vector< double > &ref_points, const std::vector< double > &ref_weights, std::vector< std::vector< double > > &points_cache, std::vector< std::vector< double > > &weights_cache)
Generates n levels of points and weights using orthogonal polynomials with respect to ref_points and ...
Definition tsgExoticQuadrature.hpp:149
double poly_eval(const std::vector< double > &roots, double x)
Evaluates a polynomial with roots given by roots at the point x.
Definition tsgExoticQuadrature.hpp:100
constexpr double num_tol
Numerical tolerance for various algorithms.
Definition tsgMathUtils.hpp:132
void decompose(std::vector< double > &diag, std::vector< double > &off_diag, const double mu0, std::vector< double > &nodes, std::vector< double > &weights)
Method for tridiagonal eigenvalue decomposition, used to compute nodes and weights for Gaussian rules...
std::vector< double > getSymmetricEigenvalues(int n, std::vector< double > const &diag, std::vector< double > const &offdiag)
Method for computing the eigenvalues of a symmetric matrix in place, using an LAPACK wrapper.
Encapsulates the Tasmanian Sparse Grid module.
Definition TasmanianSparseGrid.hpp:68
Common includes and methods for all addons.