Revision 1, step 1: one scoring criterion, the correct order, and the internal inconsistencies.
Point 1. The base step's order is Muller's 1.839, not 2: the derivative of the parabola through
the last three points errs by f'''/6 (x_n - x_{n-1})(x_n - x_{n-2}) = O(e_{n-1} e_{n-2}).
order_high_precision.py (3000 digits, to 1e-2900): 1.840 on cos x - x, e^x - 2, x^3 - x - 2,
sin x - 1/2; 2.000 only on x^2 - 2; two-point 1.618. The double-precision medians (2.000, 1.94)
are removed from the text.
Point 3. Every protocol number is re-scored under the criterion of section 9 - a sign change
within 1e-6 or f(x) == 0. rescore_uniform.py re-runs all 2779 distinct configurations of the 25
protocol sweeps on APS and CHA (the runs did not keep x) -> sweep_uniform.json, same row format;
it reproduces the APS/CHA lines of Table 10 exactly (built-in check). verify_article.py,
audit_similarity_places.py and the gap diagnostics read the re-scored data; the multiplier and
endowment measurements score by the same criterion. Table 7 (two criteria side by side) is gone;
7.3 now explains why the criterion is a sign change. Consequences stated in the text: the base
rule 2634 / 2357 against Chandrupatla 2595 / 1505 (1.5% behind on APS, no longer "level"); A'
2259 / 1074 (12.9% and 28.6% below Chandrupatla); the defect reading 2351 is second to the
shape reading 2337, not the record; the remembered analogy is level with no regime (2633 vs
2634) under this criterion; Table 9a's range is 19% to 425%.
Point 8. report_sweep.head_to_head counts every problem, failures charged (it counted only the
problems both methods solved, which is why Table 8 rows summed to 153 and 40). Family-level
comparisons added (A' vs Chandrupatla 8/1/6 of 15 and 7/0/2 of 9 families, not significant), and
an independence paragraph in section 9.
Point 11. sweep_itp.py: ITP (recommended constants and per-problem oracle) on all six corpora ->
Table 10; behind A' on every corpus, 0 bound violations.
Points 7, 9, 10 and the internals: the 2x bound is ours, not the rivals' promise; the law
predicts the group order only; "outside the proven bracket" explained (narrowest bracket of all
observed signs); 7.4's fun1 paragraph corrected (five costs under safe; the unguarded numbers
belong to fun1.4, fun1.5 and to fun3.1, fun5.1 separately); Table 1's last cell; the corpus-4
composition and odd multiplicities stated, also in the abstract.
build_tex.py: pdflatex output decoded with errors="replace" (a UTF-8 character cut by TeX's log
wrap crashed the build). Table 10 column widths rebalanced.
Checks: verify_article on the server 500 OK / 0 BAD (467 existing with the new values, 33 new);
regression x2 on the server 1232 passed, 0 failed; PDF 28 pages, 0 errors, 0 undefined, 0 overfull.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,236 @@
|
||||
"""Revision 1, step 1 (2026-09-22): corrections that need no new method.
|
||||
|
||||
point 1 the order of the base step is Muller's 1.839, not 2 (order_high_precision.py)
|
||||
point 3 ONE criterion throughout: a sign change within 1e-6 or f(x) == 0
|
||||
(rescore_uniform.py -> sweep_uniform.json); every protocol number re-scored
|
||||
point 7 the 2x bound is ours, not the rivals' promise
|
||||
point 8 head-to-head over every problem, failures charged; families as the unit
|
||||
point 9 the law predicts the group order, not the order within groups
|
||||
point 10 "outside the proven bracket" explained
|
||||
point 11 ITP in Table 10 (sweep_itp.py)
|
||||
internal Table 8 sums, section 7.4, Table 5 vs Table 7, Table 1's "captured" cell
|
||||
|
||||
Exact anchors, each found exactly once, or nothing is written.
|
||||
|
||||
python -u apply_article_revision1.py
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
PATH = "article/sim_numerics.md"
|
||||
|
||||
REPL = []
|
||||
|
||||
|
||||
def R(old, new):
|
||||
REPL.append((old, new))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------- abstract
|
||||
R("Second, any similarity fixed in advance with the scale also fixed yields at best linear convergence at a rate that is a property of the problem rather than of the method; on the eight standard problems of §2.2, five to eight of them fail. Third,",
|
||||
"Second, any similarity fixed in advance with the scale also fixed yields at best linear convergence at a rate that is a property of the problem rather than of the method. Third,")
|
||||
R("It carries a proven worst case of twice bisection plus one step and exactly one free constant, which we declare rather than argue away: the multiplier of that budget. On the 154 problems of Alefeld, Potra and Shi it needs 2806 evaluations of $f$ against 2820 for TOMS 748, 2889 for Brent and 2787 for Chandrupatla's method — level in total — and beats Chandrupatla problem by problem 87 to 42 (exact sign test $p=9\\cdot10^{-5}$). On the 45 wide-bracket problems of Chandrupatla it beats Brent and TOMS 748 and loses to ITP and to Chandrupatla (3220 against 2896 and 2441). For every data-derived scale, the ranking of the nine similarity functions matches the derived law without exception.",
|
||||
"Its order is Muller's, 1.839. It carries a proven worst case of twice bisection plus one step and one free numerical constant, the multiplier of that budget, which we declare. On the 154 problems of Alefeld, Potra and Shi it needs 2634 evaluations of $f$ against 2636 for TOMS 748, 2707 for Brent and 2595 for Chandrupatla's method; it wins more problems than it loses against Chandrupatla, 87 to 43, and needs 1.5% more in total because its losses are the larger ones. On the 45 wide-bracket problems of Chandrupatla it beats Brent and TOMS 748 and loses to ITP and to Chandrupatla (2357 against 1946 and 1505). For every data-derived scale the three similarity functions whose $1-S$ has a non-zero slope at the origin come before the three whose slope is zero, as the derived law predicts.")
|
||||
R("On the two sets it needs 2438 and 2005 evaluations against Chandrupatla's 2787 and 2441 and beats him problem by problem on both, 103 to 30 and 29 to 7.",
|
||||
"On the two sets it needs 2259 and 1074 evaluations against Chandrupatla's 2595 and 1505 and wins more problems than it loses on both, 103 to 31 and 31 to 10.")
|
||||
R("tested once, after its code was frozen, on 240 problems from six new families, it needs 3656 evaluations against Chandrupatla's 5717 and wins 177 problems to 28. Over 855 problems in six corpora it is ahead of Brent, TOMS 748 and the recent ModAB everywhere and keeps its bound where they break theirs on 118, 84 and 9 problems;",
|
||||
"tested once, after its code was frozen, on 240 problems from six new families, it needs 3656 evaluations against Chandrupatla's 5717 and wins 177 problems to 28 — a corpus the author composed knowing where the method is strong: two of its six families have multiple or fractional roots, and without them the lead is 2403 against 3569, on the simple-root families alone 737 against 747. Over 855 problems in six corpora it is ahead of Brent, TOMS 748, ITP and the recent ModAB everywhere and stays within its own bound of twice bisection on every problem, a bound that Brent, TOMS 748 and ModAB, which do not promise it, exceed on 118, 84 and 9 problems;")
|
||||
R("and the similarity that sets the step, whose form is decisive (replacing it costs 12% to 315%).",
|
||||
"and the similarity that sets the step, whose form is decisive (replacing it costs 19% to 425%).")
|
||||
|
||||
R("with the tent the step is Newton's, with any of the other eight functions the same method costs from 12% to four times more.",
|
||||
"with the tent the step is Newton's, with any of the other eight functions the proposed method costs from 19% to five times more.")
|
||||
R("and in the proposed method replacing the tent by any other function costs 12% to 315% (Table 9a).",
|
||||
"and in the proposed method replacing the tent by any other function costs 19% to 425% (Table 9a).")
|
||||
|
||||
# ---------------------------------------------------------------- section 2
|
||||
R("So \"a similarity rule scaled by the bracket is not a new method\" would be too broad a conclusion, and this paper's own Table 3 refutes it — bracket-scaled configurations take first and fourth place on Chandrupatla and one of them solves 41 of 45, where false position solves 6.",
|
||||
"So \"a similarity rule scaled by the bracket is not a new method\" would be too broad a conclusion, and this paper's own Table 3 refutes it — bracket-scaled configurations take third, fourth and sixth place on Chandrupatla's set, where false position solves 6 of 45.")
|
||||
R("In our measurements plain false position solves 127 of the 154 Alefeld–Potra–Shi problems, against 153 for bisection.",
|
||||
"In our measurements plain false position solves 127 of the 154 Alefeld–Potra–Shi problems, against 154 for bisection.")
|
||||
R("| $\\max(0,1-\\lvert z\\rvert)$ | 1 | rate 0.1716 | captured, see below |",
|
||||
"| $\\max(0,1-\\lvert z\\rvert)$ | 1 | rate 0.1716 | fails: stays at $x_\\mathrm{far}$ |")
|
||||
R("yet over the full benchmark they finish at 10497 and 11941, ahead of all three $c=0$ similarities at 14314, 15102 and 16394, and one of them heads Table 3. Overshooting is the milder failure.",
|
||||
"yet over the full benchmark (best over scales, Table 4) they finish at 9411 and 10874, ahead of all three $c=0$ similarities at 13187, 13990 and 15272. Overshooting is the milder failure.")
|
||||
|
||||
# ---------------------------------------------------------------- section 3: the order (point 1)
|
||||
R("has error $O(h^2)$. A Newton step whose derivative carries an $O(h^2)$ error satisfies $e' = e-f/\\hat f' = e-(e-ce^2+\\dots)(1+O(e^2)) = ce^2+O(e^3)$, so the predicted order is **2** — not Muller's 1.84, which belongs to a method using the parabola's *root* rather than its *derivative*. Measured medians are 1.584 for the two-point scale and 2.000 for the three-point, against 1.809 for Brent and 2.654 for TOMS 748.",
|
||||
"has error $\\tfrac16 f'''(\\eta)\\,(x_n-x_{n-1})(x_n-x_{n-2})$, that is $O(e_{n-1}e_{n-2})$. The Newton step with that derivative satisfies $e_{n+1}=\\tfrac{f''}{2f'}e_n^2+\\tfrac{f'''}{6f'}\\,e_n e_{n-1}e_{n-2}+\\dots$; the second term dominates, and the order is the root of $p^3=p^2+p+1$, $p\\approx1.839$ — **Muller's order**, as it should be, since the step uses the same parabola as Muller's method, through its derivative rather than its root. Only where the parabola is exact ($f'''=0$) does the order rise to Newton's 2. Carried to $10^{-2900}$ in 3000-digit arithmetic (`order_high_precision.py`), the computational order per step settles at 1.840 on $\\cos x-x$, $e^x-2$, $x^3-x-2$ and $\\sin x-\\tfrac12$ and at 2.000 on $x^2-2$; the two-point scale settles at 1.618. In double precision a run takes three or four superlinear steps before it reaches the tolerance, too few to tell 1.84 from 2, and we report no order measured there.")
|
||||
R("(i) a derivation that fixes every choice — which similarity, which scale, which safeguard — before any benchmark is consulted, and then predicts the ranking of all nine similarity functions correctly;",
|
||||
"(i) a derivation that fixes every choice — which similarity, which scale, which safeguard — before any benchmark is consulted, and predicts which similarity functions come first;")
|
||||
R("With the three-point scale, replacing on that test drops the observed order from 1.94 to 1.00 and the Alefeld–Potra–Shi total from 2806 to 7260 — worse than bisection.",
|
||||
"With the three-point scale, replacing on that test makes the convergence linear and takes the Alefeld–Potra–Shi total from 2634 to 7068 — nearly the cost of bisection (7338).")
|
||||
R("**The multiplier is the method's one free constant.** An earlier version of this section argued that it is \"the factor already claimed in the bound\". That is circular — the bound is twice bisection because two was chosen — and measurement settles it (`measure_budget_factor.py`, Linux):",
|
||||
"**The multiplier is the method's one free numerical constant.** It is not \"the factor already claimed in the bound\" — that argument is circular, the bound is twice bisection because two was chosen — and measurement settles it (`measure_budget_factor.py`, Linux):")
|
||||
R("| 1 | 4817 | 2997 | 7814 |\n| 1.25 | 2806 | 2752 | 5558 |\n| 1.5 | 2806 | 2889 | 5695 |\n| 2 | 2806 | 3220 | 6026 |\n| 3 | 2806 | 3756 | 6562 |\n| 4 | 2806 | 4006 | 6812 |",
|
||||
"| 1 | 4625 | 2039 | 6664 |\n| 1.25 | 2626 | 1822 | 4448 |\n| 1.5 | 2636 | 1991 | 4627 |\n| 2 | 2634 | 2357 | 4991 |\n| 3 | 2634 | 2936 | 5570 |\n| 4 | 2634 | 3229 | 5863 |")
|
||||
R("On the canonical set the projection never binds once $c\\ge1.25$, so the total does not move. On the wide-bracket set it moves monotonically with $c$, and 2 is not even the best value. Nor is zero slack ($c=1$) the degenerate case it was claimed to be, \"a worst case of exactly bisection\" under which \"the guard behaves as bisection\": it costs 4817 and 2997, far from bisection's 7530 and 3090, and on the wide-bracket set it beats $c=2$.",
|
||||
"On the canonical set the projection binds on one problem only once $c\\ge1.25$ — `aps.13.00`, whose $f$ underflows to zero around the root (20, 30 and 28 evaluations at $c=1.25$, 1.5 and 2) — so the total barely moves. On the wide-bracket set it moves monotonically with $c$ from 1.25 on, and 2 is not the best value. Nor is zero slack ($c=1$) a degenerate case under which the guard behaves as bisection: it costs 4625 and 2039, far from bisection's 7338 and 2136, and on the wide-bracket set it beats $c=2$.")
|
||||
R("| 0.1 | bisection + 1 step | 5344 | 3051 | 8395 |\n| 0.5 | bisection + 1 step | 4656 | 3002 | 7658 |\n| **1** | **bisection + 1 step** | **3568** | **3020** | **6588** |\n| 2 | bisection + 2 steps | 3692 | 2712 | 6404 |\n| 5 | bisection + 5 steps | 3006 | 2615 | 5621 |",
|
||||
"| 0.1 | bisection + 1 step | 5150 | 2097 | 7247 |\n| 0.5 | bisection + 1 step | 4462 | 2037 | 6499 |\n| **1** | **bisection + 1 step** | **3377** | **2073** | **5450** |\n| 2 | bisection + 2 steps | 3502 | 1757 | 5259 |\n| 5 | bisection + 5 steps | 2819 | 1666 | 4485 |")
|
||||
R("We nonetheless propose the scheduled projection with $c=2$ and declare its multiplier. On the canonical set it is 762 evaluations cheaper than the earned variant (2806 against 3568), and there its total does not depend on the multiplier at all; on the wide-bracket set the earned variant is the cheaper (3020 against 3220). The two are the ends of a trade stated in numbers: one declared constant and the better canonical result, or no constant, a tighter bound and the better wide-bracket result. The value 2 was fixed before any benchmark was consulted; what changed after the question whether it was load-bearing is only that it is now declared as a constant rather than argued to be none.",
|
||||
"We nonetheless propose the scheduled projection with $c=2$ and declare its multiplier. On the canonical set it is 743 evaluations cheaper than the earned variant (2634 against 3377), and there its total barely depends on the multiplier; on the wide-bracket set the earned variant is the cheaper (2073 against 2357). The two are the ends of a trade stated in numbers: one declared constant and the better canonical result, or no constant, a tighter bound and the better wide-bracket result. The value 2 was fixed before any benchmark was consulted.")
|
||||
|
||||
# ---------------------------------------------------------------- section 4: the criterion (point 3)
|
||||
R("**Cost model.** Evaluations of $f$. A run counts as solved when it reports convergence and lands within $10^{-6}$ of the published root; $x$-tolerance $10^{-12}$; budget 200 evaluations.",
|
||||
"**Cost model.** Evaluations of $f$. A run counts as solved when it reports convergence and $f$ changes sign within $10^{-6}$ of the returned point, or vanishes there — the bracketing notion of a root, the same criterion on every corpus of this paper; $x$-tolerance $10^{-12}$; budget 200 evaluations. Scoring against the published root instead, as the benchmarks' harness does, charges every method the full budget on six problems where $f$ vanishes identically around the root in floating point (§7.3). Head-to-head counts (wins/ties/losses) are taken over every problem of a set with the same charging as the totals.")
|
||||
R("With the tolerance corrected our implementation and the library agree on all 199 problems exactly, and Chandrupatla's totals move from 2785 to 2787 on the canonical set and from 2423 to 2441 on the wide-bracket set. For Brent the library is slightly dearer than our implementation (7004 against 6991 over both sets); we use the library anyway, because it is the implementation a reader can check.",
|
||||
"With the tolerance corrected our implementation and the library agree on all 199 problems exactly. For Brent the library is slightly dearer than our implementation; we use the library anyway, because it is the implementation a reader can check.")
|
||||
|
||||
# ---------------------------------------------------------------- section 5: Tables 2, 3
|
||||
R("| 1 | Chandrupatla | no | 153/154 | 2787 | 0 |\n| 2 | the same rule with no safeguard at all | no | 153/154 | 2806 | 0 |\n| **3** | **base rule: tent, 3-point, projection ($c=2$)** | **no** | 153/154 | **2806** | 0 |\n| 4 | TOMS 748 | yes | 153/154 | 2820 | 0 |\n| 5 | Brent | yes | 153/154 | 2889 | 0 |\n| 12 | Dekker | no | 153/154 | 3158 | 0 |\n| 13 | ITP, per-problem oracle | yes | 153/154 | 3260 | 0 |\n| 20 | Ridders | no | 153/154 | 3313 | 0 |\n| 29 | constant-free variant: earned projection | no | 153/154 | 3568 | 0 |\n| 34 | ITP, recommended constants | yes | 153/154 | 3957 | 0 |\n| 73 | Illinois | yes | 153/154 | 7045 | 0 |\n| 79 | bisection | no | 153/154 | 7530 | 0 |\n| 244 | false position | no | 127/154 | 10560 | — |",
|
||||
"| 1 | Chandrupatla | no | 154/154 | 2595 | 0 |\n| 2 | the same rule with no safeguard at all | no | 154/154 | 2634 | 0 |\n| **3** | **base rule: tent, 3-point, projection ($c=2$)** | **no** | 154/154 | **2634** | 0 |\n| 4 | TOMS 748 | yes | 154/154 | 2636 | 0 |\n| 5 | Brent | yes | 154/154 | 2707 | 0 |\n| 11 | ITP, per-problem oracle | yes | 154/154 | 3068 | 0 |\n| 15 | Ridders | no | 154/154 | 3124 | 0 |\n| 25 | constant-free variant: earned projection | no | 154/154 | 3377 | 0 |\n| 29 | ITP, recommended constants | yes | 154/154 | 3767 | 0 |\n| 73 | bisection | no | 154/154 | 7338 | 0 |\n| 232 | Dekker | no | 153/154 | 3158 | 0 |\n| 237 | Illinois | yes | 153/154 | 7045 | 0 |\n| 244 | false position | no | 127/154 | 10560 | — |")
|
||||
R("The base rule and the same rule without any safeguard tie at 2806: the projection never binds on this set. By total, Chandrupatla's method is first with 2787, 0.7% fewer — the same order of margin as the 0.5% by which the base rule leads TOMS 748, which we read as a tie. Problem by problem the picture is the other way round: on the problems both solve the base rule beats Chandrupatla 87/24/42 (wins/ties/losses; exact two-sided sign test $p=9\\cdot10^{-5}$), TOMS 748 86/16/51, Brent 102/11/40, ITP at its recommended constants 132/3/18, the per-problem ITP oracle 121/4/28, and bisection 152/1/0. It wins twice as many problems as it loses against Chandrupatla and trails him in total because its losses are the larger ones. The constant-free variant goes 79/3/71 against Chandrupatla ($p=0.57$, a tie in problems), 77/9/67 against TOMS 748 and 78/5/70 against Brent, and loses on the total to all three.",
|
||||
"The base rule and the same rule without any safeguard tie at 2634: the projection never binds on this set. By total, Chandrupatla's method is first with 2595, 1.5% fewer; the base rule and TOMS 748 are level (2634 against 2636). Problem by problem the base rule wins against Chandrupatla 87/24/43 (wins/ties/losses; exact two-sided sign test $p=1.4\\cdot10^{-4}$), against TOMS 748 86/16/52, Brent 102/11/41, ITP at its recommended constants 132/3/19, the per-problem ITP oracle 121/4/29, and bisection 152/1/1. It wins twice as many problems as it loses against Chandrupatla and trails that method in total because its losses are the larger ones; the problems are not independent (§9), and taken by function family the comparison is 6/1/8 of 15 families, a tie. Dekker and Illinois solve 153 of 154 and are ranked after every method that solves all. The constant-free variant goes 79/3/72 against Chandrupatla ($p=0.63$, a tie in problems), 78/9/67 against TOMS 748 and 79/5/70 against Brent, and loses on the total to all three.")
|
||||
R("| 1 | similarity, $1-\\sqrt{\\lvert z\\rvert}$, bracket scale, projection | no | **41/45** | 4516 | 0 |\n| 2 | Chandrupatla | no | 40/45 | 2441 | 0 |\n| 3 | ITP, per-problem oracle | yes | 40/45 | 2647 | 0 |\n| 4 | similarity, $e^{-\\lvert z\\rvert}$, bracket scale, both guards | no | 40/45 | 2736 | 0 |\n| 6 | ITP, recommended constants | yes | 40/45 | 2896 | 0 |\n| 10 | constant-free variant: earned projection | no | 40/45 | 3020 | 0 |\n| 16 | bisection | no | 40/45 | 3090 | 0 |\n| **45** | **base rule: tent, 3-point, projection ($c=2$)** | **no** | 40/45 | **3220** | 0 |\n| 159 | TOMS 748 | yes | 40/45 | 4000 | 15 |\n| 227 | Brent | yes | 38/45 | 4115 | 18 |\n| 228 | the same rule with no safeguard at all | no | 35/45 | 4104 | 10 |",
|
||||
"| 1 | Chandrupatla | no | 45/45 | 1505 | 0 |\n| 2 | ITP, per-problem oracle | yes | 45/45 | 1675 | 0 |\n| 3 | similarity, $e^{-\\lvert z\\rvert}$, bracket scale, both guards | no | 45/45 | 1778 | 0 |\n| 5 | ITP, recommended constants | yes | 45/45 | 1946 | 0 |\n| 9 | constant-free variant: earned projection | no | 45/45 | 2073 | 0 |\n| 15 | bisection | no | 45/45 | 2136 | 0 |\n| **49** | **base rule: tent, 3-point, projection ($c=2$)** | **no** | 45/45 | **2357** | 0 |\n| 158 | TOMS 748 | yes | 45/45 | 3088 | 15 |\n| 227 | Brent | yes | 43/45 | 3238 | 18 |\n| 229 | the same rule with no safeguard at all | no | 39/45 | 3391 | 10 |")
|
||||
R("The set's nominal winner is a similarity configuration that solves one problem more than anything else, 41 of 45, at a worse total; ranking by failures first puts it on top, and we report it as such rather than by the total that would flatter our proposal. Here Chandrupatla's method is genuinely the stronger: it beats the base rule 26 problems to 9 ($p=0.006$) and by 3220 against 2441 in total. The proposed rule beats Brent 30/4/4 and TOMS 748 31/1/8 — both of which exceed the $2\\times$ bound on 18 and 15 problems — and loses to ITP 17/0/23 and to the ITP oracle 16/0/24. The wide-bracket set is where the multiplier matters (Table 1a) and where the constant-free variant is the cheaper form, 3020 against 3220. Over both sets the base rule needs 6026 and the constant-free variant 6588, against 5228 for Chandrupatla, 5907 for the ITP oracle, 6820 for TOMS 748 and 7004 for Brent.",
|
||||
"Here Chandrupatla's method is genuinely the stronger: it beats the base rule 29 problems to 11 ($p=0.006$) and by 1505 against 2357 in total. The base rule beats Brent 34/4/7 and TOMS 748 33/1/11 — which exceed $2\\times$ bisection, a bound they do not promise, on 18 and 15 problems — and loses to ITP 18/1/26 and to the ITP oracle 16/1/28. The wide-bracket set is where the multiplier matters (Table 1a) and where the constant-free variant is the cheaper form, 2073 against 2357. Over both sets the base rule needs 4991 and the constant-free variant 5450, against 4100 for Chandrupatla, 4743 for the ITP oracle, 5724 for TOMS 748 and 5945 for Brent.")
|
||||
R("| APS, no safeguard | 153/154 | 2806 | 0 |\n| APS, projection — base rule ($2\\times$ bisection) | 153/154 | 2806 | 0 |\n| APS, earned projection — constant-free (bisection + 1 step) | 153/154 | 3568 | 0 |\n| Chandrupatla, no safeguard | 35/45 | 4104 | 10 |\n| Chandrupatla, projection — base rule | 40/45 | 3220 | 0 |\n| Chandrupatla, earned projection — constant-free | **40/45** | **3020** | **0** |",
|
||||
"| APS, no safeguard | 154/154 | 2634 | 0 |\n| APS, projection — base rule ($2\\times$ bisection) | 154/154 | 2634 | 0 |\n| APS, earned projection — constant-free (bisection + 1 step) | 154/154 | 3377 | 0 |\n| Chandrupatla, no safeguard | 39/45 | 3391 | 10 |\n| Chandrupatla, projection — base rule | 45/45 | 2357 | 0 |\n| Chandrupatla, earned projection — constant-free | **45/45** | **2073** | **0** |")
|
||||
R("The projection of the base rule never binds on the canonical set, so its totals are identical to the last evaluation; on the wide-bracket set it solves five more problems for 21% fewer evaluations. The earned projection promises twice as much — a worst case of bisection plus one step instead of twice bisection — and pays for it on the canonical set, 762 evaluations or 27%, while on the wide-bracket set it is the cheapest of the three. Both are the opposite of the usual trade on at least one set, and that is the point of projecting rather than replacing: the two safeguards that replace cost 7260 and 7239 on Alefeld–Potra–Shi, against 2806.",
|
||||
"The projection of the base rule never binds on the canonical set, so its totals are identical to the last evaluation; on the wide-bracket set it solves six more problems for 30% fewer evaluations. The earned projection promises twice as much — a worst case of bisection plus one step instead of twice bisection — and pays for it on the canonical set, 743 evaluations or 28%, while on the wide-bracket set it is the cheapest of the three. Both are the opposite of the usual trade on at least one set, and that is the point of projecting rather than replacing: the two safeguards that replace cost 7068 and 7046 on Alefeld–Potra–Shi, against 2634.")
|
||||
R("On the 199 problems as they stand, every $f$ being a formula of a few operations, the base rule is the **slowest** of the pure-Python methods compared, at 32.8 ms against 18.4 for Brent, 21.1 for ITP, 14.2 for Ridders and 22.9 for bisection — while using the fewest evaluations of all of them, 4991 against 5932, 5675, 6421 and 9474. Bisection, needing nearly twice the evaluations, finishes in two thirds of our time.\n\nThose evaluation counts are *raw*: they are what the timing loop actually spent, and a failed run contributes only the evaluations it made before the budget ran out. They are therefore not the totals of §5, where a failure is charged the full 200-evaluation budget so that no method can buy a low score by giving up — 4991 raw against 6026 charged for the base rule, 5932 against 6991 for Brent (our pure-Python implementation, which is what is timed; the tables use the library's `brentq`, 7004), 9474 against 10620 for bisection. Wall-clock time can only be compared against what was really executed, so the raw counts are the right companions to the milliseconds; every comparison in §5 uses the charged ones. Both are stated to avoid the appearance of two incompatible sets of numbers for the same methods.",
|
||||
"On the 199 problems as they stand, every $f$ being a formula of a few operations, the base rule is the **slowest** of the pure-Python methods compared, at 32.8 ms against 18.4 for Brent, 21.1 for ITP, 14.2 for Ridders and 22.9 for bisection — while using the fewest evaluations of all of them, 4991 against 5932, 5675, 6421 and 9474. Bisection, needing nearly twice the evaluations, finishes in two thirds of our time. (These are the evaluations the timing loop actually spent; for the base rule and bisection, which solve every problem, they equal the totals of §5; Brent here is our pure-Python implementation, which is what is timed.)")
|
||||
R("Corollaries 1–3 predict an ordering of the nine similarity functions and of the four scales. Table 4 reports it. The prediction holds without exception for every data-derived scale: the three similarities with $c=1$ occupy the top three places and the three with $c=0$ the bottom three. For the chosen scale the two groups are indistinguishable (16102 against 15345), which is consistent — with a chosen scale nothing converges well and the ordering carries no information.",
|
||||
"Corollaries 1–3 predict that the similarities with $c=1$ come before those with $c=0$ under a data-derived scale; they say nothing about the order within a group, nor about the functions with unbounded slope. Table 4 reports it. For every data-derived scale the three similarities with $c=1$ occupy the top three places and the three with $c=0$ the bottom three. That $c=0$ is slow is the unsurprising half — a step proportional to $z^2$ is damped quadratically. For the chosen scale the two groups are indistinguishable (14983 against 14228), which is consistent — with a chosen scale nothing converges well and the ordering carries no information.")
|
||||
R("| 3-point derived | **6893** | 22315 |\n| 2-point derived | 6981 | 22206 |\n| bracket | 10279 | 19127 |\n| start (chosen) | 16102 | 15345 |",
|
||||
"| 3-point derived | **5764** | 21200 |\n| 2-point derived | 5854 | 21089 |\n| bracket | 9149 | 18015 |\n| start (chosen) | 14983 | 14228 |")
|
||||
R("Ranked individually and best over scales, the similarities come out $1-|z|$ (6560), $e^{-|z|}$ (6895), $1/(1+|z|)$ (7118), $(1+|z|)^{-2}$ (9578), $1-\\sqrt{|z|}$ (10546), $1-|z|^{1/3}$ (12002), $e^{-z^2}$ (14307), $1/(1+z^2)$ (15102), $1/\\sqrt{1+z^2}$ (16394); the scales come out 3-point (6560), 2-point (6702), bracket (9107), start (14540). Both orderings are those the law predicts, and both were predicted before the grid was run.",
|
||||
"Ranked individually and best over scales, the similarities come out $1-|z|$ (5422), $e^{-|z|}$ (5772), $1/(1+|z|)$ (5993), $(1+|z|)^{-2}$ (8455), $1-\\sqrt{|z|}$ (9411), $1-|z|^{1/3}$ (10874), $e^{-z^2}$ (13187), $1/(1+z^2)$ (13990), $1/\\sqrt{1+z^2}$ (15272); the scales come out 3-point (5422), 2-point (5564), bracket (7972), start (13423). The group order and the order of the scales are those the law predicts and were predicted before the grid was run; the order inside each group is measured, not predicted.")
|
||||
|
||||
# ---------------------------------------------------------------- section 6 (point 10)
|
||||
R("but on Chandrupatla it removes 0.275 for the similarity rule against 0.058 for Brent and 0.068 for TOMS 748 — and that comparison already flatters them, since 69 and 141 of their probes respectively fall outside the proven bracket and are excluded, against none of ours. High-order interpolation is a wager that $f$ is locally polynomial. When the wager pays, order 1.84 or 2.65 wins the endgame; when it fails, the probes are wasted.",
|
||||
"but on Chandrupatla it removes 0.275 for the similarity rule against 0.058 for Brent and 0.068 for TOMS 748. The bracket here is reconstructed from *every* sign the method has observed — the narrowest interval the evaluations prove, not the one the method keeps; Brent and TOMS 748 always probe inside their own bracket, but 69 and 141 of their probes fall outside this narrowest one and remove nothing from it, and those probes are left out of the median. High-order interpolation is a wager that $f$ is locally polynomial. When the wager pays, a high order wins the endgame; when it fails, the probe removes little.")
|
||||
|
||||
# ---------------------------------------------------------------- section 7: Table 5 and text
|
||||
R("each parameter-free and each measured on the protocol of §4; every number below is re-checked against its own sweep file by `verify_article.py`, and every configuration in Table 5 keeps the $2\\lceil\\log_2(w_0/\\varepsilon_x)\\rceil+3$ guarantee (0 violations) and solves 193 of the 199 problems.",
|
||||
"each parameter-free and each measured on the protocol of §4; every number below is re-checked against its own sweep file by `verify_article.py`, and every configuration in Table 5 keeps the $2\\lceil\\log_2(w_0/\\varepsilon_x)\\rceil+3$ guarantee (0 violations) and solves all 199 problems.")
|
||||
R("| configuration (all with the guarantee, 193/199) | APS-154 | CHA-45 | both |\n|---|---|---|---|\n| base rule: tent, 3-point, projection $c=2$ (§3) | 2806 | 3220 | 6026 |\n| constant-free variant: earned projection (§3.1) | 3568 | 3020 | 6588 |\n| (1) trust before the step, projection | 2848 | 3114 | 5962 |\n| (1)+(2) points chosen by shape, *safe* | **2527** | 3126 | 5653 |\n| (1)+(3) far end by dissimilarity, projection | 2726 | **2799** | **5525** |\n| (1)+(2)+(3), *safe* | 2884 | 2871 | 5755 |\n| Chandrupatla | 2787 | 2441 | 5228 |\n| TOMS 748 | 2820 | 4000 | 6820 |\n| ITP, per-problem oracle | 3260 | 2647 | 5907 |",
|
||||
"| configuration (all with the guarantee, 199/199) | APS-154 | CHA-45 | both |\n|---|---|---|---|\n| base rule: tent, 3-point, projection $c=2$ (§3) | 2634 | 2357 | 4991 |\n| constant-free variant: earned projection (§3.1) | 3377 | 2073 | 5450 |\n| (1) trust before the step, projection | 2663 | 2170 | 4833 |\n| (1)+(2) points chosen by shape, *safe* | **2337** | 2177 | 4514 |\n| (1)+(3) far end by dissimilarity, projection | 2539 | **1864** | **4403** |\n| (1)+(2)+(3), *safe* | 2695 | 1928 | 4623 |\n| Chandrupatla | 2595 | 1505 | 4100 |\n| TOMS 748 | 2636 | 3088 | 5724 |\n| ITP, per-problem oracle | 3068 | 1675 | 4743 |")
|
||||
R("First, the canonical set improves from 2806 to **2527**, which is below every method measured, including Chandrupatla's 2787, with the worst-case guarantee intact. It hardly feels the declared multiplier of §3.1: 2527 for every multiplier from 1.5 to 4, 2541 at 1.25 (`measure_records_vs_multiplier.py`). Second, on the two sets together the 5525 of reading (3) passes ITP's oracle (5907) but not Chandrupatla (5228): the remaining gap is entirely on the wide-bracket families, where Chandrupatla needs 2441 against our 2695 (reading (3) under *safe*).",
|
||||
"First, the canonical set improves from 2634 to **2337**, which is below every method measured, including Chandrupatla's 2595, with the worst-case guarantee intact. It hardly feels the declared multiplier of §3.1: 2337 for every multiplier from 1.5 to 4, 2351 at 1.25 (`measure_records_vs_multiplier.py`). Second, on the two sets together the 4403 of reading (3) passes ITP's oracle (4743) but not Chandrupatla (4100): the remaining gap is entirely on the wide-bracket families, where Chandrupatla needs 1505 against our 1752 (reading (3) under *safe*).")
|
||||
R("The readings do not compose. Taken together, (2) and (3) give 2884 and 2871 — worse than either alone on the canonical set, and on the wide-bracket set worse than (3) alone.",
|
||||
"The readings do not compose. Taken together, (2) and (3) give 2695 and 1928 — worse than either alone on the canonical set, and on the wide-bracket set worse than (3) alone.")
|
||||
R("Under the constant-free earned projection the same readings gain far less. Reading (1) gives 3507 and 2997, (1)+(2) 3755 and 3021, (1)+(3) 3857 and 3002, all three together 4354 and 3037, against 3568 and 3020 for the constant-free variant itself:",
|
||||
"Under the constant-free earned projection the same readings gain little or lose. Reading (1) gives 3316 and 2050, (1)+(2) 3564 and 2074, (1)+(3) 3666 and 2052, all three together 4163 and 2087, against 3377 and 2073 for the constant-free variant itself:")
|
||||
R("Measured over the 252 cells of the grid, the correction behaves exactly as that reading predicts and not at all as a universal improvement. Paired inside each (function, safeguard) cell of the far-end reading it is cheaper in 29 of 60 cells — indistinguishable from a coin.",
|
||||
"Measured over the grid, the correction behaves as that reading predicts and not as a universal improvement. Paired inside each (function, safeguard) cell of the far-end reading it is cheaper in 33 of 63 cells — indistinguishable from a coin.")
|
||||
R("**Table 6.** The measured order in the step place, on the far-end reading with the ratio similarity $1/(1+|z|)$. Cheaper in 7 of 7 safeguards; in 29 of 60 cells over all nine functions.",
|
||||
"**Table 6.** The measured order in the step place, on the far-end reading with the ratio similarity $1/(1+|z|)$. Cheaper in 7 of 7 safeguards; in 33 of 63 cells over all nine functions.")
|
||||
R("| both | 4522 | **3675** | 3406 | **3241** |\n| bracket | 4606 | **3542** | 3602 | **3359** |\n| credit | 5190 | **4686** | 3013 | **2884** |\n| projection | 6932 | **6364** | 4789 | **4554** |\n| safe | 5987 | **5229** | 4134 | **3954** |\n| step | 6435 | **5551** | 4287 | **4068** |\n| none | 10676 | **10043** | 8265 | **7794** |",
|
||||
"| both | 4331 | **3485** | 2469 | **2306** |\n| bracket | 4418 | **3352** | 2671 | **2428** |\n| credit | 4999 | **4495** | 2064 | **1933** |\n| projection | 6783 | **6176** | 4057 | **3751** |\n| safe | 5803 | **5040** | 3218 | **3032** |\n| step | 6251 | **5362** | 3371 | **3146** |\n| none | 10676 | **9855** | 8265 | **7424** |")
|
||||
R("the best cell it reaches on the wide-bracket set is 2884, against 2695 for reading (3) above and 2441 for Chandrupatla. In the *slope* reading of §3 the same exponent is harmful, $2806\\to2854$,",
|
||||
"the best cell it reaches on the wide-bracket set is 1933, against 1752 for reading (3) above and 1505 for Chandrupatla. In the *slope* reading of §3 the same exponent is harmful, $2634\\to2703$,")
|
||||
R("In total, no. With Chandrupatla's band in our step, the wide-bracket set costs 3059 under the projection and 2892 under *credit*, against his 2441, while the canonical set rises from 2806 to 5432.",
|
||||
"In total, no. With Chandrupatla's band in our step, the wide-bracket set costs 2101 under the projection and 1942 under *credit*, against that method's own 1505, while the canonical set rises from 2634 to 5242.")
|
||||
R("Our own readings do not close it either (best 2897 on the wide-bracket set), but \"defect\" sets a new best on the canonical set: **2523** at 153/154 under the projection of the base rule, below the 2527 of reading (2) and below every method measured, with the guarantee intact — and, unlike 2527, the same for every multiplier from 1.25 to 4. Under the earned projection it gives 3545 and 2949 (6494 against 6588), the best of the readings of this section without a constant; the flat regime of §8 does better still. It refuses only 6.6% of steps, the fewest of the three. Over both sets it costs 5733 against the 5525 of reading (3), because it gives back on the wide brackets (3210) what it gains on the canonical problems — so it is a second point on the same trade, not a replacement.",
|
||||
"Our own readings do not close it either (best 1941 on the wide-bracket set), but \"defect\" gives the second-best canonical total: **2351** under the projection of the base rule, next to the 2337 of reading (2) and below every method measured, with the guarantee intact, and between 2343 and 2353 for every multiplier from 1.25 to 4. Under the earned projection it gives 3354 and 2002 (5356 against 5450), the best of the readings of this section without a constant; the flat regime of §8 does better still. It refuses only 6.6% of steps, the fewest of the three. Over both sets it costs 4697 against the 4403 of reading (3), because it gives back on the wide brackets (2346) what it gains on the canonical problems — so it is a second point on the same trade, not a replacement.")
|
||||
|
||||
# ---------------------------------------------------------------- 7.3: the artefact, and why one criterion
|
||||
R("### 7.3 Six problems of the two sets are scored unsolved for every method",
|
||||
"### 7.3 Why the criterion is a sign change: six problems the published root cannot score")
|
||||
R("The consequence is arithmetic. Each such problem charges the full budget of 200 evaluations to every method: about 1150 evaluations of every reported two-set total — ours, Chandrupatla's, TOMS 748's, ITP's, Brent's, bisection's — are this artefact, and the \"153 of 154\" and \"40 of 45\" that every method reports are statements about the scoring rather than about the methods. Re-scored with the criterion \"a root is a root\" ($|x-\\text{root}|\\le10^{-6}$ *or* $f(x)=0$), the same runs solve 199 of 199 for every method except Brent's 197, and the totals fall as follows.",
|
||||
"The consequence is arithmetic. Each such problem charges the full budget of 200 evaluations to every method, so about 1150 evaluations of every two-set total under the harness — ours and every competitor's — are this artefact, and the \"153 of 154\" and \"40 of 45\" that every method reports under the harness are statements about the scoring rather than about the methods. This is why every number in this paper uses the bracketing criterion of §4, a sign change within $10^{-6}$ of the returned point or $f=0$ there: under it Chandrupatla, TOMS 748, ITP, bisection and every configuration of Table 5 solve all 199, Brent 197, Dekker and Illinois 178 and 177.")
|
||||
R("**Table 7.** The same runs under the harness criterion and under \"a root is a root\". The ranking is unchanged; the magnitudes are not, and neither is the size of the remaining gap on the wide-bracket set: 235 evaluations, or 16%, not 10%.\n\n| method | APS as scored | APS re-scored | CHA as scored | CHA re-scored |\n|---|---|---|---|---|\n| ours, (1)+(2) points by shape | **2527** | **2337** | 3108 | 2159 |\n| ours, base rule (projection) | 2806 | 2634 | 3220 | 2357 |\n| Chandrupatla | 2787 | 2595 | **2441** | **1505** |\n| TOMS 748 | 2820 | 2636 | 4000 | 3088 |\n| Brent | 2889 | 2707 | 4115 | 3238 |\n| ITP | 3957 | 3767 | 2896 | 1907 |\n| bisection | 7530 | 7338 | 3090 | 2136 |\n",
|
||||
"")
|
||||
|
||||
# ---------------------------------------------------------------- 7.4 (internal inconsistency)
|
||||
R("The endgame is not the cause — our observed order on those very problems is the higher one (3.63 against 2.02 on the $2\\times10^4$-wide bracket). The cause is the rate of progress far from the root:",
|
||||
"The endgame is not the cause; the cost is incurred far from the root:")
|
||||
R("It is not the guarantee that caps us. With the safeguard removed entirely the same problems cost 46, 57, 61 and 68 against bisection's 57, 77, 45 and 45 — better on the wide brackets, *worse than bisection* on `fun3.1` and `fun5.1` — and still far from Chandrupatla's 24 and 44.",
|
||||
"It is not the guarantee that caps us. (The five costs above are under the *safe* safeguard; under the projection of the base rule they are 7, 12, 30, 46, 57.) With the safeguard removed entirely the two widest brackets, `fun1.4` and `fun1.5`, cost 46 and 57: better than bisection's 57 and 77, still far from Chandrupatla's 24 and 44. Unguarded, the rule is worse than bisection elsewhere — 61 and 68 against 45 on the flat problems `fun3.1` and `fun5.1` — which is what the guarantee is for.")
|
||||
R("That mechanism is right for `fun1` and *wrong as a statement about the whole gap*. Replaying our own trajectories on the 33 problems where we lose, and placing both models on the *same* evaluations — one extra evaluation each, from the same state — splits the 256 evaluations of the gap in two. On `fun1` (58 of them, about a quarter)",
|
||||
"That mechanism is right for `fun1` and *wrong as a statement about the whole gap*. Replaying our own trajectories on the 35 problems where we lose, and placing both models on the *same* evaluations — one extra evaluation each, from the same state — splits the 262 evaluations of the gap in two. On `fun1` (58 of them, about a fifth)")
|
||||
R("(verified on all 428 non-degenerate states; in the other three the negative weight underflowed to $-0$).",
|
||||
"(verified on all 431 non-degenerate states; in the other three the negative weight underflowed to $-0$).")
|
||||
R("But 172 of the 256 — two thirds — sit on `fun3`–`fun6`,",
|
||||
"But 172 of the 262 — two thirds — sit on `fun3`–`fun6`,")
|
||||
R("bracket progress with \"the step has not moved the bracket yet\" (4449 on the canonical set, §10), and the local order with nothing at all — $m\\ge2$ is exactly the condition under which a tangent step loses to a halving, since it lands at $e(1-1/m)$, and it is clean (0.2% of canonical states) but blind:",
|
||||
"bracket progress with \"the step has not moved the bracket yet\" (4258 on the canonical set, §10), and the local order with nothing at all — $m\\ge2$ is exactly the condition under which a tangent step loses to a halving, since it lands at $e(1-1/m)$, and it is clean (0.3% of canonical states) but blind:")
|
||||
R("On the re-scored wide-bracket set of Table 7 our shape reading (2159) is *worse* than bisection (2136); only the dissimilarity reading (1740) is clearly ahead,",
|
||||
"On the wide-bracket set our shape reading (2177) is *worse* than bisection (2136); only the dissimilarity reading (1752 under *safe*) is clearly ahead,")
|
||||
R("Every statement in §§7.3–7.4 is reproduced by `diag_rescore_cha.py`, `diag_rescore_aps.py`, `diag_fun7_root.py`, `diag_cha_gap.py`,",
|
||||
"Every statement in §§7.3–7.4 is reproduced by `diag_fun7_root.py`, `diag_cha_gap.py`, `diag_who_caps_us.py`,")
|
||||
|
||||
# ---------------------------------------------------------------- section 8
|
||||
R("Replacing the one flagged step by a halving costs the canonical set 2806 → 3029,",
|
||||
"Replacing the one flagged step by a halving costs the canonical set 2634 → 2839,")
|
||||
R("A sticky halving without this exit cost the canonical set 6897; with it, 3125 — the exit is what makes a false entry cheap.",
|
||||
"A sticky halving without this exit cost the canonical set 6707; with it, 2935 — the exit is what makes a false entry cheap.")
|
||||
R("and removing it alone takes the canonical set from 2806 to 2564.",
|
||||
"and removing it alone takes the canonical set from 2634 to 2392.")
|
||||
R("**Table 8.** A′ on the protocol of §4 (published roots, failures charged 200). Per problem against each rival: wins/ties/losses, exact two-sided sign test.\n\n| | APS-154 | CHA-45 | both | vs A′ per problem, APS | vs A′ per problem, CHA |\n|---|---|---|---|---|---|\n| **A′ (proposed)** | **2438** | **2005** | **4443** | — | — |\n| A′, earned budget (no free constant) | 3608 | 2807 | 6415 | | |\n| base rule (§3) | 2806 | 3220 | 6026 | | |\n| Chandrupatla | 2787 | 2441 | 5228 | A′ 103/20/30, $p=1.5\\cdot10^{-10}$ | A′ 29/4/7, $p=3\\cdot10^{-4}$ |\n| TOMS 748 | 2820 | 4000 | 6820 | A′ 127/6/20 | A′ 38/2/0 |\n| Brent | 2889 | 4115 | 7004 | A′ 118/17/18 | A′ 33/3/2 |\n| ITP, per-problem oracle | 3260 | 2647 | 5907 | A′ 126/7/20 | A′ 35/1/4 |\n| ModAB [10, 20] | 2914 | 2436 | 5350 | A′ 118/11/25 | A′ 32/9/4 |\n\nA′ is 12.5% below Chandrupatla on the canonical set and 17.9% below on the wide-bracket set, and beats every rival problem by problem on both. On the wide-bracket families it is ahead on seven of nine, level on `fun7` (the scoring artefact of §7.3) and behind on `fun9`, 65 against 55. The earned-budget form keeps its constant-free guarantee of bisection plus one step and pays for it as in §3.1.",
|
||||
"**Table 8.** A′ on the two sets of §4 (failures charged 200). A′'s wins/ties/losses against each rival over all problems of the set, exact two-sided sign test.\n\n| | APS-154 | CHA-45 | both | A′ per problem, APS | A′ per problem, CHA |\n|---|---|---|---|---|---|\n| **A′ (proposed)** | **2259** | **1074** | **3333** | — | — |\n| A′, earned budget (no free constant) | 3417 | 1852 | 5269 | | |\n| base rule (§3) | 2634 | 2357 | 4991 | | |\n| Chandrupatla | 2595 | 1505 | 4100 | 103/20/31, $p=3\\cdot10^{-10}$ | 31/4/10, $p=0.001$ |\n| TOMS 748 | 2636 | 3088 | 5724 | 127/6/21 | 42/2/1 |\n| Brent | 2707 | 3238 | 5945 | 118/17/19 | 39/3/3 |\n| ITP, per-problem oracle | 3068 | 1675 | 4743 | 126/7/21 | 35/1/9 |\n| ModAB [10, 20] | 2726 | 1681 | 4407 | 118/10/26 | 34/4/7 |\n\nA′ is 12.9% below Chandrupatla on the canonical set and 28.6% below on the wide-bracket set, and wins more problems than it loses against every rival on both. By function family, the unit in which these problems are independent (§9), it is ahead of Chandrupatla on 8 of the 15 canonical families (6 behind, one level) and on 7 of the 9 wide-bracket families — too few families for either count to be significant ($p=0.79$, $0.18$). The two it is behind on are `fun7`, 69 against 64, and `fun9`, 65 against 55. The earned-budget form keeps its constant-free guarantee of bisection plus one step and pays for it as in §3.1.")
|
||||
R("**Table 9a.** The similarity in the step of A′: the same method with each of the nine similarity functions of §5.3 in place of the tent, everything else unchanged. Totals on the protocol of §4 and over the six corpora of §9 (uniform criterion); the guarantee holds with every function.\n\n| $S$ in the step | APS + CHA | six corpora (855) |\n|---|---|---|\n| **tent $1-|z|$ (A′)** | **4443** | **13032** |\n| $e^{-|z|}$ | 4988 | 14142 |\n| $1/(1+|z|)$ | 5486 | 14843 |\n| $(1+|z|)^{-2}$ | 8360 | 28500 |\n| $1-\\sqrt{|z|}$ | 12718 | 45552 |\n| $1-|z|^{1/3}$ | 17207 | 63031 |\n| $e^{-z^2}$ | 18410 | 67701 |\n| $1/\\sqrt{1+z^2}$ | 18412 | 67854 |\n| $1/(1+z^2)$ | 18422 | 67394 |\n\nThe similarity in the step earns its place in the proposed method as it did in the base rule: the nearest other function costs 12% more on the canonical protocol and 9% more over the six corpora, the functions that approach 1 quadratically cost four to five times more, and the ranking is the one the contraction law of §2.2 predicts, the three functions with a linear approach first and the three with a quadratic approach last.",
|
||||
"**Table 9a.** The similarity in the step of A′: the same method with each of the nine similarity functions of §5.3 in place of the tent, everything else unchanged. Totals on the two sets of §4 and over the six corpora of §9; the guarantee holds with every function.\n\n| $S$ in the step | APS + CHA | six corpora (855) |\n|---|---|---|\n| **tent $1-|z|$ (A′)** | **3333** | **13032** |\n| $e^{-|z|}$ | 3965 | 14142 |\n| $1/(1+|z|)$ | 4424 | 14843 |\n| $(1+|z|)^{-2}$ | 7249 | 28500 |\n| $1-\\sqrt{|z|}$ | 11613 | 45552 |\n| $1-|z|^{1/3}$ | 16094 | 63031 |\n| $e^{-z^2}$ | 17429 | 67701 |\n| $1/(1+z^2)$ | 17452 | 67394 |\n| $1/\\sqrt{1+z^2}$ | 17487 | 67854 |\n\nThe nearest other function costs 19% more on the two sets and 9% more over the six corpora, and the functions that approach 1 quadratically cost five times more; the three functions with a linear approach come first and the three with a quadratic approach last, as the contraction law of §2.2 predicts. What this measures should be said plainly: with the tent the step is the undamped Newton step clipped to the bracket, and the other functions damp it, so the table shows that the undamped step is the better one — expected, and evidence for the choice of $S$ within the rule rather than for the similarity framing as such.")
|
||||
|
||||
# ---------------------------------------------------------------- section 9
|
||||
R("Every decision above was taken on the two sets of §4. Pre-registration protects each decision but not the chain: the final configuration was selected on the same 199 problems.",
|
||||
"Every decision above was taken on the two sets of §4. Pre-registration protects each decision but not the chain: the final configuration — a decision layer of about ten discrete rules, chosen among the many candidates listed in §10 — was selected on the same 199 problems.")
|
||||
R("4. **Corpus 4** — 240 problems in six new families (seed 20260922): random polynomials with a simple root, polynomials with a multiple root, fractional powers $|x-r|^p$ with $p\\sim U(0.15,0.95)$, sums of exponentials and sines, compositions $\\tanh$, $\\arctan$, $\\log(1+q^2)$ of a cubic, and functions odd about the root. The code of A′ was committed *before* this corpus was run, and nothing was changed after.",
|
||||
"4. **Corpus 4** — 240 problems in six new families (seed 20260922): random polynomials with a simple root, polynomials with a multiple root, fractional powers $|x-r|^p$ with $p\\sim U(0.15,0.95)$, sums of exponentials and sines, compositions $\\tanh$, $\\arctan$, $\\log(1+q^2)$ of a cubic, and functions odd about the root. The code of A′ was committed *before* this corpus was run, and nothing was changed after. The families were chosen by the author, who knew by then where the method is strong: two of the six (multiple roots, fractional powers) are the regime §8 was built for.\n\nA root must carry a sign change to be bracketed, so the multiple roots in these corpora have odd multiplicity (3, 5, 7, 9 in corpus 4) or the form $\\operatorname{sign}(x-r)|x-r|^p$ (corpora 1 and 4).")
|
||||
R("| corpus | A′ | Chandrupatla | ModAB | Brent | TOMS 748 |\n|----------------------|------------|--------------|------------|------------|------------|\n| APS (154) | **2259** (0) | 2595 (0) | 2726 (0) | 2707 (0) | 2636 (0) |\n| Chandrupatla (45) | **1074** (0) | 1505 (0) | 1681 (0) | 3238 (18) | 3088 (15) |\n| new corpus 1 (206) | **3290** (0) | 3716 (0) | 3809 (1) | 6395 (38) | 5746 (22) |\n| Roots.jl (78) | **1371** (0) | 1566 (0) | 1446 (0) | 2455 (11) | 2339 (9) |\n| applied + GSL (132) | 1382 (0) | 1382 (0) | 1460 (0) | 1503 (1) | 1756 (1) |\n| **corpus 4 (240), the one test** | **3656** (0) | 5717 (0) | 5535 (8) | 8267 (50) | 8084 (37) |\n| all 855 | **13032** | 16481 | 16657 | 24565 | 23649 |",
|
||||
"| corpus | A′ | Chandrupatla | ModAB | ITP | ITP oracle | Brent | TOMS 748 |\n|----------------------|------------|--------------|------------|------------|------------|------------|------------|\n| APS (154) | **2259** (0) | 2595 (0) | 2726 (0) | 3767 (0) | 3068 (0) | 2707 (0) | 2636 (0) |\n| Chandrupatla (45) | **1074** (0) | 1505 (0) | 1681 (0) | 1946 (0) | 1675 (0) | 3238 (18) | 3088 (15) |\n| new corpus 1 (206) | **3290** (0) | 3716 (0) | 3809 (1) | 5674 (0) | 4707 (0) | 6395 (38) | 5746 (22) |\n| Roots.jl (78) | **1371** (0) | 1566 (0) | 1446 (0) | 2161 (0) | 1629 (0) | 2455 (11) | 2339 (9) |\n| applied + GSL (132) | 1382 (0) | 1382 (0) | 1460 (0) | 3245 (0) | 2386 (0) | 1503 (1) | 1756 (1) |\n| **corpus 4 (240), the one test** | **3656** (0) | 5717 (0) | 5535 (8) | 5721 (0) | 4832 (0) | 8267 (50) | 8084 (37) |\n| all 855 | **13032** | 16481 | 16657 | 22514 | 18297 | 24565 | 23649 |")
|
||||
R("Only the last line of corpora is evidence for A′ in the strict sense; the first five were seen while it was developed and are reported as a description.",
|
||||
"Only the last line of corpora is evidence for A′ in the strict sense; the first five were seen while it was developed and are reported as a description. ITP, at its recommended constants and as the per-problem oracle, keeps its own bound of bisection plus $n_0$ everywhere and is behind A′ on every corpus.\n\n**Independence.** A sign test counts problems as independent draws, and not all of them are. In the two canonical sets one function appears with several brackets or parameters, so the independent unit is the function family (15 in APS, 9 in CHA); at that level the counts of Table 8 are not significant, because there are too few families. In corpora 1 and 4 every problem is drawn independently from its family's generator, so the per-problem test is valid — for the population those generators define, which the author chose (above).")
|
||||
R("**What the evidence supports, and what it does not.** Against Brent and TOMS 748 A′ is ahead on every corpus, by 8% to 67% in total, and it keeps its bound on all 855 problems, which Brent breaks on 118 and TOMS 748 on 84.",
|
||||
"**What the evidence supports, and what it does not.** Against Brent and TOMS 748 A′ is ahead on every corpus, by 8% to 67% in total, and it stays within its own bound of twice bisection on all 855 problems, a bound that Brent exceeds on 118 and TOMS 748 on 84 — neither promises it.")
|
||||
R("ModAB breaks the bound on 9 problems.",
|
||||
"ModAB exceeds that bound, which it does not promise either, on 9 problems.")
|
||||
|
||||
# ---------------------------------------------------------------- section 10
|
||||
R("2. **Every safeguard that replaces the step destroys the order.** Bracket-based and step-based replacement both drop the three-point rule from order 1.94 to 1.00 and cost 7260 and 7239 evaluations on Alefeld–Potra–Shi.",
|
||||
"2. **Every safeguard that replaces the step destroys the order.** Bracket-based and step-based replacement both make the three-point rule converge linearly and cost 7068 and 7046 evaluations on Alefeld–Potra–Shi.")
|
||||
R("3. **Zero slack in the projection is not the degenerate case it was said to be.** An earlier version reported that a worst case of exactly bisection leaves the projection no freedom and makes the guard behave as bisection. Measured (Table 1a), multiplier 1 costs 4817 and 2997, against bisection's 7530 and 3090 — and on the wide-bracket set it beats the multiplier of 2. It remains the most expensive multiplier on the canonical set, which is all that survives of the claim.",
|
||||
"3. **Zero slack in the projection is not a degenerate case.** A worst case of exactly bisection might be expected to leave the projection no freedom and make the guard behave as bisection. Measured (Table 1a), multiplier 1 costs 4625 and 2039, against bisection's 7338 and 2136 — and on the wide-bracket set it beats the multiplier of 2. It is the most expensive multiplier on the canonical set.")
|
||||
R("But the same similarity over the whole Chandrupatla set costs 4109 against 3220, so a switch chosen per benchmark is worse than no switch at all: 6915 against 6026 over both sets.",
|
||||
"But the same similarity over the whole Chandrupatla set costs 3204 against 2357, so a switch chosen per benchmark is worse than no switch at all: 5838 against 4991 over both sets.")
|
||||
R("It preserves the order (2.001) and improves the eight standard problems (82 against 84) — and loses on the full benchmark, 6304 against 6026.",
|
||||
"It improves the eight standard problems (82 against 84) — and loses on the full benchmark, 5336 against 4991.")
|
||||
R("A cruder variant, correcting by the fraction of its own promise the previous step kept, fails everything: the order collapses to 0.904 and the standard problems double to 161.",
|
||||
"A cruder variant, correcting by the fraction of its own promise the previous step kept, fails everything: the convergence becomes sublinear and the standard problems double to 161.")
|
||||
R("6. **One problem is scored unsolved for every method**, `aps.13.00`, $f(x)=x e^{-1/x^2}$, all of whose derivatives vanish at the root and which underflows to exactly zero throughout $|x|<0.086$. Every method returns a point where $f(x)=0$ exactly — a genuine root — which the harness scores as a failure because it lies more than $10^{-6}$ from the declared root. It is a property of the scoring, not a failure of the methods; §7.3 finds five more such problems in the wide-bracket set.",
|
||||
"6. **The harness scores one canonical problem unsolved for every method**, `aps.13.00`, $f(x)=x e^{-1/x^2}$, all of whose derivatives vanish at the root and which underflows to exactly zero throughout $|x|<0.086$. Every method returns a point where $f(x)=0$ exactly — a genuine root — which the harness scores as a failure because it lies more than $10^{-6}$ from the declared root. With the five `fun7` problems of §7.3 it is why this paper scores by a sign change.")
|
||||
R("costs 4449 on the canonical set against 2527 — a difference of 1922 evaluations for one choice of criterion. A secant step routinely collapses the error while barely moving the proven bracket, so bracket progress rejects steps that were excellent; this is the same mechanism that makes the bracket guard of §3.1 cost 7260.",
|
||||
"costs 4258 on the canonical set against 2337 — a difference of 1921 evaluations for one choice of criterion. A secant step routinely collapses the error while barely moving the proven bracket, so bracket progress rejects steps that were excellent; this is the same mechanism that makes the bracket guard of §3.1 cost 7068.")
|
||||
R("and on eight hand-picked wide problems it improves 403 evaluations to 390. Over the whole grid it is worse on both sets: 3288 on the canonical set against 2726, and 3111 on the wide-bracket set against 2695. Its apparent extra solves (194 instead of 193) are two `fun7` problems where it lands inside the flat zero region close enough to satisfy the harness — the artefact of §7.3, not a capability.",
|
||||
"and on eight hand-picked wide problems it improves 403 evaluations to 390. Over the whole grid it is worse on both sets: its best cell is 3101 on the canonical set against 2539 for the best uncapped cell of the same grid, and 1766 on the wide-bracket set against 1752.")
|
||||
R("Unguarded, the correction takes the far-end reading from 127/154 and 10676 to 128/154 and 10043 — one problem and six per cent — where Illinois, at the price of one constant (halve the stale ordinate), reaches 153/154 and 7045.",
|
||||
"Unguarded, the correction takes the far-end reading from 127/154 and 10676 to 129/154 and 9855 — two problems and eight per cent — where Illinois, at the price of one constant (halve the stale ordinate), reaches 153/154 and 7045.")
|
||||
R("for the same similarity, scale and safeguard ($(1+|z|)^{-2}$, two-point, *safe*) the wide-bracket set improves from 3695 to 3541 — but the canonical set gets worse, 5822 to 6940, against the 2806 of the base rule. An earlier version compared the 3541 with 4516, which is the total of a different configuration.",
|
||||
"for the same similarity, scale and safeguard ($(1+|z|)^{-2}$, two-point, *safe*) the wide-bracket set improves from 2759 to 2598 — but the canonical set gets worse, 5635 to 6749, against the 2634 of the base rule.")
|
||||
R("but a halving in place of each flagged step takes the canonical set from 2806 to 3029 and the wide-bracket set only from 3220 to 3198: a simple root far from convergence breaks its promises too. Requiring the promise to fail twice in a row keeps the canonical set (2803) but fires one step late, before the crossing, and replaces the most useful step of the cycle (wide brackets 3341); requiring a creep in one direction as well gives 2878 and 3354.",
|
||||
"but a halving in place of each flagged step takes the canonical set from 2634 to 2839 and the wide-bracket set only from 2357 to 2243: a simple root far from convergence breaks its promises too. Requiring the promise to fail twice in a row keeps the canonical set (2613) but fires one step late, before the crossing, and replaces the most useful step of the cycle (wide brackets 2388); requiring a creep in one direction as well gives 2688 and 2399.")
|
||||
R("Without an exit the flat families fall to 1057 — pure bisection's level — and the canonical set rises to 6897, because a false entry now lasts to the end of the run. Splitting at the order read from the failed promise, $(1-1/m)^m=r$, changes nothing: that order is $m=\\infty$ in 163 of 174 entries (6781).",
|
||||
"Without an exit the flat families fall to 1057 — pure bisection's level — and the canonical set rises to 6707, because a false entry now lasts to the end of the run. Splitting at the order read from the failed promise, $(1-1/m)^m=r$, changes nothing: that order is $m=\\infty$ in 163 of 174 entries (6591).")
|
||||
R("also at *entry* gives 3009 and 2486 against 3125 and 2503 for the exit alone:",
|
||||
"also at *entry* gives 2820 and 1532 against 2935 and 1546 for the exit alone:")
|
||||
R("Combined with the regime it was the best configuration on the two development sets (§7.2's canonical record 2523 with the flat families of §8),",
|
||||
"Combined with the regime it was the best configuration on the two development sets (§7.2's defect reading with the flat families of §8),")
|
||||
R("Remembering the analogy for the run was rejected by its own pre-registration (canonical set 2814 against 2806 without the regime), and with the split of §8.3 it is the better form (with the step pattern, wide brackets 2117 against 2221 for the analogy read in one state).",
|
||||
"Remembering the analogy for the run was rejected by its own pre-registration, under the harness scoring of the time (canonical set 2814 against 2806 without the regime; under the sign-change criterion the two are level, 2633 against 2634), and with the split of §8.3 it is the better form (with the step pattern, wide brackets 1250 against 1388 for the analogy read in one state).")
|
||||
|
||||
# ---------------------------------------------------------------- conclusion
|
||||
R("The base rule has one declared constant and carries a worst case of twice bisection plus one step. On the canonical Alefeld–Potra–Shi set it is level with TOMS 748 and with Chandrupatla's method in total and ahead of both problem by problem; on the wide-bracket set Chandrupatla is genuinely stronger (2441 against 3220).",
|
||||
"The base rule has one declared numerical constant, converges with Muller's order 1.839 and carries a worst case of twice bisection plus one step. On the canonical Alefeld–Potra–Shi set it is level with TOMS 748 in total and 1.5% behind Chandrupatla's method, while winning more problems than it loses against both; on the wide-bracket set Chandrupatla is genuinely stronger (1505 against 2357).")
|
||||
R("The claim the measurements support is a lead over Brent, TOMS 748 and ModAB everywhere, with the guarantee they do not keep,",
|
||||
"The claim the measurements support is a lead over Brent, TOMS 748, ITP and ModAB everywhere, within a bound of twice bisection that Brent, TOMS 748 and ModAB do not promise and exceed,")
|
||||
R("It is not in the shape of $S$ — nine shapes were tried and their ranking is dictated by a single number, the slope of $1-S$ at the origin.",
|
||||
"It is not in the shape of $S$ — nine shapes were tried and which group of them comes first is dictated by a single number, the slope of $1-S$ at the origin.")
|
||||
|
||||
|
||||
def main():
|
||||
src = open(PATH, encoding="utf8").read()
|
||||
bad = [old[:90] for old, _ in REPL if src.count(old) != 1]
|
||||
if bad:
|
||||
for b in bad:
|
||||
print("ANCHOR NOT FOUND EXACTLY ONCE:", b)
|
||||
raise SystemExit(f"{len(bad)} anchors failed; nothing written")
|
||||
for old, new in REPL:
|
||||
src = src.replace(old, new)
|
||||
open(PATH, "w", encoding="utf8").write(src)
|
||||
print(f"applied {len(REPL)} replacements")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,48 @@
|
||||
"""Revision point 3: the diagnosis scripts that verify_article.py runs score a run by the
|
||||
paper's single criterion (a sign change within 1e-6 or f(x) == 0), and the audit of the
|
||||
similarity places reads the re-scored sweeps. Exact anchors, counted, or nothing is written.
|
||||
|
||||
python -u apply_diag_uniform.py
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
EDITS = {
|
||||
"diag_model_order.py": [
|
||||
(" if c and math.isfinite(float(x)) and abs(float(x) - r) <= ACC:",
|
||||
" if c and solved(f, float(x)):", 1),
|
||||
(" if not (conv and abs(float(x) - r) <= ACC):",
|
||||
" if not (conv and solved(f, float(x))):", 1),
|
||||
("XTOL, MAXFEV, ACC = 1e-12, 200, 1e-6",
|
||||
"XTOL, MAXFEV, ACC = 1e-12, 200, 1e-6\n"
|
||||
"# success = the paper's single criterion since 2026-09-22 (revision point 3)\n"
|
||||
"from corpus_roots_jl import solved # noqa: E402", 1),
|
||||
],
|
||||
"diag_model_order_checks.py": [
|
||||
(" if not (conv and abs(float(x) - r) <= ACC):",
|
||||
" if not (conv and solved(f, float(x))):", 1),
|
||||
("from diag_model_order import ACC, MAXFEV, OURS, XTOL, ch_cost, iqi",
|
||||
"from diag_model_order import ACC, MAXFEV, OURS, XTOL, ch_cost, iqi, solved", 1),
|
||||
],
|
||||
"diag_flat_detectable.py": [
|
||||
(" if not (conv and abs(float(x) - r) <= ACC):",
|
||||
" if not (conv and solved(f, float(x))):", 1),
|
||||
("from diag_model_order import ACC, MAXFEV, OURS, XTOL",
|
||||
"from diag_model_order import ACC, MAXFEV, OURS, XTOL, solved", 1),
|
||||
],
|
||||
"audit_similarity_places.py": [
|
||||
("def load(path):\n with open(path, encoding=\"utf8\") as fh:\n return json.load(fh)\n",
|
||||
"def load(path):\n \"\"\"The sweep re-scored under the paper's single criterion (sweep_uniform.json).\"\"\"\n"
|
||||
" from rescore_uniform import load_uniform\n return load_uniform(path)\n", 1),
|
||||
],
|
||||
}
|
||||
|
||||
new = {}
|
||||
for path, edits in EDITS.items():
|
||||
src = open(path, encoding="utf8").read()
|
||||
for old, rep, count in edits:
|
||||
assert src.count(old) == count, (path, old[:60], src.count(old))
|
||||
src = src.replace(old, rep)
|
||||
new[path] = src
|
||||
for path, src in new.items():
|
||||
open(path, "w", encoding="utf8").write(src)
|
||||
print("edited", ", ".join(new))
|
||||
@@ -0,0 +1,523 @@
|
||||
"""Revision 1: verify_article.py checks the numbers of the revised text (single criterion,
|
||||
head-to-head over every problem) and the new claims (order, ITP in Table 10, families,
|
||||
negative items 5 and 9, section 7.3's solved counts). Exact anchors, each found exactly
|
||||
once, or nothing is written.
|
||||
|
||||
python -u apply_verify_revision1.py
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
PATH = "verify_article.py"
|
||||
REPL = []
|
||||
|
||||
|
||||
def R(old, new):
|
||||
REPL.append((old, new))
|
||||
|
||||
|
||||
# ---- main(): the base rule, its head-to-head, the earned variant, the replacing guards
|
||||
R(''' for setname, pl, tot, sol in (("APS", 3, 2806, 153),
|
||||
("CHA", 45, 3220, 40)):''',
|
||||
''' for setname, pl, tot, sol in (("APS", 3, 2634, 154),
|
||||
("CHA", 49, 2357, 45)):''')
|
||||
R(''' + row(rows, "CHA", PROPOSED)["total"], 6026)
|
||||
|
||||
print("\\nHead to head of the proposed method:")''',
|
||||
''' + row(rows, "CHA", PROPOSED)["total"], 4991)
|
||||
|
||||
print("\\nHead to head of the proposed method:")''')
|
||||
R(''' ("APS", "chandrupatla", (87, 24, 42)),
|
||||
("APS", "toms748", (86, 16, 51)),
|
||||
("APS", "brent", (102, 11, 40)),
|
||||
("APS", "itp", (132, 3, 18)),
|
||||
("APS", "itp_oracle", (121, 4, 28)),
|
||||
("APS", "bisection", (152, 1, 0)),
|
||||
("CHA", "chandrupatla", (9, 5, 26)),
|
||||
("CHA", "toms748", (31, 1, 8)),
|
||||
("CHA", "brent", (30, 4, 4)),
|
||||
("CHA", "itp", (17, 0, 23)),
|
||||
("CHA", "itp_oracle", (16, 0, 24))]:''',
|
||||
''' ("APS", "chandrupatla", (87, 24, 43)),
|
||||
("APS", "toms748", (86, 16, 52)),
|
||||
("APS", "brent", (102, 11, 41)),
|
||||
("APS", "itp", (132, 3, 19)),
|
||||
("APS", "itp_oracle", (121, 4, 29)),
|
||||
("APS", "bisection", (152, 1, 1)),
|
||||
("CHA", "chandrupatla", (11, 5, 29)),
|
||||
("CHA", "toms748", (33, 1, 11)),
|
||||
("CHA", "brent", (34, 4, 7)),
|
||||
("CHA", "itp", (18, 1, 26)),
|
||||
("CHA", "itp_oracle", (16, 1, 28))]:''')
|
||||
R(''' check("APS vs Chandrupatla sign test p < 1e-4", sign_p(w, l) < 1e-4, True)''',
|
||||
''' check("APS vs Chandrupatla sign test p (2 digits)", float(f"{sign_p(w, l):.2g}"), 0.00014)''')
|
||||
R(''' for setname, pl, tot in (("APS", 29, 3568), ("CHA", 10, 3020)):''',
|
||||
''' for setname, pl, tot in (("APS", 25, 3377), ("CHA", 9, 2073)):''')
|
||||
R(''' + row(rows, "CHA", CREDIT)["total"], 6588)
|
||||
check("credit costs 762 more on the canonical set",
|
||||
row(rows, "APS", CREDIT)["total"] - row(rows, "APS", PROPOSED)["total"], 762)
|
||||
for setname, opp, want in [("APS", "chandrupatla", (79, 3, 71)),
|
||||
("APS", "toms748", (77, 9, 67)),
|
||||
("APS", "brent", (78, 5, 70))]:''',
|
||||
''' + row(rows, "CHA", CREDIT)["total"], 5450)
|
||||
check("credit costs 743 more on the canonical set",
|
||||
row(rows, "APS", CREDIT)["total"] - row(rows, "APS", PROPOSED)["total"], 743)
|
||||
for setname, opp, want in [("APS", "chandrupatla", (79, 3, 72)),
|
||||
("APS", "toms748", (78, 9, 67)),
|
||||
("APS", "brent", (79, 5, 70))]:''')
|
||||
R(''' check("credit APS vs Chandrupatla sign test p (rounded)", round(sign_p(w, l), 2), 0.57)''',
|
||||
''' check("credit APS vs Chandrupatla sign test p (rounded)", round(sign_p(w, l), 2), 0.63)''')
|
||||
R(''' check("APS unguarded", row(rows, "APS", "pure.ratio.derived3.none")["total"],
|
||||
2806)
|
||||
cha_none = row(rows, "CHA", "pure.ratio.derived3.none")
|
||||
check("CHA unguarded total", cha_none["total"], 4104)
|
||||
check("CHA unguarded solved", cha_none["solved"], 35)''',
|
||||
''' check("APS unguarded", row(rows, "APS", "pure.ratio.derived3.none")["total"],
|
||||
2634)
|
||||
cha_none = row(rows, "CHA", "pure.ratio.derived3.none")
|
||||
check("CHA unguarded total", cha_none["total"], 3391)
|
||||
check("CHA unguarded solved", cha_none["solved"], 39)''')
|
||||
R(''' check("APS bracket-guard", row(rows, "APS", "pure.ratio.derived3.bracket")["total"],
|
||||
7260)
|
||||
check("APS both-guard", row(rows, "APS", "pure.ratio.derived3.both")["total"],
|
||||
7239)''',
|
||||
''' check("APS bracket-guard", row(rows, "APS", "pure.ratio.derived3.bracket")["total"],
|
||||
7068)
|
||||
check("APS both-guard", row(rows, "APS", "pure.ratio.derived3.both")["total"],
|
||||
7046)''')
|
||||
# ---- the field
|
||||
R(''' for lbl, pl, tot in [("chandrupatla", 1, 2787), ("toms748", 4, 2820),
|
||||
("brent", 5, 2889), ("dekker", 12, 3158),
|
||||
("itp_oracle", 13, 3260), ("ridders", 20, 3313),
|
||||
("itp", 34, 3957), ("illinois", 73, 7045),
|
||||
("bisection", 79, 7530), ("regula_falsi", 244, 10560)]:''',
|
||||
''' for lbl, pl, tot in [("chandrupatla", 1, 2595), ("toms748", 4, 2636),
|
||||
("brent", 5, 2707), ("dekker", 232, 3158),
|
||||
("itp_oracle", 11, 3068), ("ridders", 15, 3124),
|
||||
("itp", 29, 3767), ("illinois", 237, 7045),
|
||||
("bisection", 73, 7338), ("regula_falsi", 244, 10560)]:''')
|
||||
R(''' check("CHA rank 1 label", top["label"], "pure.sqrt.bracket.project")
|
||||
check("CHA rank 1 solves one more than anyone else", top["CHA"]["solved"], 41)
|
||||
for lbl, pl, tot in [("chandrupatla", 2, 2441), ("itp_oracle", 3, 2647),
|
||||
("itp", 6, 2896), ("bisection", 16, 3090),
|
||||
("toms748", 159, 4000), ("brent", 227, 4115)]:''',
|
||||
''' check("CHA rank 1 label", top["label"], "chandrupatla")
|
||||
check("CHA rank 1 solves all 45", top["CHA"]["solved"], 45)
|
||||
for lbl, pl, tot in [("chandrupatla", 1, 1505), ("itp_oracle", 2, 1675),
|
||||
("itp", 5, 1946), ("bisection", 15, 2136),
|
||||
("toms748", 158, 3088), ("brent", 227, 3238)]:''')
|
||||
R(''' check("CHA brent solved", row(rows, "CHA", "brent")["solved"], 38)''',
|
||||
''' check("CHA brent solved", row(rows, "CHA", "brent")["solved"], 43)''')
|
||||
R(''' check("chandrupatla, both sets", cha_both, 5228)''',
|
||||
''' check("chandrupatla, both sets", cha_both, 4100)''')
|
||||
R(''' row(rows, "CHA", "pure.cbrt.derived3.project")["total"], 4109)''',
|
||||
''' row(rows, "CHA", "pure.cbrt.derived3.project")["total"], 3204)''')
|
||||
R(''' check("single fixed choice, both sets", single, 6026)
|
||||
check("switch by benchmark set, both sets", switched, 6915)''',
|
||||
''' check("single fixed choice, both sets", single, 4991)
|
||||
check("switch by benchmark set, both sets", switched, 5838)''')
|
||||
R(''' want = {("derived3", "lin"): 6893, ("derived3", "quad"): 22315,
|
||||
("derived", "lin"): 6981, ("derived", "quad"): 22206,
|
||||
("bracket", "lin"): 10279, ("bracket", "quad"): 19127,
|
||||
("start", "lin"): 16102, ("start", "quad"): 15345}''',
|
||||
''' want = {("derived3", "lin"): 5764, ("derived3", "quad"): 21200,
|
||||
("derived", "lin"): 5854, ("derived", "quad"): 21089,
|
||||
("bracket", "lin"): 9149, ("bracket", "quad"): 18015,
|
||||
("start", "lin"): 14983, ("start", "quad"): 14228}''')
|
||||
R(''' for sim, v in [("ratio", 6560), ("exp_abs", 6895), ("rational", 7118),
|
||||
("ratio_soft", 9578), ("sqrt", 10546), ("cbrt", 12002),
|
||||
("exp_sq", 14307), ("rat_sq", 15102), ("cosine", 16394)]:''',
|
||||
''' for sim, v in [("ratio", 5422), ("exp_abs", 5772), ("rational", 5993),
|
||||
("ratio_soft", 8455), ("sqrt", 9411), ("cbrt", 10874),
|
||||
("exp_sq", 13187), ("rat_sq", 13990), ("cosine", 15272)]:''')
|
||||
R(''' for sc, v in [("derived3", 6560), ("derived", 6702), ("bracket", 9107),
|
||||
("start", 14540)]:''',
|
||||
''' for sc, v in [("derived3", 5422), ("derived", 5564), ("bracket", 7972),
|
||||
("start", 13423)]:''')
|
||||
R(''' verify_flat_regime_and_oos()
|
||||
|
||||
print()''',
|
||||
''' verify_flat_regime_and_oos()
|
||||
verify_revision1()
|
||||
|
||||
print()''')
|
||||
# ---- placement modes
|
||||
R(''' "sweep_slope.json": ("slope.ratio.derived3.project", 2848, 3114),
|
||||
"sweep_points.json": ("pure+shape+slope.ratio.derived3.safe", 2527, 3126),
|
||||
"sweep_direction.json": ("pure+dissim+slope.ratio.derived3.project", 2726, 2799),
|
||||
"sweep_combo.json": ("pure+shape+dissim+slope.ratio.derived3.safe", 2884, 2871),
|
||||
"sweep_gate.json": ("progress.ratio.derived.project", 4449, 3047),
|
||||
"sweep_log.json": ("log.ratio_soft.derived.safe", 6940, 3541),''',
|
||||
''' "sweep_slope.json": ("slope.ratio.derived3.project", 2663, 2170),
|
||||
"sweep_points.json": ("pure+shape+slope.ratio.derived3.safe", 2337, 2177),
|
||||
"sweep_direction.json": ("pure+dissim+slope.ratio.derived3.project", 2539, 1864),
|
||||
"sweep_combo.json": ("pure+shape+dissim+slope.ratio.derived3.safe", 2695, 1928),
|
||||
"sweep_gate.json": ("progress.ratio.derived.project", 4258, 2093),
|
||||
"sweep_log.json": ("log.ratio_soft.derived.safe", 6749, 2598),''')
|
||||
R(''' "both": (4522, 3675, 3406, 3241),
|
||||
"bracket": (4606, 3542, 3602, 3359),
|
||||
"credit": (5190, 4686, 3013, 2884),
|
||||
"project": (6932, 6364, 4789, 4554),
|
||||
"safe": (5987, 5229, 4134, 3954),
|
||||
"step": (6435, 5551, 4287, 4068),
|
||||
"none": (10676, 10043, 8265, 7794),''',
|
||||
''' "both": (4331, 3485, 2469, 2306),
|
||||
"bracket": (4418, 3352, 2671, 2428),
|
||||
"credit": (4999, 4495, 2064, 1933),
|
||||
"project": (6783, 6176, 4057, 3751),
|
||||
"safe": (5803, 5040, 3218, 3032),
|
||||
"step": (6251, 5362, 3371, 3146),
|
||||
"none": (10676, 9855, 8265, 7424),''')
|
||||
R(''' ("rational", "far", "none", "order"): (128, 10043)}''',
|
||||
''' ("rational", "far", "none", "order"): (129, 9855)}''')
|
||||
R('''ORDER_SLOPE_HARM = {("ratio", "derived3", "none", "none"): 2806,
|
||||
("ratio", "derived3", "none", "order"): 2854}''',
|
||||
'''ORDER_SLOPE_HARM = {("ratio", "derived3", "none", "none"): 2634,
|
||||
("ratio", "derived3", "none", "order"): 2703}''')
|
||||
R(''' ("ratio", "band", "project"): {"APS": 5432, "CHA": 3059},
|
||||
("ratio", "band", "credit"): {"CHA": 2892},
|
||||
("ratio", "none", "project"): {"APS": 2806},
|
||||
("ratio", "defect", "project"): {"APS": 2523, "CHA": 3210},
|
||||
("ratio_soft", "simpair", "project"): {"CHA": 2897},''',
|
||||
''' ("ratio", "band", "project"): {"APS": 5242, "CHA": 2101},
|
||||
("ratio", "band", "credit"): {"CHA": 1942},
|
||||
("ratio", "none", "project"): {"APS": 2634},
|
||||
("ratio", "defect", "project"): {"APS": 2351, "CHA": 2346},
|
||||
("ratio_soft", "simpair", "project"): {"CHA": 1941},''')
|
||||
R(''' check("defect APS solved", d["APS"]["solved"], 153)
|
||||
check("defect both sets", d["APS"]["total"] + d["CHA"]["total"], 5733)
|
||||
check("defect is the new canonical best (< 2527)", d["APS"]["total"] < 2527, True)''',
|
||||
''' check("defect APS solved", d["APS"]["solved"], 154)
|
||||
check("defect both sets", d["APS"]["total"] + d["CHA"]["total"], 4697)
|
||||
check("defect second to the shape reading (2337 < defect)", 2337 < d["APS"]["total"], True)''')
|
||||
# ---- the gap decomposition
|
||||
R(''' check("problems where we lose", len(mo["lose"]), 33)''',
|
||||
''' check("problems where we lose", len(mo["lose"]), 35)''')
|
||||
R(''' check("non-degenerate states with one negative weight", mo["neg_ok"], 428)
|
||||
check("bracketing states in total", mo["neg_all"], 431)''',
|
||||
''' check("non-degenerate states with one negative weight", int(mo["neg_ok"]), 431)
|
||||
check("bracketing states in total", mo["neg_all"], 434)''')
|
||||
R(''' check("total gap on the losing problems", sum(gap.values()), 256)''',
|
||||
''' check("total gap on the losing problems", sum(gap.values()), 262)''')
|
||||
R(''' check("m>=2 on canonical states %", round(fl["APS (canonical)"][2], 1), 0.2)''',
|
||||
''' check("m>=2 on canonical states %", float(round(fl["APS (canonical)"][2], 1)), 0.3)''')
|
||||
R(''' check("log item: x-space control APS", xcell["APS"]["total"], 5822)
|
||||
check("log item: x-space control CHA", xcell["CHA"]["total"], 3695)''',
|
||||
''' check("log item: x-space control APS", xcell["APS"]["total"], 5635)
|
||||
check("log item: x-space control CHA", xcell["CHA"]["total"], 2759)''')
|
||||
# ---- 3.1, Tables 2-3, 5.1, section 7 under credit
|
||||
R(''' for c, (aps, cha) in ((1.0, (4817, 2997)), (1.25, (2806, 2752)), (1.5, (2806, 2889)),
|
||||
(2.0, (2806, 3220)), (3.0, (2806, 3756)), (4.0, (2806, 4006))):''',
|
||||
''' for c, (aps, cha) in ((1.0, (4625, 2039)), (1.25, (2626, 1822)), (1.5, (2636, 1991)),
|
||||
(2.0, (2634, 2357)), (3.0, (2634, 2936)), (4.0, (2634, 3229))):''')
|
||||
R(''' for c0, (aps, cha) in ((0.1, (5344, 3051)), (0.5, (4656, 3002)), (1.0, (3568, 3020)),
|
||||
(2.0, (3692, 2712)), (5.0, (3006, 2615))):''',
|
||||
''' for c0, (aps, cha) in ((0.1, (5150, 2097)), (0.5, (4462, 2037)), (1.0, (3377, 2073)),
|
||||
(2.0, (3502, 1757)), (5.0, (2819, 1666))):''')
|
||||
R(''' sh = rm["shape reading (2527)"]
|
||||
check("2527 at multiplier 1.25", sh[1.25][0], 2541)
|
||||
check("2527 flat from 1.5 to 4", {sh[f][0] for f in (1.5, 2.0, 3.0, 4.0)}, {2527})
|
||||
de = rm["defect reading (2523)"]
|
||||
check("2523 flat from 1.25 to 4", {de[f][0] for f in (1.25, 1.5, 2.0, 3.0, 4.0)}, {2523})''',
|
||||
''' sh = rm["shape reading (2527)"]
|
||||
check("shape reading at multiplier 1.25", sh[1.25][0], 2351)
|
||||
check("shape reading flat from 1.5 to 4", {sh[f][0] for f in (1.5, 2.0, 3.0, 4.0)}, {2337})
|
||||
de = rm["defect reading (2523)"]
|
||||
dv = [de[f][0] for f in (1.25, 1.5, 2.0, 3.0, 4.0)]
|
||||
check("defect reading from 1.25 to 4: range", (min(dv), max(dv)), (2343, 2353))''')
|
||||
R(''' for setname, lbl, pl in (("APS", PROJ, 3), ("APS", none_, 2), ("CHA", PROJ, 45),
|
||||
("CHA", none_, 228), ("CHA", "pure.exp_abs.bracket.both", 4)):''',
|
||||
''' for setname, lbl, pl in (("APS", PROJ, 3), ("APS", none_, 2), ("CHA", PROJ, 49),
|
||||
("CHA", none_, 229), ("CHA", "pure.exp_abs.bracket.both", 3),
|
||||
("CHA", "pure.exp_abs.bracket.bracket", 4),
|
||||
("CHA", "pure.exp_abs.bracket.credit", 6),
|
||||
("APS", CREDIT, 25), ("CHA", CREDIT, 9)):''')
|
||||
R(''' check("CHA exp_abs.bracket.both total", by["pure.exp_abs.bracket.both"]["CHA"]["total"],
|
||||
2736)''',
|
||||
''' check("CHA exp_abs.bracket.both total", by["pure.exp_abs.bracket.both"]["CHA"]["total"],
|
||||
1778)''')
|
||||
R(''' (CREDIT, "APS", "itp_oracle", (86, 6, 61)),
|
||||
(CREDIT, "CHA", "itp_oracle", (2, 2, 36)),
|
||||
(CREDIT, "CHA", "bisection", (5, 0, 35)),
|
||||
(PROJ, "APS", "chandrupatla", (87, 24, 42)),
|
||||
(PROJ, "APS", "itp", (132, 3, 18)),
|
||||
(PROJ, "APS", "itp_oracle", (121, 4, 28)),
|
||||
(PROJ, "APS", "bisection", (152, 1, 0)),
|
||||
(PROJ, "CHA", "toms748", (31, 1, 8)),
|
||||
(PROJ, "CHA", "brent", (30, 4, 4)),
|
||||
(PROJ, "CHA", "itp", (17, 0, 23)),
|
||||
(PROJ, "CHA", "itp_oracle", (16, 0, 24))):''',
|
||||
''' (CREDIT, "APS", "itp_oracle", (86, 6, 62)),
|
||||
(CREDIT, "CHA", "itp_oracle", (2, 2, 41)),
|
||||
(CREDIT, "CHA", "bisection", (5, 0, 40)),
|
||||
(PROJ, "APS", "chandrupatla", (87, 24, 43)),
|
||||
(PROJ, "APS", "itp", (132, 3, 19)),
|
||||
(PROJ, "APS", "itp_oracle", (121, 4, 29)),
|
||||
(PROJ, "APS", "bisection", (152, 1, 1)),
|
||||
(PROJ, "CHA", "toms748", (33, 1, 11)),
|
||||
(PROJ, "CHA", "brent", (34, 4, 7)),
|
||||
(PROJ, "CHA", "itp", (18, 1, 26)),
|
||||
(PROJ, "CHA", "itp_oracle", (16, 1, 28))):''')
|
||||
R(''' for lbl, want in ((CREDIT, 6588), (PROJ, 6026), ("chandrupatla", 5228),
|
||||
("itp_oracle", 5907), ("toms748", 6820), ("brent", 7004)):''',
|
||||
''' for lbl, want in ((CREDIT, 5450), (PROJ, 4991), ("chandrupatla", 4100),
|
||||
("itp_oracle", 4743), ("toms748", 5724), ("brent", 5945)):''')
|
||||
R(''' for lbl, aps, cha in (("slope.ratio.derived3.credit", 3507, 2997),
|
||||
("pure+shape+slope.ratio.derived3.credit", 3755, 3021),
|
||||
("pure+dissim+slope.ratio.derived3.credit", 3857, 3002),
|
||||
("pure+shape+dissim+slope.ratio.derived3.credit", 4354, 3037),
|
||||
("defect.ratio.derived3.credit", 3545, 2949)):''',
|
||||
''' for lbl, aps, cha in (("slope.ratio.derived3.credit", 3316, 2050),
|
||||
("pure+shape+slope.ratio.derived3.credit", 3564, 2074),
|
||||
("pure+dissim+slope.ratio.derived3.credit", 3666, 2052),
|
||||
("pure+shape+dissim+slope.ratio.derived3.credit", 4163, 2087),
|
||||
("defect.ratio.derived3.credit", 3354, 2002)):''')
|
||||
R(''' check("its total over both sets", top["APS"]["total"] + top["CHA"]["total"], 6111)''',
|
||||
''' check("its total over both sets", top["APS"]["total"] + top["CHA"]["total"], 4965)''')
|
||||
R(''' d["APS"]["total"] + d["CHA"]["total"], 6494)''',
|
||||
''' d["APS"]["total"] + d["CHA"]["total"], 5356)''')
|
||||
R(''' "sweep_direction.json": ("CHA", "pure+dissim+slope.ratio.derived3.safe", 2695),
|
||||
"sweep_gate.json": ("CHA", "progress.ratio_soft.derived.safe", 2888),''',
|
||||
''' "sweep_direction.json": ("CHA", "pure+dissim+slope.ratio.derived3.safe", 1752),
|
||||
"sweep_gate.json": ("CHA", "progress.ratio_soft.derived.safe", 1929),''')
|
||||
R(''' check(f"{lbl} solved", d["APS"]["solved"] + d["CHA"]["solved"], 193)''',
|
||||
''' check(f"{lbl} solved", d["APS"]["solved"] + d["CHA"]["solved"], 199)''')
|
||||
# ---- section 8 development grids
|
||||
R(''' ("sweep_flat.json", f"flat.{P}", 3029, 3198),
|
||||
("sweep_flat2.json", f"flat2.{P}", 2803, 3341),
|
||||
("sweep_flatcreep.json", f"flatcreep.{P}", 2878, 3354),
|
||||
("sweep_flatstick.json", f"flatstickmid.{P}", 6897, 3019),
|
||||
("sweep_flatexit.json", f"flatstickexit.{P}", 3125, 2503),
|
||||
("sweep_flatjudge.json", f"flatjudge.{P}", 3009, 2486),
|
||||
("sweep_orderpt.json", f"flatanalogmem.{P}", 2814, None),
|
||||
("sweep_half.json", f"half.{P}", 2564, None)):''',
|
||||
''' ("sweep_flat.json", f"flat.{P}", 2839, 2243),
|
||||
("sweep_flat2.json", f"flat2.{P}", 2613, 2388),
|
||||
("sweep_flatcreep.json", f"flatcreep.{P}", 2688, 2399),
|
||||
("sweep_flatstick.json", f"flatstickmid.{P}", 6707, 2063),
|
||||
("sweep_flatexit.json", f"flatstickexit.{P}", 2935, 1546),
|
||||
("sweep_flatjudge.json", f"flatjudge.{P}", 2820, 1532),
|
||||
("sweep_orderpt.json", f"flatanalogmem.{P}", 2633, None),
|
||||
("sweep_half.json", f"half.{P}", 2392, None)):''')
|
||||
R(''' _cell("sweep_flatstick.json", f"flatstick.{P}")["APS"]["total"], 6781)''',
|
||||
''' _cell("sweep_flatstick.json", f"flatstick.{P}")["APS"]["total"], 6591)''')
|
||||
R(''' op[f"pure+extP+flatanalogmempt.{P}"]["CHA"]["total"], 2117)''',
|
||||
''' op[f"pure+extP+flatanalogmempt.{P}"]["CHA"]["total"], 1250)''')
|
||||
R(''' op[f"pure+extP+flatanalogpt.{P}"]["CHA"]["total"], 2221)''',
|
||||
''' op[f"pure+extP+flatanalogpt.{P}"]["CHA"]["total"], 1388)''')
|
||||
# ---- Table 8
|
||||
R(''' check("A' APS", a["APS"]["total"], 2438)
|
||||
check("A' CHA", a["CHA"]["total"], 2005)
|
||||
check("A' both", a["APS"]["total"] + a["CHA"]["total"], 4443)
|
||||
check("A' solved", a["APS"]["solved"] + a["CHA"]["solved"], 193)
|
||||
c = apr[f"{A}.credit"]
|
||||
check("A' earned budget", (c["APS"]["total"], c["CHA"]["total"]), (3608, 2807))''',
|
||||
''' check("A' APS", a["APS"]["total"], 2259)
|
||||
check("A' CHA", a["CHA"]["total"], 1074)
|
||||
check("A' both", a["APS"]["total"] + a["CHA"]["total"], 3333)
|
||||
check("A' solved", a["APS"]["solved"] + a["CHA"]["solved"], 199)
|
||||
c = apr[f"{A}.credit"]
|
||||
check("A' earned budget", (c["APS"]["total"], c["CHA"]["total"]), (3417, 1852))''')
|
||||
R(''' for setname, opp, want in (("APS", "chandrupatla", (103, 20, 30)),
|
||||
("CHA", "chandrupatla", (29, 4, 7)),
|
||||
("APS", "toms748", (127, 6, 20)), ("CHA", "toms748", (38, 2, 0)),
|
||||
("APS", "brent", (118, 17, 18)), ("CHA", "brent", (33, 3, 2)),
|
||||
("APS", "itp_oracle", (126, 7, 20)),
|
||||
("CHA", "itp_oracle", (35, 1, 4))):''',
|
||||
''' for setname, opp, want in (("APS", "chandrupatla", (103, 20, 31)),
|
||||
("CHA", "chandrupatla", (31, 4, 10)),
|
||||
("APS", "toms748", (127, 6, 21)), ("CHA", "toms748", (42, 2, 1)),
|
||||
("APS", "brent", (118, 17, 19)), ("CHA", "brent", (39, 3, 3)),
|
||||
("APS", "itp_oracle", (126, 7, 21)),
|
||||
("CHA", "itp_oracle", (35, 1, 9))):''')
|
||||
R(''' check("A' APS vs Chandrupatla p (2 digits)", float(f"{sign_p(103, 30):.2g}"), 1.5e-10)
|
||||
check("A' CHA vs Chandrupatla p (1 digit)", float(f"{sign_p(29, 7):.1g}"), 3e-4)
|
||||
check("A' below Chandrupatla, APS %", round(100 * (1 - 2438 / 2787), 1), 12.5)
|
||||
check("A' below Chandrupatla, CHA %", round(100 * (1 - 2005 / 2441), 1), 17.9)''',
|
||||
''' check("A' APS vs Chandrupatla p (1 digit)", float(f"{sign_p(103, 31):.1g}"), 3e-10)
|
||||
check("A' CHA vs Chandrupatla p (1 digit)", float(f"{sign_p(31, 10):.1g}"), 0.001)
|
||||
check("A' below Chandrupatla, APS %", round(100 * (1 - 2259 / 2595), 1), 12.9)
|
||||
check("A' below Chandrupatla, CHA %", round(100 * (1 - 1074 / 1505), 1), 28.6)''')
|
||||
R(''' check("A' level on fun7", af["fun7"] == cf["fun7"], True)''',
|
||||
''' check("A' fun7 vs Chandrupatla", (af["fun7"], cf["fun7"]), (69, 64))''')
|
||||
# ---- ModAB in Table 8: the same single-criterion runs as Table 10
|
||||
R(''' mp = mb["protocol"]["modab"]
|
||||
check("ModAB protocol APS, CHA, both", (mp["APS"]["total"], mp["CHA"]["total"],
|
||||
mp["APS"]["total"] + mp["CHA"]["total"]),
|
||||
(2914, 2436, 5350))
|
||||
for setname, want in (("APS", (118, 11, 25)), ("CHA", (32, 9, 4))):
|
||||
am = {p: v for p, v in a[setname]["per"].items()}
|
||||
mm = mp[setname]["per"]
|
||||
w = sum(cost(am[p]) < cost(mm[p]) for p in am)
|
||||
l = sum(cost(am[p]) > cost(mm[p]) for p in am)
|
||||
check(f"A' vs ModAB protocol {setname}", (w, len(am) - w - l, l), want)''',
|
||||
''' ms = mb["seen"]["modab"]
|
||||
check("Table 8 ModAB APS, CHA, both",
|
||||
(sum(cost(v) for v in ms["APS"].values()), sum(cost(v) for v in ms["CHA"].values()),
|
||||
sum(cost(v) for s_ in ("APS", "CHA") for v in ms[s_].values())), (2726, 1681, 4407))
|
||||
for setname, want in (("APS", (118, 10, 26)), ("CHA", (34, 4, 7))):
|
||||
am = {p: v for p, v in a[setname]["per"].items()}
|
||||
mm = ms[setname]
|
||||
w = sum(cost(am[p]) < cost(mm[p]) for p in am)
|
||||
l = sum(cost(am[p]) > cost(mm[p]) for p in am)
|
||||
check(f"Table 8 A' vs ModAB {setname}", (w, len(am) - w - l, l), want)''')
|
||||
# ---- Table 9a
|
||||
R(''' t9a = {"ratio": (4443, 13032), "exp_abs": (4988, 14142), "rational": (5486, 14843),
|
||||
"ratio_soft": (8360, 28500), "sqrt": (12718, 45552), "cbrt": (17207, 63031),
|
||||
"exp_sq": (18410, 67701), "cosine": (18412, 67854), "rat_sq": (18422, 67394)}''',
|
||||
''' t9a = {"ratio": (3333, 13032), "exp_abs": (3965, 14142), "rational": (4424, 14843),
|
||||
"ratio_soft": (7249, 28500), "sqrt": (11613, 45552), "cbrt": (16094, 63031),
|
||||
"exp_sq": (17429, 67701), "cosine": (17487, 67854), "rat_sq": (17452, 67394)}''')
|
||||
R(''' check("nearest other S costs more, protocol %", round(100 * (4988 / 4443 - 1)), 12)
|
||||
check("worst S costs more, protocol %", round(100 * (18422 / 4443 - 1)), 315)''',
|
||||
''' check("nearest other S costs more, two sets %", round(100 * (3965 / 3333 - 1)), 19)
|
||||
check("worst S costs more, two sets %", round(100 * (17487 / 3333 - 1)), 425)''')
|
||||
R(''' check("quadratic S: four to five times",
|
||||
(int(18410 / 4443), int(67854 / 13032)), (4, 5))''',
|
||||
''' check("quadratic S: five times",
|
||||
(int(17429 / 3333), int(67854 / 13032)), (5, 5))''')
|
||||
|
||||
NEW_FUNC = '''
|
||||
|
||||
def verify_revision1():
|
||||
"""Revision 1 (2026-09-22): the claims added or restated by the revision - the order
|
||||
of the base step, section 7.3's solved counts, the families as the unit, ITP in Table 10,
|
||||
negative items 5 and 9, and the one canonical problem the multiplier moves. Recomputed."""
|
||||
import contextlib
|
||||
import io
|
||||
import math
|
||||
import re
|
||||
from collections import defaultdict
|
||||
print("\\nRevision 1:")
|
||||
import order_high_precision
|
||||
buf = io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
order_high_precision.main()
|
||||
out = buf.getvalue()
|
||||
check("Muller order", re.search(r"Muller order .*: ([\\d.]+)", out).group(1), "1.8393")
|
||||
for name in ("cos x - x", "exp(x) - 2", "x^3 - x - 2", "sin x - 1/2"):
|
||||
line = next(ln for ln in out.splitlines() if ln.startswith(name))
|
||||
three = line[14:54].split()
|
||||
check(f"three-point order settles, {name}", three[-2], "1.840")
|
||||
line = next(ln for ln in out.splitlines() if ln.startswith("x^2 - 2"))
|
||||
check("three-point order on x^2 - 2", line[14:54].split()[-1], "2.000")
|
||||
check("two-point order, cos x - x", next(ln for ln in out.splitlines()
|
||||
if ln.startswith("cos x - x"))[54:].split()[-1], "1.618")
|
||||
|
||||
rows = _load("sweep_full.json")
|
||||
by = {r["label"]: r for r in rows}
|
||||
solved = {k: by[k]["APS"]["solved"] + by[k]["CHA"]["solved"]
|
||||
for k in ("chandrupatla", "toms748", "itp", "bisection", "brent", "dekker",
|
||||
"illinois")}
|
||||
check("section 7.3 solved counts", solved, {"chandrupatla": 199, "toms748": 199,
|
||||
"itp": 199, "bisection": 199, "brent": 197,
|
||||
"dekker": 178, "illinois": 177})
|
||||
check("Chandrupatla fewer than the base rule, APS %",
|
||||
round(100 * (by[PROJ]["APS"]["total"] / by["chandrupatla"]["APS"]["total"] - 1), 1), 1.5)
|
||||
none_ = by["pure.ratio.derived3.none"]["CHA"]
|
||||
check("guarantee on CHA: more solved, fewer evaluations",
|
||||
(45 - none_["solved"], round(100 * (1 - by[PROJ]["CHA"]["total"] / none_["total"]))),
|
||||
(6, 30))
|
||||
check("earned costs 28% more on APS",
|
||||
round(100 * (by[CREDIT]["APS"]["total"] / by[PROJ]["APS"]["total"] - 1)), 28)
|
||||
|
||||
def cost(v):
|
||||
return v[0] if v[1] else 200
|
||||
|
||||
def fam_of(pid):
|
||||
return ".".join(pid.split(".")[:2]) if pid.startswith("aps") else pid.split(".")[0]
|
||||
|
||||
def families(a, b, s):
|
||||
ta, tb = defaultdict(int), defaultdict(int)
|
||||
for p in a[s]["per"]:
|
||||
ta[fam_of(p)] += cost(a[s]["per"][p])
|
||||
tb[fam_of(p)] += cost(b[s]["per"][p])
|
||||
w = sum(ta[k] < tb[k] for k in ta)
|
||||
l = sum(ta[k] > tb[k] for k in ta)
|
||||
return w, len(ta) - w - l, l
|
||||
|
||||
def sign_p(w, l):
|
||||
k, n = min(w, l), w + l
|
||||
return min(1.0, 2.0 * sum(math.comb(n, i) for i in range(k + 1)) / 2.0 ** n)
|
||||
ap = {r["label"]: r for r in _load("sweep_aprime.json")}[
|
||||
"pure+extP+contra+flatanalogmempt+exp+half+close+sub.ratio.derived3.project"]
|
||||
ch = by["chandrupatla"]
|
||||
check("base rule vs Chandrupatla by family, APS", families(by[PROJ], ch, "APS"), (6, 1, 8))
|
||||
check("A' vs Chandrupatla by family, APS", families(ap, ch, "APS"), (8, 1, 6))
|
||||
check("A' vs Chandrupatla by family, CHA", families(ap, ch, "CHA"), (7, 0, 2))
|
||||
check("family-level p, APS and CHA (2 digits)",
|
||||
(float(f"{sign_p(8, 6):.2g}"), float(f"{sign_p(7, 2):.2g}")), (0.79, 0.18))
|
||||
|
||||
order = _load("sweep_order.json")
|
||||
cells = {}
|
||||
for r in order:
|
||||
s = r["spec"]
|
||||
if s[2] == "far":
|
||||
cells[(s[1], s[3], s[8] if len(s) > 8 else "none")] = r["APS"]["total"] + r["CHA"]["total"]
|
||||
pairs = [(k[0], k[1]) for k in cells if k[2] == "none" and (k[0], k[1], "order") in cells]
|
||||
check("far-end reading: measured order cheaper in cells",
|
||||
(sum(cells[(s_, g, "order")] < cells[(s_, g, "none")] for s_, g in pairs), len(pairs)),
|
||||
(33, 63))
|
||||
|
||||
cap, dire = _load("sweep_cap.json"), _load("sweep_direction.json")
|
||||
for s, want in (("APS", (3101, 2539)), ("CHA", (1766, 1752))):
|
||||
bc = min(r[s]["total"] for r in cap if r[s]["solved"] == r[s]["n"])
|
||||
bd = min(r[s]["total"] for r in dire if r[s]["solved"] == r[s]["n"] and r["spec"][0] == "pure")
|
||||
check(f"item 9: best capped vs best uncapped, {s}", (bc, bd), want)
|
||||
|
||||
itp = _load("sweep_itp.json")
|
||||
t10 = {"APS": (3767, 3068), "CHA": (1946, 1675), "NEW": (5674, 4707), "RJL": (2161, 1629),
|
||||
"APP": (3245, 2386), "D": (5721, 4832)}
|
||||
for s, want in t10.items():
|
||||
check(f"Table 10 ITP / oracle {s}", (sum(cost(v) for v in itp["itp"][s].values()),
|
||||
sum(cost(v) for v in itp["itp_oracle"][s].values())), want)
|
||||
check("Table 10 ITP / oracle over 855", tuple(sum(cost(v) for s in t10 for v in itp[k][s].values())
|
||||
for k in ("itp", "itp_oracle")), (22514, 18297))
|
||||
check("ITP bound violations over 855", sum(v[2] for k in ("itp", "itp_oracle")
|
||||
for s in t10 for v in itp[k][s].values()), 0)
|
||||
seen, four = _load("sweep_fourth_seen.json"), _load("sweep_fourth_fourth.json")
|
||||
apx = dict(seen["Aprime"])
|
||||
apx.update(four["Aprime"])
|
||||
check("A' ahead of ITP and the oracle on every corpus",
|
||||
all(sum(cost(v) for v in apx[s].values()) < sum(cost(v) for v in itp[k][s].values())
|
||||
for s in t10 for k in ("itp", "itp_oracle")), True)
|
||||
|
||||
from simroot.pure import pure_root
|
||||
from stage12_validation import load, per_problem
|
||||
probs = load()
|
||||
aps = [p for p in probs if p[0] == "APS"]
|
||||
runs = {fac: per_problem(lambda f, a, b, xt, mx, _f=fac: pure_root(
|
||||
f, a, b, xt, mx, similarity="ratio", scale="derived3", guard="project",
|
||||
budget_factor=_f), aps, 200, criterion="sign") for fac in (1.25, 1.5, 2.0)}
|
||||
moved = {p: tuple(runs[f][p][0] for f in (1.25, 1.5, 2.0)) for p in runs[2.0]
|
||||
if len({runs[f][p][0] for f in (1.25, 1.5, 2.0)}) > 1}
|
||||
check("Table 1a: the one canonical problem the multiplier moves", moved,
|
||||
{"aps.13.00": (20, 30, 28)})
|
||||
tot = {}
|
||||
for sc in ("derived3", "derived3_m"):
|
||||
pp = per_problem(lambda f, a, b, xt, mx, _s=sc: pure_root(
|
||||
f, a, b, xt, mx, similarity="ratio", scale=_s, guard="project"), probs, 200,
|
||||
criterion="sign")
|
||||
tot[sc] = sum(v[0] for v in pp.values())
|
||||
check("item 5: phase detector vs base rule, both sets", (tot["derived3_m"], tot["derived3"]),
|
||||
(5336, 4991))
|
||||
'''
|
||||
|
||||
|
||||
def main():
|
||||
src = open(PATH, encoding="utf8").read()
|
||||
bad = [old[:80] for old, _ in REPL if src.count(old) != 1]
|
||||
if bad:
|
||||
for b in bad:
|
||||
print("ANCHOR NOT FOUND EXACTLY ONCE:", repr(b))
|
||||
raise SystemExit(f"{len(bad)} anchors failed; nothing written")
|
||||
for old, new in REPL:
|
||||
src = src.replace(old, new)
|
||||
marker = '\n\nif __name__ == "__main__":\n main()\n'
|
||||
assert src.count(marker) == 1
|
||||
src = src.replace(marker, NEW_FUNC + marker)
|
||||
open(PATH, "w", encoding="utf8").write(src)
|
||||
print(f"applied {len(REPL)} replacements and added verify_revision1")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,40 @@
|
||||
"""Revision point 3: verify_article.py reads every row-format protocol sweep through ONE loader,
|
||||
which serves the re-scoring under the single (bracketing) criterion from sweep_uniform.json.
|
||||
Exact anchors, each replaced the stated number of times, or nothing is written.
|
||||
|
||||
python -u apply_verify_uniform.py
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
PATH = "verify_article.py"
|
||||
|
||||
src = open(PATH, encoding="utf8").read()
|
||||
|
||||
# 1. every `with open(<x>, encoding="utf8") as fh:\n <ws> name = json.load(fh)` -> name = _load(<x>)
|
||||
pat = re.compile(r'( *)with open\(([^,]+), encoding="utf8"\) as fh:\n +(\w+) = json\.load\(fh\)\n')
|
||||
n_sub = len(pat.findall(src))
|
||||
assert n_sub == 9, n_sub
|
||||
src = pat.sub(lambda m: f"{m.group(1)}{m.group(3)} = _load({m.group(2)})\n", src)
|
||||
|
||||
# 2. the loader itself: row-format protocol sweeps come from the single-criterion re-scoring
|
||||
old_loader = '''def _load(path):
|
||||
with open(path, encoding="utf8") as fh:
|
||||
return json.load(fh)
|
||||
'''
|
||||
new_loader = '''def _load(path):
|
||||
"""A results file. A row-format protocol sweep (a list of labelled cells) is served from
|
||||
sweep_uniform.json, its re-scoring under the paper's single criterion - a sign change
|
||||
within 1e-6 or f(x) == 0 (revision point 3, 2026-09-22); every other file as stored."""
|
||||
from rescore_uniform import load_uniform
|
||||
with open(path, encoding="utf8") as fh:
|
||||
data = json.load(fh)
|
||||
if isinstance(data, list) and data and "spec" in data[0]:
|
||||
return load_uniform(path)
|
||||
return data
|
||||
'''
|
||||
assert src.count(old_loader) == 1
|
||||
src = src.replace(old_loader, new_loader)
|
||||
open(PATH, "w", encoding="utf8").write(src)
|
||||
print(f"replaced {n_sub} direct reads and the loader")
|
||||
+161
-171
@@ -6,11 +6,11 @@ V. Sitnikov
|
||||
|
||||
## Abstract
|
||||
|
||||
Bisection places the next iterate at the midpoint because it uses no information about the function's value. We replace that rule with a *similarity* rule: the step is proportional to how *dissimilar* the current outcome $f(x)$ is to the expectation $0$, measured by a similarity function $S:\mathbb{R}\to[0,1]$ with $S(0)=1$. We derive the contraction factor of the resulting iteration in closed form; it predicts a linear rate to four digits when $1-S$ has a non-zero slope at the origin, and a sublinear $e_n\sim C/n$ with a predicted $C$ when it does not, both confirmed. Three consequences follow. First, with the *ratio* similarity scaled by the far end — and with that combination only, of the five tested — the rule reproduces the false-position formula identically; so does the truncated linear similarity scaled by a divided difference over the *bracket ends*, which shows that the boundary of novelty runs through which points the difference is taken over. Second, any similarity fixed in advance with the scale also fixed yields at best linear convergence at a rate that is a property of the problem rather than of the method; on the eight standard problems of §2.2, five to eight of them fail. Third, the rate vanishes exactly when the scale equals the local scale of the value axis; reading that scale off the data — a divided difference, not a fitted coefficient — turns the step into $|f|/|f'|$ and the convergence superlinear.
|
||||
Bisection places the next iterate at the midpoint because it uses no information about the function's value. We replace that rule with a *similarity* rule: the step is proportional to how *dissimilar* the current outcome $f(x)$ is to the expectation $0$, measured by a similarity function $S:\mathbb{R}\to[0,1]$ with $S(0)=1$. We derive the contraction factor of the resulting iteration in closed form; it predicts a linear rate to four digits when $1-S$ has a non-zero slope at the origin, and a sublinear $e_n\sim C/n$ with a predicted $C$ when it does not, both confirmed. Three consequences follow. First, with the *ratio* similarity scaled by the far end — and with that combination only, of the five tested — the rule reproduces the false-position formula identically; so does the truncated linear similarity scaled by a divided difference over the *bracket ends*, which shows that the boundary of novelty runs through which points the difference is taken over. Second, any similarity fixed in advance with the scale also fixed yields at best linear convergence at a rate that is a property of the problem rather than of the method. Third, the rate vanishes exactly when the scale equals the local scale of the value axis; reading that scale off the data — a divided difference, not a fitted coefficient — turns the step into $|f|/|f'|$ and the convergence superlinear.
|
||||
|
||||
The derivation fixes a *base rule* before any benchmark is consulted: a similarity whose approach to 1 is linear, the finest available data-derived scale, and a safeguard that projects the step onto the admissible interval rather than replacing it. It is, explicitly, a Newton step with a three-point divided-difference derivative, clipped to the bracket and projected onto the bisection budget. The similarity sets that step, and its form is decisive: with the tent the step is Newton's, with any of the other eight functions the same method costs from 12% to four times more. It carries a proven worst case of twice bisection plus one step and exactly one free constant, which we declare rather than argue away: the multiplier of that budget. On the 154 problems of Alefeld, Potra and Shi it needs 2806 evaluations of $f$ against 2820 for TOMS 748, 2889 for Brent and 2787 for Chandrupatla's method — level in total — and beats Chandrupatla problem by problem 87 to 42 (exact sign test $p=9\cdot10^{-5}$). On the 45 wide-bracket problems of Chandrupatla it beats Brent and TOMS 748 and loses to ITP and to Chandrupatla (3220 against 2896 and 2441). For every data-derived scale, the ranking of the nine similarity functions matches the derived law without exception.
|
||||
The derivation fixes a *base rule* before any benchmark is consulted: a similarity whose approach to 1 is linear, the finest available data-derived scale, and a safeguard that projects the step onto the admissible interval rather than replacing it. It is, explicitly, a Newton step with a three-point divided-difference derivative, clipped to the bracket and projected onto the bisection budget. The similarity sets that step, and its form is decisive: with the tent the step is Newton's, with any of the other eight functions the proposed method costs from 19% to five times more. Its order is Muller's, 1.839. It carries a proven worst case of twice bisection plus one step and one free numerical constant, the multiplier of that budget, which we declare. On the 154 problems of Alefeld, Potra and Shi it needs 2634 evaluations of $f$ against 2636 for TOMS 748, 2707 for Brent and 2595 for Chandrupatla's method; it wins more problems than it loses against Chandrupatla, 87 to 43, and needs 1.5% more in total because its losses are the larger ones. On the 45 wide-bracket problems of Chandrupatla it beats Brent and TOMS 748 and loses to ITP and to Chandrupatla (2357 against 1946 and 1505). For every data-derived scale the three similarity functions whose $1-S$ has a non-zero slope at the origin come before the three whose slope is zero, as the derived law predicts.
|
||||
|
||||
The wide-bracket gap turns out to be not the order of the model but a decision — when to give the model up — and the decision is a similarity after all, of an unfamiliar kind: the similarity of a run to its own past. A pure power is self-similar under zoom, so the dimensionless configuration of the last three points recurs, while at a simple root it tends to the linear prototype; the analogous pair yields the local order, $m=\ln L_f/\ln L_x$, and an exponential, self-similar by translation, is its limit $m=\infty$. Entering a halving regime when that analogy holds with $m\ge2$ — the condition under which a tangent step loses to a halving — splitting at the point the order predicts, and leaving when the split looks linear, together with four smaller readings of the same kind and one borrowed element, gives the method proposed here, A′. On the two sets it needs 2438 and 2005 evaluations against Chandrupatla's 2787 and 2441 and beats him problem by problem on both, 103 to 30 and 29 to 7. The chain of decisions that produced it was selected on those sets; tested once, after its code was frozen, on 240 problems from six new families, it needs 3656 evaluations against Chandrupatla's 5717 and wins 177 problems to 28. Over 855 problems in six corpora it is ahead of Brent, TOMS 748 and the recent ModAB everywhere and keeps its bound where they break theirs on 118, 84 and 9 problems; against Chandrupatla it is ahead in total on five corpora and level on the sixth. The lead is large on multiple, fractional and nearly flat roots and a matter of per cent on simple ones. Several of the resulting mechanisms coincide with classical ones — Lagouanelle's multiplicity estimate, false position on $|f|^{1/m}$ — reached here from similarity and analogy and recognised afterwards; what we found no counterpart for is the decision layer, where every choice — when to give the model up, where to split, when to return — is a judgment of similarity or of analogy, and the similarity that sets the step, whose form is decisive (replacing it costs 12% to 315%).
|
||||
The wide-bracket gap turns out to be not the order of the model but a decision — when to give the model up — and the decision is a similarity after all, of an unfamiliar kind: the similarity of a run to its own past. A pure power is self-similar under zoom, so the dimensionless configuration of the last three points recurs, while at a simple root it tends to the linear prototype; the analogous pair yields the local order, $m=\ln L_f/\ln L_x$, and an exponential, self-similar by translation, is its limit $m=\infty$. Entering a halving regime when that analogy holds with $m\ge2$ — the condition under which a tangent step loses to a halving — splitting at the point the order predicts, and leaving when the split looks linear, together with four smaller readings of the same kind and one borrowed element, gives the method proposed here, A′. On the two sets it needs 2259 and 1074 evaluations against Chandrupatla's 2595 and 1505 and wins more problems than it loses on both, 103 to 31 and 31 to 10. The chain of decisions that produced it was selected on those sets; tested once, after its code was frozen, on 240 problems from six new families, it needs 3656 evaluations against Chandrupatla's 5717 and wins 177 problems to 28 — a corpus the author composed knowing where the method is strong: two of its six families have multiple or fractional roots, and without them the lead is 2403 against 3569, on the simple-root families alone 737 against 747. Over 855 problems in six corpora it is ahead of Brent, TOMS 748, ITP and the recent ModAB everywhere and stays within its own bound of twice bisection on every problem, a bound that Brent, TOMS 748 and ModAB, which do not promise it, exceed on 118, 84 and 9 problems; against Chandrupatla it is ahead in total on five corpora and level on the sixth. The lead is large on multiple, fractional and nearly flat roots and a matter of per cent on simple ones. Several of the resulting mechanisms coincide with classical ones — Lagouanelle's multiplicity estimate, false position on $|f|^{1/m}$ — reached here from similarity and analogy and recognised afterwards; what we found no counterpart for is the decision layer, where every choice — when to give the model up, where to split, when to return — is a judgment of similarity or of analogy, and the similarity that sets the step, whose form is decisive (replacing it costs 19% to 425%).
|
||||
|
||||
---
|
||||
|
||||
@@ -43,11 +43,11 @@ $$S(a)\,a + S(b)\,b \;=\; \frac{a f(b) - b f(a)}{f(b)-f(a)}.$$
|
||||
|
||||
That is the false-position formula. Two things must be said about how far it reaches, because the obvious generalisation is false.
|
||||
|
||||
It is specific to that similarity. On $f=x^2-2$ over $[1,4]$, where false position gives 1.200000, the same construction gives 1.206812 for $e^{-|z|}$, 1.015228 for $1/(1+z^2)$, 1.007624 for $1/\sqrt{1+z^2}$ and 1.214286 for the truncated linear form: one of five reproduces it. So "a similarity rule scaled by the bracket is not a new method" would be too broad a conclusion, and this paper's own Table 3 refutes it — bracket-scaled configurations take first and fourth place on Chandrupatla and one of them solves 41 of 45, where false position solves 6.
|
||||
It is specific to that similarity. On $f=x^2-2$ over $[1,4]$, where false position gives 1.200000, the same construction gives 1.206812 for $e^{-|z|}$, 1.015228 for $1/(1+z^2)$, 1.007624 for $1/\sqrt{1+z^2}$ and 1.214286 for the truncated linear form: one of five reproduces it. So "a similarity rule scaled by the bracket is not a new method" would be too broad a conclusion, and this paper's own Table 3 refutes it — bracket-scaled configurations take third, fourth and sixth place on Chandrupatla's set, where false position solves 6 of 45.
|
||||
|
||||
**Proposition 1'.** It is, however, specific to the *bracket ends* rather than to the ratio form. Take the truncated linear similarity $S(z)=\max(0,1-|z|)$ and the divided difference over the two ends, $\sigma=|f[a,b]|\cdot|b-a|=|f(b)-f(a)|=|f(a)|+|f(b)|$. Then $1-S=|f(a)|/(|f(a)|+|f(b)|)$, which is false position again, and the agreement is exact to the last bit.
|
||||
|
||||
Together the two say where the boundary of novelty runs, and it is not where one would guess: it runs through the words *most recent* in the definition of $\hat f'$ in §3. A divided difference over the bracket ends is three centuries old; the same difference over the most recent iterates is the secant. In our measurements plain false position solves 127 of the 154 Alefeld–Potra–Shi problems, against 153 for bisection.
|
||||
Together the two say where the boundary of novelty runs, and it is not where one would guess: it runs through the words *most recent* in the definition of $\hat f'$ in §3. A divided difference over the bracket ends is three centuries old; the same difference over the most recent iterates is the secant. In our measurements plain false position solves 127 of the 154 Alefeld–Potra–Shi problems, against 154 for bisection.
|
||||
|
||||
### 2.2 The contraction law
|
||||
|
||||
@@ -76,7 +76,7 @@ sublinear rather than stagnant. Reporting a "measured rate" for these rows would
|
||||
| $1/(1+z^2)$ | 0, $c_2=1$ | $n\,e_n\to0.8536$ | 0.8503 |
|
||||
| $e^{-z^2}$ | 0, $c_2=1$ | $n\,e_n\to0.8536$ | 0.8498 |
|
||||
| $1/\sqrt{1+z^2}$ | 0, $c_2=\tfrac12$ | $n\,e_n\to1.7071$ | 1.6988 |
|
||||
| $\max(0,1-\lvert z\rvert)$ | 1 | rate 0.1716 | captured, see below |
|
||||
| $\max(0,1-\lvert z\rvert)$ | 1 | rate 0.1716 | fails: stays at $x_\mathrm{far}$ |
|
||||
|
||||
The last row is not a slow rate but an immediate failure, and it matters because that similarity is the one this paper goes on to propose. At $x_0=0$ the residual is $z=-1$, so $S=\max(0,1-1)=0$, the step is the whole bracket, the iterate lands exactly on $x_\mathrm{far}$ and never leaves: the error is 0.5858 after one step and after two hundred. **The failure is a property of the chosen scale, not of the similarity.** Under the derived scale of §3 the residual $|f|/\sigma$ stays below 1 — on this problem the clip does not engage on a single one of the seven steps the method takes — the truncation never fires, and the same function is the best of the nine (Table 4). This is the paper's own thesis, that the content sits in the scale and not in the shape of $S$, showing up as a discontinuity in the behaviour of one function.
|
||||
|
||||
@@ -84,7 +84,7 @@ The last row is not a slow rate but an immediate failure, and it matters because
|
||||
|
||||
Empirically, with $\sigma$ taken as $|f|$ at the starting point, five to eight of the eight standard problems fail outright for the six similarity functions tested. Those eight, used throughout as a quick set and never as evidence on their own, are: $x^2-2$ on $[0,2]$; $\cos x-x$ on $[0,1]$; $e^x-2$ on $[0,2]$; $x^3-x-2$ on $[1,2]$; $\sin x-\tfrac12$ on $[0,1.5]$; $x^{10}-1$ on $[0,1.3]$, which stalls false position; $e^{-x}(x-1)$ on $[-1,40]$, whose right end is flat to $10^{-16}$; and $\arctan x$ on $[-1,3]$.
|
||||
|
||||
**Corollary 2 (Missing the calibration in either direction costs).** The rate degrades as the product $c\,|f'(r)|\,|D|/\sigma$ departs from 1, upwards or downwards. We claim no symmetry between the two directions, and the measurements do not support one: similarities with unbounded slope — $1-\sqrt{|z|}$ has $c\approx3.2\cdot10^{3}$ at the resolution used, $1-|z|^{1/3}$ has $c\approx4.6\cdot10^{4}$ — fail on five and six of the eight problems with a chosen scale, yet over the full benchmark they finish at 10497 and 11941, ahead of all three $c=0$ similarities at 14314, 15102 and 16394, and one of them heads Table 3. Overshooting is the milder failure.
|
||||
**Corollary 2 (Missing the calibration in either direction costs).** The rate degrades as the product $c\,|f'(r)|\,|D|/\sigma$ departs from 1, upwards or downwards. We claim no symmetry between the two directions, and the measurements do not support one: similarities with unbounded slope — $1-\sqrt{|z|}$ has $c\approx3.2\cdot10^{3}$ at the resolution used, $1-|z|^{1/3}$ has $c\approx4.6\cdot10^{4}$ — fail on five and six of the eight problems with a chosen scale, yet over the full benchmark (best over scales, Table 4) they finish at 9411 and 10874, ahead of all three $c=0$ similarities at 13187, 13990 and 15272. Overshooting is the milder failure.
|
||||
|
||||
**Corollary 3 (The scale must come from the data).** The rate is zero exactly when $c\,|f'(r)|\,D/\sigma = 1$, i.e. $\sigma = c\,|f'(r)|\,D$. Substituting this $\sigma$ back into (1) with $c=1$ gives $x' - x = |f(x)|/|f'|$, the Newton step. The similarity rule is therefore superlinear precisely when its scale is the *local scale of the value axis*, and that scale is not available a priori: it must be read off the evaluations.
|
||||
|
||||
@@ -96,15 +96,15 @@ Corollaries 1–3 fix every choice in the method before any benchmark is consult
|
||||
|
||||
**Similarity: any with $c\neq0$.** The law makes the shape of $S$ almost irrelevant and its slope at the origin decisive. We take the plainest member, the **truncated linear** or tent form $S(z)=\max(0,1-|z|)$. It is not the ratio form $1/(1+|z|)$, which is a separate row of every table here; the two are distinguished throughout because Proposition 1 applies to the ratio form and Table 1's last row to the tent.
|
||||
|
||||
**Scale: the finest data-derived one.** We set $\sigma = |\hat f'|\cdot|x_\mathrm{far}-x|$ with $\hat f'$ a divided difference of the **most recent evaluations** — not of the bracket ends, which by Proposition 1' would give false position. A divided difference is a computation, not a fitted coefficient: nothing is chosen, regressed or tuned. The two-point difference has slope error $O(h)$ and gives the secant order $\varphi\approx1.618$; the three-point difference — the derivative at $x_n$ of the parabola through the last three evaluations, $\hat f' = f[x_{n-1},x_n] + f[x_{n-2},x_{n-1},x_n](x_n-x_{n-1})$ — has error $O(h^2)$. A Newton step whose derivative carries an $O(h^2)$ error satisfies $e' = e-f/\hat f' = e-(e-ce^2+\dots)(1+O(e^2)) = ce^2+O(e^3)$, so the predicted order is **2** — not Muller's 1.84, which belongs to a method using the parabola's *root* rather than its *derivative*. Measured medians are 1.584 for the two-point scale and 2.000 for the three-point, against 1.809 for Brent and 2.654 for TOMS 748.
|
||||
**Scale: the finest data-derived one.** We set $\sigma = |\hat f'|\cdot|x_\mathrm{far}-x|$ with $\hat f'$ a divided difference of the **most recent evaluations** — not of the bracket ends, which by Proposition 1' would give false position. A divided difference is a computation, not a fitted coefficient: nothing is chosen, regressed or tuned. The two-point difference has slope error $O(h)$ and gives the secant order $\varphi\approx1.618$; the three-point difference — the derivative at $x_n$ of the parabola through the last three evaluations, $\hat f' = f[x_{n-1},x_n] + f[x_{n-2},x_{n-1},x_n](x_n-x_{n-1})$ — has error $\tfrac16 f'''(\eta)\,(x_n-x_{n-1})(x_n-x_{n-2})$, that is $O(e_{n-1}e_{n-2})$. The Newton step with that derivative satisfies $e_{n+1}=\tfrac{f''}{2f'}e_n^2+\tfrac{f'''}{6f'}\,e_n e_{n-1}e_{n-2}+\dots$; the second term dominates, and the order is the root of $p^3=p^2+p+1$, $p\approx1.839$ — **Muller's order**, as it should be, since the step uses the same parabola as Muller's method, through its derivative rather than its root. Only where the parabola is exact ($f'''=0$) does the order rise to Newton's 2. Carried to $10^{-2900}$ in 3000-digit arithmetic (`order_high_precision.py`), the computational order per step settles at 1.840 on $\cos x-x$, $e^x-2$, $x^3-x-2$ and $\sin x-\tfrac12$ and at 2.000 on $x^2-2$; the two-point scale settles at 1.618. In double precision a run takes three or four superlinear steps before it reaches the tolerance, too few to tell 1.84 from 2, and we report no order measured there.
|
||||
|
||||
**What the rule reduces to.** With $S(z)=\max(0,1-|z|)$ one has $1-S=\min(1,|z|)$, and (1) becomes
|
||||
|
||||
$$x' \;=\; x + \operatorname{sign}(x_\mathrm{far}-x)\cdot\min\!\Bigl(\frac{|f(x)|}{|\hat f'|},\;|x_\mathrm{far}-x|\Bigr), \tag{4}$$
|
||||
|
||||
a Newton step with a three-point divided-difference derivative, clipped to the bracket and then projected as in §3.1. That the tent turns the similarity step into Newton's is a property of the similarity chosen, not a sign that the similarity has dropped out: which $S$ stands in the step decides the step, and it is measured, not assumed — Table 4 ranks the nine functions over the whole grid, the readings of §7 pay most with the tent in the step and some of them lose with other functions (§7), and in the proposed method replacing the tent by any other function costs 12% to 315% (Table 9a).
|
||||
a Newton step with a three-point divided-difference derivative, clipped to the bracket and then projected as in §3.1. That the tent turns the similarity step into Newton's is a property of the similarity chosen, not a sign that the similarity has dropped out: which $S$ stands in the step decides the step, and it is measured, not assumed — Table 4 ranks the nine functions over the whole grid, the readings of §7 pay most with the tent in the step and some of them lose with other functions (§7), and in the proposed method replacing the tent by any other function costs 19% to 425% (Table 9a).
|
||||
|
||||
We state the reduction ourselves rather than leave it to be discovered, because it locates the contribution precisely. The base rule is not a new family of methods. It is (i) a derivation that fixes every choice — which similarity, which scale, which safeguard — before any benchmark is consulted, and then predicts the ranking of all nine similarity functions correctly; (ii) a safeguard of ITP's projection type with ITP's truncation stage, and hence all three of its constants, removed; (iii) the negative results of §10; (iv) the measurements. We call it the **base rule**; the method this paper proposes builds on it in Section 8.
|
||||
We state the reduction ourselves rather than leave it to be discovered, because it locates the contribution precisely. The base rule is not a new family of methods. It is (i) a derivation that fixes every choice — which similarity, which scale, which safeguard — before any benchmark is consulted, and predicts which similarity functions come first; (ii) a safeguard of ITP's projection type with ITP's truncation stage, and hence all three of its constants, removed; (iii) the negative results of §10; (iv) the measurements. We call it the **base rule**; the method this paper proposes builds on it in Section 8.
|
||||
|
||||
**Algorithm.** Given $[a,b]$ with $f(a)f(b)<0$ and tolerance $\varepsilon_x$:
|
||||
|
||||
@@ -133,7 +133,7 @@ Every quantity in it is either an evaluation of $f$, a divided difference of eva
|
||||
|
||||
### 3.1 The safeguard: project, do not replace
|
||||
|
||||
An interpolation-only rule has no worst-case bound. The obvious safeguards *replace* the computed step with a midpoint whenever some progress test fails, and all of them are ruinous here, for a reason specific to a fast method: a step that collapses the *error* need not halve the *bracket*, so a bracket-based test fires on exactly the steps that were best. With the three-point scale, replacing on that test drops the observed order from 1.94 to 1.00 and the Alefeld–Potra–Shi total from 2806 to 7260 — worse than bisection.
|
||||
An interpolation-only rule has no worst-case bound. The obvious safeguards *replace* the computed step with a midpoint whenever some progress test fails, and all of them are ruinous here, for a reason specific to a fast method: a step that collapses the *error* need not halve the *bracket*, so a bracket-based test fires on exactly the steps that were best. With the three-point scale, replacing on that test makes the convergence linear and takes the Alefeld–Potra–Shi total from 2634 to 7068 — nearly the cost of bisection (7338).
|
||||
|
||||
The remedy is to keep as much of the computed step as the budget allows. Let $n_{\max}=2\lceil\log_2(w_0/\varepsilon_x)\rceil$ be twice the bisection step count for the initial width $w_0$ and $x$-tolerance $\varepsilon_x$, and let $\epsilon=\varepsilon_x/2$. At step $j$, with the bracket $[\ell,h]$, define the allowance and the projection
|
||||
|
||||
@@ -141,20 +141,20 @@ $$\alpha_j = 2^{\,n_{\max}-j}\epsilon, \qquad x \;=\; \operatorname{clamp}\bigl(
|
||||
|
||||
The next bracket is at most $\max(x-\ell,\,h-x)$, so (3) gives $w_{j+1}\le\alpha_j$ directly, and induction bounds the run by $n_{\max}$ steps in exact arithmetic. In floating point the bracket can land exactly on the boundary, and the termination test then asks for one more; the guarantee stated and verified is therefore $2\lceil\log_2(w_0/\varepsilon_x)\rceil+3$ evaluations.
|
||||
|
||||
**The multiplier is the method's one free constant.** An earlier version of this section argued that it is "the factor already claimed in the bound". That is circular — the bound is twice bisection because two was chosen — and measurement settles it (`measure_budget_factor.py`, Linux):
|
||||
**The multiplier is the method's one free numerical constant.** It is not "the factor already claimed in the bound" — that argument is circular, the bound is twice bisection because two was chosen — and measurement settles it (`measure_budget_factor.py`, Linux):
|
||||
|
||||
**Table 1a.** The scheduled projection at budget multiplier $c$, i.e. $n_{\max}=\lceil c\cdot\log_2(w_0/\varepsilon_x)\rceil$. Total evaluations, failures charged.
|
||||
|
||||
| $c$ | APS-154 | CHA-45 | both |
|
||||
|---|---|---|---|
|
||||
| 1 | 4817 | 2997 | 7814 |
|
||||
| 1.25 | 2806 | 2752 | 5558 |
|
||||
| 1.5 | 2806 | 2889 | 5695 |
|
||||
| 2 | 2806 | 3220 | 6026 |
|
||||
| 3 | 2806 | 3756 | 6562 |
|
||||
| 4 | 2806 | 4006 | 6812 |
|
||||
| 1 | 4625 | 2039 | 6664 |
|
||||
| 1.25 | 2626 | 1822 | 4448 |
|
||||
| 1.5 | 2636 | 1991 | 4627 |
|
||||
| 2 | 2634 | 2357 | 4991 |
|
||||
| 3 | 2634 | 2936 | 5570 |
|
||||
| 4 | 2634 | 3229 | 5863 |
|
||||
|
||||
On the canonical set the projection never binds once $c\ge1.25$, so the total does not move. On the wide-bracket set it moves monotonically with $c$, and 2 is not even the best value. Nor is zero slack ($c=1$) the degenerate case it was claimed to be, "a worst case of exactly bisection" under which "the guard behaves as bisection": it costs 4817 and 2997, far from bisection's 7530 and 3090, and on the wide-bracket set it beats $c=2$. The multiplicative family has no member that the bound singles out, so its multiplier is a genuinely free constant.
|
||||
On the canonical set the projection binds on one problem only once $c\ge1.25$ — `aps.13.00`, whose $f$ underflows to zero around the root (20, 30 and 28 evaluations at $c=1.25$, 1.5 and 2) — so the total barely moves. On the wide-bracket set it moves monotonically with $c$ from 1.25 on, and 2 is not the best value. Nor is zero slack ($c=1$) a degenerate case under which the guard behaves as bisection: it costs 4625 and 2039, far from bisection's 7338 and 2136, and on the wide-bracket set it beats $c=2$. The multiplicative family has no member that the bound singles out, so its multiplier is a genuinely free constant.
|
||||
|
||||
**The budget earned rather than scheduled: a constant-free variant.** The constant can be removed. Let $s_j=\log_2(w_j/w_{j+1})$ be the shrink a step delivers in bits — bisection delivers exactly 1 — and keep a credit
|
||||
|
||||
@@ -166,15 +166,15 @@ leaving the step alone while $C\ge1$. A step may under-deliver only by what earl
|
||||
|
||||
| $C_0$ | promise | APS-154 | CHA-45 | both |
|
||||
|---|---|---|---|---|
|
||||
| 0.1 | bisection + 1 step | 5344 | 3051 | 8395 |
|
||||
| 0.5 | bisection + 1 step | 4656 | 3002 | 7658 |
|
||||
| **1** | **bisection + 1 step** | **3568** | **3020** | **6588** |
|
||||
| 2 | bisection + 2 steps | 3692 | 2712 | 6404 |
|
||||
| 5 | bisection + 5 steps | 3006 | 2615 | 5621 |
|
||||
| 0.1 | bisection + 1 step | 5150 | 2097 | 7247 |
|
||||
| 0.5 | bisection + 1 step | 4462 | 2037 | 6499 |
|
||||
| **1** | **bisection + 1 step** | **3377** | **2073** | **5450** |
|
||||
| 2 | bisection + 2 steps | 3502 | 1757 | 5259 |
|
||||
| 5 | bisection + 5 steps | 2819 | 1666 | 4485 |
|
||||
|
||||
A looser promise buys evaluations, as it must; within one promise the cheapest endowment is determined. The constant-free variant is therefore the earned projection with $C_0=1$, whose guarantee — $\lceil\log_2(w_0/\varepsilon_x)\rceil+4$ evaluations, bisection plus one step with one more for the floating-point boundary — is verified on all 199 problems.
|
||||
|
||||
We nonetheless propose the scheduled projection with $c=2$ and declare its multiplier. On the canonical set it is 762 evaluations cheaper than the earned variant (2806 against 3568), and there its total does not depend on the multiplier at all; on the wide-bracket set the earned variant is the cheaper (3020 against 3220). The two are the ends of a trade stated in numbers: one declared constant and the better canonical result, or no constant, a tighter bound and the better wide-bracket result. The value 2 was fixed before any benchmark was consulted; what changed after the question whether it was load-bearing is only that it is now declared as a constant rather than argued to be none.
|
||||
We nonetheless propose the scheduled projection with $c=2$ and declare its multiplier. On the canonical set it is 743 evaluations cheaper than the earned variant (2634 against 3377), and there its total barely depends on the multiplier; on the wide-bracket set the earned variant is the cheaper (2073 against 2357). The two are the ends of a trade stated in numbers: one declared constant and the better canonical result, or no constant, a tighter bound and the better wide-bracket result. The value 2 was fixed before any benchmark was consulted.
|
||||
|
||||
Two remarks apply to both forms.
|
||||
|
||||
@@ -187,7 +187,7 @@ Two remarks apply to both forms.
|
||||
|
||||
**Problem sets.** The 154 problems of Alefeld, Potra and Shi [1] and the 45 of Chandrupatla [3], taken programmatically from SciPy's `scipy.optimize._tstutils` so that no bracket or root is transcribed by hand.
|
||||
|
||||
**Cost model.** Evaluations of $f$. A run counts as solved when it reports convergence and lands within $10^{-6}$ of the published root; $x$-tolerance $10^{-12}$; budget 200 evaluations. *Failures are charged the full budget*, so no method can buy a low total by giving up early, and totals are reported over all problems rather than over the subset a method happened to solve. Rankings are by failures first, then by total.
|
||||
**Cost model.** Evaluations of $f$. A run counts as solved when it reports convergence and $f$ changes sign within $10^{-6}$ of the returned point, or vanishes there — the bracketing notion of a root, the same criterion on every corpus of this paper; $x$-tolerance $10^{-12}$; budget 200 evaluations. Scoring against the published root instead, as the benchmarks' harness does, charges every method the full budget on six problems where $f$ vanishes identically around the root in floating point (§7.3). Head-to-head counts (wins/ties/losses) are taken over every problem of a set with the same charging as the totals. *Failures are charged the full budget*, so no method can buy a low total by giving up early, and totals are reported over all problems rather than over the subset a method happened to solve. Rankings are by failures first, then by total.
|
||||
|
||||
**Fairness to the competitors.** Three deliberate concessions.
|
||||
|
||||
@@ -195,9 +195,9 @@ Two remarks apply to both forms.
|
||||
2. ITP is reported both at the authors' recommended constants and as a *per-problem oracle*, the best of a $(\kappa_1,n_0)$ grid chosen separately for every problem — not an achievable method, included so that the state of the art cannot be said to have been handicapped.
|
||||
3. Our implementation of ITP is validated against the method's own theorem, that it never needs more than $n_{1/2}+n_0$ iterations, on all 154 problems for $n_0\in\{0,1,2,5\}$.
|
||||
|
||||
4. Where SciPy ships the method, the competitor **is the library**: Chandrupatla is `scipy.optimize.elementwise.find_root`, Brent is `brentq`, TOMS 748 is `toms748`, each run with the same stopping rule as every other method — a bracket no wider than $\varepsilon_x$, the relative term at machine precision, no stopping on $|f|$ — and each evaluation counted by the same wrapper around $f$. An earlier version gave each competitor the better of the library's implementation and ours, problem by problem. That concession backfired in the competitor's favour: our Chandrupatla stopped on a bracket twice as wide as everybody else's — the factor this protocol corrects for ITP in item 1 and had not corrected there — and the per-problem minimum let the looser run win. With the tolerance corrected our implementation and the library agree on all 199 problems exactly, and Chandrupatla's totals move from 2785 to 2787 on the canonical set and from 2423 to 2441 on the wide-bracket set. For Brent the library is slightly dearer than our implementation (7004 against 6991 over both sets); we use the library anyway, because it is the implementation a reader can check. ITP has no library implementation, which is why it is checked against its own theorem instead; bisection and the false-position family are not in SciPy either and are ours.
|
||||
4. Where SciPy ships the method, the competitor **is the library**: Chandrupatla is `scipy.optimize.elementwise.find_root`, Brent is `brentq`, TOMS 748 is `toms748`, each run with the same stopping rule as every other method — a bracket no wider than $\varepsilon_x$, the relative term at machine precision, no stopping on $|f|$ — and each evaluation counted by the same wrapper around $f$. An earlier version gave each competitor the better of the library's implementation and ours, problem by problem. That concession backfired in the competitor's favour: our Chandrupatla stopped on a bracket twice as wide as everybody else's — the factor this protocol corrects for ITP in item 1 and had not corrected there — and the per-problem minimum let the looser run win. With the tolerance corrected our implementation and the library agree on all 199 problems exactly. For Brent the library is slightly dearer than our implementation; we use the library anyway, because it is the implementation a reader can check. ITP has no library implementation, which is why it is checked against its own theorem instead; bisection and the false-position family are not in SciPy either and are ours.
|
||||
|
||||
**Reproducibility.** All numbers come from a single Linux run. The test functions call `libm`, whose last digit differs between platforms; the same SciPy version scores 2819 for TOMS 748 on Windows and 2820 on Linux for the same set. Every number stated in this paper is checked against the run data by a script that is part of the test suite.
|
||||
**Reproducibility.** All numbers come from a single Linux run. The test functions call `libm`, whose last digit differs between platforms; the same SciPy version scores 2635 for TOMS 748 on Windows and 2636 on Linux for the same set. Every number stated in this paper is checked against the run data by a script that is part of the test suite.
|
||||
|
||||
---
|
||||
|
||||
@@ -209,39 +209,38 @@ The grid is nine similarity functions × four scales × seven safeguards = 252 c
|
||||
|
||||
| # | configuration | tuned | solved | total evals | $>2\times$ |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | Chandrupatla | no | 153/154 | 2787 | 0 |
|
||||
| 2 | the same rule with no safeguard at all | no | 153/154 | 2806 | 0 |
|
||||
| **3** | **base rule: tent, 3-point, projection ($c=2$)** | **no** | 153/154 | **2806** | 0 |
|
||||
| 4 | TOMS 748 | yes | 153/154 | 2820 | 0 |
|
||||
| 5 | Brent | yes | 153/154 | 2889 | 0 |
|
||||
| 12 | Dekker | no | 153/154 | 3158 | 0 |
|
||||
| 13 | ITP, per-problem oracle | yes | 153/154 | 3260 | 0 |
|
||||
| 20 | Ridders | no | 153/154 | 3313 | 0 |
|
||||
| 29 | constant-free variant: earned projection | no | 153/154 | 3568 | 0 |
|
||||
| 34 | ITP, recommended constants | yes | 153/154 | 3957 | 0 |
|
||||
| 73 | Illinois | yes | 153/154 | 7045 | 0 |
|
||||
| 79 | bisection | no | 153/154 | 7530 | 0 |
|
||||
| 1 | Chandrupatla | no | 154/154 | 2595 | 0 |
|
||||
| 2 | the same rule with no safeguard at all | no | 154/154 | 2634 | 0 |
|
||||
| **3** | **base rule: tent, 3-point, projection ($c=2$)** | **no** | 154/154 | **2634** | 0 |
|
||||
| 4 | TOMS 748 | yes | 154/154 | 2636 | 0 |
|
||||
| 5 | Brent | yes | 154/154 | 2707 | 0 |
|
||||
| 11 | ITP, per-problem oracle | yes | 154/154 | 3068 | 0 |
|
||||
| 15 | Ridders | no | 154/154 | 3124 | 0 |
|
||||
| 25 | constant-free variant: earned projection | no | 154/154 | 3377 | 0 |
|
||||
| 29 | ITP, recommended constants | yes | 154/154 | 3767 | 0 |
|
||||
| 73 | bisection | no | 154/154 | 7338 | 0 |
|
||||
| 232 | Dekker | no | 153/154 | 3158 | 0 |
|
||||
| 237 | Illinois | yes | 153/154 | 7045 | 0 |
|
||||
| 244 | false position | no | 127/154 | 10560 | — |
|
||||
|
||||
The base rule and the same rule without any safeguard tie at 2806: the projection never binds on this set. By total, Chandrupatla's method is first with 2787, 0.7% fewer — the same order of margin as the 0.5% by which the base rule leads TOMS 748, which we read as a tie. Problem by problem the picture is the other way round: on the problems both solve the base rule beats Chandrupatla 87/24/42 (wins/ties/losses; exact two-sided sign test $p=9\cdot10^{-5}$), TOMS 748 86/16/51, Brent 102/11/40, ITP at its recommended constants 132/3/18, the per-problem ITP oracle 121/4/28, and bisection 152/1/0. It wins twice as many problems as it loses against Chandrupatla and trails him in total because its losses are the larger ones. The constant-free variant goes 79/3/71 against Chandrupatla ($p=0.57$, a tie in problems), 77/9/67 against TOMS 748 and 78/5/70 against Brent, and loses on the total to all three.
|
||||
The base rule and the same rule without any safeguard tie at 2634: the projection never binds on this set. By total, Chandrupatla's method is first with 2595, 1.5% fewer; the base rule and TOMS 748 are level (2634 against 2636). Problem by problem the base rule wins against Chandrupatla 87/24/43 (wins/ties/losses; exact two-sided sign test $p=1.4\cdot10^{-4}$), against TOMS 748 86/16/52, Brent 102/11/41, ITP at its recommended constants 132/3/19, the per-problem ITP oracle 121/4/29, and bisection 152/1/1. It wins twice as many problems as it loses against Chandrupatla and trails that method in total because its losses are the larger ones; the problems are not independent (§9), and taken by function family the comparison is 6/1/8 of 15 families, a tie. Dekker and Illinois solve 153 of 154 and are ranked after every method that solves all. The constant-free variant goes 79/3/72 against Chandrupatla ($p=0.63$, a tie in problems), 78/9/67 against TOMS 748 and 79/5/70 against Brent, and loses on the total to all three.
|
||||
|
||||
**Table 3.** Chandrupatla, 45 problems, brackets up to $10^{12}$ wide, out of 264 configurations.
|
||||
|
||||
| # | configuration | tuned | solved | total evals | $>2\times$ |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | similarity, $1-\sqrt{\lvert z\rvert}$, bracket scale, projection | no | **41/45** | 4516 | 0 |
|
||||
| 2 | Chandrupatla | no | 40/45 | 2441 | 0 |
|
||||
| 3 | ITP, per-problem oracle | yes | 40/45 | 2647 | 0 |
|
||||
| 4 | similarity, $e^{-\lvert z\rvert}$, bracket scale, both guards | no | 40/45 | 2736 | 0 |
|
||||
| 6 | ITP, recommended constants | yes | 40/45 | 2896 | 0 |
|
||||
| 10 | constant-free variant: earned projection | no | 40/45 | 3020 | 0 |
|
||||
| 16 | bisection | no | 40/45 | 3090 | 0 |
|
||||
| **45** | **base rule: tent, 3-point, projection ($c=2$)** | **no** | 40/45 | **3220** | 0 |
|
||||
| 159 | TOMS 748 | yes | 40/45 | 4000 | 15 |
|
||||
| 227 | Brent | yes | 38/45 | 4115 | 18 |
|
||||
| 228 | the same rule with no safeguard at all | no | 35/45 | 4104 | 10 |
|
||||
| 1 | Chandrupatla | no | 45/45 | 1505 | 0 |
|
||||
| 2 | ITP, per-problem oracle | yes | 45/45 | 1675 | 0 |
|
||||
| 3 | similarity, $e^{-\lvert z\rvert}$, bracket scale, both guards | no | 45/45 | 1778 | 0 |
|
||||
| 5 | ITP, recommended constants | yes | 45/45 | 1946 | 0 |
|
||||
| 9 | constant-free variant: earned projection | no | 45/45 | 2073 | 0 |
|
||||
| 15 | bisection | no | 45/45 | 2136 | 0 |
|
||||
| **49** | **base rule: tent, 3-point, projection ($c=2$)** | **no** | 45/45 | **2357** | 0 |
|
||||
| 158 | TOMS 748 | yes | 45/45 | 3088 | 15 |
|
||||
| 227 | Brent | yes | 43/45 | 3238 | 18 |
|
||||
| 229 | the same rule with no safeguard at all | no | 39/45 | 3391 | 10 |
|
||||
|
||||
The set's nominal winner is a similarity configuration that solves one problem more than anything else, 41 of 45, at a worse total; ranking by failures first puts it on top, and we report it as such rather than by the total that would flatter our proposal. Here Chandrupatla's method is genuinely the stronger: it beats the base rule 26 problems to 9 ($p=0.006$) and by 3220 against 2441 in total. The proposed rule beats Brent 30/4/4 and TOMS 748 31/1/8 — both of which exceed the $2\times$ bound on 18 and 15 problems — and loses to ITP 17/0/23 and to the ITP oracle 16/0/24. The wide-bracket set is where the multiplier matters (Table 1a) and where the constant-free variant is the cheaper form, 3020 against 3220. Over both sets the base rule needs 6026 and the constant-free variant 6588, against 5228 for Chandrupatla, 5907 for the ITP oracle, 6820 for TOMS 748 and 7004 for Brent.
|
||||
Here Chandrupatla's method is genuinely the stronger: it beats the base rule 29 problems to 11 ($p=0.006$) and by 1505 against 2357 in total. The base rule beats Brent 34/4/7 and TOMS 748 33/1/11 — which exceed $2\times$ bisection, a bound they do not promise, on 18 and 15 problems — and loses to ITP 18/1/26 and to the ITP oracle 16/1/28. The wide-bracket set is where the multiplier matters (Table 1a) and where the constant-free variant is the cheaper form, 2073 against 2357. Over both sets the base rule needs 4991 and the constant-free variant 5450, against 4100 for Chandrupatla, 4743 for the ITP oracle, 5724 for TOMS 748 and 5945 for Brent.
|
||||
|
||||
### 5.1 What the guarantee costs
|
||||
|
||||
@@ -249,22 +248,20 @@ It depends on which bound is bought. Against the identical rule with no safeguar
|
||||
|
||||
| | solved | total evals | runs over the $2\times$ bound |
|
||||
|---|---|---|---|
|
||||
| APS, no safeguard | 153/154 | 2806 | 0 |
|
||||
| APS, projection — base rule ($2\times$ bisection) | 153/154 | 2806 | 0 |
|
||||
| APS, earned projection — constant-free (bisection + 1 step) | 153/154 | 3568 | 0 |
|
||||
| Chandrupatla, no safeguard | 35/45 | 4104 | 10 |
|
||||
| Chandrupatla, projection — base rule | 40/45 | 3220 | 0 |
|
||||
| Chandrupatla, earned projection — constant-free | **40/45** | **3020** | **0** |
|
||||
| APS, no safeguard | 154/154 | 2634 | 0 |
|
||||
| APS, projection — base rule ($2\times$ bisection) | 154/154 | 2634 | 0 |
|
||||
| APS, earned projection — constant-free (bisection + 1 step) | 154/154 | 3377 | 0 |
|
||||
| Chandrupatla, no safeguard | 39/45 | 3391 | 10 |
|
||||
| Chandrupatla, projection — base rule | 45/45 | 2357 | 0 |
|
||||
| Chandrupatla, earned projection — constant-free | **45/45** | **2073** | **0** |
|
||||
|
||||
The projection of the base rule never binds on the canonical set, so its totals are identical to the last evaluation; on the wide-bracket set it solves five more problems for 21% fewer evaluations. The earned projection promises twice as much — a worst case of bisection plus one step instead of twice bisection — and pays for it on the canonical set, 762 evaluations or 27%, while on the wide-bracket set it is the cheapest of the three. Both are the opposite of the usual trade on at least one set, and that is the point of projecting rather than replacing: the two safeguards that replace cost 7260 and 7239 on Alefeld–Potra–Shi, against 2806.
|
||||
The projection of the base rule never binds on the canonical set, so its totals are identical to the last evaluation; on the wide-bracket set it solves six more problems for 30% fewer evaluations. The earned projection promises twice as much — a worst case of bisection plus one step instead of twice bisection — and pays for it on the canonical set, 743 evaluations or 28%, while on the wide-bracket set it is the cheapest of the three. Both are the opposite of the usual trade on at least one set, and that is the point of projecting rather than replacing: the two safeguards that replace cost 7068 and 7046 on Alefeld–Potra–Shi, against 2634.
|
||||
|
||||
### 5.2 Wall-clock time, and why it is not the cost model
|
||||
|
||||
Evaluations of $f$ are the cost model because in any real problem $f$ is the expensive part. Wall-clock time measures something narrower — the method's own arithmetic per step — and it is implementation- and language-bound. We report it because a reader will ask, and because what it shows is instructive.
|
||||
|
||||
On the 199 problems as they stand, every $f$ being a formula of a few operations, the base rule is the **slowest** of the pure-Python methods compared, at 32.8 ms against 18.4 for Brent, 21.1 for ITP, 14.2 for Ridders and 22.9 for bisection — while using the fewest evaluations of all of them, 4991 against 5932, 5675, 6421 and 9474. Bisection, needing nearly twice the evaluations, finishes in two thirds of our time.
|
||||
|
||||
Those evaluation counts are *raw*: they are what the timing loop actually spent, and a failed run contributes only the evaluations it made before the budget ran out. They are therefore not the totals of §5, where a failure is charged the full 200-evaluation budget so that no method can buy a low score by giving up — 4991 raw against 6026 charged for the base rule, 5932 against 6991 for Brent (our pure-Python implementation, which is what is timed; the tables use the library's `brentq`, 7004), 9474 against 10620 for bisection. Wall-clock time can only be compared against what was really executed, so the raw counts are the right companions to the milliseconds; every comparison in §5 uses the charged ones. Both are stated to avoid the appearance of two incompatible sets of numbers for the same methods.
|
||||
On the 199 problems as they stand, every $f$ being a formula of a few operations, the base rule is the **slowest** of the pure-Python methods compared, at 32.8 ms against 18.4 for Brent, 21.1 for ITP, 14.2 for Ridders and 22.9 for bisection — while using the fewest evaluations of all of them, 4991 against 5932, 5675, 6421 and 9474. Bisection, needing nearly twice the evaluations, finishes in two thirds of our time. (These are the evaluations the timing loop actually spent; for the base rule and bisection, which solve every problem, they equal the totals of §5; Brent here is our pure-Python implementation, which is what is timed.)
|
||||
|
||||
That inversion is the point. Making $f$ progressively more expensive by a controlled amount of arithmetic and timing the sweep directly — nothing subtracted, nothing modelled — the base rule overtakes ITP once one call to $f$ costs about 9 µs and Brent at about 20 µs, which on this machine is of the order of a hundred arithmetic operations. Below that the ranking is decided by per-step overhead; above it, by evaluations.
|
||||
|
||||
@@ -272,18 +269,18 @@ Three caveats, all of them limitations of the measurement rather than of the met
|
||||
|
||||
### 5.3 The law across the whole grid
|
||||
|
||||
Corollaries 1–3 predict an ordering of the nine similarity functions and of the four scales. Table 4 reports it. The prediction holds without exception for every data-derived scale: the three similarities with $c=1$ occupy the top three places and the three with $c=0$ the bottom three. For the chosen scale the two groups are indistinguishable (16102 against 15345), which is consistent — with a chosen scale nothing converges well and the ordering carries no information.
|
||||
Corollaries 1–3 predict that the similarities with $c=1$ come before those with $c=0$ under a data-derived scale; they say nothing about the order within a group, nor about the functions with unbounded slope. Table 4 reports it. For every data-derived scale the three similarities with $c=1$ occupy the top three places and the three with $c=0$ the bottom three. That $c=0$ is slow is the unsurprising half — a step proportional to $z^2$ is damped quadratically. For the chosen scale the two groups are indistinguishable (14983 against 14228), which is consistent — with a chosen scale nothing converges well and the ordering carries no information.
|
||||
|
||||
**Table 4.** Mean total evaluations over both sets, step guard, grouped by the slope $c$ of $1-S$ at the origin.
|
||||
|
||||
| scale | $c=1$ (linear approach) | $c=0$ (quadratic approach) |
|
||||
|---|---|---|
|
||||
| 3-point derived | **6893** | 22315 |
|
||||
| 2-point derived | 6981 | 22206 |
|
||||
| bracket | 10279 | 19127 |
|
||||
| start (chosen) | 16102 | 15345 |
|
||||
| 3-point derived | **5764** | 21200 |
|
||||
| 2-point derived | 5854 | 21089 |
|
||||
| bracket | 9149 | 18015 |
|
||||
| start (chosen) | 14983 | 14228 |
|
||||
|
||||
Ranked individually and best over scales, the similarities come out $1-|z|$ (6560), $e^{-|z|}$ (6895), $1/(1+|z|)$ (7118), $(1+|z|)^{-2}$ (9578), $1-\sqrt{|z|}$ (10546), $1-|z|^{1/3}$ (12002), $e^{-z^2}$ (14307), $1/(1+z^2)$ (15102), $1/\sqrt{1+z^2}$ (16394); the scales come out 3-point (6560), 2-point (6702), bracket (9107), start (14540). Both orderings are those the law predicts, and both were predicted before the grid was run.
|
||||
Ranked individually and best over scales, the similarities come out $1-|z|$ (5422), $e^{-|z|}$ (5772), $1/(1+|z|)$ (5993), $(1+|z|)^{-2}$ (8455), $1-\sqrt{|z|}$ (9411), $1-|z|^{1/3}$ (10874), $e^{-z^2}$ (13187), $1/(1+z^2)$ (13990), $1/\sqrt{1+z^2}$ (15272); the scales come out 3-point (5422), 2-point (5564), bracket (7972), start (13423). The group order and the order of the scales are those the law predicts and were predicted before the grid was run; the order inside each group is measured, not predicted.
|
||||
|
||||
---
|
||||
|
||||
@@ -293,7 +290,7 @@ Splitting each run at the geometric mean of the initial width and the attainable
|
||||
|
||||
Two natural explanations of the Chandrupatla advantage were tested and *refuted*. Brent discards 53.3% of its interpolations to its safeguard on the set it wins and only 34.0% on the set it loses, so safeguard rate is not the mechanism; and on Chandrupatla Brent is the bolder of the two — 56.3% of its probes land in the outer tenths of the bracket against our 41.8% — so step length is not the mechanism either.
|
||||
|
||||
The mechanism is step *quality*. Reconstructing each method's bracket from the signs it observed, the median probe removes 0.500 of the bracket for every method on Alefeld–Potra–Shi, but on Chandrupatla it removes 0.275 for the similarity rule against 0.058 for Brent and 0.068 for TOMS 748 — and that comparison already flatters them, since 69 and 141 of their probes respectively fall outside the proven bracket and are excluded, against none of ours. High-order interpolation is a wager that $f$ is locally polynomial. When the wager pays, order 1.84 or 2.65 wins the endgame; when it fails, the probes are wasted. The similarity rule makes the weakest available assumption — a single local slope — and degrades gracefully.
|
||||
The mechanism is step *quality*. Reconstructing each method's bracket from the signs it observed, the median probe removes 0.500 of the bracket for every method on Alefeld–Potra–Shi, but on Chandrupatla it removes 0.275 for the similarity rule against 0.058 for Brent and 0.068 for TOMS 748. The bracket here is reconstructed from *every* sign the method has observed — the narrowest interval the evaluations prove, not the one the method keeps; Brent and TOMS 748 always probe inside their own bracket, but 69 and 141 of their probes fall outside this narrowest one and remove nothing from it, and those probes are left out of the median. High-order interpolation is a wager that $f$ is locally polynomial. When the wager pays, a high order wins the endgame; when it fails, the probe removes little. The similarity rule makes the weakest available assumption — a single local slope — and degrades gracefully.
|
||||
|
||||
---
|
||||
|
||||
@@ -301,7 +298,7 @@ The mechanism is step *quality*. Reconstructing each method's bracket from the s
|
||||
|
||||
Everything above reads the similarity in one place: the *length* of the step, $(1-S(z))$ times the distance to the far end. But a bracketing iteration takes several decisions per step, and the similarity was not consulted in any of the others: which end counts as far (decided by distance), which points the local slope is estimated from (decided by recency), and whether the step is worth taking at all (decided after the fact, by the safeguard). Each of those is a place where a similarity can be read, and the placement turns out to matter more than the form of $S$.
|
||||
|
||||
Three readings were added to the base rule of §3 (tent similarity, three-point scale), each parameter-free and each measured on the protocol of §4; every number below is re-checked against its own sweep file by `verify_article.py`, and every configuration in Table 5 keeps the $2\lceil\log_2(w_0/\varepsilon_x)\rceil+3$ guarantee (0 violations) and solves 193 of the 199 problems.
|
||||
Three readings were added to the base rule of §3 (tent similarity, three-point scale), each parameter-free and each measured on the protocol of §4; every number below is re-checked against its own sweep file by `verify_article.py`, and every configuration in Table 5 keeps the $2\lceil\log_2(w_0/\varepsilon_x)\rceil+3$ guarantee (0 violations) and solves all 199 problems.
|
||||
|
||||
Where a safeguard other than the projection of §3.1 appears, it is one of the grid's. *safe* is the projection preceded by a step-length test — a step not at most half the step taken two evaluations earlier is replaced by a halving — with the projection still carrying the bound. *credit* replaces the scheduled allowance of (3) by one earned step by step: a surplus is banked whenever a step shrinks the bracket by more than half and drawn on when it shrinks it by less, which bounds the run by bisection plus one step. *bracket* and *both* are the replacing safeguards of §3.1, which keep a bound at the price of the order; *step* alone and *none* carry no bound.
|
||||
|
||||
@@ -311,25 +308,25 @@ Where a safeguard other than the projection of §3.1 appears, it is one of the g
|
||||
|
||||
**Table 5.** Reading the similarity in one more place is worth more than changing $S$. Evaluations of $f$; failures charged the full budget.
|
||||
|
||||
| configuration (all with the guarantee, 193/199) | APS-154 | CHA-45 | both |
|
||||
| configuration (all with the guarantee, 199/199) | APS-154 | CHA-45 | both |
|
||||
|---|---|---|---|
|
||||
| base rule: tent, 3-point, projection $c=2$ (§3) | 2806 | 3220 | 6026 |
|
||||
| constant-free variant: earned projection (§3.1) | 3568 | 3020 | 6588 |
|
||||
| (1) trust before the step, projection | 2848 | 3114 | 5962 |
|
||||
| (1)+(2) points chosen by shape, *safe* | **2527** | 3126 | 5653 |
|
||||
| (1)+(3) far end by dissimilarity, projection | 2726 | **2799** | **5525** |
|
||||
| (1)+(2)+(3), *safe* | 2884 | 2871 | 5755 |
|
||||
| Chandrupatla | 2787 | 2441 | 5228 |
|
||||
| TOMS 748 | 2820 | 4000 | 6820 |
|
||||
| ITP, per-problem oracle | 3260 | 2647 | 5907 |
|
||||
| base rule: tent, 3-point, projection $c=2$ (§3) | 2634 | 2357 | 4991 |
|
||||
| constant-free variant: earned projection (§3.1) | 3377 | 2073 | 5450 |
|
||||
| (1) trust before the step, projection | 2663 | 2170 | 4833 |
|
||||
| (1)+(2) points chosen by shape, *safe* | **2337** | 2177 | 4514 |
|
||||
| (1)+(3) far end by dissimilarity, projection | 2539 | **1864** | **4403** |
|
||||
| (1)+(2)+(3), *safe* | 2695 | 1928 | 4623 |
|
||||
| Chandrupatla | 2595 | 1505 | 4100 |
|
||||
| TOMS 748 | 2636 | 3088 | 5724 |
|
||||
| ITP, per-problem oracle | 3068 | 1675 | 4743 |
|
||||
|
||||
Two results here are worth stating plainly. First, the canonical set improves from 2806 to **2527**, which is below every method measured, including Chandrupatla's 2787, with the worst-case guarantee intact. It hardly feels the declared multiplier of §3.1: 2527 for every multiplier from 1.5 to 4, 2541 at 1.25 (`measure_records_vs_multiplier.py`). Second, on the two sets together the 5525 of reading (3) passes ITP's oracle (5907) but not Chandrupatla (5228): the remaining gap is entirely on the wide-bracket families, where Chandrupatla needs 2441 against our 2695 (reading (3) under *safe*).
|
||||
Two results here are worth stating plainly. First, the canonical set improves from 2634 to **2337**, which is below every method measured, including Chandrupatla's 2595, with the worst-case guarantee intact. It hardly feels the declared multiplier of §3.1: 2337 for every multiplier from 1.5 to 4, 2351 at 1.25 (`measure_records_vs_multiplier.py`). Second, on the two sets together the 4403 of reading (3) passes ITP's oracle (4743) but not Chandrupatla (4100): the remaining gap is entirely on the wide-bracket families, where Chandrupatla needs 1505 against our 1752 (reading (3) under *safe*).
|
||||
|
||||
The readings do not compose. Taken together, (2) and (3) give 2884 and 2871 — worse than either alone on the canonical set, and on the wide-bracket set worse than (3) alone. Two selections that are each an improvement interfere, which is a reason to measure composition rather than assume it.
|
||||
The readings do not compose. Taken together, (2) and (3) give 2695 and 1928 — worse than either alone on the canonical set, and on the wide-bracket set worse than (3) alone. Two selections that are each an improvement interfere, which is a reason to measure composition rather than assume it.
|
||||
|
||||
**Which similarity stands in the step decides whether a reading pays.** The readings above, and the decision *defect* of §7.2, compare quantities directly — an ordinal judgment of which is more similar, in which every decreasing $S$ would decide alike. Their gains nevertheless depend on the $S$ that sets the step (`audit_similarity_places.py`, on the same sweeps): on the canonical set the triple chosen by shape gains 493 evaluations with the tent in the step and loses 250 with $1/\sqrt{1+z^2}$; *defect* gains 283 with the tent and loses 215 with $1-|z|^{1/3}$. The records of this section are the pairing of the tent step with these judgments, not the judgments alone.
|
||||
|
||||
Under the constant-free earned projection the same readings gain far less. Reading (1) gives 3507 and 2997, (1)+(2) 3755 and 3021, (1)+(3) 3857 and 3002, all three together 4354 and 3037, against 3568 and 3020 for the constant-free variant itself: the earned budget binds early on the canonical problems, and what the readings buy under the projection is mostly room that the earned budget does not grant.
|
||||
Under the constant-free earned projection the same readings gain little or lose. Reading (1) gives 3316 and 2050, (1)+(2) 3564 and 2074, (1)+(3) 3666 and 2052, all three together 4163 and 2087, against 3377 and 2073 for the constant-free variant itself: the earned budget binds early on the canonical problems, and what the readings buy under the projection is mostly room that the earned budget does not grant.
|
||||
|
||||
### 7.1 The similarity function belongs to the place, not to the method
|
||||
|
||||
@@ -339,21 +336,21 @@ $$z \;=\; \frac{|f(x)|}{|f(x_\mathrm{far})|} \;=\; \Bigl(\frac{e}{E}\Bigr)^{m},
|
||||
|
||||
and under the ratio similarity $S=1/(1+|z|)$ the step fraction is $z/(1+z)$, which is exactly inverse linear interpolation. False position therefore reads a dimensionless ratio *at order one* on an approach of order $m$: its three-century-old stall is a mismatch between the similarity function and the place it is read in. The exponent $1/m$ is not a constant — $m=1/(1-ff''/f'^2)$, Lagouanelle's estimate of the multiplicity [13] with the derivatives replaced by divided differences, comes from three evaluations already paid for, as in item 5 of §10, and is 1 whenever the power model does not apply.
|
||||
|
||||
Measured over the 252 cells of the grid, the correction behaves exactly as that reading predicts and not at all as a universal improvement. Paired inside each (function, safeguard) cell of the far-end reading it is cheaper in 29 of 60 cells — indistinguishable from a coin. But in the one pairing where that reading *is* exact inverse interpolation, the ratio similarity, it is cheaper under all seven safeguards:
|
||||
Measured over the grid, the correction behaves as that reading predicts and not as a universal improvement. Paired inside each (function, safeguard) cell of the far-end reading it is cheaper in 33 of 63 cells — indistinguishable from a coin. But in the one pairing where that reading *is* exact inverse interpolation, the ratio similarity, it is cheaper under all seven safeguards:
|
||||
|
||||
**Table 6.** The measured order in the step place, on the far-end reading with the ratio similarity $1/(1+|z|)$. Cheaper in 7 of 7 safeguards; in 29 of 60 cells over all nine functions.
|
||||
**Table 6.** The measured order in the step place, on the far-end reading with the ratio similarity $1/(1+|z|)$. Cheaper in 7 of 7 safeguards; in 33 of 63 cells over all nine functions.
|
||||
|
||||
| safeguard | APS, $m=1$ | APS, measured $m$ | CHA, $m=1$ | CHA, measured $m$ |
|
||||
|---|---|---|---|---|
|
||||
| both | 4522 | **3675** | 3406 | **3241** |
|
||||
| bracket | 4606 | **3542** | 3602 | **3359** |
|
||||
| credit | 5190 | **4686** | 3013 | **2884** |
|
||||
| projection | 6932 | **6364** | 4789 | **4554** |
|
||||
| safe | 5987 | **5229** | 4134 | **3954** |
|
||||
| step | 6435 | **5551** | 4287 | **4068** |
|
||||
| none | 10676 | **10043** | 8265 | **7794** |
|
||||
| both | 4331 | **3485** | 2469 | **2306** |
|
||||
| bracket | 4418 | **3352** | 2671 | **2428** |
|
||||
| credit | 4999 | **4495** | 2064 | **1933** |
|
||||
| projection | 6783 | **6176** | 4057 | **3751** |
|
||||
| safe | 5803 | **5040** | 3218 | **3032** |
|
||||
| step | 6251 | **5362** | 3371 | **3146** |
|
||||
| none | 10676 | **9855** | 8265 | **7424** |
|
||||
|
||||
Two limits must be stated with it. The estimator is *biased low*: on a pure cube, with no noise at all, it returns 2.830 rather than 3, because a parabola through three points carries only the second difference. The bias is towards $m=1$, that is towards the uncorrected reading, which is the harmless direction, but it is a bias. And the correction does not rescue the far-end reading as a method: the best cell it reaches on the wide-bracket set is 2884, against 2695 for reading (3) above and 2441 for Chandrupatla. In the *slope* reading of §3 the same exponent is harmful, $2806\to2854$, which is the same statement read from the other side — a function that does not belong to a place does not become right by being applied there.
|
||||
Two limits must be stated with it. The estimator is *biased low*: on a pure cube, with no noise at all, it returns 2.830 rather than 3, because a parabola through three points carries only the second difference. The bias is towards $m=1$, that is towards the uncorrected reading, which is the harmless direction, but it is a bias. And the correction does not rescue the far-end reading as a method: the best cell it reaches on the wide-bracket set is 1933, against 1752 for reading (3) above and 1505 for Chandrupatla. In the *slope* reading of §3 the same exponent is harmful, $2634\to2703$, which is the same statement read from the other side — a function that does not belong to a place does not become right by being applied there.
|
||||
|
||||
### 7.2 The decision place
|
||||
|
||||
@@ -361,47 +358,36 @@ Three places have now been measured: the step length, the far end, and the point
|
||||
|
||||
Three readings of that place were measured, each on quantities already in hand and each without a constant. Two are ours: refuse when the configuration is less like a linear one than the iterate is off-centre, $|\varphi-\xi|>\min(\xi,1-\xi)$ ("defect"); and refuse when the configuration's similarity to linear falls below the iterate's similarity to the root, $S(|\varphi-\xi|)<S(z)$, with the *same* $S$ in both places ("simpair"). The third is *Chandrupatla's own band*, placed inside our step rule. It is not a proposal; it is an instrument, and it answers whether the remaining gap lives in this place.
|
||||
|
||||
In total, no. With Chandrupatla's band in our step, the wide-bracket set costs 3059 under the projection and 2892 under *credit*, against his 2441, while the canonical set rises from 2806 to 5432. The band is not idle — it refuses 63.5% of steps — so this is a decision that was taken and did not pay *in total*. Per family it did pay, and where: it closes almost the whole gap on the flat families and gives back more than that on the families where our step is good. §7.4 takes this apart; the short form is that the decision place does hold most of the gap, but no reading measured so far makes that decision correctly for *our* step.
|
||||
In total, no. With Chandrupatla's band in our step, the wide-bracket set costs 2101 under the projection and 1942 under *credit*, against that method's own 1505, while the canonical set rises from 2634 to 5242. The band is not idle — it refuses 63.5% of steps — so this is a decision that was taken and did not pay *in total*. Per family it did pay, and where: it closes almost the whole gap on the flat families and gives back more than that on the families where our step is good. §7.4 takes this apart; the short form is that the decision place does hold most of the gap, but no reading measured so far makes that decision correctly for *our* step.
|
||||
|
||||
Our own readings do not close it either (best 2897 on the wide-bracket set), but "defect" sets a new best on the canonical set: **2523** at 153/154 under the projection of the base rule, below the 2527 of reading (2) and below every method measured, with the guarantee intact — and, unlike 2527, the same for every multiplier from 1.25 to 4. Under the earned projection it gives 3545 and 2949 (6494 against 6588), the best of the readings of this section without a constant; the flat regime of §8 does better still. It refuses only 6.6% of steps, the fewest of the three. Over both sets it costs 5733 against the 5525 of reading (3), because it gives back on the wide brackets (3210) what it gains on the canonical problems — so it is a second point on the same trade, not a replacement.
|
||||
Our own readings do not close it either (best 1941 on the wide-bracket set), but "defect" gives the second-best canonical total: **2351** under the projection of the base rule, next to the 2337 of reading (2) and below every method measured, with the guarantee intact, and between 2343 and 2353 for every multiplier from 1.25 to 4. Under the earned projection it gives 3354 and 2002 (5356 against 5450), the best of the readings of this section without a constant; the flat regime of §8 does better still. It refuses only 6.6% of steps, the fewest of the three. Over both sets it costs 4697 against the 4403 of reading (3), because it gives back on the wide brackets (2346) what it gains on the canonical problems — so it is a second point on the same trade, not a replacement.
|
||||
|
||||
### 7.3 Six problems of the two sets are scored unsolved for every method
|
||||
### 7.3 Why the criterion is a sign change: six problems the published root cannot score
|
||||
|
||||
Chasing the remaining gap to Chandrupatla led to a property of the benchmarks themselves. On the five problems of the wide-bracket family `fun7`, and on the single canonical problem `aps.13.00`, the declared root is 0 while $f$ vanishes *identically* on a neighbourhood of it in floating point: $f(0\pm t)=0$ for every $t$ up to at least $3.2\times10^{-2}$, because the exponential factor underflows — at the returned points $|f(x)|$ is below the smallest normal double. Every method therefore stops after 8 to 28 evaluations at a point where $f(x)=0$ *exactly* — a genuine root — and every method is then scored as having failed, because the harness asks for $|x-\text{root}|\le10^{-6}$ while the returned point sits up to $2.8\times10^{-2}$ away.
|
||||
|
||||
The consequence is arithmetic. Each such problem charges the full budget of 200 evaluations to every method: about 1150 evaluations of every reported two-set total — ours, Chandrupatla's, TOMS 748's, ITP's, Brent's, bisection's — are this artefact, and the "153 of 154" and "40 of 45" that every method reports are statements about the scoring rather than about the methods. Re-scored with the criterion "a root is a root" ($|x-\text{root}|\le10^{-6}$ *or* $f(x)=0$), the same runs solve 199 of 199 for every method except Brent's 197, and the totals fall as follows.
|
||||
The consequence is arithmetic. Each such problem charges the full budget of 200 evaluations to every method, so about 1150 evaluations of every two-set total under the harness — ours and every competitor's — are this artefact, and the "153 of 154" and "40 of 45" that every method reports under the harness are statements about the scoring rather than about the methods. This is why every number in this paper uses the bracketing criterion of §4, a sign change within $10^{-6}$ of the returned point or $f=0$ there: under it Chandrupatla, TOMS 748, ITP, bisection and every configuration of Table 5 solve all 199, Brent 197, Dekker and Illinois 178 and 177.
|
||||
|
||||
**Table 7.** The same runs under the harness criterion and under "a root is a root". The ranking is unchanged; the magnitudes are not, and neither is the size of the remaining gap on the wide-bracket set: 235 evaluations, or 16%, not 10%.
|
||||
|
||||
| method | APS as scored | APS re-scored | CHA as scored | CHA re-scored |
|
||||
|---|---|---|---|---|
|
||||
| ours, (1)+(2) points by shape | **2527** | **2337** | 3108 | 2159 |
|
||||
| ours, base rule (projection) | 2806 | 2634 | 3220 | 2357 |
|
||||
| Chandrupatla | 2787 | 2595 | **2441** | **1505** |
|
||||
| TOMS 748 | 2820 | 2636 | 4000 | 3088 |
|
||||
| Brent | 2889 | 2707 | 4115 | 3238 |
|
||||
| ITP | 3957 | 3767 | 2896 | 1907 |
|
||||
| bisection | 7530 | 7338 | 3090 | 2136 |
|
||||
|
||||
### 7.4 Where the wide-bracket limit actually is
|
||||
|
||||
The remaining gap looks diffuse — per family +57, +49, +42, +39, +30 and smaller — but part of it has one address. The `fun1` family is the same function with brackets of growing width, and our cost against Chandrupatla's across them is 7/8, 12/12, 19/15, 59/24, 63/44: we tie or win while the bracket is narrow and lose progressively as it widens. The endgame is not the cause — our observed order on those very problems is the higher one (3.63 against 2.02 on the $2\times10^4$-wide bracket). The cause is the rate of progress far from the root: 59 evaluations on a $2\times10^4$-wide bracket is what bisection itself needs ($\lceil\log_2(2\times10^{16})\rceil\approx54$), i.e. there we advance by about one halving per evaluation while Chandrupatla advances by about 2.3.
|
||||
The remaining gap looks diffuse — per family +57, +49, +42, +39, +30 and smaller — but part of it has one address. The `fun1` family is the same function with brackets of growing width, and our cost against Chandrupatla's across them is 7/8, 12/12, 19/15, 59/24, 63/44: we tie or win while the bracket is narrow and lose progressively as it widens. The endgame is not the cause; the cost is incurred far from the root: 59 evaluations on a $2\times10^4$-wide bracket is what bisection itself needs ($\lceil\log_2(2\times10^{16})\rceil\approx54$), i.e. there we advance by about one halving per evaluation while Chandrupatla advances by about 2.3.
|
||||
|
||||
It is not the guarantee that caps us. With the safeguard removed entirely the same problems cost 46, 57, 61 and 68 against bisection's 57, 77, 45 and 45 — better on the wide brackets, *worse than bisection* on `fun3.1` and `fun5.1` — and still far from Chandrupatla's 24 and 44.
|
||||
It is not the guarantee that caps us. (The five costs above are under the *safe* safeguard; under the projection of the base rule they are 7, 12, 30, 46, 57.) With the safeguard removed entirely the two widest brackets, `fun1.4` and `fun1.5`, cost 46 and 57: better than bisection's 57 and 77, still far from Chandrupatla's 24 and 44. Unguarded, the rule is worse than bisection elsewhere — 61 and 68 against 45 on the flat problems `fun3.1` and `fun5.1` — which is what the guarantee is for.
|
||||
|
||||
Nor is it that the step fails to be relative to the bracket. With the tent similarity $1-S=\min(1,|f|/(|\hat f'|D))$, so by (4) the step is exactly $\min(D,|f|/|\hat f'|)$: a *fraction* of the distance to the far end, and the similarity is that fraction. Nor does the iterate creep along one side without moving the proven bracket: measured probe by probe, 91.5% of our evaluations on the $2\times10^4$-wide bracket do shrink the bracket, slightly *more* often than Chandrupatla's 87.5%.
|
||||
|
||||
What differs on `fun1` is how much each probe removes. Ours shrinks the bracket by 0.93 halvings per evaluation there, Chandrupatla's by 2.30. On a wide bracket of a convex function the Newton step systematically undershoots, because a linear model of the value axis cannot see the curvature that separates the iterate from the root; a model that carries the curvature — inverse quadratic interpolation — lands far closer.
|
||||
|
||||
That mechanism is right for `fun1` and *wrong as a statement about the whole gap*. Replaying our own trajectories on the 33 problems where we lose, and placing both models on the *same* evaluations — one extra evaluation each, from the same state — splits the 256 evaluations of the gap in two. On `fun1` (58 of them, about a quarter) inverse quadratic interpolation from our own three points removes far more of the bracket than our step did: 10.37 halvings against 0.62 on the $2\times10^4$-wide bracket. There the gap is the order of the model, and the reason is structural: our step $x+(1-S)(x_\mathrm{far}-x)=S\,x+(1-S)\,x_\mathrm{far}$ is a convex combination of two points, while the quadratic interpolant's Lagrange weights at 0 always include exactly one *negative* weight when the triple brackets the root (verified on all 428 non-degenerate states; in the other three the negative weight underflowed to $-0$). A similarity in $[0,1]$ cannot produce a negative weight — Proposition 1 extended from two points to three.
|
||||
That mechanism is right for `fun1` and *wrong as a statement about the whole gap*. Replaying our own trajectories on the 35 problems where we lose, and placing both models on the *same* evaluations — one extra evaluation each, from the same state — splits the 262 evaluations of the gap in two. On `fun1` (58 of them, about a fifth) inverse quadratic interpolation from our own three points removes far more of the bracket than our step did: 10.37 halvings against 0.62 on the $2\times10^4$-wide bracket. There the gap is the order of the model, and the reason is structural: our step $x+(1-S)(x_\mathrm{far}-x)=S\,x+(1-S)\,x_\mathrm{far}$ is a convex combination of two points, while the quadratic interpolant's Lagrange weights at 0 always include exactly one *negative* weight when the triple brackets the root (verified on all 431 non-degenerate states; in the other three the negative weight underflowed to $-0$). A similarity in $[0,1]$ cannot produce a negative weight — Proposition 1 extended from two points to three.
|
||||
|
||||
But 172 of the 256 — two thirds — sit on `fun3`–`fun6`, which are pure powers of order 3, 5, 9 and 19, and there *no* interpolating model works: our step removes 0.41–0.75 halvings of the bracket per evaluation, inverse quadratic interpolation from the same points only 0.01–0.17. Chandrupatla does not win those families with his model — his traced run bisects 92, 96, 100 and 100% of his steps. We lose them because our step is slower than bisection there and our guarantee, at most twice bisection, licenses exactly that. His band inside our step confirms it family by family: under the projection it takes `fun4`, `fun5`, `fun6` from 573, 456, 456 to 296, 239, 228 — against his own 297, 233, 233 — and costs +164, +111, +170, +144 on `fun1`, `fun2`, `fun8`, `fun9`, where it refuses steps that were good.
|
||||
But 172 of the 262 — two thirds — sit on `fun3`–`fun6`, which are pure powers of order 3, 5, 9 and 19, and there *no* interpolating model works: our step removes 0.41–0.75 halvings of the bracket per evaluation, inverse quadratic interpolation from the same points only 0.01–0.17. Chandrupatla does not win those families with his model — his traced run bisects 92, 96, 100 and 100% of his steps. We lose them because our step is slower than bisection there and our guarantee, at most twice bisection, licenses exactly that. His band inside our step confirms it family by family: under the projection it takes `fun4`, `fun5`, `fun6` from 573, 456, 456 to 296, 239, 228 — against his own 297, 233, 233 — and costs +164, +111, +170, +144 on `fun1`, `fun2`, `fun8`, `fun9`, where it refuses steps that were good.
|
||||
|
||||
So most of what remains is not the order of the model but the decision *when to give the model up*, and it is open because every detector measured so far confounds "the model is useless here" with something else: the band with "the configuration is not shaped for inverse quadratic interpolation", bracket progress with "the step has not moved the bracket yet" (4449 on the canonical set, §10), and the local order with nothing at all — $m\ge2$ is exactly the condition under which a tangent step loses to a halving, since it lands at $e(1-1/m)$, and it is clean (0.2% of canonical states) but blind: it reports $m\ge2$ on none of the states of families whose order is by construction 3 to 19. For the `fun1` part, three parameter-free ways round the model order have been measured and all three fail in the same way, buying the wide brackets at the price of the canonical set: a fixed fraction of the bracket (the cube-root similarity), a logarithmic change of variable, and the curvature-corrected scale of §10 item 5. The fourth way is to model the curvature directly, which is inverse quadratic interpolation — a different method rather than another reading of this one. Section 8 shows that the decision is reachable without a new model: by a similarity of the run to its own past.
|
||||
So most of what remains is not the order of the model but the decision *when to give the model up*, and it is open because every detector measured so far confounds "the model is useless here" with something else: the band with "the configuration is not shaped for inverse quadratic interpolation", bracket progress with "the step has not moved the bracket yet" (4258 on the canonical set, §10), and the local order with nothing at all — $m\ge2$ is exactly the condition under which a tangent step loses to a halving, since it lands at $e(1-1/m)$, and it is clean (0.3% of canonical states) but blind: it reports $m\ge2$ on none of the states of families whose order is by construction 3 to 19. For the `fun1` part, three parameter-free ways round the model order have been measured and all three fail in the same way, buying the wide brackets at the price of the canonical set: a fixed fraction of the bracket (the cube-root similarity), a logarithmic change of variable, and the curvature-corrected scale of §10 item 5. The fourth way is to model the curvature directly, which is inverse quadratic interpolation — a different method rather than another reading of this one. Section 8 shows that the decision is reachable without a new model: by a similarity of the run to its own past.
|
||||
|
||||
On the re-scored wide-bracket set of Table 7 our shape reading (2159) is *worse* than bisection (2136); only the dissimilarity reading (1740) is clearly ahead, which is the same statement seen from the other end: where the step cannot march, the reading that helps least is the one that only improves the local model.
|
||||
On the wide-bracket set our shape reading (2177) is *worse* than bisection (2136); only the dissimilarity reading (1752 under *safe*) is clearly ahead, which is the same statement seen from the other end: where the step cannot march, the reading that helps least is the one that only improves the local model.
|
||||
|
||||
Every statement in §§7.3–7.4 is reproduced by `diag_rescore_cha.py`, `diag_rescore_aps.py`, `diag_fun7_root.py`, `diag_cha_gap.py`, `diag_model_order.py`, `diag_model_order_checks.py`, `diag_flat_detectable.py` and `diag_band_by_family.py`, whose outputs are kept beside them.
|
||||
Every statement in §§7.3–7.4 is reproduced by `diag_fun7_root.py`, `diag_cha_gap.py`, `diag_who_caps_us.py`, `diag_model_order.py`, `diag_model_order_checks.py`, `diag_flat_detectable.py` and `diag_band_by_family.py`, whose outputs are kept beside them.
|
||||
|
||||
## 8. The flat regime, recognised by analogy
|
||||
|
||||
@@ -411,7 +397,7 @@ Every statement in §§7.3–7.4 is reproduced by `diag_rescore_cha.py`, `diag_r
|
||||
|
||||
A tangent step on an approach of local order $m$ lands at $e(1-1/m)$ and leaves the residual $r=|f_\text{new}/f_\text{old}|=(1-1/m)^m$ on the same side of the root. It beats a halving exactly when $|1-1/m|<\tfrac12$, that is for $\tfrac23<m<2$. At the upper end $r=(1-\tfrac12)^2=\tfrac14$. So a model step that did not cross the root and left $r\ge\tfrac14$ is a *promise not kept*: the model is in the regime where a halving would have done better. The constant is bisection's $\tfrac12$, carried through the formula. The relation between the order and the contraction, $e(1-1/m)$, is the one behind the classical estimates of multiplicity from successive Newton iterates [14, 15]; here it is not used to estimate $m$ but to set the point at which a model step has lost to a halving.
|
||||
|
||||
The flag sees the regime — on the flat families it rises on most model steps — but acted upon step by step it does not pay. Replacing the one flagged step by a halving costs the canonical set 2806 → 3029, because a simple root far from convergence also breaks its promises (the flag rises at least once on 142 of the 154 canonical problems). Every refinement of *when* to halve that reads the moment alone — twice in a row, the promise together with a creep in one direction, a halving that sticks once begun, a judgment of the evaluated point against the line through the bracket — trades one set for the other (§10, items 12–14).
|
||||
The flag sees the regime — on the flat families it rises on most model steps — but acted upon step by step it does not pay. Replacing the one flagged step by a halving costs the canonical set 2634 → 2839, because a simple root far from convergence also breaks its promises (the flag rises at least once on 142 of the 154 canonical problems). Every refinement of *when* to halve that reads the moment alone — twice in a row, the promise together with a creep in one direction, a halving that sticks once begun, a judgment of the evaluated point against the line through the bracket — trades one set for the other (§10, items 12–14).
|
||||
|
||||
### 8.2 The analogy: similarity of a run to its own past
|
||||
|
||||
@@ -431,7 +417,7 @@ Formula (6) is the log–log slope by which any power-law exponent is estimated,
|
||||
|
||||
**The translation limit.** The exponential is self-similar by *translation*, $e^{x-1}=e^x/e$: along its flank the step does not shrink while $f$ does, so (6) is undefined or negative. That is the limit $m\to\infty$ of (6), steeper than any power, and it is read as $m=\infty$: when an analogous pair shows $L_f<1\le L_x$. A high power far from its root is locally an exponential, $x^m=e^{m\ln x}$, and it was there, not on the flank of `fun9` it was built for, that the limit paid.
|
||||
|
||||
**Exit.** Inside the regime the step splits the bracket (§8.3). At every split the evaluated $f$ is judged against two predictions: the line through the bracket ends, $F_A(1-t)+F_Bt$ at the split fraction $t$, and 0. Nearer the line, the regime is left and the remembered analogy is cleared. A sticky halving without this exit cost the canonical set 6897; with it, 3125 — the exit is what makes a false entry cheap.
|
||||
**Exit.** Inside the regime the step splits the bracket (§8.3). At every split the evaluated $f$ is judged against two predictions: the line through the bracket ends, $F_A(1-t)+F_Bt$ at the split fraction $t$, and 0. Nearer the line, the regime is left and the remembered analogy is cleared. A sticky halving without this exit cost the canonical set 6707; with it, 2935 — the exit is what makes a false entry cheap.
|
||||
|
||||
### 8.3 Where to split: the point from the order
|
||||
|
||||
@@ -443,7 +429,7 @@ which is exact for a pure power and becomes the midpoint as $m\to\infty$. It is
|
||||
|
||||
### 8.4 Five more readings
|
||||
|
||||
**The half the step promises.** $S(z)\ge\tfrac12$ means a step of at most half the way to the far end: the model promises the root in the half of the bracket *near* $x$. The line through the bracket ends puts it nearer the end with the smaller $|f|$. When the far end has the smaller $|f|$ the two disagree about the half, and the evaluation halves. On a steep flank — a slope dominated by $f(81)=1.5\cdot10^{35}$ on `fun9.5` — this is the false promise "the root is here", and removing it alone takes the canonical set from 2806 to 2564. It is a relative of Brent's acceptance condition [2], which admits an interpolant only between the best point and $(3a+b)/4$: both refuse a model that points towards the worse end of the bracket.
|
||||
**The half the step promises.** $S(z)\ge\tfrac12$ means a step of at most half the way to the far end: the model promises the root in the half of the bracket *near* $x$. The line through the bracket ends puts it nearer the end with the smaller $|f|$. When the far end has the smaller $|f|$ the two disagree about the half, and the evaluation halves. On a steep flank — a slope dominated by $f(81)=1.5\cdot10^{35}$ on `fun9.5` — this is the false promise "the root is here", and removing it alone takes the canonical set from 2634 to 2392. It is a relative of Brent's acceptance condition [2], which admits an interpolant only between the best point and $(3a+b)/4$: both refuse a model that points towards the worse end of the bracket.
|
||||
|
||||
**The sign contradiction.** The bracket says which way $f$ must go between its ends; the last two points say which way it goes here. Opposite signs — the local picture contradicts the bracket — and the evaluation halves. It is the cause of the `fun9` well: a near-cancelling end reads the root as close while $|f|$ doubles for seventeen steps.
|
||||
|
||||
@@ -457,20 +443,20 @@ which is exact for a pure power and becomes the midpoint as $m\to\infty$. It is
|
||||
|
||||
The method this paper proposes, **A′**, is the base rule of §3 — tent similarity, three-point scale, projection with the declared multiplier $c=2$ — with the regime of §8.2–8.3 (the analogy remembered, its translation limit, the split (7), the exit) and the five readings of §8.4. Its constants are bisection's $\tfrac12$ and what follows from it: $\tfrac14=(1-\tfrac12)^2$ and the two branches $m\ge2$, $m\le\tfrac23$ of $|1-1/m|>\tfrac12$. Three choices are declared rather than derived: the multiplier $c$ of the projection (§3.1), the Euclidean geometry of the $(\xi,\varphi)$ plane, and the pattern test of the step lengthening (lags from 2 to half the history, threshold $\tfrac12$). The projection carries the guarantee, $2\lceil\log_2(w_0/\varepsilon_x)\rceil+3$ evaluations; it is verified with no violation on every corpus of this paper and under every safeguard of the grid.
|
||||
|
||||
**Table 8.** A′ on the protocol of §4 (published roots, failures charged 200). Per problem against each rival: wins/ties/losses, exact two-sided sign test.
|
||||
**Table 8.** A′ on the two sets of §4 (failures charged 200). A′'s wins/ties/losses against each rival over all problems of the set, exact two-sided sign test.
|
||||
|
||||
| | APS-154 | CHA-45 | both | vs A′ per problem, APS | vs A′ per problem, CHA |
|
||||
| | APS-154 | CHA-45 | both | A′ per problem, APS | A′ per problem, CHA |
|
||||
|---|---|---|---|---|---|
|
||||
| **A′ (proposed)** | **2438** | **2005** | **4443** | — | — |
|
||||
| A′, earned budget (no free constant) | 3608 | 2807 | 6415 | | |
|
||||
| base rule (§3) | 2806 | 3220 | 6026 | | |
|
||||
| Chandrupatla | 2787 | 2441 | 5228 | A′ 103/20/30, $p=1.5\cdot10^{-10}$ | A′ 29/4/7, $p=3\cdot10^{-4}$ |
|
||||
| TOMS 748 | 2820 | 4000 | 6820 | A′ 127/6/20 | A′ 38/2/0 |
|
||||
| Brent | 2889 | 4115 | 7004 | A′ 118/17/18 | A′ 33/3/2 |
|
||||
| ITP, per-problem oracle | 3260 | 2647 | 5907 | A′ 126/7/20 | A′ 35/1/4 |
|
||||
| ModAB [10, 20] | 2914 | 2436 | 5350 | A′ 118/11/25 | A′ 32/9/4 |
|
||||
| **A′ (proposed)** | **2259** | **1074** | **3333** | — | — |
|
||||
| A′, earned budget (no free constant) | 3417 | 1852 | 5269 | | |
|
||||
| base rule (§3) | 2634 | 2357 | 4991 | | |
|
||||
| Chandrupatla | 2595 | 1505 | 4100 | 103/20/31, $p=3\cdot10^{-10}$ | 31/4/10, $p=0.001$ |
|
||||
| TOMS 748 | 2636 | 3088 | 5724 | 127/6/21 | 42/2/1 |
|
||||
| Brent | 2707 | 3238 | 5945 | 118/17/19 | 39/3/3 |
|
||||
| ITP, per-problem oracle | 3068 | 1675 | 4743 | 126/7/21 | 35/1/9 |
|
||||
| ModAB [10, 20] | 2726 | 1681 | 4407 | 118/10/26 | 34/4/7 |
|
||||
|
||||
A′ is 12.5% below Chandrupatla on the canonical set and 17.9% below on the wide-bracket set, and beats every rival problem by problem on both. On the wide-bracket families it is ahead on seven of nine, level on `fun7` (the scoring artefact of §7.3) and behind on `fun9`, 65 against 55. The earned-budget form keeps its constant-free guarantee of bisection plus one step and pays for it as in §3.1.
|
||||
A′ is 12.9% below Chandrupatla on the canonical set and 28.6% below on the wide-bracket set, and wins more problems than it loses against every rival on both. By function family, the unit in which these problems are independent (§9), it is ahead of Chandrupatla on 8 of the 15 canonical families (6 behind, one level) and on 7 of the 9 wide-bracket families — too few families for either count to be significant ($p=0.79$, $0.18$). The two it is behind on are `fun7`, 69 against 64, and `fun9`, 65 against 55. The earned-budget form keeps its constant-free guarantee of bisection plus one step and pays for it as in §3.1.
|
||||
|
||||
**Table 9.** Leave-one-out ablation of A′ on all six corpora of §9 (uniform criterion, a sign change within $10^{-6}$). Δ = total without the component − total with it; positive means the component earns its place.
|
||||
|
||||
@@ -487,21 +473,21 @@ A′ is 12.5% below Chandrupatla on the canonical set and 17.9% below on the wid
|
||||
|
||||
Every component is positive in sum; the regime and the split carry the method. Two are marginal and we say so: the step pattern earns on two corpora of six and loses on four, and the sign contradiction is within noise (+28 over 855 problems). Removing both would change A′'s total by under one per cent (117 of 13032 evaluations); they are kept because the pre-registered rule removes only a component that earns nowhere.
|
||||
|
||||
**Table 9a.** The similarity in the step of A′: the same method with each of the nine similarity functions of §5.3 in place of the tent, everything else unchanged. Totals on the protocol of §4 and over the six corpora of §9 (uniform criterion); the guarantee holds with every function.
|
||||
**Table 9a.** The similarity in the step of A′: the same method with each of the nine similarity functions of §5.3 in place of the tent, everything else unchanged. Totals on the two sets of §4 and over the six corpora of §9; the guarantee holds with every function.
|
||||
|
||||
| $S$ in the step | APS + CHA | six corpora (855) |
|
||||
|---|---|---|
|
||||
| **tent $1-|z|$ (A′)** | **4443** | **13032** |
|
||||
| $e^{-|z|}$ | 4988 | 14142 |
|
||||
| $1/(1+|z|)$ | 5486 | 14843 |
|
||||
| $(1+|z|)^{-2}$ | 8360 | 28500 |
|
||||
| $1-\sqrt{|z|}$ | 12718 | 45552 |
|
||||
| $1-|z|^{1/3}$ | 17207 | 63031 |
|
||||
| $e^{-z^2}$ | 18410 | 67701 |
|
||||
| $1/\sqrt{1+z^2}$ | 18412 | 67854 |
|
||||
| $1/(1+z^2)$ | 18422 | 67394 |
|
||||
| **tent $1-|z|$ (A′)** | **3333** | **13032** |
|
||||
| $e^{-|z|}$ | 3965 | 14142 |
|
||||
| $1/(1+|z|)$ | 4424 | 14843 |
|
||||
| $(1+|z|)^{-2}$ | 7249 | 28500 |
|
||||
| $1-\sqrt{|z|}$ | 11613 | 45552 |
|
||||
| $1-|z|^{1/3}$ | 16094 | 63031 |
|
||||
| $e^{-z^2}$ | 17429 | 67701 |
|
||||
| $1/(1+z^2)$ | 17452 | 67394 |
|
||||
| $1/\sqrt{1+z^2}$ | 17487 | 67854 |
|
||||
|
||||
The similarity in the step earns its place in the proposed method as it did in the base rule: the nearest other function costs 12% more on the canonical protocol and 9% more over the six corpora, the functions that approach 1 quadratically cost four to five times more, and the ranking is the one the contraction law of §2.2 predicts, the three functions with a linear approach first and the three with a quadratic approach last.
|
||||
The nearest other function costs 19% more on the two sets and 9% more over the six corpora, and the functions that approach 1 quadratically cost five times more; the three functions with a linear approach come first and the three with a quadratic approach last, as the contraction law of §2.2 predicts. What this measures should be said plainly: with the tent the step is the undamped Newton step clipped to the bracket, and the other functions damp it, so the table shows that the undamped step is the better one — expected, and evidence for the choice of $S$ within the rule rather than for the similarity framing as such.
|
||||
|
||||
### 8.6 What is known, and what is new
|
||||
|
||||
@@ -521,12 +507,14 @@ What we found no counterpart for, in the literature we could reach, is the part
|
||||
|
||||
## 9. Out-of-sample evidence
|
||||
|
||||
Every decision above was taken on the two sets of §4. Pre-registration protects each decision but not the chain: the final configuration was selected on the same 199 problems. Four further corpora were therefore used, each fixed and committed before any method was run on it, each with its criteria and stop rule written down first.
|
||||
Every decision above was taken on the two sets of §4. Pre-registration protects each decision but not the chain: the final configuration — a decision layer of about ten discrete rules, chosen among the many candidates listed in §10 — was selected on the same 199 problems. Four further corpora were therefore used, each fixed and committed before any method was run on it, each with its criteria and stop rule written down first.
|
||||
|
||||
1. **New corpus 1** — 206 problems: SciPy's `original` set (6) and five generated classes of 40 (seed 20260921): smooth simple roots, transcendental simple roots, multiple roots $|x-r|^p$ with $p\sim U(2,20)$, exponential flanks, and near-cancelling terms of the `fun9` kind.
|
||||
2. **Roots.jl / ModAB** — the published bracketing benchmark of the Julia package Roots.jl [12], taken from the ModAB benchmark of Ganchovski and Traykov [10]: 91 problems, of which 13 coincide with APS or Chandrupatla functions (a seven-point identity test) and are excluded, leaving 78, many of them discontinuous or pathological.
|
||||
3. **Applied and GSL** — the 10 bracketed problems of the GNU Scientific Library's root-finding test suite [11] and 122 equations from physics and engineering on grids fixed beforehand: Kepler's equation (eccentricity up to 0.999), Colebrook–White, Lambert's W, Planck/Wien, van der Waals for CO₂ (including near-critical), internal rate of return, the finite square well.
|
||||
4. **Corpus 4** — 240 problems in six new families (seed 20260922): random polynomials with a simple root, polynomials with a multiple root, fractional powers $|x-r|^p$ with $p\sim U(0.15,0.95)$, sums of exponentials and sines, compositions $\tanh$, $\arctan$, $\log(1+q^2)$ of a cubic, and functions odd about the root. The code of A′ was committed *before* this corpus was run, and nothing was changed after.
|
||||
4. **Corpus 4** — 240 problems in six new families (seed 20260922): random polynomials with a simple root, polynomials with a multiple root, fractional powers $|x-r|^p$ with $p\sim U(0.15,0.95)$, sums of exponentials and sines, compositions $\tanh$, $\arctan$, $\log(1+q^2)$ of a cubic, and functions odd about the root. The code of A′ was committed *before* this corpus was run, and nothing was changed after. The families were chosen by the author, who knew by then where the method is strong: two of the six (multiple roots, fractional powers) are the regime §8 was built for.
|
||||
|
||||
A root must carry a sign change to be bracketed, so the multiple roots in these corpora have odd multiplicity (3, 5, 7, 9 in corpus 4) or the form $\operatorname{sign}(x-r)|x-r|^p$ (corpora 1 and 4).
|
||||
|
||||
ModAB, the most recent bracketing method we know of, is run from its authors' package (`pymodab` 1.0.9, a wrapper of their C code) with the stopping rule of every other method — a bracket no wider than $\varepsilon_x$, the relative term at machine precision, no stopping on $|f|$ — and counted by the same wrapper around $f$, whose count agrees with the package's own. Where roots are not known in closed form, and for uniformity on all six corpora, a run is solved when $f$ changes sign within $10^{-6}$ of its answer; the $x$-tolerance, the budget and the charge for a failure are those of §4.
|
||||
|
||||
@@ -534,15 +522,15 @@ ModAB, the most recent bracketing method we know of, is run from its authors' pa
|
||||
|
||||
**Table 10.** A′ against the library rivals on all six corpora (uniform criterion): total evaluations; in brackets the runs that break the $2\times$-bisection bound.
|
||||
|
||||
| corpus | A′ | Chandrupatla | ModAB | Brent | TOMS 748 |
|
||||
|----------------------|------------|--------------|------------|------------|------------|
|
||||
| APS (154) | **2259** (0) | 2595 (0) | 2726 (0) | 2707 (0) | 2636 (0) |
|
||||
| Chandrupatla (45) | **1074** (0) | 1505 (0) | 1681 (0) | 3238 (18) | 3088 (15) |
|
||||
| new corpus 1 (206) | **3290** (0) | 3716 (0) | 3809 (1) | 6395 (38) | 5746 (22) |
|
||||
| Roots.jl (78) | **1371** (0) | 1566 (0) | 1446 (0) | 2455 (11) | 2339 (9) |
|
||||
| applied + GSL (132) | 1382 (0) | 1382 (0) | 1460 (0) | 1503 (1) | 1756 (1) |
|
||||
| **corpus 4 (240), the one test** | **3656** (0) | 5717 (0) | 5535 (8) | 8267 (50) | 8084 (37) |
|
||||
| all 855 | **13032** | 16481 | 16657 | 24565 | 23649 |
|
||||
| corpus | A′ | Chandrupatla | ModAB | ITP | ITP oracle | Brent | TOMS 748 |
|
||||
|--------------------|-----------|-----------------|-----------|-----------|-----------|-----------|-----------|
|
||||
| APS (154) | **2259** (0) | 2595 (0) | 2726 (0) | 3767 (0) | 3068 (0) | 2707 (0) | 2636 (0) |
|
||||
| Chandrupatla (45) | **1074** (0) | 1505 (0) | 1681 (0) | 1946 (0) | 1675 (0) | 3238 (18) | 3088 (15) |
|
||||
| new corpus 1 (206) | **3290** (0) | 3716 (0) | 3809 (1) | 5674 (0) | 4707 (0) | 6395 (38) | 5746 (22) |
|
||||
| Roots.jl (78) | **1371** (0) | 1566 (0) | 1446 (0) | 2161 (0) | 1629 (0) | 2455 (11) | 2339 (9) |
|
||||
| applied + GSL (132) | 1382 (0) | 1382 (0) | 1460 (0) | 3245 (0) | 2386 (0) | 1503 (1) | 1756 (1) |
|
||||
| **corpus 4 (240), the one test** | **3656** (0) | 5717 (0) | 5535 (8) | 5721 (0) | 4832 (0) | 8267 (50) | 8084 (37) |
|
||||
| all 855 | **13032** | 16481 | 16657 | 22514 | 18297 | 24565 | 23649 |
|
||||
|
||||
**Table 10b.** The same runs problem by problem: A′'s wins/ties/losses against Chandrupatla and against ModAB (exact two-sided sign test).
|
||||
|
||||
@@ -555,7 +543,9 @@ ModAB, the most recent bracketing method we know of, is run from its authors' pa
|
||||
| applied + GSL (132) | 48/52/32, $p=0.09$ | 76/35/21 |
|
||||
| **corpus 4 (240), the one test** | **177/35/28, $p=10^{-27}$** | **183/23/34** |
|
||||
|
||||
Only the last line of corpora is evidence for A′ in the strict sense; the first five were seen while it was developed and are reported as a description. On corpus 4 A′ is 36% below Chandrupatla and wins 177 problems to 28. Without the two classes aimed at by the last two readings it is 2403 against 3569, per problem 107/31/22 ($p=10^{-14}$); on the simple-root classes alone, 737 against 747 (−1.3%), per problem 43/22/15 ($p=3\cdot10^{-4}$).
|
||||
Only the last line of corpora is evidence for A′ in the strict sense; the first five were seen while it was developed and are reported as a description. ITP, at its recommended constants and as the per-problem oracle, keeps its own bound of bisection plus $n_0$ everywhere and is behind A′ on every corpus.
|
||||
|
||||
**Independence.** A sign test counts problems as independent draws, and not all of them are. In the two canonical sets one function appears with several brackets or parameters, so the independent unit is the function family (15 in APS, 9 in CHA); at that level the counts of Table 8 are not significant, because there are too few families. In corpora 1 and 4 every problem is drawn independently from its family's generator, so the per-problem test is valid — for the population those generators define, which the author chose (above). On corpus 4 A′ is 36% below Chandrupatla and wins 177 problems to 28. Without the two classes aimed at by the last two readings it is 2403 against 3569, per problem 107/31/22 ($p=10^{-14}$); on the simple-root classes alone, 737 against 747 (−1.3%), per problem 43/22/15 ($p=3\cdot10^{-4}$).
|
||||
|
||||
**Table 11.** Corpus 4 by class: totals of A′ / Chandrupatla, per problem wins/ties/losses.
|
||||
|
||||
@@ -568,7 +558,7 @@ Only the last line of corpora is evidence for A′ in the strict sense; the firs
|
||||
| $\tanh$, $\arctan$, $\log(1+q^2)$ of a cubic | 503 | 1017 | 25/8/7 |
|
||||
| odd about the root | 329 | 364 | 33/3/4 |
|
||||
|
||||
**What the evidence supports, and what it does not.** Against Brent and TOMS 748 A′ is ahead on every corpus, by 8% to 67% in total, and it keeps its bound on all 855 problems, which Brent breaks on 118 and TOMS 748 on 84. Against ModAB it is ahead on every corpus, in total and problem by problem ($p\le0.0013$), on the one test of corpus 4 by 3656 to 5535 and 183 problems to 34 ($p=7\cdot10^{-26}$), and on ModAB's own benchmark as well — all 91 problems of it, 1507 against 1588, 56/13/22 ($p=1.5\cdot10^{-4}$); ModAB breaks the bound on 9 problems. Against Chandrupatla it is ahead in total on five corpora and level on the sixth, and ahead problem by problem on all six, significantly on five. The size of the lead is not uniform: it is large on multiple, fractional and nearly flat roots — the regime §8 recognises — and small on simple roots, where it is a matter of per cent. Where it is behind is named: `fun9` (65 against 55), the near-cancelling class of corpus 1 (491 against 391), random polynomials with a simple root in total (433 against 419, though ahead 20 to 12 in problems), and the smooth equations of the applied corpus, where the two are level.
|
||||
**What the evidence supports, and what it does not.** Against Brent and TOMS 748 A′ is ahead on every corpus, by 8% to 67% in total, and it stays within its own bound of twice bisection on all 855 problems, a bound that Brent exceeds on 118 and TOMS 748 on 84 — neither promises it. Against ModAB it is ahead on every corpus, in total and problem by problem ($p\le0.0013$), on the one test of corpus 4 by 3656 to 5535 and 183 problems to 34 ($p=7\cdot10^{-26}$), and on ModAB's own benchmark as well — all 91 problems of it, 1507 against 1588, 56/13/22 ($p=1.5\cdot10^{-4}$); ModAB exceeds that bound, which it does not promise either, on 9 problems. Against Chandrupatla it is ahead in total on five corpora and level on the sixth, and ahead problem by problem on all six, significantly on five. The size of the lead is not uniform: it is large on multiple, fractional and nearly flat roots — the regime §8 recognises — and small on simple roots, where it is a matter of per cent. Where it is behind is named: `fun9` (65 against 55), the near-cancelling class of corpus 1 (491 against 391), random polynomials with a simple root in total (433 against 419, though ahead 20 to 12 in problems), and the smooth equations of the applied corpus, where the two are level.
|
||||
|
||||
---
|
||||
|
||||
@@ -576,45 +566,45 @@ Only the last line of corpora is evidence for A′ in the strict sense; the firs
|
||||
|
||||
1. **The prototype-aggregation form of the method loses.** A richer construction — prototypes over *pairs* of evaluated points, softmax weights over the whole memory, similarity on both the value and the abscissa axis — leads on eight hand-picked problems but loses decisively on the real set: 0 wins, 6 ties and 147 losses against Brent. The simplest form of the idea won.
|
||||
|
||||
2. **Every safeguard that replaces the step destroys the order.** Bracket-based and step-based replacement both drop the three-point rule from order 1.94 to 1.00 and cost 7260 and 7239 evaluations on Alefeld–Potra–Shi. Only projection preserves both. We record this because it is the trap the construction naturally falls into.
|
||||
2. **Every safeguard that replaces the step destroys the order.** Bracket-based and step-based replacement both make the three-point rule converge linearly and cost 7068 and 7046 evaluations on Alefeld–Potra–Shi. Only projection preserves both. We record this because it is the trap the construction naturally falls into.
|
||||
|
||||
3. **Zero slack in the projection is not the degenerate case it was said to be.** An earlier version reported that a worst case of exactly bisection leaves the projection no freedom and makes the guard behave as bisection. Measured (Table 1a), multiplier 1 costs 4817 and 2997, against bisection's 7530 and 3090 — and on the wide-bracket set it beats the multiplier of 2. It remains the most expensive multiplier on the canonical set, which is all that survives of the claim.
|
||||
3. **Zero slack in the projection is not a degenerate case.** A worst case of exactly bisection might be expected to leave the projection no freedom and make the guard behave as bisection. Measured (Table 1a), multiplier 1 costs 4625 and 2039, against bisection's 7338 and 2136 — and on the wide-bracket set it beats the multiplier of 2. It is the most expensive multiplier on the canonical set.
|
||||
|
||||
4. **Regimes exist, at the level of a function family, and cannot be exploited by a switch.** The cube-root similarity beats the base rule on all five members of Chandrupatla's `fun4` — 32/32/40/47/59 against 89/93/113/125/153, a factor of 2.6 — and consistency across a family at different parameters is the signature of structure rather than luck. But the same similarity over the whole Chandrupatla set costs 4109 against 3220, so a switch chosen per benchmark is worse than no switch at all: 6915 against 6026 over both sets. The scale axis offers only 5.3% headroom even to an oracle handed the best scale per problem, two thirds of it inside a single problem family, and the winners are not separated by anything the method can see before it commits — the derived scale wins on bracket widths from $10^0$ to $10^{12}$.
|
||||
4. **Regimes exist, at the level of a function family, and cannot be exploited by a switch.** The cube-root similarity beats the base rule on all five members of Chandrupatla's `fun4` — 32/32/40/47/59 against 89/93/113/125/153, a factor of 2.6 — and consistency across a family at different parameters is the signature of structure rather than luck. But the same similarity over the whole Chandrupatla set costs 3204 against 2357, so a switch chosen per benchmark is worse than no switch at all: 5838 against 4991 over both sets. The scale axis offers only 5.3% headroom even to an oracle handed the best scale per problem, two thirds of it inside a single problem family, and the winners are not separated by anything the method can see before it commits — the derived scale wins on bracket widths from $10^0$ to $10^{12}$.
|
||||
|
||||
5. **The phase detector: derivation sound, estimator not.** Redoing the contraction law without the assumption $|f|\approx|f'(r)|e$ — taking $|f|\approx K e^m$ instead — does produce the march exponent on its own, $p = L/(L-\ln m)$ with $L=\ln(e/D)$, giving $p=1$ at a simple root and dropping to 0.50 and 0.23 as the approach flattens, which is the neighbourhood of the cube root that wins those families. Substituted back it collapses to the multiplier $m$, measurable as $m = 1/(1-\theta)$ with $\theta = f f''/(f')^2$ from three divided differences and no constant — which is Lagouanelle's multiplicity estimate [13]. It preserves the order (2.001) and improves the eight standard problems (82 against 84) — and loses on the full benchmark, 6304 against 6026. The estimator is the failure: on Alefeld–Potra–Shi, where almost every root is simple and the truth is $m=1$, it reports $m>1$ on 27.9% of steps with excursions to $m=34.8$, against 35.8% on the flat families. 27.9 against 35.8 is no separation. A cruder variant, correcting by the fraction of its own promise the previous step kept, fails everything: the order collapses to 0.904 and the standard problems double to 161.
|
||||
5. **The phase detector: derivation sound, estimator not.** Redoing the contraction law without the assumption $|f|\approx|f'(r)|e$ — taking $|f|\approx K e^m$ instead — does produce the march exponent on its own, $p = L/(L-\ln m)$ with $L=\ln(e/D)$, giving $p=1$ at a simple root and dropping to 0.50 and 0.23 as the approach flattens, which is the neighbourhood of the cube root that wins those families. Substituted back it collapses to the multiplier $m$, measurable as $m = 1/(1-\theta)$ with $\theta = f f''/(f')^2$ from three divided differences and no constant — which is Lagouanelle's multiplicity estimate [13]. It improves the eight standard problems (82 against 84) — and loses on the full benchmark, 5336 against 4991. The estimator is the failure: on Alefeld–Potra–Shi, where almost every root is simple and the truth is $m=1$, it reports $m>1$ on 27.9% of steps with excursions to $m=34.8$, against 35.8% on the flat families. 27.9 against 35.8 is no separation. A cruder variant, correcting by the fraction of its own promise the previous step kept, fails everything: the convergence becomes sublinear and the standard problems double to 161.
|
||||
|
||||
6. **One problem is scored unsolved for every method**, `aps.13.00`, $f(x)=x e^{-1/x^2}$, all of whose derivatives vanish at the root and which underflows to exactly zero throughout $|x|<0.086$. Every method returns a point where $f(x)=0$ exactly — a genuine root — which the harness scores as a failure because it lies more than $10^{-6}$ from the declared root. It is a property of the scoring, not a failure of the methods; §7.3 finds five more such problems in the wide-bracket set.
|
||||
6. **The harness scores one canonical problem unsolved for every method**, `aps.13.00`, $f(x)=x e^{-1/x^2}$, all of whose derivatives vanish at the root and which underflows to exactly zero throughout $|x|<0.086$. Every method returns a point where $f(x)=0$ exactly — a genuine root — which the harness scores as a failure because it lies more than $10^{-6}$ from the declared root. With the five `fun7` problems of §7.3 it is why this paper scores by a sign change.
|
||||
|
||||
7. **The symmetric ratio similarity degenerates.** For $S(x,y)=\min(|x|,|y|)/\max(|x|,|y|)$ with $y$ the target 0, $S\equiv0$; the only usable reading is $1-|f|/\sigma$, which saturates and stagnates (Table 1, last row).
|
||||
|
||||
8. **Placement beats form, and the wrong placement is expensive.** The same "refuse before the step" idea as reading (1) of §7, with refusal decided by *promised bracket progress* instead of by the shape of the model, costs 4449 on the canonical set against 2527 — a difference of 1922 evaluations for one choice of criterion. A secant step routinely collapses the error while barely moving the proven bracket, so bracket progress rejects steps that were excellent; this is the same mechanism that makes the bracket guard of §3.1 cost 7260.
|
||||
8. **Placement beats form, and the wrong placement is expensive.** The same "refuse before the step" idea as reading (1) of §7, with refusal decided by *promised bracket progress* instead of by the shape of the model, costs 4258 on the canonical set against 2337 — a difference of 1921 evaluations for one choice of criterion. A secant step routinely collapses the error while barely moving the proven bracket, so bracket progress rejects steps that were excellent; this is the same mechanism that makes the bracket guard of §3.1 cost 7068.
|
||||
|
||||
9. **Making the scale independent of the bracket does not help either.** The natural objection to the derived scale is that it defeats the very principle of a similarity step: with $\sigma=|\hat f'|D$ the normalised residual is $|f|/(|\hat f'|D)$, which on the $2\times10^4$-wide bracket of $x^3-2x-5$ at $x=10^4$ equals 0.167, so $S=0.833$ — "similar" — and the step is small although the root is some five thousand step-lengths away. The similarity is reading what fraction of the *bracket* the Newton step is, not how far the iterate is from the root. Selecting the scale between the two quantities already computed, $\sigma=\min(|\hat f'|D,\max(|f(A)|,|f(B)|))$ — no new constant, a minimum over what is in hand — does give a full-bracket step far away and Newton's step near the root, and on eight hand-picked wide problems it improves 403 evaluations to 390. Over the whole grid it is worse on both sets: 3288 on the canonical set against 2726, and 3111 on the wide-bracket set against 2695. Its apparent extra solves (194 instead of 193) are two `fun7` problems where it lands inside the flat zero region close enough to satisfy the harness — the artefact of §7.3, not a capability.
|
||||
9. **Making the scale independent of the bracket does not help either.** The natural objection to the derived scale is that it defeats the very principle of a similarity step: with $\sigma=|\hat f'|D$ the normalised residual is $|f|/(|\hat f'|D)$, which on the $2\times10^4$-wide bracket of $x^3-2x-5$ at $x=10^4$ equals 0.167, so $S=0.833$ — "similar" — and the step is small although the root is some five thousand step-lengths away. The similarity is reading what fraction of the *bracket* the Newton step is, not how far the iterate is from the root. Selecting the scale between the two quantities already computed, $\sigma=\min(|\hat f'|D,\max(|f(A)|,|f(B)|))$ — no new constant, a minimum over what is in hand — does give a full-bracket step far away and Newton's step near the root, and on eight hand-picked wide problems it improves 403 evaluations to 390. Over the whole grid it is worse on both sets: its best cell is 3101 on the canonical set against 2539 for the best uncapped cell of the same grid, and 1766 on the wide-bracket set against 1752.
|
||||
|
||||
10. **Reading the similarity at the measured order does not cure false position.** Since false position's stall is a similarity read at order one (§7.1), the obvious hope is that reading it at the measured order is the parameter-free version of the classical fix. It is not. Unguarded, the correction takes the far-end reading from 127/154 and 10676 to 128/154 and 10043 — one problem and six per cent — where Illinois, at the price of one constant (halve the stale ordinate), reaches 153/154 and 7045. A sixth of the gap is not the gap. The correction is real and it is in the right place; it is simply much smaller than a constant that was chosen for exactly this failure. *Our* 10676 and the 10560 of Table 2 are not the same algorithm — our iterate starts at the midpoint of the bracket, plain false position at an end — and the two must not be differenced.
|
||||
10. **Reading the similarity at the measured order does not cure false position.** Since false position's stall is a similarity read at order one (§7.1), the obvious hope is that reading it at the measured order is the parameter-free version of the classical fix. It is not. Unguarded, the correction takes the far-end reading from 127/154 and 10676 to 129/154 and 9855 — two problems and eight per cent — where Illinois, at the price of one constant (halve the stale ordinate), reaches 153/154 and 7045. A sixth of the gap is not the gap. The correction is real and it is in the right place; it is simply much smaller than a constant that was chosen for exactly this failure. *Our* 10676 and the 10560 of Table 2 are not the same algorithm — our iterate starts at the midpoint of the bracket, plain false position at an end — and the two must not be differenced.
|
||||
|
||||
11. **A logarithmic change of variable does not buy the wide brackets.** Working in $u=\operatorname{sign}(x-c)\log(1+|x-c|/\varepsilon_x)$ makes the step multiplicative, which looked like the right diagnosis of the flat families — for the same similarity, scale and safeguard ($(1+|z|)^{-2}$, two-point, *safe*) the wide-bracket set improves from 3695 to 3541 — but the canonical set gets worse, 5822 to 6940, against the 2806 of the base rule. An earlier version compared the 3541 with 4516, which is the total of a different configuration. A march needs a *ratio* of distances while an identity on narrow brackets needs an *absolute* unit, and no parameter-free unit provides both. §7.4 shows the diagnosis itself was wrong: on the flat families the right move is to halve, not to march.
|
||||
11. **A logarithmic change of variable does not buy the wide brackets.** Working in $u=\operatorname{sign}(x-c)\log(1+|x-c|/\varepsilon_x)$ makes the step multiplicative, which looked like the right diagnosis of the flat families — for the same similarity, scale and safeguard ($(1+|z|)^{-2}$, two-point, *safe*) the wide-bracket set improves from 2759 to 2598 — but the canonical set gets worse, 5635 to 6749, against the 2634 of the base rule. A march needs a *ratio* of distances while an identity on narrow brackets needs an *absolute* unit, and no parameter-free unit provides both. §7.4 shows the diagnosis itself was wrong: on the flat families the right move is to halve, not to march.
|
||||
|
||||
12. **Reading the unkept promise one step at a time does not pay.** The flag of §8.1 sees the flat regime, but a halving in place of each flagged step takes the canonical set from 2806 to 3029 and the wide-bracket set only from 3220 to 3198: a simple root far from convergence breaks its promises too. Requiring the promise to fail twice in a row keeps the canonical set (2803) but fires one step late, before the crossing, and replaces the most useful step of the cycle (wide brackets 3341); requiring a creep in one direction as well gives 2878 and 3354.
|
||||
12. **Reading the unkept promise one step at a time does not pay.** The flag of §8.1 sees the flat regime, but a halving in place of each flagged step takes the canonical set from 2634 to 2839 and the wide-bracket set only from 2357 to 2243: a simple root far from convergence breaks its promises too. Requiring the promise to fail twice in a row keeps the canonical set (2613) but fires one step late, before the crossing, and replaces the most useful step of the cycle (wide brackets 2388); requiring a creep in one direction as well gives 2688 and 2399.
|
||||
|
||||
13. **A halving that sticks once begun wins the flat families and loses everything else.** Without an exit the flat families fall to 1057 — pure bisection's level — and the canonical set rises to 6897, because a false entry now lasts to the end of the run. Splitting at the order read from the failed promise, $(1-1/m)^m=r$, changes nothing: that order is $m=\infty$ in 163 of 174 entries (6781).
|
||||
13. **A halving that sticks once begun wins the flat families and loses everything else.** Without an exit the flat families fall to 1057 — pure bisection's level — and the canonical set rises to 6707, because a false entry now lasts to the end of the run. Splitting at the order read from the failed promise, $(1-1/m)^m=r$, changes nothing: that order is $m=\infty$ in 163 of 174 entries (6591).
|
||||
|
||||
14. **The model's own point cannot tell a flat root from a simple one.** Judging the evaluated point against the line through the bracket ends and against 0 — the exit judgment of §8.2 — also at *entry* gives 3009 and 2486 against 3125 and 2503 for the exit alone: the model aims at the root, so $f$ is small there by construction and looks flat at a simple root as readily as at a power. The same judgment works at a split, which the model did not choose.
|
||||
14. **The model's own point cannot tell a flat root from a simple one.** Judging the evaluated point against the line through the bracket ends and against 0 — the exit judgment of §8.2 — also at *entry* gives 2820 and 1532 against 2935 and 1546 for the exit alone: the model aims at the root, so $f$ is small there by construction and looks flat at a simple root as readily as at a power. The same judgment works at a split, which the model did not choose.
|
||||
|
||||
15. **The decision reading "defect" does not transfer.** Combined with the regime it was the best configuration on the two development sets (§7.2's canonical record 2523 with the flat families of §8), and it passed every pre-registered criterion there. On new corpus 1 it did not: per problem 95/33/78 against Chandrupatla ($p=0.22$), losing the class of exponential flanks 9 to 26. It is therefore not part of A′.
|
||||
15. **The decision reading "defect" does not transfer.** Combined with the regime it was the best configuration on the two development sets (§7.2's defect reading with the flat families of §8), and it passed every pre-registered criterion there. On new corpus 1 it did not: per problem 95/33/78 against Chandrupatla ($p=0.22$), losing the class of exponential flanks 9 to 26. It is therefore not part of A′.
|
||||
|
||||
16. **A component rejected alone can pay in combination.** Remembering the analogy for the run was rejected by its own pre-registration (canonical set 2814 against 2806 without the regime), and with the split of §8.3 it is the better form (with the step pattern, wide brackets 2117 against 2221 for the analogy read in one state). Composition was measured, not assumed, throughout — which is also why §7's readings (2) and (3), each an improvement, are not combined.
|
||||
16. **A component rejected alone can pay in combination.** Remembering the analogy for the run was rejected by its own pre-registration, under the harness scoring of the time (canonical set 2814 against 2806 without the regime; under the sign-change criterion the two are level, 2633 against 2634), and with the split of §8.3 it is the better form (with the step pattern, wide brackets 1250 against 1388 for the analogy read in one state). Composition was measured, not assumed, throughout — which is also why §7's readings (2) and (3), each an improvement, are not combined.
|
||||
|
||||
---
|
||||
|
||||
## 11. Conclusion
|
||||
|
||||
A root finder can be derived from a similarity function alone, and the derivation shows where the content of such a method actually sits. It is not in the shape of $S$ — nine shapes were tried and their ranking is dictated by a single number, the slope of $1-S$ at the origin. It is not in making the similarity change faster — that overshoots exactly as readily as flatness stagnates. It is in the *scale* against which similarity is judged: chosen, the method is brittle and merely linear; taken from the bracket, it is false position and three centuries old; read off the data, it is superlinear. And the safeguard that makes such a method safe must project the step, not replace it: replacing costs the order, projecting costs nothing on one benchmark and improves the method on the other. The projection's budget multiplier is a free constant, and we declare it: it does not move the canonical result and it does move the wide-bracket one; projecting onto a budget the steps earn instead removes it, at a measured price.
|
||||
A root finder can be derived from a similarity function alone, and the derivation shows where the content of such a method actually sits. It is not in the shape of $S$ — nine shapes were tried and which group of them comes first is dictated by a single number, the slope of $1-S$ at the origin. It is not in making the similarity change faster — that overshoots exactly as readily as flatness stagnates. It is in the *scale* against which similarity is judged: chosen, the method is brittle and merely linear; taken from the bracket, it is false position and three centuries old; read off the data, it is superlinear. And the safeguard that makes such a method safe must project the step, not replace it: replacing costs the order, projecting costs nothing on one benchmark and improves the method on the other. The projection's budget multiplier is a free constant, and we declare it: it does not move the canonical result and it does move the wide-bracket one; projecting onto a budget the steps earn instead removes it, at a measured price.
|
||||
|
||||
The base rule has one declared constant and carries a worst case of twice bisection plus one step. On the canonical Alefeld–Potra–Shi set it is level with TOMS 748 and with Chandrupatla's method in total and ahead of both problem by problem; on the wide-bracket set Chandrupatla is genuinely stronger (2441 against 3220). §7.4 locates the cause: not the order of the model but the decision to give it up, which Chandrupatla takes by halving and which no reading of a single state takes correctly for our step.
|
||||
The base rule has one declared numerical constant, converges with Muller's order 1.839 and carries a worst case of twice bisection plus one step. On the canonical Alefeld–Potra–Shi set it is level with TOMS 748 in total and 1.5% behind Chandrupatla's method, while winning more problems than it loses against both; on the wide-bracket set Chandrupatla is genuinely stronger (1505 against 2357). §7.4 locates the cause: not the order of the model but the decision to give it up, which Chandrupatla takes by halving and which no reading of a single state takes correctly for our step.
|
||||
|
||||
That decision is a similarity too — of the run to its own past. A pure power repeats its configuration under zoom, an exponential under translation, a simple root tends to the line; the analogous pair reads the local order, the order decides between the model and a halving by bisection's own $\tfrac12$, and it says where to split. The method built on it, A′, is ahead of Chandrupatla on both canonical sets in total and problem by problem, and on a corpus fixed after its code was frozen it needs 36% fewer evaluations and wins 177 problems to 28. The claim the measurements support is a lead over Brent, TOMS 748 and ModAB everywhere, with the guarantee they do not keep, and over Chandrupatla a lead that is large where roots are multiple, fractional or nearly flat and small where they are simple — not superiority by the same margin everywhere. `fun9`, near-cancelling terms and smooth applied equations are where it is behind or level.
|
||||
That decision is a similarity too — of the run to its own past. A pure power repeats its configuration under zoom, an exponential under translation, a simple root tends to the line; the analogous pair reads the local order, the order decides between the model and a halving by bisection's own $\tfrac12$, and it says where to split. The method built on it, A′, is ahead of Chandrupatla on both canonical sets in total and problem by problem, and on a corpus fixed after its code was frozen it needs 36% fewer evaluations and wins 177 problems to 28. The claim the measurements support is a lead over Brent, TOMS 748, ITP and ModAB everywhere, within a bound of twice bisection that Brent, TOMS 748 and ModAB do not promise and exceed, and over Chandrupatla a lead that is large where roots are multiple, fractional or nearly flat and small where they are simple — not superiority by the same margin everywhere. `fun9`, near-cancelling terms and smooth applied equations are where it is behind or level.
|
||||
|
||||
This is the same movement as in parameter-free similarity control [6], where membership functions are eliminated by normalising the input space from the data rather than by choosing widths. Here the object normalised is the value axis, and the price of choosing it by hand is measured rather than asserted.
|
||||
|
||||
|
||||
Binary file not shown.
+536
-522
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,6 @@ produce it; if it changes with S, S takes part.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
SIMS = ("ratio", "sqrt", "cbrt", "rational", "ratio_soft", "exp_abs", "rat_sq", "exp_sq",
|
||||
"cosine")
|
||||
@@ -29,8 +28,9 @@ NAME = {"ratio": "tent 1-|z|", "sqrt": "1-sqrt|z|", "cbrt": "1-|z|^1/3",
|
||||
|
||||
|
||||
def load(path):
|
||||
with open(path, encoding="utf8") as fh:
|
||||
return json.load(fh)
|
||||
"""The sweep re-scored under the paper's single criterion (sweep_uniform.json)."""
|
||||
from rescore_uniform import load_uniform
|
||||
return load_uniform(path)
|
||||
|
||||
|
||||
def key(r):
|
||||
|
||||
+3
-1
@@ -70,7 +70,9 @@ def main():
|
||||
for _ in range(2):
|
||||
r = subprocess.run(["pdflatex", "-interaction=nonstopmode", "-halt-on-error",
|
||||
"-output-directory", "article", TEX],
|
||||
capture_output=True, text=True)
|
||||
capture_output=True, text=True, encoding="utf8", errors="replace")
|
||||
# errors="replace": TeX wraps its log at 79 bytes and can cut a UTF-8 character in
|
||||
# two; the split byte crashed the build (2026-09-22) - the log is read the same way
|
||||
log = open("article/sim_numerics.log", encoding="utf8", errors="replace").read()
|
||||
errors = [ln for ln in log.splitlines() if ln.startswith("!")]
|
||||
# only undefined references / citations count; 'Font shape ... undefined' is a font
|
||||
|
||||
@@ -22,7 +22,7 @@ from collections import defaultdict
|
||||
|
||||
from scipy.optimize._tstutils import _APS_TESTS_DICTS, _CHANDRUPATLA_TESTS_DICTS
|
||||
|
||||
from diag_model_order import ACC, MAXFEV, OURS, XTOL
|
||||
from diag_model_order import ACC, MAXFEV, OURS, XTOL, solved
|
||||
from simroot.pure import _local_order, pure_root
|
||||
|
||||
FLAT = ("fun3", "fun4", "fun5", "fun6")
|
||||
@@ -31,7 +31,7 @@ FLAT = ("fun3", "fun4", "fun5", "fun6")
|
||||
def states(f, a, b, r):
|
||||
st = {"trace": []}
|
||||
x, _n, conv = pure_root(f, a, b, XTOL, MAXFEV, stats=st, **OURS)
|
||||
if not (conv and abs(float(x) - r) <= ACC):
|
||||
if not (conv and solved(f, float(x))):
|
||||
return []
|
||||
out = []
|
||||
for s in st["trace"]:
|
||||
|
||||
+4
-2
@@ -39,6 +39,8 @@ from simroot.baselines import chandrupatla, chandrupatla_scipy
|
||||
from simroot.pure import pure_root
|
||||
|
||||
XTOL, MAXFEV, ACC = 1e-12, 200, 1e-6
|
||||
# success = the paper's single criterion since 2026-09-22 (revision point 3)
|
||||
from corpus_roots_jl import solved # noqa: E402
|
||||
OURS = dict(similarity="ratio", scale="derived3", guard="safe", prestep="slope",
|
||||
direction="dissimilar") # reading (3), CHA 2683 per set
|
||||
|
||||
@@ -78,7 +80,7 @@ def ch_cost(f, a, b, r):
|
||||
x, n, c = impl(f, a, b, XTOL, MAXFEV)
|
||||
except Exception:
|
||||
continue
|
||||
if c and math.isfinite(float(x)) and abs(float(x) - r) <= ACC:
|
||||
if c and solved(f, float(x)):
|
||||
best = int(n) if best is None else min(best, int(n))
|
||||
return best
|
||||
|
||||
@@ -119,7 +121,7 @@ def main():
|
||||
r = float(d["root"])
|
||||
st = {"trace": []}
|
||||
x, n, conv = pure_root(f, a, b, XTOL, MAXFEV, stats=st, **OURS)
|
||||
if not (conv and abs(float(x) - r) <= ACC):
|
||||
if not (conv and solved(f, float(x))):
|
||||
continue
|
||||
ch = ch_cost(f, a, b, r)
|
||||
if ch is None or n <= ch:
|
||||
|
||||
@@ -18,7 +18,7 @@ from collections import defaultdict
|
||||
|
||||
from scipy.optimize._tstutils import _CHANDRUPATLA_TESTS_DICTS
|
||||
|
||||
from diag_model_order import ACC, MAXFEV, OURS, XTOL, ch_cost, iqi
|
||||
from diag_model_order import ACC, MAXFEV, OURS, XTOL, ch_cost, iqi, solved
|
||||
from explain_chandrupatla import chandrupatla_traced
|
||||
from simroot.baselines import chandrupatla
|
||||
from simroot.pure import pure_root
|
||||
@@ -34,7 +34,7 @@ def main():
|
||||
r = float(d["root"])
|
||||
st = {"trace": []}
|
||||
x, n, conv = pure_root(f, a, b, XTOL, MAXFEV, stats=st, **OURS)
|
||||
if not (conv and abs(float(x) - r) <= ACC):
|
||||
if not (conv and solved(f, float(x))):
|
||||
continue
|
||||
ch = ch_cost(f, a, b, r)
|
||||
if ch is None or n <= ch:
|
||||
|
||||
@@ -28,13 +28,13 @@ def main():
|
||||
print(f"{'factor':>8} {'APS':>6} {'solved':>7} {'CHA':>6} {'solved':>7} {'both':>6}")
|
||||
for fac in FACTORS:
|
||||
p = per_problem(lambda f, a, b, xt, mx, _f=fac: ours(f, a, b, xt, mx, _f),
|
||||
probs, 200)
|
||||
probs, 200, criterion="sign")
|
||||
t, ok = totals(p, probs)
|
||||
out[fac] = (t["APS"], ok["APS"], t["CHA"], ok["CHA"])
|
||||
mark = " <- the text's choice" if fac == 2.0 else ""
|
||||
print(f"{fac:8.2f} {t['APS']:6d} {ok['APS']:4d}/154 {t['CHA']:6d} {ok['CHA']:4d}/45 "
|
||||
f"{t['APS'] + t['CHA']:6d}{mark}")
|
||||
p = per_problem(credit, probs, 200)
|
||||
p = per_problem(credit, probs, 200, criterion="sign")
|
||||
t, ok = totals(p, probs)
|
||||
out["credit"] = (t["APS"], ok["APS"], t["CHA"], ok["CHA"])
|
||||
print(f"{'credit':>8} {t['APS']:6d} {ok['APS']:4d}/154 {t['CHA']:6d} {ok['CHA']:4d}/45 "
|
||||
@@ -47,7 +47,7 @@ def main():
|
||||
for c0 in (0.1, 0.5, 1.0, 2.0, 5.0):
|
||||
p = per_problem(lambda f, a, b, xt, mx, _c=c0: pure_root(
|
||||
f, a, b, xt, mx, similarity="ratio", scale="derived3", guard="credit",
|
||||
endowment=_c), probs, 200)
|
||||
endowment=_c), probs, 200, criterion="sign")
|
||||
t, ok = totals(p, probs)
|
||||
out["endowment"][c0] = (t["APS"], t["CHA"])
|
||||
steps = -(-c0 // 1)
|
||||
|
||||
@@ -33,7 +33,7 @@ def main():
|
||||
out[name] = {}
|
||||
for fac in FACTORS:
|
||||
p = per_problem(lambda f, a, b, xt, mx, _c=cfg, _f=fac: pure_root(
|
||||
f, a, b, xt, mx, budget_factor=_f, **_c), probs, 200)
|
||||
f, a, b, xt, mx, budget_factor=_f, **_c), probs, 200, criterion="sign")
|
||||
t, _ok = totals(p, probs)
|
||||
out[name][fac] = (t["APS"], t["CHA"])
|
||||
cells.append(f"{t['APS']:>6d}/{t['CHA']:<6d}")
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
"""Numbers the revised text needs beyond verify_article.py's existing checks, all under the
|
||||
paper's single criterion (sweep_uniform.json, sweep_fourth_*.json, sweep_itp.json), plus the
|
||||
two small fresh runs the re-scoring cannot supply. Run on Linux; stdout is kept as
|
||||
results_numbers_uniform.txt and every number quoted from it is checked by verify_article.py.
|
||||
|
||||
python -u numbers_uniform.py
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from collections import defaultdict
|
||||
|
||||
from rescore_uniform import load_uniform
|
||||
|
||||
PROJ = "pure.ratio.derived3.project"
|
||||
CREDIT = "pure.ratio.derived3.credit"
|
||||
APRIME = "pure+extP+contra+flatanalogmempt+exp+half+close+sub.ratio.derived3.project"
|
||||
|
||||
|
||||
def cost(v):
|
||||
return v[0] if v[1] else 200
|
||||
|
||||
|
||||
def sign_p(w, l):
|
||||
k, n = min(w, l), w + l
|
||||
return 1.0 if n == 0 else min(1.0, 2.0 * sum(math.comb(n, i) for i in range(k + 1)) / 2.0 ** n)
|
||||
|
||||
|
||||
def rank(rows, s):
|
||||
return [r["label"] for r in sorted(rows, key=lambda r: (r[s]["n"] - r[s]["solved"], r[s]["total"]))]
|
||||
|
||||
|
||||
def family(pid):
|
||||
"""APS: the function number (aps.NN.MM); CHA: funN; the unit of dependence."""
|
||||
return ".".join(pid.split(".")[:2]) if pid.startswith("aps") else pid.split(".")[0]
|
||||
|
||||
|
||||
def families(a, b, s):
|
||||
"""Family-level comparison: per family the total of a against the total of b."""
|
||||
ta, tb = defaultdict(int), defaultdict(int)
|
||||
for p in a[s]["per"]:
|
||||
ta[family(p)] += cost(a[s]["per"][p])
|
||||
tb[family(p)] += cost(b[s]["per"][p])
|
||||
w = sum(ta[k] < tb[k] for k in ta)
|
||||
l = sum(ta[k] > tb[k] for k in ta)
|
||||
return w, len(ta) - w - l, l, dict(ta), dict(tb)
|
||||
|
||||
|
||||
def main():
|
||||
full = load_uniform("sweep_full.json")
|
||||
by = {r["label"]: r for r in full}
|
||||
for s in ("APS", "CHA"):
|
||||
rk = rank(full, s)
|
||||
print(f"{s} places: " + ", ".join(
|
||||
f"{lb} {rk.index(lb) + 1}" for lb in (
|
||||
"chandrupatla", "pure.ratio.derived3.none", PROJ, "toms748", "brent", "dekker",
|
||||
"itp_oracle", "ridders", CREDIT, "itp", "illinois", "bisection", "regula_falsi",
|
||||
"pure.exp_abs.bracket.both", "pure.exp_abs.bracket.bracket",
|
||||
"pure.exp_abs.bracket.credit")))
|
||||
for lb in ("dekker", "illinois", "regula_falsi", "brent", "toms748",
|
||||
"pure.ratio.derived3.none", "pure.exp_abs.bracket.both"):
|
||||
r = by[lb][s]
|
||||
print(f" {lb:<28} solved {r['solved']}/{r['n']} total {r['total']} over {r['over']}")
|
||||
# Corollary 2: best over scales, step guard (Table 4's individual ranking)
|
||||
best = {}
|
||||
for r in full:
|
||||
if r["spec"][0] == "pure" and r["spec"][3] == "step":
|
||||
best[r["spec"][1]] = min(best.get(r["spec"][1], 10 ** 9),
|
||||
r["APS"]["total"] + r["CHA"]["total"])
|
||||
print("best over scales (step guard):", dict(sorted(best.items(), key=lambda kv: kv[1])))
|
||||
|
||||
# revision point 8: families as the unit
|
||||
ap = {r["label"]: r for r in load_uniform("sweep_aprime.json")}[APRIME]
|
||||
for name, a in (("base rule", by[PROJ]), ("A'", ap)):
|
||||
for s in ("APS", "CHA"):
|
||||
w, t, l, ta, tb = families(a, by["chandrupatla"], s)
|
||||
print(f"{name} vs Chandrupatla by family, {s}: {w}/{t}/{l} of {w + t + l} families,"
|
||||
f" p={sign_p(w, l):.2g}")
|
||||
if name == "A'" and s == "CHA":
|
||||
print(" per family A' / Chandrupatla:",
|
||||
{k: (ta[k], tb[k]) for k in sorted(ta)})
|
||||
for s in ("APS", "CHA"):
|
||||
ps = list(a[s]["per"])
|
||||
w = sum(cost(a[s]["per"][p]) < cost(by["chandrupatla"][s]["per"][p]) for p in ps)
|
||||
l = sum(cost(a[s]["per"][p]) > cost(by["chandrupatla"][s]["per"][p]) for p in ps)
|
||||
print(f"{name} vs Chandrupatla by problem, {s}: {w}/{len(ps) - w - l}/{l}"
|
||||
f" p={sign_p(w, l):.2g}")
|
||||
# Table 6: the 60 paired (function, safeguard) cells of the far-end reading
|
||||
order = load_uniform("sweep_order.json")
|
||||
cells = {}
|
||||
for r in order:
|
||||
sim, sc, gu = r["spec"][1], r["spec"][2], r["spec"][3]
|
||||
ex = r["spec"][8] if len(r["spec"]) > 8 else "none"
|
||||
if sc == "far":
|
||||
cells[(sim, gu, ex)] = r["APS"]["total"] + r["CHA"]["total"]
|
||||
pairs = [(k[0], k[1]) for k in cells if k[2] == "none" and (k[0], k[1], "order") in cells]
|
||||
cheaper = sum(cells[(s_, g, "order")] < cells[(s_, g, "none")] for s_, g in pairs)
|
||||
print(f"far-end reading, measured order cheaper in {cheaper} of {len(pairs)} cells")
|
||||
fp = [r for r in order if r["spec"][1] == "rational" and r["spec"][2] == "far"
|
||||
and r["spec"][3] == "none"]
|
||||
for r in fp:
|
||||
print(f" false position reading {r['spec'][8]}: APS solved {r['APS']['solved']} "
|
||||
f"total {r['APS']['total']}")
|
||||
# negative item 9: the capped scale
|
||||
cap = {r["label"]: r for r in load_uniform("sweep_cap.json")}
|
||||
dire = {r["label"]: r for r in load_uniform("sweep_direction.json")}
|
||||
for lb in ("pure+dissim+slope.ratio.derived3_cap.project",
|
||||
"pure+dissim+slope.ratio.derived3_cap.safe"):
|
||||
r = cap[lb]
|
||||
print(f"cap {lb}: {r['APS']['total']} / {r['CHA']['total']} solved "
|
||||
f"{r['APS']['solved'] + r['CHA']['solved']}")
|
||||
for lb in ("pure+dissim+slope.ratio.derived3.project", "pure+dissim+slope.ratio.derived3.safe"):
|
||||
r = dire[lb]
|
||||
print(f"control {lb}: {r['APS']['total']} / {r['CHA']['total']}")
|
||||
# Table 1a: which canonical problems the multiplier moves
|
||||
from simroot.pure import pure_root
|
||||
from stage12_validation import load, per_problem
|
||||
probs = [p for p in load() if p[0] == "APS"]
|
||||
runs = {}
|
||||
for fac in (1.25, 1.5, 2.0):
|
||||
runs[fac] = per_problem(lambda f, a, b, xt, mx, _f=fac: pure_root(
|
||||
f, a, b, xt, mx, similarity="ratio", scale="derived3", guard="project",
|
||||
budget_factor=_f), probs, 200, criterion="sign")
|
||||
moved = {p: (runs[1.25][p][0], runs[1.5][p][0], runs[2.0][p][0]) for p in runs[2.0]
|
||||
if len({runs[1.25][p][0], runs[1.5][p][0], runs[2.0][p][0]}) > 1}
|
||||
print("canonical problems moved by the multiplier (1.25, 1.5, 2):", moved)
|
||||
# negative item 5: the phase detector (scale derived3_m) on the full benchmark
|
||||
allp = load()
|
||||
for sc in ("derived3", "derived3_m"):
|
||||
pp = per_problem(lambda f, a, b, xt, mx, _s=sc: pure_root(
|
||||
f, a, b, xt, mx, similarity="ratio", scale=_s, guard="project"), allp, 200,
|
||||
criterion="sign")
|
||||
t = {"APS": 0, "CHA": 0}
|
||||
for s_, pid, *_ in allp:
|
||||
t[s_] += pp[pid][0]
|
||||
print(f"phase detector item: scale {sc}: APS {t['APS']} CHA {t['CHA']} "
|
||||
f"both {t['APS'] + t['CHA']}")
|
||||
print("numbers uniform done")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,72 @@
|
||||
"""Revision point 1 (2026-09-22): the order of the base rule's step, measured where it can be.
|
||||
|
||||
Near a simple root the base rule's step is Newton's step with the derivative of the parabola
|
||||
through the last three points (tent similarity, step shorter than the distance to the far end,
|
||||
projection inactive). The error of that derivative is f'''/6 (x_n - x_{n-1})(x_n - x_{n-2}),
|
||||
i.e. O(e_{n-1} e_{n-2}), so e_{n+1} ~ e_n e_{n-1} e_{n-2} and the order is the root of
|
||||
p^3 = p^2 + p + 1, 1.839 - Muller's order. On a quadratic f the parabola is exact and the
|
||||
order is Newton's 2. In double precision a run has 3-4 superlinear steps before the error
|
||||
reaches the tolerance, too few to tell 1.84 from 2; here the iteration is carried to 10^-2900
|
||||
in 3000-digit arithmetic and the computational order e_{n+1} ~ e_n^p is read per step.
|
||||
The two-point (secant) scale is measured the same way for reference.
|
||||
|
||||
python -u order_high_precision.py -> results_order_high_precision.txt (stdout)
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import mpmath as mp
|
||||
|
||||
mp.mp.dps = 3000
|
||||
FLOOR = mp.mpf(10) ** -2900
|
||||
|
||||
|
||||
def iterate(f, x0, x1, x2, points, steps=60):
|
||||
xs = [mp.mpf(x0), mp.mpf(x1), mp.mpf(x2)]
|
||||
for _ in range(steps):
|
||||
a, b, c = xs[-3], xs[-2], xs[-1]
|
||||
fb, fc = f(b), f(c)
|
||||
d12 = (fc - fb) / (c - b)
|
||||
if points == 3:
|
||||
d01 = (fb - f(a)) / (b - a)
|
||||
slope = d12 + (d12 - d01) / (c - a) * (c - b)
|
||||
else:
|
||||
slope = d12
|
||||
xs.append(c - fc / slope)
|
||||
if xs[-1] == c:
|
||||
break
|
||||
return xs
|
||||
|
||||
|
||||
def orders(xs, root):
|
||||
"""Computational order per step, from errors above the precision floor only."""
|
||||
e = [abs(x - root) for x in xs]
|
||||
e = [v for v in e if v > FLOOR]
|
||||
return [mp.log(e[i + 1]) / mp.log(e[i]) for i in range(3, len(e) - 1)]
|
||||
|
||||
|
||||
CASES = (
|
||||
("cos x - x", lambda x: mp.cos(x) - x, (0.5, 0.9, 0.7), lambda: mp.findroot(lambda x: mp.cos(x) - x, 0.74)),
|
||||
("exp(x) - 2", lambda x: mp.exp(x) - 2, (0.5, 1.0, 0.8), lambda: mp.log(2)),
|
||||
("x^3 - x - 2", lambda x: x ** 3 - x - 2, (1.3, 1.7, 1.5), lambda: mp.findroot(lambda x: x ** 3 - x - 2, 1.52)),
|
||||
("sin x - 1/2", lambda x: mp.sin(x) - mp.mpf(1) / 2, (0.3, 0.7, 0.5), lambda: mp.asin(mp.mpf(1) / 2)),
|
||||
("x^2 - 2", lambda x: x ** 2 - 2, (1.2, 1.6, 1.3), lambda: mp.sqrt(2)),
|
||||
)
|
||||
|
||||
|
||||
def main():
|
||||
muller = mp.findroot(lambda p: p ** 3 - p ** 2 - p - 1, 1.8)
|
||||
golden = (1 + mp.sqrt(5)) / 2
|
||||
print(f"Muller order (root of p^3 = p^2 + p + 1): {float(muller):.4f}")
|
||||
print(f"secant order (golden ratio): {float(golden):.4f}")
|
||||
print(f"{'function':<14}{'three-point: last orders':<40}{'two-point: last orders'}")
|
||||
for name, f, (a, b, c), root in CASES:
|
||||
r = root()
|
||||
o3 = orders(iterate(f, a, b, c, 3), r)
|
||||
o2 = orders(iterate(f, a, b, c, 2), r)
|
||||
print(f"{name:<14}{' '.join(f'{float(v):.3f}' for v in o3[-3:]):<40}"
|
||||
f"{' '.join(f'{float(v):.3f}' for v in o2[-3:])}")
|
||||
print("order high precision done")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+4
-2
@@ -63,13 +63,15 @@ def best_pure(rows, setname):
|
||||
|
||||
|
||||
def head_to_head(rows, a, b, setname):
|
||||
"""Wins/ties/losses of a against b over EVERY problem of the set, a failure charged the
|
||||
full budget - the charging of the totals. Until 2026-09-22 only the problems both
|
||||
methods solved were counted, so a row of the paper summed to 153 of 154 (found on revision)."""
|
||||
ra = next(r for r in rows if r["label"] == a)[setname]
|
||||
rb = next(r for r in rows if r["label"] == b)[setname]
|
||||
win = tie = loss = both = 0
|
||||
for pid, (na, oka) in ra["per"].items():
|
||||
nb, okb = rb["per"][pid]
|
||||
if not (oka and okb):
|
||||
continue
|
||||
na, nb = (na if oka else 200), (nb if okb else 200)
|
||||
both += 1
|
||||
if na < nb:
|
||||
win += 1
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
"""The protocol tables under the single criterion of sweep_uniform.json (revision point 3), next
|
||||
to the numbers the paper printed under the published-root criterion.
|
||||
|
||||
python -u report_uniform.py
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
|
||||
from rescore_uniform import load_uniform
|
||||
|
||||
APRIME = "pure+extP+contra+flatanalogmempt+exp+half+close+sub.ratio.derived3"
|
||||
|
||||
|
||||
def rows(path):
|
||||
return {r["label"]: r for r in load_uniform(path)}
|
||||
|
||||
|
||||
def old(path):
|
||||
with open(path, encoding="utf8") as fh:
|
||||
return {r["label"]: r for r in json.load(fh)}
|
||||
|
||||
|
||||
def cost(v):
|
||||
return v[0] if v[1] else 200
|
||||
|
||||
|
||||
def wtl(a, b, s):
|
||||
ps = list(a[s]["per"])
|
||||
w = sum(cost(a[s]["per"][p]) < cost(b[s]["per"][p]) for p in ps)
|
||||
l = sum(cost(a[s]["per"][p]) > cost(b[s]["per"][p]) for p in ps)
|
||||
return w, len(ps) - w - l, l
|
||||
|
||||
|
||||
def rank(R, s):
|
||||
return sorted(R.values(), key=lambda r: (r[s]["n"] - r[s]["solved"], r[s]["total"]))
|
||||
|
||||
|
||||
def main():
|
||||
U, O = rows("sweep_full.json"), old("sweep_full.json")
|
||||
for s in ("APS", "CHA"):
|
||||
print(f"\n== {s}: top 12 of {len(U)} under the single criterion (old total in brackets)")
|
||||
for i, r in enumerate(rank(U, s)[:12], 1):
|
||||
lb = r["label"]
|
||||
print(f" {i:2d}. {lb:<34} solved {r[s]['solved']:3d}/{r[s]['n']} total {r[s]['total']:5d}"
|
||||
f" ({O[lb][s]['total']}) over {r[s]['over']}")
|
||||
pos = {r["label"]: i for i, r in enumerate(rank(U, s), 1)}
|
||||
for lb in ("pure.ratio.derived3.project", "chandrupatla", "toms748", "brent",
|
||||
"itp_oracle", "itp", "bisection"):
|
||||
print(f" place {pos[lb]:3d}: {lb:<30} {U[lb][s]['total']:5d} ({O[lb][s]['total']})"
|
||||
f" solved {U[lb][s]['solved']}")
|
||||
base, ch = U["pure.ratio.derived3.project"], U["chandrupatla"]
|
||||
print("\nbase rule vs Chandrupatla, failures charged:",
|
||||
{s: wtl(base, ch, s) for s in ("APS", "CHA")})
|
||||
A = rows("sweep_aprime.json")
|
||||
ap = A[f"{APRIME}.project"]
|
||||
print(f"\nTable 8 under the single criterion: A' {ap['APS']['total']} / {ap['CHA']['total']}"
|
||||
f" earned {A[APRIME + '.credit']['APS']['total']} / {A[APRIME + '.credit']['CHA']['total']}")
|
||||
for opp in ("chandrupatla", "toms748", "brent", "itp_oracle", "itp", "bisection"):
|
||||
o = U[opp]
|
||||
print(f" {opp:<14} {o['APS']['total']:5d} {o['CHA']['total']:5d} "
|
||||
f"A' vs: APS {wtl(ap, o, 'APS')} CHA {wtl(ap, o, 'CHA')}")
|
||||
print("\nTable 5 cells (single criterion / old):")
|
||||
for path, lb in (("sweep_full.json", "pure.ratio.derived3.credit"),
|
||||
("sweep_slope.json", "slope.ratio.derived3.project"),
|
||||
("sweep_points.json", "pure+shape+slope.ratio.derived3.safe"),
|
||||
("sweep_direction.json", "pure+dissim+slope.ratio.derived3.project"),
|
||||
("sweep_combo.json", "pure+shape+dissim+slope.ratio.derived3.safe")):
|
||||
try:
|
||||
r, o = rows(path)[lb], old(path)[lb]
|
||||
print(f" {lb:<46} {r['APS']['total']:5d} {r['CHA']['total']:5d} "
|
||||
f"({o['APS']['total']} {o['CHA']['total']}) over {r['APS']['over'] + r['CHA']['over']}")
|
||||
except KeyError:
|
||||
print(f" {lb}: label not in {path}")
|
||||
S = rows("sweep_aprime_s.json")
|
||||
print("\nTable 9a protocol column (single criterion / old):")
|
||||
So = old("sweep_aprime_s.json")
|
||||
for lb, r in S.items():
|
||||
print(f" {r['spec'][1]:<11} {r['APS']['total'] + r['CHA']['total']:6d} "
|
||||
f"({So[lb]['APS']['total'] + So[lb]['CHA']['total']})")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,140 @@
|
||||
"""Revision point 3 (2026-09-22): ONE scoring criterion for the whole paper.
|
||||
|
||||
The protocol tables were scored against the published root (|x - root| <= 1e-6), which charges
|
||||
every method the full budget on six problems where f vanishes identically near the root
|
||||
(section 7.3). Section 9 uses the bracketing criterion: a sign change of f within 1e-6 of the
|
||||
answer, or f(x) == 0 (corpus_roots_jl.solved). The runs did not keep x, so they cannot be
|
||||
re-scored from the files; every distinct configuration of every protocol sweep is run again
|
||||
here, on APS and CHA, under the bracketing criterion, and written in the SAME row format
|
||||
(label, spec, APS/CHA: total, solved, n, over, per[pid] = [n, ok]) so that every table and
|
||||
check can switch files without changing code.
|
||||
|
||||
Built-in check: A', the base rule and the library rivals must reproduce the APS and CHA
|
||||
lines of Table 10 exactly (those runs already use this criterion).
|
||||
|
||||
python -u rescore_uniform.py all configurations -> sweep_uniform.json
|
||||
python -u rescore_uniform.py --smoke 12 configurations, local code check
|
||||
python -u rescore_uniform.py --workers N
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import glob
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
import time
|
||||
from multiprocessing import get_context
|
||||
|
||||
os.environ.setdefault("OMP_NUM_THREADS", "1")
|
||||
|
||||
from corpus_roots_jl import solved
|
||||
from sweep_full import MAXFEV, XTOL, label, load_problems, make_method
|
||||
|
||||
OUT = "sweep_uniform.json"
|
||||
|
||||
|
||||
def sources():
|
||||
"""Every row-format protocol sweep and the distinct specs in it (JSON-encoded)."""
|
||||
files = {}
|
||||
for p in sorted(glob.glob("sweep_*.json")):
|
||||
if "smoke" in p or p == OUT:
|
||||
continue
|
||||
with open(p, encoding="utf8") as fh:
|
||||
d = json.load(fh)
|
||||
if isinstance(d, list) and d and "spec" in d[0]:
|
||||
files[p] = [json.dumps(r["spec"]) for r in d]
|
||||
return files
|
||||
|
||||
|
||||
def evaluate(spec_json):
|
||||
import scipy.optimize._tstutils as T
|
||||
spec = tuple(json.loads(spec_json))
|
||||
method = make_method(spec)
|
||||
res = {"label": label(spec), "spec": list(spec)}
|
||||
for setname in ("APS", "CHA"):
|
||||
total = nsolved = over = n_probs = 0
|
||||
per = {}
|
||||
for s, pid, f, a, b, _root in load_problems():
|
||||
if s != setname:
|
||||
continue
|
||||
n_probs += 1
|
||||
T._f6_cache.clear()
|
||||
random.seed(20260921)
|
||||
try:
|
||||
x, n, conv = method(f, a, b, XTOL, MAXFEV)
|
||||
x = float(x)
|
||||
except Exception:
|
||||
x, n, conv = float("nan"), MAXFEV, False
|
||||
# no reset here: the random step function is checked on the realisation the
|
||||
# method met, exactly as in sweep_fourth.evaluate (Table 10)
|
||||
ok = bool(conv and solved(f, x))
|
||||
n = int(n)
|
||||
total += n if ok else MAXFEV
|
||||
per[pid] = [n, ok]
|
||||
if ok:
|
||||
nsolved += 1
|
||||
if n > 2 * math.ceil(math.log2(abs(b - a) / XTOL)) + 4:
|
||||
over += 1
|
||||
res[setname] = {"total": total, "solved": nsolved, "n": n_probs, "over": over,
|
||||
"per": per}
|
||||
return spec_json, res
|
||||
|
||||
|
||||
_CACHE = {}
|
||||
|
||||
|
||||
def load_uniform(path):
|
||||
"""The rows of protocol sweep `path`, re-scored under the bracketing criterion. The
|
||||
15 MB file is read once per process; callers get fresh lists of the shared rows."""
|
||||
if "U" not in _CACHE:
|
||||
with open(OUT, encoding="utf8") as fh:
|
||||
_CACHE["U"] = json.load(fh)
|
||||
U = _CACHE["U"]
|
||||
return [U["by_spec"][s] for s in U["files"][path]]
|
||||
|
||||
|
||||
def main():
|
||||
workers = int(sys.argv[sys.argv.index("--workers") + 1]) if "--workers" in sys.argv else 6
|
||||
files = sources()
|
||||
specs = sorted({s for v in files.values() for s in v})
|
||||
if "--smoke" in sys.argv:
|
||||
must = [json.dumps(list(x)) for x in (
|
||||
("base", "chandrupatla"), ("base", "brent"), ("base", "toms748"),
|
||||
("pure", "ratio", "derived3", "project"),
|
||||
("pure", "ratio", "derived3", "project", "x",
|
||||
"contra+flatanalogmempt+exp+half+close+sub", "recent", "distance", "none",
|
||||
"pattern"))]
|
||||
specs = [s for s in must if s in specs] + [s for s in specs if s not in must][:7]
|
||||
print(f"{len(files)} sweep files, {sum(map(len, files.values()))} rows, "
|
||||
f"{len(specs)} distinct configurations, {workers} workers", flush=True)
|
||||
t0 = time.time()
|
||||
by_spec = {}
|
||||
with get_context("spawn").Pool(workers, maxtasksperchild=40) as pool:
|
||||
for i, (s, r) in enumerate(pool.imap_unordered(evaluate, specs, chunksize=2), 1):
|
||||
by_spec[s] = r
|
||||
if i % 25 == 0 or i == len(specs):
|
||||
el = time.time() - t0
|
||||
print(f" {i}/{len(specs)} done, {el:.0f} s, ETA {el / i * (len(specs) - i):.0f} s",
|
||||
flush=True)
|
||||
files = {p: v for p, v in files.items() if all(s in by_spec for s in v)}
|
||||
with open(OUT if "--smoke" not in sys.argv else "sweep_uniform_smoke.json", "w",
|
||||
encoding="utf8") as fh:
|
||||
json.dump({"criterion": "sign change within 1e-6 or f(x) == 0",
|
||||
"files": files, "by_spec": by_spec}, fh)
|
||||
# the built-in check against Table 10 (APS, CHA lines, same criterion)
|
||||
want = {'["pure", "ratio", "derived3", "project", "x", "contra+flatanalogmempt+exp+half+close'
|
||||
'+sub", "recent", "distance", "none", "pattern"]': (2259, 1074),
|
||||
'["base", "chandrupatla"]': (2595, 1505), '["base", "brent"]': (2707, 3238),
|
||||
'["base", "toms748"]': (2636, 3088)}
|
||||
for s, (aps, cha) in want.items():
|
||||
if s in by_spec:
|
||||
got = (by_spec[s]["APS"]["total"], by_spec[s]["CHA"]["total"])
|
||||
print(f" check vs Table 10: {by_spec[s]['label']:<60} {got} want {(aps, cha)} "
|
||||
+ ("OK" if got == (aps, cha) else "MISMATCH"), flush=True)
|
||||
print("rescore done", flush=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,37 @@
|
||||
APS places: chandrupatla 1, pure.ratio.derived3.none 2, pure.ratio.derived3.project 3, toms748 4, brent 5, dekker 232, itp_oracle 11, ridders 15, pure.ratio.derived3.credit 25, itp 29, illinois 237, bisection 73, regula_falsi 244, pure.exp_abs.bracket.both 24, pure.exp_abs.bracket.bracket 21, pure.exp_abs.bracket.credit 33
|
||||
dekker solved 153/154 total 3158 over 0
|
||||
illinois solved 153/154 total 7045 over 0
|
||||
regula_falsi solved 127/154 total 10560 over 5
|
||||
brent solved 154/154 total 2707 over 0
|
||||
toms748 solved 154/154 total 2636 over 0
|
||||
pure.ratio.derived3.none solved 154/154 total 2634 over 0
|
||||
pure.exp_abs.bracket.both solved 154/154 total 3269 over 0
|
||||
CHA places: chandrupatla 1, pure.ratio.derived3.none 229, pure.ratio.derived3.project 49, toms748 158, brent 227, dekker 232, itp_oracle 2, ridders 119, pure.ratio.derived3.credit 9, itp 5, illinois 233, bisection 15, regula_falsi 248, pure.exp_abs.bracket.both 3, pure.exp_abs.bracket.bracket 4, pure.exp_abs.bracket.credit 6
|
||||
dekker solved 25/45 total 5185 over 4
|
||||
illinois solved 24/45 total 6047 over 3
|
||||
regula_falsi solved 6/45 total 8239 over 2
|
||||
brent solved 43/45 total 3238 over 18
|
||||
toms748 solved 45/45 total 3088 over 15
|
||||
pure.ratio.derived3.none solved 39/45 total 3391 over 10
|
||||
pure.exp_abs.bracket.both solved 45/45 total 1778 over 0
|
||||
best over scales (step guard): {'ratio': 5422, 'exp_abs': 5772, 'rational': 5993, 'ratio_soft': 8455, 'sqrt': 9411, 'cbrt': 10874, 'exp_sq': 13187, 'rat_sq': 13990, 'cosine': 15272}
|
||||
base rule vs Chandrupatla by family, APS: 6/1/8 of 15 families, p=0.79
|
||||
base rule vs Chandrupatla by family, CHA: 3/0/6 of 9 families, p=0.51
|
||||
base rule vs Chandrupatla by problem, APS: 87/24/43 p=0.00014
|
||||
base rule vs Chandrupatla by problem, CHA: 11/5/29 p=0.0064
|
||||
A' vs Chandrupatla by family, APS: 8/1/6 of 15 families, p=0.79
|
||||
A' vs Chandrupatla by family, CHA: 7/0/2 of 9 families, p=0.18
|
||||
per family A' / Chandrupatla: {'fun1': (87, 103), 'fun2': (147, 152), 'fun3': (124, 305), 'fun4': (167, 297), 'fun5': (209, 233), 'fun6': (154, 233), 'fun7': (69, 64), 'fun8': (52, 63), 'fun9': (65, 55)}
|
||||
A' vs Chandrupatla by problem, APS: 103/20/31 p=3.2e-10
|
||||
A' vs Chandrupatla by problem, CHA: 31/4/10 p=0.0015
|
||||
far-end reading, measured order cheaper in 33 of 63 cells
|
||||
false position reading none: APS solved 127 total 10676
|
||||
false position reading order: APS solved 129 total 9855
|
||||
cap pure+dissim+slope.ratio.derived3_cap.project: 7315 / 2328 solved 199
|
||||
cap pure+dissim+slope.ratio.derived3_cap.safe: 4854 / 2027 solved 199
|
||||
control pure+dissim+slope.ratio.derived3.project: 2539 / 1864
|
||||
control pure+dissim+slope.ratio.derived3.safe: 2934 / 1752
|
||||
canonical problems moved by the multiplier (1.25, 1.5, 2): {'aps.13.00': (20, 30, 28)}
|
||||
phase detector item: scale derived3: APS 2634 CHA 2357 both 4991
|
||||
phase detector item: scale derived3_m: APS 2926 CHA 2410 both 5336
|
||||
numbers uniform done
|
||||
@@ -0,0 +1,9 @@
|
||||
Muller order (root of p^3 = p^2 + p + 1): 1.8393
|
||||
secant order (golden ratio): 1.6180
|
||||
function three-point: last orders two-point: last orders
|
||||
cos x - x 1.841 1.840 1.840 1.619 1.619 1.618
|
||||
exp(x) - 2 1.840 1.840 1.840 1.618 1.618 1.618
|
||||
x^3 - x - 2 1.841 1.840 1.840 1.618 1.618 1.618
|
||||
sin x - 1/2 1.841 1.840 1.839 1.619 1.618 1.618
|
||||
x^2 - 2 2.001 2.001 2.000 1.619 1.618 1.618
|
||||
order high precision done
|
||||
@@ -0,0 +1,70 @@
|
||||
|
||||
== APS: top 12 of 264 under the single criterion (old total in brackets)
|
||||
1. chandrupatla solved 154/154 total 2595 (2787) over 0
|
||||
2. pure.ratio.derived3.none solved 154/154 total 2634 (2806) over 0
|
||||
3. pure.ratio.derived3.project solved 154/154 total 2634 (2806) over 0
|
||||
4. toms748 solved 154/154 total 2636 (2820) over 0
|
||||
5. brent solved 154/154 total 2707 (2889) over 0
|
||||
6. pure.ratio.derived3.step solved 154/154 total 2846 (3036) over 0
|
||||
7. pure.ratio.derived3.safe solved 154/154 total 2846 (3036) over 0
|
||||
8. pure.ratio.derived.step solved 154/154 total 2914 (3104) over 0
|
||||
9. pure.ratio.derived.safe solved 154/154 total 2914 (3104) over 0
|
||||
10. pure.ratio.derived.project solved 154/154 total 3005 (3154) over 0
|
||||
11. itp_oracle solved 154/154 total 3068 (3260) over 0
|
||||
12. pure.exp_abs.derived3.project solved 154/154 total 3116 (3264) over 0
|
||||
place 3: pure.ratio.derived3.project 2634 (2806) solved 154
|
||||
place 1: chandrupatla 2595 (2787) solved 154
|
||||
place 4: toms748 2636 (2820) solved 154
|
||||
place 5: brent 2707 (2889) solved 154
|
||||
place 11: itp_oracle 3068 (3260) solved 154
|
||||
place 29: itp 3767 (3957) solved 154
|
||||
place 73: bisection 7338 (7530) solved 154
|
||||
|
||||
== CHA: top 12 of 264 under the single criterion (old total in brackets)
|
||||
1. chandrupatla solved 45/45 total 1505 (2441) over 0
|
||||
2. itp_oracle solved 45/45 total 1675 (2647) over 0
|
||||
3. pure.exp_abs.bracket.both solved 45/45 total 1778 (2736) over 0
|
||||
4. pure.exp_abs.bracket.bracket solved 45/45 total 1848 (2804) over 0
|
||||
5. itp solved 45/45 total 1946 (2896) over 0
|
||||
6. pure.exp_abs.bracket.credit solved 45/45 total 1952 (2907) over 0
|
||||
7. pure.cbrt.derived.credit solved 45/45 total 2048 (2995) over 0
|
||||
8. pure.cbrt.derived3.credit solved 45/45 total 2063 (3016) over 0
|
||||
9. pure.ratio.derived3.credit solved 45/45 total 2073 (3020) over 0
|
||||
10. pure.rational.bracket.credit solved 45/45 total 2089 (3039) over 0
|
||||
11. pure.exp_abs.derived3.credit solved 45/45 total 2102 (3049) over 0
|
||||
12. pure.ratio_soft.derived3.credit solved 45/45 total 2105 (3054) over 0
|
||||
place 49: pure.ratio.derived3.project 2357 (3220) solved 45
|
||||
place 1: chandrupatla 1505 (2441) solved 45
|
||||
place 158: toms748 3088 (4000) solved 45
|
||||
place 227: brent 3238 (4115) solved 43
|
||||
place 2: itp_oracle 1675 (2647) solved 45
|
||||
place 5: itp 1946 (2896) solved 45
|
||||
place 15: bisection 2136 (3090) solved 45
|
||||
|
||||
base rule vs Chandrupatla, failures charged: {'APS': (87, 24, 43), 'CHA': (11, 5, 29)}
|
||||
|
||||
Table 8 under the single criterion: A' 2259 / 1074 earned 3417 / 1852
|
||||
chandrupatla 2595 1505 A' vs: APS (103, 20, 31) CHA (31, 4, 10)
|
||||
toms748 2636 3088 A' vs: APS (127, 6, 21) CHA (42, 2, 1)
|
||||
brent 2707 3238 A' vs: APS (118, 17, 19) CHA (39, 3, 3)
|
||||
itp_oracle 3068 1675 A' vs: APS (126, 7, 21) CHA (35, 1, 9)
|
||||
itp 3767 1946 A' vs: APS (133, 6, 15) CHA (37, 1, 7)
|
||||
bisection 7338 2136 A' vs: APS (152, 1, 1) CHA (41, 1, 3)
|
||||
|
||||
Table 5 cells (single criterion / old):
|
||||
pure.ratio.derived3.credit 3377 2073 (3568 3020) over 0
|
||||
slope.ratio.derived3.project 2663 2170 (2848 3114) over 0
|
||||
pure+shape+slope.ratio.derived3.safe 2337 2177 (2527 3126) over 0
|
||||
pure+dissim+slope.ratio.derived3.project 2539 1864 (2726 2799) over 0
|
||||
pure+shape+dissim+slope.ratio.derived3.safe 2695 1928 (2884 2871) over 0
|
||||
|
||||
Table 9a protocol column (single criterion / old):
|
||||
exp_abs 3965 (4988)
|
||||
rational 4424 (5486)
|
||||
ratio 3333 (4443)
|
||||
ratio_soft 7249 (8360)
|
||||
sqrt 11613 (12718)
|
||||
cbrt 16094 (17207)
|
||||
cosine 17487 (18412)
|
||||
rat_sq 17452 (18422)
|
||||
exp_sq 17429 (18410)
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
# Revision 1: ITP on the six corpora, then the verifier against the single criterion.
|
||||
export OMP_NUM_THREADS=1 OPENBLAS_NUM_THREADS=1 MKL_NUM_THREADS=1
|
||||
cd "$HOME/sim-numerics" || exit 1
|
||||
echo "=== ITP ==="
|
||||
~/torchenv/bin/python -u sweep_itp.py 2>&1 | grep -v Warn | grep -v "return "
|
||||
echo "=== VERIFY ==="
|
||||
~/torchenv/bin/python -u verify_article.py > ~/verify_uniform.log 2>&1
|
||||
echo "verify OK $(grep -c '^ OK' ~/verify_uniform.log) BAD $(grep -c '^ BAD' ~/verify_uniform.log)"
|
||||
grep -A8 '^Traceback' ~/verify_uniform.log
|
||||
echo "=== REVISION1 DONE ==="
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
# The article verifier alone, detached, with an end marker.
|
||||
export OMP_NUM_THREADS=1 OPENBLAS_NUM_THREADS=1 MKL_NUM_THREADS=1
|
||||
cd "$HOME/sim-numerics" || exit 1
|
||||
~/torchenv/bin/python -u verify_article.py > ~/verify_uniform.log 2>&1
|
||||
echo "verify OK $(grep -c '^ OK' ~/verify_uniform.log) BAD $(grep -c '^ BAD' ~/verify_uniform.log)"
|
||||
grep '^ BAD' ~/verify_uniform.log
|
||||
grep -A8 '^Traceback' ~/verify_uniform.log
|
||||
tail -1 ~/verify_uniform.log
|
||||
echo "=== VERIFY DONE ==="
|
||||
+10
-3
@@ -81,15 +81,22 @@ def load():
|
||||
return out
|
||||
|
||||
|
||||
def per_problem(method, probs, maxfev):
|
||||
"""Charged evaluation count per problem, and whether it was solved."""
|
||||
def per_problem(method, probs, maxfev, criterion="root"):
|
||||
"""Charged evaluation count per problem, and whether it was solved. criterion="root":
|
||||
within ACC of the published root (this stage's original scoring); "sign": the paper's
|
||||
single criterion since 2026-09-22, a sign change within 1e-6 or f(x) == 0."""
|
||||
from corpus_roots_jl import solved
|
||||
out = {}
|
||||
for _s, pid, f, a, b, root in probs:
|
||||
try:
|
||||
x, n, conv = method(f, a, b, XTOL, maxfev)
|
||||
x = float(x)
|
||||
except Exception:
|
||||
x, n, conv = float("nan"), maxfev, False
|
||||
ok = bool(conv and math.isfinite(x) and abs(x - root) <= ACC)
|
||||
if criterion == "sign":
|
||||
ok = bool(conv and solved(f, x))
|
||||
else:
|
||||
ok = bool(conv and math.isfinite(x) and abs(x - root) <= ACC)
|
||||
out[pid] = (n if ok else maxfev, ok)
|
||||
return out
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,72 @@
|
||||
"""Revision point 11 (2026-09-22): ITP in Table 10 - at the authors' recommended constants and as
|
||||
the per-problem oracle of section 4 - on all six corpora, under the uniform criterion of
|
||||
section 9, with the harness of sweep_fourth.py (same problems, same seeding, same charging).
|
||||
|
||||
python -u sweep_itp.py run -> sweep_itp.json, then the table
|
||||
python -u sweep_itp.py --report
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
from multiprocessing import Pool
|
||||
|
||||
import sweep_fourth
|
||||
from sweep_oos import sign_p
|
||||
|
||||
sweep_fourth.CONFIGS["itp"] = ("base", "itp")
|
||||
sweep_fourth.CONFIGS["itp_oracle"] = ("base", "itp_oracle")
|
||||
SETS = ("APS", "CHA", "NEW", "RJL", "APP", "D")
|
||||
|
||||
|
||||
def job(j):
|
||||
name, which = j
|
||||
return name, which, sweep_fourth.evaluate((name, which))[1]
|
||||
|
||||
|
||||
def cost(v):
|
||||
return v[0] if v[1] else 200
|
||||
|
||||
|
||||
def report(R):
|
||||
seen = json.load(open("sweep_fourth_seen.json", encoding="utf8"))
|
||||
four = json.load(open("sweep_fourth_fourth.json", encoding="utf8"))
|
||||
ap = dict(seen["Aprime"])
|
||||
ap.update(four["Aprime"])
|
||||
print("corpus A' ITP (viol) ITP oracle (viol) A' vs ITP A' vs oracle")
|
||||
tot = {"A": 0, "itp": 0, "itp_oracle": 0}
|
||||
for s in SETS:
|
||||
a = ap[s]
|
||||
row = [f"{s:<5} {sum(cost(v) for v in a.values()):6d}"]
|
||||
tot["A"] += sum(cost(v) for v in a.values())
|
||||
h = []
|
||||
for k in ("itp", "itp_oracle"):
|
||||
r = R[k][s]
|
||||
t = sum(cost(v) for v in r.values())
|
||||
tot[k] += t
|
||||
row.append(f"{t:6d} ({sum(v[2] for v in r.values())})")
|
||||
w = sum(cost(a[p]) < cost(r[p]) for p in a)
|
||||
l = sum(cost(a[p]) > cost(r[p]) for p in a)
|
||||
h.append(f"{w}/{len(a) - w - l}/{l} p={sign_p(w, l):.1g}")
|
||||
print(" ".join(row) + " " + " ".join(h))
|
||||
print(f"all {tot['A']:6d} {tot['itp']:6d} {tot['itp_oracle']:6d}")
|
||||
|
||||
|
||||
def main():
|
||||
if "--report" not in sys.argv:
|
||||
jobs = [(n, w) for n in ("itp", "itp_oracle") for w in ("seen", "fourth")]
|
||||
with Pool(len(jobs)) as pool:
|
||||
out = pool.map(job, jobs)
|
||||
R = {}
|
||||
for name, _which, res in out:
|
||||
R.setdefault(name, {}).update(res)
|
||||
with open("sweep_itp.json", "w", encoding="utf8") as fh:
|
||||
json.dump(R, fh)
|
||||
with open("sweep_itp.json", encoding="utf8") as fh:
|
||||
R = json.load(fh)
|
||||
report(R)
|
||||
print("itp done")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
File diff suppressed because one or more lines are too long
+304
-177
@@ -37,8 +37,7 @@ def row(rows, setname, lbl):
|
||||
|
||||
|
||||
def main():
|
||||
with open("sweep_full.json", encoding="utf8") as fh:
|
||||
rows = json.load(fh)
|
||||
rows = _load("sweep_full.json")
|
||||
|
||||
# Guard against quoting places from a field that is missing a competitor.
|
||||
# It has already happened once: before Chandrupatla's own method was
|
||||
@@ -55,28 +54,28 @@ def main():
|
||||
|
||||
# ---- the proposed method: projection, one declared constant ----------
|
||||
print("\nThe proposed method (projection, multiplier declared):")
|
||||
for setname, pl, tot, sol in (("APS", 3, 2806, 153),
|
||||
("CHA", 45, 3220, 40)):
|
||||
for setname, pl, tot, sol in (("APS", 3, 2634, 154),
|
||||
("CHA", 49, 2357, 45)):
|
||||
d = row(rows, setname, PROPOSED)
|
||||
check(f"{setname} place", place(rows, setname, PROPOSED), pl)
|
||||
check(f"{setname} total", d["total"], tot)
|
||||
check(f"{setname} solved", d["solved"], sol)
|
||||
check("both sets", row(rows, "APS", PROPOSED)["total"]
|
||||
+ row(rows, "CHA", PROPOSED)["total"], 6026)
|
||||
+ row(rows, "CHA", PROPOSED)["total"], 4991)
|
||||
|
||||
print("\nHead to head of the proposed method:")
|
||||
for setname, opp, want in [
|
||||
("APS", "chandrupatla", (87, 24, 42)),
|
||||
("APS", "toms748", (86, 16, 51)),
|
||||
("APS", "brent", (102, 11, 40)),
|
||||
("APS", "itp", (132, 3, 18)),
|
||||
("APS", "itp_oracle", (121, 4, 28)),
|
||||
("APS", "bisection", (152, 1, 0)),
|
||||
("CHA", "chandrupatla", (9, 5, 26)),
|
||||
("CHA", "toms748", (31, 1, 8)),
|
||||
("CHA", "brent", (30, 4, 4)),
|
||||
("CHA", "itp", (17, 0, 23)),
|
||||
("CHA", "itp_oracle", (16, 0, 24))]:
|
||||
("APS", "chandrupatla", (87, 24, 43)),
|
||||
("APS", "toms748", (86, 16, 52)),
|
||||
("APS", "brent", (102, 11, 41)),
|
||||
("APS", "itp", (132, 3, 19)),
|
||||
("APS", "itp_oracle", (121, 4, 29)),
|
||||
("APS", "bisection", (152, 1, 1)),
|
||||
("CHA", "chandrupatla", (11, 5, 29)),
|
||||
("CHA", "toms748", (33, 1, 11)),
|
||||
("CHA", "brent", (34, 4, 7)),
|
||||
("CHA", "itp", (18, 1, 26)),
|
||||
("CHA", "itp_oracle", (16, 1, 28))]:
|
||||
w, t, l, _ = head_to_head(rows, PROPOSED, opp, setname)
|
||||
check(f"{setname} vs {opp}", (w, t, l), want)
|
||||
|
||||
@@ -85,48 +84,48 @@ def main():
|
||||
k, n = min(w, l), w + l
|
||||
return min(1.0, 2.0 * sum(_m.comb(n, i) for i in range(k + 1)) / 2.0 ** n)
|
||||
w, _t, l, _ = head_to_head(rows, PROPOSED, "chandrupatla", "APS")
|
||||
check("APS vs Chandrupatla sign test p < 1e-4", sign_p(w, l) < 1e-4, True)
|
||||
check("APS vs Chandrupatla sign test p (2 digits)", float(f"{sign_p(w, l):.2g}"), 0.00014)
|
||||
w, _t, l, _ = head_to_head(rows, PROPOSED, "chandrupatla", "CHA")
|
||||
check("CHA vs Chandrupatla sign test p (rounded)", round(sign_p(w, l), 3), 0.006)
|
||||
|
||||
# ---- the constant-free variant ---------------------------------------
|
||||
print("\nThe constant-free variant (earned projection):")
|
||||
for setname, pl, tot in (("APS", 29, 3568), ("CHA", 10, 3020)):
|
||||
for setname, pl, tot in (("APS", 25, 3377), ("CHA", 9, 2073)):
|
||||
check(f"credit {setname} place", place(rows, setname, CREDIT), pl)
|
||||
check(f"credit {setname} total", row(rows, setname, CREDIT)["total"], tot)
|
||||
check("credit both sets", row(rows, "APS", CREDIT)["total"]
|
||||
+ row(rows, "CHA", CREDIT)["total"], 6588)
|
||||
check("credit costs 762 more on the canonical set",
|
||||
row(rows, "APS", CREDIT)["total"] - row(rows, "APS", PROPOSED)["total"], 762)
|
||||
for setname, opp, want in [("APS", "chandrupatla", (79, 3, 71)),
|
||||
("APS", "toms748", (77, 9, 67)),
|
||||
("APS", "brent", (78, 5, 70))]:
|
||||
+ row(rows, "CHA", CREDIT)["total"], 5450)
|
||||
check("credit costs 743 more on the canonical set",
|
||||
row(rows, "APS", CREDIT)["total"] - row(rows, "APS", PROPOSED)["total"], 743)
|
||||
for setname, opp, want in [("APS", "chandrupatla", (79, 3, 72)),
|
||||
("APS", "toms748", (78, 9, 67)),
|
||||
("APS", "brent", (79, 5, 70))]:
|
||||
w, t, l, _ = head_to_head(rows, CREDIT, opp, setname)
|
||||
check(f"credit {setname} vs {opp}", (w, t, l), want)
|
||||
w, _t, l, _ = head_to_head(rows, CREDIT, "chandrupatla", "APS")
|
||||
check("credit APS vs Chandrupatla sign test p (rounded)", round(sign_p(w, l), 2), 0.57)
|
||||
check("credit APS vs Chandrupatla sign test p (rounded)", round(sign_p(w, l), 2), 0.63)
|
||||
|
||||
# ---- what the earlier, order-destroying guards cost --------------------
|
||||
print("\nThe guards that replace the step instead of projecting it:")
|
||||
check("APS unguarded", row(rows, "APS", "pure.ratio.derived3.none")["total"],
|
||||
2806)
|
||||
2634)
|
||||
cha_none = row(rows, "CHA", "pure.ratio.derived3.none")
|
||||
check("CHA unguarded total", cha_none["total"], 4104)
|
||||
check("CHA unguarded solved", cha_none["solved"], 35)
|
||||
check("CHA unguarded total", cha_none["total"], 3391)
|
||||
check("CHA unguarded solved", cha_none["solved"], 39)
|
||||
check("CHA unguarded bound violations", cha_none["over"], 10)
|
||||
check("APS bracket-guard", row(rows, "APS", "pure.ratio.derived3.bracket")["total"],
|
||||
7260)
|
||||
7068)
|
||||
check("APS both-guard", row(rows, "APS", "pure.ratio.derived3.both")["total"],
|
||||
7239)
|
||||
7046)
|
||||
|
||||
# ---- the field --------------------------------------------------------
|
||||
print("\nAlefeld-Potra-Shi:")
|
||||
check("APS winner", rank(rows, "APS")[0]["label"], "chandrupatla")
|
||||
for lbl, pl, tot in [("chandrupatla", 1, 2787), ("toms748", 4, 2820),
|
||||
("brent", 5, 2889), ("dekker", 12, 3158),
|
||||
("itp_oracle", 13, 3260), ("ridders", 20, 3313),
|
||||
("itp", 34, 3957), ("illinois", 73, 7045),
|
||||
("bisection", 79, 7530), ("regula_falsi", 244, 10560)]:
|
||||
for lbl, pl, tot in [("chandrupatla", 1, 2595), ("toms748", 4, 2636),
|
||||
("brent", 5, 2707), ("dekker", 232, 3158),
|
||||
("itp_oracle", 11, 3068), ("ridders", 15, 3124),
|
||||
("itp", 29, 3767), ("illinois", 237, 7045),
|
||||
("bisection", 73, 7338), ("regula_falsi", 244, 10560)]:
|
||||
check(f"APS {lbl} place", place(rows, "APS", lbl), pl)
|
||||
check(f"APS {lbl} total", row(rows, "APS", lbl)["total"], tot)
|
||||
check("APS regula falsi solved", row(rows, "APS", "regula_falsi")["solved"],
|
||||
@@ -134,31 +133,31 @@ def main():
|
||||
|
||||
print("\nChandrupatla:")
|
||||
top = rank(rows, "CHA")[0]
|
||||
check("CHA rank 1 label", top["label"], "pure.sqrt.bracket.project")
|
||||
check("CHA rank 1 solves one more than anyone else", top["CHA"]["solved"], 41)
|
||||
for lbl, pl, tot in [("chandrupatla", 2, 2441), ("itp_oracle", 3, 2647),
|
||||
("itp", 6, 2896), ("bisection", 16, 3090),
|
||||
("toms748", 159, 4000), ("brent", 227, 4115)]:
|
||||
check("CHA rank 1 label", top["label"], "chandrupatla")
|
||||
check("CHA rank 1 solves all 45", top["CHA"]["solved"], 45)
|
||||
for lbl, pl, tot in [("chandrupatla", 1, 1505), ("itp_oracle", 2, 1675),
|
||||
("itp", 5, 1946), ("bisection", 15, 2136),
|
||||
("toms748", 158, 3088), ("brent", 227, 3238)]:
|
||||
check(f"CHA {lbl} place", place(rows, "CHA", lbl), pl)
|
||||
check(f"CHA {lbl} total", row(rows, "CHA", lbl)["total"], tot)
|
||||
check("CHA brent solved", row(rows, "CHA", "brent")["solved"], 38)
|
||||
check("CHA brent solved", row(rows, "CHA", "brent")["solved"], 43)
|
||||
|
||||
ours_both = (row(rows, "APS", PROPOSED)["total"]
|
||||
+ row(rows, "CHA", PROPOSED)["total"])
|
||||
cha_both = (row(rows, "APS", "chandrupatla")["total"]
|
||||
+ row(rows, "CHA", "chandrupatla")["total"])
|
||||
check("chandrupatla, both sets", cha_both, 5228)
|
||||
check("chandrupatla, both sets", cha_both, 4100)
|
||||
check("Chandrupatla beats us on both sets", cha_both < ours_both, True)
|
||||
|
||||
# ---- the regime findings ---------------------------------------------
|
||||
print("\nNegative results, the regime claims:")
|
||||
check("CHA cbrt over the whole set",
|
||||
row(rows, "CHA", "pure.cbrt.derived3.project")["total"], 4109)
|
||||
row(rows, "CHA", "pure.cbrt.derived3.project")["total"], 3204)
|
||||
switched = (row(rows, "APS", PROJ)["total"]
|
||||
+ row(rows, "CHA", "pure.cbrt.derived3.project")["total"])
|
||||
single = row(rows, "APS", PROJ)["total"] + row(rows, "CHA", PROJ)["total"]
|
||||
check("single fixed choice, both sets", single, 6026)
|
||||
check("switch by benchmark set, both sets", switched, 6915)
|
||||
check("single fixed choice, both sets", single, 4991)
|
||||
check("switch by benchmark set, both sets", switched, 5838)
|
||||
check("switching is worse than not switching", switched > single, True)
|
||||
for pid, ours_n, cb_n in (("fun4.1", 89, 32), ("fun4.2", 93, 32),
|
||||
("fun4.3", 113, 40), ("fun4.4", 125, 47),
|
||||
@@ -172,10 +171,10 @@ def main():
|
||||
print("\nThe law across the grid:")
|
||||
lin = ("ratio", "rational", "exp_abs")
|
||||
quad = ("rat_sq", "exp_sq", "cosine")
|
||||
want = {("derived3", "lin"): 6893, ("derived3", "quad"): 22315,
|
||||
("derived", "lin"): 6981, ("derived", "quad"): 22206,
|
||||
("bracket", "lin"): 10279, ("bracket", "quad"): 19127,
|
||||
("start", "lin"): 16102, ("start", "quad"): 15345}
|
||||
want = {("derived3", "lin"): 5764, ("derived3", "quad"): 21200,
|
||||
("derived", "lin"): 5854, ("derived", "quad"): 21089,
|
||||
("bracket", "lin"): 9149, ("bracket", "quad"): 18015,
|
||||
("start", "lin"): 14983, ("start", "quad"): 14228}
|
||||
for scale in ("derived3", "derived", "bracket", "start"):
|
||||
for group, gname in ((lin, "lin"), (quad, "quad")):
|
||||
tot = cnt = 0
|
||||
@@ -204,15 +203,15 @@ def main():
|
||||
[s for s, _ in sorted(best_by_sim.items(), key=lambda kv: kv[1])],
|
||||
["ratio", "exp_abs", "rational", "ratio_soft", "sqrt", "cbrt",
|
||||
"exp_sq", "rat_sq", "cosine"])
|
||||
for sim, v in [("ratio", 6560), ("exp_abs", 6895), ("rational", 7118),
|
||||
("ratio_soft", 9578), ("sqrt", 10546), ("cbrt", 12002),
|
||||
("exp_sq", 14307), ("rat_sq", 15102), ("cosine", 16394)]:
|
||||
for sim, v in [("ratio", 5422), ("exp_abs", 5772), ("rational", 5993),
|
||||
("ratio_soft", 8455), ("sqrt", 9411), ("cbrt", 10874),
|
||||
("exp_sq", 13187), ("rat_sq", 13990), ("cosine", 15272)]:
|
||||
check(f"similarity {sim} best", best_by_sim[sim], v)
|
||||
check("scale ranking",
|
||||
[s for s, _ in sorted(best_by_scale.items(), key=lambda kv: kv[1])],
|
||||
["derived3", "derived", "bracket", "start"])
|
||||
for sc, v in [("derived3", 6560), ("derived", 6702), ("bracket", 9107),
|
||||
("start", 14540)]:
|
||||
for sc, v in [("derived3", 5422), ("derived", 5564), ("bracket", 7972),
|
||||
("start", 13423)]:
|
||||
check(f"scale {sc} best", best_by_scale[sc], v)
|
||||
|
||||
verify_placement_modes()
|
||||
@@ -221,6 +220,7 @@ def main():
|
||||
verify_gap_decomposition()
|
||||
verify_safeguard_and_tables()
|
||||
verify_flat_regime_and_oos()
|
||||
verify_revision1()
|
||||
|
||||
print()
|
||||
if FAILS:
|
||||
@@ -239,32 +239,32 @@ def main():
|
||||
# --------------------------------------------------------------------------
|
||||
PLACEMENT = {
|
||||
# file label APS CHA
|
||||
"sweep_slope.json": ("slope.ratio.derived3.project", 2848, 3114),
|
||||
"sweep_points.json": ("pure+shape+slope.ratio.derived3.safe", 2527, 3126),
|
||||
"sweep_direction.json": ("pure+dissim+slope.ratio.derived3.project", 2726, 2799),
|
||||
"sweep_combo.json": ("pure+shape+dissim+slope.ratio.derived3.safe", 2884, 2871),
|
||||
"sweep_gate.json": ("progress.ratio.derived.project", 4449, 3047),
|
||||
"sweep_log.json": ("log.ratio_soft.derived.safe", 6940, 3541),
|
||||
"sweep_slope.json": ("slope.ratio.derived3.project", 2663, 2170),
|
||||
"sweep_points.json": ("pure+shape+slope.ratio.derived3.safe", 2337, 2177),
|
||||
"sweep_direction.json": ("pure+dissim+slope.ratio.derived3.project", 2539, 1864),
|
||||
"sweep_combo.json": ("pure+shape+dissim+slope.ratio.derived3.safe", 2695, 1928),
|
||||
"sweep_gate.json": ("progress.ratio.derived.project", 4258, 2093),
|
||||
"sweep_log.json": ("log.ratio_soft.derived.safe", 6749, 2598),
|
||||
}
|
||||
# The per-place table of section "the similarity function belongs to the place":
|
||||
# seven PAIRED comparisons in sweep_order.json. Checked as pairs, because a pair is
|
||||
# what the pre-registration licensed and a single cell would prove nothing.
|
||||
ORDER_PAIRS = {
|
||||
# guard (APS m=1, APS measured, CHA m=1, CHA measured)
|
||||
"both": (4522, 3675, 3406, 3241),
|
||||
"bracket": (4606, 3542, 3602, 3359),
|
||||
"credit": (5190, 4686, 3013, 2884),
|
||||
"project": (6932, 6364, 4789, 4554),
|
||||
"safe": (5987, 5229, 4134, 3954),
|
||||
"step": (6435, 5551, 4287, 4068),
|
||||
"none": (10676, 10043, 8265, 7794),
|
||||
"both": (4331, 3485, 2469, 2306),
|
||||
"bracket": (4418, 3352, 2671, 2428),
|
||||
"credit": (4999, 4495, 2064, 1933),
|
||||
"project": (6783, 6176, 4057, 3751),
|
||||
"safe": (5803, 5040, 3218, 3032),
|
||||
"step": (6251, 5362, 3371, 3146),
|
||||
"none": (10676, 9855, 8265, 7424),
|
||||
}
|
||||
# the negative item: the order does not cure false position
|
||||
ORDER_FALSEPOS = {("rational", "far", "none", "none"): (127, 10676),
|
||||
("rational", "far", "none", "order"): (128, 10043)}
|
||||
("rational", "far", "none", "order"): (129, 9855)}
|
||||
# and the harmful direction, quoted in the same subsection
|
||||
ORDER_SLOPE_HARM = {("ratio", "derived3", "none", "none"): 2806,
|
||||
("ratio", "derived3", "none", "order"): 2854}
|
||||
ORDER_SLOPE_HARM = {("ratio", "derived3", "none", "none"): 2634,
|
||||
("ratio", "derived3", "none", "order"): 2703}
|
||||
|
||||
|
||||
def verify_per_place():
|
||||
@@ -273,8 +273,7 @@ def verify_per_place():
|
||||
print(" !! sweep_order.json absent — section 'belongs to the place' unverifiable")
|
||||
FAILS.append("missing sweep_order.json")
|
||||
return
|
||||
with open("sweep_order.json", encoding="utf8") as fh:
|
||||
rows = json.load(fh)
|
||||
rows = _load("sweep_order.json")
|
||||
|
||||
def cell(sim, sc, gu, ex):
|
||||
for r in rows:
|
||||
@@ -318,11 +317,11 @@ def verify_per_place():
|
||||
|
||||
DECISION_CELLS = {
|
||||
# (similarity, prestep, guard): {set: total}
|
||||
("ratio", "band", "project"): {"APS": 5432, "CHA": 3059},
|
||||
("ratio", "band", "credit"): {"CHA": 2892},
|
||||
("ratio", "none", "project"): {"APS": 2806},
|
||||
("ratio", "defect", "project"): {"APS": 2523, "CHA": 3210},
|
||||
("ratio_soft", "simpair", "project"): {"CHA": 2897},
|
||||
("ratio", "band", "project"): {"APS": 5242, "CHA": 2101},
|
||||
("ratio", "band", "credit"): {"CHA": 1942},
|
||||
("ratio", "none", "project"): {"APS": 2634},
|
||||
("ratio", "defect", "project"): {"APS": 2351, "CHA": 2346},
|
||||
("ratio_soft", "simpair", "project"): {"CHA": 1941},
|
||||
}
|
||||
DECISION_RATES = {"band": 63.5, "defect": 6.6}
|
||||
|
||||
@@ -333,8 +332,7 @@ def verify_decision_place():
|
||||
print(" !! sweep_decision.json absent — section 'decision place' unverifiable")
|
||||
FAILS.append("missing sweep_decision.json")
|
||||
return
|
||||
with open("sweep_decision.json", encoding="utf8") as fh:
|
||||
rows = json.load(fh)
|
||||
rows = _load("sweep_decision.json")
|
||||
by = {(r["spec"][1], r["spec"][5], r["spec"][3]): r for r in rows}
|
||||
for k, sets in DECISION_CELLS.items():
|
||||
r = by.get(k)
|
||||
@@ -345,9 +343,9 @@ def verify_decision_place():
|
||||
for setname, want in sets.items():
|
||||
check(f"{'.'.join(k)} {setname}", r[setname]["total"], want)
|
||||
d = by[("ratio", "defect", "project")]
|
||||
check("defect APS solved", d["APS"]["solved"], 153)
|
||||
check("defect both sets", d["APS"]["total"] + d["CHA"]["total"], 5733)
|
||||
check("defect is the new canonical best (< 2527)", d["APS"]["total"] < 2527, True)
|
||||
check("defect APS solved", d["APS"]["solved"], 154)
|
||||
check("defect both sets", d["APS"]["total"] + d["CHA"]["total"], 4697)
|
||||
check("defect second to the shape reading (2337 < defect)", 2337 < d["APS"]["total"], True)
|
||||
fam = [r for r in rows if r["spec"][3] in ("project", "safe", "credit")]
|
||||
check("decision grid guarantee violations", sum(r["APS"]["over"] + r["CHA"]["over"]
|
||||
for r in fam), 0)
|
||||
@@ -389,7 +387,7 @@ def verify_gap_decomposition():
|
||||
ck = diag_model_order_checks.main()
|
||||
fl = diag_flat_detectable.main()
|
||||
per = mo["per_problem"]
|
||||
check("problems where we lose", len(mo["lose"]), 33)
|
||||
check("problems where we lose", len(mo["lose"]), 35)
|
||||
check("fun1.4 our bracket halvings/eval", round(per["fun1.4"][2], 2), 0.62)
|
||||
check("fun1.4 IQI from our points", round(per["fun1.4"][3], 2), 10.37)
|
||||
flat = [p for p in per if p.split(".")[0] in ("fun3", "fun4", "fun5", "fun6")]
|
||||
@@ -397,13 +395,13 @@ def verify_gap_decomposition():
|
||||
check("flat: ours max", round(max(per[p][2] for p in flat), 2), 0.75)
|
||||
check("flat: IQI min", round(min(per[p][3] for p in flat), 2), 0.01)
|
||||
check("flat: IQI max", round(max(per[p][3] for p in flat), 2), 0.17)
|
||||
check("non-degenerate states with one negative weight", mo["neg_ok"], 428)
|
||||
check("bracketing states in total", mo["neg_all"], 431)
|
||||
check("non-degenerate states with one negative weight", int(mo["neg_ok"]), 431)
|
||||
check("bracketing states in total", mo["neg_all"], 434)
|
||||
check("every exception is an underflowed zero weight",
|
||||
all(any(w == 0.0 for w in ws) for _p, _f, ws in ck["exceptions"]), True)
|
||||
fam = ck["fam"]
|
||||
gap = {k: v[2] - v[3] for k, v in fam.items()}
|
||||
check("total gap on the losing problems", sum(gap.values()), 256)
|
||||
check("total gap on the losing problems", sum(gap.values()), 262)
|
||||
check("flat families' gap", sum(gap[k] for k in ("fun3", "fun4", "fun5", "fun6")), 172)
|
||||
check("fun1 gap", gap["fun1"], 58)
|
||||
for k, want in (("fun3", 92), ("fun4", 96), ("fun5", 100), ("fun6", 100)):
|
||||
@@ -411,11 +409,10 @@ def verify_gap_decomposition():
|
||||
check(f"Chandrupatla bisect share {k} %", round(100.0 * b / (b + q)), want)
|
||||
for k, want in (("fun4", 297), ("fun5", 233), ("fun6", 233)):
|
||||
check(f"Chandrupatla total {k}", fam[k][3], want)
|
||||
check("m>=2 on canonical states %", round(fl["APS (canonical)"][2], 1), 0.2)
|
||||
check("m>=2 on canonical states %", float(round(fl["APS (canonical)"][2], 1)), 0.3)
|
||||
check("m>=2 on flat states %", round(fl["CHA flat fun3-6"][2], 1), 0.0)
|
||||
# the band per family, from the Linux sweep
|
||||
with open("sweep_decision.json", encoding="utf8") as fh:
|
||||
rows = json.load(fh)
|
||||
rows = _load("sweep_decision.json")
|
||||
by = {(r["spec"][1], r["spec"][5], r["spec"][3]): r for r in rows}
|
||||
base = by[("ratio", "none", "project")]["CHA"]["per"]
|
||||
band = by[("ratio", "band", "project")]["CHA"]["per"]
|
||||
@@ -429,11 +426,10 @@ def verify_gap_decomposition():
|
||||
for k, d in (("fun1", 164), ("fun2", 111), ("fun8", 170), ("fun9", 144)):
|
||||
check(f"band cost on {k}", fam_total(band, k) - fam_total(base, k), d)
|
||||
# negative item 11, corrected pairing: the same configuration in x and in log space
|
||||
with open("sweep_full.json", encoding="utf8") as fh:
|
||||
full = json.load(fh)
|
||||
full = _load("sweep_full.json")
|
||||
xcell = next(r for r in full if r["label"] == "pure.ratio_soft.derived.safe")
|
||||
check("log item: x-space control APS", xcell["APS"]["total"], 5822)
|
||||
check("log item: x-space control CHA", xcell["CHA"]["total"], 3695)
|
||||
check("log item: x-space control APS", xcell["APS"]["total"], 5635)
|
||||
check("log item: x-space control CHA", xcell["CHA"]["total"], 2759)
|
||||
|
||||
|
||||
def verify_safeguard_and_tables():
|
||||
@@ -448,51 +444,54 @@ def verify_safeguard_and_tables():
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
bf = measure_budget_factor.main()
|
||||
rm = measure_records_vs_multiplier.main()
|
||||
for c, (aps, cha) in ((1.0, (4817, 2997)), (1.25, (2806, 2752)), (1.5, (2806, 2889)),
|
||||
(2.0, (2806, 3220)), (3.0, (2806, 3756)), (4.0, (2806, 4006))):
|
||||
for c, (aps, cha) in ((1.0, (4625, 2039)), (1.25, (2626, 1822)), (1.5, (2636, 1991)),
|
||||
(2.0, (2634, 2357)), (3.0, (2634, 2936)), (4.0, (2634, 3229))):
|
||||
check(f"multiplier {c} APS", bf[c][0], aps)
|
||||
check(f"multiplier {c} CHA", bf[c][2], cha)
|
||||
for c0, (aps, cha) in ((0.1, (5344, 3051)), (0.5, (4656, 3002)), (1.0, (3568, 3020)),
|
||||
(2.0, (3692, 2712)), (5.0, (3006, 2615))):
|
||||
for c0, (aps, cha) in ((0.1, (5150, 2097)), (0.5, (4462, 2037)), (1.0, (3377, 2073)),
|
||||
(2.0, (3502, 1757)), (5.0, (2819, 1666))):
|
||||
check(f"endowment {c0} APS", bf["endowment"][c0][0], aps)
|
||||
check(f"endowment {c0} CHA", bf["endowment"][c0][1], cha)
|
||||
within_one_step = {c0: sum(v) for c0, v in bf["endowment"].items() if c0 <= 1.0}
|
||||
check("C0=1 cheapest within the one-step promise",
|
||||
min(within_one_step, key=within_one_step.get), 1.0)
|
||||
sh = rm["shape reading (2527)"]
|
||||
check("2527 at multiplier 1.25", sh[1.25][0], 2541)
|
||||
check("2527 flat from 1.5 to 4", {sh[f][0] for f in (1.5, 2.0, 3.0, 4.0)}, {2527})
|
||||
check("shape reading at multiplier 1.25", sh[1.25][0], 2351)
|
||||
check("shape reading flat from 1.5 to 4", {sh[f][0] for f in (1.5, 2.0, 3.0, 4.0)}, {2337})
|
||||
de = rm["defect reading (2523)"]
|
||||
check("2523 flat from 1.25 to 4", {de[f][0] for f in (1.25, 1.5, 2.0, 3.0, 4.0)}, {2523})
|
||||
dv = [de[f][0] for f in (1.25, 1.5, 2.0, 3.0, 4.0)]
|
||||
check("defect reading from 1.25 to 4: range", (min(dv), max(dv)), (2343, 2353))
|
||||
|
||||
print("\nTables 2-3 regenerated:")
|
||||
with open("sweep_full.json", encoding="utf8") as fh:
|
||||
rows = json.load(fh)
|
||||
rows = _load("sweep_full.json")
|
||||
by = {r["label"]: r for r in rows}
|
||||
none_ = "pure.ratio.derived3.none"
|
||||
for setname, lbl, pl in (("APS", PROJ, 3), ("APS", none_, 2), ("CHA", PROJ, 45),
|
||||
("CHA", none_, 228), ("CHA", "pure.exp_abs.bracket.both", 4)):
|
||||
for setname, lbl, pl in (("APS", PROJ, 3), ("APS", none_, 2), ("CHA", PROJ, 49),
|
||||
("CHA", none_, 229), ("CHA", "pure.exp_abs.bracket.both", 3),
|
||||
("CHA", "pure.exp_abs.bracket.bracket", 4),
|
||||
("CHA", "pure.exp_abs.bracket.credit", 6),
|
||||
("APS", CREDIT, 25), ("CHA", CREDIT, 9)):
|
||||
check(f"{setname} {lbl} place", place(rows, setname, lbl), pl)
|
||||
check("CHA exp_abs.bracket.both total", by["pure.exp_abs.bracket.both"]["CHA"]["total"],
|
||||
2736)
|
||||
1778)
|
||||
check("CHA TOMS 748 over the 2x bound", by["toms748"]["CHA"]["over"], 15)
|
||||
check("CHA Brent over the 2x bound", by["brent"]["CHA"]["over"], 18)
|
||||
for lbl, setname, opp, want in (
|
||||
(CREDIT, "APS", "itp_oracle", (86, 6, 61)),
|
||||
(CREDIT, "CHA", "itp_oracle", (2, 2, 36)),
|
||||
(CREDIT, "CHA", "bisection", (5, 0, 35)),
|
||||
(PROJ, "APS", "chandrupatla", (87, 24, 42)),
|
||||
(PROJ, "APS", "itp", (132, 3, 18)),
|
||||
(PROJ, "APS", "itp_oracle", (121, 4, 28)),
|
||||
(PROJ, "APS", "bisection", (152, 1, 0)),
|
||||
(PROJ, "CHA", "toms748", (31, 1, 8)),
|
||||
(PROJ, "CHA", "brent", (30, 4, 4)),
|
||||
(PROJ, "CHA", "itp", (17, 0, 23)),
|
||||
(PROJ, "CHA", "itp_oracle", (16, 0, 24))):
|
||||
(CREDIT, "APS", "itp_oracle", (86, 6, 62)),
|
||||
(CREDIT, "CHA", "itp_oracle", (2, 2, 41)),
|
||||
(CREDIT, "CHA", "bisection", (5, 0, 40)),
|
||||
(PROJ, "APS", "chandrupatla", (87, 24, 43)),
|
||||
(PROJ, "APS", "itp", (132, 3, 19)),
|
||||
(PROJ, "APS", "itp_oracle", (121, 4, 29)),
|
||||
(PROJ, "APS", "bisection", (152, 1, 1)),
|
||||
(PROJ, "CHA", "toms748", (33, 1, 11)),
|
||||
(PROJ, "CHA", "brent", (34, 4, 7)),
|
||||
(PROJ, "CHA", "itp", (18, 1, 26)),
|
||||
(PROJ, "CHA", "itp_oracle", (16, 1, 28))):
|
||||
w, t, l, _ = head_to_head(rows, lbl, opp, setname)
|
||||
check(f"{lbl.split('.')[-1]} {setname} vs {opp}", (w, t, l), want)
|
||||
for lbl, want in ((CREDIT, 6588), (PROJ, 6026), ("chandrupatla", 5228),
|
||||
("itp_oracle", 5907), ("toms748", 6820), ("brent", 7004)):
|
||||
for lbl, want in ((CREDIT, 5450), (PROJ, 4991), ("chandrupatla", 4100),
|
||||
("itp_oracle", 4743), ("toms748", 5724), ("brent", 5945)):
|
||||
check(f"both sets {lbl}", by[lbl]["APS"]["total"] + by[lbl]["CHA"]["total"], want)
|
||||
|
||||
print("\n§7 under the earned projection:")
|
||||
@@ -501,36 +500,35 @@ def verify_safeguard_and_tables():
|
||||
for p in glob.glob("sweep_*.json"):
|
||||
if "smoke" in p:
|
||||
continue
|
||||
with open(p, encoding="utf8") as fh:
|
||||
data = json.load(fh)
|
||||
data = _load(p)
|
||||
# only grid files (a list of labelled cells); the out-of-sample results
|
||||
# (sweep_oos.json, sweep_fourth_*.json, ...) are dicts of a different shape
|
||||
if not isinstance(data, list):
|
||||
continue
|
||||
for r in data:
|
||||
cells.setdefault(r["label"], r)
|
||||
for lbl, aps, cha in (("slope.ratio.derived3.credit", 3507, 2997),
|
||||
("pure+shape+slope.ratio.derived3.credit", 3755, 3021),
|
||||
("pure+dissim+slope.ratio.derived3.credit", 3857, 3002),
|
||||
("pure+shape+dissim+slope.ratio.derived3.credit", 4354, 3037),
|
||||
("defect.ratio.derived3.credit", 3545, 2949)):
|
||||
for lbl, aps, cha in (("slope.ratio.derived3.credit", 3316, 2050),
|
||||
("pure+shape+slope.ratio.derived3.credit", 3564, 2074),
|
||||
("pure+dissim+slope.ratio.derived3.credit", 3666, 2052),
|
||||
("pure+shape+dissim+slope.ratio.derived3.credit", 4163, 2087),
|
||||
("defect.ratio.derived3.credit", 3354, 2002)):
|
||||
check(f"{lbl} APS", cells[lbl]["APS"]["total"], aps)
|
||||
check(f"{lbl} CHA", cells[lbl]["CHA"]["total"], cha)
|
||||
free = [r for r in cells.values() if r.get("spec") and len(r["spec"]) > 3
|
||||
and r["spec"][0] == "pure" and r["spec"][3] == "credit"
|
||||
and r["APS"]["solved"] + r["CHA"]["solved"] == 193]
|
||||
and r["APS"]["solved"] + r["CHA"]["solved"] == r["APS"]["n"] + r["CHA"]["n"]]
|
||||
top = min(free, key=lambda r: r["APS"]["total"] + r["CHA"]["total"])
|
||||
check("best constant-free configuration", top["label"],
|
||||
"defect+flatanalogmempt+exp+half.ratio.derived3.credit")
|
||||
check("its total over both sets", top["APS"]["total"] + top["CHA"]["total"], 6111)
|
||||
check("its total over both sets", top["APS"]["total"] + top["CHA"]["total"], 4965)
|
||||
d = cells["defect.ratio.derived3.credit"]
|
||||
check("defect under the earned projection, both sets",
|
||||
d["APS"]["total"] + d["CHA"]["total"], 6494)
|
||||
d["APS"]["total"] + d["CHA"]["total"], 5356)
|
||||
|
||||
|
||||
PLACEMENT_PER_SET = {
|
||||
"sweep_direction.json": ("CHA", "pure+dissim+slope.ratio.derived3.safe", 2695),
|
||||
"sweep_gate.json": ("CHA", "progress.ratio_soft.derived.safe", 2888),
|
||||
"sweep_direction.json": ("CHA", "pure+dissim+slope.ratio.derived3.safe", 1752),
|
||||
"sweep_gate.json": ("CHA", "progress.ratio_soft.derived.safe", 1929),
|
||||
}
|
||||
|
||||
|
||||
@@ -541,8 +539,7 @@ def verify_placement_modes():
|
||||
print(f" !! {path} absent — the section quoting it cannot be verified")
|
||||
FAILS.append(f"missing {path}")
|
||||
continue
|
||||
with open(path, encoding="utf8") as fh:
|
||||
rows = json.load(fh)
|
||||
rows = _load(path)
|
||||
try:
|
||||
d = next(r for r in rows if r["label"] == lbl)
|
||||
except StopIteration:
|
||||
@@ -551,13 +548,12 @@ def verify_placement_modes():
|
||||
continue
|
||||
check(f"{lbl} APS", d["APS"]["total"], aps)
|
||||
check(f"{lbl} CHA", d["CHA"]["total"], cha)
|
||||
check(f"{lbl} solved", d["APS"]["solved"] + d["CHA"]["solved"], 193)
|
||||
check(f"{lbl} solved", d["APS"]["solved"] + d["CHA"]["solved"], 199)
|
||||
check(f"{lbl} guarantee (over 2x)", d["APS"]["over"] + d["CHA"]["over"], 0)
|
||||
for path, (setname, lbl, want) in PLACEMENT_PER_SET.items():
|
||||
if not os.path.exists(path):
|
||||
continue
|
||||
with open(path, encoding="utf8") as fh:
|
||||
rows = json.load(fh)
|
||||
rows = _load(path)
|
||||
d = next((r for r in rows if r["label"] == lbl), None)
|
||||
if d is None:
|
||||
FAILS.append(f"{lbl} missing from {path}")
|
||||
@@ -566,8 +562,15 @@ def verify_placement_modes():
|
||||
|
||||
|
||||
def _load(path):
|
||||
"""A results file. A row-format protocol sweep (a list of labelled cells) is served from
|
||||
sweep_uniform.json, its re-scoring under the paper's single criterion - a sign change
|
||||
within 1e-6 or f(x) == 0 (revision point 3, 2026-09-22); every other file as stored."""
|
||||
from rescore_uniform import load_uniform
|
||||
with open(path, encoding="utf8") as fh:
|
||||
return json.load(fh)
|
||||
data = json.load(fh)
|
||||
if isinstance(data, list) and data and "spec" in data[0]:
|
||||
return load_uniform(path)
|
||||
return data
|
||||
|
||||
|
||||
def _cell(path, lbl):
|
||||
@@ -591,21 +594,21 @@ def verify_flat_regime_and_oos():
|
||||
print("\nSection 8 and negative items 12-16 (the development grids):")
|
||||
P = "ratio.derived3.project"
|
||||
for path, lbl, aps, cha in (
|
||||
("sweep_flat.json", f"flat.{P}", 3029, 3198),
|
||||
("sweep_flat2.json", f"flat2.{P}", 2803, 3341),
|
||||
("sweep_flatcreep.json", f"flatcreep.{P}", 2878, 3354),
|
||||
("sweep_flatstick.json", f"flatstickmid.{P}", 6897, 3019),
|
||||
("sweep_flatexit.json", f"flatstickexit.{P}", 3125, 2503),
|
||||
("sweep_flatjudge.json", f"flatjudge.{P}", 3009, 2486),
|
||||
("sweep_orderpt.json", f"flatanalogmem.{P}", 2814, None),
|
||||
("sweep_half.json", f"half.{P}", 2564, None)):
|
||||
("sweep_flat.json", f"flat.{P}", 2839, 2243),
|
||||
("sweep_flat2.json", f"flat2.{P}", 2613, 2388),
|
||||
("sweep_flatcreep.json", f"flatcreep.{P}", 2688, 2399),
|
||||
("sweep_flatstick.json", f"flatstickmid.{P}", 6707, 2063),
|
||||
("sweep_flatexit.json", f"flatstickexit.{P}", 2935, 1546),
|
||||
("sweep_flatjudge.json", f"flatjudge.{P}", 2820, 1532),
|
||||
("sweep_orderpt.json", f"flatanalogmem.{P}", 2633, None),
|
||||
("sweep_half.json", f"half.{P}", 2392, None)):
|
||||
r = _cell(path, lbl)
|
||||
check(f"{lbl} APS", r["APS"]["total"], aps)
|
||||
if cha is not None:
|
||||
check(f"{lbl} CHA", r["CHA"]["total"], cha)
|
||||
check(f"{lbl} guarantee", r["APS"]["over"] + r["CHA"]["over"], 0)
|
||||
check("sticky with order from the failed promise, APS",
|
||||
_cell("sweep_flatstick.json", f"flatstick.{P}")["APS"]["total"], 6781)
|
||||
_cell("sweep_flatstick.json", f"flatstick.{P}")["APS"]["total"], 6591)
|
||||
check("sticky midpoint: flat families",
|
||||
_flat_sum(_cell("sweep_flatstick.json", f"flatstickmid.{P}")), 1057)
|
||||
full = {r["label"]: r for r in _load("sweep_full.json")}
|
||||
@@ -617,9 +620,9 @@ def verify_flat_regime_and_oos():
|
||||
check("split from the order: flat families, high end",
|
||||
_flat_sum(op[f"pure+extP+flatanalogpt.{P}"]), 847)
|
||||
check("item 16: remembered + split, with the step pattern, CHA",
|
||||
op[f"pure+extP+flatanalogmempt.{P}"]["CHA"]["total"], 2117)
|
||||
op[f"pure+extP+flatanalogmempt.{P}"]["CHA"]["total"], 1250)
|
||||
check("item 16: one-state analogy + split, with the step pattern, CHA",
|
||||
op[f"pure+extP+flatanalogpt.{P}"]["CHA"]["total"], 2221)
|
||||
op[f"pure+extP+flatanalogpt.{P}"]["CHA"]["total"], 1388)
|
||||
|
||||
print("\nSection 8 diagnostics (fresh runs):")
|
||||
import diag_analogy_decoupled
|
||||
@@ -668,37 +671,37 @@ def verify_flat_regime_and_oos():
|
||||
A = f"pure+extP+{ap}.ratio.derived3"
|
||||
apr = {r["label"]: r for r in rows_ap}
|
||||
a = apr[f"{A}.project"]
|
||||
check("A' APS", a["APS"]["total"], 2438)
|
||||
check("A' CHA", a["CHA"]["total"], 2005)
|
||||
check("A' both", a["APS"]["total"] + a["CHA"]["total"], 4443)
|
||||
check("A' solved", a["APS"]["solved"] + a["CHA"]["solved"], 193)
|
||||
check("A' APS", a["APS"]["total"], 2259)
|
||||
check("A' CHA", a["CHA"]["total"], 1074)
|
||||
check("A' both", a["APS"]["total"] + a["CHA"]["total"], 3333)
|
||||
check("A' solved", a["APS"]["solved"] + a["CHA"]["solved"], 199)
|
||||
c = apr[f"{A}.credit"]
|
||||
check("A' earned budget", (c["APS"]["total"], c["CHA"]["total"]), (3608, 2807))
|
||||
check("A' earned budget", (c["APS"]["total"], c["CHA"]["total"]), (3417, 1852))
|
||||
check("A' under every safeguard: violations",
|
||||
sum(r["APS"]["over"] + r["CHA"]["over"] for lb, r in apr.items() if lb.startswith(A)), 0)
|
||||
check("A' safeguards measured", sum(1 for lb in apr if lb.startswith(A + ".")), 7)
|
||||
both = [r for r in _load("sweep_full.json")] + rows_ap
|
||||
for setname, opp, want in (("APS", "chandrupatla", (103, 20, 30)),
|
||||
("CHA", "chandrupatla", (29, 4, 7)),
|
||||
("APS", "toms748", (127, 6, 20)), ("CHA", "toms748", (38, 2, 0)),
|
||||
("APS", "brent", (118, 17, 18)), ("CHA", "brent", (33, 3, 2)),
|
||||
("APS", "itp_oracle", (126, 7, 20)),
|
||||
("CHA", "itp_oracle", (35, 1, 4))):
|
||||
for setname, opp, want in (("APS", "chandrupatla", (103, 20, 31)),
|
||||
("CHA", "chandrupatla", (31, 4, 10)),
|
||||
("APS", "toms748", (127, 6, 21)), ("CHA", "toms748", (42, 2, 1)),
|
||||
("APS", "brent", (118, 17, 19)), ("CHA", "brent", (39, 3, 3)),
|
||||
("APS", "itp_oracle", (126, 7, 21)),
|
||||
("CHA", "itp_oracle", (35, 1, 9))):
|
||||
w, t, l, _ = head_to_head(both, f"{A}.project", opp, setname)
|
||||
check(f"A' {setname} vs {opp}", (w, t, l), want)
|
||||
|
||||
def sign_p(w, l):
|
||||
k, n = min(w, l), w + l
|
||||
return min(1.0, 2.0 * sum(math.comb(n, i) for i in range(k + 1)) / 2.0 ** n)
|
||||
check("A' APS vs Chandrupatla p (2 digits)", float(f"{sign_p(103, 30):.2g}"), 1.5e-10)
|
||||
check("A' CHA vs Chandrupatla p (1 digit)", float(f"{sign_p(29, 7):.1g}"), 3e-4)
|
||||
check("A' below Chandrupatla, APS %", round(100 * (1 - 2438 / 2787), 1), 12.5)
|
||||
check("A' below Chandrupatla, CHA %", round(100 * (1 - 2005 / 2441), 1), 17.9)
|
||||
check("A' APS vs Chandrupatla p (1 digit)", float(f"{sign_p(103, 31):.1g}"), 3e-10)
|
||||
check("A' CHA vs Chandrupatla p (1 digit)", float(f"{sign_p(31, 10):.1g}"), 0.001)
|
||||
check("A' below Chandrupatla, APS %", round(100 * (1 - 2259 / 2595), 1), 12.9)
|
||||
check("A' below Chandrupatla, CHA %", round(100 * (1 - 1074 / 1505), 1), 28.6)
|
||||
from where_we_lose import per_family
|
||||
af, cf = per_family(a, "CHA"), per_family(full["chandrupatla"], "CHA")
|
||||
check("A' fun9 vs Chandrupatla", (af["fun9"], cf["fun9"]), (65, 55))
|
||||
check("A' ahead on wide-bracket families", sum(af[k] < cf[k] for k in cf), 7)
|
||||
check("A' level on fun7", af["fun7"] == cf["fun7"], True)
|
||||
check("A' fun7 vs Chandrupatla", (af["fun7"], cf["fun7"]), (69, 64))
|
||||
|
||||
print("\nTable 9 (ablation of A' on six corpora, sweep_ablation_all.json):")
|
||||
ab = _load("sweep_ablation_all.json")
|
||||
@@ -802,16 +805,16 @@ def verify_flat_regime_and_oos():
|
||||
(1580, 1382))
|
||||
print("\nModAB (sweep_modab.json, the authors' package):")
|
||||
mb = _load("sweep_modab.json")
|
||||
mp = mb["protocol"]["modab"]
|
||||
check("ModAB protocol APS, CHA, both", (mp["APS"]["total"], mp["CHA"]["total"],
|
||||
mp["APS"]["total"] + mp["CHA"]["total"]),
|
||||
(2914, 2436, 5350))
|
||||
for setname, want in (("APS", (118, 11, 25)), ("CHA", (32, 9, 4))):
|
||||
ms = mb["seen"]["modab"]
|
||||
check("Table 8 ModAB APS, CHA, both",
|
||||
(sum(cost(v) for v in ms["APS"].values()), sum(cost(v) for v in ms["CHA"].values()),
|
||||
sum(cost(v) for s_ in ("APS", "CHA") for v in ms[s_].values())), (2726, 1681, 4407))
|
||||
for setname, want in (("APS", (118, 10, 26)), ("CHA", (34, 4, 7))):
|
||||
am = {p: v for p, v in a[setname]["per"].items()}
|
||||
mm = mp[setname]["per"]
|
||||
mm = ms[setname]
|
||||
w = sum(cost(am[p]) < cost(mm[p]) for p in am)
|
||||
l = sum(cost(am[p]) > cost(mm[p]) for p in am)
|
||||
check(f"A' vs ModAB protocol {setname}", (w, len(am) - w - l, l), want)
|
||||
check(f"Table 8 A' vs ModAB {setname}", (w, len(am) - w - l, l), want)
|
||||
md = dict(mb["seen"]["modab"])
|
||||
md.update(mb["fourth"]["modab"])
|
||||
worst_p = 0.0
|
||||
@@ -843,20 +846,20 @@ def verify_flat_regime_and_oos():
|
||||
print("\nTable 9a and section 7: the similarity in the step (fresh audit run):")
|
||||
aps_ = {r["spec"][1]: r for r in _load("sweep_aprime_s.json")}
|
||||
abs_ = _load("sweep_ablation_s.json")
|
||||
t9a = {"ratio": (4443, 13032), "exp_abs": (4988, 14142), "rational": (5486, 14843),
|
||||
"ratio_soft": (8360, 28500), "sqrt": (12718, 45552), "cbrt": (17207, 63031),
|
||||
"exp_sq": (18410, 67701), "cosine": (18412, 67854), "rat_sq": (18422, 67394)}
|
||||
t9a = {"ratio": (3333, 13032), "exp_abs": (3965, 14142), "rational": (4424, 14843),
|
||||
"ratio_soft": (7249, 28500), "sqrt": (11613, 45552), "cbrt": (16094, 63031),
|
||||
"exp_sq": (17429, 67701), "cosine": (17487, 67854), "rat_sq": (17452, 67394)}
|
||||
for s_, (two, six) in t9a.items():
|
||||
r = aps_[s_]
|
||||
check(f"Table 9a {s_} APS+CHA", r["APS"]["total"] + r["CHA"]["total"], two)
|
||||
check(f"Table 9a {s_} six corpora", sum(tot(abs_[f"S:{s_}"], s) for s in sets), six)
|
||||
check(f"Table 9a {s_} guarantee", r["APS"]["over"] + r["CHA"]["over"]
|
||||
+ sum(v[2] for s in sets for v in abs_[f"S:{s_}"][s].values()), 0)
|
||||
check("nearest other S costs more, protocol %", round(100 * (4988 / 4443 - 1)), 12)
|
||||
check("worst S costs more, protocol %", round(100 * (18422 / 4443 - 1)), 315)
|
||||
check("nearest other S costs more, two sets %", round(100 * (3965 / 3333 - 1)), 19)
|
||||
check("worst S costs more, two sets %", round(100 * (17487 / 3333 - 1)), 425)
|
||||
check("nearest other S costs more, six corpora %", round(100 * (14142 / 13032 - 1)), 9)
|
||||
check("quadratic S: four to five times",
|
||||
(int(18410 / 4443), int(67854 / 13032)), (4, 5))
|
||||
check("quadratic S: five times",
|
||||
(int(17429 / 3333), int(67854 / 13032)), (5, 5))
|
||||
import audit_similarity_places
|
||||
buf = io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
@@ -876,5 +879,129 @@ def verify_flat_regime_and_oos():
|
||||
check(f"sign test p for {w}:{l}", f"{sign_p(w, l):.1g}", printed)
|
||||
|
||||
|
||||
def verify_revision1():
|
||||
"""Revision 1 (2026-09-22): the claims added or restated by the revision - the order
|
||||
of the base step, section 7.3's solved counts, the families as the unit, ITP in Table 10,
|
||||
negative items 5 and 9, and the one canonical problem the multiplier moves. Recomputed."""
|
||||
import contextlib
|
||||
import io
|
||||
import math
|
||||
import re
|
||||
from collections import defaultdict
|
||||
print("\nRevision 1:")
|
||||
import order_high_precision
|
||||
buf = io.StringIO()
|
||||
with contextlib.redirect_stdout(buf):
|
||||
order_high_precision.main()
|
||||
out = buf.getvalue()
|
||||
check("Muller order", re.search(r"Muller order .*: ([\d.]+)", out).group(1), "1.8393")
|
||||
for name in ("cos x - x", "exp(x) - 2", "x^3 - x - 2", "sin x - 1/2"):
|
||||
line = next(ln for ln in out.splitlines() if ln.startswith(name))
|
||||
three = line[14:54].split()
|
||||
check(f"three-point order settles, {name}", three[-2], "1.840")
|
||||
line = next(ln for ln in out.splitlines() if ln.startswith("x^2 - 2"))
|
||||
check("three-point order on x^2 - 2", line[14:54].split()[-1], "2.000")
|
||||
check("two-point order, cos x - x", next(ln for ln in out.splitlines()
|
||||
if ln.startswith("cos x - x"))[54:].split()[-1], "1.618")
|
||||
|
||||
rows = _load("sweep_full.json")
|
||||
by = {r["label"]: r for r in rows}
|
||||
solved = {k: by[k]["APS"]["solved"] + by[k]["CHA"]["solved"]
|
||||
for k in ("chandrupatla", "toms748", "itp", "bisection", "brent", "dekker",
|
||||
"illinois")}
|
||||
check("section 7.3 solved counts", solved, {"chandrupatla": 199, "toms748": 199,
|
||||
"itp": 199, "bisection": 199, "brent": 197,
|
||||
"dekker": 178, "illinois": 177})
|
||||
check("Chandrupatla fewer than the base rule, APS %",
|
||||
round(100 * (by[PROJ]["APS"]["total"] / by["chandrupatla"]["APS"]["total"] - 1), 1), 1.5)
|
||||
none_ = by["pure.ratio.derived3.none"]["CHA"]
|
||||
check("guarantee on CHA: more solved, fewer evaluations",
|
||||
(45 - none_["solved"], round(100 * (1 - by[PROJ]["CHA"]["total"] / none_["total"]))),
|
||||
(6, 30))
|
||||
check("earned costs 28% more on APS",
|
||||
round(100 * (by[CREDIT]["APS"]["total"] / by[PROJ]["APS"]["total"] - 1)), 28)
|
||||
|
||||
def cost(v):
|
||||
return v[0] if v[1] else 200
|
||||
|
||||
def fam_of(pid):
|
||||
return ".".join(pid.split(".")[:2]) if pid.startswith("aps") else pid.split(".")[0]
|
||||
|
||||
def families(a, b, s):
|
||||
ta, tb = defaultdict(int), defaultdict(int)
|
||||
for p in a[s]["per"]:
|
||||
ta[fam_of(p)] += cost(a[s]["per"][p])
|
||||
tb[fam_of(p)] += cost(b[s]["per"][p])
|
||||
w = sum(ta[k] < tb[k] for k in ta)
|
||||
l = sum(ta[k] > tb[k] for k in ta)
|
||||
return w, len(ta) - w - l, l
|
||||
|
||||
def sign_p(w, l):
|
||||
k, n = min(w, l), w + l
|
||||
return min(1.0, 2.0 * sum(math.comb(n, i) for i in range(k + 1)) / 2.0 ** n)
|
||||
ap = {r["label"]: r for r in _load("sweep_aprime.json")}[
|
||||
"pure+extP+contra+flatanalogmempt+exp+half+close+sub.ratio.derived3.project"]
|
||||
ch = by["chandrupatla"]
|
||||
check("base rule vs Chandrupatla by family, APS", families(by[PROJ], ch, "APS"), (6, 1, 8))
|
||||
check("A' vs Chandrupatla by family, APS", families(ap, ch, "APS"), (8, 1, 6))
|
||||
check("A' vs Chandrupatla by family, CHA", families(ap, ch, "CHA"), (7, 0, 2))
|
||||
check("family-level p, APS and CHA (2 digits)",
|
||||
(float(f"{sign_p(8, 6):.2g}"), float(f"{sign_p(7, 2):.2g}")), (0.79, 0.18))
|
||||
|
||||
order = _load("sweep_order.json")
|
||||
cells = {}
|
||||
for r in order:
|
||||
s = r["spec"]
|
||||
if s[2] == "far":
|
||||
cells[(s[1], s[3], s[8] if len(s) > 8 else "none")] = r["APS"]["total"] + r["CHA"]["total"]
|
||||
pairs = [(k[0], k[1]) for k in cells if k[2] == "none" and (k[0], k[1], "order") in cells]
|
||||
check("far-end reading: measured order cheaper in cells",
|
||||
(sum(cells[(s_, g, "order")] < cells[(s_, g, "none")] for s_, g in pairs), len(pairs)),
|
||||
(33, 63))
|
||||
|
||||
cap, dire = _load("sweep_cap.json"), _load("sweep_direction.json")
|
||||
for s, want in (("APS", (3101, 2539)), ("CHA", (1766, 1752))):
|
||||
bc = min(r[s]["total"] for r in cap if r[s]["solved"] == r[s]["n"])
|
||||
bd = min(r[s]["total"] for r in dire if r[s]["solved"] == r[s]["n"] and r["spec"][0] == "pure")
|
||||
check(f"item 9: best capped vs best uncapped, {s}", (bc, bd), want)
|
||||
|
||||
itp = _load("sweep_itp.json")
|
||||
t10 = {"APS": (3767, 3068), "CHA": (1946, 1675), "NEW": (5674, 4707), "RJL": (2161, 1629),
|
||||
"APP": (3245, 2386), "D": (5721, 4832)}
|
||||
for s, want in t10.items():
|
||||
check(f"Table 10 ITP / oracle {s}", (sum(cost(v) for v in itp["itp"][s].values()),
|
||||
sum(cost(v) for v in itp["itp_oracle"][s].values())), want)
|
||||
check("Table 10 ITP / oracle over 855", tuple(sum(cost(v) for s in t10 for v in itp[k][s].values())
|
||||
for k in ("itp", "itp_oracle")), (22514, 18297))
|
||||
check("ITP bound violations over 855", sum(v[2] for k in ("itp", "itp_oracle")
|
||||
for s in t10 for v in itp[k][s].values()), 0)
|
||||
seen, four = _load("sweep_fourth_seen.json"), _load("sweep_fourth_fourth.json")
|
||||
apx = dict(seen["Aprime"])
|
||||
apx.update(four["Aprime"])
|
||||
check("A' ahead of ITP and the oracle on every corpus",
|
||||
all(sum(cost(v) for v in apx[s].values()) < sum(cost(v) for v in itp[k][s].values())
|
||||
for s in t10 for k in ("itp", "itp_oracle")), True)
|
||||
|
||||
from simroot.pure import pure_root
|
||||
from stage12_validation import load, per_problem
|
||||
probs = load()
|
||||
aps = [p for p in probs if p[0] == "APS"]
|
||||
runs = {fac: per_problem(lambda f, a, b, xt, mx, _f=fac: pure_root(
|
||||
f, a, b, xt, mx, similarity="ratio", scale="derived3", guard="project",
|
||||
budget_factor=_f), aps, 200, criterion="sign") for fac in (1.25, 1.5, 2.0)}
|
||||
moved = {p: tuple(runs[f][p][0] for f in (1.25, 1.5, 2.0)) for p in runs[2.0]
|
||||
if len({runs[f][p][0] for f in (1.25, 1.5, 2.0)}) > 1}
|
||||
check("Table 1a: the one canonical problem the multiplier moves", moved,
|
||||
{"aps.13.00": (20, 30, 28)})
|
||||
tot = {}
|
||||
for sc in ("derived3", "derived3_m"):
|
||||
pp = per_problem(lambda f, a, b, xt, mx, _s=sc: pure_root(
|
||||
f, a, b, xt, mx, similarity="ratio", scale=_s, guard="project"), probs, 200,
|
||||
criterion="sign")
|
||||
tot[sc] = sum(v[0] for v in pp.values())
|
||||
check("item 5: phase detector vs base rule, both sets", (tot["derived3_m"], tot["derived3"]),
|
||||
(5336, 4991))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user