Fit and compare complex models reliably and rapidly with advanced nested sampling techniques for Bayesian inference.
The main nested sampling implementations in UltraNest for Bayesian parameter estimation and model comparison. These classes provide the primary interface for conducting nested sampling analysis.
Advanced nested sampler with reactive exploration that adapts to the problem structure. This is the recommended sampler for most applications as it automatically adjusts sampling parameters based on the likelihood landscape.
class ReactiveNestedSampler:
def __init__(
self,
param_names: list,
loglike: callable,
transform: callable = None,
derived_param_names: list = [],
wrapped_params: list = None,
resume: str = 'subfolder',
run_num: int = None,
log_dir: str = None,
num_test_samples: int = 2,
draw_multiple: bool = True,
num_bootstraps: int = 30,
vectorized: bool = False,
ndraw_min: int = 128,
ndraw_max: int = 65536,
storage_backend: str = 'hdf5',
warmstart_max_tau: float = -1
):
"""
Initialize a ReactiveNestedSampler.
Parameters:
- param_names (list): Names of parameters being sampled
- loglike (callable): Log-likelihood function accepting parameter array
- transform (callable, optional): Transform from unit cube [0,1]^n to parameter space
- derived_param_names (list): Names of derived parameters computed from main parameters
- wrapped_params (list, optional): Indices of circular/periodic parameters
- resume (str): Resume strategy ('resume', 'overwrite', 'subfolder', 'resume-similar')
- run_num (int, optional): Run number for organizing multiple runs
- log_dir (str, optional): Directory for output files
- num_test_samples (int): Number of test samples for validation
- draw_multiple (bool): Enable adaptive multiple point drawing
- num_bootstraps (int): Number of bootstrap rounds for error estimation
- vectorized (bool): Whether likelihood function accepts multiple points
- ndraw_min (int): Minimum number of points to draw per iteration
- ndraw_max (int): Maximum number of points to draw per iteration
- storage_backend (str): Storage backend ('hdf5', 'tsv', 'csv')
- warmstart_max_tau (float): Disorder tolerance for warm restarts
"""
def run(self):
"""
Execute the nested sampling run.
Returns:
dict: Complete results including evidence, posterior samples, and diagnostics
"""
def run_iter(self):
"""
Iterator interface for nested sampling execution.
Yields:
dict: Intermediate results at each iteration
"""
def print_results(self, use_unicode: bool = True):
"""
Print a summary of sampling results.
Parameters:
- use_unicode (bool): Use Unicode characters for formatting
"""
def plot(self):
"""Create diagnostic plots for the sampling run."""
def plot_corner(self):
"""Create corner plot of posterior distributions."""
def plot_trace(self):
"""Create trace plots showing parameter evolution."""
def plot_run(self):
"""Create run diagnostic plots."""
def store_tree(self):
"""Store the sampling tree for detailed analysis."""
@property
def results(self):
"""
dict: Dictionary containing final sampling results including:
- 'logz': Log evidence estimate
- 'logzerr': Log evidence uncertainty
- 'posterior': Posterior samples and statistics
- 'samples': Raw samples from nested sampling
- 'loglikelihood': Log-likelihood values
- 'information': Information content (H)
"""
@property
def stepsampler(self):
"""Current step sampler instance used for parameter space exploration."""import numpy as np
from ultranest import ReactiveNestedSampler
# Define parameters
param_names = ['amplitude', 'mean', 'sigma']
# Define log-likelihood (Gaussian model)
def loglike(theta):
amplitude, mean, sigma = theta
# Your likelihood calculation
model_prediction = amplitude * np.exp(-0.5 * ((x_data - mean) / sigma)**2)
chi2 = np.sum((y_data - model_prediction)**2 / yerr_data**2)
return -0.5 * chi2
# Define prior transform
def prior_transform(cube):
params = cube.copy()
params[0] = cube[0] * 10 # amplitude: 0 to 10
params[1] = cube[1] * 20 - 10 # mean: -10 to 10
params[2] = cube[2] * 5 # sigma: 0 to 5
return params
# Create and run sampler
sampler = ReactiveNestedSampler(
param_names=param_names,
loglike=loglike,
transform=prior_transform,
resume='subfolder'
)
result = sampler.run()Traditional nested sampler with fixed number of live points. Provides more direct control over sampling parameters but requires manual tuning for optimal performance.
class NestedSampler:
def __init__(
self,
param_names: list,
loglike: callable,
transform: callable = None,
derived_param_names: list = [],
resume: str = 'subfolder',
run_num: int = None,
log_dir: str = 'logs/test',
num_live_points: int = 1000,
vectorized: bool = False,
wrapped_params: list = []
):
"""
Initialize a traditional NestedSampler.
Parameters:
- param_names (list): Names of parameters being sampled
- loglike (callable): Log-likelihood function
- transform (callable, optional): Prior transform function
- derived_param_names (list): Names of derived parameters
- resume (str): Resume strategy
- run_num (int, optional): Run identifier
- log_dir (str): Output directory
- num_live_points (int): Fixed number of live points to maintain
- vectorized (bool): Whether likelihood accepts multiple points
- wrapped_params (list): Indices of circular parameters
"""
def run(self):
"""
Execute nested sampling with fixed live points.
Returns:
dict: Sampling results
"""
def print_results(self):
"""Print summary of results."""
def plot(self):
"""Generate diagnostic plots."""Access stored nested sampling results from previous runs.
def read_file(
log_dir: str,
x_dim: int,
num_bootstraps: int = 20,
random: bool = True,
verbose: bool = False,
check_insertion_order: bool = True
):
"""
Read UltraNest output files from a completed run.
Parameters:
- log_dir (str): Directory containing output files
- x_dim (int): Dimensionality of parameter space
- num_bootstraps (int): Number of bootstraps for estimating logZ
- random (bool): Use randomization for volume estimation
- verbose (bool): Show progress during reading
- check_insertion_order (bool): Perform MWW insertion order test for convergence assessment
Returns:
dict: Results dictionary with same structure as sampler.results
"""Resume sampling from similar previous runs to improve efficiency.
def warmstart_from_similar_file(**kwargs):
"""
Initialize sampling using similar previous run as starting point.
Returns:
Initialization data for faster convergence
"""For improved performance with expensive likelihood functions:
# Vectorized likelihood function
def vectorized_loglike(theta_array):
"""
Compute log-likelihood for multiple parameter sets.
Parameters:
- theta_array (array): Shape (n_points, n_params)
Returns:
array: Log-likelihood values, shape (n_points,)
"""
return np.array([loglike(theta) for theta in theta_array])
sampler = ReactiveNestedSampler(
param_names=param_names,
loglike=vectorized_loglike,
vectorized=True # Enable vectorized processing
)Compute additional quantities from main parameters:
def loglike_with_derived(theta):
x, y = theta
# Compute derived parameter
derived = x**2 + y**2
# Return likelihood and derived parameters
return -0.5 * (x**2 + y**2), np.array([derived])
sampler = ReactiveNestedSampler(
param_names=['x', 'y'],
loglike=loglike_with_derived,
derived_param_names=['radius_squared']
)Handle circular/periodic parameters (e.g., angles):
sampler = ReactiveNestedSampler(
param_names=['x', 'y', 'angle'],
loglike=loglike,
wrapped_params=[2] # Angle parameter is circular
)Install with Tessl CLI
npx tessl i tessl/pypi-ultranest