tidal.inference package#

Bayesian inference for TIDAL parameter estimation.

Wraps the existing simulation + measurement pipeline as a likelihood function for Monte Carlo and nested sampling. Nested sampling uses PolyChord (Handley et al. 2015) with anesthetic (Handley 2019) for analysis and visualization.

Setup:

pip install tidal[inference]            # anesthetic only
bash scripts/install_polychord.sh       # PolyChord (requires gfortran)

References

Skilling, J. (2004) “Nested Sampling”, AIP Conference Proceedings 735. Handley, W. et al. (2015) “PolyChord: next-generation nested sampling”, MNRAS 453. Handley, W. (2019) “anesthetic: nested sampling visualization”, JOSS 4.

class tidal.inference.ConstraintSet(constraints=<factory>, expressions=<factory>)[source]#

Bases: object

A collection of parameter constraints combined with logical AND.

Parameters:
  • constraints (list of callables) – Each callable takes dict[str, float] and returns bool.

  • expressions (list of str) – The original expression strings (for display/serialization).

check(params)[source]#

Return True if all constraints are satisfied.

Parameters:

params (dict[str, float])

Return type:

bool

classmethod from_strings(exprs)[source]#

Create from a list of constraint expression strings.

Parameters:

exprs (list[str])

Return type:

ConstraintSet

constraints: list[Callable[[dict[str, float]], bool]]#
expressions: list[str]#
class tidal.inference.InferenceResult(samples, log_likelihood, log_prior, param_names, method, metrics=None, log_evidence=None, log_evidence_err=None, weights=None, metadata=<factory>)[source]#

Bases: object

Container for inference samples and diagnostics.

Parameters:
  • samples (NDArray) – Parameter samples, shape (n_samples, n_params).

  • log_likelihood (NDArray) – Log-likelihood for each sample, shape (n_samples,).

  • log_prior (NDArray) – Log-prior for each sample, shape (n_samples,).

  • param_names (list[str]) – Parameter names, length n_params.

  • method (str) – Sampling method: "mc" or "nested".

  • metrics (dict[str, NDArray] | None) – Additional simulation metrics per sample (P_max, etc.).

  • log_evidence (float | None) – Log-evidence (nested sampling only).

  • log_evidence_err (float | None) – Uncertainty on log-evidence (nested sampling only).

  • weights (NDArray | None) – Importance weights for nested sampling, shape (n_samples,).

  • metadata (dict) – Additional metadata (sampler settings, wall time, etc.).

best()[source]#

Return the MAP (maximum a posteriori) parameter values.

Return type:

dict[str, float]

credible_interval(level=0.95)[source]#

Return equal-tailed credible intervals for each parameter.

Parameters:

level (float) – Credible level (default: 0.95 for 95% CI).

Return type:

dict[str, tuple[float, float]]

effective_sample_size()[source]#

Kish effective sample size from weights.

For unweighted MC samples, returns n_samples. For nested sampling, uses importance weights.

Reference: Kish, L. (1965) Survey Sampling, Wiley.

Return type:

float

classmethod from_directory(path)[source]#

Load inference results from a saved directory.

Expects inference.json and results.csv as written by save().

Parameters:

path (Path) – Directory containing saved inference results.

Return type:

InferenceResult

log_evidence: float | None = None#
log_evidence_err: float | None = None#
property log_posterior: NDArray[np.float64]#

Log-posterior = log-prior + log-likelihood.

metrics: dict[str, NDArray[np.float64]] | None = None#
property n_params: int#
property n_samples: int#
parameter_importance(n_bootstrap=100)[source]#

Compute parameter importance via KL divergence.

Uses anesthetic to compute total and per-parameter information gain from prior to posterior, plus Bayesian model dimensionality.

Parameters:

n_bootstrap (int) – Number of bootstrap samples for uncertainty estimation.

Return type:

ParameterImportanceResult

posterior_mean()[source]#

Return the posterior mean parameter values.

For nested sampling, uses importance-weighted mean.

Return type:

dict[str, float]

save(output_dir)[source]#

Save inference results to disk.

Writes: - results.csv and results.json via SweepResults - inference.json with evidence, ESS, and summary statistics

Parameters:

output_dir (Path)

Return type:

None

to_anesthetic()[source]#

Convert to anesthetic NestedSamples for custom analysis.

Returns the native anesthetic object with .D_KL(), .d_G(), .logZ(), .plot_2d() etc.

Return type:

Any

to_sweep_results()[source]#

Convert to a SweepResults.

This allows reusing the existing CSV/JSON serialization infrastructure.

Return type:

SweepResults

weights: NDArray[np.float64] | None = None#
samples: NDArray[np.float64]#
log_likelihood: NDArray[np.float64]#
log_prior: NDArray[np.float64]#
param_names: list[str]#
method: str#
metadata: dict[str, Any]#
class tidal.inference.ParameterImportanceResult(param_names, d_kl, d_kl_err, d_g, d_g_err, marginal_d_kl, log_evidence, log_evidence_err, consistency=<factory>)[source]#

Bases: object

Results from parameter importance analysis.

Parameters:
  • param_names (list[str]) – Parameter names.

  • d_kl (float) – Total KL divergence (nats) — information gained from prior to posterior.

  • d_kl_err (float) – Bootstrap uncertainty on D_KL.

  • d_g (float) – Bayesian model dimensionality — effective number of constrained parameters.

  • d_g_err (float) – Bootstrap uncertainty on d_G.

  • marginal_d_kl (dict[str, float]) – Per-parameter marginal KL divergence (nats). High D_KL means the data strongly constrains that parameter.

  • log_evidence (float) – Log Bayesian evidence (log Z).

  • log_evidence_err (float) – Bootstrap uncertainty on log Z.

  • consistency (dict[str, Any]) – Self-check diagnostics for the marginal estimates (#420/#433): sum_marginals, superadditivity_ok (for a product prior the chain rule gives D_KL(joint) >= sum of marginals exactly, so a violating sum means the estimator is broken), superadditivity_applicable (False when the low-n_eff bias allowance dwarfs the signal and “ok” would be vacuous), bias_allowance / tolerance (the check’s actual power), product_prior (whether the bound is exact for this run), saturated_params (marginals within 90% of the histogram ceiling log(n_bins) — resolution-limited values), n_eff (Kish effective sample size of the posterior weights), noise_floor (per-parameter estimator bias (n_bins - 1)/(2 n_eff) — a marginal at or below its floor is noise, not constraint), floor_dominated_params (the names that fail that test), fallback_params (names scored against an empirical sample-range reference instead of their prior — unreliable), range_clipped (names with posterior mass outside the recorded prior range, mapped to the clipped weight fraction — the prior record does not describe the samples), and note. Empty dict when marginals could not be computed.

param_names: list[str]#
d_kl: float#
d_kl_err: float#
d_g: float#
d_g_err: float#
marginal_d_kl: dict[str, float]#
log_evidence: float#
log_evidence_err: float#
consistency: dict[str, Any]#
class tidal.inference.Prior(name, distribution, low, high)[source]#

Bases: object

A 1-D marginal prior distribution.

Parameters:
  • name (str) – Parameter name (must match the JSON spec’s parameter key).

  • distribution (str) – One of "uniform", "log_uniform", "normal", "arctan_uniform".

  • low (float) – Lower bound (for uniform/log_uniform) or mean (for normal). Ignored for arctan_uniform — see below.

  • high (float) – Upper bound (for uniform/log_uniform) or std (for normal). Ignored for arctan_uniform — see below.

Notes

arctan_uniform does NOT use low/high (GH #425): the angle is uniform on the fixed eps-truncated range (-pi/2 + _ARCTAN_EPS, +pi/2 - _ARCTAN_EPS), so the support is always |x| <= tan(pi/2 - _ARCTAN_EPS) ~= 19.98 regardless of the recorded bounds. A UserWarning fires at construction when the given bounds differ from that implied support; pass 0:0 (the sanctioned sentinel used in the docs) to declare the bounds deliberately unused without warning. Honoring the bounds would silently redefine the prior for every archived chain whose metadata records these unused numbers, so any change must be versioned — deliberately deferred, see the options in GH #425.

property effective_support: tuple[float, float]#

The range sample() actually draws from — not what was typed.

Thin accessor for effective_support(); see it for the per-distribution contract and the defects that motivated it.

log_prob(x)[source]#

Evaluate log p(x) under this prior.

Parameters:

x (float)

Return type:

float

sample(rng, n)[source]#

Draw n samples from this prior.

Parameters:
  • rng (np.random.Generator)

  • n (int)

Return type:

NDArray[np.float64]

transform(u)[source]#

Map u in [0, 1] to the physical parameter space.

This implements the prior_transform protocol used by PolyChord.

Parameters:

u (float)

Return type:

float

name: str#
distribution: str#
low: float#
high: float#
tidal.inference.parse_constraint(expr)[source]#

Parse a constraint expression string into a callable.

Parameters:

expr (str) – A comparison expression, e.g. "xi > 0" or "deltam**2 < 2*alpha*xi".

Returns:

A function (params: dict[str, float]) -> bool that returns True if the constraint is satisfied.

Return type:

callable

Raises:

ConstraintError – If the expression cannot be parsed safely.