The .tex is no longer stale: regenerated from the canonical .md by build_tex.py (pandoc 3.1.3 + pdflatex on the server; marked GENERATED, never edited by hand). PDF: 28 pages, 0 errors, 0 undefined references, 0 overfull boxes. For LaTeX the .md got braces on four n_\max subscripts (fix_md_for_latex.py; rendering identical) and Table 10 was split into totals (10) and per-problem counts (10b) so that it fits a page; numbers unchanged. verify_article on the server 467 OK / 0 BAD; regression x2 1226 passed, 0 failed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,50 @@
|
|||||||
|
"""Split Table 10 of article/sim_numerics.md in two - totals (with bound violations) and the
|
||||||
|
per-problem counts - so that it fits a printed page. The numbers are unchanged.
|
||||||
|
|
||||||
|
python -u apply_article_table10_split.py
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
PATH = "article/sim_numerics.md"
|
||||||
|
|
||||||
|
OLD_START = "**Table 10.** A′ against the library rivals on all six corpora (uniform criterion)."
|
||||||
|
OLD_END = "| all 855 | **13032** | 16481 | 16657 | 24565 | 23649 | | |"
|
||||||
|
|
||||||
|
NEW = """**Table 10.** A′ against the library rivals on all six corpora (uniform criterion): total evaluations; in brackets the runs that break the $2\\times$-bisection bound.
|
||||||
|
|
||||||
|
| corpus | A′ | Chandrupatla | ModAB | Brent | TOMS 748 |
|
||||||
|
|----------------------|------------|--------------|------------|------------|------------|
|
||||||
|
| APS (154) | **2259** (0) | 2595 (0) | 2726 (0) | 2707 (0) | 2636 (0) |
|
||||||
|
| Chandrupatla (45) | **1074** (0) | 1505 (0) | 1681 (0) | 3238 (18) | 3088 (15) |
|
||||||
|
| new corpus 1 (206) | **3290** (0) | 3716 (0) | 3809 (1) | 6395 (38) | 5746 (22) |
|
||||||
|
| Roots.jl (78) | **1371** (0) | 1566 (0) | 1446 (0) | 2455 (11) | 2339 (9) |
|
||||||
|
| applied + GSL (132) | 1382 (0) | 1382 (0) | 1460 (0) | 1503 (1) | 1756 (1) |
|
||||||
|
| **corpus 4 (240), the one test** | **3656** (0) | 5717 (0) | 5535 (8) | 8267 (50) | 8084 (37) |
|
||||||
|
| all 855 | **13032** | 16481 | 16657 | 24565 | 23649 |
|
||||||
|
|
||||||
|
**Table 10b.** The same runs problem by problem: A′'s wins/ties/losses against Chandrupatla and against ModAB (exact two-sided sign test).
|
||||||
|
|
||||||
|
| corpus | A′ vs Chandrupatla | A′ vs ModAB |
|
||||||
|
|----------------------|------------------------------|--------------|
|
||||||
|
| APS (154) | 103/20/31, $p=3\\cdot10^{-10}$ | 118/10/26 |
|
||||||
|
| Chandrupatla (45) | 31/4/10, $p=0.001$ | 34/4/7 |
|
||||||
|
| new corpus 1 (206) | 108/33/65, $p=0.001$ | 125/26/55 |
|
||||||
|
| Roots.jl (78) | 44/14/20, $p=0.004$ | 47/11/20 |
|
||||||
|
| applied + GSL (132) | 48/52/32, $p=0.09$ | 76/35/21 |
|
||||||
|
| **corpus 4 (240), the one test** | **177/35/28, $p=10^{-27}$** | **183/23/34** |"""
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with open(PATH, encoding="utf8") as fh:
|
||||||
|
text = fh.read()
|
||||||
|
if text.count(OLD_START) != 1 or text.count(OLD_END) != 1:
|
||||||
|
raise SystemExit("Table 10 anchors not found exactly once")
|
||||||
|
i, j = text.index(OLD_START), text.index(OLD_END) + len(OLD_END)
|
||||||
|
text = text[:i] + NEW + text[j:]
|
||||||
|
with open(PATH, "w", encoding="utf8") as fh:
|
||||||
|
fh.write(text)
|
||||||
|
print("Table 10 split")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
+25
-14
@@ -135,15 +135,15 @@ Every quantity in it is either an evaluation of $f$, a divided difference of eva
|
|||||||
|
|
||||||
An interpolation-only rule has no worst-case bound. The obvious safeguards *replace* the computed step with a midpoint whenever some progress test fails, and all of them are ruinous here, for a reason specific to a fast method: a step that collapses the *error* need not halve the *bracket*, so a bracket-based test fires on exactly the steps that were best. With the three-point scale, replacing on that test drops the observed order from 1.94 to 1.00 and the Alefeld–Potra–Shi total from 2806 to 7260 — worse than bisection.
|
An interpolation-only rule has no worst-case bound. The obvious safeguards *replace* the computed step with a midpoint whenever some progress test fails, and all of them are ruinous here, for a reason specific to a fast method: a step that collapses the *error* need not halve the *bracket*, so a bracket-based test fires on exactly the steps that were best. With the three-point scale, replacing on that test drops the observed order from 1.94 to 1.00 and the Alefeld–Potra–Shi total from 2806 to 7260 — worse than bisection.
|
||||||
|
|
||||||
The remedy is to keep as much of the computed step as the budget allows. Let $n_\max=2\lceil\log_2(w_0/\varepsilon_x)\rceil$ be twice the bisection step count for the initial width $w_0$ and $x$-tolerance $\varepsilon_x$, and let $\epsilon=\varepsilon_x/2$. At step $j$, with the bracket $[\ell,h]$, define the allowance and the projection
|
The remedy is to keep as much of the computed step as the budget allows. Let $n_{\max}=2\lceil\log_2(w_0/\varepsilon_x)\rceil$ be twice the bisection step count for the initial width $w_0$ and $x$-tolerance $\varepsilon_x$, and let $\epsilon=\varepsilon_x/2$. At step $j$, with the bracket $[\ell,h]$, define the allowance and the projection
|
||||||
|
|
||||||
$$\alpha_j = 2^{\,n_\max-j}\epsilon, \qquad x \;=\; \operatorname{clamp}\bigl(x_\mathrm{sim},\; h-\alpha_j,\; \ell+\alpha_j\bigr). \tag{3}$$
|
$$\alpha_j = 2^{\,n_{\max}-j}\epsilon, \qquad x \;=\; \operatorname{clamp}\bigl(x_\mathrm{sim},\; h-\alpha_j,\; \ell+\alpha_j\bigr). \tag{3}$$
|
||||||
|
|
||||||
The next bracket is at most $\max(x-\ell,\,h-x)$, so (3) gives $w_{j+1}\le\alpha_j$ directly, and induction bounds the run by $n_\max$ steps in exact arithmetic. In floating point the bracket can land exactly on the boundary, and the termination test then asks for one more; the guarantee stated and verified is therefore $2\lceil\log_2(w_0/\varepsilon_x)\rceil+3$ evaluations.
|
The next bracket is at most $\max(x-\ell,\,h-x)$, so (3) gives $w_{j+1}\le\alpha_j$ directly, and induction bounds the run by $n_{\max}$ steps in exact arithmetic. In floating point the bracket can land exactly on the boundary, and the termination test then asks for one more; the guarantee stated and verified is therefore $2\lceil\log_2(w_0/\varepsilon_x)\rceil+3$ evaluations.
|
||||||
|
|
||||||
**The multiplier is the method's one free constant.** An earlier version of this section argued that it is "the factor already claimed in the bound". That is circular — the bound is twice bisection because two was chosen — and measurement settles it (`measure_budget_factor.py`, Linux):
|
**The multiplier is the method's one free constant.** An earlier version of this section argued that it is "the factor already claimed in the bound". That is circular — the bound is twice bisection because two was chosen — and measurement settles it (`measure_budget_factor.py`, Linux):
|
||||||
|
|
||||||
**Table 1a.** The scheduled projection at budget multiplier $c$, i.e. $n_\max=\lceil c\cdot\log_2(w_0/\varepsilon_x)\rceil$. Total evaluations, failures charged.
|
**Table 1a.** The scheduled projection at budget multiplier $c$, i.e. $n_{\max}=\lceil c\cdot\log_2(w_0/\varepsilon_x)\rceil$. Total evaluations, failures charged.
|
||||||
|
|
||||||
| $c$ | APS-154 | CHA-45 | both |
|
| $c$ | APS-154 | CHA-45 | both |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
@@ -532,17 +532,28 @@ ModAB, the most recent bracketing method we know of, is run from its authors' pa
|
|||||||
|
|
||||||
**The history is part of the result.** The variant carried to corpora 1–3 was A′ without the tolerance step and the overshoot branch. It transferred to corpus 1 by every pre-registered criterion (total 10% below Chandrupatla, per problem 105/34/67, $p=0.005$), did *not* transfer to Roots.jl (total 6.5% below, but per problem 38/10/30, $p=0.4$) and lost on the applied corpus (14% above). The losses there were traced to two gaps of the base step — no closing of the bracket once the root is reached, and no recognition of roots of order below one — which became the last two readings of §8.4; they were developed on the seen corpora and tested once, on corpus 4.
|
**The history is part of the result.** The variant carried to corpora 1–3 was A′ without the tolerance step and the overshoot branch. It transferred to corpus 1 by every pre-registered criterion (total 10% below Chandrupatla, per problem 105/34/67, $p=0.005$), did *not* transfer to Roots.jl (total 6.5% below, but per problem 38/10/30, $p=0.4$) and lost on the applied corpus (14% above). The losses there were traced to two gaps of the base step — no closing of the bracket once the root is reached, and no recognition of roots of order below one — which became the last two readings of §8.4; they were developed on the seen corpora and tested once, on corpus 4.
|
||||||
|
|
||||||
**Table 10.** A′ against the library rivals on all six corpora (uniform criterion). Totals; in brackets the runs that break the $2\times$-bisection bound. Per problem against Chandrupatla: wins/ties/losses.
|
**Table 10.** A′ against the library rivals on all six corpora (uniform criterion): total evaluations; in brackets the runs that break the $2\times$-bisection bound.
|
||||||
|
|
||||||
| corpus | A′ | Chandrupatla | ModAB | Brent | TOMS 748 | A′ vs Chandrupatla | A′ vs ModAB |
|
| corpus | A′ | Chandrupatla | ModAB | Brent | TOMS 748 |
|
||||||
|---|---|---|---|---|---|---|---|
|
|----------------------|------------|--------------|------------|------------|------------|
|
||||||
| APS (154) | **2259** (0) | 2595 (0) | 2726 (0) | 2707 (0) | 2636 (0) | 103/20/31, $p=3\cdot10^{-10}$ | 118/10/26 |
|
| APS (154) | **2259** (0) | 2595 (0) | 2726 (0) | 2707 (0) | 2636 (0) |
|
||||||
| Chandrupatla (45) | **1074** (0) | 1505 (0) | 1681 (0) | 3238 (18) | 3088 (15) | 31/4/10, $p=0.001$ | 34/4/7 |
|
| Chandrupatla (45) | **1074** (0) | 1505 (0) | 1681 (0) | 3238 (18) | 3088 (15) |
|
||||||
| new corpus 1 (206) | **3290** (0) | 3716 (0) | 3809 (1) | 6395 (38) | 5746 (22) | 108/33/65, $p=0.001$ | 125/26/55 |
|
| new corpus 1 (206) | **3290** (0) | 3716 (0) | 3809 (1) | 6395 (38) | 5746 (22) |
|
||||||
| Roots.jl (78) | **1371** (0) | 1566 (0) | 1446 (0) | 2455 (11) | 2339 (9) | 44/14/20, $p=0.004$ | 47/11/20 |
|
| Roots.jl (78) | **1371** (0) | 1566 (0) | 1446 (0) | 2455 (11) | 2339 (9) |
|
||||||
| applied + GSL (132) | 1382 (0) | 1382 (0) | 1460 (0) | 1503 (1) | 1756 (1) | 48/52/32, $p=0.09$ | 76/35/21 |
|
| applied + GSL (132) | 1382 (0) | 1382 (0) | 1460 (0) | 1503 (1) | 1756 (1) |
|
||||||
| **corpus 4 (240), the one test** | **3656** (0) | 5717 (0) | 5535 (8) | 8267 (50) | 8084 (37) | **177/35/28, $p=10^{-27}$** | **183/23/34** |
|
| **corpus 4 (240), the one test** | **3656** (0) | 5717 (0) | 5535 (8) | 8267 (50) | 8084 (37) |
|
||||||
| all 855 | **13032** | 16481 | 16657 | 24565 | 23649 | | |
|
| all 855 | **13032** | 16481 | 16657 | 24565 | 23649 |
|
||||||
|
|
||||||
|
**Table 10b.** The same runs problem by problem: A′'s wins/ties/losses against Chandrupatla and against ModAB (exact two-sided sign test).
|
||||||
|
|
||||||
|
| corpus | A′ vs Chandrupatla | A′ vs ModAB |
|
||||||
|
|----------------------|------------------------------|--------------|
|
||||||
|
| APS (154) | 103/20/31, $p=3\cdot10^{-10}$ | 118/10/26 |
|
||||||
|
| Chandrupatla (45) | 31/4/10, $p=0.001$ | 34/4/7 |
|
||||||
|
| new corpus 1 (206) | 108/33/65, $p=0.001$ | 125/26/55 |
|
||||||
|
| Roots.jl (78) | 44/14/20, $p=0.004$ | 47/11/20 |
|
||||||
|
| applied + GSL (132) | 48/52/32, $p=0.09$ | 76/35/21 |
|
||||||
|
| **corpus 4 (240), the one test** | **177/35/28, $p=10^{-27}$** | **183/23/34** |
|
||||||
|
|
||||||
Only the last line of corpora is evidence for A′ in the strict sense; the first five were seen while it was developed and are reported as a description. On corpus 4 A′ is 36% below Chandrupatla and wins 177 problems to 28. Without the two classes aimed at by the last two readings it is 2403 against 3569, per problem 107/31/22 ($p=10^{-14}$); on the simple-root classes alone, 737 against 747 (−1.3%), per problem 43/22/15 ($p=3\cdot10^{-4}$).
|
Only the last line of corpora is evidence for A′ in the strict sense; the first five were seen while it was developed and are reported as a description. On corpus 4 A′ is 36% below Chandrupatla and wins 177 problems to 28. Without the two classes aimed at by the last two readings it is 2403 against 3569, per problem 107/31/22 ($p=10^{-14}$); on the simple-root classes alone, 737 against 747 (−1.3%), per problem 43/22/15 ($p=3\cdot10^{-4}$).
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
+2162
-864
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,93 @@
|
|||||||
|
"""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)
|
||||||
|
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()
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
"""Make the math of article/sim_numerics.md valid LaTeX as well as MathJax: a sub- or
|
||||||
|
superscript that starts with a bare control word (n_\\max) needs braces in LaTeX (n_{\\max}).
|
||||||
|
The rendered formula is identical. Reports what it finds; --apply writes.
|
||||||
|
|
||||||
|
python -u fix_md_for_latex.py [--apply]
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
PATH = "article/sim_numerics.md"
|
||||||
|
# only argument-less control words (n_\max); a macro with an argument (x_\mathrm{far},
|
||||||
|
# r_\text{new}) is valid LaTeX as written, and bracing it would detach its argument
|
||||||
|
PAT = re.compile(r"([_^])(\\[A-Za-z]+)(?![A-Za-z{])")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with open(PATH, encoding="utf8") as fh:
|
||||||
|
text = fh.read()
|
||||||
|
hits = PAT.findall(text)
|
||||||
|
print(f"{len(hits)} bare control words in sub/superscripts:", sorted(set(h[1] for h in hits)))
|
||||||
|
if "--apply" in sys.argv:
|
||||||
|
text = PAT.sub(lambda m: f"{m.group(1)}{{{m.group(2)}}}", text)
|
||||||
|
with open(PATH, "w", encoding="utf8") as fh:
|
||||||
|
fh.write(text)
|
||||||
|
print("braced")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user