mixle.doe.propagate module

Forward uncertainty propagation: push an input distribution through a model to output statistics.

Given input uncertainty (a Gaussian or a sampler) and a model f, report the induced uncertainty on the output – mean, standard deviation, and quantiles. Monte Carlo is general; the unscented transform propagates the first two moments with 2d+1 deterministic sigma points (exact for a linear model, a useful low-cost approximation for mild nonlinearity). The back half of the UQ loop, after sensitivity.

propagate(func, mean, cov=None, *, n=10000, method='montecarlo', quantiles=(0.05, 0.5, 0.95), seed=0)[source]

Propagate a Gaussian input N(mean, cov) through func to output statistics.

Parameters:
  • func (Callable[[ndarray], ndarray]) – a vectorized model f(X) -> y mapping (m, d) inputs to (m,) (or (m, k)) outputs.

  • mean (ndarray) – length-d input mean. cov: (d, d) input covariance (defaults to identity).

  • n (int) – Monte Carlo sample size (ignored by the unscented method).

  • method (str) – 'montecarlo' (sample + summarize, gives quantiles) or 'unscented' (sigma-point moment propagation, mean + std only). Looked up through the propagator registry.

  • quantiles (tuple[float, ...]) – output quantiles to report (Monte Carlo only).

  • cov (ndarray | None)

  • seed (int)

Returns:

{'mean', 'std', 'quantiles' (mc only), 'samples' (mc only)}.

Raises:

ValueError – if mean is non-finite, cov’s shape doesn’t match mean, cov is not a valid (finite, PSD-within-tolerance) covariance, n is not a positive integer, any quantiles entry is outside [0, 1], or method is not registered.

Return type:

dict[str, Any]

register_propagator(name)[source]

Decorator registering a propagation method under name for propagate().

The decorated callable receives (func, mean, cov, *, n, quantiles, seed) (mean/cov already coerced to float arrays) and returns the output-statistics dict.

(MXR-080-1901) Registering a name that is already taken raises instead of replacing it. The old _PROPAGATORS[name] = fn silently overwrote, so re-registering "montecarlo" (by import order, a name collision between two plugins, or a module imported twice) changed what EVERY existing propagate(..., method="montecarlo") call in the process returns – the same call site, the same documented method name, different outputs, and nothing anywhere recording the substitution. This is the registry’s only mutation point, so refusing the collision here is enough to make a resolved method name mean one fixed thing for the life of the process. Adding a NEW name is unaffected: that is the extension point and it stays open. To deliberately replace a built-in, delete the existing entry from _PROPAGATORS first – an explicit, greppable act rather than an invisible one.

Parameters:

name (str)

Return type:

Callable[[Callable[[…], dict[str, Any]]], Callable[[…], dict[str, Any]]]

unscented_transform(func, mean, cov, *, alpha=1e-3, beta=2.0, kappa=0.0)[source]

Propagate (mean, cov) through func with the unscented (sigma-point) transform.

Returns the output (mean, covariance). Exact for an affine func; for a nonlinear one it captures the mean and covariance to second order with only 2d+1 evaluations.

Raises:

ValueError – if mean is non-finite, cov’s shape doesn’t match mean, cov is not a valid covariance (see _safe_cholesky()), alpha/beta/kappa are not finite non-Boolean scalars, alpha <= 0, beta < 0, d + lambda <= 0, func’s return doesn’t have a leading dimension of 2d+1 (rejected explicitly, not silently reinterpreted via a total-size-only reshape), or func’s return or derived covariance is non-finite/invalid.

Parameters:
Return type:

tuple[ndarray, ndarray]