geopulse.uq.uncertain

Core uncertainty type: Uncertain[T].

Design philosophy: UQ is baked in from day one, not bolted on later. The Uncertain type wraps any numeric value (scalar, array, or dataclass) and can represent either a deterministic value or a distribution of values.

When deterministic values flow through the pipeline, there is zero overhead. When distributions flow through, Monte-Carlo propagation kicks in via propagate_uncertainty().

Examples

>>> from geopulse.uq.uncertain import Uncertain, propagate_uncertainty
>>> b = Uncertain(nominal=1.0, distribution="gaussian", params={"std": 0.1})
>>> out = propagate_uncertainty(lambda x: 2.0 * x, b, n_samples=200)
>>> abs(out.mean - 2.0) < 0.05
True

Functions

propagate_uncertainty(func, *args[, ...])

Propagate uncertainty through a function via Monte Carlo.

Classes

Uncertain(nominal[, samples, distribution, ...])

A value that may carry uncertainty information.

class geopulse.uq.uncertain.Uncertain(nominal, samples=None, distribution='deterministic', params=<factory>)[source]

Bases: Generic[T]

A value that may carry uncertainty information.

Parameters:
  • nominal (TypeVar(T)) – The central / best-estimate value.

  • samples (Optional[list[TypeVar(T)]]) – Monte-Carlo samples, if uncertainty has been propagated. Length equals the number of MC draws.

  • distribution (str) – Distribution family. One of "deterministic", "gaussian", "uniform", "ensemble". Default: "deterministic".

  • params (dict) – Distribution parameters. For gaussian: {"std": ...}. For uniform: {"low": ..., "high": ...}. For ensemble: empty (samples ARE the distribution).

Notes

Uncertain is not frozen: generate_samples() is a query method and does not mutate the instance, but downstream propagation code may attach freshly-drawn samples after construction.

nominal: T
samples: list[T] | None = None
distribution: str = 'deterministic'
params: dict
property is_deterministic: bool

Whether this value carries no uncertainty.

property n_samples: int

Number of Monte-Carlo samples, or 0 if deterministic.

property mean: Any

Mean of samples, or nominal if deterministic.

property std: Any

Standard deviation of samples, or zero if deterministic.

generate_samples(n, rng=None)[source]

Draw n Monte-Carlo samples from the declared distribution.

Parameters:
  • n (int) – Number of samples to generate.

  • rng (Optional[Generator]) – Reproducible RNG. If None, a fresh default RNG is created.

Return type:

list

Returns:

listn samples, each with the same shape/type as nominal.

Raises:

ValueError – If distribution is not one of the supported families.

geopulse.uq.uncertain.propagate_uncertainty(func, *args, n_samples=100, seed=42, **kwargs)[source]

Propagate uncertainty through a function via Monte Carlo.

Any argument that is an Uncertain with a non-deterministic distribution is sampled; deterministic arguments pass through unchanged.

Parameters:
  • func (Callable[..., Any]) – The function to propagate through.

  • *args (Any) – Positional arguments — may include Uncertain values.

  • n_samples (int) – Number of Monte-Carlo samples. Default: 100.

  • seed (int) – Random seed for reproducibility. Default: 42.

  • **kwargs (Any) – Keyword arguments — may include Uncertain values.

Return type:

Uncertain

Returns:

Uncertain – Result with distribution="ensemble" and samples populated.

Examples

>>> u = Uncertain(nominal=1.0, distribution="gaussian", params={"std": 0.1})
>>> out = propagate_uncertainty(lambda x: x * 2, u, n_samples=100)
>>> out.n_samples
100