Files
sim-numerics/corpus_applied.py

98 lines
4.5 KiB
Python

"""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)