diff --git a/README.md b/README.md index ab52f6f..c6fa19b 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,71 @@ -# sim-numerics — similarity as a step rule for root finding +# sim-numerics — similarity and analogy as step rules for root finding -Artifact for the paper `article/sim_numerics.tex`. Every claim in the paper is -produced by one of the scripts below; nothing in the text is transcribed by -hand, and `verify_article.py` checks all 72 stated numbers against the run -data as part of the test suite. +A bracketing root finder derived from a similarity function, with a decision layer that recognises +multiple and fractional roots by analogy, and a worst case of twice bisection plus three evaluations +that holds whatever proposes the step. + +Everything here is released under the Apache License 2.0; copyright Valeri Sitnikov (`NOTICE`). +Archive of record, with the paper, the data and the full history: +[10.5281/zenodo.22894336](https://doi.org/10.5281/zenodo.22894336) (version 1.0.0: +[10.5281/zenodo.22894337](https://doi.org/10.5281/zenodo.22894337)). + +## Using the method + +`lib/` builds `simbracket`, the method as a compiled library (Cython, Python 3.10 or later, wheels for +Linux and Windows in the archive). It agrees with the reference implementation bit for bit, point and +evaluation count, on all 868 problems of the six corpora. + +```python +from simbracket import find_root, evaluation_bound + +x, nfev, converged = find_root(f, a, b, xtol=1e-12, maxfev=200) +# f(a) and f(b) of opposite signs; stops when the bracket is no wider than xtol or f(x) == 0; +# never more than evaluation_bound(a, b, xtol) = 2*ceil(log2(|b-a|/xtol)) + 3 evaluations +``` + +From source instead: `simroot.pure.pure_root` with the configuration named `APRIME` in +`sweep_full.py`. + +## What it costs + +On the 240 problems of corpus 4, fixed before the method's code was frozen, the method needs 3656 +evaluations. Chandrupatla's method needs 5717 there, ModAB 5535, Brent 8267 and TOMS 748 8084. It is +the cheapest of those methods on 77% of the problems, and on 88% of the multiple and fractional +roots. ## Reproducing +Use one platform for all numbers. The test functions call `libm`, whose last digit differs between +platforms, and the same SciPy version scores 2635 for TOMS 748 on Windows against 2636 on Linux for +the same set. The published numbers are from Linux (Ubuntu 24.04, Python 3.12.3). + ``` -python -m pytest tests/ -q # 490 tests -python sweep_full.py # the full grid, writes sweep_full.json -python verify_article.py # every paper number vs the data +python -m pytest tests -q # 1240 tests +python -u verify_article.py # 548 numbers of the paper against the run data ``` -Heavy runs go to a Linux machine (Python 3.12, run detached with a log, -`setsid nohup ... > sweep.log 2>&1`). **Use one platform for all numbers**: the -test functions call `libm`, whose last digit differs between Windows and Linux, -and the same SciPy version scores 2819 for TOMS 748 on Windows against 2820 on -Linux for the same set. The paper's numbers are the Linux ones. - -## Where each claim comes from - -| Paper | Claim | Script | -|---|---|---| -| Prop. 1 | the two-point similarity step **is** regula falsi | `tests/test_simroot.py::test_the_pure_two_point_similarity_step_is_regula_falsi_exactly` | -| Prop. 2, Table 1 | contraction law, predicted 0.1716 vs measured 0.1716 | `stage0c_why_pure_fails.py` | -| Cor. 1 | a chosen similarity fails on 5–8 of 8 problems | `stage0b_pure_similarity.py` | -| Cor. 2 | faster similarity is not better (`sqrt`, `cbrt`) | `stage0d_derived_similarity.py` | -| Cor. 3 | derived scale ⇒ the step is \|f\|/\|f'\| ⇒ superlinear | `stage0d_derived_similarity.py`, `stage0e_guard_cost.py` | -| §3 safeguards | bracket vs step vs both, and what each costs | `stage2_guard_modes.py`, `stage3_bound_check.py` | -| §3 order | 1.584 (2-point) vs 1.944 (3-point) | `stage5_three_point.py` | -| §3.1 | project vs replace; the guarantee costs nothing | `stage6_projection.py` | -| §3.1 | the projection invariant, instrumented per step | `stage6b_invariant.py` | -| §4 fairness | ITP is not handicapped; κ₁ and n₀ sweeps | `stage2b_itp_fairness.py` | -| Tables 2, 3 | the 154-configuration ranking on both sets | `sweep_full.py` → `report_sweep.py` | -| Table 4 | the law across the whole grid | `sweep_full.py` → `report_sweep.py` | -| §6 | approach vs endgame, order, boldness, step quality | `stage4_why.py` | -| §7.1 | the prototype-aggregation form loses 0/6/147 | `bench_full.py` (`SIM.pair2d.*`) | -| §7.2 | the 2× bound and high order are incompatible | `stage5_three_point.py`, `tests/test_three_point.py` | -| §7.4 | the symmetric ratio similarity degenerates | `simroot/pure.py` (`PURE_SIMS["ratio"]` docstring), `stage0d` | +Any table of the paper can be recomputed from scratch with its sweep script; each script's docstring +names the table it produces. Heavy runs belong on a Linux machine, detached, with a log. ## Layout ``` -simroot/pure.py the method: one similarity, one step rule, three guards -simroot/baselines.py bisection, 4 false-position variants, Ridders, Brent, - TOMS 748 (SciPy), ITP (own, validated against its theorem) -simroot/sim.py the prototype-aggregation form — a NEGATIVE result, kept - because the paper reports it -stage0*..stage5* the derivation, in the order it was actually established -bench_full.py 17 methods on both sets -sweep_full.py 9 similarities x 4 scales x 4 guards + 10 baselines -report_sweep.py reads sweep_full.json, produces the paper's tables -verify_article.py asserts the paper against the data (72 checks) -tests/ 490 tests; every bug found in audit is pinned here +simroot/pure.py the method: the similarity step, the decision layer, the projection +simroot/baselines.py bisection, the false-position family, Ridders, Brent, TOMS 748, ITP +lib/ the source of the compiled library simbracket +corpus_*.py the problem corpora, as code +sweep_*.py the runs; each writes its results file +verify_article.py every number stated in the paper, against the data +article/ the paper +PREREG_*.md POSTHOC_*.md what was recorded before each run, and what after +FINDINGS_*.md what the diagnoses found +tests/ 1240 tests; every bug found in an audit is pinned here ``` -## Negative results, so they are not reopened +## What was refuted -1. Similarity normalised by the two bracket ends **is** regula falsi, identically. -2. A faster-changing similarity is not better; what matters is the slope of - `1 - S` at zero matching the problem, and only the data supplies it. -3. Prototype-pair aggregation with softmax over the whole memory loses to the - simplest form: 0 wins / 6 ties / 147 losses against Brent on APS. -4. "Our safeguard fires less often" — refuted: Brent discards 53% of its - interpolations on the set it wins, 34% on the set it loses. -5. "Our steps are bolder" — refuted: on Chandrupatla Brent is bolder (56.3% - against 41.8%) and still loses. The mechanism is step *quality*: median - bracket removed 0.275 against 0.058. -6. Every safeguard that REPLACES the computed step with a midpoint destroys the - order: with the three-point scale, order falls from 1.94 to 1.00 and the APS - total from 2806 to 7260. **Resolved** by projecting the step onto the - admissible interval instead (`guard="project"`), which costs nothing on APS - (2806 either way) and gains on Chandrupatla (40/45 at 3220 against 35/45 at - 4104 unguarded). -7. Zero slack in the projection is degenerate: a worst case of exactly bisection - demands a halving at every step, leaving the projection no freedom. -8. Writing the projection as a radius around the midpoint instead of a clamp - loses the invariant to cancellation — a relative 8.9e-5 overshoot on eleven - Chandrupatla problems. -``` +The archive keeps eleven negative results in the form in which they were written, among them: a +similarity normalised by the two bracket ends is regula falsi identically; a faster-changing +similarity is not better; every safeguard that *replaces* the computed step with a midpoint destroys +the order, which is why the step is projected instead; and the phase detector whose derivation is +sound and whose estimator is not. They are kept so that they are not reopened.