"""Generate test-only certified Gauss brackets from exact rational arithmetic. Newton/Decimal produces candidates only. Exact Fraction signs prove n distinct Legendre roots; rational interval recurrence encloses the associated weights. No runtime solver dependency, reference modification, or libm ULP premise. """ from decimal import Decimal, localcontext from fractions import Fraction as F from pathlib import Path import math import re import json def add(a, b): return a[0] + b[0], a[1] + b[1] def neg(a): return -a[1], -a[0] def mul(a, b): v = [x * y for x in a for y in b] return min(v), max(v) def div(a, b): assert b[0] > 0 or b[1] < 0 return mul(a, (1 / b[1], 1 / b[0])) def scale(a, b): return mul(a, (F(b), F(b))) def legendre(n, x): p, q = (F(1), F(1)), x for k in range(2, n + 1): p, q = q, scale(add(scale(mul(x, q), 2 * k - 1), neg(scale(p, k - 1))), F(1, k)) derivative = div(scale(add(mul(x, q), neg(p)), n), add(mul(x, x), (-F(1), -F(1)))) return q, derivative def bracket(value): return math.nextafter(float(value[0]), -math.inf), math.nextafter(float(value[1]), math.inf) def rule(n): result = [] for i in range(n): with localcontext() as context: context.prec = 90 z = Decimal(str(math.cos(math.pi * (i + .75) / (n + .5)))) for _ in range(30): p, q = Decimal(1), z for k in range(2, n + 1): p, q = q, ((2 * k - 1) * z * q - (k - 1) * p) / k d = n * (z * q - p) / (z * z - 1) z -= q / d lo, hi = bracket((F(z), F(z))) pl = legendre(n, (F(lo), F(lo)))[0][0] ph = legendre(n, (F(hi), F(hi)))[0][0] assert pl * ph < 0 x = F(lo), F(hi) derivative = legendre(n, x)[1] w = div((F(2), F(2)), mul(add((F(1), F(1)), neg(mul(x, x))), mul(derivative, derivative))) result.append((lo, hi, *bracket(w))) result.sort() assert all(a[1] < b[0] for a, b in zip(result, result[1:])) assert sum(F(r[2]) for r in result) < 2 < sum(F(r[3]) for r in result) return result def slab_fixtures(): # Approved Appendix A supplies the independently implemented Cholesky / # Jacobi spectral candidates; Appendix E supplies certified transcendentals. document = Path(__file__).resolve().parents[3] / "docs/shell-transient-heat-transfer/numerical-oracle-scratch.md" blocks = re.findall(r"```python\n(.*?)```", document.read_text(encoding="utf-8-sig"), re.S) spectral = {} exec(blocks[0].split('out={"lambda"')[0], spectral) interval_scope = {} exec(blocks[-1].split("\nfor t in [.001")[0], interval_scope) iv, ia, im, isc = (interval_scope[k] for k in ("interval", "add", "mul", "scale")) ex = interval_scope["exneg"] n = 4 def exact_inverse(matrix): a = [list(row) + [F(i == j) for j in range(n)] for i, row in enumerate(matrix)] for k in range(n): pivot = next(i for i in range(k, n) if a[i][k]) a[k], a[pivot] = a[pivot], a[k] divisor = a[k][k] a[k] = [x / divisor for x in a[k]] for i in range(n): if i != k: factor = a[i][k] a[i] = [x - factor * y for x, y in zip(a[i], a[k])] return [row[n:] for row in a] def exact_mm(a, b): return [[sum((x*y for x, y in zip(row, col)), F(0)) for col in zip(*b)] for row in a] def matrix_multiply(a, b): return [[sum_intervals([im(x, y) for x, y in zip(row, col)]) for col in zip(*b)] for row in a] def sum_intervals(values): total = iv(0) for v in values: total = ia(total, v) return total def apply(a, v): return [sum_intervals([im(x, y) for x, y in zip(row, v)]) for row in a] def power(a, count): result = [[iv(i == j) for j in range(n)] for i in range(n)] while count: if count & 1: result = matrix_multiply(result, a) count >>= 1 if count: a = matrix_multiply(a, a) return result c = [[F(0) for _ in range(5)] for _ in range(5)] k = [[F(0) for _ in range(5)] for _ in range(5)] for offset in (0, 2): for i in range(3): for j in range(3): c[offset+i][offset+j] += F([[4, 2, -1], [2, 16, 2], [-1, 2, 4]][i][j], 60) k[offset+i][offset+j] += F(2, 3)*[[7, -8, 1], [-8, 16, -8], [1, -8, 7]][i][j] cf, kf = [r[1:] for r in c[1:]], [r[1:] for r in k[1:]] inverse = exact_inverse(cf) d = exact_mm(inverse, kf) y = [-1-sum(inverse[i][j]*c[j+1][0] for j in range(n)) for i in range(n)] def matrix_exponential(t): # An independent enclosure of exp(-Cff^-1 Kff t) certifies all spectral # eigenpair/coefficient errors together, rather than assuming libm ULPs. # For ||B||inf<=1/2, the 64-term exponential remainder is bounded by # 2*(1/2)^65/65!. Entrywise intervals preserve subsequent squarings. magnitude = max(sum(abs(x*t) for x in row) for row in d) shift = 0 while magnitude > F(1, 2): magnitude /= 2 shift += 1 a = [[iv(-x*t/F(2)**shift) for x in row] for row in d] term = [[iv(i == j) for j in range(n)] for i in range(n)] result = [row[:] for row in term] for order in range(1, 65): term = [[isc(x, F(1, order)) for x in row] for row in matrix_multiply(term, a)] result = [[ia(x, z) for x, z in zip(row, terms)] for row, terms in zip(result, term)] remainder = 2*F(1, 2)**65/math.factorial(65) result = [[ia(x, iv(-remainder, remainder)) for x in row] for row in result] for _ in range(shift): result = matrix_multiply(result, result) return result def outputs(error): temperature = [iv(1)] + [ia(iv(1), z) for z in error] derivative = [iv(0)] + apply([[iv(-x) for x in row] for row in d], error) flux = [] for offset, s in ((0, -1), (0, 0), (0, 1), (2, -1), (2, 0), (2, 1)): deriv = [F(4)*F(s-F(1, 2)), F(-8*s), F(4)*F(s+F(1, 2))] flux.append(sum_intervals([isc(temperature[offset+i], -deriv[i]) for i in range(3)])) energy = sum_intervals([isc(temperature[j], sum(c[i][j] for i in range(5))) for j in range(5)]) reaction = sum_intervals([isc(temperature[j], k[0][j]) for j in range(5)] + [isc(derivative[j], c[0][j]) for j in range(5)]) return temperature + flux + [energy, reaction] def spectral_candidate(t, count): amplitudes = [] for eigenvalue, coefficient in zip(spectral["lam"], spectral["coef"]): decay = ex(iv(F(eigenvalue)*t)) if count is None else power_scalar( interval_scope["div"](iv(1), iv(1+F(eigenvalue)*t/count)), count) amplitudes.append(isc(decay, F(coefficient))) return outputs(apply([[iv(F(x)) for x in row] for row in spectral["W"]], amplitudes)) def power_scalar(x, count): result = iv(1) while count: if count & 1: result = im(result, x) count >>= 1 if count: x = im(x, x) return result table = [[.141, 10.7, .0304, 10.9], [.0153, 1.28, .00468, .824], [.00598, .253, .00130, .00632], [.00139, .136, .000666, .00953], [.000142, .0284, .0000945, .000526], [.0000414, .00816, .0000159, .0000479]] fixtures, metrics = [], [] for time, space in zip((.001, .01, .05, .1, .5, 1.), table): t = F(time) temperatures, flux, energy, _, _ = interval_scope["series_interval"](time) continuum = temperatures + [flux[i] for i in (0, 1, 2, 2, 3, 4)] + [energy, flux[0]] solutions = [] spectral_enclosure = 0. for count in (None, 4096, 8192): if count is None: operator = matrix_exponential(t) else: a = [[cf[i][j]+t/count*kf[i][j] for j in range(n)] for i in range(n)] operator = power([[iv(x) for x in row] for row in exact_mm(exact_inverse(a), cf)], count) exact = outputs(apply(operator, [iv(x) for x in y])) candidate = spectral_candidate(t, count) enclosed = [(min(a[0], b[0]), max(a[1], b[1])) for a, b in zip(exact, candidate)] spectral_enclosure = max(spectral_enclosure, max(float(hi-lo) for lo, hi in enclosed)) solutions.append(enclosed) fixtures.append((time, space, continuum, *solutions)) metrics.append({"time": time, "spectral_and_matrix_function_enclosure": spectral_enclosure}) print(json.dumps({"eigenvalues": spectral["lam"], "slab_oracle_metrics": metrics}, indent=2)) return fixtures if __name__ == "__main__": output = ["// Generated by thermal_oracle_generator.py; exact root/weight certificates.", "#ifndef FESA_TESTS_THERMAL_GAUSS_ORACLE_H_", "#define FESA_TESTS_THERMAL_GAUSS_ORACLE_H_", "#include ", "namespace thermal_oracle {", "struct GaussPoint { double x_lo,x_hi,w_lo,w_hi; };"] for n in (12, 16): rows = rule(n) output.append(f"inline constexpr std::array kGauss{n}{{{{") output.extend(" {" + ",".join(x.hex() for x in row) + "}," for row in rows) output.append("}};") output.extend(["}", "#endif", ""]) destination = Path(__file__).with_name("thermal_gauss_oracle.h") destination.write_text("\n".join(output), encoding="utf-8") print("Certified Legendre roots/weights: 12 + 16 distinct roots;", destination.name) fixtures = slab_fixtures() output = ["// Generated by thermal_oracle_generator.py. Outward binary64 brackets.", "#ifndef FESA_TESTS_THERMAL_SLAB_ORACLE_H_", "#define FESA_TESTS_THERMAL_SLAB_ORACLE_H_", "#include ", "namespace thermal_oracle {", "struct Bracket { double lo,hi; };", "struct SlabCase { double time; std::array space; std::array fourier,continuous,be4096,be8192; };", "inline constexpr std::array kSlab{{"] for time, space, *values in fixtures: output.append("{" + time.hex() + ",{{" + ",".join(x.hex() for x in space) + "}},") for rows in values: output.append("{{" + ",".join("{" + ",".join(x.hex() for x in bracket(row)) + "}" for row in rows) + "}},") output.append("},") output.extend(["}};", "}", "#endif", ""]) Path(__file__).with_name("thermal_slab_oracle.h").write_text("\n".join(output), encoding="utf-8")