Valeri's second point measured: the similarity function belongs to the PLACE it is read in, not to the method. False position's three-century stall is a similarity read at order one on an approach of order m: with sigma = |f(far)| the residual ratio is (e/E)^m, so raising it to the measured 1/m recovers the distance ratio exactly. Paired inside each cell, the correction is cheaper in 7 of 7 safeguards for S = 1/(1+z) - the one function that makes that place exact inverse interpolation - and in only 29 of 60 cells over all nine functions, i.e. a coin. It does NOT beat Chandrupatla (2884 against 2683 and 2423), it HARMS the slope reading (2806 -> 2854), and it does not cure false position: 127/154 and 10676 become 128/154 and 10043, where Illinois buys 153/154 and 7045 with one constant. Estimator bias measured and stated: a pure cube reads 2.830, not 3

Also fixes a real regression from cc2c499: the derived3_cap branch was inserted in front of the derived3_m note and swallowed its division, so derived3_m silently became derived3 (2806 against 2806) and a refutation recorded in the paper stopped being reproducible. The full pin caught it; a cheap pin now guards it too. And \label{sec:method} never existed while the table on page 7 referenced it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
vvs
2026-09-21 01:17:25 +01:00
co-authored by Claude Opus 5
parent cc2c499f63
commit 15b94242e0
13 changed files with 756 additions and 11 deletions
+68
View File
@@ -0,0 +1,68 @@
# FINDINGS — функция похожести ПО МЕСТУ (слот 1)
Пред-регистрация: `PREREG_similarity_per_slot_2026-09-21.md`. Сетка: 252 конфигурации × 199 задач,
сервер 161, `sweep_order.json`, лог `results_sweep_order.txt`. Якорь достоверности:
`pure.ratio.derived3` воспроизводит опубликованное **2806** бит-в-бит.
## Вердикты
| # | предсказание | вердикт |
|---|---|---|
| **L1** | показатель улучшает чтение по дальнему концу | **ВЕРНА — но только при соответствующей функции похожести** |
| **L2** | CHA < 2683 | **ЛОЖНА** — лучшее 2884 |
| **L3** | APS не хуже точки отсчёта | **ЛОЖНА в чтении по наклону** — 2806 → 2854 |
| **L4** | гарантия цела | **ВЕРНА** — 0 нарушений из 108 ячеек семейства гарантии |
| **L5** | шаг не выходит за скобку | **ВЕРНА** — закреплено тестом, с документированным насыщением до ровно 1.0 при `z ≳ 1/eps` |
## Главное: место определяет функцию
`far` + `rational` — единственное сочетание, в котором чтение по дальнему концу **есть** точная
обратная интерполяция. Там показатель выигрывает **7 из 7** предохранителей:
| предохранитель | APS none → order | CHA none → order |
|---|---|---|
| both | 4522 → **3675** | 3387 → **3216** |
| bracket | 4606 → **3542** | 3571 → **3303** |
| credit | 5190 → **4686** | 3013 → **2884** |
| project | 6932 → **6364** | 4794 → **4559** |
| safe | 5987 → **5229** | 4108 → **3923** |
| step | 6435 → **5551** | 4257 → **4022** |
| none | 10676 → **10043** | 8265 → **7794** |
По всем девяти функциям похожести — **29 из 60 ячеек**, то есть неотличимо от монеты. Вывод, который
это позволяет сделать: **показатель порядка не универсальное улучшение, а согласование функции
похожести с местом, где она читается.** Там, где функция месту не соответствует, измеренный порядок
не помогает и не мешает систематически.
## Чего НЕ получилось, прямо
1. **Chandrupatla не побит.** 2884 против 2683 (наше лучшее) и 2423 (его). Пятая попытка против
одной и той же измеренной причины.
2. **Стойло false position беспараметрически не вылечено.** Незащищённый: 127/154 и 10676 → 128/154
и 10043 (−6%, +1 задача). Illinois с константой ½: 153/154 и 7045. Показатель снимает шестую
часть разрыва, а не разрыв. ⚠️ Наши 10676 и опубликованные 10560 — **не один алгоритм**: наш
метод стартует из середины скобки, классический false position — с конца.
3. **В чтении по наклону показатель вредит** на APS (2806 → 2854) и теряет задачи на CHA.
## Измеренная граница оценки порядка
Трёхточечная оценка читает **чистый куб как 2.830, а не 3** — смещение −5.7%, направленное к
единице, то есть к неисправленному чтению. Парабола через три точки несёт только вторую разность,
поэтому порядок кубики недооценивается даже в идеальном бесшумном случае. Закреплено тестом
`test_local_order_reads_a_cube_low_by_a_fixed_bias`; в статье должно стоять как смещение, а не как
точность.
## Найденный по ходу баг (не в новом коде)
Коммит `cc2c499` вставил ветку `derived3_cap` прямо перед примечанием `derived3_m` и **проглотил его
делитель**: `derived3_m` молча стал псевдонимом `derived3` (2806 против 2806), и опровержение,
записанное в статью, перестало воспроизводиться. Поймал полный пин
`test_m_loses_on_the_full_benchmark` — ровно то, для чего он и стоит. Исправлено; добавлен дешёвый
пин `test_derived3_m_actually_divides_by_the_order`.
## Что остаётся неисследованным
Слот 2 пред-регистрации: **место решения предохранителя**. Полоса приёма Чандрупатлы
(`1−√(1−ξ) < φ < √ξ`) — это другая функция похожести в другом месте: похожесть конфигурации на
линейную, читаемая не для длины шага, а для выбора «модель или деление». У нас в этом месте похожести
нет вовсе. Гонять отдельной сеткой.
+83
View File
@@ -0,0 +1,83 @@
# PREREG — функция похожести ПО МЕСТУ, а не одна на метод
Составлено до прогона. Основание — два замечания Валерия 2026-09-21, идущие подряд:
1. «просто функция похожести подобрана неверно» — про провал `derived3_cap`;
2. «в принципе функция похожести может быть разной в разных местах… В какой-то статье
упоминалось, что функция похожести может подбираться по домену. В нашем случае это не домен,
а **место параметра**».
## 1. Что было не так в четырёх предыдущих попытках
Все четыре (`cbrt`, логарифм, `derived3_m`, `derived3_cap`) меняли **масштаб** `σ`, оставляя
**одну** функцию `S` на весь метод. Измеренная причина разрыва при этом ни разу не была затронута:
недолёт **линейной модели**, 0.93 против 2.26 половинений на пробу.
## 2. Прочитанное до прогона (корпус экономит замер)
`article/sim_numerics.tex`, Предложение 4: чтение похожести **по концам скобки** с рациональной
похожестью `S = 1/(1+z)` **тождественно false position** — 127/154, 10560 оценок. То есть слот
«масштаб = значение на дальнем конце» **уже закрыт при `m = 1`**. Гипотеза ниже — ровно про то,
почему он закрыт: стойло false position трёхвековой давности есть чтение похожести **на порядке 1**
там, где подход имеет порядок `m`.
## 3. Слот 1 — длина шага: показатель = ИЗМЕРЕННЫЙ порядок
Для `f ≈ K·e^m` (`e = |x − r|`) отношение остатков безразмерно и не требует наклона:
z = |f(x)| / |f(far)| = (e/E)^m ⇒ z^(1/m) = e/E
а доля шага до дальнего конца при обратной интерполяции есть `t/(1+t)`, `t = z^(1/m)`. При `m = 1`
это **в точности false position** (Предложение 4), при `m > 1` — обратная интерполяция **порядка m**,
которая для чистой степени попадает в корень **за один шаг**. Показатель `1/m` **не выбирается**:
`m = 1/(1 − f·f''/f'²)` считается `_local_order` по трём уже сделанным оценкам и равен 1, когда
степенная модель не применима.
**Почему это не повторение `derived3_m`.** Там `m` стоял **делителем масштаба** в чтении по наклону,
где, как доказано в docstring, показатель схлопывается в множитель. Здесь `m` стоит **показателем над
безразмерным отношением**, и схлопывания нет. Плюс структурное свойство: `t/(1+t) < 1` всегда, то
есть шаг **никогда не выходит за скобку** — ложное `m > 1` (27.9% шагов на APS) ограничено дальним
концом, а не проецируется предохранителем.
**Режимы:** новая шкала `scale="far"` (σ = |f| на том конце, к которому шаг) и новый ключ
`exponent="none"|"order"`. По умолчанию `"none"` — опубликованное поведение бит-в-бит.
### Сетка (контроль внутри самой сетки)
Внутри каждой тройки (`S`, шкала, предохранитель) меняется **ровно одно** — показатель. Если
`order` не бьёт `none` в паре `far`+`rational`, гипотеза мертва без толкований.
## 4. Слот 2 — решение предохранителя (объявляется здесь, гоняется ПОСЛЕ слота 1)
Чандрупатла выигрывает не шагом, а **полосой приёма**: `1−√(1−ξ) < φ < √ξ`. В наших терминах это
**другая функция похожести в другом месте** — похожесть конфигурации на линейную (`|φ − ξ|`),
читаемая не для длины шага, а для решения «модель или деление». Сейчас у нас в этом месте похожести
нет вовсе: знаковый гейт и проекция. Гоняется **отдельной сеткой после слота 1**, чтобы не смешать
два изменения.
## 5. Точка отсчёта и цели
| величина | текущее | цель |
|---|---|---|
| APS-154 | 2726 (лучшее 2527) | **≤ 2527** |
| CHA-45 по-наборно | 2683 | **< 2683** (Chandrupatla 2423) |
| два набора | 5511 | **< 5511** |
| решено | 193/199 | ≥ 193 |
| гарантия `over2x` | 0 | **0** |
## 6. Предсказания и фальсификаторы
| # | Предсказание | ФАЛЬСИФИКАТОР → вывод |
|---|---|---|
| **L1** | `exponent="order"` улучшает `far`-чтение против `none` в той же тройке | не улучшает → порядок как показатель над отношением остатков не лечит стойло false position; слот 1 закрыт |
| **L2** | лучшая конфигурация слота 1 даёт CHA < 2683 | не даёт → измеренная причина не устраняется и местом похожести тоже |
| **L3** | APS не хуже 2726 | хуже → снова обмен «широкие за счёт узких», пятый раз |
| **L4** | гарантия цела (`over2x = 0`) | нарушена → немедленное закрытие |
| **L5** | шаг ни разу не выходит за скобку в режиме `far` (проекция предохранителя не срабатывает) | срабатывает → вывод `t/(1+t) < 1` неверно реализован, это баг, а не результат |
**Правило остановки:** L1 ложна ⇒ слот 1 закрывается, слот 2 гоняется всё равно (это другое место).
L1 верна, L2 ложна ⇒ улучшение записывается как есть, без заявки на Chandrupatla. L4 ложна ⇒ стоп.
🔴 **Запрет на подбор:** «своя `S` в каждом месте» не даёт права перебрать меню `S` и объявить
победителя. Показатель в слоте 1 **измеряется** (`_local_order`), а не выбирается. Любой выбор `S`
из списка остаётся тем же изъяном, что жёсткая константа, и отчёт обязан называть его выбором.
+106
View File
@@ -0,0 +1,106 @@
"""Verdicts L1-L5 for PREREG 2026-09-21 slot 1, read off sweep_order.json.
Nothing here selects a winner by hunting: L1 is a PAIRED comparison inside each
(similarity, guard) cell, which is the only comparison the pre-registration licenses.
python -u analyze_order.py
"""
from __future__ import annotations
import json
import math
REF = {"APS_base": 2806, "APS_best": 2527, "CHA_best": 2683, "BOTH_best": 5511,
"falsepos": (127, 10560), "illinois": (153, 7045), "bisect": (153, 7530)}
def load():
with open("sweep_order.json", encoding="utf8") as fh:
return json.load(fh)
def key(r):
s = r["spec"]
return (s[1], s[2], s[3], s[8] if len(s) > 8 else "none")
def main():
res = load()
by = {key(r): r for r in res}
print("L1 PAIRED: does the measured order improve the FAR reading? "
"(the only licensed comparison)")
print(f"{'similarity':<11} {'guard':<9} {'APS none':>9} {'APS ord':>8} "
f"{'CHA none':>9} {'CHA ord':>8} {'solved n/o':>12}")
wins = losses = 0
for (sim, sc, gu, ex) in sorted(by):
if sc != "far" or ex != "none":
continue
a, b = by[(sim, sc, gu, "none")], by.get((sim, sc, gu, "order"))
if b is None:
continue
d = (a["APS"]["total"] + a["CHA"]["total"]) - (b["APS"]["total"] + b["CHA"]["total"])
wins += d > 0
losses += d < 0
print(f"{sim:<11} {gu:<9} {a['APS']['total']:9d} {b['APS']['total']:8d} "
f"{a['CHA']['total']:9d} {b['CHA']['total']:8d} "
f"{a['APS']['solved']}+{a['CHA']['solved']}/"
f"{b['APS']['solved']}+{b['CHA']['solved']:>2}")
print(f" -> order cheaper in {wins} of {wins + losses} far cells\n")
print("L1b same pairing on the DERIVED3 reading")
for (sim, sc, gu, ex) in sorted(by):
if sc != "derived3" or ex != "none" or gu not in ("safe", "project", "none"):
continue
a, b = by[(sim, sc, gu, "none")], by.get((sim, sc, gu, "order"))
if b is None:
continue
print(f"{sim:<11} {gu:<9} {a['APS']['total']:9d} {b['APS']['total']:8d} "
f"{a['CHA']['total']:9d} {b['CHA']['total']:8d} "
f"{a['APS']['solved']}+{a['CHA']['solved']}/"
f"{b['APS']['solved']}+{b['CHA']['solved']:>2}")
print("\nL2/L3 best cells in the grid, by the paper's per-set rule "
"(solved first, then cost)")
for setname, target in (("APS", REF["APS_best"]), ("CHA", REF["CHA_best"])):
rows = sorted(res, key=lambda r: (r[setname]["n"] - r[setname]["solved"],
r[setname]["total"]))
for r in rows[:3]:
s = r["spec"]
print(f" {setname} {r['label']:<38} {r[setname]['solved']}/"
f"{r[setname]['n']} {r[setname]['total']:6d} "
f"over2x={r[setname]['over']} "
f"(target {target}) exponent={s[8] if len(s) > 8 else 'none'}")
print("\nL4 guarantee: cells with over2x > 0 (any set)")
bad = [r["label"] for r in res if r["APS"]["over"] or r["CHA"]["over"]]
print(f" {len(bad)} of {len(res)}" + (f": {bad[:6]}" if bad else " -> intact"))
print("\nFALSE POSITION, unguarded: is the measured order the parameter-free Illinois?")
print(f" {'cell':<34} {'solved':>7} {'APS fev':>9}")
print(f" {'false position (paper)':<34} {REF['falsepos'][0]}/154 "
f"{REF['falsepos'][1]:9d}")
print(f" {'Illinois (constant 1/2)':<34} {REF['illinois'][0]}/154 "
f"{REF['illinois'][1]:9d}")
for ex in ("none", "order"):
r = by.get(("rational", "far", "none", ex))
if r:
print(f" {'far+rational, guard=none, ' + ex:<34} "
f"{r['APS']['solved']}/154 {r['APS']['total']:9d}")
for ex in ("none", "order"):
r = by.get(("rational", "far", "safe", ex))
if r:
print(f" {'far+rational, guard=safe, ' + ex:<34} "
f"{r['APS']['solved']}/154 {r['APS']['total']:9d}")
print("\nBOTH SETS, best order cell against the reference 5511")
rows = [r for r in res if len(r["spec"]) > 8 and r["spec"][8] == "order"]
rows.sort(key=lambda r: (398 - r["APS"]["solved"] - r["CHA"]["solved"],
r["APS"]["total"] + r["CHA"]["total"]))
for r in rows[:3]:
print(f" {r['label']:<38} {r['APS']['solved'] + r['CHA']['solved']}/199 "
f"{r['APS']['total'] + r['CHA']['total']:6d} (reference {REF['BOTH_best']})")
if __name__ == "__main__":
main()
Binary file not shown.
+73
View File
@@ -213,6 +213,7 @@ the evaluations.
\end{corollary} \end{corollary}
\section{The method} \section{The method}
\label{sec:method}
Corollaries~\ref{cor:chosen}--\ref{cor:derived} fix every choice in the method Corollaries~\ref{cor:chosen}--\ref{cor:derived} fix every choice in the method
before any benchmark is consulted. We record them here as a prediction, and before any benchmark is consulted. We record them here as a prediction, and
@@ -563,6 +564,66 @@ 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 $2859$ --- worse than either alone. Two selections that are each an improvement
interfere, which is a reason to measure composition rather than assume it. interfere, which is a reason to measure composition rather than assume it.
\subsection{The similarity function belongs to the place, not to the method}
\label{sec:perplace}
Everything above varies \emph{where} the similarity is read while keeping one
function $S$ for the whole method. That is itself an assumption, and it is
measurable. Proposition~\ref{prop:falsi} says the two-point normalisation is
false position; what it does not say is \emph{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,
\begin{equation}
\label{eq:orderz}
z \;=\; \frac{|f(x)|}{|f(x_{\mathrm{far}})|} \;=\; \Bigl(\frac{e}{E}\Bigr)^{m},
\qquad\text{so}\qquad z^{1/m} \;=\; \frac{e}{E},
\end{equation}
and under $S=1/(1+z)$ the step fraction is $z/(1+z)$, which is exactly inverse
linear interpolation. False position therefore reads a dimensionless ratio
\emph{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, 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 reading it is cheaper in $29$ of
$60$ cells --- indistinguishable from a coin. But in the one pairing where the
far reading \emph{is} exact inverse interpolation, $S=1/(1+z)$, it is cheaper
in all seven safeguards:
\begin{table}[h]
\centering
\begin{tabular}{lrrrr}
\toprule
safeguard & APS $m{=}1$ & APS measured $m$ & CHA $m{=}1$ & CHA measured $m$\\
\midrule
both & 4522 & \textbf{3675} & 3387 & \textbf{3216}\\
bracket & 4606 & \textbf{3542} & 3571 & \textbf{3303}\\
credit & 5190 & \textbf{4686} & 3013 & \textbf{2884}\\
project & 6932 & \textbf{6364} & 4794 & \textbf{4559}\\
safe & 5987 & \textbf{5229} & 4108 & \textbf{3923}\\
step & 6435 & \textbf{5551} & 4257 & \textbf{4022}\\
none & 10676 & \textbf{10043} & 8265 & \textbf{7794}\\
\bottomrule
\end{tabular}
\caption{The measured order in the step place, on the far reading. Cheaper in
$7$ of $7$ safeguards for the similarity that matches the place, and in $29$ of
$60$ cells over all nine functions.}
\end{table}
Two limits must be stated with it. The estimator is \emph{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 bracket
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 \emph{slope} reading 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.
\subsection{Six problems of the two sets are scored unsolved for every method} \subsection{Six problems of the two sets are scored unsolved for every method}
\label{sec:fun7} \label{sec:fun7}
@@ -693,6 +754,18 @@ $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 against $2683$. Its apparent extra solves ($194$ instead of $193$) are two
\texttt{fun7} problems where it lands inside the flat zero region close enough to \texttt{fun7} problems where it lands inside the flat zero region close enough to
satisfy the harness --- the artefact of \S\ref{sec:fun7}, not a capability. satisfy the harness --- the artefact of \S\ref{sec:fun7}, not a capability.
\item \textbf{Reading the similarity at the measured order does not cure false
position.} Since false position's stall is a similarity read at order one
(\S\ref{sec:perplace}), 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 bracket 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. \emph{Our} $10676$ and the $10560$ of Table~\ref{tab:aps} 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.
\item \textbf{A logarithmic change of variable does not buy the wide brackets.} \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 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 step multiplicative, which is the right diagnosis of the flat families --- CHA
+115
View File
@@ -0,0 +1,115 @@
sweep: 252 configurations x 199 problems (FULL)
10/252 done, 0s elapsed
20/252 done, 0s elapsed
/home/valeri/sim-numerics/simroot/pure.py:116: RuntimeWarning: overflow encountered in scalar multiply
"cosine": lambda z: 1.0 / math.sqrt(1.0 + z * z),
30/252 done, 1s elapsed
/home/valeri/sim-numerics/simroot/pure.py:116: RuntimeWarning: overflow encountered in scalar multiply
"cosine": lambda z: 1.0 / math.sqrt(1.0 + z * z),
/home/valeri/sim-numerics/simroot/pure.py:116: RuntimeWarning: overflow encountered in scalar multiply
"cosine": lambda z: 1.0 / math.sqrt(1.0 + z * z),
/home/valeri/sim-numerics/simroot/pure.py:116: RuntimeWarning: overflow encountered in scalar multiply
"cosine": lambda z: 1.0 / math.sqrt(1.0 + z * z),
40/252 done, 1s elapsed
50/252 done, 1s elapsed
60/252 done, 1s elapsed
70/252 done, 2s elapsed
/home/valeri/sim-numerics/simroot/pure.py:115: RuntimeWarning: overflow encountered in scalar multiply
"exp_sq": lambda z: math.exp(-z * z),
80/252 done, 2s elapsed
90/252 done, 2s elapsed
100/252 done, 2s elapsed
110/252 done, 2s elapsed
/home/valeri/sim-numerics/simroot/pure.py:114: RuntimeWarning: overflow encountered in scalar multiply
"rat_sq": lambda z: 1.0 / (1.0 + z * z),
/home/valeri/sim-numerics/simroot/pure.py:114: RuntimeWarning: overflow encountered in scalar multiply
"rat_sq": lambda z: 1.0 / (1.0 + z * z),
120/252 done, 3s elapsed
/home/valeri/sim-numerics/simroot/pure.py:114: RuntimeWarning: overflow encountered in scalar multiply
"rat_sq": lambda z: 1.0 / (1.0 + z * z),
130/252 done, 3s elapsed
140/252 done, 3s elapsed
150/252 done, 3s elapsed
160/252 done, 3s elapsed
/home/valeri/sim-numerics/simroot/pure.py:110: RuntimeWarning: overflow encountered in scalar power
"ratio_soft": lambda z: 1.0 / (1.0 + abs(z)) ** 2,
/home/valeri/sim-numerics/simroot/pure.py:110: RuntimeWarning: overflow encountered in scalar power
"ratio_soft": lambda z: 1.0 / (1.0 + abs(z)) ** 2,
/home/valeri/sim-numerics/simroot/pure.py:110: RuntimeWarning: overflow encountered in scalar power
"ratio_soft": lambda z: 1.0 / (1.0 + abs(z)) ** 2,
/home/valeri/sim-numerics/simroot/pure.py:110: RuntimeWarning: overflow encountered in scalar power
"ratio_soft": lambda z: 1.0 / (1.0 + abs(z)) ** 2,
170/252 done, 4s elapsed
/home/valeri/sim-numerics/simroot/pure.py:110: RuntimeWarning: overflow encountered in scalar power
"ratio_soft": lambda z: 1.0 / (1.0 + abs(z)) ** 2,
/home/valeri/sim-numerics/simroot/pure.py:110: RuntimeWarning: overflow encountered in scalar power
"ratio_soft": lambda z: 1.0 / (1.0 + abs(z)) ** 2,
/home/valeri/sim-numerics/simroot/pure.py:110: RuntimeWarning: overflow encountered in scalar power
"ratio_soft": lambda z: 1.0 / (1.0 + abs(z)) ** 2,
180/252 done, 4s elapsed
190/252 done, 4s elapsed
200/252 done, 4s elapsed
210/252 done, 4s elapsed
220/252 done, 4s elapsed
230/252 done, 4s elapsed
240/252 done, 5s elapsed
250/252 done, 5s elapsed
252/252 done, 5s elapsed
wrote sweep_order.json (5s total)
====================================================================================
APS: 154 problems (top 20 of 252)
====================================================================================
configuration solved total fev over 2x
------------------------------------------------------------------------------------
pure.ratio.derived3.none 153/154 2806 0
pure.ratio.derived3.project 153/154 2806 0
pure+ord.ratio.derived3.none 153/154 2854 0
pure+ord.ratio.derived3.project 153/154 2854 0
pure+ord.ratio.derived3.step 153/154 3000 0
pure+ord.ratio.derived3.safe 153/154 3000 0
pure.ratio.derived3.step 153/154 3036 0
pure.ratio.derived3.safe 153/154 3036 0
pure+ord.exp_abs.derived3.project 153/154 3227 0
pure+ord.exp_abs.derived3.none 153/154 3227 0
pure.exp_abs.derived3.none 153/154 3264 0
pure.exp_abs.derived3.project 153/154 3264 0
pure+ord.exp_abs.derived3.step 153/154 3308 0
pure+ord.exp_abs.derived3.safe 153/154 3308 0
pure.exp_abs.derived3.step 153/154 3312 0
pure.exp_abs.derived3.safe 153/154 3312 0
pure.rational.derived3.none 153/154 3356 0
pure.rational.derived3.project 153/154 3356 0
pure.rational.derived3.step 153/154 3420 0
pure.rational.derived3.safe 153/154 3420 0
====================================================================================
CHA: 45 problems (top 20 of 252)
====================================================================================
configuration solved total fev over 2x
------------------------------------------------------------------------------------
pure.sqrt.far.project 41/45 4516 0
pure+ord.rational.far.credit 40/45 2884 0
pure+ord.ratio.derived3.credit 40/45 2994 0
pure.rational.far.credit 40/45 3013 0
pure.cbrt.derived3.credit 40/45 3016 0
pure.ratio.derived3.credit 40/45 3020 0
pure+ord.cbrt.derived3.credit 40/45 3029 0
pure.exp_abs.far.credit 40/45 3034 0
pure+ord.exp_abs.far.credit 40/45 3035 0
pure+ord.ratio_soft.derived3.credit 40/45 3039 0
pure.exp_abs.derived3.credit 40/45 3049 0
pure.ratio_soft.derived3.credit 40/45 3054 0
pure+ord.exp_abs.derived3.credit 40/45 3067 0
pure.sqrt.far.credit 40/45 3094 0
pure+ord.sqrt.far.credit 40/45 3096 0
pure.ratio.far.credit 40/45 3113 0
pure.cbrt.far.credit 40/45 3127 0
pure+ord.rat_sq.far.credit 40/45 3128 0
pure.rat_sq.far.credit 40/45 3129 0
pure+ord.cbrt.far.credit 40/45 3130 0
====================================================================================
THE STAGE-0C LAW ACROSS THE GRID
====================================================================================
scale=derived3 slope c=1 (linear) mean total 6910 mean solved 192.2/199
scale=derived3 slope c=0 (quadratic) mean total 22334 mean solved 192.8/199
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
# Frozen runner for PREREG 2026-09-21 slot 1 (the similarity read BY PLACE).
# Frozen on purpose: editing a .sh while it runs has broken a run before.
cd "$HOME/sim-numerics" || exit 1
exec ~/torchenv/bin/python -u sweep_full.py --order
+64 -7
View File
@@ -124,6 +124,38 @@ SPACES = ("x", "log")
POINT_RULES = ("recent", "shape") POINT_RULES = ("recent", "shape")
DIRECTIONS = ("distance", "dissimilar") DIRECTIONS = ("distance", "dissimilar")
EXPONENTS = ("none", "order")
def _read_z(resid, sc, exponent, m):
"""The normalised residual the similarity function is applied to.
Valeri, 2026-09-21: "the similarity function may simply be the wrong one", and then
"the similarity function can differ in different PLACES - not by domain, by the place
of the parameter". This is the step-length place, and here the reading is fixed by
what f looks like locally rather than chosen.
For |f| ~ K.e^m the residual ratio against the far end is dimensionless and needs no
slope at all: z = |f(x)|/|f(far)| = (e/E)^m, so z^(1/m) = e/E recovers the DISTANCE
ratio exactly. Under S = 1/(1+z) the step fraction is z/(1+z), which at m = 1 is
false position (Proposition 4 in the paper: 127/154, 10560 evaluations) - and false
position's three-century-old stall is precisely a similarity read at order 1 on an
order-m approach. Reading it at the MEASURED order turns the same formula into
order-m inverse interpolation, exact in one step for a pure power.
m comes from _local_order, i.e. from three evaluations already paid for, and is 1
whenever the power model does not apply, so nothing here is selected.
"""
z = resid / sc
if exponent == "order" and m is not None and m > 1.0 and z > 0.0:
try:
z = z ** (1.0 / m)
except (OverflowError, ValueError):
return resid / sc
if not math.isfinite(z):
return resid / sc
return z
def _shape_defect(x, fx, u, fu, v, fv): def _shape_defect(x, fx, u, fu, v, fv):
"""|phi - xi| for the triple, or None when it is degenerate. """|phi - xi| for the triple, or None when it is degenerate.
@@ -455,7 +487,7 @@ def _local_order(x2, f2, x1, f1, x0, f0):
def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived", def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
guard="step", stats=None, budget_factor=2.0, guard="step", stats=None, budget_factor=2.0,
budget_extra=None, endowment=1.0, space="x", prestep="none", budget_extra=None, endowment=1.0, space="x", prestep="none",
points="recent", direction="distance"): points="recent", direction="distance", exponent="none"):
"""The pure similarity root finder. """The pure similarity root finder.
similarity : key into PURE_SIMS similarity : key into PURE_SIMS
@@ -505,8 +537,16 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
if similarity not in PURE_SIMS: if similarity not in PURE_SIMS:
raise ValueError(f"unknown similarity {similarity!r}") raise ValueError(f"unknown similarity {similarity!r}")
if scale not in ("derived", "derived3", "derived_rho", "derived3_rho", if scale not in ("derived", "derived3", "derived_rho", "derived3_rho",
"derived3_m", "derived3_cap", "start", "bracket"): "derived3_m", "derived3_cap", "start", "bracket", "far"):
raise ValueError(f"unknown scale {scale!r}") raise ValueError(f"unknown scale {scale!r}")
if exponent not in EXPONENTS:
raise ValueError(f"unknown exponent {exponent!r}")
if exponent == "order" and scale not in ("derived3", "derived3_cap", "bracket", "far"):
# the order is read from a three-point divided difference; under the two-point
# scale there is no second difference to read it from, and computing one from
# elsewhere would hide that (PREREG 2026-09-21, slot 1)
raise ValueError("exponent='order' requires scale in "
"{'derived3', 'derived3_cap', 'bracket', 'far'}")
if space not in SPACES: if space not in SPACES:
raise ValueError(f"unknown space {space!r}") raise ValueError(f"unknown space {space!r}")
if prestep not in ("none", "progress", "slope"): if prestep not in ("none", "progress", "slope"):
@@ -604,6 +644,11 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
else: else:
slope = _slope3(x, fx, x_prev, f_prev, x_prev2, f_prev2) slope = _slope3(x, fx, x_prev, f_prev, x_prev2, f_prev2)
sc = abs(slope) * abs(far - x) sc = abs(slope) * abs(far - x)
if scale == "derived3_m":
# REFUTED as an improvement; kept so the refutation stays
# REPRODUCIBLE, which is the whole point of keeping it. The long
# note is at the end of the derived3_cap branch below.
sc /= _local_order(x, fx, x_prev, f_prev, x_prev2, f_prev2)
elif scale == "derived3_cap": elif scale == "derived3_cap":
# Valeri, 2026-09-21: "if the similarity formed the step, the step would be # Valeri, 2026-09-21: "if the similarity formed the step, the step would be
# large far from the target and small near it". It does not, and the reason # large far from the target and small near it". It does not, and the reason
@@ -617,7 +662,12 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
# order) returns. A min over what is in hand - no constant, no threshold. # order) returns. A min over what is in hand - no constant, no threshold.
slope = _slope3(x, fx, x_prev, f_prev, x_prev2, f_prev2) slope = _slope3(x, fx, x_prev, f_prev, x_prev2, f_prev2)
sc = min(abs(slope) * abs(far - x), max(abs(FA), abs(FB))) sc = min(abs(slope) * abs(far - x), max(abs(FA), abs(FB)))
if scale == "derived3_m": # NOTE on scale="derived3_m" (the live code is in the derived3 branch
# above). On 2026-09-21 the derived3_cap branch was inserted directly
# in front of this note and swallowed the division with it, so
# derived3_m silently became derived3 - 2806 against 2806 - and the
# refutation stopped being reproducible. test_m_loses_on_the_full
# _benchmark caught it, which is what that pin is for.
# REFUTED as an improvement - kept for reproducibility. # REFUTED as an improvement - kept for reproducibility.
# The DERIVATION holds: dropping the linearity # The DERIVATION holds: dropping the linearity
# assumption from the contraction law does produce the # assumption from the contraction law does produce the
@@ -646,10 +696,14 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
# rho it is read from the CURVATURE, which stays # rho it is read from the CURVATURE, which stays
# meaningful as |f| goes to zero, and it returns to 1 # meaningful as |f| goes to zero, and it returns to 1
# at a simple root, leaving the endgame untouched. # at a simple root, leaving the endgame untouched.
sc /= _local_order(x, fx, x_prev, f_prev,
x_prev2, f_prev2)
elif scale == "start": elif scale == "start":
sc = start_scale sc = start_scale
elif scale == "far":
# the value at the end the step AIMS AT, already computed. With
# S = 1/(1+z) this is false position exactly (Proposition 4), which
# is why it is the honest control for the order exponent: the pair
# (far, none) against (far, order) differs in one thing only.
sc = abs(FB) if far == B else abs(FA)
else: else:
sc = max(abs(FA), abs(FB)) sc = max(abs(FA), abs(FB))
if scale.endswith("_rho"): if scale.endswith("_rho"):
@@ -696,6 +750,9 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
if sc == 0.0 or not math.isfinite(sc): if sc == 0.0 or not math.isfinite(sc):
x_new = 0.5 * (A + B) x_new = 0.5 * (A + B)
else: else:
m_loc = (_local_order(x, fx, x_prev, f_prev, x_prev2, f_prev2)
if exponent == "order" else None)
z_now = _read_z(abs(fx), sc, exponent, m_loc)
step = None step = None
if prestep == "slope": if prestep == "slope":
# PRE-STEP GATE ON SHAPE (PREREG 2026-09-21). The step trusts the # PRE-STEP GATE ON SHAPE (PREREG 2026-09-21). The step trusts the
@@ -720,7 +777,7 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
# less than bisection would remove, spend the same single # less than bisection would remove, spend the same single
# evaluation on the midpoint instead. Two lengths already in hand # evaluation on the midpoint instead. Two lengths already in hand
# are compared; there is no threshold and no new constant. # are compared; there is no threshold and no new constant.
cand = (1.0 - S(abs(fx) / sc)) * (far - x) cand = (1.0 - S(z_now)) * (far - x)
half = 0.5 * (A + B) - x half = 0.5 * (A + B) - x
if abs(cand) < abs(half): if abs(cand) < abs(half):
step = half step = half
@@ -734,7 +791,7 @@ def pure_root(f, a, b, xtol, maxfev, similarity="ratio", scale="derived",
c_near = A if abs(FA) <= abs(FB) else B c_near = A if abs(FA) <= abs(FB) else B
step = _log_space_step(S, x, fx, far, slope, c_near, xtol) step = _log_space_step(S, x, fx, far, slope, c_near, xtol)
if step is None: if step is None:
step = (1.0 - S(abs(fx) / sc)) * (far - x) step = (1.0 - S(z_now)) * (far - x)
if sg.reject_step(step): if sg.reject_step(step):
x_new = 0.5 * (A + B) x_new = 0.5 * (A + B)
step = x_new - x step = x_new - x
+42 -4
View File
@@ -113,11 +113,12 @@ def make_method(spec):
prestep = spec[5] if len(spec) > 5 else "none" prestep = spec[5] if len(spec) > 5 else "none"
points = spec[6] if len(spec) > 6 else "recent" points = spec[6] if len(spec) > 6 else "recent"
direction = spec[7] if len(spec) > 7 else "distance" direction = spec[7] if len(spec) > 7 else "distance"
exponent = spec[8] if len(spec) > 8 else "none"
def m(f, a, b, xtol, maxfev): def m(f, a, b, xtol, maxfev):
return pure_root(f, a, b, xtol, maxfev, similarity=sim, return pure_root(f, a, b, xtol, maxfev, similarity=sim,
scale=scale, guard=guard, space=space, prestep=prestep, scale=scale, guard=guard, space=space, prestep=prestep,
points=points, direction=direction) points=points, direction=direction, exponent=exponent)
return m return m
@@ -131,6 +132,11 @@ def label(spec):
tag = f"{tag}+shape" tag = f"{tag}+shape"
if len(spec) > 7 and spec[7] != "distance": if len(spec) > 7 and spec[7] != "distance":
tag = f"{tag}+dissim" tag = f"{tag}+dissim"
if len(spec) > 8 and spec[8] != "none":
# the exponent must be visible in the label: (far, none) is false position and
# (far, order) is the hypothesis, and a results file that cannot tell them apart
# is worthless
tag = f"{tag}+ord"
if len(spec) > 5 and spec[5] != "none": if len(spec) > 5 and spec[5] != "none":
# name the gate by WHICH gate it is: "progress" is a measured negative and must # name the gate by WHICH gate it is: "progress" is a measured negative and must
# never be confused with "slope" in a results file # never be confused with "slope" in a results file
@@ -198,6 +204,35 @@ def build_grid_log(smoke):
for sim in sims for sc in ("derived", "derived3") for gu in guards] for sim in sims for sc in ("derived", "derived3") for gu in guards]
def _preflight_order_mode():
"""Fail LOUDLY if the per-place reading is not actually deployed.
Same lesson as _preflight_log_mode: `evaluate` swallows every exception and charges
MAXFEV, so a stale simroot/pure.py on the server reports a sweep of zeros instead of
an error. Checks BOTH new things — the far scale and the order exponent."""
for sc, ex in (("far", "none"), ("far", "order"), ("derived3", "order")):
x, _n, ok = pure_root(lambda t: t - 1.0, 0.0, 3.0, 1e-10, 100,
similarity="rational", scale=sc, guard="credit",
exponent=ex)
if not (ok and abs(x - 1.0) < 1e-8):
raise SystemExit(f"order-mode preflight FAILED for scale={sc} exponent={ex}: "
"refusing to run a sweep that would report zeros")
def build_grid_order(smoke):
"""Slot 1 of PREREG 2026-09-21: the similarity function read BY PLACE.
The exponent is the only thing that moves inside each (similarity, scale, guard)
triple, so (far, none) — which is false position exactly, Proposition 4 — is the
control for (far, order). Baselines are not recomputed; they are in sweep_full.json."""
_preflight_order_mode()
sims = ["rational", "ratio"] if smoke else sorted(PURE_SIMS)
guards = ("credit", "safe") if smoke else GUARD_MODES
return [("pure", sim, sc, gu, "x", "none", "recent", "distance", ex)
for sim in sims for sc in ("far", "derived3")
for ex in ("none", "order") for gu in guards]
def build_grid_cap(smoke): def build_grid_cap(smoke):
"""Scale as a SELECTION between the two computed ones (PREREG 2026-09-21): identical to """Scale as a SELECTION between the two computed ones (PREREG 2026-09-21): identical to
the slope+dissimilar configuration except scale = derived3_cap, so one thing changes.""" the slope+dissimilar configuration except scale = derived3_cap, so one thing changes."""
@@ -274,10 +309,12 @@ def main():
gatemode = "--gate" in sys.argv # the pre-step gate grid, likewise gatemode = "--gate" in sys.argv # the pre-step gate grid, likewise
slopemode = "--slope" in sys.argv # the slope-stability gate grid slopemode = "--slope" in sys.argv # the slope-stability gate grid
capmode = "--cap" in sys.argv # scale selected between the two computed ones capmode = "--cap" in sys.argv # scale selected between the two computed ones
ordermode = "--order" in sys.argv # slot 1: the similarity read BY PLACE
combomode = "--combo" in sys.argv # modes A and B together combomode = "--combo" in sys.argv # modes A and B together
pointsmode = "--points" in sys.argv # mode A: triple by shape pointsmode = "--points" in sys.argv # mode A: triple by shape
dirmode = "--direction" in sys.argv # mode B: far end by dissimilarity dirmode = "--direction" in sys.argv # mode B: far end by dissimilarity
specs = (build_grid_cap(smoke) if capmode else specs = (build_grid_order(smoke) if ordermode else
build_grid_cap(smoke) if capmode else
build_grid_combo(smoke) if combomode else build_grid_combo(smoke) if combomode else
build_grid_points(smoke) if pointsmode else build_grid_points(smoke) if pointsmode else
build_grid_direction(smoke) if dirmode else build_grid_direction(smoke) if dirmode else
@@ -299,8 +336,9 @@ def main():
# the published sweep_full.json is what verify_article.py checks the paper # the published sweep_full.json is what verify_article.py checks the paper
# against, so the log grid never writes into it # against, so the log grid never writes into it
if capmode or combomode or pointsmode or dirmode: if ordermode or capmode or combomode or pointsmode or dirmode:
base = ("sweep_cap" if capmode else base = ("sweep_order" if ordermode else
"sweep_cap" if capmode else
"sweep_combo" if combomode else "sweep_combo" if combomode else
"sweep_points" if pointsmode else "sweep_direction") "sweep_points" if pointsmode else "sweep_direction")
out = f"{base}_smoke.json" if smoke else f"{base}.json" out = f"{base}_smoke.json" if smoke else f"{base}.json"
+1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+127
View File
@@ -0,0 +1,127 @@
"""Pins for PREREG 2026-09-21 slot 1: the similarity function read BY PLACE.
Every claim the mode rests on is pinned here, including the ones that make it falsifiable:
the default must stay bit-for-bit published, the far reading must BE false position, and
the order exponent must invert the power law exactly.
"""
from __future__ import annotations
import math
import pytest
from simroot.pure import PURE_SIMS, _local_order, _read_z, pure_root
PROBS = (
(lambda t: t ** 3 - 2.0 * t - 5.0, 1.0, 4.0),
(lambda t: math.exp(t) - 2.0, 0.0, 3.0),
(lambda t: (t - 1.0) ** 3, 0.0, 10.0),
(lambda t: math.sin(t) - 0.5, 0.0, 1.5),
)
@pytest.mark.parametrize("f,a,b", PROBS)
@pytest.mark.parametrize("guard", ("safe", "credit", "project"))
def test_default_is_bit_for_bit_the_published_method(f, a, b, guard):
"""R1: the new parameter must not touch the published grid when left alone."""
ref = pure_root(f, a, b, 1e-12, 200, similarity="ratio", scale="derived3", guard=guard)
new = pure_root(f, a, b, 1e-12, 200, similarity="ratio", scale="derived3", guard=guard,
exponent="none")
assert ref == new
def test_far_reading_with_rational_is_false_position():
"""R2: Proposition 4 must hold in the CODE, not only in the paper.
The first similarity step from x with S = 1/(1+z), z = |f(x)|/|f(far)| must land on the
secant root of the pair (x, far). If it does not, the (far, none) cell is not the
control the pre-registration claims it is.
"""
f = lambda t: t ** 3 - 2.0 * t - 5.0 # noqa: E731
a, b = 1.0, 4.0
x = 0.5 * (a + b)
# the far end must be the one whose sign differs, otherwise there is no secant root
# between the pair at all; on this bracket that is a, not b
far, fx = a, f(x)
ffar = f(far)
assert fx * ffar < 0.0
z = abs(fx) / abs(ffar)
step = (1.0 - PURE_SIMS["rational"](z)) * (far - x)
secant = x - fx * (far - x) / (ffar - fx)
assert step == pytest.approx(secant - x, rel=1e-12)
def test_order_exponent_inverts_the_power_law_exactly():
"""R3: the whole derivation is z^(1/m) = e/E. Pinned as an identity."""
for m in (1.0, 2.0, 3.0, 7.0):
for e, big in ((0.1, 2.0), (1.0, 5.0), (1e-3, 1.0)):
z = (e / big) ** m
got = _read_z(z, 1.0, "order", m)
assert got == pytest.approx(e / big, rel=1e-9)
def test_order_exponent_is_inert_at_order_one():
"""A simple root must leave the reading untouched, or the endgame is not preserved."""
for z in (1e-9, 0.3, 1.0, 12.0):
assert _read_z(z, 1.0, "order", 1.0) == z
assert _read_z(z, 1.0, "order", None) == z
assert _read_z(z, 1.0, "none", 5.0) == z
def test_local_order_reads_a_cube_low_by_a_fixed_bias():
"""MEASURED, and pinned as measured: on a pure cube the three-point estimator returns
2.830, not 3. The parabola through three points carries only the second difference, so
a cubic's order is under-read by 5.7% even in the ideal noiseless case. The bias is
towards 1, i.e. towards the uncorrected reading, which is the safe direction — but it
is a bias and the paper must say so rather than claim the estimator is exact."""
f = lambda t: t ** 3 # noqa: E731
xs = (0.30, 0.31, 0.32)
m = _local_order(xs[2], f(xs[2]), xs[1], f(xs[1]), xs[0], f(xs[0]))
assert m == pytest.approx(2.83, rel=0.02)
assert 1.0 < m < 3.0
def test_step_fraction_can_never_leave_the_bracket():
"""L5: under S = 1/(1+z) the fraction z/(1+z) is at most 1, so the step never passes
the far end. At z >= 1/eps it SATURATES at exactly 1 in floating point — the step
lands ON the end, which the loop already turns into a bisection because x_new must be
strictly inside. Pinned so the saturation is a documented boundary, not a surprise."""
for z in (0.0, 1e-12, 1.0, 1e6):
assert 0.0 <= 1.0 - PURE_SIMS["rational"](z) < 1.0
assert 1.0 - PURE_SIMS["rational"](1e300) == 1.0
@pytest.mark.parametrize("f,a,b", PROBS)
def test_far_and_order_still_solve_and_stay_in_the_bracket(f, a, b):
ok_any = False
for ex in ("none", "order"):
x, n, conv = pure_root(f, a, b, 1e-10, 300, similarity="rational", scale="far",
guard="safe", exponent=ex)
assert min(a, b) <= x <= max(a, b)
assert n <= 300
ok_any = ok_any or conv
assert ok_any
def test_derived3_m_actually_divides_by_the_order():
"""REGRESSION, 2026-09-21. The derived3_cap branch was inserted in front of the
derived3_m note and swallowed its division, so derived3_m became a silent alias of
derived3 (2806 against 2806) and a refutation recorded in the paper stopped being
reproducible. One cheap problem where the order is genuinely above 1 is enough to
catch it, so the guard does not depend on the full 154-problem pin."""
f = lambda t: (t - 1.0) ** 3 # noqa: E731
plain = pure_root(f, 0.0, 10.0, 1e-10, 300, similarity="ratio", scale="derived3",
guard="project")
with_m = pure_root(f, 0.0, 10.0, 1e-10, 300, similarity="ratio", scale="derived3_m",
guard="project")
assert plain != with_m
def test_bad_combinations_are_refused_not_silently_reinterpreted():
with pytest.raises(ValueError):
pure_root(lambda t: t, 0.0, 1.0, 1e-9, 50, exponent="cube")
with pytest.raises(ValueError):
# two-point scale has no second difference to read the order from
pure_root(lambda t: t, 0.0, 1.0, 1e-9, 50, scale="derived", exponent="order")
with pytest.raises(ValueError):
pure_root(lambda t: t, 0.0, 1.0, 1e-9, 50, scale="nonesuch")
+71
View File
@@ -201,6 +201,7 @@ def main():
check(f"scale {sc} best", best_by_scale[sc], v) check(f"scale {sc} best", best_by_scale[sc], v)
verify_placement_modes() verify_placement_modes()
verify_per_place()
print() print()
if FAILS: if FAILS:
@@ -226,6 +227,76 @@ PLACEMENT = {
"sweep_gate.json": ("gate.ratio.derived.project", 4449, 2991), "sweep_gate.json": ("gate.ratio.derived.project", 4449, 2991),
"sweep_log.json": ("log.ratio_soft.derived.safe", 6940, 3474), "sweep_log.json": ("log.ratio_soft.derived.safe", 6940, 3474),
} }
# 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, 3387, 3216),
"bracket": (4606, 3542, 3571, 3303),
"credit": (5190, 4686, 3013, 2884),
"project": (6932, 6364, 4794, 4559),
"safe": (5987, 5229, 4108, 3923),
"step": (6435, 5551, 4257, 4022),
"none": (10676, 10043, 8265, 7794),
}
# the negative item: the order does not cure false position
ORDER_FALSEPOS = {("rational", "far", "none", "none"): (127, 10676),
("rational", "far", "none", "order"): (128, 10043)}
# and the harmful direction, quoted in the same subsection
ORDER_SLOPE_HARM = {("ratio", "derived3", "none", "none"): 2806,
("ratio", "derived3", "none", "order"): 2854}
def verify_per_place():
print("\nThe per-place reading (sweep_order.json):")
if not os.path.exists("sweep_order.json"):
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)
def cell(sim, sc, gu, ex):
for r in rows:
s = r["spec"]
if (s[1], s[2], s[3], s[8] if len(s) > 8 else "none") == (sim, sc, gu, ex):
return r
return None
cheaper = 0
for gu, (a1, a2, c1, c2) in ORDER_PAIRS.items():
p = cell("rational", "far", gu, "none")
q = cell("rational", "far", gu, "order")
if p is None or q is None:
FAILS.append(f"order pair {gu} missing from sweep_order.json")
print(f" !! pair {gu} missing — stale sweep")
continue
check(f"far+rational {gu} APS m=1", p["APS"]["total"], a1)
check(f"far+rational {gu} APS order", q["APS"]["total"], a2)
check(f"far+rational {gu} CHA m=1", p["CHA"]["total"], c1)
check(f"far+rational {gu} CHA order", q["CHA"]["total"], c2)
cheaper += (q["APS"]["total"] + q["CHA"]["total"]
< p["APS"]["total"] + p["CHA"]["total"])
check("cheaper in 7 of 7 safeguards", cheaper, 7)
for (sim, sc, gu, ex), (solved, total) in ORDER_FALSEPOS.items():
r = cell(sim, sc, gu, ex)
if r is None:
FAILS.append(f"false-position cell {ex} missing")
continue
check(f"false position {ex} solved", r["APS"]["solved"], solved)
check(f"false position {ex} APS", r["APS"]["total"], total)
for (sim, sc, gu, ex), want in ORDER_SLOPE_HARM.items():
r = cell(sim, sc, gu, ex)
if r is None:
FAILS.append(f"slope-harm cell {ex} missing")
continue
check(f"slope reading {ex} APS", r["APS"]["total"], want)
fam = [r for r in rows if r["spec"][3] in ("project", "safe", "credit")]
check("guarantee family violations", sum(r["APS"]["over"] + r["CHA"]["over"]
for r in fam), 0)
PLACEMENT_PER_SET = { PLACEMENT_PER_SET = {
"sweep_direction.json": ("CHA", "pure+dissim+slope.ratio.derived3.safe", 2683), "sweep_direction.json": ("CHA", "pure+dissim+slope.ratio.derived3.safe", 2683),
"sweep_gate.json": ("CHA", "gate.ratio_soft.derived.safe", 2851), "sweep_gate.json": ("CHA", "gate.ratio_soft.derived.safe", 2851),