Files
sim-numerics/build_tex.py
T
vvsandClaude Opus 5 862feaff86 Revision 1, step 1: one scoring criterion, the correct order, and the internal inconsistencies.
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>
2026-09-22 07:01:36 +01:00

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