From de1f8f726d7c2531d1a94134067ecc4de2b7fbef Mon Sep 17 00:00:00 2001 From: Valeri Sitnikov Date: Mon, 21 Sep 2026 07:48:55 +0100 Subject: [PATCH] The new sections move into the canonical text, article/sim_numerics.md (Valeri's decision): section 7 'Where the similarity is read' with 7.1 per-place similarity, 7.2 the decision place, 7.3 the fun7 scoring artefact, 7.4 the gap decomposition; negative results 8-11 appended so items 1-7 keep their numbers; abstract paragraph; Future work rewritten (the refuted log transform removed); item 6 now says aps.13.00 is a scoring artefact, not a method failure. Translated into the .md's revised names: code 'ratio' = the tent max(0,1-|z|), code 'rational' = the ratio similarity 1/(1+|z|); the proposed method stays the .md's (tent, 3-point, projection). Found on the way: negative item 'log change of variable' compared 3474 with 4516, the total of a DIFFERENT configuration; the honest pair is the same configuration in x, CHA 3643 -> 3474, APS 5822 -> 6940. Fixed in both texts. The gap-decomposition numbers were only traced to saved logs; they are now RECOMPUTED by verify_article.py from fresh runs of the diagnosis scripts (which return their values): 216 checks OK on Linux, 762 tests pass twice. Open, for Valeri: the .md still says the projection's doubling is 'not a tuning constant', which simroot/pure.py (project_credit) refutes and which is why the .tex proposes credit; the .md's Tables 2-3 predate Chandrupatla's own method as a baseline (2785 APS, first place), so its 'parity' abstract is out of date; Brent 2890/4101 in the .md against 2889/4099 in the current sweep. Co-Authored-By: Claude Opus 5 --- article/sim_numerics.md | 126 +++++++++++++++++++++++++++++++++++-- article/sim_numerics.tex | 8 ++- diag_flat_detectable.py | 3 + diag_model_order.py | 6 ++ diag_model_order_checks.py | 3 + verify_article.py | 63 +++++++++++++++++++ 6 files changed, 200 insertions(+), 9 deletions(-) diff --git a/article/sim_numerics.md b/article/sim_numerics.md index 2bf8862..6bf5123 100644 --- a/article/sim_numerics.md +++ b/article/sim_numerics.md @@ -10,6 +10,8 @@ Bisection places the next iterate at the midpoint because it uses no information The derivation fixes the method completely, 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. What results is, explicitly, a Newton step with a three-point divided-difference derivative, clipped to the bracket and projected onto the bisection budget; the similarity function is scaffolding of the derivation and does not appear in the final rule. It carries a proven worst case of twice bisection plus one step and contains no constant calibrated on a problem or on the benchmark. On the 154 problems of Alefeld, Potra and Shi it needs 2806 evaluations of $f$ against 2820 for TOMS 748 — a margin of 0.5%, which is a tie — and 2890 for Brent, whom it beats on 102 problems to 40 head to head. On the 45 problems of Chandrupatla it beats Brent 30 to 4 and TOMS 748 31 to 8, and loses to ITP. The result is parity with methods built on tuned constants, obtained without any. For every data-derived scale, the ranking of the nine similarity functions matches the derived law without exception. +Reading the same similarity in one more place — which three points the local model is built on, selected by the shape of their configuration rather than by recency — lowers the Alefeld–Potra–Shi count to 2527, below every method measured here including Chandrupatla's 2785, with the guarantee intact and still no tuning constant; reading it instead on the choice of far end gives 5511 over both sets, and reading it in the decision to trust the model or halve lowers the canonical count further, to 2523. Where the similarity is read turns out to matter more than which similarity it is. The gap that remains on the wide-bracket set is taken apart on the same evaluations: a third of it is the order of the model — a convex two-point step cannot carry the negative weight of quadratic interpolation — and two thirds is not a model at all but the decision when to give the model up, which Chandrupatla takes by bisecting on up to all of his steps and which no reading measured here takes correctly for ours. + --- ## 1. Introduction @@ -100,7 +102,7 @@ $$x' \;=\; x + \operatorname{sign}(x_\mathrm{far}-x)\cdot\min\!\Bigl(\frac{|f(x) a Newton step with a three-point divided-difference derivative, clipped to the bracket and then projected as in §3.1. The similarity function does not appear in (4): it is scaffolding of the derivation, not machinery of the algorithm. -We state this ourselves rather than leave it to be discovered, because it locates the contribution precisely. It 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 §7; (iv) the measurements. +We state this ourselves rather than leave it to be discovered, because it locates the contribution precisely. It 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 §8; (iv) the measurements. **Algorithm.** Given $[a,b]$ with $f(a)f(b)<0$ and tolerance $\varepsilon_x$: @@ -251,7 +253,110 @@ The mechanism is step *quality*. Reconstructing each method's bracket from the s --- -## 7. Negative results +## 7. Where the similarity is read + +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 proposed 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. + +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. + +1. **Trust before the step.** The step trusts a local slope, so the question of trust is whether that slope has settled: if two consecutive estimates have opposite signs the local model is not established, and the evaluation is spent halving instead. A sign is compared, not a magnitude. +2. **Which points the model uses.** For a linear $f$ the ratio of positions $\xi=(x-u)/(v-u)$ and the ratio of values $\varphi=(f(x)-f(u))/(f(v)-f(u))$ coincide, so $|\varphi-\xi|$ measures how unlike a linear configuration a triple is. Among the declared candidate triples the one minimising it is *selected* — an argmin over what is already in hand, with no threshold. +3. **Which end is far.** Read by dissimilarity instead of distance: the end whose $|f|$ is larger is the one less similar to the target. + +**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 | +|---|---|---|---| +| proposed: tent, 3-point, projection (§3) | 2806 | 3220 | 6026 | +| (1) trust before the step, projection | 2848 | 3074 | 5922 | +| (1)+(2) points chosen by shape, *safe* | **2527** | 3108 | 5635 | +| (1)+(3) far end by dissimilarity, projection | 2726 | **2785** | **5511** | +| (1)+(2)+(3), *safe* | 2884 | 2859 | 5743 | +| Chandrupatla | 2785 | 2423 | 5208 | +| TOMS 748 | 2820 | 4000 | 6820 | +| ITP, per-problem oracle | 3260 | 2611 | 5871 | + +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 2785, and it is obtained with the worst-case guarantee intact and still without a tuning constant. Second, on the two sets together the 5511 of reading (3) passes ITP's oracle (5871) but not Chandrupatla (5208): the remaining gap is entirely on the wide-bracket families, where Chandrupatla needs 2423 against our 2683 (reading (3) under *safe*). + +The readings do not compose. Taken together, (2) and (3) give 2884 and 2859 — worse than either alone. Two selections that are each an improvement interfere, which is a reason to measure composition rather than assume it. + +### 7.1 The similarity function belongs to the place, not to the method + +Everything above varies *where* the similarity is read while keeping one function $S$ for the whole method. That is itself an assumption, and it is measurable. Proposition 1 says that the ratio similarity scaled by the far end is false position; what it does not say is *why* false position stalls. Write $|f|\sim K e^m$ near the current point, $e=|x-r|$. Then the residual ratio against the far end needs no slope at all, + +$$z \;=\; \frac{|f(x)|}{|f(x_\mathrm{far})|} \;=\; \Bigl(\frac{e}{E}\Bigr)^{m}, \qquad\text{so}\qquad z^{1/m} \;=\; \frac{e}{E}, \tag{5}$$ + +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)$ comes from three evaluations already paid for, as in item 5 of §8, 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: + +**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. + +| safeguard | APS, $m=1$ | APS, measured $m$ | CHA, $m=1$ | CHA, measured $m$ | +|---|---|---|---|---| +| both | 4522 | **3675** | 3387 | **3216** | +| bracket | 4606 | **3542** | 3571 | **3303** | +| credit | 5190 | **4686** | 3013 | **2884** | +| projection | 6932 | **6364** | 4794 | **4559** | +| safe | 5987 | **5229** | 4108 | **3923** | +| step | 6435 | **5551** | 4257 | **4022** | +| none | 10676 | **10043** | 8265 | **7794** | + +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 2683 for reading (3) above and 2423 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. + +### 7.2 The decision place + +Three places have now been measured: the step length, the far end, and the points the model is built on. The fourth is the *decision* — whether the local model deserves this evaluation or halving is the better use of it. Chandrupatla's method is strong exactly there: it refuses its model on most steps by the acceptance band $1-\sqrt{1-\xi}<\varphi<\sqrt{\xi}$, with $\xi$ and $\varphi$ the ratios of positions and of values defined above. The rule of §3 has no similarity in this place at all: a sign gate and a projection that repairs *after* the step. + +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|)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. -6. **One problem defeats 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 machine zero at distance up to 0.086 from the root. +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. 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. + +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 2683. 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. + +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. + +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 3643 to 3474 — but the canonical set gets worse, 5822 to 6940, against the 2806 of the proposed rule. An earlier version compared the 3474 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. + --- -## 8. Conclusion +## 9. 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. @@ -279,9 +392,10 @@ This is the same movement as in parameter-free similarity control [6], where mem ### Future work -One weakness has a clear diagnosis and no fix inside this framework. On brackets many orders of magnitude wider than the distance to the root, the search must cross those decades, and an *additive* step of $|f|/|f'|$ is sized by the local slope, which knows nothing about how many decades remain. That is why the cube-root similarity, whose step is a fixed *fraction* of the bracket, beats the proposed rule 2.6-fold on those families, and why ITP keeps its lead on the Chandrupatla set. +The diagnosis of §7.4 leaves one question, and it is narrower than the one this section used to pose. An earlier version proposed a logarithmic change of variable to turn an additive step into a geometric march; that was measured and refuted (§8, item 11), and the step turned out to be a fraction of the bracket already. + +What is open is a decision, not a model. On two thirds of the remaining gap the right move is to halve, and Chandrupatla halves; our guarantee permits a step that is slower than halving, and nothing we have measured tells our step when it is. The condition itself is known exactly — a tangent step on an approach of local order $m$ lands at $e(1-1/m)$ and loses to a halving when $m\ge2$ — so the constant is bisection's $\tfrac12$ and not a choice. What is missing is a reading of $m$ that sees it: the three-point estimator reports $m\ge2$ on 0.2% of canonical states, which is the right silence, and on 5.8% of states of pure powers of order 3 to 19, which is blindness. Two successive residuals of the run itself carry the order more directly than a parabola through three points — on an order-$m$ approach under tangent steps their ratio settles at $(1-1/m)^m$, while at a simple root it goes to zero — and that is the reading we would test next, under the same rule as every other here: pre-registered, with the canonical set as the price it must not charge. -The regime is therefore multiplicative versus additive movement, not one similarity function versus another — a change of the space the method works in, not of a coefficient inside it. The natural instrument is a logarithmic change of variable, $u = \operatorname{sign}(x-c)\log(1+|x-c|/s)$, in which an additive step becomes a geometric march and the exponent that the cube root fixes at $1/3$ by accident disappears as a free quantity. Two conditions decide whether that is a method or another refuted idea: the origin $c$ and unit $s$ must be read from the bracket rather than chosen, and the transform must be the identity to within rounding on narrow brackets, so that the wide-bracket families are not bought at the price of the canonical set. Every attempt reported in §7 failed on exactly that second condition. --- diff --git a/article/sim_numerics.tex b/article/sim_numerics.tex index 025f6e2..fbd09f2 100644 --- a/article/sim_numerics.tex +++ b/article/sim_numerics.tex @@ -852,9 +852,11 @@ 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. \item \textbf{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 is the right diagnosis of the flat families --- CHA -improves from $4516$ to $3474$ --- but the canonical set pays $6940$ against -$2806$. A march needs a \emph{ratio} of distances while an identity on narrow +step multiplicative, which looked like the right diagnosis of the flat families +--- for the same similarity, scale and safeguard CHA improves from $3643$ to +$3474$ --- but the canonical set gets worse, $5822$ to $6940$, against the $2806$ +of the projection variant. An earlier version compared the $3474$ with $4516$, +the total of a different configuration. A march needs a \emph{ratio} of distances while an identity on narrow brackets needs an \emph{absolute} unit, and no parameter-free unit provides both. \item \textbf{The prototype-aggregation form of the method loses.} A richer diff --git a/diag_flat_detectable.py b/diag_flat_detectable.py index 07f505b..16680c2 100644 --- a/diag_flat_detectable.py +++ b/diag_flat_detectable.py @@ -54,12 +54,15 @@ def main(): groups[key] += states(d["f"], a, b, float(d["root"])) print(f"{'group':<18} {'states':>7} {'m > 1':>8} {'m >= 2':>8}") + shares = {} for k in ("APS (canonical)", "CHA other", "CHA flat fun3-6"): ms = groups[k] n = max(len(ms), 1) gt1 = 100.0 * sum(m > 1.0 for m in ms) / n ge2 = 100.0 * sum(m >= 2.0 for m in ms) / n + shares[k] = (len(ms), gt1, ge2) print(f"{k:<18} {len(ms):7d} {gt1:7.1f}% {ge2:7.1f}%") + return shares # for verify_article.py if __name__ == "__main__": diff --git a/diag_model_order.py b/diag_model_order.py index 6e66930..6998ec1 100644 --- a/diag_model_order.py +++ b/diag_model_order.py @@ -108,6 +108,7 @@ def main(): valid = {m: 0 for m in MODELS} states_all = 0 lose = [] + results = {} print(f"{'problem':<8} {'ours':>5} {'CH':>4} {'states':>6} " f"bracket halvings per evaluation: {'ours':>6} {'IQI-rec':>8} {'IQI-brk':>8}") for d in _CHANDRUPATLA_TESTS_DICTS: @@ -178,6 +179,7 @@ def main(): paired[m][1] += 1 states_all += cnt mean = lambda v: (sum(v) / len(v)) if v else float("nan") # noqa: E731 + results[pid] = (n, ch, mean(per["ours"]), mean(per["iqiR"]), mean(per["iqiB"])) print(f"{pid:<8} {n:5d} {ch:4d} {cnt:6d} {'':33} " f"{mean(per['ours']):6.2f} {mean(per['iqiR']):8.2f} {mean(per['iqiB']):8.2f}") @@ -199,6 +201,10 @@ def main(): print("\nPAIRED on states where both are valid: mean (IQI - ours) bracket halvings") for m, (s_, c) in paired.items(): print(f" {m}: {s_ / c if c else float('nan'):+.2f} per evaluation (n={c})") + # returned so verify_article.py can check the paper's numbers against a fresh run + # instead of against a transcription of this printout + return {"per_problem": results, "neg_ok": neg_ok, "neg_all": neg_all, + "lose": lose} if __name__ == "__main__": diff --git a/diag_model_order_checks.py b/diag_model_order_checks.py index 3266a1c..c27adab 100644 --- a/diag_model_order_checks.py +++ b/diag_model_order_checks.py @@ -77,6 +77,9 @@ def main(): print(f" {pid:<8} f = [{', '.join(f'{v:.3e}' for v in fs)}] " f"w = [{', '.join(f'{v:.3e}' for v in w)}] " f"zero weights: {sum(v == 0.0 for v in w)} min|f| {tiny:.1e}") + # for verify_article.py: {family: (bisect, iqi, ours n, ch n, problems)} and the + # number of exceptions, each of which must be a weight that underflowed to zero + return {"fam": dict(fam), "exceptions": exceptions} if __name__ == "__main__": diff --git a/verify_article.py b/verify_article.py index 64a9464..012c5c1 100644 --- a/verify_article.py +++ b/verify_article.py @@ -203,6 +203,7 @@ def main(): verify_placement_modes() verify_per_place() verify_decision_place() + verify_gap_decomposition() print() if FAILS: @@ -356,6 +357,68 @@ def verify_decision_place(): check(f"{mode} refusal rate %", round(100.0 * ref / nfev, 1), want) +def verify_gap_decomposition(): + """Section 7.4 of the .md (sec:widelimit in the .tex): the wide-bracket gap taken + apart on the same evaluations. Every number is RECOMPUTED by running the diagnosis + scripts, not transcribed from their saved printouts.""" + import contextlib + import io + print("\nThe gap decomposition (fresh runs of the diagnosis scripts):") + import diag_flat_detectable + import diag_model_order + import diag_model_order_checks + with contextlib.redirect_stdout(io.StringIO()): + mo = diag_model_order.main() + 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("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")] + check("flat: ours min", round(min(per[p][2] for p in flat), 2), 0.41) + check("flat: ours max", round(max(per[p][2] for p in flat), 2), 0.81) + 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"], 433) + 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()), 262) + check("flat families' gap", sum(gap[k] for k in ("fun3", "fun4", "fun5", "fun6")), 178) + check("fun1 gap", gap["fun1"], 58) + for k, want in (("fun3", 93), ("fun4", 96), ("fun5", 100), ("fun6", 100)): + b, q = fam[k][0], fam[k][1] + check(f"Chandrupatla bisect share {k} %", round(100.0 * b / (b + q)), want) + for k, want in (("fun4", 293), ("fun5", 228), ("fun6", 228)): + 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 flat states %", round(fl["CHA flat fun3-6"][2], 1), 5.8) + # the band per family, from the Linux sweep + with open("sweep_decision.json", encoding="utf8") as fh: + rows = json.load(fh) + 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"] + + def fam_total(per_, k): + return sum(n if ok else 200 for pid, (n, ok) in per_.items() + if pid.split(".")[0] == k) + for k, b0, b1 in (("fun4", 573, 296), ("fun5", 456, 239), ("fun6", 456, 235)): + check(f"band {k} no-gate", fam_total(base, k), b0) + check(f"band {k} with band", fam_total(band, k), b1) + 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) + 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"], 3643) + + PLACEMENT_PER_SET = { "sweep_direction.json": ("CHA", "pure+dissim+slope.ratio.derived3.safe", 2683), "sweep_gate.json": ("CHA", "gate.ratio_soft.derived.safe", 2851),