Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -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`.
25 changes: 12 additions & 13 deletions examples/basic_example.py
Original file line number Diff line number Diff line change
@@ -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")

Expand Down Expand Up @@ -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,
Expand All @@ -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,
)
Expand All @@ -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")

Expand Down
8 changes: 4 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "[email protected]"},
]
description = "Bayesian Posterior Post-processing in Python"
description = "Accelerate Sequential Posterior Inference via REuse"
readme = "README.md"
requires-python = ">=3.10"
license = {text = "MIT"}
Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions src/poppy/__init__.py → src/aspire/__init__.py
Original file line number Diff line number Diff line change
@@ -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",
]
12 changes: 6 additions & 6 deletions src/poppy/poppy.py → src/aspire/aspire.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
logger = logging.getLogger(__name__)


class Poppy:
"""Posterior post-processing.
class Aspire:
"""Accelerated Sequential Posterior Inference via REuse (aspire).

Parameters
----------
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
----------
Expand Down Expand Up @@ -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.

Expand Down
3 changes: 2 additions & 1 deletion src/poppy/flows/__init__.py → src/aspire/flows/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
64 changes: 32 additions & 32 deletions src/poppy/utils.py → src/aspire/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@

from array_api_compat.common._typing import Array

from .poppy import Poppy
from .aspire import Aspire

logger = logging.getLogger(__name__)


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.

Expand All @@ -43,29 +43,29 @@ 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
-------
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)

Expand All @@ -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.
Expand All @@ -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()
Expand Down Expand Up @@ -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:
Expand Down
3 changes: 1 addition & 2 deletions tests/integration_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
from collections import namedtuple

import pytest

from poppy.samples import Samples
from aspire.samples import Samples

SamplerConfig = namedtuple(
"SamplerConfig",
Expand Down
Loading