Point 1. The base step's order is Muller's 1.839, not 2: the derivative of the parabola through
the last three points errs by f'''/6 (x_n - x_{n-1})(x_n - x_{n-2}) = O(e_{n-1} e_{n-2}).
order_high_precision.py (3000 digits, to 1e-2900): 1.840 on cos x - x, e^x - 2, x^3 - x - 2,
sin x - 1/2; 2.000 only on x^2 - 2; two-point 1.618. The double-precision medians (2.000, 1.94)
are removed from the text.
Point 3. Every protocol number is re-scored under the criterion of section 9 - a sign change
within 1e-6 or f(x) == 0. rescore_uniform.py re-runs all 2779 distinct configurations of the 25
protocol sweeps on APS and CHA (the runs did not keep x) -> sweep_uniform.json, same row format;
it reproduces the APS/CHA lines of Table 10 exactly (built-in check). verify_article.py,
audit_similarity_places.py and the gap diagnostics read the re-scored data; the multiplier and
endowment measurements score by the same criterion. Table 7 (two criteria side by side) is gone;
7.3 now explains why the criterion is a sign change. Consequences stated in the text: the base
rule 2634 / 2357 against Chandrupatla 2595 / 1505 (1.5% behind on APS, no longer "level"); A'
2259 / 1074 (12.9% and 28.6% below Chandrupatla); the defect reading 2351 is second to the
shape reading 2337, not the record; the remembered analogy is level with no regime (2633 vs
2634) under this criterion; Table 9a's range is 19% to 425%.
Point 8. report_sweep.head_to_head counts every problem, failures charged (it counted only the
problems both methods solved, which is why Table 8 rows summed to 153 and 40). Family-level
comparisons added (A' vs Chandrupatla 8/1/6 of 15 and 7/0/2 of 9 families, not significant), and
an independence paragraph in section 9.
Point 11. sweep_itp.py: ITP (recommended constants and per-problem oracle) on all six corpora ->
Table 10; behind A' on every corpus, 0 bound violations.
Points 7, 9, 10 and the internals: the 2x bound is ours, not the rivals' promise; the law
predicts the group order only; "outside the proven bracket" explained (narrowest bracket of all
observed signs); 7.4's fun1 paragraph corrected (five costs under safe; the unguarded numbers
belong to fun1.4, fun1.5 and to fun3.1, fun5.1 separately); Table 1's last cell; the corpus-4
composition and odd multiplicities stated, also in the abstract.
build_tex.py: pdflatex output decoded with errors="replace" (a UTF-8 character cut by TeX's log
wrap crashed the build). Table 10 column widths rebalanced.
Checks: verify_article on the server 500 OK / 0 BAD (467 existing with the new values, 33 new);
regression x2 on the server 1232 passed, 0 failed; PDF 28 pages, 0 errors, 0 undefined, 0 overfull.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
96 lines
4.1 KiB
Python
96 lines
4.1 KiB
Python
"""Regenerate article/sim_numerics.tex (and the PDF) from the canonical article/sim_numerics.md.
|
|
|
|
The .md is the text; the .tex is a build product and is never edited by hand. Title, author
|
|
and abstract become pandoc metadata; the body is converted as it stands (section numbers are
|
|
part of the headings, so LaTeX numbering is off). Unicode that pdflatex does not know is
|
|
declared in the header. Run on the server (pandoc 3.1.3, pdflatex):
|
|
|
|
python -u build_tex.py -> article/sim_numerics.tex, article/sim_numerics.pdf
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
MD = "article/sim_numerics.md"
|
|
TEX = "article/sim_numerics.tex"
|
|
|
|
HEADER = r"""
|
|
\usepackage{amsmath,amssymb}
|
|
\usepackage{textcomp}
|
|
\DeclareUnicodeCharacter{2032}{\ensuremath{'}}
|
|
\DeclareUnicodeCharacter{2212}{\ensuremath{-}}
|
|
\DeclareUnicodeCharacter{00D7}{\ensuremath{\times}}
|
|
\DeclareUnicodeCharacter{00B5}{\textmu}
|
|
\DeclareUnicodeCharacter{2192}{\ensuremath{\rightarrow}}
|
|
\DeclareUnicodeCharacter{0394}{\ensuremath{\Delta}}
|
|
\DeclareUnicodeCharacter{2082}{\textsubscript{2}}
|
|
\usepackage[margin=2.5cm]{geometry}
|
|
\usepackage[htt]{hyphenat}
|
|
\setlength{\emergencystretch}{3em}
|
|
\usepackage{etoolbox}
|
|
\AtBeginEnvironment{longtable}{\small}
|
|
"""
|
|
|
|
BANNER = ("%% GENERATED from article/sim_numerics.md by build_tex.py - do not edit by hand.\n"
|
|
"%% The .md is the canonical text; every number in it is checked by verify_article.py.\n")
|
|
|
|
|
|
def split_front(md):
|
|
lines = md.split("\n")
|
|
title = lines[0].lstrip("# ").strip()
|
|
rest = lines[1:]
|
|
author = next(ln.strip() for ln in rest if ln.strip())
|
|
text = "\n".join(rest)
|
|
head, _, body = text.partition("## Abstract")
|
|
abstract, _, body = body.partition("\n---\n")
|
|
return title, author, abstract.strip(), body.lstrip("\n")
|
|
|
|
|
|
def main():
|
|
with open(MD, encoding="utf8") as fh:
|
|
title, author, abstract, body = split_front(fh.read())
|
|
meta = {"title": title, "author": author, "abstract": abstract,
|
|
"header-includes": HEADER, "documentclass": "article",
|
|
"classoption": ["11pt", "a4paper"]}
|
|
os.makedirs("build", exist_ok=True)
|
|
with open("build/meta.json", "w", encoding="utf8") as fh:
|
|
json.dump(meta, fh)
|
|
with open("build/body.md", "w", encoding="utf8") as fh:
|
|
fh.write(body)
|
|
subprocess.run(["pandoc", "build/body.md", "--metadata-file=build/meta.json", "-s",
|
|
"-f", "markdown+tex_math_dollars+pipe_tables", "-t", "latex",
|
|
"-o", "build/body.tex"], check=True)
|
|
with open("build/body.tex", encoding="utf8") as fh:
|
|
tex = fh.read()
|
|
with open(TEX, "w", encoding="utf8") as fh:
|
|
fh.write(BANNER + tex)
|
|
for _ in range(2):
|
|
r = subprocess.run(["pdflatex", "-interaction=nonstopmode", "-halt-on-error",
|
|
"-output-directory", "article", TEX],
|
|
capture_output=True, text=True, encoding="utf8", errors="replace")
|
|
# errors="replace": TeX wraps its log at 79 bytes and can cut a UTF-8 character in
|
|
# two; the split byte crashed the build (2026-09-22) - the log is read the same way
|
|
log = open("article/sim_numerics.log", encoding="utf8", errors="replace").read()
|
|
errors = [ln for ln in log.splitlines() if ln.startswith("!")]
|
|
# only undefined references / citations count; 'Font shape ... undefined' is a font
|
|
# substitution warning, not a defect of the text
|
|
undefined = [ln for ln in log.splitlines()
|
|
if "undefined" in ln.lower() and ("reference" in ln.lower()
|
|
or "citation" in ln.lower())]
|
|
overfull = sum(1 for ln in log.splitlines() if ln.startswith("Overfull"))
|
|
pages = next((ln for ln in log.splitlines() if "Output written" in ln), "no output")
|
|
print(f"pdflatex exit {r.returncode}; errors {len(errors)}; undefined {len(undefined)}; "
|
|
f"overfull boxes {overfull}")
|
|
for ln in errors[:10] + undefined[:10]:
|
|
print(" ", ln)
|
|
print(pages)
|
|
print("build done")
|
|
sys.exit(0 if r.returncode == 0 and not errors else 1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|