Nucleide

UQ-Lite Sampling

Seeded multivariate-normal sampling over caller-supplied covariance blocks, SANDY-compatible moment estimators, and the decay perturbation consumer.

Nucleide UQ-lite draws seeded multivariate-normal samples over caller-supplied covariance blocks: the SANDY role (seeded MVN draws that reproduce caller covariance information) with no vendored covariance stores, no transport coupling, and no ERRORR/NJOY machinery. The moment estimators agree exactly with SANDY’s Samples.get_mean / get_cov (oracle-check gate at 1e-9 against SANDY 1.1.0)fiorito-2017sandy-repo.

Overview

Given a mean vector μ∈Rp\mu \in \mathbb{R}^p and a covariance block C∈Rp×pC \in \mathbb{R}^{p \times p}, the kernel draws nn reproducible samples x∼N(μ,C)x \sim N(\mu, C), checks the sample moments recover the inputs, and optionally applies the draws as relative/absolute/log-normal perturbations to decay data. A log-normal entry point draws x∼N(μlog⁡,Clog⁡)x \sim N(\mu_{\log}, C_{\log}) in log space and returns y=exp⁡(x)y = \exp(x). Seeds pin the ChaCha12 stream, so identical inputs give bit-identical samples.

Mathematical details

Factor sampling: with any BB such that BBT=CB B^T = C and z∼N(0,I)z \sim N(0, I),

x=μ+Bz.(U1)x = \mu + B z. \tag{U1}

The primary path takes B=LB = L from the Cholesky factorisation; when CC is positive-semidefinite but numerically singular, the fallback is the eigen-clipping reconstruction B=Uclip(S)B = U \sqrt{\mathrm{clip}(S)} with eigenvalues floored at 10−1210^{-12} times the largest eigenvalue. Standard normals come from the Box–Muller transformbox-muller-1958.

Sample moments use the unbiased covariance (Anderson, Ch. 3)anderson-2003:

xˉ=1n∑kxk,S=1n−1∑k(xk−xˉ)(xk−xˉ)T.(U2)\bar{x} = \frac{1}{n}\sum_k x_k, \qquad S = \frac{1}{n-1}\sum_k (x_k - \bar{x})(x_k - \bar{x})^T. \tag{U2}

The 1/(n−1)1/(n-1) denominator matches pandas.DataFrame.cov (ddof=1), which is what SANDY’s Samples.get_cov calls — that shared convention is what the oracle-check gate checks.

Convergence gates use the MVN sampling variances (Anderson, Ch. 7)anderson-2003:

std(xˉi)=Cii/n,Var(Sij)=CiiCjj+Cij2 n−1 .(U3)\mathrm{std}(\bar{x}_i) = \sqrt{C_{ii}/n}, \qquad \mathrm{Var}(S_{ij}) = \frac{C_{ii}C_{jj} + C_{ij}^2}{\,n-1\,}. \tag{U3}

Honest gates assert moments within kk standard errors at a stated kk (the fixtures pin k=5k = 5) — never hand-waved round numbers.

Perturbation conventions apply one draw elementwise:

relative:x′=b (1+δ),absolute:x′=b+δ,lognormal:x′=b exp⁡(δ).(U4)\mathrm{relative:}\quad x' = b\,(1 + \delta), \qquad \mathrm{absolute:}\quad x' = b + \delta, \qquad \mathrm{lognormal:}\quad x' = b\,\exp(\delta). \tag{U4}

Log-normal draws reuse the (U1) factor path and RNG stream, then map y=exp⁡(x)y = \exp(x) elementwise; μlog⁡\mu_{\log}/Clog⁡C_{\log} are log-space MVN parameters, never the moments of yy itself. The closed-form moments are

E[yi]=exp⁡(μi+Cii/2),Cov(yi,yj)=exp⁡(μi+μj+(Cii+Cjj)/2) (exp⁡(Cij)−1).(U6)\mathrm{E}[y_i] = \exp(\mu_i + C_{ii}/2), \qquad \mathrm{Cov}(y_i, y_j) = \exp(\mu_i + \mu_j + (C_{ii} + C_{jj})/2)\,(\exp(C_{ij}) - 1). \tag{U6}

Branch fractions renormalise to preserve the incoming 1−BR(SF)1 - \mathrm{BR(SF)} deficit (spontaneous-fission branches are dropped at generation time, so kept branches sum to the kept share, not 1.0):

bi′=kept  max⁡(0, bi(1+δi))∑jmax⁡(0, bj(1+δj)).(U5)b'_i = \mathrm{kept}\; \frac{\max(0,\, b_i(1 + \delta_i))} {\sum_j \max(0,\, b_j(1 + \delta_j))}. \tag{U5}

Negative raw branches clamp to zero before renormalisation: the negative-clamp half of SANDY Samples.truncate_normal(mode=1), which additionally caps values above 2 at 2 for relative-unit samples centered at 1 — no analogue here, since branches renormalise and energies are absolute.

Fission yields renormalise to preserve the incoming block sum — the same deficit discipline as (U5), except the preserver is sum(base) itself (independent blocks sum to 2 per parent/energy set, cumulative blocks sum higher), never a hard-coded constant:

bi′=kept  max⁡(0, bi(1+δi))∑jmax⁡(0, bj(1+δj)),kept=∑jbj.(U8)b'_i = \mathrm{kept}\; \frac{\max(0,\, b_i(1 + \delta_i))} {\sum_j \max(0,\, b_j(1 + \delta_j))}, \qquad \mathrm{kept} = \sum_j b_j. \tag{U8}

Zero-base rows stay zero via 0(1+δ)=00(1 + \delta) = 0. The kernel owns no yield data and never selects the set: the caller supplies the block and builds the relative draws (tape dY/Y sigmas, or correlated draws from (U1) forwarded as δ\delta); set selection (e.g. the lowest-energy independent set) lives with the caller. Explicit-covariance mode is that composition — no new parameters.

Latin-hypercube draws reuse the (U1) factor path with a stratified normal source:

uj,i=(πj(i)+wj,i)/n,zj,i=Φ−1(uj,i),xi=μ+Bzi.(U7)u_{j,i} = (\pi_j(i) + w_{j,i})/n, \quad z_{j,i} = \Phi^{-1}(u_{j,i}), \quad x_i = \mu + B z_i. \tag{U7}

Per dimension jj, one jittered uniform per stratum: πj\pi_j is a Fisher–Yates permutation of 0..n−10..n-1 and wj,i∼U(0,1)w_{j,i} \sim U(0,1), both from the seeded StdRng (ChaCha12); Φ−1\Phi^{-1} is the hand-rolled inverse-normal CDF on f64 (Acklam/Beasley-Springer-Moro rational-approximation class — same arithmetic class as the Box–Muller closurebox-muller-1958); then the shared factor path (Cholesky primary, eigen-clip fallback, reported never silent) and x=μ+Bzx = \mu + Bz. LHS is a draw mode, not a perturbation convention. The pinned kk-SE IID gates (U3) are the wrong null for stratified draws — LHS variance is smaller than IID by construction — so the separate gate is: G1 stratification-exact (each dimension hits each of the nn strata exactly once at the pinned seed) plus G2 LHS-valid moment bound (sample mean/covariance within kk IID standard errors from (U3) as an upper bound, never an equality null). Oracle-check SANDY get_mean/get_cov 1e-9 agreement is estimator identities, draw-independentfiorito-2017.

Algorithm

sample_mvn validates (non-empty, square, finite, symmetric within 10−810^{-8} relative tolerance — SANDY instead requires exact symmetry), factorises (Cholesky, else eigen-clip with the taken path reported, never silent), fills a Box–Muller stream from the seed, and applies (U1). sample_lognormal reuses that path and stream, then applies y=exp⁡(x)y = \exp(x) (f64::exp is the only addition); lognormal_mean / lognormal_cov spell the closed-form (U6) moments. sample_lhs reuses the same validation, factor path, and x=μ+Bzx = \mu + Bz application with the stratified (U7) normal source (per-dimension Fisher–Yates permutation plus jitter from the seeded StdRng, hand-rolled Φ−1\Phi^{-1}). sample_mean / sample_cov implement (U2); check_convergence implements (U3) with caller tolerances. perturb_branches implements (U5); perturb_fission_yields implements (U8) over caller-supplied yield blocks; perturb_energies implements (U4) with a zero clamp (a no-op for the log-normal convention, whose draws stay positive).

Worked example

The fixtures/uq/cov_2x2.json block C=(0.250.100.100.16)C = \bigl(\begin{smallmatrix}0.25 & 0.10\\ 0.10 & 0.16\end{smallmatrix}\bigr) has the closed-form Cholesky factor L=(0.5000.200.12≈0.3464)L = \bigl(\begin{smallmatrix}0.50 & 0\\ 0.20 & \sqrt{0.12}\approx0.3464\end{smallmatrix}\bigr): 0.502=0.250.50^2 = 0.25, 0.50×0.20=0.100.50 \times 0.20 = 0.10, 0.202+0.34642≈0.160.20^2 + 0.3464^2 \approx 0.16. At the pinned seed the 20,000 draws recover the inputs within 0.78 standard errors (U1 gate, k=5k = 5).

The fixtures/uq/lognormal_2x2.json log-space block (μlog⁡=0\mu_{\log} = 0, Clog⁡C_{\log} with variances 0.04/0.09 and covariance 0.01) has closed-form log-normal moments E[y]=(e0.02,e0.045)≈(1.0202,1.0460)\mathrm{E}[y] = (e^{0.02}, e^{0.045}) \approx (1.0202, 1.0460) from (U6). At the pinned seed the 50,000 draws satisfy the separate U5 gate: ln⁡(y)\ln(y) recovers the log-space block within the MVN kk-SE gate and the sample mean of yy recovers E[y]\mathrm{E}[y] within kk standard errors (k=5k = 5) — the MVN gates are not reused after the exp⁡\exp transform.

The fixtures/uq/lhs_2x2.json block (mean [1,2][1, 2], CC as above, n=5000n = 5000, k=5k = 5, seed 20260916) takes the Cholesky path at the pinned seed and satisfies the separate U6 gate (theory U7): G1 exact one-per-stratum recovery per dimension plus G2 sample mean/covariance within the kk IID standard-error upper bound (moment worst 1.064 SE at the pinned seed).

The U7 gate perturbs a caller-selected U235-thermal subset (Te134/Xe138/Sr95 from the real yield library, dY/Y sigmas, n=20000n = 20000, k=5k = 5, seed 20260917) with theory (U8): every perturbed draw sums to the incoming block sum exactly (kept sum 0.1556691), and the forwarded relative draws recover their diagonal moment block within the IID kk-SE gate (moment worst 1.534 SE at the pinned seed).

Assumptions and limitations

  • Inputs are caller-supplied blocks; no covariance library is read or shipped, and no ENDF/ERRORR parsing exists here.
  • Fission-yield perturbation over caller-supplied blocks is in (perturb_fission_yields, theory U8, U7 gate); ERRORR/NJOY covariance tapes for yields stay out (caller-supplied blocks only), as do MF32/MF40 resonance machinery and transport coupling. Latin-hypercube sampling over caller-supplied blocks is in (sample_lhs, theory U7, separate G1/G2 gate); tape-driven LHS workflows stay out.
  • Draws are not interchangeable with SANDY’s: the published SANDY scheme factorises the correlation structure with Cholesky, but the current SANDY implementation uses SVD behind a different RNG stream — same target distribution, different bits. Only the estimators agree.
  • SANDY samples MF31–MF35/MF8 covariances from ENDF-6 tapes (including decay data and fission yields) with NJOY/ERRORR preprocessing and variance-decomposition sensitivity indices — beyond this kernel’s caller-block scope. Fission-yield parity is closed over caller-supplied blocks (perturb_fission_yields, U8, U7 gate); tape-driven FY covariance workflows stay out. Latin-hypercube parity is closed over caller-supplied blocks (sample_lhs, U7, G1/G2 gate); tape-driven LHS workflows stay out. Log-normal sampling is covered here only over caller-supplied blocks (y=exp⁡(x)y = \exp(x) post-transform with log-space mean/covariance semantics); tape-driven log-normal workflows stay out.
  • SANDY’s summarize_sample (Frobenius-norm deviations, normality tests) is the closest analogue of check_convergence; ours is the kk-standard-error formulation (U3) instead.

The validation/uq_lite_vs_sandy.py harness checks the kernel two ways: seeded synthetic statistical checks in-repo and a live SANDY moment comparison against the 1.1.0 wheel in the validation container.

See also

References

  1. [sandy-repo]SANDY source (LGPL-3.0-or-later)— Upstream implementation (2026)↩
  2. [anderson-2003]An Introduction to Multivariate Statistical Analysis, 3rd ed.— Wiley Series in Probability and Statistics, 752 (2003)↩
  3. [nucleide-linalg]Nucleide linalg implementation— Nucleide implementation (2026)↩