diff --git a/BAYESIAN_IN_ERL.md b/BAYESIAN_IN_ERL.md new file mode 100644 index 00000000..dc99953f --- /dev/null +++ b/BAYESIAN_IN_ERL.md @@ -0,0 +1,361 @@ +# Bayesian Analysis in EasyReflectometryLib — Implementation Plan + +## Current State + +- `BAYESIAN_BUMPS.md` (in `MD/`) describes a 3-phase plan. Phase 1 + (docs/notebook) is complete. +- `bayesian_bumps.py` (attached notebook) works but users must directly + import from `bumps.fitters`, `bumps.names`, `bumps.parameter` — a + leaky abstraction. +- The `Bumps` minimizer in `easyscience` + (`core/src/easyscience/fitting/minimizers/minimizer_bumps.py`) only + exposes **classical optimization** methods (`amoeba`, `newton`, `lm`), + NOT the DREAM/MCMC sampler. +- The `AvailableMinimizers` enum only has `Bumps`, `Bumps_simplex`, + `Bumps_newton`, `Bumps_lm`. This should remain optimizer-focused; + DREAM should be exposed as a sampling workflow, not as another + minimizer choice. +- `MultiFitter` in reflectometry-lib currently only has `fit()` and + `fit_single_data_set_1d()`. + +## Goal + +Users should be able to run Bayesian MCMC sampling with a **clean +high-level API** like: + +```python +fitter = MultiFitter(model) +fitter.switch_minimizer(AvailableMinimizers.Bumps) + +# Classical fit first +analysed = fitter.fit(data) + +# Bayesian sampling +posterior = fitter.sample(data, samples=5000, burn=1000, thin=10) + +# Analyze +from easyreflectometry.analysis.bayesian import plot_corner, posterior_summary +plot_corner(posterior) +print(posterior_summary(posterior)) +``` + +Important API boundary: `fit()` remains classical optimization only. +Bayesian DREAM sampling is exposed through `sample()` so users do not +receive sampler-shaped results from an optimizer-shaped API. + +## Implementation Plan + +### Step 1 — Keep DREAM separate from `AvailableMinimizers` + +**File**: `core/src/easyscience/fitting/available_minimizers.py` + +Do **not** add `Bumps_dream` as a normal `AvailableMinimizers` member. +The enum is currently used to instantiate minimizer backends and to +route calls through `Fitter.fit()`, which expects optimizer-style +`FitResults`. DREAM is an MCMC sampler and returns a sampler state/chain +rather than a best-fit result. + +Use `AvailableMinimizers.Bumps` to select the BUMPS backend, then expose +DREAM through a dedicated `sample()` method. This avoids making +`project.minimizer = AvailableMinimizers.Bumps_dream` look like a valid +classical fitting mode. + +### Step 2 — Add dedicated DREAM sampling support to the Bumps minimizer (core repo) + +**File**: `core/src/easyscience/fitting/minimizers/minimizer_bumps.py` + +**2a.** Keep `supported_methods()` optimizer-only (`amoeba`, `newton`, +`lm`). Do not add `'dream'` there unless the EasyScience fitting +abstraction is later split into optimizer and sampler concepts. + +**2b.** Add a new method `sample()` to the `Bumps` class: + +```python +def sample( + self, + x: np.ndarray, + y: np.ndarray, + weights: np.ndarray, + samples: int = 10000, + burn: int = 2000, + thin: int = 10, + chains: int | None = None, + population: int | None = None, + model: Callable | None = None, + parameters: list | None = None, + progress_callback: Callable | None = None, + seed: int | None = None, + **kwargs, +) -> dict: + """Run Bayesian MCMC sampling using BUMPS DREAM sampler. + + Returns a dict with: + - 'draws': np.ndarray, shape (n_samples, n_params) — posterior samples + - 'param_names': list[str] — parameter names + - 'state': DreamState — raw BUMPS state for save/restore + - 'logp': np.ndarray — log-posterior values + """ +``` + +The implementation would: + +1. Build the `Curve` model + `FitProblem` (reuse `_make_model()` logic) +2. Translate user-friendly aliases to BUMPS DREAM settings and call + `bumps_fit(problem, method='dream', samples=samples, burn=burn, thin=thin, pop=population, ...)` +3. Extract `result.state.draw().points` and return structured dict +4. Preserve and restore the EasyScience global object stack state, + mirroring the existing `fit()` implementation +5. Handle multi-dataset via the same `MultiFitter._precompute_reshaping` + pattern + +**2c.** Do **not** modify `fit()` to handle `method='dream'`, and do +**not** delegate `fit(method='dream')` to `sample()`. `fit()` returns +`FitResults`; `sample()` returns posterior samples and sampler metadata. +Keeping the methods separate prevents incompatible return types from +leaking into `Fitter.fit()` and reflectometry-lib `MultiFitter.fit()`. + +Recommended alias mapping: + +| Public argument | BUMPS DREAM setting | Rationale | +| ---------------- | --------------------------- | ----------------------------------------------------------------------- | +| `samples` | `samples` | Clear user-facing chain length; prefer over optimizer-oriented `steps`. | +| `burn` | `burn` | Matches BUMPS and common MCMC terminology. | +| `thin` | `thin` | Matches BUMPS and common MCMC terminology. | +| `chains` | `pop` | User-friendly MCMC wording; maps to BUMPS population count. | +| `population` | `pop` | BUMPS-aware alias for advanced users. | +| `initialization` | `init` | More readable than `init`, but pass through to BUMPS. | +| `seed` | RNG seeding before sampling | Expose reproducibility without requiring users to know BUMPS internals. | + +If both `chains` and `population` are provided, raise `ValueError` +unless they match. Accept `steps` only as a deprecated alias for +`samples`, with a warning, because `steps` already means optimizer +budget in EasyScience `Bumps.fit()`. + +### Step 3 — Add `sample()` to reflectometry-lib `MultiFitter` + +**File**: `reflectometry-lib/src/easyreflectometry/fitting.py` + +Add a `sample()` method to `MultiFitter`: + +```python +def sample( + self, + data: sc.DataGroup, + samples: int = 10000, + burn: int = 2000, + thin: int = 10, + chains: int | None = None, + population: int | None = None, + seed: int | None = None, + objective: str | None = None, +) -> dict: + """Run Bayesian MCMC sampling on reflectometry data. + + :param data: DataGroup with reflectivity data. + :param samples: Number of retained DREAM samples requested from BUMPS. + :param burn: Burn-in steps. + :param thin: Thinning interval. + :param chains: User-friendly alias for BUMPS DREAM population count. + :param population: BUMPS DREAM population count (`pop`) for advanced users. + :param seed: Random seed for reproducibility. + :param objective: Zero-variance handling strategy. + :return: Dict with posterior samples, parameter names, and sampler state. + """ +``` + +Internally: + +1. Reuse `_prepare_fit_arrays` for data preparation +2. Mirror the EasyScience `Fitter.fit()` lifecycle for reshaping, fit + function wrapping, and restoration +3. Delegate to `self.easy_science_multi_fitter.minimizer.sample(...)` + for the MCMC +4. Handle multi-model / multi-contrast aggregation as one joint + posterior +5. Return structured posterior dict or `PosteriorResults` + +The `MultiFitter` currently stores `self.easy_science_multi_fitter` +which has `.minimizer` — we'll call `sample()` on it when the minimizer +is a `Bumps` instance. + +### Step 4 — Create Bayesian analysis module in reflectometry-lib + +**New file**: +`reflectometry-lib/src/easyreflectometry/analysis/__init__.py` **New +file**: `reflectometry-lib/src/easyreflectometry/analysis/bayesian.py` + +The `bayesian.py` module provides: + +```python +class PosteriorResults: + """Container for Bayesian posterior samples with analysis methods.""" + + draws: np.ndarray # (n_samples, n_params) + param_names: list[str] + logp: np.ndarray | None + sampler_state: Any | None + + def summary(self) -> str: + """Return formatted summary table with mean, sd, HDI for each parameter.""" + + def corner(self, **kwargs) -> None: + """Plot parameter correlation corner plot using the `corner` library.""" + + def credible_interval(self, alpha: float = 0.95) -> dict: + """Return {param_name: (lower, upper)} credible intervals.""" + + def gelman_rubin(self) -> dict: + """Compute R-hat convergence diagnostic.""" + +def posterior_summary(draws, param_names) -> str: ... +def plot_corner(draws, param_names, **kwargs) -> None: ... +def plot_trace(draws, param_names, **kwargs) -> None: ... +def credible_intervals(draws, param_names, alpha=0.95) -> dict: ... +``` + +**Posterior predictive functions** (reflectivity & SLD): + +```python +def posterior_predictive_reflectivity( + draws, param_names, model, q_values, n_samples=200 +) -> tuple[np.ndarray, np.ndarray, np.ndarray]: + """Return (median, lower_95, upper_95) reflectivity arrays.""" + +def posterior_sld_profile( + draws, param_names, model, n_samples=200 +) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: + """Return (z, median, lower_95, upper_95) SLD profile arrays.""" +``` + +Posterior predictive helpers must save original parameter values and +errors before applying any posterior draw, and restore them in a +`finally` block after prediction. Parameter lookup should use +EasyScience parameter `unique_name` values, matching the BUMPS names +after removing the minimizer prefix, rather than display names. This +avoids leaving the model mutated after plotting and avoids collisions +when repeated models or multi-contrast fits contain similarly named +parameters. + +### Step 5 — Dependencies + +Add to `pyproject.toml` in reflectometry-lib: + +```toml +[project.optional-dependencies] +bayesian = ["corner>=2.2", "arviz>=0.18"] +``` + +Make `corner` and `arviz` optional imports — the analysis module should +work with graceful fallbacks when they're not installed. + +### Step 6 — Update exports + +**File**: `reflectometry-lib/src/easyreflectometry/__init__.py` + +Add `PosteriorResults` and analysis functions to the public API if +desired. + +### Step 7 — Update the example notebook + +**File**: +`reflectometry-lib/docs/src/tutorials/advancedfitting/bayesian_bumps.py` + +Replace low-level BUMPS calls with the new high-level API: + +- `fitter.sample(data, samples=500, burn=100, thin=10)` instead of + manual `FitProblem` + `bumps_fit` +- `plot_corner(posterior['draws'], posterior['param_names'])` instead of + manual `corner.corner()` +- `posterior_summary(...)` instead of manual numpy statistics + +### Step 8 — Tests + +**File**: `reflectometry-lib/tests/test_bayesian.py` (new) + +```python +def test_sample_basic(): ... +def test_posterior_summary_format(): ... +def test_corner_plot_does_not_crash(): ... +def test_credible_intervals(): ... +def test_sample_seed_reproducibility(): ... +``` + +Also add a test in `core/tests/` for the `Bumps.sample()` method. + +## Architecture Diagram + +``` +User Code + │ + ├─ fitter.fit(data) ──► classical chi² minimization + ├─ fitter.sample(data, ...) ──► Bayesian DREAM MCMC + │ + ▼ +reflectometry-lib MultiFitter + │ ._prepare_fit_arrays() ← reused from fit() + │ delegates to ↓ + ▼ +easyscience Bumps minimizer + │ .fit(x, y, weights) ──► amoeba/newton/lm + │ .sample(x, y, weights, ...) ──► DREAM MCMC (NEW) + │ + ▼ +bumps.fitters.fit / FitProblem / Curve + └──► reflectivity model evaluation via fit_func + +Post-hoc analysis: + reflectometry-lib analysis.bayesian + ├── PosteriorResults (container) + ├── plot_corner() → corner.corner() + ├── posterior_summary() → numpy stats + └── posterior_predictive_reflectivity() → model.interface.fit_func() +``` + +## Risk Assessment + +| Risk | Mitigation | +| -------------------------------------------- | -------------------------------------------------------------------------------- | +| DREAM may not converge with default settings | Expose `samples`, `burn`, `thin`, `chains`/`population`; document best practices | +| MCMC is 10-100× slower than least-squares | Document that classical fit first is recommended; add progress callback | +| `corner` / `arviz` may not be installed | Make optional dependencies with graceful fallbacks | +| Multi-dataset sampling aggregation | Follow existing `MultiFitter._precompute_reshaping` pattern | +| BUMPS DREAM API changes | Pin bumps version; wrap in our API | +| Reproducibility | Expose `seed` parameter; document how to save/load DreamState | +| Model mutation during posterior prediction | Save/restore original parameter values and map draws by `unique_name` | + +## Files to Create / Modify + +### Create: + +1. `reflectometry-lib/src/easyreflectometry/analysis/__init__.py` +2. `reflectometry-lib/src/easyreflectometry/analysis/bayesian.py` +3. `reflectometry-lib/tests/test_bayesian.py` + +### Modify: + +4. `core/src/easyscience/fitting/available_minimizers.py` — no + `Bumps_dream`; optionally document that samplers are exposed + separately +5. `core/src/easyscience/fitting/minimizers/minimizer_bumps.py` — add + dedicated `sample()` method without adding `'dream'` to optimizer + methods +6. `reflectometry-lib/src/easyreflectometry/fitting.py` — add `sample()` + to `MultiFitter` +7. `reflectometry-lib/src/easyreflectometry/__init__.py` — optional: + export new classes +8. `reflectometry-lib/pyproject.toml` — add optional `bayesian` + dependencies +9. `reflectometry-lib/docs/src/tutorials/advancedfitting/bayesian_bumps.py` + — update to use new API + +## Implementation Order + +1. **core changes** (Steps 1-2): Add `Bumps.sample()` method while + keeping DREAM out of optimizer enum/method dispatch +2. **reflectometry-lib fitting** (Step 3): Add `MultiFitter.sample()` +3. **reflectometry-lib analysis** (Step 4): Create + `analysis/bayesian.py` with corner plot & stats +4. **Dependencies** (Step 5): Add optional deps to pyproject.toml +5. **Exports** (Step 6): Update `__init__.py` +6. **Example update** (Step 7): Update notebook to use new API +7. **Tests** (Step 8): Add test coverage diff --git a/docs/docs/tutorials/advancedfitting/bayesian_bumps.ipynb b/docs/docs/tutorials/advancedfitting/bayesian_bumps.ipynb new file mode 100644 index 00000000..43c94db1 --- /dev/null +++ b/docs/docs/tutorials/advancedfitting/bayesian_bumps.ipynb @@ -0,0 +1,494 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "649cf9aa", + "metadata": {}, + "source": [ + "# Bayesian Fitting with BUMPS\n", + "\n", + "This notebook demonstrates the full high-level Bayesian MCMC API in\n", + "EasyReflectometry.\n", + "\n", + "It covers:\n", + "\n", + "- Building a reflectometry model with realistic bounds (critical for MCMC).\n", + "- Classical optimisation first (good starting point for Bayesian sampling).\n", + "- High-level DREAM MCMC sampling via\n", + " ``MultiFitter.sample()`` and ``PosteriorResults``.\n", + "- Posterior inspection: summary table, corner plot, trace plot, credible\n", + " intervals, Gelman-Rubin R-hat.\n", + "- Posterior-predictive checks: reflectivity and SLD profile with 95 %\n", + " credible bands.\n", + "\n", + "**Note**: Requires ``corner`` and ``arviz`` for some plots (install via\n", + "``pip install easyreflectometry[bayesian]``)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "61aa83ac", + "metadata": {}, + "outputs": [], + "source": [ + "import warnings\n", + "\n", + "import corner as _corner\n", + "import matplotlib.pyplot as plt\n", + "from easyscience.fitting import AvailableMinimizers\n", + "\n", + "from easyreflectometry.analysis.bayesian import PosteriorResults\n", + "from easyreflectometry.analysis.bayesian import posterior_predictive_reflectivity\n", + "from easyreflectometry.analysis.bayesian import posterior_predictive_sld_profile\n", + "from easyreflectometry.calculators import CalculatorFactory\n", + "from easyreflectometry.data.measurement import load\n", + "from easyreflectometry.fitting import MultiFitter\n", + "from easyreflectometry.model import Model\n", + "from easyreflectometry.model import PercentageFwhm\n", + "from easyreflectometry.sample import Layer\n", + "from easyreflectometry.sample import Material\n", + "from easyreflectometry.sample import Multilayer\n", + "from easyreflectometry.sample import Sample\n", + "\n", + "warnings.filterwarnings('ignore')\n", + "\n", + "print('All libraries imported successfully.')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14986b98", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- Load experimental data -------------------------------------------------\n", + "data_path = 'example.ort'\n", + "data = load(data_path)\n", + "print('Data loaded with keys:', list(data.keys()))\n", + "\n", + "# Quick look at the data\n", + "qz = data['coords']['Qz_0'].values\n", + "r_data = data['data']['R_0'].values\n", + "\n", + "plt.figure(figsize=(7, 4))\n", + "plt.semilogy(qz, r_data, 'o', label='Data')\n", + "plt.xlabel('Q / Å⁻¹')\n", + "plt.ylabel('Reflectivity')\n", + "plt.title('Experimental data (example.ort)')\n", + "plt.legend()\n", + "plt.grid(True, alpha=0.3)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd56a6eb", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- Create a monolayer model (Si / Film / D₂O) ----------------------------\n", + "si = Material(sld=2.07, isld=0.0, name='Si')\n", + "film = Material(sld=2.0, isld=0.0, name='Film')\n", + "d2o = Material(sld=6.36, isld=0.0, name='D2O')\n", + "\n", + "si_layer = Layer(material=si, thickness=0.0, roughness=3.0, name='Si')\n", + "film_layer = Layer(material=film, thickness=250.0, roughness=3.0, name='Film')\n", + "d2o_layer = Layer(material=d2o, thickness=0.0, roughness=3.0, name='D2O')\n", + "\n", + "sample = Sample(\n", + " Multilayer(si_layer),\n", + " Multilayer(film_layer),\n", + " Multilayer(d2o_layer),\n", + " name='Monolayer Sample',\n", + ")\n", + "\n", + "resolution = PercentageFwhm(0.02)\n", + "model = Model(\n", + " sample=sample,\n", + " scale=1.0,\n", + " background=1e-6,\n", + " resolution_function=resolution,\n", + " name='Monolayer Model',\n", + ")\n", + "\n", + "# ---- Make key parameters free with realistic bounds (essential for MCMC) -----\n", + "film_layer.thickness.fixed = False\n", + "film_layer.thickness.bounds = (100, 400)\n", + "\n", + "film.sld.fixed = False\n", + "film.sld.bounds = (0.5, 4.0)\n", + "\n", + "model.scale.fixed = False\n", + "model.scale.bounds = (0.8, 1.2)\n", + "\n", + "model.background.fixed = False\n", + "model.background.bounds = (1e-7, 1e-5)\n", + "\n", + "print('Model created with the following free parameters:')\n", + "for p in model.get_parameters():\n", + " if not p.fixed:\n", + " print(f' {p.name}: value={p.value}, bounds={p.bounds}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "991e1169", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- Set up the calculator and fitter ---------------------------------------\n", + "interface = CalculatorFactory()\n", + "interface.switch('refnx') # or 'refl1d'\n", + "model.interface = interface\n", + "\n", + "fitter = MultiFitter(model)\n", + "# Use the BUMPS backend — DREAM sampling is only available through BUMPS.\n", + "fitter.switch_minimizer(AvailableMinimizers.Bumps)\n", + "\n", + "print('Fitter ready with minimizer:', fitter.easy_science_multi_fitter.minimizer.name)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb0f989e", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- Classical fit first ----------------------------------------------------\n", + "# A classical optimisation gives a good starting point and a sanity check\n", + "# before launching the (much more expensive) MCMC sampler.\n", + "\n", + "analysed = fitter.fit(data)\n", + "\n", + "print('Classical fit successful:', analysed.get('success', 'N/A'))\n", + "print('Reduced χ² ≈', analysed.get('reduced_chi', 'N/A'))\n", + "\n", + "# Plot the fit\n", + "r_model = analysed['R_0_model'].values\n", + "\n", + "plt.figure(figsize=(8, 5))\n", + "plt.semilogy(qz, r_data, 'o', label='Data', alpha=0.7)\n", + "plt.semilogy(qz, r_model, '-', label='Classical BUMPS fit', linewidth=2)\n", + "plt.xlabel('Q / Å⁻¹')\n", + "plt.ylabel('Reflectivity')\n", + "plt.title('Classical fit before Bayesian sampling')\n", + "plt.legend()\n", + "plt.grid(True, alpha=0.3)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20c9b0e0", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- Bayesian MCMC sampling -------------------------------------------------\n", + "# ``MultiFitter.sample()`` delegates to the BUMPS DREAM sampler.\n", + "# All keyword arguments are forwarded with user-friendly names:\n", + "# ``samples`` ← total retained samples\n", + "# ``burn`` ← burn‑in steps\n", + "# ``thin`` ← thinning interval\n", + "# ``chains`` ← DREAM population count (alias for ``pop``)\n", + "# ``population``← BUMPS‑native ``pop`` for advanced users\n", + "# ``seed`` ← random seed for reproducibility\n", + "\n", + "posterior_dict = fitter.sample(\n", + " data,\n", + " samples=2000, # Short for demo; use 20 k+ in production\n", + " burn=500,\n", + " thin=10,\n", + " seed=42,\n", + ")\n", + "\n", + "print('DREAM sampling complete.')\n", + "print(f' Posterior shape : {posterior_dict[\"draws\"].shape}')\n", + "print(f' Parameters : {posterior_dict[\"param_names\"]}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f23934a0", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- Wrap in PosteriorResults -----------------------------------------------\n", + "# ``PosteriorResults`` gives you a convenient object with built-in analysis\n", + "# methods. You can also use the raw ``dict`` with the standalone functions\n", + "# — both styles are shown below.\n", + "\n", + "posterior = PosteriorResults(\n", + " draws=posterior_dict['draws'],\n", + " param_names=posterior_dict['param_names'],\n", + " logp=posterior_dict.get('logp'),\n", + " sampler_state=posterior_dict.get('state'),\n", + ")\n", + "\n", + "print(posterior)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef300cb1", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- Posterior summary table ------------------------------------------------\n", + "# ``.summary()`` prints mean, standard deviation and 95 % HDI for each parameter.\n", + "\n", + "print(posterior.summary())\n", + "print()\n", + "\n", + "# The standalone function produces the same output:\n", + "# print(posterior_summary(posterior.draws, posterior.param_names))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e759a2a0", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- Corner plot ------------------------------------------------------------\n", + "# Visualise all pairwise parameter correlations and marginal distributions.\n", + "\n", + "posterior.corner()\n", + "plt.suptitle('Posterior distributions from BUMPS DREAM', y=1.02)\n", + "plt.show()\n", + "\n", + "# Standalone equivalent:\n", + "# plot_corner(posterior.draws, posterior.param_names)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "593f5ed3", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- Trace plot -------------------------------------------------------------\n", + "# Inspect the MCMC chains for convergence. Requires ``arviz``.\n", + "\n", + "try:\n", + " posterior.trace()\n", + " plt.suptitle('MCMC trace plots', y=1.02)\n", + " plt.show()\n", + "except ImportError:\n", + " print('Skipped: arviz is not installed.')\n", + " print('Install with: pip install easyreflectometry[bayesian]')\n", + "\n", + "# Standalone equivalent:\n", + "# plot_trace(posterior.draws, posterior.param_names)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3049e68a", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- Credible intervals -----------------------------------------------------\n", + "# Equal-tailed 95 % credible intervals for each parameter.\n", + "\n", + "ci_95 = posterior.credible_interval(alpha=0.95)\n", + "print('95 % credible intervals:')\n", + "for name, (lo, hi) in ci_95.items():\n", + " print(f' {name:<30s} [{lo:.4f}, {hi:.4f}]')\n", + "\n", + "# You can request narrower intervals too:\n", + "ci_50 = posterior.credible_interval(alpha=0.50)\n", + "print('\\n50 % credible intervals:')\n", + "for name, (lo, hi) in ci_50.items():\n", + " print(f' {name:<30s} [{lo:.4f}, {hi:.4f}]')\n", + "\n", + "# Standalone equivalent:\n", + "# ci = credible_intervals(posterior.draws, posterior.param_names, alpha=0.95)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "806bf47a", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- 2D parameter heatmap ---------------------------------------------------\n", + "# Joint posterior density for a specific pair of parameters.\n", + "# Uses the ``corner`` library (already loaded as ``corner``).\n", + "\n", + "params_of_interest = ['Layer_1_ThicknessParameter_0', 'Material_1_SldParameter_0']\n", + "idx = [posterior.param_names.index(p) for p in params_of_interest]\n", + "\n", + "_corner.corner(\n", + " posterior.draws[:, idx],\n", + " labels=params_of_interest,\n", + " quantiles=[0.16, 0.5, 0.84],\n", + " show_titles=True,\n", + " title_fmt='.4f',\n", + " bins=50,\n", + " hist_bin_factor=1.5,\n", + ")\n", + "plt.suptitle('Parameter heatmap: thickness vs SLD', y=1.02)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34e3cc3e", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- Gelman-Rubin R‑hat convergence diagnostic ------------------------------\n", + "# Requires ``arviz``. Values close to 1.0 indicate good convergence.\n", + "\n", + "rhat = posterior.gelman_rubin()\n", + "if rhat is not None:\n", + " print('Gelman-Rubin R‑hat:')\n", + " for name, r in rhat.items():\n", + " flag = ' ✓' if r < 1.1 else ' ⚠'\n", + " print(f' {name:<30s} R̂ = {r:.3f}{flag}')\n", + "else:\n", + " print('Skipped: arviz is not installed.')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c7e5816e", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- Posterior-predictive reflectivity --------------------------------------\n", + "# Propagate parameter uncertainty through the model to obtain median\n", + "# reflectivity and 95 % credible band.\n", + "\n", + "r_median, r_lower, r_upper = posterior_predictive_reflectivity(\n", + " posterior.draws,\n", + " posterior.param_names,\n", + " model,\n", + " qz,\n", + " n_samples=200,\n", + ")\n", + "\n", + "plt.figure(figsize=(9, 6))\n", + "plt.semilogy(qz, r_data, 'o', label='Data', alpha=0.6)\n", + "plt.semilogy(qz, r_median, '-', color='tab:orange', label='Posterior median')\n", + "plt.fill_between(\n", + " qz,\n", + " r_lower,\n", + " r_upper,\n", + " color='tab:orange',\n", + " alpha=0.3,\n", + " label='95 % credible interval',\n", + ")\n", + "plt.xlabel('Q / Å⁻¹')\n", + "plt.ylabel('Reflectivity')\n", + "plt.title('Bayesian Posterior-Predictive Check')\n", + "plt.legend()\n", + "plt.grid(True, alpha=0.3)\n", + "plt.show()\n", + "\n", + "print('The 95 % credible interval captures parameter uncertainty propagated through the model.')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef27b8ec", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- Posterior-predictive SLD profile ---------------------------------------\n", + "# The same idea applied to the scattering-length-density profile.\n", + "\n", + "z, sld_median, sld_lower, sld_upper = posterior_predictive_sld_profile(\n", + " posterior.draws,\n", + " posterior.param_names,\n", + " model,\n", + " n_samples=200,\n", + ")\n", + "\n", + "plt.figure(figsize=(8, 4))\n", + "plt.plot(z, sld_median, label='Posterior median SLD')\n", + "plt.fill_between(\n", + " z,\n", + " sld_lower,\n", + " sld_upper,\n", + " alpha=0.3,\n", + " label='95 % credible interval',\n", + ")\n", + "plt.xlabel('z / Å')\n", + "plt.ylabel('SLD / 10⁻⁶ Å⁻²')\n", + "plt.title('SLD Profile with Bayesian Uncertainty')\n", + "plt.legend()\n", + "plt.grid(True, alpha=0.3)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37e78b4e", + "metadata": {}, + "outputs": [], + "source": [ + "# ---- Summary ----------------------------------------------------------------\n", + "print('―' * 60)\n", + "print('Bayesian analysis complete!')\n", + "print('―' * 60)\n", + "print()\n", + "print('API surface demonstrated:')\n", + "print(' MultiFitter.sample(data, samples=, burn=, thin=, seed=)')\n", + "print(' PosteriorResults(draws, param_names, logp=, sampler_state=)')\n", + "print(' .summary() — formatted parameter table')\n", + "print(' .corner() — pairwise correlation plot')\n", + "print(' .trace() — MCMC chain trace plot')\n", + "print(' .credible_interval(alpha) — equal-tailed credible intervals')\n", + "print(' .gelman_rubin() — R̂ convergence diagnostic')\n", + "print()\n", + "print(' Standalone functions (work on raw dict):')\n", + "print(' posterior_summary(draws, names)')\n", + "print(' plot_corner(draws, names)')\n", + "print(' plot_trace(draws, names)')\n", + "print(' credible_intervals(draws, names, alpha)')\n", + "print(' posterior_predictive_reflectivity(draws, names, model, q, n)')\n", + "print(' posterior_predictive_sld_profile(draws, names, model, n)')\n", + "print()\n", + "print('The high-level API provides clean, safe access to BUMPS DREAM sampling.')" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "era", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/docs/tutorials/advancedfitting/example.ort b/docs/docs/tutorials/advancedfitting/example.ort new file mode 100644 index 00000000..968fa7bb --- /dev/null +++ b/docs/docs/tutorials/advancedfitting/example.ort @@ -0,0 +1,448 @@ +# # ORSO reflectivity data file | 0.1 standard | YAML encoding | https://www.reflectometry.org/ +# data_source: +# owner: +# name: Andrew Nelson +# affiliation: ANSTO +# contact: Andrew.Nelson@ansto.gov.au +# experiment: +# facility: ANSTO +# start_date: 2021-05-12 +# title: Example data file from refnx docs +# instrument: platypus +# probe: neutron +# sample: +# name: Polymer Film +# category: solid / liquid +# composition: Si / SiO2 / Film / D2O +# measurement: +# instrument_settings: +# wavelength: +# magnitude: 12 +# unit: angstrom +# incident_angle: +# magnitude: 3 +# unit: deg +# data_files: +# - Unknown.nxs +# scheme: angle-dispersive +# reduction: +# software: ess +# timestamp: 2022-01-27T15:33:59+01:00 +# corrections: +# - footprint +# - incident intensity +# - detector efficiency +# columns: +# - {name: Qz, unit: 1/angstrom, dimension: WW transfer} +# - {name: R, dimension: reflectivity} +# - {name: sR, dimension: error-reflectivity} +# - {name: sQz, unit: 1/angstrom, dimension: resolution-WW transfer} +## Qz RQz sR sQz +8.060220000e-03 7.095810000e-01 8.506760000e-02 1.407419648e-04 +8.136620000e-03 8.622810000e-01 1.123700000e-01 1.420996057e-04 +8.263750000e-03 9.086470000e-01 7.900470000e-02 1.443588017e-04 +8.370670000e-03 7.732920000e-01 7.927280000e-02 1.462583099e-04 +8.450330000e-03 1.057970000e+00 1.259590000e-01 1.476732801e-04 +8.530830000e-03 1.015660000e+00 1.132950000e-01 1.491031133e-04 +8.612170000e-03 7.347170000e-01 6.115660000e-02 1.505473850e-04 +8.694370000e-03 7.692160000e-01 6.170580000e-02 1.520069445e-04 +8.777430000e-03 1.115740000e+00 1.127300000e-01 1.534813672e-04 +8.861360000e-03 9.723030000e-01 8.971600000e-02 1.549710776e-04 +8.946160000e-03 7.512140000e-01 5.493930000e-02 1.564760759e-04 +9.031850000e-03 7.976490000e-01 5.671220000e-02 1.579963619e-04 +9.118440000e-03 9.221890000e-01 6.858410000e-02 1.595327850e-04 +9.205930000e-03 9.757550000e-01 7.293950000e-02 1.610844959e-04 +9.294320000e-03 8.195040000e-01 5.216170000e-02 1.626523440e-04 +9.383640000e-03 7.883200000e-01 4.794730000e-02 1.642367538e-04 +9.473890000e-03 7.947010000e-01 4.602240000e-02 1.658368761e-04 +9.565080000e-03 8.744000000e-01 5.151640000e-02 1.674535601e-04 +9.657210000e-03 8.396620000e-01 4.742850000e-02 1.690872306e-04 +9.750300000e-03 8.008720000e-01 4.399580000e-02 1.707370382e-04 +9.844360000e-03 1.117100000e+00 7.373300000e-02 1.724042569e-04 +9.939390000e-03 8.884110000e-01 4.954100000e-02 1.740884620e-04 +1.003540000e-02 7.791290000e-01 3.898730000e-02 1.757896536e-04 +1.013240000e-02 7.999680000e-01 3.899740000e-02 1.775086809e-04 +1.023040000e-02 8.431240000e-01 4.159800000e-02 1.792451193e-04 +1.032940000e-02 9.613320000e-01 4.925360000e-02 1.809989689e-04 +1.048680000e-02 8.805440000e-01 2.990830000e-02 1.837851690e-04 +1.063270000e-02 7.557350000e-01 3.208510000e-02 1.863700799e-04 +1.073590000e-02 9.712310000e-01 4.534850000e-02 1.881969711e-04 +1.084010000e-02 8.955490000e-01 3.905420000e-02 1.900425474e-04 +1.094540000e-02 8.625890000e-01 3.580720000e-02 1.919068087e-04 +1.105180000e-02 8.909920000e-01 3.612570000e-02 1.937906045e-04 +1.115930000e-02 9.003480000e-01 3.679240000e-02 1.956930853e-04 +1.126790000e-02 8.459270000e-01 3.218810000e-02 1.976151006e-04 +1.137760000e-02 9.431520000e-01 3.655330000e-02 1.995570749e-04 +1.148840000e-02 9.956310000e-01 3.901160000e-02 2.015185836e-04 +1.160040000e-02 9.695940000e-01 3.636230000e-02 2.034996267e-04 +1.171350000e-02 9.051810000e-01 3.204100000e-02 2.055014781e-04 +1.182780000e-02 8.933810000e-01 3.061190000e-02 2.075232887e-04 +1.194330000e-02 9.196020000e-01 3.146770000e-02 2.095659076e-04 +1.205990000e-02 9.189980000e-01 3.060970000e-02 2.116293349e-04 +1.217770000e-02 7.810560000e-01 2.355420000e-02 2.137135706e-04 +1.229680000e-02 8.649150000e-01 2.720250000e-02 2.158190394e-04 +1.241700000e-02 8.435160000e-01 2.550150000e-02 2.179457412e-04 +1.253850000e-02 9.984180000e-01 3.197220000e-02 2.200945253e-04 +1.266120000e-02 8.812600000e-01 2.602730000e-02 2.222645425e-04 +1.278520000e-02 8.835690000e-01 2.558620000e-02 2.244570667e-04 +1.291050000e-02 9.376700000e-01 2.746510000e-02 2.266716733e-04 +1.303700000e-02 1.019200000e+00 3.051070000e-02 2.289087870e-04 +1.316480000e-02 8.455260000e-01 2.262690000e-02 2.311684076e-04 +1.329390000e-02 8.738040000e-01 2.324680000e-02 2.334509599e-04 +1.342430000e-02 8.659530000e-01 2.249060000e-02 2.357568686e-04 +1.355610000e-02 8.779820000e-01 2.244910000e-02 2.380861337e-04 +1.368920000e-02 9.475450000e-01 2.489850000e-02 2.404387551e-04 +1.382370000e-02 8.881540000e-01 2.209620000e-02 2.428155821e-04 +1.395950000e-02 8.913620000e-01 2.181480000e-02 2.452161902e-04 +1.409670000e-02 8.884560000e-01 2.150920000e-02 2.476410039e-04 +1.423530000e-02 9.137170000e-01 2.225860000e-02 2.500908727e-04 +1.437530000e-02 8.103640000e-01 1.882890000e-02 2.525649471e-04 +1.451680000e-02 7.385480000e-01 1.688270000e-02 2.550645011e-04 +1.465970000e-02 6.865100000e-01 1.597420000e-02 2.575891102e-04 +1.480400000e-02 5.822400000e-01 1.350210000e-02 2.601396235e-04 +1.494980000e-02 4.468550000e-01 1.006260000e-02 2.627156166e-04 +1.509700000e-02 3.924610000e-01 9.155490000e-03 2.653175139e-04 +1.524580000e-02 3.205170000e-01 7.319590000e-03 2.679461649e-04 +1.539610000e-02 2.810060000e-01 6.399090000e-03 2.706011448e-04 +1.554790000e-02 2.401000000e-01 5.442390000e-03 2.732828784e-04 +1.570120000e-02 2.208810000e-01 5.024370000e-03 2.759917903e-04 +1.585610000e-02 1.920330000e-01 4.314410000e-03 2.787278805e-04 +1.601260000e-02 1.798490000e-01 4.051590000e-03 2.814919983e-04 +1.617070000e-02 1.600690000e-01 3.562020000e-03 2.842837190e-04 +1.633030000e-02 1.531290000e-01 3.467770000e-03 2.871038920e-04 +1.649160000e-02 1.342200000e-01 3.016000000e-03 2.899525174e-04 +1.665450000e-02 1.283300000e-01 2.888530000e-03 2.928300196e-04 +1.681900000e-02 1.247940000e-01 2.861820000e-03 2.957363988e-04 +1.698530000e-02 1.091270000e-01 2.483100000e-03 2.986720796e-04 +1.715320000e-02 1.044290000e-01 2.353920000e-03 3.016374867e-04 +1.732280000e-02 9.468300000e-02 2.091620000e-03 3.046326200e-04 +1.758810000e-02 8.969110000e-02 1.439380000e-03 3.093191777e-04 +1.784190000e-02 8.091440000e-02 1.872780000e-03 3.138010489e-04 +1.801850000e-02 7.465440000e-02 1.714220000e-03 3.169189092e-04 +1.819680000e-02 7.036610000e-02 1.634230000e-03 3.200686191e-04 +1.837700000e-02 6.904450000e-02 1.605300000e-03 3.232497539e-04 +1.855890000e-02 6.270550000e-02 1.461460000e-03 3.264631629e-04 +1.874270000e-02 5.939150000e-02 1.400070000e-03 3.297088462e-04 +1.892840000e-02 5.754770000e-02 1.360950000e-03 3.329872283e-04 +1.911590000e-02 5.138330000e-02 1.226680000e-03 3.362987340e-04 +1.930540000e-02 4.922670000e-02 1.178240000e-03 3.396437879e-04 +1.949670000e-02 4.521740000e-02 1.079620000e-03 3.430219654e-04 +1.969000000e-02 4.245560000e-02 1.022250000e-03 3.464349651e-04 +1.988520000e-02 4.126130000e-02 9.947810000e-04 3.498819376e-04 +2.008240000e-02 3.523330000e-02 8.777900000e-04 3.533637323e-04 +2.028150000e-02 3.352710000e-02 8.367470000e-04 3.568803492e-04 +2.048270000e-02 3.326840000e-02 8.339590000e-04 3.604326376e-04 +2.068590000e-02 3.166440000e-02 7.898860000e-04 3.640210222e-04 +2.089120000e-02 2.916000000e-02 7.496130000e-04 3.676450784e-04 +2.109850000e-02 2.652010000e-02 7.063830000e-04 3.713060800e-04 +2.130800000e-02 2.518290000e-02 6.713890000e-04 3.750036024e-04 +2.151950000e-02 2.387570000e-02 6.426930000e-04 3.787384951e-04 +2.173310000e-02 2.289290000e-02 6.330680000e-04 3.825111825e-04 +2.194900000e-02 2.086460000e-02 5.931280000e-04 3.863216648e-04 +2.216690000e-02 2.087710000e-02 5.920100000e-04 3.901703665e-04 +2.238710000e-02 1.822280000e-02 5.292050000e-04 3.940581370e-04 +2.260950000e-02 1.773460000e-02 5.251520000e-04 3.979849764e-04 +2.283410000e-02 1.587140000e-02 4.818770000e-04 4.019513092e-04 +2.306100000e-02 1.432550000e-02 4.516190000e-04 4.059575601e-04 +2.329020000e-02 1.427760000e-02 4.522490000e-04 4.100041538e-04 +2.352170000e-02 1.266240000e-02 4.198450000e-04 4.140919397e-04 +2.375550000e-02 1.221280000e-02 4.137860000e-04 4.182204929e-04 +2.399170000e-02 1.046080000e-02 3.745320000e-04 4.223906630e-04 +2.423020000e-02 1.061330000e-02 3.810520000e-04 4.266016005e-04 +2.447120000e-02 9.879030000e-03 3.641280000e-04 4.308567027e-04 +2.471450000e-02 8.372030000e-03 3.313930000e-04 4.351542710e-04 +2.496030000e-02 7.670480000e-03 3.077050000e-04 4.394943054e-04 +2.520860000e-02 7.344890000e-03 3.049780000e-04 4.438810525e-04 +2.545940000e-02 6.798650000e-03 2.898680000e-04 4.483102657e-04 +2.571270000e-02 5.916300000e-03 2.671780000e-04 4.527819450e-04 +2.596850000e-02 5.344980000e-03 2.515360000e-04 4.573003369e-04 +2.622690000e-02 5.122650000e-03 2.474120000e-04 4.618611950e-04 +2.648800000e-02 4.750310000e-03 2.379530000e-04 4.664730124e-04 +2.675160000e-02 4.307150000e-03 2.238500000e-04 4.711272958e-04 +2.701790000e-02 4.018170000e-03 2.200510000e-04 4.758325386e-04 +2.728680000e-02 3.539150000e-03 2.046530000e-04 4.805802475e-04 +2.755850000e-02 3.818190000e-03 2.079440000e-04 4.853789156e-04 +2.783290000e-02 2.864750000e-03 1.819210000e-04 4.902285431e-04 +2.811000000e-02 2.795800000e-03 1.766910000e-04 4.951206367e-04 +2.839000000e-02 2.621500000e-03 1.750020000e-04 5.000679362e-04 +2.867270000e-02 2.484770000e-03 1.694560000e-04 5.050619484e-04 +2.895830000e-02 2.420090000e-03 1.709250000e-04 5.101069199e-04 +2.924670000e-02 2.359260000e-03 1.700600000e-04 5.151986041e-04 +2.953810000e-02 1.978560000e-03 1.600210000e-04 5.203454942e-04 +2.983230000e-02 1.947200000e-03 1.582820000e-04 5.255475902e-04 +3.012960000e-02 1.735930000e-03 1.527310000e-04 5.307963989e-04 +3.042980000e-02 1.894590000e-03 1.603050000e-04 5.361004136e-04 +3.073300000e-02 1.696680000e-03 1.525740000e-04 5.414596341e-04 +3.103920000e-02 1.793690000e-03 1.592450000e-04 5.468698140e-04 +3.134860000e-02 1.786860000e-03 1.552020000e-04 5.523351998e-04 +3.166100000e-02 1.872010000e-03 1.583950000e-04 5.578557915e-04 +3.197660000e-02 1.688180000e-03 1.499840000e-04 5.634315891e-04 +3.229530000e-02 1.732370000e-03 1.543250000e-04 5.690625926e-04 +3.261730000e-02 1.537600000e-03 1.453960000e-04 5.747530487e-04 +3.294240000e-02 1.541340000e-03 1.497560000e-04 5.804987107e-04 +3.327080000e-02 1.700330000e-03 1.572080000e-04 5.863038252e-04 +3.360260000e-02 2.142240000e-03 1.728870000e-04 5.921683922e-04 +3.393760000e-02 1.944020000e-03 1.686890000e-04 5.980924118e-04 +3.422050000e-02 1.914000000e-03 1.077140000e-04 6.019483327e-04 +3.466450000e-02 1.986410000e-03 1.438280000e-04 6.103523719e-04 +3.502190000e-02 1.849740000e-03 1.279740000e-04 6.165099550e-04 +3.538500000e-02 1.932640000e-03 1.227080000e-04 6.227354838e-04 +3.571620000e-02 2.188990000e-03 1.495980000e-04 6.288506008e-04 +3.607730000e-02 2.314320000e-03 1.503450000e-04 6.351568151e-04 +3.646770000e-02 1.831770000e-03 1.041590000e-04 6.416328939e-04 +3.682630000e-02 1.797150000e-03 1.012920000e-04 6.480155472e-04 +3.716160000e-02 2.278740000e-03 1.417330000e-04 6.543599810e-04 +3.754210000e-02 2.183390000e-03 1.294600000e-04 6.609379784e-04 +3.794040000e-02 1.799000000e-03 9.624980000e-05 6.676221409e-04 +3.831280000e-02 1.828080000e-03 9.734640000e-05 6.742680840e-04 +3.868400000e-02 1.949850000e-03 1.082600000e-04 6.809692330e-04 +3.906920000e-02 2.042140000e-03 1.122450000e-04 6.877680540e-04 +3.947340000e-02 1.659460000e-03 8.395540000e-05 6.946772869e-04 +3.986330000e-02 1.620310000e-03 8.073380000e-05 7.016035062e-04 +4.026580000e-02 1.588620000e-03 7.617690000e-05 7.086189042e-04 +4.066080000e-02 1.582510000e-03 7.829120000e-05 7.156810150e-04 +4.107010000e-02 1.429900000e-03 7.034450000e-05 7.228323046e-04 +4.147810000e-02 1.336120000e-03 6.498820000e-05 7.300472933e-04 +4.187440000e-02 1.721900000e-03 9.200060000e-05 7.373174879e-04 +4.230490000e-02 1.404890000e-03 6.788170000e-05 7.446980943e-04 +4.273170000e-02 1.146480000e-03 5.315150000e-05 7.521381533e-04 +4.315460000e-02 1.030130000e-03 4.872800000e-05 7.596504046e-04 +4.358350000e-02 1.018640000e-03 4.851630000e-05 7.672348483e-04 +4.401550000e-02 1.060250000e-03 5.148880000e-05 7.748999775e-04 +4.445490000e-02 9.115610000e-04 4.517670000e-05 7.826415457e-04 +4.489830000e-02 7.795360000e-04 3.746760000e-05 7.904553063e-04 +4.534700000e-02 5.957570000e-04 2.867780000e-05 7.983539991e-04 +4.579470000e-02 6.476450000e-04 3.286690000e-05 8.063333774e-04 +4.625120000e-02 5.268390000e-04 2.666210000e-05 8.143891946e-04 +4.671240000e-02 4.365460000e-04 2.240950000e-05 8.225299441e-04 +4.717830000e-02 3.696050000e-04 1.929650000e-05 8.307471325e-04 +4.764690000e-02 3.315640000e-04 1.808550000e-05 8.390577463e-04 +4.812080000e-02 2.545840000e-04 1.440620000e-05 8.474405525e-04 +4.859940000e-02 2.090800000e-04 1.312430000e-05 8.559167841e-04 +4.908280000e-02 1.929370000e-04 1.261590000e-05 8.644779478e-04 +4.957100000e-02 1.309220000e-04 9.992220000e-06 8.731240437e-04 +5.006400000e-02 1.098230000e-04 9.080510000e-06 8.818635651e-04 +5.056190000e-02 9.565480000e-05 8.370090000e-06 8.906880186e-04 +5.106550000e-02 7.925720000e-05 7.699130000e-06 8.995974043e-04 +5.157340000e-02 7.956050000e-05 6.898560000e-06 9.086044619e-04 +5.208640000e-02 7.224950000e-05 6.102730000e-06 9.177006984e-04 +5.260450000e-02 7.825130000e-05 6.391360000e-06 9.268903603e-04 +5.312790000e-02 8.637120000e-05 6.561860000e-06 9.361734476e-04 +5.365650000e-02 1.331620000e-04 8.789840000e-06 9.455499603e-04 +5.419050000e-02 1.436320000e-04 8.178840000e-06 9.550241449e-04 +5.472980000e-02 1.586820000e-04 8.565340000e-06 9.645917550e-04 +5.527450000e-02 1.900070000e-04 9.755240000e-06 9.742612837e-04 +5.582470000e-02 2.354200000e-04 1.141720000e-05 9.840284844e-04 +5.638040000e-02 2.339320000e-04 1.034520000e-05 9.938933571e-04 +5.694170000e-02 2.433900000e-04 1.059550000e-05 1.003855902e-03 +5.750870000e-02 2.708580000e-04 1.125130000e-05 1.013924612e-03 +5.808130000e-02 3.109660000e-04 1.233550000e-05 1.024095240e-03 +5.865970000e-02 3.483270000e-04 1.357860000e-05 1.034367788e-03 +5.924390000e-02 3.329570000e-04 1.275590000e-05 1.044750747e-03 +5.983400000e-02 3.546590000e-04 1.322360000e-05 1.055235624e-03 +6.043000000e-02 3.544670000e-04 1.306610000e-05 1.065826667e-03 +6.103190000e-02 3.855150000e-04 1.408930000e-05 1.076523875e-03 +6.164000000e-02 3.325090000e-04 1.201760000e-05 1.087335742e-03 +6.225410000e-02 3.330870000e-04 1.197150000e-05 1.098253773e-03 +6.287440000e-02 3.303070000e-04 1.197230000e-05 1.109286464e-03 +6.350090000e-02 3.224690000e-04 1.162910000e-05 1.120433812e-03 +6.413370000e-02 2.744620000e-04 9.948790000e-06 1.131691573e-03 +6.477280000e-02 2.792430000e-04 1.025370000e-05 1.143063992e-03 +6.541840000e-02 2.389380000e-04 8.960850000e-06 1.154555315e-03 +6.607040000e-02 2.330280000e-04 8.726650000e-06 1.166165544e-03 +6.672900000e-02 1.863430000e-04 7.236140000e-06 1.177890432e-03 +6.739420000e-02 1.649490000e-04 6.619500000e-06 1.189738471e-03 +6.806600000e-02 1.332440000e-04 5.541570000e-06 1.201709662e-03 +6.874460000e-02 1.153760000e-04 4.971620000e-06 1.213799758e-03 +6.943000000e-02 8.250330000e-05 3.951150000e-06 1.226017252e-03 +7.012230000e-02 6.719230000e-05 3.570180000e-06 1.238357898e-03 +7.082150000e-02 5.033220000e-05 2.926230000e-06 1.250825942e-03 +7.152780000e-02 3.336120000e-05 2.509700000e-06 1.263421384e-03 +7.224110000e-02 2.290520000e-05 2.116380000e-06 1.276148471e-03 +7.293380000e-02 1.879440000e-05 1.860530000e-06 1.288068702e-03 +7.366830000e-02 1.553440000e-05 1.798210000e-06 1.301292643e-03 +7.440150000e-02 1.824520000e-05 1.951840000e-06 1.314359459e-03 +7.514050000e-02 2.235620000e-05 1.801000000e-06 1.327506960e-03 +7.587210000e-02 2.773620000e-05 1.890140000e-06 1.340293500e-03 +7.664020000e-02 3.931010000e-05 2.300950000e-06 1.354192651e-03 +7.739640000e-02 4.596690000e-05 2.332400000e-06 1.367582209e-03 +7.810610000e-02 5.541310000e-05 2.459260000e-06 1.379328330e-03 +7.886820000e-02 6.726050000e-05 2.729570000e-06 1.392692408e-03 +7.979530000e-02 7.650640000e-05 2.773090000e-06 1.409143772e-03 +8.072890000e-02 7.794720000e-05 2.857410000e-06 1.425518696e-03 +8.153340000e-02 8.505420000e-05 2.990400000e-06 1.439910454e-03 +8.233180000e-02 9.685690000e-05 3.222700000e-06 1.454408377e-03 +8.316050000e-02 9.462400000e-05 3.166210000e-06 1.469122877e-03 +8.402520000e-02 8.585640000e-05 2.824460000e-06 1.484058201e-03 +8.486480000e-02 8.101440000e-05 2.662540000e-06 1.499057224e-03 +8.573420000e-02 7.655920000e-05 2.549780000e-06 1.514268578e-03 +8.655530000e-02 7.385430000e-05 2.485840000e-06 1.529496917e-03 +8.743720000e-02 6.249710000e-05 2.190920000e-06 1.545009780e-03 +8.831630000e-02 5.495430000e-05 2.001270000e-06 1.560658534e-03 +8.911080000e-02 5.694540000e-05 2.081580000e-06 1.576247836e-03 +9.004160000e-02 4.229200000e-05 1.729710000e-06 1.592304265e-03 +9.095460000e-02 3.367540000e-05 1.458910000e-06 1.608462612e-03 +9.185040000e-02 2.545640000e-05 1.249630000e-06 1.624727124e-03 +9.274350000e-02 2.092210000e-05 1.159760000e-06 1.641140268e-03 +9.362890000e-02 1.531120000e-05 1.060140000e-06 1.657689303e-03 +9.455270000e-02 1.265650000e-05 9.577530000e-07 1.674480395e-03 +9.551780000e-02 9.331240000e-06 8.621390000e-07 1.691509297e-03 +9.647710000e-02 8.901520000e-06 7.828970000e-07 1.708691077e-03 +9.741890000e-02 1.079150000e-05 8.938470000e-07 1.725991763e-03 +9.842590000e-02 1.213680000e-05 9.113080000e-07 1.743589710e-03 +9.942010000e-02 1.540800000e-05 9.077770000e-07 1.761323549e-03 +1.004250000e-01 1.938030000e-05 9.602530000e-07 1.779248486e-03 +1.014340000e-01 2.091160000e-05 1.040890000e-06 1.797347534e-03 +1.024990000e-01 2.519250000e-05 1.078370000e-06 1.815722611e-03 +1.034980000e-01 2.818800000e-05 1.132170000e-06 1.834144401e-03 +1.045460000e-01 2.998100000e-05 1.178530000e-06 1.852837973e-03 +1.056080000e-01 3.056280000e-05 1.150490000e-06 1.871735383e-03 +1.066820000e-01 2.819030000e-05 1.099070000e-06 1.890832384e-03 +1.077580000e-01 2.692630000e-05 1.037400000e-06 1.910111989e-03 +1.088310000e-01 2.541920000e-05 1.012560000e-06 1.929574198e-03 +1.099160000e-01 2.282700000e-05 9.367100000e-07 1.949244491e-03 +1.110400000e-01 1.769170000e-05 7.904500000e-07 1.969169580e-03 +1.121170000e-01 1.547510000e-05 7.625400000e-07 1.989209328e-03 +1.132440000e-01 1.172580000e-05 6.688050000e-07 2.009529352e-03 +1.143190000e-01 1.050270000e-05 6.598050000e-07 2.029959788e-03 +1.154640000e-01 8.121530000e-06 5.847030000e-07 2.050708720e-03 +1.166450000e-01 4.988840000e-06 5.267190000e-07 2.071720941e-03 +1.177620000e-01 4.909990000e-06 5.360960000e-07 2.092830835e-03 +1.189250000e-01 5.304340000e-06 5.240840000e-07 2.114229497e-03 +1.201290000e-01 5.689050000e-06 4.912340000e-07 2.135895696e-03 +1.213460000e-01 6.444710000e-06 5.061070000e-07 2.157799706e-03 +1.225860000e-01 7.456190000e-06 5.058030000e-07 2.179954265e-03 +1.238230000e-01 8.248420000e-06 5.025600000e-07 2.202325401e-03 +1.250910000e-01 1.067490000e-05 5.845390000e-07 2.224964074e-03 +1.263610000e-01 1.131620000e-05 5.722280000e-07 2.247827816e-03 +1.276430000e-01 1.104400000e-05 5.762550000e-07 2.270937863e-03 +1.289320000e-01 1.062580000e-05 5.655340000e-07 2.294294212e-03 +1.302100000e-01 9.337660000e-06 5.254720000e-07 2.317858646e-03 +1.315470000e-01 8.922800000e-06 5.000680000e-07 2.341754314e-03 +1.328540000e-01 6.436110000e-06 4.446880000e-07 2.365841081e-03 +1.341620000e-01 6.181130000e-06 4.556250000e-07 2.390178397e-03 +1.355150000e-01 4.685680000e-06 4.034780000e-07 2.414821469e-03 +1.368240000e-01 4.667540000e-06 3.809290000e-07 2.439659885e-03 +1.382040000e-01 4.262500000e-06 3.763010000e-07 2.464842276e-03 +1.395890000e-01 3.884300000e-06 3.571580000e-07 2.490292204e-03 +1.409890000e-01 3.699480000e-06 3.796620000e-07 2.516022408e-03 +1.424300000e-01 3.659930000e-06 3.543380000e-07 2.542066861e-03 +1.438510000e-01 4.559390000e-06 3.665690000e-07 2.568357617e-03 +1.452630000e-01 4.580880000e-06 3.470620000e-07 2.594911663e-03 +1.467500000e-01 4.829290000e-06 3.503920000e-07 2.621826671e-03 +1.482250000e-01 4.930920000e-06 3.533300000e-07 2.649009215e-03 +1.497100000e-01 4.781000000e-06 3.612560000e-07 2.676489022e-03 +1.512250000e-01 4.644840000e-06 3.397110000e-07 2.704291571e-03 +1.527360000e-01 4.365080000e-06 3.324590000e-07 2.732374397e-03 +1.542610000e-01 3.807060000e-06 3.253780000e-07 2.760775718e-03 +1.558250000e-01 3.544150000e-06 3.053880000e-07 2.789516767e-03 +1.573660000e-01 2.632690000e-06 2.773550000e-07 2.818538093e-03 +1.589410000e-01 2.129680000e-06 2.570610000e-07 2.847903395e-03 +1.605110000e-01 2.509080000e-06 2.684170000e-07 2.877574452e-03 +1.621370000e-01 2.606260000e-06 2.683540000e-07 2.907627704e-03 +1.637550000e-01 2.467960000e-06 2.618110000e-07 2.937986711e-03 +1.654040000e-01 2.437690000e-06 2.457080000e-07 2.968710928e-03 +1.670350000e-01 2.818460000e-06 2.626350000e-07 2.999740899e-03 +1.687360000e-01 3.201910000e-06 2.677220000e-07 3.031182793e-03 +1.704100000e-01 3.020960000e-06 2.548660000e-07 3.062934688e-03 +1.721190000e-01 2.398550000e-06 2.324640000e-07 3.095064532e-03 +1.738390000e-01 2.458240000e-06 2.385460000e-07 3.127555337e-03 +1.755740000e-01 2.033660000e-06 2.231960000e-07 3.160419844e-03 +1.773360000e-01 1.684040000e-06 2.048280000e-07 3.193666546e-03 +1.790870000e-01 1.293830000e-06 2.007650000e-07 3.227265717e-03 +1.809070000e-01 1.439670000e-06 1.882070000e-07 3.261306534e-03 +1.827150000e-01 1.540200000e-06 1.999980000e-07 3.295708314e-03 +1.845350000e-01 1.338490000e-06 1.864820000e-07 3.330500781e-03 +1.863830000e-01 1.615990000e-06 1.863690000e-07 3.365705170e-03 +1.882470000e-01 1.493470000e-06 1.883860000e-07 3.401317233e-03 +1.901260000e-01 2.059680000e-06 1.920700000e-07 3.437345464e-03 +1.920380000e-01 1.690150000e-06 1.767700000e-07 3.473806849e-03 +1.939540000e-01 1.488370000e-06 1.792740000e-07 3.510675908e-03 +1.959000000e-01 1.403820000e-06 1.747280000e-07 3.547990861e-03 +1.978600000e-01 1.346890000e-06 1.705690000e-07 3.585734722e-03 +1.998450000e-01 9.477100000e-07 1.617790000e-07 3.623937217e-03 +2.018330000e-01 1.089550000e-06 1.735020000e-07 3.662568619e-03 +2.038630000e-01 1.246350000e-06 1.654660000e-07 3.701684134e-03 +2.059040000e-01 1.227370000e-06 1.644900000e-07 3.741254037e-03 +2.079590000e-01 1.168960000e-06 1.584560000e-07 3.781286820e-03 +2.100420000e-01 1.161720000e-06 1.521980000e-07 3.821807963e-03 +2.121400000e-01 1.216890000e-06 1.588540000e-07 3.862808973e-03 +2.142570000e-01 1.317570000e-06 1.546070000e-07 3.904298343e-03 +2.163990000e-01 1.032790000e-06 1.472920000e-07 3.946293059e-03 +2.185700000e-01 1.030660000e-06 1.514730000e-07 3.988805862e-03 +2.207810000e-01 5.945350000e-07 1.511720000e-07 4.031853738e-03 +2.229880000e-01 7.279960000e-07 1.429280000e-07 4.075394220e-03 +2.252160000e-01 7.806310000e-07 1.485250000e-07 4.119465528e-03 +2.274670000e-01 1.063390000e-06 1.499300000e-07 4.164076155e-03 +2.297410000e-01 6.526970000e-07 1.296680000e-07 4.209234596e-03 +2.320370000e-01 1.074380000e-06 1.484530000e-07 4.254932355e-03 +2.343560000e-01 8.687630000e-07 1.468620000e-07 4.301220393e-03 +2.366980000e-01 9.218680000e-07 1.450820000e-07 4.348060490e-03 +2.390640000e-01 6.471490000e-07 1.368090000e-07 4.395495113e-03 +2.414540000e-01 5.363930000e-07 1.356880000e-07 4.443524261e-03 +2.438670000e-01 6.337170000e-07 1.304030000e-07 4.492147934e-03 +2.463040000e-01 6.292700000e-07 1.365570000e-07 4.541408598e-03 +2.487660000e-01 6.332920000e-07 1.224530000e-07 4.591263788e-03 +2.512530000e-01 1.037050000e-06 1.354090000e-07 4.641713503e-03 +2.537640000e-01 8.252860000e-07 1.431610000e-07 4.692842675e-03 +2.563010000e-01 6.268250000e-07 1.192570000e-07 4.744608839e-03 +2.588630000e-01 5.252590000e-07 1.227410000e-07 4.797054460e-03 +2.614500000e-01 5.218320000e-07 1.309180000e-07 4.850137073e-03 +2.640640000e-01 3.916590000e-07 1.213700000e-07 4.903941609e-03 +2.667030000e-01 4.724390000e-07 1.399730000e-07 4.958425602e-03 +2.693690000e-01 5.595360000e-07 1.391510000e-07 5.013589053e-03 +2.720620000e-01 6.640700000e-07 1.448670000e-07 5.069474428e-03 +2.747820000e-01 4.593780000e-07 1.514660000e-07 5.126081726e-03 +2.775290000e-01 3.669610000e-07 1.435460000e-07 5.183453413e-03 +2.803030000e-01 5.315310000e-07 1.483080000e-07 5.241589490e-03 +2.831050000e-01 4.289140000e-07 1.361450000e-07 5.300447491e-03 +2.859350000e-01 5.520060000e-07 1.419830000e-07 5.360112348e-03 +2.887930000e-01 5.702640000e-07 1.529000000e-07 5.420541594e-03 +2.916800000e-01 5.047310000e-07 1.364290000e-07 5.481777696e-03 +2.945960000e-01 6.619230000e-07 1.407930000e-07 5.543863119e-03 +2.975410000e-01 7.601320000e-07 1.607210000e-07 5.606755399e-03 +3.005160000e-01 4.685270000e-07 1.348870000e-07 5.670454534e-03 +3.035200000e-01 4.428600000e-07 1.471340000e-07 5.735087923e-03 +3.065540000e-01 4.899790000e-07 1.404300000e-07 5.800528167e-03 +3.096190000e-01 3.601630000e-07 1.337280000e-07 5.866902666e-03 +3.127140000e-01 2.905630000e-07 1.480620000e-07 5.934168953e-03 +3.158410000e-01 5.199630000e-07 1.515620000e-07 6.002327027e-03 +3.189980000e-01 4.666650000e-07 1.562560000e-07 6.071461822e-03 +3.221870000e-01 3.888830000e-07 1.570110000e-07 6.141530870e-03 +3.254080000e-01 4.467780000e-07 1.555120000e-07 6.212576639e-03 +3.286620000e-01 3.238850000e-07 1.525860000e-07 6.284599127e-03 +3.319470000e-01 3.787360000e-07 1.581800000e-07 6.357640802e-03 +3.352660000e-01 3.881990000e-07 1.539110000e-07 6.431701663e-03 +3.386180000e-01 4.428770000e-07 1.490980000e-07 6.506824176e-03 +3.420030000e-01 2.477870000e-07 1.463210000e-07 6.582965876e-03 +3.454230000e-01 2.857690000e-07 1.351350000e-07 6.660211693e-03 +3.488760000e-01 4.759640000e-07 1.536640000e-07 6.738561630e-03 +3.523640000e-01 4.496390000e-07 1.539560000e-07 6.818015684e-03 +3.558870000e-01 2.471470000e-07 1.443220000e-07 6.898573857e-03 +3.594450000e-01 2.167640000e-07 1.491810000e-07 6.980363546e-03 +3.630390000e-01 5.205850000e-07 1.573690000e-07 7.063257354e-03 +3.666690000e-01 5.246970000e-07 1.545410000e-07 7.147425144e-03 +3.703350000e-01 3.644030000e-07 1.550240000e-07 7.232781985e-03 +3.740370000e-01 4.597520000e-07 1.653080000e-07 7.319370343e-03 +3.777770000e-01 5.359220000e-07 1.820430000e-07 7.407232683e-03 +3.815540000e-01 4.268070000e-07 1.770030000e-07 7.496411472e-03 +3.853690000e-01 4.036660000e-07 1.811100000e-07 7.586906710e-03 +3.892220000e-01 2.554540000e-07 1.597290000e-07 7.678718396e-03 +3.931130000e-01 9.269720000e-08 1.654020000e-07 7.771931464e-03 +3.970440000e-01 1.106720000e-07 1.808880000e-07 7.866503446e-03 +4.010140000e-01 4.521630000e-07 1.731910000e-07 7.962519276e-03 +4.050230000e-01 3.780660000e-07 1.515970000e-07 8.059978953e-03 +4.090730000e-01 3.091360000e-07 1.571950000e-07 8.158924942e-03 +4.131630000e-01 3.417740000e-07 1.448180000e-07 8.259357245e-03 +4.172940000e-01 3.449240000e-07 1.595810000e-07 8.361318327e-03 +4.214660000e-01 2.518400000e-07 1.597570000e-07 8.464850655e-03 +4.256800000e-01 4.017370000e-07 1.538140000e-07 8.569954228e-03 +4.299360000e-01 3.172790000e-07 1.691300000e-07 8.676713978e-03 +4.342350000e-01 5.506310000e-07 1.611420000e-07 8.785087440e-03 +4.385770000e-01 5.085100000e-07 1.649900000e-07 8.895159545e-03 +4.429620000e-01 6.025930000e-07 1.738350000e-07 9.006930294e-03 +4.473910000e-01 4.384540000e-07 1.653500000e-07 9.120484618e-03 +4.518650000e-01 3.387570000e-07 1.876390000e-07 9.235822519e-03 +4.563830000e-01 4.358460000e-07 1.978260000e-07 9.352943995e-03 +4.609460000e-01 3.855790000e-07 1.761430000e-07 9.471933979e-03 +4.655550000e-01 3.834150000e-07 1.884540000e-07 9.592834938e-03 diff --git a/pixi.lock b/pixi.lock index 0399edad..809f36c5 100644 --- a/pixi.lock +++ b/pixi.lock @@ -202,6 +202,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: git+https://github.com/easyscience/corelib.git?rev=bayesian#efd7ff176ab33f84d8a20843dfe18663560e39b8 - pypi: https://files.pythonhosted.org/packages/ac/68/1666e3a4462f8202d836920114fa7a5ee9275d1fa45366d336c551a162dd/coverage-7.13.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl - pypi: https://files.pythonhosted.org/packages/21/0e/8459ca4413e1a21a06c97d134bfaf18adfd27cea068813dc0faae06cbf00/cssselect2-0.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl @@ -210,7 +211,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4a/8a/4cb9367a86f2b9526727ee94e5e6a3d86f9f7d7d947927b444e5bcd56a89/easyscience-2.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e2/98/8b1e801939839d405f1f122e7d175cebe9aeb4e114f95bfc45e3152af9a7/fonttools-4.62.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl @@ -225,10 +225,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/b3/88c0ef22878c86035f058df0ac6c171319ffd0aa52a406455ed3a3847566/ipympl-0.10.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/16/5a/736dd2f4535dbf3bf26523f9158c011389ef88dd06ec2eef67fd744f1c7b/jupytext-1.19.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/2b/0a/7b98e1e119878a27ba8618ca1e18b14f992ff1eda40f47bccccf4de44121/kiwisolver-1.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl @@ -315,7 +312,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/a4/ce/3b6fee91c85626eaf769d617f1be9d2e15c1cca027bbdeb2e0d751469355/verspec-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b1/4f/f71e641e504111a5a74e3a20bc52d01bd86788b22699dd3fee1c63253cf6/virtualenv-21.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/ca/d53764f0534ff857239595f090f4cb83b599d226cc326c7de5eb3d802715/xhtml2pdf-0.2.17-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/66/fe/b1e10b08d287f518994f1e2ff9b6d26f0adeecd8dd7d533b01bab29a3eda/yarl-1.23.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl @@ -511,6 +507,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl + - pypi: git+https://github.com/easyscience/corelib.git?rev=bayesian#efd7ff176ab33f84d8a20843dfe18663560e39b8 - pypi: https://files.pythonhosted.org/packages/0c/c9/44fb661c55062f0818a6ffd2685c67aa30816200d5f2817543717d4b92eb/coverage-7.13.5-cp313-cp313-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/21/0e/8459ca4413e1a21a06c97d134bfaf18adfd27cea068813dc0faae06cbf00/cssselect2-0.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl @@ -519,7 +516,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4a/8a/4cb9367a86f2b9526727ee94e5e6a3d86f9f7d7d947927b444e5bcd56a89/easyscience-2.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3b/56/6f389de21c49555553d6a5aeed5ac9767631497ac836c4f076273d15bd72/fonttools-4.62.1-cp313-cp313-macosx_10_13_universal2.whl @@ -534,10 +530,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/b3/88c0ef22878c86035f058df0ac6c171319ffd0aa52a406455ed3a3847566/ipympl-0.10.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/16/5a/736dd2f4535dbf3bf26523f9158c011389ef88dd06ec2eef67fd744f1c7b/jupytext-1.19.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a8/3a/d0a972b34e1c63e2409413104216cd1caa02c5a37cb668d1687d466c1c45/kiwisolver-1.5.0-cp313-cp313-macosx_11_0_arm64.whl @@ -624,7 +617,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/a4/ce/3b6fee91c85626eaf769d617f1be9d2e15c1cca027bbdeb2e0d751469355/verspec-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b1/4f/f71e641e504111a5a74e3a20bc52d01bd86788b22699dd3fee1c63253cf6/virtualenv-21.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/ca/d53764f0534ff857239595f090f4cb83b599d226cc326c7de5eb3d802715/xhtml2pdf-0.2.17-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ae/50/06d511cc4b8e0360d3c94af051a768e84b755c5eb031b12adaaab6dec6e5/yarl-1.23.0-cp313-cp313-macosx_11_0_arm64.whl @@ -810,6 +802,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl + - pypi: git+https://github.com/easyscience/corelib.git?rev=bayesian#efd7ff176ab33f84d8a20843dfe18663560e39b8 - pypi: https://files.pythonhosted.org/packages/66/40/7732d648ab9d069a46e686043241f01206348e2bbf128daea85be4d6414b/coverage-7.13.5-cp313-cp313-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/21/0e/8459ca4413e1a21a06c97d134bfaf18adfd27cea068813dc0faae06cbf00/cssselect2-0.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl @@ -818,7 +811,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4a/8a/4cb9367a86f2b9526727ee94e5e6a3d86f9f7d7d947927b444e5bcd56a89/easyscience-2.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/38/60/35186529de1db3c01f5ad625bde07c1f576305eab6d86bbda4c58445f721/fonttools-4.62.1-cp313-cp313-win_amd64.whl @@ -834,10 +826,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/b3/88c0ef22878c86035f058df0ac6c171319ffd0aa52a406455ed3a3847566/ipympl-0.10.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/16/5a/736dd2f4535dbf3bf26523f9158c011389ef88dd06ec2eef67fd744f1c7b/jupytext-1.19.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/be/8a/be60e3bbcf513cc5a50f4a3e88e1dcecebb79c1ad607a7222877becaa101/kiwisolver-1.5.0-cp313-cp313-win_amd64.whl @@ -926,7 +915,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/a4/ce/3b6fee91c85626eaf769d617f1be9d2e15c1cca027bbdeb2e0d751469355/verspec-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b1/4f/f71e641e504111a5a74e3a20bc52d01bd86788b22699dd3fee1c63253cf6/virtualenv-21.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/ca/d53764f0534ff857239595f090f4cb83b599d226cc326c7de5eb3d802715/xhtml2pdf-0.2.17-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7a/84/266e8da36879c6edcd37b02b547e2d9ecdfea776be49598e75696e3316e1/yarl-1.23.0-cp313-cp313-win_amd64.whl @@ -1131,6 +1119,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: git+https://github.com/easyscience/corelib.git?rev=bayesian#efd7ff176ab33f84d8a20843dfe18663560e39b8 - pypi: https://files.pythonhosted.org/packages/92/be/b1afb692be85b947f3401375851484496134c5554e67e822c35f28bf2fbc/coverage-7.13.5-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl - pypi: https://files.pythonhosted.org/packages/21/0e/8459ca4413e1a21a06c97d134bfaf18adfd27cea068813dc0faae06cbf00/cssselect2-0.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl @@ -1139,7 +1128,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4a/8a/4cb9367a86f2b9526727ee94e5e6a3d86f9f7d7d947927b444e5bcd56a89/easyscience-2.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cc/a1/40a5c4d8e28b0851d53a8eeeb46fbd73c325a2a9a165f290a5ed90e6c597/fonttools-4.62.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl @@ -1154,10 +1142,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/b3/88c0ef22878c86035f058df0ac6c171319ffd0aa52a406455ed3a3847566/ipympl-0.10.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/16/5a/736dd2f4535dbf3bf26523f9158c011389ef88dd06ec2eef67fd744f1c7b/jupytext-1.19.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/80/46/bddc13df6c2a40741e0cc7865bb1c9ed4796b6760bd04ce5fae3928ef917/kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl @@ -1244,7 +1229,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/a4/ce/3b6fee91c85626eaf769d617f1be9d2e15c1cca027bbdeb2e0d751469355/verspec-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b1/4f/f71e641e504111a5a74e3a20bc52d01bd86788b22699dd3fee1c63253cf6/virtualenv-21.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/ca/d53764f0534ff857239595f090f4cb83b599d226cc326c7de5eb3d802715/xhtml2pdf-0.2.17-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9a/64/c53487d9f4968045b8afa51aed7ca44f58b2589e772f32745f3744476c82/yarl-1.23.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl @@ -1436,6 +1420,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0d/44/c4b0b6095fef4dc9c420e041799591e3b63e9619e3044f7f4f6c21c0ab24/contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl + - pypi: git+https://github.com/easyscience/corelib.git?rev=bayesian#efd7ff176ab33f84d8a20843dfe18663560e39b8 - pypi: https://files.pythonhosted.org/packages/35/8b/cd129b0ca4afe886a6ce9d183c44d8301acbd4ef248622e7c49a23145605/coverage-7.13.5-cp311-cp311-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/21/0e/8459ca4413e1a21a06c97d134bfaf18adfd27cea068813dc0faae06cbf00/cssselect2-0.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl @@ -1444,7 +1429,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4a/8a/4cb9367a86f2b9526727ee94e5e6a3d86f9f7d7d947927b444e5bcd56a89/easyscience-2.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/23ff32561ec8d45a4d48578b4d241369d9270dc50926c017570e60893701/fonttools-4.62.1-cp311-cp311-macosx_10_9_universal2.whl @@ -1459,10 +1443,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/b3/88c0ef22878c86035f058df0ac6c171319ffd0aa52a406455ed3a3847566/ipympl-0.10.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/16/5a/736dd2f4535dbf3bf26523f9158c011389ef88dd06ec2eef67fd744f1c7b/jupytext-1.19.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/aa/510dc933d87767584abfe03efa445889996c70c2990f6f87c3ebaa0a18c5/kiwisolver-1.5.0-cp311-cp311-macosx_11_0_arm64.whl @@ -1549,7 +1530,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/a4/ce/3b6fee91c85626eaf769d617f1be9d2e15c1cca027bbdeb2e0d751469355/verspec-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b1/4f/f71e641e504111a5a74e3a20bc52d01bd86788b22699dd3fee1c63253cf6/virtualenv-21.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/ca/d53764f0534ff857239595f090f4cb83b599d226cc326c7de5eb3d802715/xhtml2pdf-0.2.17-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b2/0d/71ceabc14c146ba8ee3804ca7b3d42b1664c8440439de5214d366fec7d3a/yarl-1.23.0-cp311-cp311-macosx_11_0_arm64.whl @@ -1731,6 +1711,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl + - pypi: git+https://github.com/easyscience/corelib.git?rev=bayesian#efd7ff176ab33f84d8a20843dfe18663560e39b8 - pypi: https://files.pythonhosted.org/packages/af/7f/4cd8a92531253f9d7c1bbecd9fa1b472907fb54446ca768c59b531248dc5/coverage-7.13.5-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/21/0e/8459ca4413e1a21a06c97d134bfaf18adfd27cea068813dc0faae06cbf00/cssselect2-0.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl @@ -1739,7 +1720,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4a/8a/4cb9367a86f2b9526727ee94e5e6a3d86f9f7d7d947927b444e5bcd56a89/easyscience-2.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d3/97/bf54c5b3f2be34e1f143e6db838dfdc54f2ffa3e68c738934c82f3b2a08d/fonttools-4.62.1-cp311-cp311-win_amd64.whl @@ -1755,10 +1735,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/b3/88c0ef22878c86035f058df0ac6c171319ffd0aa52a406455ed3a3847566/ipympl-0.10.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/16/5a/736dd2f4535dbf3bf26523f9158c011389ef88dd06ec2eef67fd744f1c7b/jupytext-1.19.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/be/6c/28f17390b62b8f2f520e2915095b3c94d88681ecf0041e75389d9667f202/kiwisolver-1.5.0-cp311-cp311-win_amd64.whl @@ -1847,7 +1824,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/a4/ce/3b6fee91c85626eaf769d617f1be9d2e15c1cca027bbdeb2e0d751469355/verspec-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b1/4f/f71e641e504111a5a74e3a20bc52d01bd86788b22699dd3fee1c63253cf6/virtualenv-21.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/ca/d53764f0534ff857239595f090f4cb83b599d226cc326c7de5eb3d802715/xhtml2pdf-0.2.17-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/22/b85eca6fa2ad9491af48c973e4c8cf6b103a73dbb271fe3346949449fca0/yarl-1.23.0-cp311-cp311-win_amd64.whl @@ -2054,6 +2030,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl + - pypi: git+https://github.com/easyscience/corelib.git?rev=bayesian#efd7ff176ab33f84d8a20843dfe18663560e39b8 - pypi: https://files.pythonhosted.org/packages/ac/68/1666e3a4462f8202d836920114fa7a5ee9275d1fa45366d336c551a162dd/coverage-7.13.5-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl - pypi: https://files.pythonhosted.org/packages/21/0e/8459ca4413e1a21a06c97d134bfaf18adfd27cea068813dc0faae06cbf00/cssselect2-0.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl @@ -2062,7 +2039,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4a/8a/4cb9367a86f2b9526727ee94e5e6a3d86f9f7d7d947927b444e5bcd56a89/easyscience-2.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e2/98/8b1e801939839d405f1f122e7d175cebe9aeb4e114f95bfc45e3152af9a7/fonttools-4.62.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl @@ -2077,10 +2053,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/b3/88c0ef22878c86035f058df0ac6c171319ffd0aa52a406455ed3a3847566/ipympl-0.10.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/16/5a/736dd2f4535dbf3bf26523f9158c011389ef88dd06ec2eef67fd744f1c7b/jupytext-1.19.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/2b/0a/7b98e1e119878a27ba8618ca1e18b14f992ff1eda40f47bccccf4de44121/kiwisolver-1.5.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl @@ -2167,7 +2140,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/a4/ce/3b6fee91c85626eaf769d617f1be9d2e15c1cca027bbdeb2e0d751469355/verspec-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b1/4f/f71e641e504111a5a74e3a20bc52d01bd86788b22699dd3fee1c63253cf6/virtualenv-21.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/ca/d53764f0534ff857239595f090f4cb83b599d226cc326c7de5eb3d802715/xhtml2pdf-0.2.17-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/66/fe/b1e10b08d287f518994f1e2ff9b6d26f0adeecd8dd7d533b01bab29a3eda/yarl-1.23.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl @@ -2363,6 +2335,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl + - pypi: git+https://github.com/easyscience/corelib.git?rev=bayesian#efd7ff176ab33f84d8a20843dfe18663560e39b8 - pypi: https://files.pythonhosted.org/packages/0c/c9/44fb661c55062f0818a6ffd2685c67aa30816200d5f2817543717d4b92eb/coverage-7.13.5-cp313-cp313-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/21/0e/8459ca4413e1a21a06c97d134bfaf18adfd27cea068813dc0faae06cbf00/cssselect2-0.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl @@ -2371,7 +2344,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4a/8a/4cb9367a86f2b9526727ee94e5e6a3d86f9f7d7d947927b444e5bcd56a89/easyscience-2.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/3b/56/6f389de21c49555553d6a5aeed5ac9767631497ac836c4f076273d15bd72/fonttools-4.62.1-cp313-cp313-macosx_10_13_universal2.whl @@ -2386,10 +2358,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/b3/88c0ef22878c86035f058df0ac6c171319ffd0aa52a406455ed3a3847566/ipympl-0.10.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/16/5a/736dd2f4535dbf3bf26523f9158c011389ef88dd06ec2eef67fd744f1c7b/jupytext-1.19.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a8/3a/d0a972b34e1c63e2409413104216cd1caa02c5a37cb668d1687d466c1c45/kiwisolver-1.5.0-cp313-cp313-macosx_11_0_arm64.whl @@ -2476,7 +2445,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/a4/ce/3b6fee91c85626eaf769d617f1be9d2e15c1cca027bbdeb2e0d751469355/verspec-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b1/4f/f71e641e504111a5a74e3a20bc52d01bd86788b22699dd3fee1c63253cf6/virtualenv-21.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/ca/d53764f0534ff857239595f090f4cb83b599d226cc326c7de5eb3d802715/xhtml2pdf-0.2.17-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ae/50/06d511cc4b8e0360d3c94af051a768e84b755c5eb031b12adaaab6dec6e5/yarl-1.23.0-cp313-cp313-macosx_11_0_arm64.whl @@ -2662,6 +2630,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/ae/44/c1221527f6a71a01ec6fbad7fa78f1d50dfa02217385cf0fa3eec7087d59/click-8.3.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl + - pypi: git+https://github.com/easyscience/corelib.git?rev=bayesian#efd7ff176ab33f84d8a20843dfe18663560e39b8 - pypi: https://files.pythonhosted.org/packages/66/40/7732d648ab9d069a46e686043241f01206348e2bbf128daea85be4d6414b/coverage-7.13.5-cp313-cp313-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/21/0e/8459ca4413e1a21a06c97d134bfaf18adfd27cea068813dc0faae06cbf00/cssselect2-0.9.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl @@ -2670,7 +2639,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4a/8a/4cb9367a86f2b9526727ee94e5e6a3d86f9f7d7d947927b444e5bcd56a89/easyscience-2.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/38/60/35186529de1db3c01f5ad625bde07c1f576305eab6d86bbda4c58445f721/fonttools-4.62.1-cp313-cp313-win_amd64.whl @@ -2686,10 +2654,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/94/84/d9273cd09688070a6523c4aee4663a8538721b2b755c4962aafae0011e72/identify-2.6.19-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/12/c9/6869a1dcf4aaf309b9543ec070be3ec3adebee7c9bec9af8c230494134b9/interrogate-1.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/b3/88c0ef22878c86035f058df0ac6c171319ffd0aa52a406455ed3a3847566/ipympl-0.10.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b3/52/bc858b1665d0dec3a2511f4e6f5c18ea85c0977563d624d597c95d6d0fd7/jupyterquiz-2.9.6.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/16/5a/736dd2f4535dbf3bf26523f9158c011389ef88dd06ec2eef67fd744f1c7b/jupytext-1.19.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/be/8a/be60e3bbcf513cc5a50f4a3e88e1dcecebb79c1ad607a7222877becaa101/kiwisolver-1.5.0-cp313-cp313-win_amd64.whl @@ -2778,7 +2743,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/a4/ce/3b6fee91c85626eaf769d617f1be9d2e15c1cca027bbdeb2e0d751469355/verspec-0.1.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b1/4f/f71e641e504111a5a74e3a20bc52d01bd86788b22699dd3fee1c63253cf6/virtualenv-21.3.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl - - pypi: https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/93/ca/d53764f0534ff857239595f090f4cb83b599d226cc326c7de5eb3d802715/xhtml2pdf-0.2.17-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/7a/84/266e8da36879c6edcd37b02b547e2d9ecdfea776be49598e75696e3316e1/yarl-1.23.0-cp313-cp313-win_amd64.whl @@ -5409,11 +5373,11 @@ packages: requires_python: '>=3.12' - pypi: ./ name: easyreflectometry - version: 1.5.0+devdirty9 - sha256: 6cb81566f4ddb1401f1f6cfdac62844e904c9e177f74d0526912a44ae0489a16 + version: 1.4.1+devdirty39 + sha256: 4ec8c51ba0a6b6582ff3e2a5758d63f81474a4f837ba5c485b2496d179cf3f7e requires_dist: - bumps - - easyscience + - easyscience @ git+https://github.com/easyscience/corelib.git@bayesian - orsopy - pooch - refl1d>=1.0.0 @@ -5421,6 +5385,8 @@ packages: - scipp - svglib<1.6 ; sys_platform == 'darwin' or sys_platform == 'linux' - xhtml2pdf + - arviz>=0.18 ; extra == 'bayesian' + - corner>=2.2 ; extra == 'bayesian' - build ; extra == 'dev' - copier ; extra == 'dev' - docstripy ; extra == 'dev' @@ -5455,34 +5421,31 @@ packages: - versioningit ; extra == 'dev' requires_python: '>=3.11' editable: true -- pypi: https://files.pythonhosted.org/packages/4a/8a/4cb9367a86f2b9526727ee94e5e6a3d86f9f7d7d947927b444e5bcd56a89/easyscience-2.3.1-py3-none-any.whl +- pypi: git+https://github.com/easyscience/corelib.git?rev=bayesian#efd7ff176ab33f84d8a20843dfe18663560e39b8 name: easyscience - version: 2.3.1 - sha256: 51dd343ff4bcf7c36e8fada32ed3ca2bdc7e1226ae08965a2c11d9fd936e3e40 + version: 2.3.1+dev11 requires_dist: - asteval - bumps - dfo-ls - - ipykernel - - ipympl - - ipython - - ipywidgets - - jupyterlab - lmfit - - matplotlib - numpy - - pixi-kernel - - pooch - scipp - - uncertainties - build ; extra == 'dev' - copier ; extra == 'dev' - - docformatter ; extra == 'dev' + - docstripy ; extra == 'dev' + - format-docstring ; extra == 'dev' - gitpython ; extra == 'dev' - interrogate ; extra == 'dev' + - ipykernel ; extra == 'dev' + - ipympl ; extra == 'dev' + - ipython ; extra == 'dev' + - ipywidgets ; extra == 'dev' - jinja2 ; extra == 'dev' + - jupyterlab ; extra == 'dev' - jupyterquiz ; extra == 'dev' - jupytext ; extra == 'dev' + - matplotlib ; extra == 'dev' - mike ; extra == 'dev' - mkdocs ; extra == 'dev' - mkdocs-autorefs ; extra == 'dev' @@ -5494,7 +5457,9 @@ packages: - nbmake ; extra == 'dev' - nbqa ; extra == 'dev' - nbstripout ; extra == 'dev' + - pooch ; extra == 'dev' - pre-commit ; extra == 'dev' + - pydoclint ; extra == 'dev' - pytest ; extra == 'dev' - pytest-cov ; extra == 'dev' - pytest-xdist ; extra == 'dev' @@ -6475,27 +6440,6 @@ packages: - pkg:pypi/ipykernel?source=hash-mapping size: 133644 timestamp: 1770566133040 -- pypi: https://files.pythonhosted.org/packages/12/b3/88c0ef22878c86035f058df0ac6c171319ffd0aa52a406455ed3a3847566/ipympl-0.10.0-py3-none-any.whl - name: ipympl - version: 0.10.0 - sha256: a09c4f0ff86490cc62aed45e53b912fb706e3ec3506c4a51ce4a670d6667f5ce - requires_dist: - - ipython<10 - - ipywidgets>=7.6.0,<9 - - matplotlib>=3.5.0,<4 - - numpy - - pillow - - traitlets<6 - - intersphinx-registry ; extra == 'docs' - - myst-nb ; extra == 'docs' - - sphinx-book-theme ; extra == 'docs' - - sphinx-copybutton ; extra == 'docs' - - sphinx-thebe ; extra == 'docs' - - sphinx-togglebutton ; extra == 'docs' - - sphinx>=1.5 ; extra == 'docs' - - nbval>=0.11.0 ; extra == 'test' - - pytest>=9.0.2 ; extra == 'test' - requires_python: '>=3.9' - conda: https://conda.anaconda.org/conda-forge/noarch/ipython-9.13.0-pyh53cf698_0.conda sha256: a0af49948a1842dfd15a0b0b2fd56c94ddbd07e07a6c8b4bc70d43015eafaff0 md5: 73e9657cd19605740d21efb14d8d0cb9 diff --git a/pyproject.toml b/pyproject.toml index 681c5562..2713a73f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,8 @@ classifiers = [ ] requires-python = '>=3.11' dependencies = [ - 'easyscience', + 'easyscience @ git+https://github.com/easyscience/corelib.git@bayesian', + # 'easyscience', 'scipp', 'refnx', 'refl1d>=1.0.0', @@ -70,6 +71,8 @@ dev = [ 'spdx-headers', # SPDX license header validation ] +bayesian = ["corner>=2.2", "arviz>=0.18"] + [project.urls] Documentation = 'https://easyscience.github.io/reflectometry-lib' 'Release Notes' = 'https://github.com/easyscience/reflectometry-lib/releases' diff --git a/src/easyreflectometry/__init__.py b/src/easyreflectometry/__init__.py index 8ff945d0..22d1210c 100644 --- a/src/easyreflectometry/__init__.py +++ b/src/easyreflectometry/__init__.py @@ -5,6 +5,7 @@ from importlib import metadata +from .analysis.bayesian import PosteriorResults from .project import Project try: @@ -13,6 +14,7 @@ __version__ = '0.0.0' __all__ = [ - 'Project', - '__version__', + Project, + PosteriorResults, + __version__, ] diff --git a/src/easyreflectometry/analysis/__init__.py b/src/easyreflectometry/analysis/__init__.py new file mode 100644 index 00000000..4fb784d9 --- /dev/null +++ b/src/easyreflectometry/analysis/__init__.py @@ -0,0 +1,21 @@ +# SPDX-FileCopyrightText: 2026 EasyReflectometry contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Post-hoc analysis utilities for reflectometry fitting results.""" + +from easyreflectometry.analysis.bayesian import PosteriorResults +from easyreflectometry.analysis.bayesian import credible_intervals +from easyreflectometry.analysis.bayesian import plot_corner +from easyreflectometry.analysis.bayesian import plot_trace +from easyreflectometry.analysis.bayesian import posterior_predictive_reflectivity +from easyreflectometry.analysis.bayesian import posterior_predictive_sld_profile +from easyreflectometry.analysis.bayesian import posterior_summary + +__all__ = [ + 'PosteriorResults', + 'plot_corner', + 'plot_trace', + 'posterior_summary', + 'credible_intervals', + 'posterior_predictive_reflectivity', + 'posterior_predictive_sld_profile', +] diff --git a/src/easyreflectometry/analysis/bayesian.py b/src/easyreflectometry/analysis/bayesian.py new file mode 100644 index 00000000..f7e8a732 --- /dev/null +++ b/src/easyreflectometry/analysis/bayesian.py @@ -0,0 +1,375 @@ +# SPDX-FileCopyrightText: 2026 EasyReflectometry contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Bayesian posterior analysis for reflectometry fitting results.""" + +from __future__ import annotations + +import warnings +from typing import Any + +import numpy as np + +try: + import corner as _corner + + _HAS_CORNER = True +except ImportError: + _HAS_CORNER = False + +try: + import arviz as _arviz + + _HAS_ARVIZ = True +except ImportError: + _HAS_ARVIZ = False + + +def _require_corner(): + if not _HAS_CORNER: + raise ImportError( + 'The ``corner`` library is required for corner plots. ' + 'Install it with ``pip install corner`` or ' + '``pip install easyreflectometry[bayesian]``.' + ) + + +def _require_arviz(): + if not _HAS_ARVIZ: + raise ImportError( + 'The ``arviz`` library is required for trace plots and R-hat. ' + 'Install it with ``pip install arviz`` or ' + '``pip install easyreflectometry[bayesian]``.' + ) + + +def _to_arviz_data(draws: np.ndarray, param_names: list[str]): + """Convert posterior draws to an arviz InferenceData object. + + :param draws: Posterior samples, shape ``(n_samples, n_params)`` or + ``(n_chains, n_draws, n_params)``. + :type draws: np.ndarray + :param param_names: Parameter names (one per column). + :type param_names: list[str] + :return: arviz InferenceData object. + """ + draws = np.asarray(draws) + if draws.ndim == 2: + draws = draws[np.newaxis, ...] # (1, n_samples, n_params) + + # Build a dict of {param_name: (chain, draw) array} + posterior_dict = {} + for i, name in enumerate(param_names): + posterior_dict[name] = draws[:, :, i] + + return _arviz.from_dict({'posterior': posterior_dict}) + + +class PosteriorResults: + """Container for Bayesian posterior samples with analysis methods. + + :param draws: Posterior samples, shape ``(n_samples, n_params)``. + :type draws: np.ndarray + :param param_names: Parameter names (one per column of ``draws``). + :type param_names: list[str] + :param logp: Log-posterior values, shape ``(n_samples,)``, or ``None``. + :type logp: np.ndarray | None + :param sampler_state: Raw sampler state object (e.g. BUMPS ``DreamState``), or ``None``. + :type sampler_state: Any | None + """ + + def __init__( + self, + draws: np.ndarray, + param_names: list[str], + logp: np.ndarray | None = None, + sampler_state: Any | None = None, + ): + self.draws = np.asarray(draws) + self.param_names = list(param_names) + self.logp = np.asarray(logp) if logp is not None else None + self.sampler_state = sampler_state + + def __repr__(self) -> str: + n_samples, n_params = self.draws.shape + return f'PosteriorResults(n_samples={n_samples}, n_params={n_params}, param_names={self.param_names})' + + def summary(self) -> str: + """Return a formatted summary table with mean, sd, and HDI for each parameter. + + :return: Formatted summary table as a string. + :rtype: str + """ + return posterior_summary(self.draws, self.param_names) + + def corner(self, **kwargs) -> None: + """Plot parameter correlation corner plot. + + Requires the ``corner`` library. + + :param kwargs: Additional keyword arguments passed to ``corner.corner``. + """ + plot_corner(self.draws, self.param_names, **kwargs) + + def trace(self, **kwargs) -> None: + """Plot MCMC trace plot. + + Requires the ``arviz`` library. + + :param kwargs: Additional keyword arguments passed to ``arviz.plot_trace``. + """ + plot_trace(self.draws, self.param_names, **kwargs) + + def credible_interval(self, alpha: float = 0.95) -> dict: + """Compute equal-tailed credible intervals for each parameter. + + :param alpha: Credible interval width (e.g. 0.95 for 95%). + :type alpha: float + :return: Dictionary mapping parameter name to ``(lower, upper)``. + :rtype: dict + """ + return credible_intervals(self.draws, self.param_names, alpha=alpha) + + def gelman_rubin(self) -> dict | None: + """Compute the Gelman-Rubin R-hat convergence diagnostic. + + Requires the ``arviz`` library. Returns ``None`` if ``arviz`` is not + available. + + :return: Dictionary mapping parameter name to R-hat value, or ``None``. + :rtype: dict | None + """ + if not _HAS_ARVIZ: + warnings.warn( + 'The ``arviz`` library is required for Gelman-Rubin R-hat. Install it with ``pip install arviz``.', + UserWarning, + ) + return None + # arviz requires at least 2 chains; treat the posterior as one chain + data = _to_arviz_data(self.draws, self.param_names) + rhat = _arviz.rhat(data) + return {name: float(rhat[name].values) for name in self.param_names} + + +def posterior_summary(draws: np.ndarray, param_names: list[str]) -> str: + """Return a formatted summary table with mean, sd, and HDI for each parameter. + + :param draws: Posterior samples, shape ``(n_samples, n_params)``. + :type draws: np.ndarray + :param param_names: Parameter names (one per column). + :type param_names: list[str] + :return: Formatted summary table as a string. + :rtype: str + """ + draws = np.asarray(draws) + lines = [f'{"parameter":<30s} {"mean":>10s} {"sd":>10s} {"hdi_2.5%":>10s} {"hdi_97.5%":>10s}'] + for i, name in enumerate(param_names): + col = draws[:, i] + lo, hi = np.percentile(col, [2.5, 97.5]) + lines.append(f'{name:<30s} {col.mean():>10.4f} {col.std():>10.4f} {lo:>10.4f} {hi:>10.4f}') + return '\n'.join(lines) + + +def plot_corner(draws: np.ndarray, param_names: list[str], **kwargs) -> None: + """Plot a parameter correlation corner plot. + + Requires the ``corner`` library. + + :param draws: Posterior samples, shape ``(n_samples, n_params)``. + :type draws: np.ndarray + :param param_names: Parameter names (one per column). + :type param_names: list[str] + :param kwargs: Additional keyword arguments passed to ``corner.corner``. + """ + _require_corner() + draws = np.asarray(draws) + defaults = { + 'labels': param_names, + 'quantiles': [0.16, 0.5, 0.84], + 'show_titles': True, + 'title_fmt': '.3f', + 'title_kwargs': {'fontsize': 12}, + } + defaults.update(kwargs) + _corner.corner(draws, **defaults) + + +def plot_trace(draws: np.ndarray, param_names: list[str], **kwargs) -> None: + """Plot MCMC trace plot. + + Requires the ``arviz`` library. + + :param draws: Posterior samples, shape ``(n_samples, n_params)``. + :type draws: np.ndarray + :param param_names: Parameter names (one per column). + :type param_names: list[str] + :param kwargs: Additional keyword arguments passed to ``arviz.plot_trace``. + """ + _require_arviz() + idata = _to_arviz_data(draws, param_names) + _arviz.plot_trace(idata, var_names=param_names, **kwargs) + + +def credible_intervals( + draws: np.ndarray, + param_names: list[str], + alpha: float = 0.95, +) -> dict: + """Compute equal-tailed credible intervals for each parameter. + + :param draws: Posterior samples, shape ``(n_samples, n_params)``. + :type draws: np.ndarray + :param param_names: Parameter names (one per column). + :type param_names: list[str] + :param alpha: Credible interval width (e.g. 0.95 for 95%). + :type alpha: float + :return: Dictionary mapping parameter name to ``(lower, upper)``. + :rtype: dict + """ + draws = np.asarray(draws) + tail = (1.0 - alpha) / 2.0 + lo_pct = tail * 100 + hi_pct = (1.0 - tail) * 100 + result = {} + for i, name in enumerate(param_names): + col = draws[:, i] + lo, hi = np.percentile(col, [lo_pct, hi_pct]) + result[name] = (float(lo), float(hi)) + return result + + +def _save_parameter_state(model) -> dict: + """Save the current values and errors of all free parameters in a model. + + :param model: A reflectometry model with ``get_parameters()``. + :return: Dictionary mapping ``unique_name`` to ``(value, error)``. + :rtype: dict + """ + state = {} + for param in model.get_parameters(): + state[param.unique_name] = (param.value, param.error) + return state + + +def _restore_parameter_state(model, state: dict) -> None: + """Restore parameter values and errors from a saved state. + + :param model: A reflectometry model with ``get_parameters()``. + :param state: Dictionary mapping ``unique_name`` to ``(value, error)``. + """ + for param in model.get_parameters(): + if param.unique_name in state: + param.value = state[param.unique_name][0] + param.error = state[param.unique_name][1] + + +def _apply_draw(model, draws: np.ndarray, param_names: list[str], row: int) -> None: + """Apply a single posterior draw to the model parameters. + + Parameter lookup uses ``unique_name``, matching the BUMPS names after + removing the minimizer prefix, which avoids collisions when repeated models + or multi-contrast fits contain similarly named parameters. + + :param model: A reflectometry model with ``get_parameters()``. + :param draws: Posterior samples array. + :param param_names: Parameter names matching the columns of ``draws``. + :param row: Index of the draw to apply. + """ + param_lookup = {p.unique_name: p for p in model.get_parameters()} + for j, name in enumerate(param_names): + if name in param_lookup: + param_lookup[name].value = float(draws[row, j]) + + +def posterior_predictive_reflectivity( + draws: np.ndarray, + param_names: list[str], + model, + q_values: np.ndarray, + n_samples: int = 200, +) -> tuple[np.ndarray, np.ndarray, np.ndarray]: + """Compute the posterior predictive reflectivity with credible intervals. + + Parameter values and errors are saved before applying any posterior draw + and restored in a ``finally`` block, so the model is not left mutated. + + :param draws: Posterior samples, shape ``(n_samples_posterior, n_params)``. + :type draws: np.ndarray + :param param_names: Parameter names matching the columns of ``draws``. + :type param_names: list[str] + :param model: A reflectometry model with ``interface.fit_func``. + :param q_values: Q values at which to evaluate reflectivity. + :type q_values: np.ndarray + :param n_samples: Number of posterior draws to use (last ``n_samples``). + :type n_samples: int + :return: Tuple of ``(median, lower_95, upper_95)`` reflectivity arrays. + :rtype: tuple[np.ndarray, np.ndarray, np.ndarray] + """ + draws = np.asarray(draws) + q_values = np.asarray(q_values) + + n_total = draws.shape[0] + n_use = min(n_samples, n_total) + sample_indices = range(n_total - n_use, n_total) + + saved_state = _save_parameter_state(model) + try: + reflectivity_samples = [] + for i in sample_indices: + _apply_draw(model, draws, param_names, i) + r_calc = model.interface.fit_func(q_values, model.unique_name) + reflectivity_samples.append(np.asarray(r_calc)) + finally: + _restore_parameter_state(model, saved_state) + + reflectivity_samples = np.array(reflectivity_samples) + median = np.median(reflectivity_samples, axis=0) + lower = np.percentile(reflectivity_samples, 2.5, axis=0) + upper = np.percentile(reflectivity_samples, 97.5, axis=0) + return median, lower, upper + + +def posterior_predictive_sld_profile( + draws: np.ndarray, + param_names: list[str], + model, + n_samples: int = 200, +) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: + """Compute the posterior predictive SLD profile with credible intervals. + + Parameter values and errors are saved before applying any posterior draw + and restored in a ``finally`` block, so the model is not left mutated. + + :param draws: Posterior samples, shape ``(n_samples_posterior, n_params)``. + :type draws: np.ndarray + :param param_names: Parameter names matching the columns of ``draws``. + :type param_names: list[str] + :param model: A reflectometry model with ``interface.sld_profile``. + :param n_samples: Number of posterior draws to use (last ``n_samples``). + :type n_samples: int + :return: Tuple of ``(z, median, lower_95, upper_95)`` SLD profile arrays. + :rtype: tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray] + """ + draws = np.asarray(draws) + + n_total = draws.shape[0] + n_use = min(n_samples, n_total) + sample_indices = range(n_total - n_use, n_total) + + saved_state = _save_parameter_state(model) + try: + sld_samples = [] + z_shared = None + for i in sample_indices: + _apply_draw(model, draws, param_names, i) + z, sld = model.interface.sld_profile(model.unique_name) + if z_shared is None: + z_shared = np.asarray(z) + sld_samples.append(np.asarray(sld)) + finally: + _restore_parameter_state(model, saved_state) + + sld_samples = np.array(sld_samples) + median = np.median(sld_samples, axis=0) + lower = np.percentile(sld_samples, 2.5, axis=0) + upper = np.percentile(sld_samples, 97.5, axis=0) + return z_shared, median, lower, upper diff --git a/src/easyreflectometry/fitting.py b/src/easyreflectometry/fitting.py index 78f74e68..3d50fe99 100644 --- a/src/easyreflectometry/fitting.py +++ b/src/easyreflectometry/fitting.py @@ -353,6 +353,85 @@ def fit_single_data_set_1d(self, data: DataSet1D, objective: str | None = None) ] return result + def sample( + self, + data: sc.DataGroup, + samples: int = 10000, + burn: int = 2000, + thin: int = 10, + chains: int | None = None, + population: int | None = None, + seed: int | None = None, + objective: str | None = None, + initializer: str | None = None, + progress_callback=None, + abort_test=None, + ) -> dict: + """Run Bayesian MCMC sampling on reflectometry data using the DREAM sampler. + + Requires that the minimizer is a BUMPS instance (i.e. the minimizer was + switched to ``AvailableMinimizers.Bumps``). + + :param data: DataGroup with reflectivity data. + :param samples: Number of retained DREAM samples requested from BUMPS. + :param burn: Burn-in steps. + :param thin: Thinning interval. + :param chains: User-friendly alias for BUMPS DREAM population count. + :param population: BUMPS DREAM population count for advanced users. + :param seed: Random seed for reproducibility. + :param objective: Zero-variance handling strategy. + :param initializer: DREAM population initializer. One of ``'eps'``, + ``'cov'``, ``'lhs'``, or ``'random'``. By default, None (BUMPS + uses ``'eps'``). + :param progress_callback: Optional callback for progress updates during + sampling. Forwarded to the core MultiFitter. + :return: Dictionary with keys ``'draws'``, ``'param_names'``, ``'state'``, + and ``'logp'``. + :raises RuntimeError: If the current minimizer is not a BUMPS instance. + """ + obj = _validate_objective(objective) if objective is not None else self._objective + + refl_nums = [k[3:] for k in data['coords'].keys() if 'Qz' == k[:2]] + x = [] + y = [] + dy = [] + + # Process each reflectivity dataset + for i in refl_nums: + x_vals = data['coords'][f'Qz_{i}'].values + y_vals = data['data'][f'R_{i}'].values + variances = data['data'][f'R_{i}'].variances + + x_out, y_eff, weights, stats = _prepare_fit_arrays(x_vals, y_vals, variances, obj) + + if stats['masked'] > 0: + warnings.warn( + f'Masked {stats["masked"]} data point(s) in reflectivity {i} due to zero variance during sampling.', + UserWarning, + ) + x.append(x_out) + y.append(y_eff) + dy.append(weights) + + # Delegate the actual BUMPS/DREAM sampling to the core MultiFitter + sampler_kwargs = {} + if initializer is not None: + sampler_kwargs['init'] = initializer + return self.easy_science_multi_fitter.sample( + x=x, + y=y, + weights=dy, + samples=samples, + burn=burn, + thin=thin, + chains=chains, + population=population, + seed=seed, + sampler_kwargs=sampler_kwargs or None, + progress_callback=progress_callback, + abort_test=abort_test, + ) + @property def chi2(self) -> float | None: """Total chi-squared across all fitted datasets, or None if no fit has been performed.""" diff --git a/tests/test_bayesian.py b/tests/test_bayesian.py new file mode 100644 index 00000000..3de2bd3f --- /dev/null +++ b/tests/test_bayesian.py @@ -0,0 +1,241 @@ +# SPDX-FileCopyrightText: 2026 EasyReflectometry contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Tests for the Bayesian analysis module.""" + +import numpy as np +import pytest + + +@pytest.fixture +def sample_draws(): + """Generate synthetic posterior draws for testing.""" + rng = np.random.default_rng(42) + n_samples = 100 + # Two parameters: 'thickness' and 'sld' + thickness = rng.normal(loc=250, scale=10, size=n_samples) + sld = rng.normal(loc=2.0, scale=0.2, size=n_samples) + draws = np.column_stack([thickness, sld]) + param_names = ['Film_thickness', 'Film_sld'] + return draws, param_names + + +class TestPosteriorSummary: + def test_returns_string(self, sample_draws): + from easyreflectometry.analysis.bayesian import posterior_summary + + draws, param_names = sample_draws + result = posterior_summary(draws, param_names) + assert isinstance(result, str) + assert 'parameter' in result + assert 'mean' in result + assert 'sd' in result + + def test_contains_param_names(self, sample_draws): + from easyreflectometry.analysis.bayesian import posterior_summary + + draws, param_names = sample_draws + result = posterior_summary(draws, param_names) + for name in param_names: + assert name in result + + +class TestCredibleIntervals: + def test_returns_dict(self, sample_draws): + from easyreflectometry.analysis.bayesian import credible_intervals + + draws, param_names = sample_draws + result = credible_intervals(draws, param_names) + assert isinstance(result, dict) + for name in param_names: + assert name in result + lo, hi = result[name] + assert lo < hi + + def test_alpha_95_coverage(self, sample_draws): + from easyreflectometry.analysis.bayesian import credible_intervals + + draws, param_names = sample_draws + result = credible_intervals(draws, param_names, alpha=0.95) + for i, name in enumerate(param_names): + lo, hi = result[name] + # 95% interval should contain at least 90% of samples + col = draws[:, i] + inside = np.sum((col >= lo) & (col <= hi)) + assert inside / len(col) >= 0.90 + + def test_alpha_50_narrower(self, sample_draws): + from easyreflectometry.analysis.bayesian import credible_intervals + + draws, param_names = sample_draws + ci_95 = credible_intervals(draws, param_names, alpha=0.95) + ci_50 = credible_intervals(draws, param_names, alpha=0.50) + for name in param_names: + assert (ci_95[name][1] - ci_95[name][0]) > (ci_50[name][1] - ci_50[name][0]) + + +class TestPosteriorResults: + def test_repr(self, sample_draws): + from easyreflectometry.analysis.bayesian import PosteriorResults + + draws, param_names = sample_draws + pr = PosteriorResults(draws, param_names) + rep = repr(pr) + assert 'PosteriorResults' in rep + assert str(draws.shape[0]) in rep + + def test_summary_delegates(self, sample_draws): + from easyreflectometry.analysis.bayesian import PosteriorResults + + draws, param_names = sample_draws + pr = PosteriorResults(draws, param_names) + summary_str = pr.summary() + assert isinstance(summary_str, str) + assert 'parameter' in summary_str + + def test_credible_interval_delegates(self, sample_draws): + from easyreflectometry.analysis.bayesian import PosteriorResults + + draws, param_names = sample_draws + pr = PosteriorResults(draws, param_names) + ci = pr.credible_interval(alpha=0.95) + assert isinstance(ci, dict) + for name in param_names: + assert name in ci + + +class TestPosteriorPredictiveReflectivity: + def test_returns_tuples(self, sample_draws): + """Test with a mock model that returns a constant array.""" + from unittest.mock import MagicMock + + from easyreflectometry.analysis.bayesian import posterior_predictive_reflectivity + + draws, param_names = sample_draws + mock_model = MagicMock() + mock_model.unique_name = 'test_model' + mock_model.interface = MagicMock() + mock_model.interface.fit_func = MagicMock(return_value=np.ones(50)) + mock_model.get_parameters = MagicMock(return_value=[]) + + q_values = np.linspace(0.01, 0.3, 50) + median, lower, upper = posterior_predictive_reflectivity( + draws, + param_names, + mock_model, + q_values, + n_samples=20, + ) + assert median.shape == (50,) + assert lower.shape == (50,) + assert upper.shape == (50,) + + +class TestPosteriorPredictiveSLDProfile: + def test_returns_tuples(self, sample_draws): + """Test with a mock model that returns constant z and sld.""" + from unittest.mock import MagicMock + + from easyreflectometry.analysis.bayesian import posterior_predictive_sld_profile + + draws, param_names = sample_draws + mock_model = MagicMock() + mock_model.unique_name = 'test_model' + mock_model.interface = MagicMock() + mock_model.interface.sld_profile = MagicMock(return_value=(np.linspace(0, 500, 100), np.ones(100) * 2.0)) + mock_model.get_parameters = MagicMock(return_value=[]) + + z, median, lower, upper = posterior_predictive_sld_profile( + draws, + param_names, + mock_model, + n_samples=20, + ) + assert z.shape == (100,) + assert median.shape == (100,) + assert lower.shape == (100,) + assert upper.shape == (100,) + + +class TestCornerPlot: + def test_plot_corner_does_not_crash(self, sample_draws): + """Test that plot_corner does not crash when corner is available.""" + import matplotlib + + matplotlib.use('Agg') # Non-interactive backend for testing + + try: + from easyreflectometry.analysis.bayesian import plot_corner + + draws, param_names = sample_draws + plot_corner(draws, param_names) + except ImportError: + pytest.skip('corner library not installed') + + +class TestSaveRestoreParameterState: + def test_save_and_restore(self): + """Test that parameter state save/restore works correctly.""" + from easyreflectometry.analysis.bayesian import _restore_parameter_state + from easyreflectometry.analysis.bayesian import _save_parameter_state + + # Use simple objects that support attribute assignment + class MockParam: + def __init__(self, unique_name, raw_value, error): + self.unique_name = unique_name + self.value = raw_value + self.error = error + + param1 = MockParam('param_a', 1.5, 0.1) + param2 = MockParam('param_b', 3.0, 0.2) + + class MockModel: + def get_parameters(self): + return [param1, param2] + + model = MockModel() + + state = _save_parameter_state(model) + assert state['param_a'] == (1.5, 0.1) + assert state['param_b'] == (3.0, 0.2) + + # Modify values + param1.raw_value = 99.0 + param1.value = 99.0 + param2.raw_value = 99.0 + param2.value = 99.0 + + _restore_parameter_state(model, state) + assert param1.value == 1.5 + assert param1.error == 0.1 + assert param2.value == 3.0 + assert param2.error == 0.2 + + +class TestApplyDraw: + def test_apply_draw_updates_parameters(self): + """Test that _apply_draw sets parameter values correctly.""" + from easyreflectometry.analysis.bayesian import _apply_draw + + class MockParam: + def __init__(self, unique_name): + self.unique_name = unique_name + self.value = None + + param_a = MockParam('thickness') + param_b = MockParam('sld') + + class MockModel: + def get_parameters(self): + return [param_a, param_b] + + model = MockModel() + draws = np.array([[250.0, 2.0], [260.0, 2.1]]) + param_names = ['thickness', 'sld'] + + _apply_draw(model, draws, param_names, row=0) + assert param_a.value == 250.0 + assert param_b.value == 2.0 + + _apply_draw(model, draws, param_names, row=1) + assert param_a.value == 260.0 + assert param_b.value == 2.1 diff --git a/tests/test_fitting.py b/tests/test_fitting.py index 28dfe0fa..a860fdb4 100644 --- a/tests/test_fitting.py +++ b/tests/test_fitting.py @@ -801,3 +801,236 @@ def _fake_fit(*, x, y, weights): fitter.fit_single_data_set_1d(data, objective='legacy_mask') assert len(captured['x'][0]) == 2 # one point dropped + + +# --------------------------------------------------------------------------- +# Tests for MultiFitter.sample (Bayesian MCMC) +# --------------------------------------------------------------------------- + + +class TestSampleRequiresBumpsEngine: + """sample() must raise when the core engine is not a BUMPS instance.""" + + def test_raises_runtime_error_when_not_bumps(self): + model = Model() + model.interface = CalculatorFactory() + fitter = MultiFitter(model) + + data = sc.DataGroup({ + 'coords': {'Qz_0': sc.array(dims=['Qz_0'], values=np.linspace(0.01, 0.3, 10))}, + 'data': {'R_0': sc.array(dims=['Qz_0'], values=np.ones(10), variances=np.ones(10) * 0.01)}, + }) + + with pytest.raises(RuntimeError, match='Bayesian sampling requires a BUMPS minimizer'): + fitter.sample(data) + + +class TestSampleBasic: + """Basic sample() dispatch and return-value forwarding.""" + + def test_returns_core_result_dict(self): + """sample() returns whatever the core MultiFitter.sample() returns.""" + model = Model() + model.interface = CalculatorFactory() + fitter = MultiFitter(model) + + # Mock the core MultiFitter.sample to return a known dict + fake_result = {'draws': np.ones((10, 2)), 'param_names': ['a', 'b'], 'state': None, 'logp': None} + fitter.easy_science_multi_fitter = MagicMock() + fitter.easy_science_multi_fitter.sample = MagicMock(return_value=fake_result) + + data = sc.DataGroup({ + 'coords': {'Qz_0': sc.array(dims=['Qz_0'], values=np.linspace(0.01, 0.3, 10))}, + 'data': {'R_0': sc.array(dims=['Qz_0'], values=np.ones(10), variances=np.ones(10) * 0.01)}, + }) + + result = fitter.sample(data, samples=100, burn=20, thin=2, population=5) + assert result is fake_result + + def test_forwards_hyperparams_to_core(self): + """Samples, burn, thin, population, chains, seed are forwarded to core.""" + model = Model() + model.interface = CalculatorFactory() + fitter = MultiFitter(model) + + captured = {} + + def _fake_sample(*, x, y, weights, samples, burn, thin, chains, population, seed, **kwargs): + captured['samples'] = samples + captured['burn'] = burn + captured['thin'] = thin + captured['chains'] = chains + captured['population'] = population + captured['seed'] = seed + return {'draws': np.ones((10, 2)), 'param_names': ['a', 'b'], 'state': None, 'logp': None} + + fitter.easy_science_multi_fitter = MagicMock() + fitter.easy_science_multi_fitter.sample = MagicMock(side_effect=_fake_sample) + + data = sc.DataGroup({ + 'coords': {'Qz_0': sc.array(dims=['Qz_0'], values=np.linspace(0.01, 0.3, 10))}, + 'data': {'R_0': sc.array(dims=['Qz_0'], values=np.ones(10), variances=np.ones(10) * 0.01)}, + }) + + fitter.sample(data, samples=500, burn=100, thin=5, population=8, seed=42) + assert captured['samples'] == 500 + assert captured['burn'] == 100 + assert captured['thin'] == 5 + assert captured['chains'] is None # population is the canonical param + assert captured['population'] == 8 + assert captured['seed'] == 42 + + def test_forwards_chains_as_population(self): + """'chains' argument is forwarded as the 'chains' param to core (aliased to pop there).""" + model = Model() + model.interface = CalculatorFactory() + fitter = MultiFitter(model) + + captured = {} + + def _fake_sample(*, x, y, weights, chains, **kwargs): + captured['chains'] = chains + return {'draws': np.ones((10, 2)), 'param_names': ['a', 'b'], 'state': None, 'logp': None} + + fitter.easy_science_multi_fitter = MagicMock() + fitter.easy_science_multi_fitter.sample = MagicMock(side_effect=_fake_sample) + + data = sc.DataGroup({ + 'coords': {'Qz_0': sc.array(dims=['Qz_0'], values=np.linspace(0.01, 0.3, 10))}, + 'data': {'R_0': sc.array(dims=['Qz_0'], values=np.ones(10), variances=np.ones(10) * 0.01)}, + }) + + fitter.sample(data, samples=100, burn=20, thin=2, chains=6) + assert captured['chains'] == 6 + + +class TestSampleInitializer: + """initializer parameter is forwarded via sampler_kwargs.""" + + def test_initializer_passed_as_sampler_kwargs_init(self): + """initializer='lhs' should be passed as sampler_kwargs={'init': 'lhs'} to core.""" + model = Model() + model.interface = CalculatorFactory() + fitter = MultiFitter(model) + + captured = {} + + def _fake_sample(*, sampler_kwargs, **kwargs): + captured['sampler_kwargs'] = sampler_kwargs + return {'draws': np.ones((10, 2)), 'param_names': ['a', 'b'], 'state': None, 'logp': None} + + fitter.easy_science_multi_fitter = MagicMock() + fitter.easy_science_multi_fitter.sample = MagicMock(side_effect=_fake_sample) + + data = sc.DataGroup({ + 'coords': {'Qz_0': sc.array(dims=['Qz_0'], values=np.linspace(0.01, 0.3, 10))}, + 'data': {'R_0': sc.array(dims=['Qz_0'], values=np.ones(10), variances=np.ones(10) * 0.01)}, + }) + + fitter.sample(data, samples=100, burn=20, thin=2, initializer='lhs') + assert captured['sampler_kwargs'] == {'init': 'lhs'} + + def test_initializer_none_omits_sampler_kwargs(self): + """When initializer is None, sampler_kwargs should be None, not an empty dict.""" + model = Model() + model.interface = CalculatorFactory() + fitter = MultiFitter(model) + + captured = {} + + def _fake_sample(*, sampler_kwargs, **kwargs): + captured['sampler_kwargs'] = sampler_kwargs + return {'draws': np.ones((10, 2)), 'param_names': ['a', 'b'], 'state': None, 'logp': None} + + fitter.easy_science_multi_fitter = MagicMock() + fitter.easy_science_multi_fitter.sample = MagicMock(side_effect=_fake_sample) + + data = sc.DataGroup({ + 'coords': {'Qz_0': sc.array(dims=['Qz_0'], values=np.linspace(0.01, 0.3, 10))}, + 'data': {'R_0': sc.array(dims=['Qz_0'], values=np.ones(10), variances=np.ones(10) * 0.01)}, + }) + + fitter.sample(data, samples=100, burn=20, thin=2) + assert captured['sampler_kwargs'] is None + + +class TestSampleZeroVariance: + """Zero-variance handling in the sample() data-preparation path.""" + + def test_hybrid_transforms_zero_variance_points(self): + """sample() uses the objective from constructor to prepare data arrays.""" + import warnings + + model = Model() + model.interface = CalculatorFactory() + # Use legacy_mask so zero-variance points are dropped + fitter = MultiFitter(model, objective='legacy_mask') + + captured = {} + + def _fake_sample(*, x, y, weights, **kwargs): + captured['x'] = x + captured['y'] = y + captured['weights'] = weights + return {'draws': np.ones((10, 2)), 'param_names': ['a', 'b'], 'state': None, 'logp': None} + + fitter.easy_science_multi_fitter = MagicMock() + fitter.easy_science_multi_fitter.sample = MagicMock(side_effect=_fake_sample) + + qz = np.linspace(0.01, 0.3, 10) + r = np.exp(-qz * 50) + var = np.ones(10) * 0.01 + var[3:5] = 0.0 # 2 zero-variance points + + data = sc.DataGroup({ + 'coords': {'Qz_0': sc.array(dims=['Qz_0'], values=qz)}, + 'data': {'R_0': sc.array(dims=['Qz_0'], values=r, variances=var)}, + }) + + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter('always') + fitter.sample(data, samples=100, burn=20, thin=2) + + # legacy_mask should drop the 2 zero-variance points + assert len(captured['x'][0]) == 8 + assert len(captured['y'][0]) == 8 + assert len(captured['weights'][0]) == 8 + + mask_warnings = [str(ww.message) for ww in w if 'Masked' in str(ww.message)] + assert len(mask_warnings) == 1 + assert '2 data point(s)' in mask_warnings[0] + + def test_per_call_objective_override(self): + """sample() respects per-call objective override.""" + import warnings + + model = Model() + model.interface = CalculatorFactory() + fitter = MultiFitter(model, objective='legacy_mask') # default + + captured = {} + + def _fake_sample(*, x, y, weights, **kwargs): + captured['x'] = x + captured['y'] = y + return {'draws': np.ones((10, 2)), 'param_names': ['a', 'b'], 'state': None, 'logp': None} + + fitter.easy_science_multi_fitter = MagicMock() + fitter.easy_science_multi_fitter.sample = MagicMock(side_effect=_fake_sample) + + qz = np.linspace(0.01, 0.3, 10) + r = np.exp(-qz * 50) + var = np.ones(10) * 0.01 + var[3:5] = 0.0 + + data = sc.DataGroup({ + 'coords': {'Qz_0': sc.array(dims=['Qz_0'], values=qz)}, + 'data': {'R_0': sc.array(dims=['Qz_0'], values=r, variances=var)}, + }) + + # Override to hybrid — should keep all 10 points + with warnings.catch_warnings(record=True): + warnings.simplefilter('always') + fitter.sample(data, samples=100, burn=20, thin=2, objective='hybrid') + + assert len(captured['x'][0]) == 10 # all points kept (Mighell-substituted)