mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-30 18:56:16 +00:00
Lean proof fixes: - N3L_Energy.lean: fully close gaussian_line_integral_unit_dir (nlinarith+hab for unit-circle quadratic, sqrt_mul+neg_div for integral_gaussian_1d match, exp_sum_of_sq order fix, add_assoc for h_gauss_shift, sq_sqrt for field_simp, sq_abs for perpDistance hd) - Add Adapters/AlphaProofNexus: 12 Erdos/graph adapter stubs (AlphaProof nexus) - Add Adapters/ErgodicAdditive.lean, SidonMatroid.lean - Add AntiDiophantine.lean, EffectiveBoundDQ.lean, PVGS_DQ_Bridge.lean - Add FormalConjectures/Util/ProblemImports.lean - Add RRC/EntropyCandidates/Candidates.lean - Add OTOM external project (lakefile.toml, lake-manifest.json, lean-toolchain) Infrastructure: - Add 4-Infrastructure/shim/: 17 Python probes (RRC manifold, Sidon kernel, Wannier, arxiv harvest, math_symbols DB, coverage density, geometric entropy) - Add 4-Infrastructure/NoDupeLabs/: Node server + package files - Add 6-Documentation/docs/specs/DP_RRC_RECEIPT_ENCODING_SPEC.md - Add fix_offloat.py Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
133 lines
6.2 KiB
Python
133 lines
6.2 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
math_symbols.py — Math-symbol database loader + LaTeX/Unicode normalizer.
|
||
|
||
Backs the RRC geometry / tensor-notation kernel. Provides:
|
||
|
||
* MATH_SYMBOLS — full symbol table from shared-data/data/math_symbols_v1.json
|
||
(built by build_math_symbols_db.py: unicode-math-table.tex +
|
||
unicodedata, ~2950 symbols).
|
||
* LATEX_TO_CHAR — command → Unicode char. A curated map of the STANDARD LaTeX
|
||
macros (\\Gamma, \\rho, \\nabla, …) takes precedence over the
|
||
unicode-math table (which binds \\Gamma to a math-italic
|
||
codepoint, not the plain Greek letter), then the full DB
|
||
fills in the long tail (\\boxtimes, \\curlyvee, …).
|
||
* CHAR_INFO — char → {role, name, block, category} for feature extraction.
|
||
* normalize_math(text) — canonicalize LaTeX/Unicode so the notation signatures
|
||
match regardless of encoding: \\Gamma ≡ Γ, \\rho\\sigma ≡ ρσ,
|
||
and Penrose abstract-index R^{a}{}_{bcd} collapses cleanly.
|
||
|
||
Degrades gracefully: if the JSON DB is absent, the curated map alone still drives
|
||
normalization of the common macros.
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import re
|
||
from pathlib import Path
|
||
|
||
_DB_PATHS = [
|
||
Path("/home/allaun/Research Stack/shared-data/data/math_symbols_v1.json"),
|
||
Path(__file__).resolve().parent.parent.parent / "shared-data/data/math_symbols_v1.json",
|
||
Path("shared-data/data/math_symbols_v1.json"),
|
||
]
|
||
|
||
# ── Curated standard-LaTeX macros (authoritative for the common commands) ─────
|
||
_GREEK = {
|
||
"alpha": "α", "beta": "β", "gamma": "γ", "delta": "δ", "epsilon": "ε",
|
||
"varepsilon": "ε", "zeta": "ζ", "eta": "η", "theta": "θ", "vartheta": "ϑ",
|
||
"iota": "ι", "kappa": "κ", "lambda": "λ", "mu": "μ", "nu": "ν", "xi": "ξ",
|
||
"omicron": "ο", "pi": "π", "varpi": "ϖ", "rho": "ρ", "varrho": "ϱ",
|
||
"sigma": "σ", "varsigma": "ς", "tau": "τ", "upsilon": "υ", "phi": "φ",
|
||
"varphi": "φ", "chi": "χ", "psi": "ψ", "omega": "ω",
|
||
"Gamma": "Γ", "Delta": "Δ", "Theta": "Θ", "Lambda": "Λ", "Xi": "Ξ",
|
||
"Pi": "Π", "Sigma": "Σ", "Upsilon": "Υ", "Phi": "Φ", "Psi": "Ψ", "Omega": "Ω",
|
||
}
|
||
_OPS = {
|
||
"nabla": "∇", "partial": "∂", "infty": "∞", "times": "×", "cdot": "⋅",
|
||
"otimes": "⊗", "oplus": "⊕", "odot": "⊙", "wedge": "∧", "vee": "∨",
|
||
"pm": "±", "mp": "∓", "ast": "∗", "star": "⋆", "circ": "∘", "bullet": "∙",
|
||
"to": "→", "rightarrow": "→", "longrightarrow": "→", "mapsto": "↦",
|
||
"leftarrow": "←", "Rightarrow": "⇒", "Leftarrow": "⇐", "leftrightarrow": "↔",
|
||
"leq": "≤", "le": "≤", "geq": "≥", "ge": "≥", "neq": "≠", "ne": "≠",
|
||
"approx": "≈", "equiv": "≡", "cong": "≅", "sim": "∼", "simeq": "≃",
|
||
"propto": "∝", "in": "∈", "notin": "∉", "ni": "∋", "subset": "⊂",
|
||
"subseteq": "⊆", "supset": "⊃", "supseteq": "⊇", "cup": "∪", "cap": "∩",
|
||
"setminus": "∖", "emptyset": "∅", "forall": "∀", "exists": "∃",
|
||
"sum": "∑", "prod": "∏", "coprod": "∐", "int": "∫", "oint": "∮", "iint": "∬",
|
||
"Box": "□", "square": "□", "Diamond": "◇", "dagger": "†", "ddagger": "‡",
|
||
"ell": "ℓ", "hbar": "ℏ", "Re": "ℜ", "Im": "ℑ", "aleph": "ℵ", "wp": "℘",
|
||
"angle": "∠", "perp": "⊥", "parallel": "∥", "nparallel": "∦", "top": "⊤",
|
||
"bot": "⊥", "models": "⊨", "vdash": "⊢", "boxtimes": "⊠", "boxplus": "⊞",
|
||
"rtimes": "⋊", "ltimes": "⋉", "bigwedge": "⋀", "bigvee": "⋁",
|
||
"bigcup": "⋃", "bigcap": "⋂", "bigotimes": "⨂", "bigoplus": "⨁", "bigodot": "⨀",
|
||
"langle": "⟨", "rangle": "⟩", "lVert": "‖", "rVert": "‖", "Vert": "‖",
|
||
"nabla": "∇", "triangle": "△", "sharp": "♯", "flat": "♭", "lor": "∨", "land": "∧",
|
||
}
|
||
# Formatting / spacing macros that carry no symbol meaning — stripped.
|
||
_DROP_WORD = {
|
||
"mathrm", "mathbf", "mathit", "mathsf", "mathtt", "mathcal", "mathbb",
|
||
"mathfrak", "mathscr", "boldsymbol", "bm", "operatorname", "text", "textrm",
|
||
"textbf", "textit", "mathnormal", "left", "right", "big", "Big", "bigg",
|
||
"Bigg", "bigl", "bigr", "Bigl", "Bigr", "displaystyle", "textstyle",
|
||
"scriptstyle", "limits", "nolimits", "quad", "qquad",
|
||
}
|
||
|
||
_CURATED: dict[str, str] = {**_GREEK, **_OPS}
|
||
|
||
|
||
def _load_db() -> dict:
|
||
for p in _DB_PATHS:
|
||
try:
|
||
if p.exists():
|
||
return json.loads(p.read_text(encoding="utf-8"))
|
||
except Exception:
|
||
continue
|
||
return {"symbols": []}
|
||
|
||
|
||
MATH_SYMBOLS: list[dict] = _load_db().get("symbols", [])
|
||
|
||
# command (no backslash) → char. Curated wins; DB fills the long tail.
|
||
LATEX_TO_CHAR: dict[str, str] = {}
|
||
for _s in MATH_SYMBOLS:
|
||
_cmd = (_s.get("latex") or "").lstrip("\\").strip()
|
||
if _cmd and _cmd.isalpha() and _cmd not in LATEX_TO_CHAR:
|
||
LATEX_TO_CHAR[_cmd] = _s["char"]
|
||
LATEX_TO_CHAR.update(_CURATED) # curated standard macros take precedence
|
||
|
||
CHAR_INFO: dict[str, dict] = {s["char"]: s for s in MATH_SYMBOLS}
|
||
|
||
_CMD_RE = re.compile(r"\\([A-Za-z]+)")
|
||
_SPACE_RE = re.compile(r"\\[,!;:> ]") # \, \! \; \: thin/neg spaces
|
||
_EMPTY_GRP_RE = re.compile(r"\{\s*\}") # Penrose empty index slots {}
|
||
_WS_RE = re.compile(r"[ \t]+")
|
||
|
||
|
||
def _sub_cmd(m: re.Match) -> str:
|
||
word = m.group(1)
|
||
if word in _DROP_WORD:
|
||
return " "
|
||
if word in LATEX_TO_CHAR:
|
||
return LATEX_TO_CHAR[word]
|
||
return m.group(0) # unknown command: leave untouched
|
||
|
||
|
||
def normalize_math(text: str) -> str:
|
||
"""Canonicalize LaTeX + Unicode math so notation signatures match uniformly.
|
||
|
||
\\Gamma → Γ, \\rho\\sigma\\mu\\nu → ρσμν, \\nabla_\\mu → ∇_μ, strips
|
||
\\mathrm/\\left/\\, wrappers, and collapses Penrose empty index groups
|
||
R^{a}{}_{bcd} → R^{a}_{bcd}. Idempotent on already-Unicode input.
|
||
"""
|
||
if not text:
|
||
return ""
|
||
text = _SPACE_RE.sub(" ", text)
|
||
# iterate to resolve nested wrappers like \mathrm{\Gamma}
|
||
for _ in range(3):
|
||
new = _CMD_RE.sub(_sub_cmd, text)
|
||
if new == text:
|
||
break
|
||
text = new
|
||
text = _EMPTY_GRP_RE.sub("", text)
|
||
return _WS_RE.sub(" ", text).strip()
|