بنقرة واحدة
develop-sampler
Guide for adding a new internal sampler (proposal strategy) to JNesty.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Guide for adding a new internal sampler (proposal strategy) to JNesty.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
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 bounding method to JNesty.
JNesty usage guide — public API, parameters, results access, FITS I/O, bounding methods, tuning, and plotting.
| name | /develop-sampler |
| description | Guide for adding a new internal sampler (proposal strategy) to JNesty. |
Internal samplers live in src/jnesty/internal_samplers.py. Each implements the InternalSampler interface and is registered in SAMPLER_REGISTRY for lookup by string name.
The core NS loop in src/jnesty/sampler.py calls sampler_obj.sample() to propose replacement live points and sampler_obj.tune() to adapt the proposal scale.
There is also a standalone vmap_queue_refill() function for Dynesty-style queue mode that generates multiple candidates in parallel outside of any sampler object.
class InternalSampler:
"""Base class for proposal samplers."""
def __init__(self, ndim, **kwargs):
self.ndim = ndim
def sample(self, key, x_starts, logL_constraint, loglikelihood_fn,
axes, scale, n_steps, prior_bounds=None, walk_schedule=None):
"""
Generate a replacement point.
Parameters
----------
key : jax.random.PRNGKey
x_starts : array
If batch_size=1: (ndim,) single starting point.
If batch_size>1: (batch_size, ndim) diverse starting points.
logL_constraint : float, minimum log-likelihood
loglikelihood_fn : callable, log-likelihood
axes : array
If batch_size=1: (ncdim, ncdim) single axes matrix.
If batch_size>1: (batch_size, ncdim, ncdim) per-walk axes.
scale : float, current proposal scale
n_steps : int, number of walk/slice steps
prior_bounds : optional (2, ndim) array for rejection
walk_schedule : optional array, not used in current code (legacy)
Returns
-------
(x_new, logL_new, n_accepted, n_total) tuple
n_total includes boundary rejections (matches Dynesty semantics)
"""
raise NotImplementedError
def tune(self, scale, acceptance_rate, ndim, iteration):
"""Adapt scale based on acceptance rate. Returns new scale."""
raise NotImplementedError
Important: sample() returns a 4-tuple (x_new, logL_new, n_accepted, n_total), not a 3-tuple. The n_total counts all proposals including boundary rejections.
All code inside sample() must be JAX-compatible because it runs inside lax.while_loop:
jnp.where(), jax.lax.cond(), jax.lax.select()jax.debug.print() or io_callback for debugging onlylax.scan for loops, not Python forkey, subkey = random.split(key)jnp.where(in_bounds, loglikelihood_fn(x), -inf) for XLA fusion — lax.cond with data-dependent predicates inside lax.scan kills GPU kernel fusionThe existing RWalkSampler demonstrates the pattern:
_single_walk(key, x_start, logL_constraint, loglikelihood_fn, axes, scale, n_steps, ndim, n_cluster, prior_bounds, walk_schedule)
Core walk function using lax.scan over n_steps. Each step:
randsphere() transformed by axes matrix (clustered dims)(x_final, n_accepted, n_total)_propose_one(key, x, axes, scale, n_cluster, ndim, walk_schedule, step_idx)
Single proposal generation. First n_cluster dimensions perturbed via axes transform; remaining dims uniform from [0,1].
apply_reflect(u)
Iterative reflection into [0,1]. Matches Dynesty's apply_reflect.
vmap_queue_refill(refill_key, live_x, live_logL, loglstar, loglikelihood_fn, me_axes, me_logvol_ells, bound_axes, scale, rwalk_K, ndim, ncdim, queue_size, use_multi_ellipsoid, prior_bounds=None)
Generates queue_size candidates in parallel. Each gets full rwalk_K steps from a random starting point (live point above loglstar) with a random volume-weighted ellipsoid. Returns (queue_x, queue_logL, queue_nacc, queue_ntot).
When batch_size > 1, RWalkSampler.sample() runs batch_size independent walks in parallel via jax.vmap:
rwalk_K // batch_sizeRWalkSampler.tune() uses Robbins-Munro adaptation matching Dynesty:
proposed_scale = scale * jnp.exp(
(acceptance_rate - target_acceptance)
/ ncdim / target_acceptance
)
Uses ncdim (clustered dimensions) not full ndim, matching Dynesty.
Add your class to src/jnesty/internal_samplers.py:
class SliceSampler(InternalSampler):
def __init__(self, ndim, **kwargs):
super().__init__(ndim, **kwargs)
def sample(self, key, x_starts, logL_constraint, loglikelihood_fn,
axes, scale, n_steps, prior_bounds=None, walk_schedule=None):
# Your sampling logic
# Must return (x_new, logL_new, n_accepted, n_total)
pass
def tune(self, scale, acceptance_rate, ndim, iteration):
# Your scale adaptation (or return scale unchanged)
return scale
Add to the SAMPLER_REGISTRY dict at the bottom of the file:
SAMPLER_REGISTRY = {
'rwalk': RWalkSampler,
'slice': SliceSampler, # Add this
}
In src/jnesty/sampler.py, the sampler is currently hardcoded:
sampler_obj = get_sampler('rwalk', ndim, ...) # line ~400
To make it configurable, add a sampler field to WhileLoopNSConfig and pass it through.
In src/jnesty/jnesty.py, add a sampler parameter to NestedSampler.__init__:
def __init__(self, ..., sampler='rwalk', ...):
If the sampler should work with queue mode, you may need a queue-refill function similar to vmap_queue_refill(). This function generates queue_size candidates in parallel, each using the full rwalk_K steps independently.
python -m py_compile src/jnesty/internal_samplers.pyInternalSamplersample() returns (x_new, logL_new, n_accepted, n_total) — 4-tuplesample() is JAX-compatible (no Python control flow in hot path)sample() handles both single and batch modes (x_starts shape varies)tune() returns a valid scale (or passes through unchanged)SAMPLER_REGISTRYWhileLoopNSConfig, NestedSampler)