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>
248 lines
9.8 KiB
Python
248 lines
9.8 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
rrc_self_classify.py — Self-classifying RRC pipeline.
|
||
|
||
Takes a new equation (name + LaTeX text + route_hint), runs it through
|
||
all 6 kernel stages, assigns manifold location + regime, and emits a receipt.
|
||
|
||
Usage:
|
||
# Classify a single equation
|
||
python3 4-Infrastructure/shim/rrc_self_classify.py \\
|
||
--name "my_sidon_test" \\
|
||
--equation "|A| ≤ √(2N) + 1" \\
|
||
--route "number_theory"
|
||
|
||
# Batch classify from JSONL
|
||
python3 4-Infrastructure/shim/rrc_self_classify.py --batch new_eqs.jsonl
|
||
|
||
# Self-test: classify all kernel titles against themselves
|
||
python3 4-Infrastructure/shim/rrc_self_classify.py --self-test
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import re
|
||
import subprocess
|
||
import sys
|
||
import time
|
||
from collections import defaultdict
|
||
from pathlib import Path
|
||
from typing import Any
|
||
|
||
NEON_HOST = "neon-64gb"
|
||
CONTAINER = "arxiv-pg"
|
||
DB = "arxiv"
|
||
|
||
# Import the kernel detection logic
|
||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||
from rrc_arxiv_kernel_refine import (
|
||
DIOPHANTINE_KERNEL, COMBINATORICS_KERNEL,
|
||
detect_diophantine_type, detect_combinatorics_type,
|
||
detect_obscure_type, detect_dataset_type, detect_sidon_type,
|
||
detect_geometry_type, detect_reconstruction_type,
|
||
extract_keywords, search_papers,
|
||
RECEIPT_PATH,
|
||
)
|
||
|
||
RECEIPT_PATH = Path("archive/experimental-shim-probes/rrc_equation_classifier_receipt.json")
|
||
|
||
|
||
def classify_equation(name: str, eq_text: str, route_hint: str = "") -> dict:
|
||
"""Run an equation through all 6 kernel stages and return the best match."""
|
||
stages = [
|
||
# v0: graph-reconstruction kernel — fires FIRST (matches the batch
|
||
# kernel_refine ordering), so reconstruction-conjecture equations are
|
||
# tagged before the generic combinatorics/sidon stages claim them.
|
||
("kernel_refine_v0", lambda: detect_reconstruction_type(name, eq_text)),
|
||
("kernel_refine_v6", lambda: detect_sidon_type(name, eq_text)),
|
||
("kernel_refine_v3", lambda: detect_combinatorics_type(name, eq_text)),
|
||
("kernel_refine_v4", lambda: detect_dataset_type(name, eq_text)),
|
||
("kernel_refine_v2", lambda: detect_diophantine_type(name, eq_text)),
|
||
("kernel_refine_v5", lambda: detect_obscure_type(name, eq_text)),
|
||
# v7: geometry/topology kernel — last kernel stage before the keyword
|
||
# fallback, so existing number-theory matches are untouched and only
|
||
# otherwise-unmatched eqs (e.g. the geodesic equation) reach it.
|
||
("kernel_refine_v7", lambda: detect_geometry_type(name, eq_text)),
|
||
]
|
||
|
||
best_paper_id = None
|
||
best_match = None
|
||
best_stage = None
|
||
|
||
for stage_name, detector in stages:
|
||
try:
|
||
matches = detector()
|
||
if matches:
|
||
best = matches[0]
|
||
best_paper_id = best.get("paper_id")
|
||
best_match = best
|
||
best_stage = stage_name
|
||
break
|
||
except Exception:
|
||
continue
|
||
|
||
# Fallback: generic keyword search
|
||
if not best_paper_id:
|
||
kw = extract_keywords(name + " " + eq_text + " " + route_hint)
|
||
results = search_papers(kw)
|
||
if results and results[0]["score"] >= 3:
|
||
best_paper_id = results[0]["paper_id"]
|
||
best_match = results[0]
|
||
best_stage = "kernel_refine_v1"
|
||
|
||
# Compute manifold assignment
|
||
slack, regime = _compute_regime(best_match)
|
||
sidon_label, strand = _assign_label(name)
|
||
manifold_route = _guess_route(name, eq_text, route_hint)
|
||
# Coherence: a geometry-kernel match implies the geometry/topology route,
|
||
# overriding the keyword route-guess (which lacks geometry vocabulary like
|
||
# "perelman"/"chern"). Only applied when the caller gave no explicit hint.
|
||
if (best_match and str(best_match.get("match_type", "")).startswith("geometry")
|
||
and (not route_hint or route_hint == "?")):
|
||
manifold_route = "geometry_topology"
|
||
|
||
result = {
|
||
"name": name,
|
||
"equation_snippet": eq_text[:100],
|
||
"classified_at": time.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
||
"match": {
|
||
"paper_id": best_paper_id,
|
||
"title": best_match.get("title", "") if best_match else "",
|
||
"score": best_match.get("score", 0) if best_match else 0,
|
||
"stage": best_stage,
|
||
"match_type": best_match.get("match_type", "") if best_match else "",
|
||
"signals": best_match.get("signals", []) if best_match else [],
|
||
},
|
||
"manifold": {
|
||
"route": manifold_route,
|
||
"regime": regime,
|
||
"slack": slack,
|
||
"sidon_label": sidon_label,
|
||
"strand": strand,
|
||
},
|
||
"classification": "classified" if best_paper_id else "unmatched",
|
||
}
|
||
|
||
return result
|
||
|
||
|
||
def _compute_regime(match: dict | None) -> tuple[int, str]:
|
||
if match is None:
|
||
return 0, "unclassified"
|
||
score = match.get("score", 0)
|
||
if isinstance(score, str):
|
||
try:
|
||
score = int(score)
|
||
except ValueError:
|
||
score = 0
|
||
# Geometry/topology eqs sit off the Sidon diophantine axis — label them
|
||
# by curvature regime instead of (anti_)diophantine slack.
|
||
if str(match.get("match_type", "")).startswith("geometry"):
|
||
return (64 if score >= 6 else 16), "riemannian"
|
||
if score >= 100:
|
||
return 128, "anti_diophantine"
|
||
elif score >= 20:
|
||
return 64, "transition"
|
||
elif score >= 5:
|
||
return 16, "transition_tight"
|
||
return 4, "diophantine"
|
||
|
||
|
||
def _assign_label(name: str) -> tuple[int, int]:
|
||
labels = [1, 2, 4, 8, 16, 32, 64, 128]
|
||
idx = hash(name) % len(labels)
|
||
return labels[idx], idx
|
||
|
||
|
||
def _guess_route(name: str, eq_text: str, route_hint: str) -> str:
|
||
if route_hint and route_hint != "?":
|
||
return route_hint
|
||
combined = (name + " " + eq_text).lower()
|
||
route_patterns = [
|
||
("thermodynamic_energy", ["energy", "entropy", "heat", "temperature", "thermo"]),
|
||
("geometry_topology", ["geometry", "metric", "manifold", "curvature", "geodesic"]),
|
||
("cognitive_load", ["cognitive", "load", "emotional", "signal", "gate"]),
|
||
("compression_route", ["compress", "encoding", "codec", "hutter", "entropy"]),
|
||
("magnetic_signal", ["magnetic", "field", "plasma", "wave"]),
|
||
("control_signal", ["control", "overflow", "gain", "threshold", "tuning"]),
|
||
("number_theory", ["prime", "modulo", "sidon", "sumset", "additive", "bound"]),
|
||
("chaotic_couch", ["chaotic", "couch", "soliton", "turbulence"]),
|
||
]
|
||
best_route, best_score = "unclassified", 0
|
||
for route, kws in route_patterns:
|
||
score = sum(3 for kw in kws if kw in combined)
|
||
if score > best_score:
|
||
best_score = score
|
||
best_route = route
|
||
return best_route
|
||
|
||
|
||
def self_test():
|
||
"""Self-test: classify a set of known equations to verify pipeline."""
|
||
test_cases = [
|
||
{"name": "sidon_maximum_bound", "equation": "|A| ≤ √(2N) + 1", "route": "number_theory"},
|
||
{"name": "sumset_growth", "equation": "|A+A| ≥ |A|(|A|−1)/2", "route": "combinatorics"},
|
||
{"name": "baker_lower_bound", "equation": "log|Λ| > −C·log(H₁)·log(H₂)", "route": "number_theory"},
|
||
{"name": "entropy_rate", "equation": "H(X|Y) = H(X) − I(X;Y)", "route": "thermodynamic_energy"},
|
||
{"name": "geodesic_equation", "equation": "d²x^i/ds² + Γ^i_jk dx^j/ds dx^k/ds = 0", "route": "geometry_topology"},
|
||
{"name": "sidon_set_collision", "equation": "a + b = c + d ⇒ {a,b} = {c,d}", "route": "number_theory"},
|
||
{"name": "singer_construction", "equation": "|D| = q+1, D ⊂ ℤ_{q²+q+1}", "route": "number_theory"},
|
||
{"name": "cap_set_bound", "equation": "|A| ≤ 3·(2.756)^n", "route": "number_theory"},
|
||
{"name": "CAUCHY_DAVENPORT", "equation": "|A+B| ≥ min(p, |A|+|B|−1)", "route": "number_theory"},
|
||
{"name": "emotional_gate", "equation": "G_em = max(0, L_em − T_em)", "route": "cognitive_load"},
|
||
]
|
||
|
||
print("=" * 60)
|
||
print("RRC Self-Classification Test")
|
||
print("=" * 60)
|
||
|
||
results = []
|
||
for tc in test_cases:
|
||
result = classify_equation(tc["name"], tc["equation"], tc["route"])
|
||
results.append(result)
|
||
|
||
stage = result["match"]["stage"] or "NONE"
|
||
paper = result["match"]["paper_id"] or "—"
|
||
route = result["manifold"]["route"]
|
||
regime = result["manifold"]["regime"]
|
||
status = "✓" if result["classification"] == "classified" else "✗"
|
||
|
||
print(f"\n {status} {tc['name']:35s} {stage:20s} {route:25s} {regime:15s}")
|
||
print(f" → paper={paper}")
|
||
print(f" → {tc['equation'][:60]}")
|
||
signals = result["match"].get("signals", [])
|
||
if signals:
|
||
print(f" → signals: {', '.join(signals)}")
|
||
|
||
# Summary
|
||
classified = sum(1 for r in results if r["classification"] == "classified")
|
||
print(f"\n{'='*60}")
|
||
print(f" Classified: {classified}/{len(results)}")
|
||
for stage in set(r["match"]["stage"] for r in results if r["match"]["stage"]):
|
||
cnt = sum(1 for r in results if r["match"]["stage"] == stage)
|
||
print(f" {stage:25s} {cnt}")
|
||
|
||
|
||
def main():
|
||
import argparse
|
||
ap = argparse.ArgumentParser(description="RRC Self-Classifying Pipeline")
|
||
ap.add_argument("--name", type=str, help="Equation name")
|
||
ap.add_argument("--equation", type=str, help="Equation LaTeX")
|
||
ap.add_argument("--route", type=str, default="", help="Route hint")
|
||
ap.add_argument("--self-test", action="store_true", help="Run self-test")
|
||
args = ap.parse_args()
|
||
|
||
if args.self_test:
|
||
self_test()
|
||
return
|
||
|
||
if not args.name or not args.equation:
|
||
print("ERROR: --name and --equation required (or --self-test)", file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
result = classify_equation(args.name, args.equation, args.route)
|
||
print(json.dumps(result, indent=2, ensure_ascii=False))
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|