r"""Deterministic Markdown -> LaTeX converter for the arXiv preprint (paper-specific, not general). Converts `paper/the-evolution-of-sex-for-ai.md` into `body.tex`, which `main.tex` inputs. Kept deliberately dumb and auditable: the paper uses a small Markdown subset (##/### headings, bold, italics, inline code, links, bullet/numbered lists, one blockquote, horizontal rules, and `(Figure: \`path\`.)` figure references), and this script handles exactly that subset. Re-run after editing the Markdown; the Markdown remains the source of truth. Usage: python paper/arxiv/md2tex.py """ from __future__ import annotations import re from pathlib import Path SRC = Path(__file__).resolve().parents[1] / "the-evolution-of-sex-for-ai.md" OUT = Path(__file__).resolve().parent / "body.tex" # Figure references in the text -> (graphics file under figs/, caption). FIGURES = { "results/E14/E14.png": ("figs/E14.pdf", "Mating systems (E14): the best mate-pool breadth shrinks as skills get more entangled. " "(A) best fitness peaks at intermediate breadth on rugged landscapes; (B) the population mean " "is monotonically favoured by promiscuity; (C) diversity is monotonically destroyed by it."), "results/E12/E12.png": ("figs/E12.pdf", "Model speciation, analytic (E12): hybrid fitness vs divergence traces compatible $\\rightarrow$ " "outbreeding depression $\\rightarrow$ inviability; the isolation cliff arrives earlier the " "denser the incompatibilities (epistasis), and damage grows super-linearly (the Orr--Turelli " "snowball)."), "results/speciation_real/speciation_real.png": ("figs/speciation_real.pdf", "Model speciation in real weights (E13). (A) the merge barrier decomposed by alignment " "strength: the independent-init barrier is a coordinate artefact (removed by alignment); the " "conflict barrier survives even the full function-preserving symmetry group. (B) the isolation " "cliff: residual barrier rises and hybrid accuracy falls ($0.97 \\rightarrow 0.03$) with " "functional conflict. (C) the pre-registered emergent test: divergent-but-compatible " "specialists develop no isolation at any divergence --- the merge instead rescues them " "(Fisher--Muller)."), } UNICODE = { "—": "---", "–": "--", "→": r"\(\rightarrow\)", "≈": r"\(\approx\)", "≥": r"\(\geq\)", "×": r"\(\times\)", "·": r"\(\cdot\)", "μ": r"\(\mu\)", } SPECIALS = {"&": r"\&", "%": r"\%", "#": r"\#", "_": r"\_", "$": r"\$", "~": r"\textasciitilde{}", "^": r"\textasciicircum{}"} def esc(s: str) -> str: s = s.replace("\\", r"\textbackslash{}") for k, v in SPECIALS.items(): s = s.replace(k, v) for k, v in UNICODE.items(): s = s.replace(k, v) return s def inline(s: str) -> str: """Escape + convert inline markup. Code spans are protected, then bold, italic, links.""" parts = re.split(r"(`[^`]*`)", s) out = [] for p in parts: if p.startswith("`") and p.endswith("`") and len(p) >= 2: out.append(r"\texttt{" + esc(p[1:-1]) + "}") else: p = esc(p) p = re.sub(r"\[([^\]]+)\]\((https?://[^)]+)\)", r"\\href{\2}{\1}", p) p = re.sub(r"\*\*([^*]+)\*\*", r"\\textbf{\1}", p) p = re.sub(r"\*([^*]+)\*", r"\\emph{\1}", p) p = re.sub(r'"([^"]+)"', r"``\1''", p) # straight quotes -> LaTeX quotes out.append(p) return "".join(out) def figure_block(md_path: str) -> str: gfx, caption = FIGURES[md_path] return ("\\begin{figure*}[t]\\centering\n" f"\\includegraphics[width=\\textwidth]{{{gfx}}}\n" f"\\caption{{{caption}}}\n\\end{{figure*}}\n") def convert(text: str) -> str: """Block-based conversion: soft-wrapped lines are joined per paragraph/item BEFORE inline conversion, so bold/italic/code spans and figure pointers crossing a line break work.""" fig_queue: list[str] = [] def fig_sub(m): path = m.group(1) if path in FIGURES: fig_queue.append(figure_block(path)) return "" return m.group(0) lines = text.split("\n") i = 0 # Skip the header block (title/subtitle/author) up to and including the first horizontal rule: # main.tex composes the title page itself. while i < len(lines) and lines[i].strip() != "---": i += 1 i += 1 # Group into blocks separated by blank lines; a block is a heading, rule, quote, list, or paragraph. blocks: list[list[str]] = [] cur: list[str] = [] for line in lines[i:]: if line.strip() == "": if cur: blocks.append(cur); cur = [] else: cur.append(line) if cur: blocks.append(cur) def emit_para(joined: str, out: list[str]) -> None: joined = re.sub(r"\(Figure: `([^`]+)`\.?\)", fig_sub, joined) joined = re.sub(r"\s{2,}", " ", joined).strip() if joined: out.append(inline(joined)) out.append("") while fig_queue: out.append(fig_queue.pop(0)); out.append("") def emit_table(block: list[str], out: list[str]) -> None: """Pipe table -> small-font tabular with wrapped paragraph columns (full text width).""" rows = [[c.strip() for c in line.strip().strip("|").split("|")] for line in block] header, body = rows[0], [r for r in rows[2:]] # rows[1] is the |---| separator n = len(header) widths = " ".join([f"p{{{0.92 / n:.3f}\\textwidth}}"] * n) out.append("\\medskip\\noindent\\begin{center}\\footnotesize") # non-floating: stays in place out.append(f"\\begin{{tabular}}{{{widths}}}") out.append("\\hline") out.append(" & ".join(inline(c) for c in header) + " \\\\ \\hline") for r in body: r = (r + [""] * n)[:n] out.append(" & ".join(inline(c) for c in r) + " \\\\[3pt]") out.append("\\hline\\end{tabular}\\end{center}\\medskip") out.append("") out: list[str] = [] for block in blocks: first = block[0].strip() if first.startswith("|") and len(block) >= 2 and set(block[1].strip()) <= set("|-: "): emit_table(block, out) elif first == "---" and len(block) == 1: out.append("\\medskip\\hrule\\medskip"); out.append("") elif first.startswith("## "): out.append(f"\\section*{{{inline(first[3:])}}}"); out.append("") elif first.startswith("### "): out.append(f"\\subsection*{{{inline(first[4:])}}}"); out.append("") elif first.startswith("> "): joined = " ".join(l.strip().lstrip("> ").strip() for l in block) out.append("\\begin{quote}" + inline(joined) + "\\end{quote}"); out.append("") elif re.match(r"^(- |\d+\. )", first): env = "itemize" if first.startswith("- ") else "enumerate" out.append(f"\\begin{{{env}}}") items: list[str] = [] for l in block: s = l.strip() if re.match(r"^(- |\d+\. )", s): items.append(re.sub(r"^(- |\d+\. )", "", s)) else: items[-1] = items[-1] + " " + s # soft-wrapped continuation of the item for it in items: it = re.sub(r"\(Figure: `([^`]+)`\.?\)", fig_sub, it) out.append("\\item " + inline(it.strip())) out.append(f"\\end{{{env}}}"); out.append("") while fig_queue: out.append(fig_queue.pop(0)); out.append("") else: emit_para(" ".join(l.strip() for l in block), out) return "\n".join(out) + "\n" if __name__ == "__main__": OUT.write_text(convert(SRC.read_text())) print(f"wrote {OUT}")