diff --git a/README.md b/README.md index 26aa714..76d8742 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ -# poppy +# aspire: Accelerated Sequential Posterior Inference via REuse -Posterior post-processing in python. +aspire is a framework for reusing existing posterior samples to obtain new results at a reduced code. ## Installation -Poppy can be installed from PyPI using `pip` +aspire can be installed from PyPI using `pip` ``` -pip install poppy-inference +pip install aspire-inference ``` -**Important:** the name of `poppy` on PyPI is `poppy-inference` but once installed -the package can be imported and used as `poppy`. +**Important:** the name of `aspire` on PyPI is `aspire-inference` but once installed +the package can be imported and used as `aspire`. diff --git a/examples/basic_example.py b/examples/basic_example.py index 06fff12..9723097 100644 --- a/examples/basic_example.py +++ b/examples/basic_example.py @@ -1,18 +1,17 @@ """ -This examples demonstrates how to use Poppy to fit a flow to a simple Gaussian +This examples demonstrates how to use aspire to fit a flow to a simple Gaussian likelihood with a uniform prior. """ import math from pathlib import Path +from aspire import Aspire +from aspire.plot import plot_comparison +from aspire.samples import Samples +from aspire.utils import AspireFile, configure_logger from scipy.stats import norm, uniform -from poppy import Poppy -from poppy.plot import plot_comparison -from poppy.samples import Samples -from poppy.utils import PoppyFile, configure_logger - # Configure the logger configure_logger("INFO") @@ -44,8 +43,8 @@ def log_prior(samples: Samples): parameters = [f"x_{i}" for i in range(dims)] prior_bounds = {p: [-10, 10] for p in parameters} -# Define the poppy object -poppy = Poppy( +# Define the aspire object +aspire = Aspire( log_likelihood=log_likelihood, log_prior=log_prior, dims=dims, @@ -54,7 +53,7 @@ def log_prior(samples: Samples): ) # Fit the flow to the initial samples -history = poppy.fit( +history = aspire.fit( initial_samples, n_epochs=50, ) @@ -63,13 +62,13 @@ def log_prior(samples: Samples): fig.savefig(outdir / "loss.png") # Produce samples from the posterior -samples = poppy.sample_posterior(5000) +samples = aspire.sample_posterior(5000) # Save the the results to a file -# The PoppyFile is a small wrapper around h5py.File that automatically +# The AspireFile is a small wrapper around h5py.File that automatically # includes additional metadata -with PoppyFile(outdir / "poppy_result.h5", "w") as f: - poppy.save_config(f, "poppy_config") +with AspireFile(outdir / "aspire_result.h5", "w") as f: + aspire.save_config(f, "aspire_config") samples.save(f, "posterior_samples") history.save(f, "flow_history") diff --git a/pyproject.toml b/pyproject.toml index d6c63ed..2934c1a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,11 +3,11 @@ requires = ["setuptools>=45", "setuptools-scm[toml]>=6.2"] build-backend = "setuptools.build_meta" [project] -name = "poppy-inference" +name = "aspire-inference" authors = [ {name = "Michael J. Williams", email = "michaeljw1@googlemail.com"}, ] -description = "Bayesian Posterior Post-processing in Python" +description = "Accelerate Sequential Posterior Inference via REuse" readme = "README.md" requires-python = ">=3.10" license = {text = "MIT"} @@ -49,12 +49,12 @@ test = [ ] [project.urls] -Homepage = "https://github.com/mj-will/poppy" +Homepage = "https://github.com/mj-will/aspire" [tool.setuptools_scm] [tool.setuptools.package-dir] -poppy = "src/poppy" +aspire = "src/aspire" [tool.ruff] line-length = 79 diff --git a/src/poppy/__init__.py b/src/aspire/__init__.py similarity index 61% rename from src/poppy/__init__.py rename to src/aspire/__init__.py index 56e53f5..fd67f10 100644 --- a/src/poppy/__init__.py +++ b/src/aspire/__init__.py @@ -1,19 +1,19 @@ """ -bayesian-poppy: Bayesian posterior post-processing in python +aspire: Accelerated Sequential Posterior Inference via REuse """ import logging from importlib.metadata import PackageNotFoundError, version -from .poppy import Poppy +from .aspire import Aspire try: - __version__ = version("bayesian-poppy") + __version__ = version("aspire") except PackageNotFoundError: __version__ = "unknown" logging.getLogger(__name__).addHandler(logging.NullHandler()) __all__ = [ - "Poppy", + "Aspire", ] diff --git a/src/poppy/poppy.py b/src/aspire/aspire.py similarity index 98% rename from src/poppy/poppy.py rename to src/aspire/aspire.py index 80b8c29..983f844 100644 --- a/src/poppy/poppy.py +++ b/src/aspire/aspire.py @@ -18,8 +18,8 @@ logger = logging.getLogger(__name__) -class Poppy: - """Posterior post-processing. +class Aspire: + """Accelerated Sequential Posterior Inference via REuse (aspire). Parameters ---------- @@ -294,8 +294,8 @@ def sample_posterior( .. code-block:: python - poppy = Poppy(...) - poppy.sample_posterior( + aspire = aspire(...) + aspire.sample_posterior( n_samples=1000, sampler="minipcn_smc", adaptive=True, @@ -385,7 +385,7 @@ def enable_pool(self, pool: mp.Pool, **kwargs): def config_dict( self, include_sampler_config: bool = True, **kwargs ) -> dict: - """Return a dictionary with the configuration of the Poppy object. + """Return a dictionary with the configuration of the aspire object. Parameters ---------- @@ -417,7 +417,7 @@ def config_dict( return config def save_config( - self, h5_file: h5py.File, path="poppy_config", **kwargs + self, h5_file: h5py.File, path="aspire_config", **kwargs ) -> None: """Save the configuration to an HDF5 file. diff --git a/src/poppy/flows/__init__.py b/src/aspire/flows/__init__.py similarity index 92% rename from src/poppy/flows/__init__.py rename to src/aspire/flows/__init__.py index 2909d63..67c4260 100644 --- a/src/poppy/flows/__init__.py +++ b/src/aspire/flows/__init__.py @@ -23,7 +23,8 @@ def get_flow_wrapper(backend: str = "zuko", flow_matching: bool = False): from importlib.metadata import entry_points eps = { - ep.name.lower(): ep for ep in entry_points().get("poppy.flows", []) + ep.name.lower(): ep + for ep in entry_points().get("aspire.flows", []) } if backend in eps: FlowClass = eps[backend].load() diff --git a/src/poppy/flows/base.py b/src/aspire/flows/base.py similarity index 100% rename from src/poppy/flows/base.py rename to src/aspire/flows/base.py diff --git a/src/poppy/flows/jax/__init__.py b/src/aspire/flows/jax/__init__.py similarity index 100% rename from src/poppy/flows/jax/__init__.py rename to src/aspire/flows/jax/__init__.py diff --git a/src/poppy/flows/jax/flows.py b/src/aspire/flows/jax/flows.py similarity index 100% rename from src/poppy/flows/jax/flows.py rename to src/aspire/flows/jax/flows.py diff --git a/src/poppy/flows/jax/utils.py b/src/aspire/flows/jax/utils.py similarity index 100% rename from src/poppy/flows/jax/utils.py rename to src/aspire/flows/jax/utils.py diff --git a/src/poppy/flows/torch/__init__.py b/src/aspire/flows/torch/__init__.py similarity index 100% rename from src/poppy/flows/torch/__init__.py rename to src/aspire/flows/torch/__init__.py diff --git a/src/poppy/flows/torch/flows.py b/src/aspire/flows/torch/flows.py similarity index 100% rename from src/poppy/flows/torch/flows.py rename to src/aspire/flows/torch/flows.py diff --git a/src/poppy/history.py b/src/aspire/history.py similarity index 100% rename from src/poppy/history.py rename to src/aspire/history.py diff --git a/src/poppy/plot.py b/src/aspire/plot.py similarity index 100% rename from src/poppy/plot.py rename to src/aspire/plot.py diff --git a/src/poppy/samplers/__init__.py b/src/aspire/samplers/__init__.py similarity index 100% rename from src/poppy/samplers/__init__.py rename to src/aspire/samplers/__init__.py diff --git a/src/poppy/samplers/base.py b/src/aspire/samplers/base.py similarity index 100% rename from src/poppy/samplers/base.py rename to src/aspire/samplers/base.py diff --git a/src/poppy/samplers/importance.py b/src/aspire/samplers/importance.py similarity index 100% rename from src/poppy/samplers/importance.py rename to src/aspire/samplers/importance.py diff --git a/src/poppy/samplers/mcmc.py b/src/aspire/samplers/mcmc.py similarity index 100% rename from src/poppy/samplers/mcmc.py rename to src/aspire/samplers/mcmc.py diff --git a/src/poppy/samplers/smc/__init__.py b/src/aspire/samplers/smc/__init__.py similarity index 100% rename from src/poppy/samplers/smc/__init__.py rename to src/aspire/samplers/smc/__init__.py diff --git a/src/poppy/samplers/smc/base.py b/src/aspire/samplers/smc/base.py similarity index 100% rename from src/poppy/samplers/smc/base.py rename to src/aspire/samplers/smc/base.py diff --git a/src/poppy/samplers/smc/blackjax.py b/src/aspire/samplers/smc/blackjax.py similarity index 100% rename from src/poppy/samplers/smc/blackjax.py rename to src/aspire/samplers/smc/blackjax.py diff --git a/src/poppy/samplers/smc/emcee.py b/src/aspire/samplers/smc/emcee.py similarity index 100% rename from src/poppy/samplers/smc/emcee.py rename to src/aspire/samplers/smc/emcee.py diff --git a/src/poppy/samplers/smc/minipcn.py b/src/aspire/samplers/smc/minipcn.py similarity index 100% rename from src/poppy/samplers/smc/minipcn.py rename to src/aspire/samplers/smc/minipcn.py diff --git a/src/poppy/samples.py b/src/aspire/samples.py similarity index 100% rename from src/poppy/samples.py rename to src/aspire/samples.py diff --git a/src/poppy/transforms.py b/src/aspire/transforms.py similarity index 100% rename from src/poppy/transforms.py rename to src/aspire/transforms.py diff --git a/src/poppy/utils.py b/src/aspire/utils.py similarity index 88% rename from src/poppy/utils.py rename to src/aspire/utils.py index 0c8af94..fa2f20d 100644 --- a/src/poppy/utils.py +++ b/src/aspire/utils.py @@ -23,7 +23,7 @@ from array_api_compat.common._typing import Array - from .poppy import Poppy + from .aspire import Aspire logger = logging.getLogger(__name__) @@ -31,7 +31,7 @@ def configure_logger( log_level: str | int = "INFO", additional_loggers: list[str] = None, - include_poppy_loggers: bool = True, + include_aspire_loggers: bool = True, ) -> logging.Logger: """Configure the logger. @@ -43,8 +43,8 @@ def configure_logger( The log level to use. Defaults to "INFO". additional_loggers : list of str, optional Additional loggers to configure. Defaults to None. - include_poppy_loggers : bool, optional - Whether to include all loggers that start with "poppy_" or "poppy-". + include_aspire_loggers : bool, optional + Whether to include all loggers that start with "aspire_" or "aspire-". Defaults to True. Returns @@ -52,20 +52,20 @@ def configure_logger( logging.Logger The configured logger. """ - logger = logging.getLogger("poppy") + logger = logging.getLogger("aspire") logger.setLevel(log_level) ch = logging.StreamHandler() ch.setLevel(log_level) formatter = logging.Formatter( - "%(asctime)s - poppy - %(levelname)s - %(message)s" + "%(asctime)s - aspire - %(levelname)s - %(message)s" ) ch.setFormatter(formatter) logger.addHandler(ch) additional_loggers = additional_loggers or [] for name in logger.manager.loggerDict: - if include_poppy_loggers and ( - name.startswith("poppy_") or name.startswith("poppy-") + if include_aspire_loggers and ( + name.startswith("aspire_") or name.startswith("aspire-") ): additional_loggers.append(name) @@ -82,13 +82,13 @@ def configure_logger( class PoolHandler: """Context manager to temporarily replace the log_likelihood method of a - Poppy instance with a version that uses a multiprocessing pool to + aspire instance with a version that uses a multiprocessing pool to parallelize computation. Parameters ---------- - poppy_instance : Poppy - The Poppy instance to modify. The log_likelihood method of this + aspire_instance : aspire + The aspire instance to modify. The log_likelihood method of this instance must accept a :code:`map_fn` keyword argument. pool : multiprocessing.Pool The pool to use for parallel computation. @@ -97,60 +97,60 @@ class PoolHandler: Defaults to True. parallelize_prior : bool, optional Whether to parallelize the log_prior method as well. Defaults to False. - If True, the log_prior method of the Poppy instance must also + If True, the log_prior method of the aspire instance must also accept a :code:`map_fn` keyword argument. """ def __init__( self, - poppy_instance: Poppy, + aspire_instance: Aspire, pool: Pool, close_pool: bool = True, parallelize_prior: bool = False, ): self.parallelize_prior = parallelize_prior - self.poppy_instance = poppy_instance + self.aspire_instance = aspire_instance self.pool = pool self.close_pool = close_pool @property - def poppy_instance(self): - return self._poppy_instance + def aspire_instance(self): + return self._aspire_instance - @poppy_instance.setter - def poppy_instance(self, value: Poppy): + @aspire_instance.setter + def aspire_instance(self, value: Aspire): signature = inspect.signature(value.log_likelihood) if "map_fn" not in signature.parameters: raise ValueError( - "The log_likelihood method of the Poppy instance must accept a" + "The log_likelihood method of the Aspire instance must accept a" " 'map_fn' keyword argument." ) signature = inspect.signature(value.log_prior) if "map_fn" not in signature.parameters and self.parallelize_prior: raise ValueError( - "The log_prior method of the Poppy instance must accept a" + "The log_prior method of the Aspire instance must accept a" " 'map_fn' keyword argument if parallelize_prior is True." ) - self._poppy_instance = value + self._aspire_instance = value def __enter__(self): - self.original_log_likelihood = self.poppy_instance.log_likelihood - self.original_log_prior = self.poppy_instance.log_prior + self.original_log_likelihood = self.aspire_instance.log_likelihood + self.original_log_prior = self.aspire_instance.log_prior if self.pool is not None: logger.debug("Updating map function in log-likelihood method") - self.poppy_instance.log_likelihood = partial( + self.aspire_instance.log_likelihood = partial( self.original_log_likelihood, map_fn=self.pool.map ) if self.parallelize_prior: logger.debug("Updating map function in log-prior method") - self.poppy_instance.log_prior = partial( + self.aspire_instance.log_prior = partial( self.original_log_prior, map_fn=self.pool.map ) return self.pool def __exit__(self, exc_type, exc_value, traceback): - self.poppy_instance.log_likelihood = self.original_log_likelihood - self.poppy_instance.log_prior = self.original_log_prior + self.aspire_instance.log_likelihood = self.original_log_likelihood + self.aspire_instance.log_prior = self.original_log_prior if self.close_pool: logger.debug("Closing pool") self.pool.close() @@ -384,17 +384,17 @@ def get_package_version(package_name: str) -> str: return "not installed" -class PoppyFile(h5py.File): +class AspireFile(h5py.File): """A subclass of h5py.File that adds metadata to the file.""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self._set_poppy_metadata() + self._set_aspire_metadata() - def _set_poppy_metadata(self): - from . import __version__ as poppy_version + def _set_aspire_metadata(self): + from . import __version__ as aspire_version - self.attrs["poppy_version"] = poppy_version + self.attrs["aspire_version"] = aspire_version def update_at_indices(x: Array, slc: Array, y: Array) -> Array: diff --git a/tests/integration_tests/conftest.py b/tests/integration_tests/conftest.py index dae349a..ae17db3 100644 --- a/tests/integration_tests/conftest.py +++ b/tests/integration_tests/conftest.py @@ -2,8 +2,7 @@ from collections import namedtuple import pytest - -from poppy.samples import Samples +from aspire.samples import Samples SamplerConfig = namedtuple( "SamplerConfig", diff --git a/tests/integration_tests/test_integration.py b/tests/integration_tests/test_integration.py index 93cfb1d..65ce293 100644 --- a/tests/integration_tests/test_integration.py +++ b/tests/integration_tests/test_integration.py @@ -1,6 +1,5 @@ import pytest - -from poppy import Poppy +from aspire import Aspire def test_integration_zuko( @@ -16,7 +15,7 @@ def test_integration_zuko( if sampler_config.sampler == "blackjax_smc": pytest.xfail(reason="BlackJAX requires JAX arrays.") - poppy = Poppy( + aspire = Aspire( log_likelihood=log_likelihood, log_prior=log_prior, dims=dims, @@ -26,8 +25,8 @@ def test_integration_zuko( bounded_to_unbounded=bounded_to_unbounded, flow_backend="zuko", ) - poppy.fit(samples, n_epochs=5) - poppy.sample_posterior( + aspire.fit(samples, n_epochs=5) + aspire.sample_posterior( n_samples=100, sampler=sampler_config.sampler, **sampler_config.sampler_kwargs, @@ -51,7 +50,7 @@ def test_integration_flowjax( if sampler_config.sampler == "blackjax_smc" and samples_backend != "jax": pytest.xfail(reason="BlackJAX requires JAX arrays.") - poppy = Poppy( + aspire = Aspire( log_likelihood=log_likelihood, log_prior=log_prior, dims=dims, @@ -62,8 +61,8 @@ def test_integration_flowjax( flow_backend="flowjax", key=jax.random.key(0), ) - poppy.fit(samples, max_epochs=5) - poppy.sample_posterior( + aspire.fit(samples, max_epochs=5) + aspire.sample_posterior( n_samples=100, sampler=sampler_config.sampler, **sampler_config.sampler_kwargs, diff --git a/tests/test_flows/test_jax_flows/test_flowjax_flows.py b/tests/test_flows/test_jax_flows/test_flowjax_flows.py index 9c6f280..87bf0a2 100644 --- a/tests/test_flows/test_jax_flows/test_flowjax_flows.py +++ b/tests/test_flows/test_jax_flows/test_flowjax_flows.py @@ -1,8 +1,7 @@ import jax import jax.numpy as jnp - -from poppy.flows.jax.flows import FlowJax -from poppy.transforms import FlowTransform +from aspire.flows.jax.flows import FlowJax +from aspire.transforms import FlowTransform def test_zuko_flow(): diff --git a/tests/test_flows/test_torch_flows/test_zuko_flows.py b/tests/test_flows/test_torch_flows/test_zuko_flows.py index 38525b9..83037ae 100644 --- a/tests/test_flows/test_torch_flows/test_zuko_flows.py +++ b/tests/test_flows/test_torch_flows/test_zuko_flows.py @@ -1,7 +1,6 @@ import torch - -from poppy.flows.torch.flows import ZukoFlow -from poppy.transforms import FlowTransform +from aspire.flows.torch.flows import ZukoFlow +from aspire.transforms import FlowTransform def test_zuko_flow():