homodyne.optimization.cmc.reparameterization

The reparameterization module transforms correlated physics parameters into an orthogonal sampling space for MCMC, then converts back to physics parameters for output. This improves NUTS sampling efficiency by reducing posterior correlations between parameters that span different scales (e.g., D₀ ~ 10⁴ and γ̇₀ ~ 10⁻³).

Note

Reparameterized values are computed after the time grid is constructed, since t_ref = sqrt(dt × t_max) depends on the data. core.py calls compute_t_ref() and falls back to t_ref=1.0 if inputs are invalid.


ReparamConfig

Configuration dataclass controlling which parameters are reparameterized.

class homodyne.optimization.cmc.reparameterization.ReparamConfig[source]

Bases: object

Configuration for internal reparameterization.

enable_d_ref

Enable D_ref reparameterization (D0, alpha → log_D_ref, alpha).

Type:

bool

enable_gamma_ref

Sample log(gamma_ref) where gamma_ref = gamma_dot_t0 * t_ref^beta.

Type:

bool

t_ref

Reference time for reparameterization (geometric mean of time range).

Type:

float

enable_d_ref: bool = True
enable_gamma_ref: bool = True
t_ref: float = 1.0
property enable_d_total: bool

Backward-compatible alias for enable_d_ref.

property enable_log_gamma: bool

Backward-compatible alias for enable_gamma_ref.

__init__(enable_d_ref=True, enable_gamma_ref=True, t_ref=1.0)

Parameter Transformations

The following transforms are applied when reparameterization is enabled:

Physics Parameter

Sampling Parameter

Transform

D₀ (diffusion)

log_D_ref

log(D₀ × t_ref^α)

D_offset

D_offset_ratio

D_offset / D_ref ∈ (−1+ε, ∞); supports negative D_offset

γ̇₀ (shear rate)

log_gamma_ref

log(γ̇₀ × t_ref)

The prior on D_offset_ratio is TruncatedNormal(low=-1+ε). The lower bound enforces D_ref + D_offset > 0 at t_ref (non-negative total diffusion coefficient at the reference time). Negative values of D_offset_ratio in the range (-1, 0) correspond to jammed/arrested systems where D_offset < 0 physically reduces diffusion.

The back-transform is exact: D_offset = D_ref × D_offset_ratio.


compute_t_ref

homodyne.optimization.cmc.reparameterization.compute_t_ref(dt, t_max, *, fallback_value=None)[source]

Compute reference time as geometric mean of time range.

Parameters:
  • dt (float) – Time step (minimum time scale).

  • t_max (float) – Maximum time in the dataset.

  • fallback_value (float | None) – If provided and inputs are invalid, return this value with a warning instead of raising ValueError. If None (default), raises on invalid inputs.

Returns:

Reference time t_ref = sqrt(dt * t_max), or fallback_value if inputs invalid.

Return type:

float

Raises:

ValueError – If dt or t_max are non-positive or non-finite and fallback_value is None.


transform_nlsq_to_reparam_space

homodyne.optimization.cmc.reparameterization.transform_nlsq_to_reparam_space(nlsq_values, nlsq_uncertainties, t_ref)[source]

Transform NLSQ estimates to reference-time reparameterized space.

Computes D_ref, log_D_ref, gamma_ref, log_gamma_ref from NLSQ physics parameters, with delta-method uncertainty propagation.

Parameters:
  • nlsq_values (dict[str, float]) – NLSQ parameter estimates (D0, alpha, D_offset, gamma_dot_t0, beta, …).

  • nlsq_uncertainties (dict[str, float] | None) – NLSQ standard errors for each parameter.

  • t_ref (float) – Reference time for reparameterization.

Returns:

(reparam_values, reparam_uncertainties) in the reparameterized space. Keys: “log_D_ref”, “D_offset_ratio”, “log_gamma_ref” (when available).

Return type:

tuple[dict[str, float], dict[str, float]]


transform_to_sampling_space

homodyne.optimization.cmc.reparameterization.transform_to_sampling_space(params, config)[source]

Transform physics params → sampling params.

Parameters:
  • params (dict[str, float]) – Physics parameters (D0, D_offset, gamma_dot_t0, etc.).

  • config (ReparamConfig) – Reparameterization configuration.

Returns:

Transformed parameters for sampling.

Return type:

dict[str, float]


transform_to_physics_space

homodyne.optimization.cmc.reparameterization.transform_to_physics_space(samples, config)[source]

Transform sampling params → physics params (vectorized).

Parameters:
  • samples (dict[str, ndarray]) – Sampled parameters from MCMC.

  • config (ReparamConfig) – Reparameterization configuration.

Returns:

Physics parameters.

Return type:

dict[str, ndarray]


Usage Examples

NLSQ warm-start to reparameterized priors

from homodyne.optimization.cmc.reparameterization import (
    compute_t_ref,
    transform_nlsq_to_reparam_space,
    ReparamConfig,
)

# From data: dt=0.001s, t_max=0.1s
t_ref = compute_t_ref(dt=0.001, t_max=0.1)  # sqrt(0.001 * 0.1) ≈ 0.01

nlsq_values = {"D0": 19231.0, "alpha": 1.5, "D_offset": 100.0,
                "gamma_dot_t0": 0.003, "beta": 0.8}
nlsq_uncert = {"D0": 500.0, "alpha": 0.1, "D_offset": 20.0,
                "gamma_dot_t0": 0.001, "beta": 0.05}

reparam_vals, reparam_unc = transform_nlsq_to_reparam_space(
    nlsq_values, nlsq_uncert, t_ref
)
# reparam_vals contains: log_D_ref, D_offset_ratio, log_gamma_ref, alpha, beta

Converting MCMC samples back to physics

from homodyne.optimization.cmc.reparameterization import (
    transform_to_physics_space,
    ReparamConfig,
)
import numpy as np

config = ReparamConfig(enable_d_ref=True, enable_gamma_ref=True, t_ref=0.01)

# Batched MCMC samples (e.g., from 4 chains × 1000 samples)
samples = {
    "log_D_ref": np.random.normal(-2.0, 0.1, size=4000),
    "alpha": np.random.normal(1.5, 0.05, size=4000),
    "D_offset_ratio": np.random.normal(0.05, 0.1, size=4000),  # D_offset / D_ref
    "log_gamma_ref": np.random.normal(-5.5, 0.2, size=4000),
    "beta": np.random.normal(0.8, 0.03, size=4000),
}

physics = transform_to_physics_space(samples, config)
# physics contains: D0, alpha, D_offset, gamma_dot_t0, beta

Internal reparameterization for CMC sampling.

Transforms correlated parameters to orthogonal sampling space, then converts back to physics parameters for output.

Reparameterizations (v2.23.0, reference-time): - D0, D_offset → log_D_ref, D_offset_ratio (decorrelates D0/alpha via observable) - gamma_dot_t0 → log_gamma_ref (decorrelates gamma_dot_t0/beta via observable)

Theory:

For f(t) = A × t^α, the value at a reference time f_ref = A × t_ref^α is well-constrained by data. Sampling (f_ref, α) instead of (A, α) decorrelates them because f_ref relates to observables while α controls the shape.

t_ref = √(dt × t_max) is the geometric mean of the time range.

D_offset reparameterization (v2.23.0):

D_offset_ratio = D_offset / D_ref is a simple linear map that handles negative D_offset (jammed/arrested systems) without singularity. The old D_offset_frac = D_offset / (D_ref + D_offset) had a pole at D_offset = -D_ref and was restricted to [0, 0.5], silently clipping negative NLSQ warm-starts. D_offset_ratio uses a Normal prior (unbounded).