Skip to content

feat: symbolic superposition — learn the shift law that collapses a curve family - #25

Merged
jkitchin merged 2 commits into
mainfrom
claude/issue-14-b5dm9b
Aug 13, 2026
Merged

feat: symbolic superposition — learn the shift law that collapses a curve family#25
jkitchin merged 2 commits into
mainfrom
claude/issue-14-b5dm9b

Conversation

@jkitchin

Copy link
Copy Markdown
Owner

Closes #14.

Adds jaxsr.superposition, which discovers a symbolic transform collapsing a family of curves indexed by a condition (time–temperature superposition and its relatives), instead of returning a table of per-curve shift factors that cannot extrapolate to a condition never measured.

Built on all five supporting issues, now in main: #15 (SurfaceDerivatives), #16 (basis-identity keying), #17 (pipeline-level resampling), #18 (add_block), #19 (sample_weight).

Mechanism

The differential strategy from the issue. Fit one smoothed surface per channel, use

y_q = σ·s'(q)·y_x + v'(q)

to eliminate the unknown master curve entirely, sparse-regress s' and v' against structured Θ(q) ⊙ y_x | Θ(q) blocks, then integrate back analytically with the anchor s(c_ref) = 0.

Candidate families are arrhenius, wlf (denominator constant fitted by profile likelihood) and polynomial. Each term carries an exact antiderivative, so the recovered law is symbolic rather than a quadrature table — and a test numerically integrates every derivative term and checks it against its antiderivative.

The two findings are load-bearing, not documentation

The transform is identifiable; the equation is not. shift_expression_'s own docstring says it is not the headline result. The reported quantities are shift_factors() and effective_activation_energy(), which are stable across structural variants.

The quick-start output in the guide is a real run, deliberately kept because it is unflattering: on data generated from a pure Arrhenius law, with the Arrhenius basis available, the search picked the WLF term with c2 = 1.070 instead. Arrhenius is WLF at c2 = 1, so they are the same function and no information criterion can separate them. The transform is right to 0.02 decades; the named family is wrong.

Expression stability is anti-correlated with validity. So the verdict comes from leave-one-condition-out collapse against a noise floor measured from the raw data before any surface is fitted, graded supported / weakly_supported / not_supported. A test pair reproduces the separation:

held-out collapse
genuine superposition 1.0× the noise floor
thermorheologically complex control 7.9× the noise floor

A companion test asserts the control's in-sample collapse still looks respectable — that is the whole reason the module exists.

Each withheld condition also records the shift that would have aligned it best, so a bad collapse can be attributed either to the law extrapolating wrongly or to the curve not collapsing under any shift at all.

Using #19

The issue filed sample_weight as a dependency, so the module uses it. Rows are weighted by 1/σ² of the estimated target, since derivative standard errors blow up at the edges of the condition range — exactly where a shift law is most tempted to bend. Measured over six noise realizations at 3% noise:

weighting median shift error worst E_eff (true 55.9)
"none" 0.023 decades 0.038 52.9 ± 1.8 kJ/mol
"derivative_se" (default) 0.013 decades 0.023 54.1 ± 1.2 kJ/mol

That lands on the 54.2 ± 1.3 reported in the issue's Phase 0 study.

Conventions checked rather than assumed

  • Domain sign. It names the transform rather than changing it — the collapse is identical either way, so getting it wrong flips every shift factor and E_eff while the plots still look perfect. No guessing from data; there is a test asserting exactly this.
  • Kelvin. Non-positive values rejected; a column topping out below 150 warns. Reciprocal-condition families are refused outright for a non-temperature condition.
  • Dimensionless q, so design columns stay order-one instead of mixing T⁻² against polynomials.
  • The master-curve smoother is fitted separately from the derivative surface, so the discovery does not certify itself.

Scope note

Strategy 2 (direct collapse) is not implemented — the issue ranked it as worth doing only after strategy 1 establishes baselines. Its known bias is documented rather than hidden: over-smoothing in the condition direction flattens s' and biases E_eff a few percent low, which is visible in the table above.

Verification

  • Full suite 886 passed, 10 skipped (78 new tests)
  • Green on the NumPy backend (scripts/test_under_numpy.py, 28 s) — no new JAX API surface needed shim additions
  • black --check and ruff check clean
  • Both guides' worked examples executed verbatim; the guide's sample output is a real run
  • src/jaxsr/skill/ re-synced from .claude/skills/jaxsr/

Also adds docs/guides/superposition.md, the matching skill guide with a SKILL.md routing entry, an API reference page, and CHANGELOG/README entries.


Generated by Claude Code

jkitchin and others added 2 commits August 12, 2026 23:14
…urve family

Adds `jaxsr.superposition`, which discovers a *symbolic* transform collapsing a
family of curves indexed by a condition (time-temperature superposition and its
relatives), instead of returning a table of per-curve shift factors that cannot
extrapolate to a condition never measured.

Uses the differential strategy: fit one smoothed surface per channel, use
y_q = σ·s'(q)·y_x + v'(q) to eliminate the unknown master curve, sparse-regress
s' and v' against structured Θ(q) ⊙ y_x | Θ(q) blocks, then integrate back
analytically with the anchor s(c_ref) = 0. Candidate families are arrhenius, wlf
(denominator constant fitted by profile likelihood) and polynomial, each carrying
an exact antiderivative so the recovered law stays symbolic.

Two findings shape the API rather than being footnotes:

The transform is identifiable; the equation is not. Over a realistic condition
window 1/(1+q)^2, 1/(c2+q)^2 and low-order polynomials span nearly the same
function space, so `shift_expression_` is documented as *not* the headline. The
transform and `effective_activation_energy()` are, being stable across structural
variants.

Expression stability is anti-correlated with validity. A material with no valid
shift factor yields a confident, stable, reproducible law and a fine in-sample
collapse. So `validity_report_` grades supported / weakly_supported /
not_supported from leave-one-condition-out collapse against a measured noise
floor, and a test reproduces the separation (1.0x for a genuine superposition,
7.9x for a thermorheologically complex control).

Rows are weighted by the precision of the estimated target (built on the
`sample_weight` support from #19), since derivative standard errors blow up at
the edges of the condition range. On a synthetic Arrhenius benchmark at 3% noise
this halves the shift error (0.023 -> 0.013 decades) and tightens E_eff from
52.9 ± 1.8 to 54.1 ± 1.2 kJ/mol against a true 55.9.

Conventions that fail silently are checked rather than assumed: the domain sign
convention (which names the transform rather than changing it, so getting it
wrong flips every shift factor while the plots still look perfect), kelvin
(non-positive rejected, Celsius-looking warned), and a dimensionless condition
coordinate so design columns stay order-one. The master-curve smoother is fitted
separately from the derivative surface, so the discovery does not certify itself.

Closes #14.

78 new tests; full suite 886 passed, and green on the NumPy backend.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NYK13hwKpUryx5hQw3A3Fy
An audit of the six features merged today found three gaps. This closes them.

#17 (grouped/pipeline resampling) and #18 (structured blocks) had no CHANGELOG
entry at all, so `add_block`, `without_blocks`, `blocks`, `filter_by_block`, the
`groups=`/`resample_fn=` parameters, `summarize_selection_replicates` and
`cross_validate(groups=, strategy=)` were invisible in the release notes. Both now
have entries.

Both features also had no published docs home -- they were covered only under
.claude/skills/, because docs/guides/ has no basis-library or uncertainty guide to
extend. Rather than copy ~700 lines that would immediately drift from the skill
originals, this adds two focused guides matching how surface-derivatives.md and
sample-weights.md were done:

- docs/guides/structured-blocks.md -- the Theta(a) * column pattern, what add_block
  handles for you, and the without_blocks diagnostic for whether a block earned its
  place.
- docs/guides/resampling.md -- choosing the resampling unit, grouped rows,
  pipeline-level resampling, and reporting your own replicates.

Every code block in both guides was executed. One was wrong on first run:
cross_validate with 4 groups and the default cv=5 raises, so the example now passes
cv=4 and the guide documents the constraint and the leave-one-group-out alternative.

Adds docs/examples/superposition_master_curves.ipynb, the first example notebook for
any of today's features. It walks synthetic rheology end to end and demonstrates all
three findings on real output rather than asserting them:

- the transform is identifiable but the equation is not -- generated from pure
  Arrhenius with the Arrhenius basis available, the search picks WLF at c2=1.07
  (the same function), recovering the transform to 0.016 decades and E_eff to
  54.2 vs 55.9 kJ/mol;
- a thermorheologically complex control still reads as a master curve on the plot
  while sitting at 6x the noise floor in-sample and 7.9x held out;
- that control comes back *perfectly* stable -- 1 distinct structure, score 1.00 --
  against 3 structures and 0.75 for the genuine case.

The notebook's narrative was corrected after reading its own executed figure: an
earlier draft claimed both collapses look identical, which the plot does not support.
It now makes the defensible point instead -- the eye cannot supply the noise floor,
so 0.18 reads as ordinary scatter on an axis spanning seven decades.

Also fixes two pre-existing broken links in docs/quickstart.md (stray ../ prefixes);
all docs cross-references now resolve.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NYK13hwKpUryx5hQw3A3Fy
@jkitchin
jkitchin merged commit 616f7a0 into main Aug 13, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a superposition module: learn a symbolic transform that collapses a family of curves

1 participant