Add GP_ELITE (pure-Python GP, LM constants, optional dimensional constraints) - #212
Add GP_ELITE (pure-Python GP, LM constants, optional dimensional constraints)#212ariel95500-create wants to merge 10 commits into
Conversation
|
Bumped to gp-elite 0.4.1 (now on PyPI) and updated metadata.yml. 0.4.1 fixes a silent float64 overflow in the Levenberg-Marquardt constant For reference, Happy to adjust anything to fit the harness. |
090e9ea to
3f27b67
Compare
Add metadata for GP_ELITE symbolic regression package
Implement GPEliteSRBench class for symbolic regression with time constraints.
|
Reopening — the branch was accidentally reset while syncing the fork, |
Implemented GPEliteSRBench class for symbolic regression with time constraints and multiple restarts. Added methods for fitting the model, generating sympy expressions, and calculating model complexity.
|
Restored after an accidental fork sync emptied this PR — the branch was
Apologies for the churn. |
every push and PR rebuilds all 27 images, because the gate in build-and-test is hardcoded to should_run=true (5b13029). check-changes already computes what changed, but nothing consumes it. one method submission can cost a lot: #209 went through 16 full 27-image runs, #210 and #212 another 24 between them. pull requests now build only the methods they touch. everything else - pushes to master/dev, the new weekly schedule, manual dispatch - still rebuilds everything, so a method that breaks from upstream drift without anyone touching it still gets caught. that drift is calendar-driven, which is what the schedule is for; during a quiet stretch there are no merges to catch it. - a method rebuilds if either algorithms/<name>/ or experiment/methods/<name>/ changed. the second one matters: a regressor.py edit has to retest the method even though the install is untouched. - changes to shared build inputs (dockerfiles, base_environment, scripts, entry.sh, configure.sh, workflows) still rebuild everything. - build-and-test always runs and always reports for every algorithm, so the check names stay present and can be marked required. only the docker build step is skipped. - dropped always() from build-and-test. with the gate inside the job, a failed check-changes would have left an empty build list, skipped every build and reported green. - check-changes no longer diffs against github.event.before, so a force-push to a CI branch no longer fails the job. also fixes a long-standing bug: changed-experiments used awk field $2 on experiment/methods/<name>/..., which is the literal string "methods", not the method name. it needs $3. nothing consumed that output before, so it never showed up.
|
Thanks — the only thing failing is a missing One command from your branch: |
add missing __init__.py for gp-elite
|
thanks for your submission; sorry about the the code looks good overall. one thing i'd like changed before merging. for k in range(max(1, int(self.restarts))):
r = symbolic_regression(...)
...
if elapsed > 0.85 * budget or elapsed + elapsed / (k + 1) > budget:
break
self.model_ = bestthe budget is only checked between restarts, and a single suggest moving the assignment inside the loop: if score > best_score:
best, best_score = r, score
self.model_ = best
self.equation_ = best.expression
self.is_fitted_ = Trueif two other questions:
|
|
Thanks for the careful review, all three are real and fixed in the latest commit. On the model_ timing: I moved the assignment inside the loop so the champion is published as soon as it's found. You're right that symbolic_regression isn't itself time-bounded, so a single overrunning restart could hit SIGALRM before assignment and lose the whole run; now the harness will always find the best result so far. I don't currently expose a per-call time limit in the engine, so the first restart still isn't bounded, but it's no longer fatal. I'll add a real per-call budget upstream as a follow-up. On np.int64: good catch. In practice the engine only ever emits native float leaves (I checked across many evolved models), so it doesn't trigger today, but the guard was fragile, so I now test np.integer and np.floating explicitly. On the operators: you're right that the fallback was unsafe. Under physical and full the sets are {+, -, *, /, pow, max2, min2} and {abs, cos, cube, exp, is_even, log, neg, sin, sq, sqrt, step, tan, tanh}. max2 and min2 fail to parse, and cube, step and is_even silently parse as undefined sympy functions rather than the intended math, so I replaced the fallback with an explicit mapping for every operator (Max/Min, **3, Heaviside, and so on), with domain guards on sqrt and log to match the engine, and an explicit error for any unmapped name. |
This PR adds GP_ELITE, a pure-Python symbolic regression library
(pip install gp-elite, MIT).
Method: genetic programming with island parallelism, Levenberg-Marquardt
constant optimization, native multi-restart with merged archives, and a
complexity/accuracy Pareto front. The regressor passes scikit-learn's
check_estimator, implements max_time via time-boxed sequential restarts,
and model() returns a sympy-compatible string using the dataset column
names, with input normalization folded in (the string reproduces
est.predict on raw features to ~1e-12).
Internal run of the SRBench ground-truth protocol on the 119 Feynman
datasets (10k rows, 75/25 split, 3 seeds, R2_test>0.999): 60.2% of runs
solved, 69% of datasets solved by at least one seed, median R2 0.99973.
Raw jsonl logs and the runner are available in the project repo.
Repo: https://github.com/ariel95500-create/gp-elite
Happy to adjust anything to fit the harness.