Reference
Quadriceps — Module
QuadricepsPositive-weight cubature rules in d ≥ 1 dimensions for two weight functions:
- GH (
ghpos): the Gaussian weight, by default the standard normal densityN(0, I_d); - Le (
lepos): the uniform weight, by default the uniform density on[0,1]^d.
A rule of degree p integrates every polynomial of total degree ≤ p exactly. All weights are strictly positive. The rules shipped with the package are the smallest ones known to its author; see the README and the documentation for where each one comes from.
The two exported functions mirror gausshermite and gausslegendre from FastGaussQuadrature.jl:
X, w = ghpos(3, 4) # as exact as the 4×4×4 Gauss–Hermite grid (degree 7), with 27 nodes
X, w = ghpos(3; p = 7) # the same rule, requested by degree
X, w = lepos(2, 5) # degree 9 on the unit square: 17 nodes instead of 25The second argument q is the number of nodes of the one-dimensional Gauss rule whose exactness is wanted, as in gausshermite(q); the degree is p = 2q - 1.
Unexported but public: Quadriceps.available, Quadriceps.extended, Quadriceps.nnodes, Quadriceps.ruleinfo, Quadriceps.exactness_error.
Exported
Quadriceps.ghpos — Function
ghpos([T = Float64,] d, q; normalize = true, pragmatic = false) -> X, w
ghpos([T = Float64,] d; p, normalize = true, pragmatic = false) -> X, wPositive-weight cubature rule for the Gaussian weight in d dimensions: the smallest one the package has.
The first method follows gausshermite(q; normalize) of FastGaussQuadrature.jl. There, q is the number of nodes of the one-dimensional Gauss rule, which is exact to degree 2q - 1. Here, ghpos(d, q) returns a rule with the same exactness in d dimensions, degree p = 2q - 1, that replaces the q^d-node product grid; for d = 1 it is gausshermite(q) itself. The second method takes the degree directly, as the keyword p; ghpos(d, q) is ghpos(d; p = 2q - 1).
X is an n × d matrix with one node per row, w the vector of n weights, all strictly positive, and
\[\sum_{i=1}^n w_i f(X_{i,1}, …, X_{i,d}) = \int f(x)\, ω(x)\, dx\]
for every polynomial f of total degree ≤ p (up to rounding; see Quadriceps.ruleinfo for the measured error of each stored rule).
Keyword arguments
p: the degree of exactness,p ≥ 0(second method only, required). Rules are stored at odd degrees; a request is served by the smallest stored rule of degree≥ p, so an evenpgets the rule forp + 1.normalize = true: the weight is the standard normal densityω(x) = (2π)^(-d/2) exp(-|x|²/2), so the weights sum to 1 and the rule computesE f(Z)forZ ~ N(0, I_d). Withnormalize = falsethe weight isω(x) = exp(-|x|²)and the weights sum toπ^(d/2). The keyword means what it means ingausshermite, but the default differs:gausshermitedefaults tonormalize = false, and only itsnormalize = trueis a rule for the normal density.pragmatic = false: what to do when no stored rule covers the request. Withfalse, throw anArgumentError. Withtrue, return the cheapest (fewest nodes) tensor product of lower-dimensional rules instead: stored rules and one-dimensional Gauss–Hermite rules, combined over the split ofdthat minimizes the number of nodes. Such a product is a valid positive-weight rule of the requested degree; it is just not small. Withpragmatic = truethe product is also returned in the rare case that it has strictly fewer nodes than the stored rule, so the result is always the cheapest the package can build.
Number type
The optional first argument T is the element type of X and w. Beyond Float64 the data depend on how many significant bits T holds (precision(T); a type without that method counts as wide):
- up to 113 bits —
Float128of Quadmath.jl,Double64of DoubleFloats.jl,BigFloatundersetprecision(BigFloat, 113)— are served fromdata/rules128.bin: every node and weight is the 80-digit rule correctly rounded to IEEE binary128 (113 bits, about 34 digits), and forFloat128the conversion is exact; - more than 113 bits —
BigFloatat its default 256 bits,Float64x4of MultiFloats.jl, … — are served fromdata/rules80.bin: the 80-digit rules of the Zenodo deposit (record 10.5281/zenodo.22881864) themselves, held in a 40-byte binary format. The result carries 80 correct digits, whatever the precision ofT.
Both files ship with the package; nothing is fetched from anywhere. Rounded on to Float64 either is the Float64 rule (to the last bit, except that a coordinate of size 1e-30 standing for zero can come out one unit in the last place off). One-dimensional Gauss factors are computed to the accuracy of the data they are combined with. Quadriceps.extended lists the cells with the measured error of each rule in both formats: every stored rule is one of them, so T never fails on a cell the Float64 call answers.
using Quadmath
X, w = ghpos(Float128, 3, 4) # the 27-node rule in quadruple precision
X, w = ghpos(BigFloat, 3, 4) # the same rule to 80 digits
Float64.(X) ≈ ghpos(3, 4)[1] # true: the same ruleDetails
d = 1returns the Gauss–Hermite rule withq(orp ÷ 2 + 1) nodes, as ann × 1matrix; it is never an error.- The result is a fresh copy; mutating it does not affect later calls. Loaded rules are cached, so repeated calls are cheap.
Examples
X, w = ghpos(3, 4) # degree 7: 27 nodes instead of 4³ = 64
sum(w .* X[:, 1] .^ 2 .* X[:, 2] .^ 4) # E[Z₁² Z₂⁴] = 3
ghpos(3; p = 7) == ghpos(3, 4) # true
ghpos(3, 21) # ArgumentError: nothing stored at that degree
X, w = ghpos(3, 21; pragmatic = true) # tensor product of lower-dimensional rules
X, w = ghpos(7, 5; pragmatic = true) # d = 7 as (d = 2) × (d = 5)See also lepos, Quadriceps.nnodes, Quadriceps.available.
Quadriceps.lepos — Function
lepos([T = Float64,] d, q; normalize = true, pragmatic = false) -> X, w
lepos([T = Float64,] d; p, normalize = true, pragmatic = false) -> X, wPositive-weight cubature rule for the uniform weight on a d-dimensional cube: the smallest one the package has.
The first method follows gausslegendre(q) of FastGaussQuadrature.jl: q is the number of nodes of the one-dimensional Gauss rule, and lepos(d, q) returns a rule with the same exactness in d dimensions, degree p = 2q - 1, that replaces the q^d-node product grid; for d = 1 it is gausslegendre(q) itself. The second method takes the degree directly, as the keyword p; lepos(d, q) is lepos(d; p = 2q - 1).
X is an n × d matrix with one node per row, w the vector of n weights, all strictly positive, and sum(w[i] * f(X[i, :])) equals the integral of f against the weight for every polynomial f of total degree ≤ p (up to rounding; see Quadriceps.ruleinfo).
Keyword arguments
p: the degree of exactness,p ≥ 0(second method only, required); an evenpgets the rule forp + 1.normalize = true: the weight is the uniform density on[0,1]^d, so the weights sum to 1 and the rule computesE f(U)forUuniform on the unit cube. Withnormalize = falsethe rule is for∫ f(x) dxover[-1,1]^d, the convention ofgausslegendre, and the weights sum to2^d.pragmatic = false: as forghpos. Withfalse, a request that no stored rule covers is anArgumentError; withtrue, the cheapest tensor product of lower-dimensional rules (stored rules and one-dimensional Gauss–Legendre rules) is returned instead.
The optional number type T and the details listed under ghpos apply here too. All nodes of every stored Le rule lie inside the cube.
Examples
X, w = lepos(2, 5) # degree 9: 17 nodes on [0,1]² instead of 25
sum(w .* X[:, 1] .^ 3 .* X[:, 2] .^ 2) # 1/4 · 1/3
X, w = lepos(2, 5; normalize = false) # the same rule on [-1,1]², weights sum to 4
X, w = lepos(6, 6; pragmatic = true) # d = 6 from a product of stored rulesSee also ghpos, Quadriceps.nnodes, Quadriceps.available.
Public, not exported
Quadriceps.available — Function
Quadriceps.available(family)All stored rules of family (:gh or :le), as a vector of Quadriceps.RuleInfo sorted by dimension and degree. Tensor products, which pragmatic = true builds on demand, are not listed.
[(r.d, r.p, r.n) for r in Quadriceps.available(:gh) if r.d == 3]Quadriceps.extended — Function
Quadriceps.extended(family)The cells of family (:gh or :le) that are stored beyond double precision — every stored cell — and so available as ghpos(T, d, q) or lepos(T, d, q) for a number type T wider than Float64: a vector of named tuples (family, d, p, n, relerr128, relerr80), sorted by dimension and degree. Both errors are the largest relative monomial error of the rule, measured in much wider arithmetic: relerr128 of the rule rounded to IEEE binary128 (Float128; the unit is the machine epsilon of that format, 2^-112 ≈ 1.93e-34, and a few epsilons is the floor of the format, as a few 1e-16 is for the relerr of the Float64 rules), relerr80 of the 80-digit rule that a type wider than 113 bits receives, as the deposit measured it.
Quadriceps.nnodes — Function
Quadriceps.nnodes(family, d, q; pragmatic = false) -> Integer
Quadriceps.nnodes(family, d; p, pragmatic = false) -> IntegerNumber of nodes of the rule that ghpos (family = :gh) or lepos (family = :le) returns for the same arguments, without building it. Throws the same ArgumentError when there is no rule. The count is an Int when it fits and a BigInt otherwise (tensor products in high dimensions).
Quadriceps.ruleinfo — Function
Quadriceps.ruleinfo(family, d, q; pragmatic = false)
Quadriceps.ruleinfo(family, d; p, pragmatic = false)Describe the rule that ghpos or lepos returns for the same arguments: a vector with one entry per tensor factor, in the order of the columns of X. An entry is either the Quadriceps.RuleInfo of a stored rule (dimension, degree, node count, measured error, origin) or, for a one-dimensional Gauss factor, the named tuple (family, d = 1, p, n, origin = "Gauss"). A request answered by a single stored rule gives a one-element vector.
Use it to find out whom to cite: the origin field names the published source of every rule that is not the package author's own.
Quadriceps.RuleInfo — Type
Quadriceps.RuleInfoCatalog entry of one stored rule. Fields:
family—:ghor:le;d,p,n— dimension, degree of exactness, number of nodes;moller— Möller's lower bound onnfor this(d, p), or-1where it is not tabulated; a rule withn == molleris proven minimal;relerr— largest relative monomial error of the storedFloat64rule over all monomials of total degree≤ p, measured when the package data were built (seeQuadriceps.exactness_error);minweight— smallest weight (always> 0);interior—truewhen every node lies inside the integration domain (alwaystruefor GH);origin— who the rule belongs to:"own", or"derived: …","same-rule: …","transcribed: …"followed by the published source;source_id— the same information as the small integer stored indata/rules.bin(0: own; 3: derived from Diallo and Worku; 10 and up: a published rule; see the format page).
Quadriceps.exactness_error — Function
Quadriceps.exactness_error(X, w, p, family) -> errLargest relative monomial error of the rule (X, w) over all monomials of total degree ≤ p, for the normalized weight of family (:gh: N(0, I_d); :le: uniform on [0,1]^d):
\[\max_{|a| ≤ p} \frac{|\sum_i w_i x_i^a - \mathrm{E}\,x^a|}{\max(\sum_i |w_i|\,|x_i^a|,\ 1)} .\]
The denominator is the scale of the sum being computed, so a value near eps() means the rule is exact to rounding. The element type of X and w sets the arithmetic: pass BigFloat arrays to measure beyond double precision. Rules returned with normalize = false must be checked in the normalized frame.
X, w = ghpos(4, 5) # degree 2·5 - 1 = 9
Quadriceps.exactness_error(X, w, 9, :gh) # ≈ 4e-16