From 8ea89dd38d965797e11ce9179122c714b5883f64 Mon Sep 17 00:00:00 2001 From: Valeri Sitnikov Date: Mon, 21 Sep 2026 19:47:21 +0100 Subject: [PATCH] PREREG before any run: third corpus - the GSL root-finding test suite (10, published) and 122 physics/engineering equations on grids fixed beforehand (Kepler incl. e up to 0.999, Colebrook-White, Lambert W, Planck/Wien, van der Waals CO2 incl. near-critical, IRR, finite square well). T1-T3 as before; GSL part reported separately; per equation breakdown. Co-Authored-By: Claude Opus 5 --- PREREG_applied_2026-09-21.md | 37 ++++++++++++++ corpus_applied.py | 97 ++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 PREREG_applied_2026-09-21.md create mode 100644 corpus_applied.py diff --git a/PREREG_applied_2026-09-21.md b/PREREG_applied_2026-09-21.md new file mode 100644 index 0000000..72dc471 --- /dev/null +++ b/PREREG_applied_2026-09-21.md @@ -0,0 +1,37 @@ +# PREREG — третий независимый корпус: набор GSL и прикладные уравнения + +Составлено до прогона, ветка `signfix-and-gates`. Валерий: «давай ещё найдём корпус для теста, для +статьи это будет только плюс». + +## Корпус (`corpus_applied.py`, закоммичен до прогона) + +- **G** — тестовый набор модуля поиска корней GNU Scientific Library (`roots/test.c`, + `test_funcs.c`, зеркало github.com/ampl/gsl): все 10 задач со скобкой, как в оригинале. +- **P** — 122 уравнения из физики и инженерии на стандартных сетках параметров, заданных до прогона: + уравнение Кеплера (35: e ∈ {0.1, 0.5, 0.9, 0.99, 0.999} × 7 значений M), Колбрука–Уайта (36: Re × + шероховатость), W-функция Ламберта (7), закон смещения Вина/Планка (7), Ван-дер-Ваальс для CO₂ + (20: T × P, включая околокритическую T = 304 K), внутренняя норма доходности (12), конечная + квантовая яма (5). Все 132 имеют разные знаки на концах. +- Успех — смена знака в пределах 10⁻⁶ от ответа (как в PREREG_roots_jl). XTOL 10⁻¹², MAXFEV 200, + неудача = 200; гарантия ≤ 2⌈log₂(w/xtol)⌉ + 4. + +Сетки выбраны мной — корпус не так независим, как опубликованный, поэтому **часть G (опубликованная) +сообщается отдельно**, а по части P — разбивка по уравнениям. + +## Варианты и критерии — те же + +**A** = Г2 + `contra+flatanalogmempt+exp+half`; **B** = `defect+flatanalogmempt+exp`; справочно — предложенный +метод без добавок; соперники — библиотечные Чандрупатла, Брент, TOMS748. + +| # | ПРОЙДЕНО, если (все 132) | +|---|---| +| **T1** | сумма вызовов V меньше, чем у Чандрупатлы | +| **T2** | по задачам против Чандрупатлы побед больше, чем поражений, знаковый тест p < 0.05 | +| **T3** | гарантия: 0 нарушений; решено не меньше, чем у Чандрупатлы | + +«Переносится» — T1, T2, T3 одновременно; сообщается также, выполнен ли T1 отдельно (выигрыш по сумме). +Метод, корпус и критерии не меняются. + +**Ожидание, записано заранее:** почти-кратные случаи — Кеплер с e → 1 при малом M (около нуля +E − e sin E ≈ (1 − e)E + E³/6) и околокритический Ван-дер-Ваальс; остальное — гладкие простые корни, +где по двум прошлым корпусам ожидается паритет. diff --git a/corpus_applied.py b/corpus_applied.py new file mode 100644 index 0000000..4d925bf --- /dev/null +++ b/corpus_applied.py @@ -0,0 +1,97 @@ +"""A third OUT-OF-SAMPLE corpus for PREREG_applied_2026-09-21, fixed before any method runs on it. + +Part G - the GNU Scientific Library root-finding test suite (roots/test.c, test_funcs.c, + mirror github.com/ampl/gsl): the 10 bracketed problems, verbatim. +Part P - equations from physics and engineering on standard parameter grids, chosen before + any run (the grids are the pre-registration; nothing is tuned afterwards): + kepler E - e sin E - M = 0, E in [0, pi]; e x M grid (e up to 0.999: near-cubic) + colebrook 1/sqrt(f) + 2 log10(eps/3.7 + 2.51/(Re sqrt(f))) = 0, f in [1e-3, 0.2] + lambert x e^x - y = 0, x in [0, max(1, ln y + 1)] + planck x - n (1 - e^-x) = 0, x in [0.5, 2n] (n = 3: frequency peak, 5: wavelength) + vdw (P + a/V^2)(V - b) - R T = 0 for CO2, V in [1.001 b, 2RT/P + b] (T near 304 K is + near-critical: a flat, nearly triple root) + irr -100 + sum_{t=1..n} c (1+r)^-t = 0, r in [-0.5, 10] + well z sin z - sqrt(z0^2 - z^2) cos z = 0 (finite square well, ground state), + z in [0, min(pi/2, z0)] +Roots are not all known in closed form; success is a sign change within 1e-6 of the answer, +the criterion of PREREG_roots_jl (corpus_roots_jl.solved). +""" +from __future__ import annotations + +import math + +pi = math.pi + + +def _sgn(x): + return 0.0 if x == 0 else math.copysign(1.0, x) + + +GSL = [ + ("G.sin[3,4]", math.sin, 3.0, 4.0), + ("G.sin[-4,-3]", math.sin, -4.0, -3.0), + ("G.sin[-1/3,1]", math.sin, -1.0 / 3.0, 1.0), + ("G.cos[0,3]", math.cos, 0.0, 3.0), + ("G.cos[-3,0]", math.cos, -3.0, 0.0), + ("G.x^20-1", lambda x: x ** 20.0 - 1, 0.1, 2.0), + ("G.sqrt|x|sgn", lambda x: math.sqrt(abs(x)) * _sgn(x), -1.0 / 3.0, 1.0), + ("G.x^2-1e-8", lambda x: x ** 2.0 - 1e-8, 0.0, 1.0), + ("G.x*exp(-x)", lambda x: x * math.exp(-x), -1.0 / 3.0, 2.0), + ("G.(x-1)^7", lambda x: (x - 1) ** 7.0, 0.9995, 1.0002), +] + + +def _applied(): + out = [] + for e in (0.1, 0.5, 0.9, 0.99, 0.999): + for M in (0.001, 0.01, 0.1, 0.5, 1.0, 2.0, 3.0): + out.append((f"P.kepler.e{e}.M{M}", + (lambda E, e=e, M=M: E - e * math.sin(E) - M), 0.0, pi)) + for Re in (4e3, 1e4, 1e5, 1e6, 1e7, 1e8): + for rel in (0.0, 1e-6, 1e-4, 1e-3, 1e-2, 5e-2): + out.append((f"P.colebrook.Re{Re:.0e}.e{rel}", + (lambda f, Re=Re, rel=rel: 1 / math.sqrt(f) + + 2 * math.log10(rel / 3.7 + 2.51 / (Re * math.sqrt(f)))), 1e-3, 0.2)) + for y in (1e-6, 1e-3, 0.1, 1.0, 10.0, 1e3, 1e6): + out.append((f"P.lambert.y{y}", (lambda x, y=y: x * math.exp(x) - y), + 0.0, max(1.0, math.log(y) + 1.0))) + for n in (2, 3, 4, 5, 6, 8, 10): + out.append((f"P.planck.n{n}", (lambda x, n=n: x - n * (1 - math.exp(-x))), 0.5, 2.0 * n)) + a, b, R = 3.64, 0.04267, 0.08314 + for T in (280.0, 304.0, 350.0, 500.0): + for P in (1.0, 10.0, 40.0, 73.0, 100.0): + out.append((f"P.vdw.T{T:.0f}.P{P:.0f}", + (lambda V, T=T, P=P: (P + a / V ** 2) * (V - b) - R * T), + 1.001 * b, 2 * R * T / P + b)) + for c in (5.0, 10.0, 20.0, 50.0): + for n in (5, 10, 30): + out.append((f"P.irr.c{c:.0f}.n{n}", + (lambda r, c=c, n=n: -100.0 + sum(c * (1 + r) ** -t for t in range(1, n + 1))), + -0.5, 10.0)) + for z0 in (1.0, 3.0, 5.0, 10.0, 20.0): + out.append((f"P.well.z0{z0:.0f}", + (lambda z, z0=z0: z * math.sin(z) - math.sqrt(max(z0 * z0 - z * z, 0.0)) * math.cos(z)), + 0.0, min(pi / 2, z0))) + return out + + +def build(): + """[(id, f, a, b)] with values of opposite sign at the ends, and the ids dropped.""" + out, dropped = [], [] + for pid, f, a, b in GSL + _applied(): + try: + fa, fb = f(a), f(b) + good = (math.isfinite(fa) and math.isfinite(fb) and fa != 0 and fb != 0 + and (fa < 0) != (fb < 0)) + except (OverflowError, ValueError, ZeroDivisionError): + good = False + (out if good else dropped).append((pid, f, float(a), float(b)) if good else pid) + return out, dropped + + +if __name__ == "__main__": + from collections import Counter + probs, dropped = build() + print(len(probs), "problems;", dict(Counter(p[0].split(".")[0] + "." + p[0].split(".")[1] + if p[0].startswith("P.") else "GSL" for p in probs))) + print("dropped (no sign change at the ends):", dropped)