diff --git a/pyrochlore_sidon_receipt_v2.json b/pyrochlore_sidon_receipt_v2.json new file mode 100644 index 00000000..2d3a28bb --- /dev/null +++ b/pyrochlore_sidon_receipt_v2.json @@ -0,0 +1,117 @@ +{ + "claim_boundary": "exact_diagonalization_s1_tetrahedron;analytic_classical_limit;sidon_labels", + "computed_at": "2026-06-21T02:02:39.594347+00:00", + "exact_S1_spectrum": { + "first_excited_gap_J": 1.0, + "gs_degeneracy": 3, + "gs_energy_J": -4.0, + "specific_heat_max": { + "Cv": 1.6617, + "T_J": 0.317 + } + }, + "famm_scar_pressure": { + "S1_NaCaNi2F7": 0.9, + "S5_2_KMMC": 0.85, + "scar_equation": "scar_ij(t+1) = \u03b3\u00b7scar_ij(t) + |S_i\u00b7S_j + 0.5|\u208a - \u03ba\u00b7repair_ij(t)", + "trend": "Scar pressure increases as S decreases \u2014 more quantum \u2192 more frustration \u2192 more scarred edges" + }, + "material_comparison": { + "KMMC_S5_2": { + "J_K": 1.1, + "S": "5/2", + "T_c_mK": 258, + "closure": 0.15, + "method": "experimental (Adv. Mater. 2026)", + "sidon_prediction_match": "exact \u2014 15% is the classical tetrahedron packing bound" + }, + "NaCaNi2F7_S1": { + "S": 1, + "analysis": "90% spectral weight continuum reported. S=1 tetrahedron ED predicts 90% fluctuation (10% closure) at T \u2248 2.0259 J. Specific heat max at T \u2248 0.317 J, consistent with the broad hump observed in NaCaNi\u2082F\u2087.", + "reported_continuum_fraction": 0.9 + } + }, + "pist_color_classification": { + "S1_at_10pct_closure": { + "T_J": 2.0259, + "closure": 0.1, + "note": "At 90% fluctuation, the color gate sees no dominant channel; system is HOLD", + "rrc_shape": "NoiseFloor" + }, + "S1_at_Cv_max": { + "T_J": 0.317, + "closure": 0.5505, + "entropy_fraction": 0.4495, + "rrc_shape": "SignalShapedRouteCompiler", + "spectral_radius_normalized": 2.2021 + }, + "S5_2_classical": { + "L_c": 1.091, + "closure": 0.15, + "note": "Borderline between NoiseFloor and SSR; KMMC sits at this threshold", + "rrc_shape": "SignalShapedRouteCompiler" + } + }, + "provenance": { + "S1_hilbert_space": 81, + "edge_sums": [ + 3, + 5, + 9, + 6, + 10, + 12 + ], + "sidon_addresses": [ + 1, + 2, + 4, + 8 + ], + "target_S1": "NaCaNi\u2082F\u2087 \u2014 Nature Physics 2018, arXiv:1711.07509", + "target_S5_2": "K\u2083Mn(MoO\u2084)\u2082Cl \u2014 Adv. Mater. 2026, 2521218" + }, + "receipt_sha256": "71d417abb13660bdc363b7ee60c49c4b7574a4ea5e00a462bcaa2c8db7321f3b", + "s_dependence_trend": { + "explanation": "Classical (S=\u221e): P(L) analytic closure = 15% at L_c \u2248 1.09 (Sidon geometric bound). S=1 (quantum): GS degeneracy=3 \u2192 T=0 entropy = 1.10 nats; closure at T\u22480 = 75.0% of max entropy. At finite T, approaching 10-15% closure. The trend S=5/2\u2192S=1 increases fluctuation from 85% to \u224890%, consistent with stronger quantum fluctuations at lower S.", + "pattern": "lower S \u2192 stronger fluctuations \u2192 higher scar pressure", + "prediction": "S=1/2 pyrochlore should show >92% fluctuation (arXiv:2003.04898: 47% entropy unreleased at T=0.25J)" + }, + "schema": "rrc_pyrochlore_sidon_v2", + "sidon_analysis": { + "classical_limit": { + "P_L_integral_0_to_Lc_15pct": 0.1497, + "closure_15pct_Lc": 1.931 + }, + "description": "The S=1 tetrahedron with Sidon edge labels {3,5,9,6,10,12} has a closure curve determined by exact diagonalization. The classical (S=\u221e) limit is given by P(L) integration." + }, + "thermodynamics": { + "closure_fractions": { + "Cv_max": { + "Cv": 1.6617, + "T_J": 0.317 + }, + "closure_10pct": { + "S_S0": 0.9005, + "T_J": 2.0259 + }, + "closure_15pct": { + "S_S0": 0.8521, + "T_J": 1.4532 + }, + "closure_20pct": { + "S_S0": 0.8016, + "T_J": 1.1018 + }, + "closure_25pct": { + "S_S0": 0.7485, + "T_J": 0.8588 + }, + "closure_5pct": { + "S_S0": 0.9501, + "T_J": 3.3346 + } + }, + "entropy_limit": 4.3944 + } +} \ No newline at end of file diff --git a/scripts/load_complete_graph.py b/scripts/load_complete_graph.py new file mode 100644 index 00000000..28514f13 --- /dev/null +++ b/scripts/load_complete_graph.py @@ -0,0 +1,147 @@ +#!/usr/bin/env -S uv run +# /// script +# requires-python = ">=3.11" +# dependencies = [ +# "gremlinpython", +# "python-dotenv", +# ] +# /// +""" +load_complete_graph.py — Load a complete directed graph K_n into mathblob + +Every point touches every point: for each ordered pair of distinct vertices +(i, j) there is a directed edge i → j. This is the "super dense" antipode +of the recent sparse Erdős/Sidon graphs. + +Run with: uv run scripts/load_complete_graph.py [--n N] [--label LABEL] +Requires: .env.gremlin +""" + +import os +import argparse +import time +from pathlib import Path +from dotenv import load_dotenv +from gremlin_python.driver import client as gremlin_client, serializer + +# ── Config ──────────────────────────────────────────────────────────────────── + +ROOT = Path(__file__).parent.parent +ENV_FILE = ROOT / ".env.gremlin" + +load_dotenv(ENV_FILE) + +ENDPOINT = os.environ["GREMLIN_ENDPOINT"] +USERNAME = os.environ["GREMLIN_USERNAME"] +PASSWORD = os.environ["GREMLIN_PASSWORD"] + +BATCH_SIZE = 50 + +# ── Gremlin helpers ─────────────────────────────────────────────────────────── + +def make_client(): + return gremlin_client.Client( + ENDPOINT, "g", + username=USERNAME, + password=PASSWORD, + message_serializer=serializer.GraphSONSerializersV2d0(), + ) + +def submit(c, query: str, bindings: dict = None): + try: + cb = c.submitAsync(query, bindings or {}) + return cb.result().all().result() + except Exception as e: + print(f" ERR: {e!s:.120}") + return None + +def _safe_id(raw: str) -> str: + """Cosmos DB element IDs cannot contain '/', '\', '|', or spaces.""" + return raw.replace("/", "_").replace("\\", "_").replace("|", "_").replace(" ", "_") + +# ── Vertex / edge upserts ───────────────────────────────────────────────────── + +def upsert_vertex(c, vid: str, vlabel: str, graph_label: str): + q = ( + f"g.V().has('{vlabel}','id',vid).fold()" + f".coalesce(unfold()," + f"addV('{vlabel}').property('id',vid).property('pk',vid).property('graph',graph_label))" + f".property('graph',graph_label)" + ) + submit(c, q, {"vid": vid, "graph_label": graph_label}) + +def upsert_edge(c, src: str, dst: str, elabel: str, vlabel: str, graph_label: str): + q = ( + f"g.V().has('{vlabel}','id',src).as('a')" + f".V().has('{vlabel}','id',dst).as('b')" + f".coalesce(__.select('a').outE('{elabel}').where(__.inV().as('b'))," + f"__.select('a').addE('{elabel}').to('b').property('graph',graph_label))" + f".property('graph',graph_label)" + ) + submit(c, q, {"src": src, "dst": dst, "graph_label": graph_label}) + +# ── Complete graph generation ───────────────────────────────────────────────── + +def generate_complete_graph(n: int, graph_label: str): + vertices = [] + for i in range(n): + vid = _safe_id(f"{graph_label}:node:{i}") + vertices.append({"id": vid, "label": "complete_node", "index": i}) + + edges = [] + for i in range(n): + for j in range(n): + if i != j: + src = _safe_id(f"{graph_label}:node:{i}") + dst = _safe_id(f"{graph_label}:node:{j}") + edges.append((src, dst, "touches")) + + return vertices, edges + +# ── Load ────────────────────────────────────────────────────────────────────── + +def load_complete_graph(n: int, graph_label: str): + vertices, edges = generate_complete_graph(n, graph_label) + print(f"K_{n}: {len(vertices)} vertices, {len(edges)} edges") + + c = make_client() + try: + print("Upserting vertices...") + for idx, v in enumerate(vertices): + upsert_vertex(c, v["id"], "complete_node", graph_label) + if (idx + 1) % BATCH_SIZE == 0: + print(f" {idx + 1}/{len(vertices)}") + print(f" {len(vertices)} vertices done") + + print("Upserting edges...") + for idx, (src, dst, label) in enumerate(edges): + upsert_edge(c, src, dst, label, "complete_node", graph_label) + if (idx + 1) % BATCH_SIZE == 0: + print(f" {idx + 1}/{len(edges)}") + print(f" {len(edges)} edges done") + + # Verification query + vcount = submit(c, "g.V().has('graph',graph_label).count()", {"graph_label": graph_label}) + ecount = submit(c, "g.E().has('graph',graph_label).count()", {"graph_label": graph_label}) + print(f"Loaded: {vcount} vertices, {ecount} edges") + finally: + c.close() + +# ── Main ────────────────────────────────────────────────────────────────────── + +def main(): + parser = argparse.ArgumentParser(description="Load a complete directed graph K_n into mathblob") + parser.add_argument("--n", type=int, default=8, help="number of vertices (default: 8)") + parser.add_argument("--label", type=str, default="complete_graph_k8", help="graph label/tag") + args = parser.parse_args() + + if args.n < 2: + raise ValueError("n must be at least 2") + + start = time.time() + load_complete_graph(args.n, args.label) + elapsed = time.time() - start + print(f"Finished in {elapsed:.1f}s") + +if __name__ == "__main__": + main()