Janus 2.0.0
High-performance C++20 dual-mode numerical framework
Loading...
Searching...
No Matches
Quadrature.hpp
Go to the documentation of this file.
1#pragma once
7
13#include <Eigen/Eigenvalues>
14#include <array>
15#include <cmath>
16#include <cstdint>
17#include <functional>
18#include <limits>
19#include <map>
20#include <numeric>
21#include <string>
22#include <utility>
23#include <vector>
24
25namespace janus {
26
36
50
60
69
70namespace detail {
71
73 std::array<double, 15> nodes;
74 std::array<double, 15> primary_weights;
75 std::array<double, 15> embedded_weights;
76};
77
79 static const EmbeddedQuadratureRule rule = {
80 std::array<double, 15>{-0.991455371120812639, -0.949107912342758525, -0.864864423359769073,
81 -0.741531185599394440, -0.586087235467691130, -0.405845151377397167,
82 -0.207784955007898468, 0.0, 0.207784955007898468,
83 0.405845151377397167, 0.586087235467691130, 0.741531185599394440,
84 0.864864423359769073, 0.949107912342758525, 0.991455371120812639},
85 std::array<double, 15>{0.022935322010529225, 0.063092092629978553, 0.104790010322250184,
86 0.140653259715525919, 0.169004726639267903, 0.190350578064785410,
87 0.204432940075298892, 0.209482141084727828, 0.204432940075298892,
88 0.190350578064785410, 0.169004726639267903, 0.140653259715525919,
89 0.104790010322250184, 0.063092092629978553, 0.022935322010529225},
90 std::array<double, 15>{0.0, 0.129484966168869693, 0.0, 0.279705391489276668, 0.0,
91 0.381830050505118945, 0.0, 0.417959183673469388, 0.0,
92 0.381830050505118945, 0.0, 0.279705391489276668, 0.0,
93 0.129484966168869693, 0.0},
94 };
95 return rule;
96}
97
98inline void validate_order(int order, const std::string &context) {
99 if (order <= 0) {
100 throw InvalidArgument(context + ": order must be positive");
101 }
102}
103
104inline void validate_level(int level, const std::string &context) {
105 if (level <= 0) {
106 throw InvalidArgument(context + ": level must be positive");
107 }
108}
109
110inline double binomial(int n, int k) {
111 if (k < 0 || k > n) {
112 return 0.0;
113 }
114 if (k == 0 || k == n) {
115 return 1.0;
116 }
117 k = std::min(k, n - k);
118 double out = 1.0;
119 for (int i = 1; i <= k; ++i) {
120 out *= static_cast<double>(n - k + i) / static_cast<double>(i);
121 }
122 return out;
123}
124
125inline int clenshaw_curtis_order_from_level(int level) {
126 validate_level(level, "clenshaw_curtis_order_from_level");
127 if (level == 1) {
128 return 1;
129 }
130 return (1 << (level - 1)) + 1;
131}
132
133inline int gauss_order_from_level(int level) {
134 validate_level(level, "gauss_order_from_level");
135 return level;
136}
137
138inline bool is_bounded_support(const PolynomialChaosDimension &dimension) {
139 return dimension.family == PolynomialChaosFamily::Legendre ||
141}
142
143inline double standard_normal_moment(int degree) {
144 if (degree % 2 == 1) {
145 return 0.0;
146 }
147 const int half = degree / 2;
148 return std::exp(std::lgamma(static_cast<double>(degree) + 1.0) -
149 static_cast<double>(half) * std::log(2.0) -
150 std::lgamma(static_cast<double>(half) + 1.0));
151}
152
153inline double shifted_beta_moment(int degree, double alpha, double beta) {
154 const double a = beta + 1.0;
155 const double b = alpha + 1.0;
156
157 double moment = 0.0;
158 for (int j = 0; j <= degree; ++j) {
159 const double log_u_moment = std::lgamma(a + static_cast<double>(j)) + std::lgamma(a + b) -
160 std::lgamma(a) - std::lgamma(a + b + static_cast<double>(j));
161 const double u_moment = std::exp(log_u_moment);
162 const double coeff = binomial(degree, j) * std::pow(2.0, static_cast<double>(j)) *
163 ((degree - j) % 2 == 0 ? 1.0 : -1.0);
164 moment += coeff * u_moment;
165 }
166
167 return moment;
168}
169
170inline double probability_moment(const PolynomialChaosDimension &dimension, int degree) {
171 if (degree < 0) {
172 throw InvalidArgument("probability_moment: degree must be >= 0");
173 }
174
175 switch (dimension.family) {
177 return standard_normal_moment(degree);
178
180 if (degree % 2 == 1) {
181 return 0.0;
182 }
183 return 1.0 / static_cast<double>(degree + 1);
184
186 return shifted_beta_moment(degree, dimension.alpha, dimension.beta);
187
189 return std::exp(std::lgamma(dimension.alpha + static_cast<double>(degree) + 1.0) -
190 std::lgamma(dimension.alpha + 1.0));
191 }
192
193 throw InvalidArgument("probability_moment: unsupported family");
194}
195
197 const NumericVector &nodes) {
198 if (!is_bounded_support(dimension)) {
199 throw InvalidArgument("clenshaw_curtis_probability_weights: Clenshaw-Curtis is only "
200 "supported for bounded Legendre/Jacobi families");
201 }
202
203 if (nodes.size() == 1) {
204 NumericVector weights(1);
205 weights(0) = 1.0;
206 return weights;
207 }
208
209 if (dimension.family == PolynomialChaosFamily::Legendre) {
210 return 0.5 * cgl_weights(static_cast<int>(nodes.size()), nodes);
211 }
212
213 const Eigen::Index n = nodes.size();
214 NumericMatrix vandermonde(n, n);
215 NumericVector moments(n);
216
217 for (Eigen::Index k = 0; k < n; ++k) {
218 moments(k) = probability_moment(dimension, static_cast<int>(k));
219 }
220 for (Eigen::Index j = 0; j < n; ++j) {
221 double x_power = 1.0;
222 for (Eigen::Index k = 0; k < n; ++k) {
223 vandermonde(k, j) = x_power;
224 x_power *= nodes(j);
225 }
226 }
227
228 const NumericVector weights = vandermonde.colPivHouseholderQr().solve(moments);
229 const NumericVector residual = vandermonde * weights - moments;
230 if (residual.lpNorm<Eigen::Infinity>() > 1e-8) {
231 throw RuntimeError("clenshaw_curtis_probability_weights: failed to recover stable "
232 "quadrature weights");
233 }
234 return weights;
235}
236
238make_gauss_from_jacobi_matrix(const NumericVector &diag, const NumericVector &offdiag, int level) {
239 NumericMatrix J = NumericMatrix::Zero(diag.size(), diag.size());
240 J.diagonal() = diag;
241 for (Eigen::Index i = 0; i < offdiag.size(); ++i) {
242 J(i, i + 1) = offdiag(i);
243 J(i + 1, i) = offdiag(i);
244 }
245
246 Eigen::SelfAdjointEigenSolver<NumericMatrix> solver(J);
247 if (solver.info() != Eigen::Success) {
248 throw RuntimeError("make_gauss_from_jacobi_matrix: eigendecomposition failed");
249 }
250
252 rule.nodes = solver.eigenvalues();
253 rule.weights = solver.eigenvectors().row(0).array().square().transpose();
254 rule.nested = false;
255 rule.level = level;
256 return rule;
257}
258
260 int level) {
261 validate_order(order, "gauss_rule");
262 detail::validate_dimension(dimension, "gauss_rule");
263
264 switch (dimension.family) {
266 const auto [nodes, weights_dx] = gauss_legendre_rule(order);
268 rule.nodes = nodes;
269 rule.weights = 0.5 * weights_dx;
270 rule.nested = false;
271 rule.level = level;
272 return rule;
273 }
274
276 NumericVector diag = NumericVector::Zero(order);
277 NumericVector offdiag(std::max(0, order - 1));
278 for (int i = 1; i < order; ++i) {
279 offdiag(i - 1) = std::sqrt(static_cast<double>(i));
280 }
281 return make_gauss_from_jacobi_matrix(diag, offdiag, level);
282 }
283
285 NumericVector diag(order);
286 NumericVector offdiag(std::max(0, order - 1));
287 const double alpha = dimension.alpha;
288 const double beta = dimension.beta;
289
290 diag(0) = (beta - alpha) / (alpha + beta + 2.0);
291 for (int n = 1; n < order; ++n) {
292 const double nn = static_cast<double>(n);
293 const double nab = 2.0 * nn + alpha + beta;
294 diag(n) = (beta * beta - alpha * alpha) / (nab * (nab + 2.0));
295 }
296
297 for (int n = 1; n < order; ++n) {
298 const double nn = static_cast<double>(n);
299 const double numerator = 4.0 * nn * (nn + alpha) * (nn + beta) * (nn + alpha + beta);
300 const double denom = std::pow(2.0 * nn + alpha + beta, 2.0) *
301 (2.0 * nn + alpha + beta - 1.0) * (2.0 * nn + alpha + beta + 1.0);
302 offdiag(n - 1) = std::sqrt(numerator / denom);
303 }
304
305 return make_gauss_from_jacobi_matrix(diag, offdiag, level);
306 }
307
309 NumericVector diag(order);
310 NumericVector offdiag(std::max(0, order - 1));
311 const double alpha = dimension.alpha;
312 for (int n = 0; n < order; ++n) {
313 diag(n) = 2.0 * static_cast<double>(n) + alpha + 1.0;
314 }
315 for (int n = 1; n < order; ++n) {
316 offdiag(n - 1) = std::sqrt(static_cast<double>(n) * (static_cast<double>(n) + alpha));
317 }
318 return make_gauss_from_jacobi_matrix(diag, offdiag, level);
319 }
320 }
321
322 throw InvalidArgument("gauss_rule: unsupported family");
323}
324
326 int order, int level) {
327 if (dimension.family != PolynomialChaosFamily::Legendre) {
328 throw InvalidArgument("gauss_kronrod_rule: Gauss-Kronrod 15 is only supported for "
329 "Legendre / uniform dimensions");
330 }
331 if (order != 7 && order != 15) {
332 throw InvalidArgument("gauss_kronrod_rule: order must be 7 or 15");
333 }
334
335 const auto &embedded = gauss_kronrod_15_rule();
337 rule.nodes.resize(order);
338 rule.weights.resize(order);
339 rule.nested = true;
340 rule.level = level;
341
342 if (order == 15) {
343 for (int i = 0; i < 15; ++i) {
344 rule.nodes(i) = embedded.nodes[static_cast<std::size_t>(i)];
345 rule.weights(i) = 0.5 * embedded.primary_weights[static_cast<std::size_t>(i)];
346 }
347 return rule;
348 }
349
350 int cursor = 0;
351 for (int i = 0; i < 15; ++i) {
352 const double w = embedded.embedded_weights[static_cast<std::size_t>(i)];
353 if (w == 0.0) {
354 continue;
355 }
356 rule.nodes(cursor) = embedded.nodes[static_cast<std::size_t>(i)];
357 rule.weights(cursor) = 0.5 * w;
358 ++cursor;
359 }
360 return rule;
361}
362
364 int order, int level) {
365 if (!is_bounded_support(dimension)) {
366 throw InvalidArgument("clenshaw_curtis_rule: Clenshaw-Curtis is only supported for "
367 "bounded Legendre/Jacobi dimensions");
368 }
369
370 validate_order(order, "clenshaw_curtis_rule");
372 rule.nodes = (order == 1) ? NumericVector::Zero(1) : cgl_nodes(order);
373 rule.weights = clenshaw_curtis_probability_weights(dimension, rule.nodes);
374 rule.nested = true;
375 rule.level = level;
376 return rule;
377}
378
379inline std::vector<std::vector<int>> positive_compositions(int dim, int sum) {
380 std::vector<std::vector<int>> out;
381 std::vector<int> current(static_cast<std::size_t>(dim), 1);
382
383 std::function<void(int, int)> recurse = [&](int axis, int remaining) {
384 if (axis == dim - 1) {
385 current[static_cast<std::size_t>(axis)] = remaining;
386 out.push_back(current);
387 return;
388 }
389
390 for (int value = 1; value <= remaining - (dim - axis - 1); ++value) {
391 current[static_cast<std::size_t>(axis)] = value;
392 recurse(axis + 1, remaining - value);
393 }
394 };
395
396 recurse(0, sum);
397 return out;
398}
399
400inline std::string sample_key(const NumericVector &point, double tolerance) {
401 if (tolerance <= 0.0) {
402 throw InvalidArgument("sample_key: tolerance must be positive");
403 }
404
405 const double scale = 1.0 / tolerance;
406 std::string key;
407 key.reserve(static_cast<std::size_t>(point.size()) * 24u);
408 for (Eigen::Index i = 0; i < point.size(); ++i) {
409 const std::int64_t value = static_cast<std::int64_t>(std::llround(point(i) * scale));
410 key += std::to_string(value);
411 key.push_back('|');
412 }
413 return key;
414}
415
416} // namespace detail
417
428 switch (rule) {
430 return detail::gauss_rule(dimension, order, order);
431
433 return detail::clenshaw_curtis_rule(dimension, order, order);
434
436 return detail::gauss_kronrod_rule(dimension, order, order);
437
439 if (detail::is_bounded_support(dimension)) {
440 return detail::clenshaw_curtis_rule(dimension, order, order);
441 }
442 return detail::gauss_rule(dimension, order, order);
443 }
444
445 throw InvalidArgument("stochastic_quadrature_rule: unsupported rule");
446}
447
458 detail::validate_level(level, "stochastic_quadrature_level");
459
460 switch (rule) {
462 return detail::gauss_rule(dimension, detail::gauss_order_from_level(level), level);
463
465 return detail::clenshaw_curtis_rule(dimension,
467
469 if (level > 2) {
470 throw InvalidArgument("stochastic_quadrature_level: Gauss-Kronrod 15 only supports "
471 "levels 1 (7-point) and 2 (15-point)");
472 }
473 return detail::gauss_kronrod_rule(dimension, level == 1 ? 7 : 15, level);
474 }
475
477 if (detail::is_bounded_support(dimension)) {
479 dimension, detail::clenshaw_curtis_order_from_level(level), level);
480 }
481 return detail::gauss_rule(dimension, detail::gauss_order_from_level(level), level);
482 }
483
484 throw InvalidArgument("stochastic_quadrature_level: unsupported rule");
485}
486
493tensor_product_quadrature(const std::vector<UnivariateQuadratureRule> &rules) {
494 if (rules.empty()) {
495 throw InvalidArgument("tensor_product_quadrature: need at least one univariate rule");
496 }
497
498 Eigen::Index total_points = 1;
499 bool nested = true;
500 int level = 0;
501 for (const auto &rule : rules) {
502 if (rule.nodes.size() == 0 || rule.weights.size() == 0) {
503 throw InvalidArgument("tensor_product_quadrature: rules must contain nodes and "
504 "weights");
505 }
506 if (rule.nodes.size() != rule.weights.size()) {
507 throw InvalidArgument("tensor_product_quadrature: node/weight size mismatch");
508 }
509 if (total_points > std::numeric_limits<Eigen::Index>::max() / rule.nodes.size()) {
510 throw InvalidArgument("tensor_product_quadrature: grid is too large");
511 }
512 total_points *= rule.nodes.size();
513 nested = nested && rule.nested;
514 level = std::max(level, rule.level);
515 }
516
518 grid.samples.resize(total_points, static_cast<Eigen::Index>(rules.size()));
519 grid.weights.resize(total_points);
520 grid.nested = nested;
521 grid.level = level;
522
523 for (Eigen::Index row = 0; row < total_points; ++row) {
524 Eigen::Index cursor = row;
525 double weight = 1.0;
526 for (Eigen::Index axis = static_cast<Eigen::Index>(rules.size()) - 1; axis >= 0; --axis) {
527 const auto &rule = rules[static_cast<std::size_t>(axis)];
528 const Eigen::Index local = cursor % rule.nodes.size();
529 cursor /= rule.nodes.size();
530 grid.samples(row, axis) = rule.nodes(local);
531 weight *= rule.weights(local);
532 if (axis == 0) {
533 break;
534 }
535 }
536 grid.weights(row) = weight;
537 }
538
539 return grid;
540}
541
554smolyak_sparse_grid(const std::vector<PolynomialChaosDimension> &dimensions, int level,
555 SmolyakQuadratureOptions options = {}) {
556 if (dimensions.empty()) {
557 throw InvalidArgument("smolyak_sparse_grid: need at least one stochastic dimension");
558 }
559 detail::validate_level(level, "smolyak_sparse_grid");
560 if (options.merge_tolerance <= 0.0) {
561 throw InvalidArgument("smolyak_sparse_grid: merge_tolerance must be positive");
562 }
563 if (options.zero_weight_tolerance < 0.0) {
564 throw InvalidArgument("smolyak_sparse_grid: zero_weight_tolerance must be >= 0");
565 }
566
567 struct WeightedPoint {
568 NumericVector point;
569 double weight = 0.0;
570 };
571
572 std::map<std::string, WeightedPoint> merged;
573 const int dim = static_cast<int>(dimensions.size());
574 const int q = level + dim - 1;
575 bool fully_nested = true;
576
577 for (int sum = level; sum <= q; ++sum) {
578 const double combination =
579 (((q - sum) % 2) == 0 ? 1.0 : -1.0) * detail::binomial(dim - 1, q - sum);
580 if (combination == 0.0) {
581 continue;
582 }
583
584 for (const auto &index : detail::positive_compositions(dim, sum)) {
585 std::vector<UnivariateQuadratureRule> rules;
586 rules.reserve(dimensions.size());
587 for (int axis = 0; axis < dim; ++axis) {
589 dimensions[static_cast<std::size_t>(axis)],
590 index[static_cast<std::size_t>(axis)], options.rule);
591 fully_nested = fully_nested && rule.nested;
592 rules.push_back(std::move(rule));
593 }
594
596 for (Eigen::Index row = 0; row < tensor.samples.rows(); ++row) {
597 NumericVector point = tensor.samples.row(row).transpose();
598 const std::string key = detail::sample_key(point, options.merge_tolerance);
599 auto &entry = merged[key];
600 if (entry.point.size() == 0) {
601 entry.point = std::move(point);
602 }
603 entry.weight += combination * tensor.weights(row);
604 }
605 }
606 }
607
608 std::vector<WeightedPoint> points;
609 points.reserve(merged.size());
610 for (const auto &[key, value] : merged) {
611 (void)key;
612 if (std::abs(value.weight) <= options.zero_weight_tolerance) {
613 continue;
614 }
615 points.push_back(value);
616 }
617
618 if (points.empty()) {
619 throw RuntimeError("smolyak_sparse_grid: all points cancelled numerically");
620 }
621
623 grid.samples.resize(static_cast<Eigen::Index>(points.size()), static_cast<Eigen::Index>(dim));
624 grid.weights.resize(static_cast<Eigen::Index>(points.size()));
625 grid.nested = fully_nested;
626 grid.level = level;
627
628 for (std::size_t i = 0; i < points.size(); ++i) {
629 grid.samples.row(static_cast<Eigen::Index>(i)) = points[i].point.transpose();
630 grid.weights(static_cast<Eigen::Index>(i)) = points[i].weight;
631 }
632
633 return grid;
634}
635
644template <JanusScalar Scalar>
646 const UnivariateQuadratureRule &rule,
647 const JanusVector<Scalar> &sample_values) {
648 if (basis.dimension() != 1) {
649 throw InvalidArgument("pce_projection_coefficients(rule): univariate rule requires a "
650 "one-dimensional PolynomialChaosBasis");
651 }
652
653 NumericMatrix samples(rule.nodes.size(), 1);
654 samples.col(0) = rule.nodes;
655 return pce_projection_coefficients(basis, samples, rule.weights, sample_values);
656}
657
666template <JanusScalar Scalar>
668 const UnivariateQuadratureRule &rule,
669 const JanusMatrix<Scalar> &sample_values) {
670 if (basis.dimension() != 1) {
671 throw InvalidArgument("pce_projection_coefficients(rule): univariate rule requires a "
672 "one-dimensional PolynomialChaosBasis");
673 }
674
675 NumericMatrix samples(rule.nodes.size(), 1);
676 samples.col(0) = rule.nodes;
677 return pce_projection_coefficients(basis, samples, rule.weights, sample_values);
678}
679
688template <JanusScalar Scalar>
690 const StochasticQuadratureGrid &grid,
691 const JanusVector<Scalar> &sample_values) {
692 return pce_projection_coefficients(basis, grid.samples, grid.weights, sample_values);
693}
694
703template <JanusScalar Scalar>
705 const StochasticQuadratureGrid &grid,
706 const JanusMatrix<Scalar> &sample_values) {
707 return pce_projection_coefficients(basis, grid.samples, grid.weights, sample_values);
708}
709
710} // namespace janus
C++20 concepts constraining valid Janus scalar types.
Custom exception hierarchy for Janus framework.
Core type aliases for numeric and symbolic Eigen/CasADi interop.
Orthogonal polynomial evaluation, spectral nodes, weights, and differentiation matrices.
Polynomial chaos expansion (PCE) basis, projection, and regression.
Input validation failed (e.g., mismatched sizes, invalid parameters).
Definition JanusError.hpp:31
Multidimensional polynomial chaos basis with fixed truncation/order.
Definition PolynomialChaos.hpp:456
int dimension() const
Definition PolynomialChaos.hpp:488
Operation failed at runtime (e.g., CasADi eval with free variables).
Definition JanusError.hpp:41
Smooth approximation of ReLU function: softplus(x) = (1/beta) * log(1 + exp(beta * x)).
Definition Diagnostics.hpp:131
void validate_dimension(const PolynomialChaosDimension &dimension, const std::string &context)
Definition PolynomialChaos.hpp:112
std::pair< NumericVector, NumericVector > gauss_legendre_rule(int n)
Definition OrthogonalPolynomials.hpp:23
bool is_bounded_support(const PolynomialChaosDimension &dimension)
Definition Quadrature.hpp:138
void validate_level(int level, const std::string &context)
Definition Quadrature.hpp:104
double standard_normal_moment(int degree)
Definition Quadrature.hpp:143
UnivariateQuadratureRule gauss_kronrod_rule(const PolynomialChaosDimension &dimension, int order, int level)
Definition Quadrature.hpp:325
const EmbeddedQuadratureRule & gauss_kronrod_15_rule()
Definition Quadrature.hpp:78
void validate_order(int order, const std::string &context)
Definition Quadrature.hpp:98
NumericVector clenshaw_curtis_probability_weights(const PolynomialChaosDimension &dimension, const NumericVector &nodes)
Definition Quadrature.hpp:196
int clenshaw_curtis_order_from_level(int level)
Definition Quadrature.hpp:125
UnivariateQuadratureRule make_gauss_from_jacobi_matrix(const NumericVector &diag, const NumericVector &offdiag, int level)
Definition Quadrature.hpp:238
int gauss_order_from_level(int level)
Definition Quadrature.hpp:133
UnivariateQuadratureRule clenshaw_curtis_rule(const PolynomialChaosDimension &dimension, int order, int level)
Definition Quadrature.hpp:363
std::vector< std::vector< int > > positive_compositions(int dim, int sum)
Definition Quadrature.hpp:379
double binomial(int n, int k)
Definition Quadrature.hpp:110
double shifted_beta_moment(int degree, double alpha, double beta)
Definition Quadrature.hpp:153
double probability_moment(const PolynomialChaosDimension &dimension, int degree)
Definition Quadrature.hpp:170
UnivariateQuadratureRule gauss_rule(const PolynomialChaosDimension &dimension, int order, int level)
Definition Quadrature.hpp:259
std::string sample_key(const NumericVector &point, double tolerance)
Definition Quadrature.hpp:400
Definition Diagnostics.hpp:19
JanusVector< Scalar > pce_projection_coefficients(const PolynomialChaosBasis &basis, const NumericMatrix &samples, const NumericVector &weights, const JanusVector< Scalar > &sample_values)
Compute PCE projection coefficients from weighted samples (vector).
Definition PolynomialChaos.hpp:554
NumericVector cgl_weights(int N, const NumericVector &nodes)
CGL (Clenshaw-Curtis) quadrature weights on [-1, 1].
Definition OrthogonalPolynomials.hpp:224
Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > JanusMatrix
Dynamic-size matrix for both numeric and symbolic backends.
Definition JanusTypes.hpp:43
JanusMatrix< NumericScalar > NumericMatrix
Eigen::MatrixXd equivalent.
Definition JanusTypes.hpp:66
StochasticQuadratureGrid tensor_product_quadrature(const std::vector< UnivariateQuadratureRule > &rules)
Build the tensor-product grid from a list of one-dimensional rules.
Definition Quadrature.hpp:493
JanusVector< NumericScalar > NumericVector
Eigen::VectorXd equivalent.
Definition JanusTypes.hpp:67
UnivariateQuadratureRule stochastic_quadrature_rule(const PolynomialChaosDimension &dimension, int order, StochasticQuadratureRule rule=StochasticQuadratureRule::Gauss)
Build a one-dimensional stochastic quadrature rule with a fixed order.
Definition Quadrature.hpp:426
@ Jacobi
Beta-family random variable on [-1, 1].
Definition PolynomialChaos.hpp:28
@ Hermite
Standard normal random variable via probabilists' Hermite polynomials.
Definition PolynomialChaos.hpp:26
@ Laguerre
Gamma / exponential-family random variable on [0, inf).
Definition PolynomialChaos.hpp:29
@ Legendre
Uniform random variable on [-1, 1].
Definition PolynomialChaos.hpp:27
StochasticQuadratureRule
One-dimensional rule family used to generate stochastic quadrature nodes.
Definition Quadrature.hpp:54
@ AutoNested
Use Clenshaw-Curtis on bounded families, Gauss otherwise.
Definition Quadrature.hpp:58
@ ClenshawCurtis
Nested Clenshaw-Curtis-like rule on bounded support.
Definition Quadrature.hpp:56
@ Gauss
Family-appropriate Gauss rule.
Definition Quadrature.hpp:55
@ GaussKronrod15
Embedded 7/15-point Legendre rule reused from quad(...).
Definition Quadrature.hpp:57
UnivariateQuadratureRule stochastic_quadrature_level(const PolynomialChaosDimension &dimension, int level, StochasticQuadratureRule rule=StochasticQuadratureRule::AutoNested)
Build a one-dimensional stochastic quadrature rule from a refinement level.
Definition Quadrature.hpp:456
NumericVector cgl_nodes(int N)
Compute Chebyshev-Gauss-Lobatto nodes on [-1, 1].
Definition OrthogonalPolynomials.hpp:181
Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > JanusVector
Dynamic-size column vector for both numeric and symbolic backends.
Definition JanusTypes.hpp:49
StochasticQuadratureGrid smolyak_sparse_grid(const std::vector< PolynomialChaosDimension > &dimensions, int level, SmolyakQuadratureOptions options={})
Build a Smolyak sparse grid on probability measures.
Definition Quadrature.hpp:554
Multidimensional stochastic quadrature grid with row-major sample layout.
Definition Quadrature.hpp:44
NumericMatrix samples
Definition Quadrature.hpp:45
int level
Definition Quadrature.hpp:48
NumericVector weights
Definition Quadrature.hpp:46
bool nested
Definition Quadrature.hpp:47
One-dimensional stochastic quadrature rule on a probability measure.
Definition Quadrature.hpp:30
bool nested
Definition Quadrature.hpp:33
One stochastic dimension in a polynomial chaos basis.
Definition PolynomialChaos.hpp:47
PolynomialChaosFamily family
Definition PolynomialChaos.hpp:48
double alpha
Definition PolynomialChaos.hpp:49
double beta
Definition PolynomialChaos.hpp:50
Options for Smolyak sparse-grid construction.
Definition Quadrature.hpp:64
double zero_weight_tolerance
Definition Quadrature.hpp:67
double merge_tolerance
Definition Quadrature.hpp:66
StochasticQuadratureRule rule
Definition Quadrature.hpp:65
Multidimensional stochastic quadrature grid with row-major sample layout.
Definition Quadrature.hpp:44
NumericMatrix samples
Definition Quadrature.hpp:45
int level
Definition Quadrature.hpp:48
NumericVector weights
Definition Quadrature.hpp:46
bool nested
Definition Quadrature.hpp:47
One-dimensional stochastic quadrature rule on a probability measure.
Definition Quadrature.hpp:30
int level
Definition Quadrature.hpp:34
NumericVector nodes
Definition Quadrature.hpp:31
NumericVector weights
Definition Quadrature.hpp:32
bool nested
Definition Quadrature.hpp:33
Definition Quadrature.hpp:72
std::array< double, 15 > primary_weights
Definition Quadrature.hpp:74
std::array< double, 15 > nodes
Definition Quadrature.hpp:73
std::array< double, 15 > embedded_weights
Definition Quadrature.hpp:75
JanusVector< NumericScalar > NumericVector
Eigen::VectorXd equivalent.
Definition JanusTypes.hpp:67