aspire-inference 0.1.0a6__tar.gz → 0.1.0a8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/PKG-INFO +16 -2
  2. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/README.md +14 -1
  3. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/aspire_inference.egg-info/PKG-INFO +16 -2
  4. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/aspire_inference.egg-info/SOURCES.txt +11 -0
  5. aspire_inference-0.1.0a8/docs/Makefile +20 -0
  6. aspire_inference-0.1.0a8/docs/api.rst +28 -0
  7. aspire_inference-0.1.0a8/docs/conf.py +57 -0
  8. aspire_inference-0.1.0a8/docs/entry_points.rst +29 -0
  9. aspire_inference-0.1.0a8/docs/examples.rst +28 -0
  10. aspire_inference-0.1.0a8/docs/index.rst +63 -0
  11. aspire_inference-0.1.0a8/docs/installation.rst +73 -0
  12. aspire_inference-0.1.0a8/docs/requirements.txt +2 -0
  13. aspire_inference-0.1.0a8/docs/user_guide.rst +128 -0
  14. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/pyproject.toml +1 -0
  15. aspire_inference-0.1.0a8/readthedocs.yml +15 -0
  16. aspire_inference-0.1.0a8/src/aspire/flows/__init__.py +68 -0
  17. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/samples.py +20 -2
  18. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/transforms.py +2 -2
  19. aspire_inference-0.1.0a8/tests/test_flows/test_flows_core.py +47 -0
  20. aspire_inference-0.1.0a6/src/aspire/flows/__init__.py +0 -40
  21. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/.github/workflows/lint.yml +0 -0
  22. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/.github/workflows/publish.yml +0 -0
  23. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/.github/workflows/tests.yml +0 -0
  24. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/.gitignore +0 -0
  25. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/.pre-commit-config.yaml +0 -0
  26. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/LICENSE +0 -0
  27. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/aspire_inference.egg-info/dependency_links.txt +0 -0
  28. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/aspire_inference.egg-info/requires.txt +0 -0
  29. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/aspire_inference.egg-info/top_level.txt +0 -0
  30. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/examples/basic_example.py +0 -0
  31. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/examples/smc_example.py +0 -0
  32. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/setup.cfg +0 -0
  33. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/__init__.py +0 -0
  34. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/aspire.py +0 -0
  35. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/flows/base.py +0 -0
  36. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/flows/jax/__init__.py +0 -0
  37. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/flows/jax/flows.py +0 -0
  38. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/flows/jax/utils.py +0 -0
  39. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/flows/torch/__init__.py +0 -0
  40. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/flows/torch/flows.py +0 -0
  41. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/history.py +0 -0
  42. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/plot.py +0 -0
  43. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/samplers/__init__.py +0 -0
  44. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/samplers/base.py +0 -0
  45. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/samplers/importance.py +0 -0
  46. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/samplers/mcmc.py +0 -0
  47. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/samplers/smc/__init__.py +0 -0
  48. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/samplers/smc/base.py +0 -0
  49. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/samplers/smc/blackjax.py +0 -0
  50. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/samplers/smc/emcee.py +0 -0
  51. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/samplers/smc/minipcn.py +0 -0
  52. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/src/aspire/utils.py +0 -0
  53. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/tests/conftest.py +0 -0
  54. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/tests/integration_tests/conftest.py +0 -0
  55. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/tests/integration_tests/test_integration.py +0 -0
  56. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/tests/test_flows/test_jax_flows/test_flowjax_flows.py +0 -0
  57. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/tests/test_flows/test_torch_flows/test_zuko_flows.py +0 -0
  58. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/tests/test_samples.py +0 -0
  59. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/tests/test_transforms.py +0 -0
  60. {aspire_inference-0.1.0a6 → aspire_inference-0.1.0a8}/tests/test_utils.py +0 -0
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aspire-inference
3
- Version: 0.1.0a6
3
+ Version: 0.1.0a8
4
4
  Summary: Accelerate Sequential Posterior Inference via REuse
5
5
  Author-email: "Michael J. Williams" <michaeljw1@googlemail.com>
6
6
  License: MIT
7
7
  Project-URL: Homepage, https://github.com/mj-will/aspire
8
+ Project-URL: Documentation, https://aspire.readthedocs.io/
8
9
  Classifier: Programming Language :: Python :: 3
9
10
  Requires-Python: >=3.10
10
11
  Description-Content-Type: text/markdown
@@ -38,7 +39,7 @@ Dynamic: license-file
38
39
 
39
40
  # aspire: Accelerated Sequential Posterior Inference via REuse
40
41
 
41
- aspire is a framework for reusing existing posterior samples to obtain new results at a reduced code.
42
+ aspire is a framework for reusing existing posterior samples to obtain new results at a reduced cost.
42
43
 
43
44
  ## Installation
44
45
 
@@ -50,3 +51,16 @@ pip install aspire-inference
50
51
 
51
52
  **Important:** the name of `aspire` on PyPI is `aspire-inference` but once installed
52
53
  the package can be imported and used as `aspire`.
54
+
55
+ ## Documentation
56
+
57
+ See the [documentation on ReadTheDocs][docs].
58
+
59
+ ## Citation
60
+
61
+ If you use `aspire` in your work please cite the [DOI][DOI] and [paper][paper].
62
+
63
+
64
+ [docs]: https://aspire.readthedocs.io/
65
+ [DOI]: https://doi.org/10.5281/zenodo.15658747
66
+ [paper]: https://arxiv.org/abs/2511.04218
@@ -1,6 +1,6 @@
1
1
  # aspire: Accelerated Sequential Posterior Inference via REuse
2
2
 
3
- aspire is a framework for reusing existing posterior samples to obtain new results at a reduced code.
3
+ aspire is a framework for reusing existing posterior samples to obtain new results at a reduced cost.
4
4
 
5
5
  ## Installation
6
6
 
@@ -12,3 +12,16 @@ pip install aspire-inference
12
12
 
13
13
  **Important:** the name of `aspire` on PyPI is `aspire-inference` but once installed
14
14
  the package can be imported and used as `aspire`.
15
+
16
+ ## Documentation
17
+
18
+ See the [documentation on ReadTheDocs][docs].
19
+
20
+ ## Citation
21
+
22
+ If you use `aspire` in your work please cite the [DOI][DOI] and [paper][paper].
23
+
24
+
25
+ [docs]: https://aspire.readthedocs.io/
26
+ [DOI]: https://doi.org/10.5281/zenodo.15658747
27
+ [paper]: https://arxiv.org/abs/2511.04218
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aspire-inference
3
- Version: 0.1.0a6
3
+ Version: 0.1.0a8
4
4
  Summary: Accelerate Sequential Posterior Inference via REuse
5
5
  Author-email: "Michael J. Williams" <michaeljw1@googlemail.com>
6
6
  License: MIT
7
7
  Project-URL: Homepage, https://github.com/mj-will/aspire
8
+ Project-URL: Documentation, https://aspire.readthedocs.io/
8
9
  Classifier: Programming Language :: Python :: 3
9
10
  Requires-Python: >=3.10
10
11
  Description-Content-Type: text/markdown
@@ -38,7 +39,7 @@ Dynamic: license-file
38
39
 
39
40
  # aspire: Accelerated Sequential Posterior Inference via REuse
40
41
 
41
- aspire is a framework for reusing existing posterior samples to obtain new results at a reduced code.
42
+ aspire is a framework for reusing existing posterior samples to obtain new results at a reduced cost.
42
43
 
43
44
  ## Installation
44
45
 
@@ -50,3 +51,16 @@ pip install aspire-inference
50
51
 
51
52
  **Important:** the name of `aspire` on PyPI is `aspire-inference` but once installed
52
53
  the package can be imported and used as `aspire`.
54
+
55
+ ## Documentation
56
+
57
+ See the [documentation on ReadTheDocs][docs].
58
+
59
+ ## Citation
60
+
61
+ If you use `aspire` in your work please cite the [DOI][DOI] and [paper][paper].
62
+
63
+
64
+ [docs]: https://aspire.readthedocs.io/
65
+ [DOI]: https://doi.org/10.5281/zenodo.15658747
66
+ [paper]: https://arxiv.org/abs/2511.04218
@@ -3,6 +3,7 @@
3
3
  LICENSE
4
4
  README.md
5
5
  pyproject.toml
6
+ readthedocs.yml
6
7
  .github/workflows/lint.yml
7
8
  .github/workflows/publish.yml
8
9
  .github/workflows/tests.yml
@@ -11,6 +12,15 @@ aspire_inference.egg-info/SOURCES.txt
11
12
  aspire_inference.egg-info/dependency_links.txt
12
13
  aspire_inference.egg-info/requires.txt
13
14
  aspire_inference.egg-info/top_level.txt
15
+ docs/Makefile
16
+ docs/api.rst
17
+ docs/conf.py
18
+ docs/entry_points.rst
19
+ docs/examples.rst
20
+ docs/index.rst
21
+ docs/installation.rst
22
+ docs/requirements.txt
23
+ docs/user_guide.rst
14
24
  examples/basic_example.py
15
25
  examples/smc_example.py
16
26
  src/aspire/__init__.py
@@ -42,5 +52,6 @@ tests/test_transforms.py
42
52
  tests/test_utils.py
43
53
  tests/integration_tests/conftest.py
44
54
  tests/integration_tests/test_integration.py
55
+ tests/test_flows/test_flows_core.py
45
56
  tests/test_flows/test_jax_flows/test_flowjax_flows.py
46
57
  tests/test_flows/test_torch_flows/test_zuko_flows.py
@@ -0,0 +1,20 @@
1
+ # Minimal makefile for Sphinx documentation
2
+ #
3
+
4
+ # You can set these variables from the command line, and also
5
+ # from the environment for the first two.
6
+ SPHINXOPTS ?=
7
+ SPHINXBUILD ?= sphinx-build
8
+ SOURCEDIR = .
9
+ BUILDDIR = _build
10
+
11
+ # Put it first so that "make" without argument is like "make help".
12
+ help:
13
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14
+
15
+ .PHONY: help Makefile
16
+
17
+ # Catch-all target: route all unknown targets to Sphinx using the new
18
+ # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19
+ %: Makefile
20
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
@@ -0,0 +1,28 @@
1
+ API Reference
2
+ =============
3
+
4
+ This section documents the main public classes.
5
+
6
+ Aspire interface
7
+ ----------------
8
+
9
+ .. autoclass:: aspire.Aspire
10
+ :members:
11
+ :undoc-members:
12
+ :show-inheritance:
13
+
14
+ Samples utilities
15
+ -----------------
16
+
17
+ .. automodule:: aspire.samples
18
+ :members: Samples, SMCSamples
19
+ :undoc-members:
20
+ :show-inheritance:
21
+
22
+ History objects
23
+ ---------------
24
+
25
+ .. automodule:: aspire.history
26
+ :members: History, FlowHistory, SMCHistory
27
+ :undoc-members:
28
+ :show-inheritance:
@@ -0,0 +1,57 @@
1
+ """Sphinx configuration for the aspire documentation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import sys
7
+
8
+ # Ensure the package can be imported when building the docs locally
9
+ ROOT = os.path.abspath("..")
10
+ if ROOT not in sys.path:
11
+ sys.path.insert(0, ROOT)
12
+
13
+ import aspire # noqa: E402
14
+
15
+ # -- Project information -----------------------------------------------------
16
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
17
+
18
+ project = "aspire"
19
+ copyright = "2025, Michael J. Williams"
20
+ author = "Michael J. Williams"
21
+ version = aspire.__version__
22
+ release = aspire.__version__
23
+
24
+ # -- General configuration ---------------------------------------------------
25
+ # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
26
+
27
+ extensions = [
28
+ "sphinx.ext.autodoc",
29
+ "sphinx.ext.autosummary",
30
+ "sphinx.ext.napoleon",
31
+ "sphinx.ext.viewcode",
32
+ ]
33
+
34
+ autodoc_typehints = "description"
35
+ autodoc_member_order = "bysource"
36
+ autosummary_generate = True
37
+ napoleon_google_docstring = False
38
+ napoleon_numpy_docstring = True
39
+ napoleon_preprocess_types = True
40
+
41
+ templates_path = ["_templates"]
42
+ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
43
+
44
+ # -- Options for HTML output -------------------------------------------------
45
+
46
+ html_theme = "sphinx_book_theme"
47
+ html_static_path = ["_static"]
48
+ html_title = "aspire"
49
+ html_theme_options = {
50
+ "path_to_docs": "docs",
51
+ "repository_url": "https://github.com/mj-will/aspire",
52
+ "repository_branch": "main",
53
+ "use_edit_page_button": True,
54
+ "use_issues_button": True,
55
+ "use_repository_button": True,
56
+ "use_download_button": True,
57
+ }
@@ -0,0 +1,29 @@
1
+ Entry Points
2
+ ============
3
+
4
+ Aspire uses Python's entry point system to allow for extensibility and
5
+ integration with external libraries. This mechanism enables users to register
6
+ custom components that can be seamlessly integrated into the Aspire framework.
7
+
8
+ .. _custom_flows:
9
+
10
+ Custom Flows
11
+ ------------
12
+
13
+ Aspire supports custom flow implementations via the
14
+ ``aspire.flows`` entry point group. To register a new flow backend, define an
15
+ entry point in your ``pyproject.toml`` like so:
16
+
17
+ .. code-block:: toml
18
+
19
+ [project.entry-points."aspire.flows"]
20
+ myflow = "my_module:MyFlowClass"
21
+
22
+
23
+ The specified class must inherit from :class:`aspire.flows.base.Flow` (or one
24
+ of the existing flow wrappers), implement the required methods and define the
25
+ ``xp`` attribute which specifies the array namespace.
26
+ You can then select your custom flow by setting
27
+ ``flow_backend="myflow"`` when initializing Aspire.
28
+
29
+ For an example see ``GWFlow`` in ``aspire-gw`` (https://github.com/mj-will/aspire-gw).
@@ -0,0 +1,28 @@
1
+ Examples
2
+ ========
3
+
4
+ The repository ships with runnable scripts that demonstrate typical Aspire
5
+ workflows. Execute them from the examples directory after installing the relevant
6
+ extras.
7
+
8
+ Sequential Monte Carlo (MiniPCN)
9
+ --------------------------------
10
+
11
+ .. literalinclude:: ../examples/smc_example.py
12
+ :language: python
13
+ :linenos:
14
+ :lines: 1-80
15
+ :caption: ``examples/smc_example.py`` (excerpt)
16
+
17
+ Run the full example:
18
+
19
+ .. code-block:: console
20
+
21
+ $ python smc_example.py
22
+
23
+ The script demonstrates how to:
24
+
25
+ - Build contrived mixtures of Gaussians for testing,
26
+ - Fit a Neural Spline Flow to biased initial samples,
27
+ - Run adaptive MiniPCN-SMC via :meth:`aspire.Aspire.sample_posterior`,
28
+ - Plot diagnostics (loss curves, beta schedule, corner plots).
@@ -0,0 +1,63 @@
1
+ aspire: Accelerated Sequential Posterior Inference via REuse
2
+ ============================================================
3
+
4
+ ``aspire`` is a lightweight framework for reusing existing posterior samples
5
+ and normalizing flows to accelerate Bayesian inference. It focuses on
6
+ practical workflows: fit a flow, adaptively run Sequential Monte Carlo (SMC),
7
+ MCMC or importance samplers, and visualise or export the resulting samples.
8
+
9
+ Key capabilities
10
+ ----------------
11
+
12
+ - Fit flow-based proposals (PyTorch or JAX backends) with automatic handling of
13
+ bounded and periodic parameters.
14
+ - Run adaptive SMC (MiniPCN or BlackJAX kernels) and importance sampling with
15
+ detailed diagnostic histories.
16
+ - Inspect results via convenience helpers for evidence estimates, corner plots,
17
+ and HDF5/JSON export.
18
+
19
+ Quick start
20
+ -----------
21
+
22
+ .. code-block:: python
23
+
24
+ import numpy as np
25
+ from aspire import Aspire
26
+ from aspire.samples import Samples
27
+
28
+ def log_likelihood(samples):
29
+ x = samples.x
30
+ return -0.5 * np.sum(x**2, axis=-1)
31
+
32
+ def log_prior(samples):
33
+ return -0.5 * np.sum(samples.x**2, axis=-1)
34
+
35
+ init = Samples(np.random.normal(size=(2_000, 4)))
36
+
37
+ aspire = Aspire(
38
+ log_likelihood=log_likelihood,
39
+ log_prior=log_prior,
40
+ dims=4,
41
+ parameters=[f"x{i}" for i in range(4)],
42
+ )
43
+ aspire.fit(init, n_epochs=20)
44
+ posterior = aspire.sample_posterior(
45
+ sampler="smc",
46
+ n_samples=500,
47
+ sampler_kwargs=dict(n_steps=100),
48
+ )
49
+
50
+ posterior.plot_corner()
51
+
52
+ Use the sections below for environment setup, conceptual guidance, runnable
53
+ examples, and the complete API reference.
54
+
55
+ .. toctree::
56
+ :maxdepth: 2
57
+ :caption: Contents
58
+
59
+ installation
60
+ user_guide
61
+ examples
62
+ entry_points
63
+ api
@@ -0,0 +1,73 @@
1
+ Installation
2
+ ============
3
+
4
+ ``aspire`` targets Python 3.10+ and relies on ``numpy``, ``matplotlib``,
5
+ ``array-api-compat`` and ``h5py`` for core functionality. Optional extras
6
+ provide tighter integration with popular samplers and flow backends.
7
+
8
+ Basic setup
9
+ -----------
10
+
11
+ Install the library from PyPI (note the published name):
12
+
13
+ .. code-block:: console
14
+
15
+ $ python -m pip install aspire-inference
16
+
17
+ The installed distribution exposes the ``aspire`` import namespace.
18
+
19
+ Optional extras
20
+ ---------------
21
+
22
+ Additional features can be enabled by installing the relevant extras:
23
+
24
+ .. list-table::
25
+ :header-rows: 1
26
+ :widths: 20 70
27
+
28
+ * - Extra
29
+ - Purpose
30
+ * - ``scipy``
31
+ - Access to SciPy utilities used by certain transforms.
32
+ * - ``jax``
33
+ - JAX + ``flowjax`` backend for training normalizing flows.
34
+ * - ``torch``
35
+ - PyTorch + ``zuko`` backend (default) for normalizing flows and flow matching.
36
+ * - ``minipcn``
37
+ - Enables the MiniPCN SMC kernel.
38
+ * - ``emcee``
39
+ - Enables the ``emcee`` ensemble sampler integration.
40
+ * - ``blackjax``
41
+ - Enables the BlackJAX SMC kernel.
42
+ * - ``test``
43
+ - Installs ``pytest`` and coverage helpers for local testing.
44
+
45
+ Install extras via:
46
+
47
+ .. code-block:: console
48
+
49
+ $ python -m pip install "aspire-inference[torch,minipcn]"
50
+
51
+ From source
52
+ -----------
53
+
54
+ Clone the repository and install in editable mode:
55
+
56
+ .. code-block:: console
57
+
58
+ $ git clone https://github.com/mj-will/aspire.git
59
+ $ cd aspire
60
+ # (optional) create/activate a virtual environment
61
+ $ python -m pip install -e ".[torch,minipcn]"
62
+
63
+ After installation, run the unit test suite to confirm everything is wired up:
64
+
65
+ .. code-block:: console
66
+
67
+ $ python -m pytest
68
+
69
+ Building the docs locally requires ``sphinx`` and (optionally) the
70
+ ``sphinx-``. These are installed automatically when you run
71
+ ``python -m pip install -r docs/requirements.txt`` if such a file exists, or
72
+ you can install ``sphinx`` manually before invoking ``make html`` inside the
73
+ ``docs`` directory.
@@ -0,0 +1,2 @@
1
+ sphinx>=7.2
2
+ sphinx-book-theme>=1.1
@@ -0,0 +1,128 @@
1
+ User Guide
2
+ ==========
3
+
4
+ This guide walks through the main concepts you will use when combining
5
+ existing samples with new inference runs. It focuses on the high-level Python
6
+ API exposed by :class:`aspire.Aspire`.
7
+
8
+ Workflow overview
9
+ -----------------
10
+
11
+ 1. **Describe your problem** via ``log_likelihood`` and ``log_prior``
12
+ callables that accept :class:`aspire.samples.Samples` or compatible
13
+ objects.
14
+ 2. **Package initial draws** with :class:`aspire.samples.Samples` (or
15
+ :class:`aspire.samples.BaseSamples`) to benefit from consistent typing,
16
+ plotting helpers, and device-aware conversions.
17
+ 3. **Fit a proposal** with :meth:`aspire.Aspire.fit` to learn a proposal
18
+ tailored to the current posterior (normalising flow by default).
19
+ 4. **Sample the posterior** using :meth:`aspire.Aspire.sample_posterior`
20
+ with either importance sampling or an adaptive SMC kernel (MiniPCN,
21
+ BlackJAX, or custom samplers).
22
+ 5. **Inspect, save, and reuse** the resulting
23
+ :class:`aspire.samples.Samples`, :class:`aspire.history.History`
24
+ objects, and the fitted flow.
25
+
26
+ Working with samples
27
+ --------------------
28
+
29
+ ``aspire`` uses dataclasses defined in :mod:`aspire.samples` to keep sample
30
+ arrays, weights, and evidence estimates together. Key features:
31
+
32
+ * Automatic conversion between array namespaces (NumPy, JAX, PyTorch) via the
33
+ ``xp`` argument.
34
+ * Convenience exporters (:meth:`aspire.samples.BaseSamples.to_dict`,
35
+ :meth:`aspire.samples.BaseSamples.save`) for logging or serialisation.
36
+ * Plotting helpers (:meth:`aspire.samples.BaseSamples.plot_corner`) that
37
+ integrate with ``corner`` while respecting weights.
38
+
39
+ When constructing your own samples, provide parameter names to enable labelled
40
+ plots and dataframes. Use :meth:`aspire.samples.Samples.from_samples` to
41
+ switch namespaces or merge multiple runs with
42
+ :meth:`aspire.samples.Samples.concatenate`.
43
+
44
+ Flows and transforms
45
+ --------------------
46
+
47
+ Aspire can work with any proposal that implements ``sample_and_log_prob`` and
48
+ ``log_prob``; normalising flows remain the default. Flows are defined via
49
+ :class:`aspire.flows.base.Flow` and instantiated by
50
+ :meth:`aspire.Aspire.init_flow`. By default Aspire uses the ``zuko``
51
+ implementation of Masked Autoregressive Flows on top of PyTorch. The flow is
52
+ automatically wrapped with :class:`aspire.transforms.FlowTransform` (or a
53
+ composite of bounded / periodic transforms) so you can work with native
54
+ parameter ranges while still optimising in unconstrained space.
55
+
56
+ You can choose a backend by setting ``flow_backend="flowjax"`` to leverage JAX
57
+ or by providing a fully constructed ``flow`` instance. When ``flow_matching``
58
+ is enabled, Aspire trains a score-based model instead of a classical density
59
+ estimator (requires the `zuko` backend).
60
+
61
+ External flow implementations can be plugged in via the
62
+ ``aspire.flows`` entry point group. See :ref:`custom_flows` for details.
63
+
64
+ Sampling strategies
65
+ -------------------
66
+
67
+ The :meth:`aspire.Aspire.sample_posterior` method orchestrates several
68
+ samplers, grouped below by inference style.
69
+
70
+ Importance sampling
71
+ ~~~~~~~~~~~~~~~~~~~
72
+
73
+ ``importance``
74
+ Draws independent samples from the fitted flow and reweights them using
75
+ the provided likelihood/prior functions. Perfect for quick sanity checks
76
+ or sanity bounds on evidence estimates.
77
+
78
+ Markov chain Monte Carlo
79
+ ~~~~~~~~~~~~~~~~~~~~~~~~
80
+
81
+ ``minipcn``
82
+ Runs the :class:`aspire.samplers.mcmc.MiniPCN` kernel directly (no SMC
83
+ temperature ladder). Configure ``n_samples`` and pass MCMC kwargs such as
84
+ ``n_steps`` or ``step_fn`` via ``sampler_kwargs``.
85
+ ``emcee``
86
+ Uses the :class:`aspire.samplers.mcmc.Emcee` ensemble sampler for
87
+ gradient-free proposals. Provide ``sampler_kwargs`` like ``nwalkers`` or
88
+ ``n_steps`` to control the chain length.
89
+
90
+ Sequential Monte Carlo
91
+ ~~~~~~~~~~~~~~~~~~~~~~
92
+
93
+ ``smc`` / ``minipcn_smc``
94
+ Runs adaptive SMC with the MiniPCN MCMC kernel. Configure the number of
95
+ particles via ``n_samples`` and pass kernel settings in ``sampler_kwargs``
96
+ (for example ``n_steps``, ``target_acceptance_rate`` or ``step_fn``).
97
+ ``blackjax_smc``
98
+ Uses BlackJAX kernels (requires the ``blackjax`` extra) while keeping the
99
+ same adaptive temperature schedule as the MiniPCN backend.
100
+ ``emcee_smc``
101
+ Replaces the internal MCMC move with the ``emcee`` ensemble sampler,
102
+ providing a gradient-free option that still benefits from SMC tempering.
103
+
104
+ You can plug in custom preconditioning by setting ``preconditioning`` to
105
+ ``"standard"`` (affine normalisation based on current samples), ``"flow"``
106
+ (use the fitted flow as a transport map), or ``None`` to disable additional
107
+ transforms.
108
+
109
+ History, diagnostics, and persistence
110
+ -------------------------------------
111
+
112
+ Every sampler attaches a history object (see :mod:`aspire.history`) with
113
+ diagnostic metrics such as effective sample size, intermediate temperatures,
114
+ or acceptance rates. Plot them via :meth:`aspire.history.SMCHistory.plot` or
115
+ specialised helpers like :meth:`aspire.history.SMCHistory.plot_beta`.
116
+
117
+ Use the following methods to persist and later resume work:
118
+
119
+ * :meth:`aspire.Aspire.save_flow` / :meth:`aspire.Aspire.load_flow` to
120
+ snapshot the trained flow.
121
+ * :meth:`aspire.Aspire.save_config` or
122
+ :meth:`aspire.Aspire.save_config_to_json` to capture all hyperparameters.
123
+ * :meth:`aspire.samples.BaseSamples.save` to store weighted samples in HDF5
124
+ for downstream analysis.
125
+
126
+ Together these utilities support iterative workflows where you continuously
127
+ refine the proposal distribution, reuse expensive likelihood evaluations, and
128
+ relaunch SMC runs with minimal boilerplate.
@@ -55,6 +55,7 @@ test = [
55
55
 
56
56
  [project.urls]
57
57
  Homepage = "https://github.com/mj-will/aspire"
58
+ Documentation = "https://aspire.readthedocs.io/"
58
59
 
59
60
  [tool.setuptools_scm]
60
61
 
@@ -0,0 +1,15 @@
1
+ version: 2
2
+
3
+ sphinx:
4
+ configuration: docs/conf.py
5
+
6
+ build:
7
+ os: ubuntu-22.04
8
+ tools:
9
+ python: "3.13"
10
+
11
+ python:
12
+ install:
13
+ - method: pip
14
+ path: .
15
+ - requirements: docs/requirements.txt
@@ -0,0 +1,68 @@
1
+ import logging
2
+ from typing import Any
3
+
4
+ logger = logging.getLogger(__name__)
5
+
6
+
7
+ def get_flow_wrapper(
8
+ backend: str = "zuko", flow_matching: bool = False
9
+ ) -> tuple[type, Any]:
10
+ """Get the wrapper for the flow implementation.
11
+
12
+ Parameters
13
+ ----------
14
+ backend : str
15
+ The backend to use. Options are "zuko" (PyTorch), "flowjax" (JAX), or
16
+ any other registered flow class via entry points. Default is "zuko".
17
+ flow_matching : bool, optional
18
+ Whether to use flow matching variant of the flow. Default is False.
19
+
20
+ Returns
21
+ -------
22
+ FlowClass : type
23
+ The flow class corresponding to the specified backend.
24
+ xp : module
25
+ The array API module corresponding to the specified backend.
26
+ """
27
+ from importlib.metadata import entry_points
28
+
29
+ if backend == "zuko":
30
+ import array_api_compat.torch as torch_api
31
+
32
+ from .torch.flows import ZukoFlow, ZukoFlowMatching
33
+
34
+ if flow_matching:
35
+ return ZukoFlowMatching, torch_api
36
+ else:
37
+ return ZukoFlow, torch_api
38
+ elif backend == "flowjax":
39
+ import jax.numpy as jnp
40
+
41
+ from .jax.flows import FlowJax
42
+
43
+ if flow_matching:
44
+ raise NotImplementedError(
45
+ "Flow matching not implemented for JAX backend"
46
+ )
47
+ return FlowJax, jnp
48
+ else:
49
+ if flow_matching:
50
+ logger.warning(
51
+ "Flow matching option is ignored for external backends."
52
+ )
53
+ eps = {
54
+ ep.name.lower(): ep for ep in entry_points(group="aspire.flows")
55
+ }
56
+ if backend in eps:
57
+ FlowClass = eps[backend].load()
58
+ xp = getattr(FlowClass, "xp", None)
59
+ if xp is None:
60
+ raise ValueError(
61
+ f"Flow class {backend} does not define an `xp` attribute"
62
+ )
63
+ return FlowClass, xp
64
+ else:
65
+ known_backends = ["zuko", "flowjax"] + list(eps.keys())
66
+ raise ValueError(
67
+ f"Unknown backend '{backend}'. Available backends: {known_backends}"
68
+ )
@@ -14,6 +14,7 @@ from array_api_compat import (
14
14
  )
15
15
  from array_api_compat import device as api_device
16
16
  from array_api_compat.common._typing import Array
17
+ from matplotlib.figure import Figure
17
18
 
18
19
  from .utils import (
19
20
  asarray,
@@ -161,7 +162,24 @@ class BaseSamples:
161
162
 
162
163
  return pd.DataFrame(self.to_dict(flat=flat))
163
164
 
164
- def plot_corner(self, parameters: list[str] | None = None, **kwargs):
165
+ def plot_corner(
166
+ self,
167
+ parameters: list[str] | None = None,
168
+ fig: Figure | None = None,
169
+ **kwargs,
170
+ ):
171
+ """Plot a corner plot of the samples.
172
+
173
+ Parameters
174
+ ----------
175
+ parameters : list[str] | None
176
+ List of parameters to plot. If None, all parameters are plotted.
177
+ fig : matplotlib.figure.Figure | None
178
+ Figure to plot on. If None, a new figure is created.
179
+ **kwargs : dict
180
+ Additional keyword arguments to pass to corner.corner(). Kwargs
181
+ are deep-copied before use.
182
+ """
165
183
  import corner
166
184
 
167
185
  kwargs = copy.deepcopy(kwargs)
@@ -173,7 +191,7 @@ class BaseSamples:
173
191
  x = self.x[:, indices] if self.x.ndim > 1 else self.x[indices]
174
192
  else:
175
193
  x = self.x
176
- fig = corner.corner(to_numpy(x), **kwargs)
194
+ fig = corner.corner(to_numpy(x), fig=fig, **kwargs)
177
195
  return fig
178
196
 
179
197
  def __str__(self):
@@ -684,7 +684,7 @@ class FlowPreconditioningTransform(BaseTransform):
684
684
  self.flow_kwargs.setdefault("dtype", dtype)
685
685
  self.fit_kwargs = dict(fit_kwargs or {})
686
686
 
687
- FlowClass = get_flow_wrapper(
687
+ FlowClass, xp = get_flow_wrapper(
688
688
  backend=flow_backend, flow_matching=flow_matching
689
689
  )
690
690
  transform = CompositeTransform(
@@ -695,7 +695,7 @@ class FlowPreconditioningTransform(BaseTransform):
695
695
  bounded_transform=bounded_transform,
696
696
  affine_transform=affine_transform,
697
697
  device=device,
698
- xp=FlowClass.xp,
698
+ xp=xp,
699
699
  eps=eps,
700
700
  dtype=dtype,
701
701
  )
@@ -0,0 +1,47 @@
1
+ import pytest
2
+
3
+ from aspire.flows import get_flow_wrapper
4
+
5
+
6
+ def test_get_flow_wrapper_zuko():
7
+ FlowClass, xp = get_flow_wrapper(backend="zuko", flow_matching=False)
8
+ import array_api_compat.torch as torch_api
9
+
10
+ from aspire.flows.torch.flows import ZukoFlow
11
+
12
+ assert FlowClass is ZukoFlow
13
+ assert xp is torch_api
14
+
15
+
16
+ def test_get_flow_wrapper_zuko_flow_matching():
17
+ FlowClass, xp = get_flow_wrapper(backend="zuko", flow_matching=True)
18
+ import array_api_compat.torch as torch_api
19
+
20
+ from aspire.flows.torch.flows import ZukoFlowMatching
21
+
22
+ assert FlowClass is ZukoFlowMatching
23
+ assert xp is torch_api
24
+
25
+
26
+ def test_get_flow_wrapper_flowjax():
27
+ FlowClass, xp = get_flow_wrapper(backend="flowjax", flow_matching=False)
28
+ import jax.numpy as jnp
29
+
30
+ from aspire.flows.jax.flows import FlowJax
31
+
32
+ assert FlowClass is FlowJax
33
+ assert xp is jnp
34
+
35
+
36
+ def test_get_flow_wrapper_flowjax_flow_matching_not_implemented():
37
+ with pytest.raises(
38
+ NotImplementedError,
39
+ match="Flow matching not implemented for JAX backend",
40
+ ):
41
+ get_flow_wrapper(backend="flowjax", flow_matching=True)
42
+
43
+
44
+ def test_get_flow_wrapper_external_backend_not_found():
45
+ msg = "Unknown backend 'unknown_backend'. Available backends: "
46
+ with pytest.raises(ValueError, match=msg):
47
+ get_flow_wrapper(backend="unknown_backend")
@@ -1,40 +0,0 @@
1
- def get_flow_wrapper(backend: str = "zuko", flow_matching: bool = False):
2
- """Get the wrapper for the flow implementation."""
3
- if backend == "zuko":
4
- import array_api_compat.torch as torch_api
5
-
6
- from .torch.flows import ZukoFlow, ZukoFlowMatching
7
-
8
- if flow_matching:
9
- return ZukoFlowMatching, torch_api
10
- else:
11
- return ZukoFlow, torch_api
12
- elif backend == "flowjax":
13
- import jax.numpy as jnp
14
-
15
- from .jax.flows import FlowJax
16
-
17
- if flow_matching:
18
- raise NotImplementedError(
19
- "Flow matching not implemented for JAX backend"
20
- )
21
- return FlowJax, jnp
22
- else:
23
- from importlib.metadata import entry_points
24
-
25
- eps = {
26
- ep.name.lower(): ep
27
- for ep in entry_points().get("aspire.flows", [])
28
- }
29
- if backend in eps:
30
- FlowClass = eps[backend].load()
31
- xp = getattr(FlowClass, "xp", None)
32
- if xp is None:
33
- raise ValueError(
34
- f"Flow class {backend} does not define an `xp` attribute"
35
- )
36
- return FlowClass, xp
37
- else:
38
- raise ValueError(
39
- f"Unknown flow class: {backend}. Available classes: {list(eps.keys())}"
40
- )