Skip to content

Centralize the θ↔u scale transform: ~12 algorithm sites inline base-10 (np.log10/10**/exp10) instead of routing through Scale (ADR-0010 drift) #412

@wshlavacek

Description

@wshlavacek

Problem

scale.py / ADR-0010 claim the log10/10** boundary "lives in exactly one place" and is "not smeared across FreeParameter.add / _reflect / prior_logpdf / sample_value." That holds inside FreeParameter — but the algorithm layer bypasses the Scale object and inlines the transform directly as np.log10(x) if v.log_space else x / 10 ** u if v.log_space else u / exp10(...) at ~12 sites. So the θ↔u boundary is in fact replicated, not centralized — exactly the drift/bug surface ADR-0003 warns against, and the concrete blocker that made the recent LogBase(n) (second log base) question untenable: a base change would have to be chased through every one of these.

This is pure tech debt, and it compoundscmaes/powell already copied the if v.log_space idiom when they were added.

Inventory (behavior-preserving refactor target)

  • algorithms/base.py:237_param_vec (the PSet→u bridge), forward transform
  • algorithms/base.py:1232exp10, the base-10 inverse helper
  • algorithms/optimizers/local_base.py:66,89,103 — start point / box widths / u→θ
  • algorithms/optimizers/powell.py:108,109 — box bounds in u
  • algorithms/optimizers/simplex.py:137,316,357,374,399,400,424,442 — start point + the centroid / reflection / contraction arithmetic in log space (the densest cluster)
  • algorithms/optimizers/particle_swarm.py:232 — velocity update in log space
  • algorithms/samplers/adaptive_mcmc.py:462,473,517 — pset→log10 (chain state + index-file inputs)
  • algorithms/samplers/base.py:358 — histogram data in log10
  • algorithms/samplers/dream.py:132 — u→θ

Direction (for an ADR / design note)

  • FreeParameter already owns _scale.forward/_scale.inverse (used by add / set_value / value_from_quantile / _reflect). Expose a public transform (e.g. to_sampling_space(θ) / from_sampling_space(u)) so the algorithms ask the parameter instead of inlining np.log10/10**.
  • _param_vec is already the single PSet→u forward chokepoint; add the inverse peer (_pset_from_u, today replicated in local_base / dream / simplex) so the u-vector↔PSet conversion lives in one place too.
  • The simplex internal arithmetic (centroid / reflection / contraction in u) should build u-vectors via the chokepoint and map back, rather than inlining per-operation log10.
  • Contract: behavior-preserving / byte-green against the existing optimizer + sampler tests (mirrors the M2.3 Prior and M2.4 NoiseModel extractions). No new scale behavior — this is the cleanup that makes ADR-0010's "one place" claim actually true.

Why it matters

  • Removes the replicated-transform drift/bug surface (ADR-0003).
  • Makes the Scale object the real single source of truth (ADR-0010's stated intent).
  • Is the genuine prerequisite for any future scale change (a second log base, an alternate parameterization) — the refactor the LogBase(n) discussion identified as the actual gating work.

Relevant ADRs: 0003 (prior/proposal share one scale), 0010 (scale lives in one place — the intent this restores).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions