Repository navigation
Releases: psaegert/srbf
Releases · psaegert/srbf
Release list
srbf 0.21.0
Added
- Operon as a subprocess worker (
worker: operon): pyoperon 0.6.1'sSymbolicRegressorin the configuration
its first author published for benchmarking (NSGA-II on R² and length, one Levenberg–Marquardt step per individual,
population 1,000, length at most 50, depth at most 10, MDL selection from the Pareto front), without its
hyperparameter search. srbf sets the operators and a budget in evaluations (rung filesevals_<n>.pkl); the whole
Pareto front is stored. - DSO as a subprocess worker (
worker: dso; DSO v3.0.0 in its own Python 3.7 environment,
scripts/envs/build_dso_env.sh):options.arm: dsrruns DSO's shipped regression defaults,udsrthe uDSR paper's
benchmark configuration (uDSR*: priority-queue training, GP-meld, the LINEAR token). Three patches, documented in
docs/models.md: GP-meld evaluates the trees it breeds, LINEAR's inverse table gainsnegandn4, and a GP-meld
clone shares the primitive set. On the NGGP Nguyen anchor the uDSR* path recovers 14 of 15 runs. - GP-GOMEA as a subprocess worker (
worker: gpgomea): the original GP-GOMEA at commit 6a92cb6, the one SRBench 2021
ran, in its first author's benchmark configuration. Its protected operators are written as the functions it
computes, and the linear-scaling coefficients are recomputed in float64. On SRBench 2021's Feynman protocol it
recovers 71.7 % (published: 70.9 %). - RILS-ROLS as a subprocess worker (
worker: rilsrols): rils-rols 1.6.7 in its first author's SRBench
configuration, with an output-only patch that prints constants at full precision; the budget is fit calls
(evals_<n>.pkl). On Feynman it recovers 81.7 % (published: 82.59 %). - The Flash-ANSR oracle: with
generation_config.method: oracle(flash-ansr'sOracleConfig), the Flash-ANSR adapter
hands the model each problem's ground truth as its only candidate, which shows how well the fitting does when the
form is given. A ladder over the refiner's restarts (restarts_<n>.pkl,
configs/evaluation/scaling/flash-ansr-v25.0-T8-oracle_srbf.yaml). srbf tablejudges result trees (every method, draw, catalog, rung and shard) into one CSV with every metric, in
parallel and with a per-file cache. Withscripts/site_timing.py(the time axis from reference-machine result files;
--patternnames a method's own rung files) andscripts/catalog_mu.py, the results site is rebuilt from the result
files with srbf alone.- QLattice as a subprocess worker (
worker: qlattice): feyn 3.5.0 through its authors' SRBench loop (200 epochs,
at most 10 edges,wide_parsimony, squared error). srbf sets the operators, the budget (n_epochs, rung files
epochs_<n>.pkl) and the seed; the answer is the first model the loop returns, written at full precision, with
feyn's protected functions written out where they clip.scripts/envs/build_qlattice_env.shbuilds a pinned
Python 3.12 environment; feyn runs offline without a licence key (CC BY-NC-ND 4.0: research use). On SRBench 2025's
first-principles data it reproduces the published QLattice accuracy: mean mid-rank 0.41 among the published runs
(2 epochs: 0.07). - The
flash_ansr_hybridadapter type is built in again. The hybrid method moved into flash-ansr 0.19
(flash_ansr.hybrid); srbf's adapter hands it each problem through its evaluation path (HybridRegressor.solve)
and records the answer like every adapter. Configs that named the private plugin (hybrid_adapter:build) use
type: flash_ansr_hybrid.pip install srbf[hybrid]brings flash-ansr with PySR; flash-ansr 0.19 is allowed. srbf tablestores the expressions it judged:predicted_expression(in the ground truth's variable names and
the engine's spelling) andground_truth_expression, as prefix tokens at full precision.- The results site's Predictions view: one problem at a time, the true formula and every method's formula, typeset,
with whether each recovered it.scripts/site_export_v2.pywrites one file per method, problem set, budget,
finished run and block of 500 problems; a finished file never changes. srbf status -c CONFIG: how far every run of a config is (done,started,not started, with the
row counts), without loading a model; the exit code is 0 when every run is done.
Benchmark.runs_from_config(..., build_adapter=False)is the same from Python.- An adapter from your own package:
model_adapter.type: mypackage.module:functionnames a builder
function; nothing in srbf has to be edited for an in-process adapter. - What a worker reports about itself is stored with the results:
__meta__["worker"]holds the return
value of the worker'sinfo()(its interpreter, package versions, checkpoint). - Symbolic recovery at three levels of masking.
symbolic_recoverymasks every number (the structure is
the ground truth's);symbolic_recovery_mask_fittablemasks only the fittable constants, so exponents and root
indices have to be the ground truth's as well;symbolic_recovery_mask_nonealso asks for the constants, measured as
numeric recovery is. Each level implies the one before it, and agreement at a stricter level is a witness
at the looser one. The two new columns need an engine. precision_score,recall_scoreandedit_distance_normamong the derived metrics: the two parts of
the token F1, and the edit distance over the length of the longer sequence.- The documentation is tested against the package (
tests/test_docs.py): every command, flag, adapter
type, suite catalog and derived metric is documented; every documented flag, import and repository path
exists; every example parses; and the site builds with broken links as errors.
Changed
- srbf no longer depends on flash-ansr, and its root is
SRBF_ROOT.{{ROOT}}in a config stands for the
SRBF_ROOTdirectory (the current directory when it is unset);FLASH_ANSR_ROOTmeans nothing to srbf any more,
so a script that set only it must setSRBF_ROOT. srbf reads its configs and resolves{{ROOT}}itself
(srbf.paths). flash-ansr is an optional install,pip install "srbf[flash-ansr]", needed only by the adapters
built on it (flash_ansr, andflash_ansr_hybridthroughsrbf[hybrid]) and by the two baselines that fit their
constants with its refiner (lample_charton,brute_force); they import it when they are built and say how to
install it when it is missing. A run of any other method never imports it: the FVU the NeSymReS and hybrid adapters
record is srbf's ownsrbf.metrics.fvu, and the run's provenance reads flash-ansr's version without importing it.
Flash-ANSR checkpoints are downloaded withhf download <checkpoint> --local-dir "$SRBF_ROOT/models/<checkpoint>".
CI runs the suite with and without flash-ansr, and a test imports every srbf module where flash-ansr cannot be
imported. - The results site averages over problem sets, with the problem as the unit. A problem's value is the mean of
its runs, and the catalogs are combined by a random-effects average (Paule–Mandel between-catalog variance,
intervals over these problem sets, rates on the logit scale, ratios as geometric means), so erbench-syneq no longer decides
a pooled number on its own; tables and tooltips add where one more catalog would fall. Paired contrasts compare
every run of one method with every run of the other and test over catalogs (rates on the difference, other metrics
on the per-problem superiority); ranks are built from the pairwise chances to beat, with Holm-corrected pairwise
tests in place of Friedman and the Nemenyi critical difference. Two predictions that both meet Numeric Recovery tie
in comparisons, and a failed run counts as worst in the medians, distributions, ranks and comparisons of log10 FVU
and R². The time axis averages the catalogs the same way.scripts/site_random_effects.pyis the reference; the
site suite runs the page's own code against it. log10_fvuis floored at the float64 epsilon (srbf.metrics.numeric.LOG10_FVU_FLOOR, (\log_{10} 2^{-52}
\approx -15.65)). An exact fit used to be (-\infty), which every mean left out, while the same formula written
another way landed at finite rounding noise anywhere down to about (-320), which every mean took in: on the
2026-09 board, 22 % of T8-120M's usable predictions sat below the float64 epsilon and at budget 128 values below
(-20) made 45 % of its mean's sum. Below the epsilon the unexplained variance is smaller than about one rounding
unit of the variance it is divided by, so all of these are one value now, and an exact fit counts in a mean.
Blow-ups stay (+\infty). The judge's fingerprint changes, sosrbf tablere-judges its cache.- The results site is written for a first-time reader. Every hint, popover, metric definition, method note and
protocol text, and the prose below the explorer, say what they mean in plain words ("problem set", "budget",
"run"; no pipeline vocabulary), with the longer explanations moved to a from-scratch "How to read the results"
section. The Numeric Recovery threshold is described as what it is (FVU at most 2^-23: a typical error of at most
0.035 % of the values' spread). A method missing at a budget is said to be not run there, or not finished yet;
the export carries each method's planned budgets for that.copy_lint.pyand a rendered-text test in the site
suite keep the pipeline's words out. - A worker is handed the problem and nothing of the ground truth.
metacarries the problem's identifiers and
sampling parameters (benchmark_eq_id,eval_row_index,n_support,noise_level, the variable
names); the ground truth's skeleton, expression, constants and complexity stay on srbf's side. - Every method sees every column.
drop_unused_variables(and the PySR block'spadding, and
remove_paddingof the NeSymReS...
srbf 0.20.3
A second sign of a hang for out-of-process workers: overdue (a problem that runs many times longer than the problems before it), for workers that are stuck while busy. Opt-in via hang_overdue_factor; see the CHANGELOG.
Release notes written by Claude (Claude Code) on behalf of @psaegert.
v0.20.2
Added
- A hang policy for out-of-process workers (opt-in:
hang_after_idle_son a worker-backed adapter).
While a problem is in flight, the worker's process tree is sampled from/proc; less than
hang_idle_cpu_sCPU seconds (default 1) overhang_after_idle_sseconds of wall is a hang, and so is a
missed hardtimeout. The problem is retried once in a fresh worker and a second hang fails it. Every
hang is written tohang_log(JSON lines: problem, attempt, kind, seconds, CPU in the window, outcome)
and counted in the row'sworker_hangs. Hang restarts do not spendmax_restarts, which stays the
budget for crashes. Without the key nothing changes. - PySR on the whole suite, on the reference machine.
scripts/make_pysr_suite_config.pywrites one
experiment per catalog with the data sources and runners of a Flash-ANSR scaling config, PySR with
upstream defaults, the iteration count as the ladder, and the hang policy on (60 s);
scripts/run_timing_ladder.py --full-suiteruns such a config unit by unit on whole catalogs, and the
solomon timing queue runs it (three runs,RUN_PYSR_SUITE=0skips them). scripts/stop_timing_queue.sh: stops the timing queue without corrupting its marks (the queue first,
processes matched by their exact command, any mark written while stopping rolled back).
v0.20.1
Fixed
- The
flash_ansr_hybridadapter builds again. Its builder reademissionfrom the Flash-ANSR
adapter, which has not carried it since the flash-ansr 0.17 port made emission a sampling policy
of theflash_ansrblock; every hybrid config failed at build time with anAttributeError. The
builder now takes emission from theflash_ansrblock, as the Flash-ANSR builder does. scripts/make_hybrid_config.pywrites configs this release can run: adapter type
flash_ansr_hybrid(not the retiredflash_ansr_pysr); apysr:block holding only
PySRSettingsfields, since PySR runs in-process (the worker-protocol keys and the--pysr-python,
--worker-logand--engineoptions are gone);drawsinstead ofchoices; and
ranking: {mode: mdl}, the two-part code, instead of the fixedmdl_strength: 1.0e-2.
Changed
- Timing read-out: failures do not count towards the time.
scripts/timing_readout.pydrops
every row that carries an error orprediction_success: False, whether or not afit_timewas
recorded, so the reported seconds are the mean over the problems a method answered. Before, a fit
that returned without a surviving candidate was still counted. scripts/site_export_v2.pypublishes no as-run wall clock:fit_timeandgeneration_time
are no longer release metrics; the only time a release carries is the reference-machine table.
Added
scripts/timing_queue_solomon.sh:RUN_PYSR=0andRUN_NESYMRES=0defer the PySR-alone and
NeSymReS rows of the timing queue.
v0.20.0
Changed
- flash-ansr 0.18: the two-part code is the ranking. Pin
flash-ansr>=0.18,<0.19. Every shipped
scaling config ranks withranking: {mode: mdl}-- flash-ansr's two-part code
(n/2) log2 FVU + bits(the score study's S1, owner ruling 2026-09-16) -- instead of the fixed
mdl_strength: 1.0e-2(S0) they carried before; a config that still namesmdl_strengthruns
the fixed weight, so the old numbers stay reproducible on request. Result files record the
ranking as before (mdl_strength: null= the two-part code).
v0.19.0
Changed
- flash-ansr 0.17 API. The Flash-ANSR adapter is built from
refine,rankingandcompute
mappings (FlashANSR.load(..., refine=, ranking=, compute=)), the sampling policy from a
SoftmaxSamplingConfig/PriorSamplingConfig(draws,emission, ...), and every problem runs
throughmodel.fit(X, y, variable_names=..., draws=..., complexity=...); candidate curves and the
per-rank ledger are read from the returnedFitResult(result.predict(X, rank=...)). Requires
flash-ansr>=0.17,<0.18. drawsreplaceschoicesin every evaluation config (configs/evaluation/scaling/*.yaml,
scripts/make_scaling_configs.py); a config still spellingchoicesis refused with aValueError.
0.18.0
Fixed
symbolic_recoveryjudges both sides through the same simplify. The ground truth's skeleton is
simplified before the comparison (pow x1 / <c> <c>->pow x1 <c>); a prediction whose canonical
form is not strictly shorter was judged by its stored skeleton UNsimplified, so a prediction
byte-identical to the ground truth (pow x1 / 2 3) was not exact. Every law with a rational
exponent -- 396 of 6,660, 7 % of erbench-syneq -- was unjudgeable as exact, whatever the answer. The
stored skeleton now goes through the same simplify on the fallback path. A second-stage metric over
stored prefixes: re-derive, nothing needs re-running. Results judged under 0.17.x and 0.18.x are not
comparable on those laws, which is what the minor bump marks.
Added
- Answer provenance in the flash_ansr adapter's rows:
predicted_typed_frozen(predicted typed
literals kept verbatim),predicted_typed_thaw(a thawed duplicate: the typed token indices it
re-fitted; None otherwise) andpredicted_spelling(the constant ladder's re-spelling record) for
the rank-0 answer, from flash-ansr >= 0.16.1 (whose ladder children carry the thaw mark). Pin
flash-ansr>=0.16.1,<0.17.
Release notes are the [0.18.0] section of CHANGELOG.md, assembled by Claude Code (https://claude.ai/code/session_01MktGcCWQs8zePRutL56sT4).
0.17.0
Changed
- Evaluates flash-ansr 0.16 (
flash-ansr>=0.16,<0.17). flash-ansr 0.16.0 keeps the numbers a
model predicts in a mixed emission (0.15.x post-processing deleted them from 72 % of valid
candidates) and defaults torefiner_typed_spans='freeze_then_free', so every flash-ansr arm
evaluated under this srbf draws from a different candidate pool than under 0.16.x; results
across the two are not comparable, which is what the minor bump marks. Nothing in the driver,
the metrics or the judge changed.
Added
- The diffsym worker (
worker: diffsym,configs/evaluation/baselines/diffsym_fastsrb.yaml):
Mara Eliana's discrete diffusion model (D3PM) conditioned on the support set, run out of process in
its own interpreter (it pins simplipy 0.2.15 and its own torch). Per problem it samplesn_samples
token sequences, decodes/simplifies/validates them into prefix candidates, fits each candidate's
constants with diffsym's own ConstantFitter and returns the best by R^2. Two translations sit
between the two: the pre-0.12 vocabulary (pow2/pow1_3) is respelled with
respell_legacy_prefix, and diffsym's positionalx1..xnbecome the catalog's own variable names.
A candidate naming a variable the problem does not have (the decoder's vocabulary is the
checkpoint'sx1..x8, not the problem's) is dropped and counted indiffsym_n_out_of_rangerather
than failing in the fitter. Smoked on the v4.0 checkpoint (119M parameters, step 1.7M):srbf check
green on fastsrb, II.38.14 recovered at 32 draws.
Release notes are the [0.17.0] section of CHANGELOG.md, assembled by Claude Code (https://claude.ai/code/session_01MktGcCWQs8zePRutL56sT4).
0.16.1
Fixed
- The judged skeleton is the canonical form the prediction was priced as. flash-ansr < 0.15.2
emitted a fitted candidate as its skeleton with the numbers filled in, so a factor the fit made
cancel (exp(-x^2) * tanh(x)^2 / tanh(x)^2) or a constant the fit made fold stayed in the spelling
while the certified price had collapsed it -- andsymbolic_recovery, a masked-skeleton identity,
missed the recovery.derive_metricsnow judges the masked, simplified skeleton of the prediction's
canonical form whenever that form is strictly shorter than the emitted one (the stored skeleton
stays underpredicted_skeleton_prefix_as_emitted), so files from before and after flash-ansr
0.15.2 are judged alike. Measured on the T8-20M r = 0 readings (766 problems): symbolic recovery
9.3 % as emitted -> 13.2 % canonical. Numeric metrics and the MDL price are unaffected.
0.16.0
Removed
- The hybrid arm's method code. srbf is the evaluation framework; a method does not live in it.
srbf/hybrid_adapter.py(model_adapter.type: flash_ansr_pysr),scripts/make_hybrid_config.py,
scripts/run_hybrid_sweep.py,scripts/hybrid_rescore.pyandscripts/hybrid_curve.pyare gone. The method -- Flash-ANSR
generating by the clock until its share (1 - r) T, its top-K candidates seeding PySR, PySR on its own
clock (its share minus the running means of its fixed cost and of the pricing that follows), its hall
of fame re-fitted with flash-ansr's refiner, re-spelled by the constant ladder, priced and scored like
Flash-ANSR's own candidates, Flash-ANSR's sorting picking rank 0 -- and its sweep tooling now live in
theflash-ansr-hybridpackage (0.1.0:HybridRegressor,flash-ansr-hybrid-make-config,
flash-ansr-hybrid-run-sweep,flash-ansr-hybrid-rescore,flash-ansr-hybrid-curve). PySR runs in-process there, so the
pysr:block no longer names an interpreter.
Added
model_adapter.type: flash_ansr_hybrid(FlashANSRHybridAdapter): the thin adapter for the
flash-ansr-hybrid regressor --flash_ansr:(the model block),hybrid:(the regressor's
HybridConfigfields plussnapshot_dir), optionallypysr:(itsPySRSettings). It hands each
problem's arrays to the regressor and records its answer with the usual FVU columns; nothing of the
method is in srbf. The package is thehybridextra (pip install "srbf[hybrid]"), imported lazily.