with one click
develop-bound
Guide for adding a new bounding method to JNesty.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Guide for adding a new bounding method to JNesty.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
JNesty code architecture — modules, data flow, key data structures, JAX patterns, and demo scripts.
Diagnosing convergence problems, poor acceptance rates, and incorrect results in JNesty.
Guide for adding a new internal sampler (proposal strategy) to JNesty.
JNesty usage guide — public API, parameters, results access, FITS I/O, bounding methods, tuning, and plotting.
| name | /develop-bound |
| description | Guide for adding a new bounding method to JNesty. |
Bounding methods live in src/jnesty/bounding.py. Each implements the Bound interface and is registered in BOUND_REGISTRY for lookup by string name.
The core NS loop in src/jnesty/sampler.py calls bound_obj.fit() to update the bound, bound_obj.get_axes() for proposal generation, and optionally uses bound-specific state for multi-ellipsoid proposals.
class Bound:
"""Base class for bounding distributions."""
def __init__(self, ndim, **kwargs):
self.ndim = ndim
def fit(self, points):
"""Fit the bound to live points. Returns self."""
raise NotImplementedError
def sample(self, key, n=1):
"""Sample point(s) from the bound."""
raise NotImplementedError
def get_axes(self):
"""Return (ndim, ndim) axes matrix for proposal generation."""
raise NotImplementedError
def contains(self, point):
"""Check if point is inside the bound."""
raise NotImplementedError
'none')fit(): no-opget_axes(): identity matrixsample(): uniform from [0,1]^ndim'single')fit(): covariance eigenvalue decompositionget_axes(): eigenvectors scaled by sqrt(eigenvalues)'multi')fit(): delegates to fit_multi_ellipsoid() from multi_ellipsoid.pyMultiEllipsoidState NamedTupleget_axes(): axes of the largest-volume ellipsoidget_walk_schedule(rwalk_K): Bresenham interleaving of ellipsoid indicesqueue_size=8) by defaultThe bound is used in several places in src/jnesty/sampler.py:
bound_obj.fit(live_x) after Phase 1 completesbound_axes = bound_obj.get_axes() for rwalk proposalsestimate_batch_size_from_memory() uses bound_axes for probefit_multi_ellipsoid(live_x_cur, ...) between chunksFor multi-ellipsoid, the chunked loop mode is activated when use_chunked_loop = True (bound is 'multi' and bound_update_interval > 0). The loop runs chunks of bound_update_interval likelihood calls, then refits the bound between chunks.
The bound state is packed into the flat tuple that lax.while_loop carries:
bound_axes — (ndim, ndim) axes matrixme_axes — (max_ellipsoids, ndim, ndim) multi-ellipsoid axesme_logvol_ells — (max_ellipsoids,) multi-ellipsoid log-volumescalls_at_update — total_calls at last bound update (for chunk timing)total_calls — total likelihood calls (non-resetting)Queue mode adds indices 18-22 for the candidate queue.
A new bound that needs additional state in the loop must extend this tuple and update the packing/unpacking in sampler.py.
At bound updates (chunk boundaries), hist_accept (index 11) and hist_total (index 12) are reset to 0. This matches Dynesty's behavior: scale adapts quickly to the new bound shape.
Add your class to src/jnesty/bounding.py:
class MyBound(Bound):
def __init__(self, ndim, **kwargs):
super().__init__(ndim, **kwargs)
# Your initialization
def fit(self, points):
# Fit to live points
return self
def sample(self, key, n=1):
# Sample from the bound
pass
def get_axes(self):
# Return (ndim, ndim) axes for proposals
pass
def contains(self, point):
# Check membership
pass
Add to BOUND_REGISTRY:
BOUND_REGISTRY = {
'none': UnitCube,
'single': SingleEllipsoid,
'multi': MultiEllipsoidBound,
'mybound': MyBound, # Add this
}
If your bound needs periodic refitting or custom state carried through lax.while_loop:
sampler.pyuse_chunked_loop branch similar to multi-ellipsoidbody_fn_q) if queue support is neededIf your bound is stateless or only needs initial fitting, no changes to sampler.py are needed — the factory handles it.
python -m py_compile src/jnesty/bounding.pyBoundfit, sample, get_axes, containsBOUND_REGISTRYNestedSampler.__init__ accepts the new bound string