mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
238 lines
7.8 KiB
Python
238 lines
7.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Tiny PDE-style replay harness.
|
|
|
|
This is the first local replay fixture for the PDEBench route surface. It uses
|
|
deterministic built-in micro-fixtures only: no external PDEBench data is
|
|
downloaded, vendored, or scored.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import json
|
|
from dataclasses import dataclass
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
|
|
REPO = Path(__file__).resolve().parents[2]
|
|
OUT_DIR = REPO / "shared-data" / "data" / "pde_tiny_replay"
|
|
RECEIPT = OUT_DIR / "pde_tiny_replay_receipt.json"
|
|
TABLE = OUT_DIR / "pde_tiny_replay_table.jsonl"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class Fixture:
|
|
fixture_id: str
|
|
route_surface: str
|
|
law_family: str
|
|
grid_n: int
|
|
steps: int
|
|
shift_per_step: int
|
|
truth_boundary: str
|
|
candidate_boundary: str
|
|
initial_support: list[int]
|
|
negative_control: bool
|
|
|
|
|
|
FIXTURES = [
|
|
Fixture(
|
|
fixture_id="advection_periodic_exact_shift_admit",
|
|
route_surface="PDEBench",
|
|
law_family="linear_advection_integer_cfl",
|
|
grid_n=64,
|
|
steps=48,
|
|
shift_per_step=1,
|
|
truth_boundary="periodic",
|
|
candidate_boundary="periodic",
|
|
initial_support=[0, 3, 7, 15, 31],
|
|
negative_control=False,
|
|
),
|
|
Fixture(
|
|
fixture_id="advection_wrong_boundary_negative",
|
|
route_surface="PDEBench",
|
|
law_family="linear_advection_integer_cfl",
|
|
grid_n=64,
|
|
steps=48,
|
|
shift_per_step=1,
|
|
truth_boundary="periodic",
|
|
candidate_boundary="zero_outflow",
|
|
initial_support=[0, 3, 7, 15, 31],
|
|
negative_control=True,
|
|
),
|
|
Fixture(
|
|
fixture_id="advection_short_exact_hold_diagnostic",
|
|
route_surface="PDEBench",
|
|
law_family="linear_advection_integer_cfl",
|
|
grid_n=8,
|
|
steps=2,
|
|
shift_per_step=1,
|
|
truth_boundary="periodic",
|
|
candidate_boundary="periodic",
|
|
initial_support=[0, 3],
|
|
negative_control=False,
|
|
),
|
|
]
|
|
|
|
|
|
def stable_json(obj: Any) -> str:
|
|
return json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=True)
|
|
|
|
|
|
def sha256_text(text: str) -> str:
|
|
return hashlib.sha256(text.encode("utf-8", errors="replace")).hexdigest()
|
|
|
|
|
|
def rel(path: Path) -> str:
|
|
return str(path.relative_to(REPO))
|
|
|
|
|
|
def initial_state(grid_n: int, support: list[int]) -> list[int]:
|
|
values = [0] * grid_n
|
|
for index in support:
|
|
values[index % grid_n] = 1
|
|
return values
|
|
|
|
|
|
def step_advection(values: list[int], shift: int, boundary: str) -> list[int]:
|
|
out = [0] * len(values)
|
|
for index, value in enumerate(values):
|
|
target = index + shift
|
|
if boundary == "periodic":
|
|
out[target % len(values)] = value
|
|
elif boundary == "zero_outflow":
|
|
if 0 <= target < len(values):
|
|
out[target] = value
|
|
else:
|
|
raise ValueError(f"unsupported boundary {boundary}")
|
|
return out
|
|
|
|
|
|
def trajectory(fixture: Fixture, boundary: str) -> list[list[int]]:
|
|
rows = [initial_state(fixture.grid_n, fixture.initial_support)]
|
|
for _ in range(fixture.steps):
|
|
rows.append(step_advection(rows[-1], fixture.shift_per_step, boundary))
|
|
return rows
|
|
|
|
|
|
def mismatch_rows(truth: list[list[int]], candidate: list[list[int]]) -> list[dict[str, int]]:
|
|
mismatches: list[dict[str, int]] = []
|
|
for t_index, (truth_row, candidate_row) in enumerate(zip(truth, candidate)):
|
|
for x_index, (truth_value, candidate_value) in enumerate(zip(truth_row, candidate_row)):
|
|
if truth_value != candidate_value:
|
|
mismatches.append(
|
|
{
|
|
"t": t_index,
|
|
"x": x_index,
|
|
"truth": truth_value,
|
|
"candidate": candidate_value,
|
|
}
|
|
)
|
|
return mismatches
|
|
|
|
|
|
def run_fixture(fixture: Fixture) -> dict[str, Any]:
|
|
truth = trajectory(fixture, fixture.truth_boundary)
|
|
candidate = trajectory(fixture, fixture.candidate_boundary)
|
|
mismatches = mismatch_rows(truth, candidate)
|
|
replay_valid = not mismatches
|
|
residual_declared = True
|
|
|
|
encoded_payload = {
|
|
"law_family": fixture.law_family,
|
|
"grid_n": fixture.grid_n,
|
|
"steps": fixture.steps,
|
|
"shift_per_step": fixture.shift_per_step,
|
|
"boundary": fixture.candidate_boundary,
|
|
"initial_support": fixture.initial_support,
|
|
}
|
|
explicit_payload = {
|
|
"trajectory": truth,
|
|
}
|
|
residual_payload = {"mismatches": mismatches}
|
|
|
|
encoded_bytes = len(stable_json(encoded_payload).encode("utf-8"))
|
|
explicit_bytes = len(stable_json(explicit_payload).encode("utf-8"))
|
|
residual_bytes = 0 if replay_valid else len(stable_json(residual_payload).encode("utf-8"))
|
|
total_candidate_bytes = encoded_bytes + residual_bytes
|
|
byte_gain = explicit_bytes - total_candidate_bytes
|
|
|
|
if fixture.negative_control and replay_valid:
|
|
status = "FAIL_NEGATIVE_CONTROL"
|
|
elif replay_valid and residual_declared and byte_gain > 0 and not fixture.negative_control:
|
|
status = "ADMIT_FIXTURE"
|
|
else:
|
|
status = "HOLD_DIAGNOSTIC"
|
|
|
|
result = {
|
|
"fixture_id": fixture.fixture_id,
|
|
"route_surface": fixture.route_surface,
|
|
"law_family": fixture.law_family,
|
|
"truth_boundary": fixture.truth_boundary,
|
|
"candidate_boundary": fixture.candidate_boundary,
|
|
"negative_control": fixture.negative_control,
|
|
"grid_n": fixture.grid_n,
|
|
"steps": fixture.steps,
|
|
"shift_per_step": fixture.shift_per_step,
|
|
"initial_support": fixture.initial_support,
|
|
"trajectory_hash": sha256_text(stable_json(truth)),
|
|
"candidate_hash": sha256_text(stable_json(candidate)),
|
|
"mismatch_count": len(mismatches),
|
|
"replay_valid": replay_valid,
|
|
"residual_declared": residual_declared,
|
|
"encoded_bytes": encoded_bytes,
|
|
"explicit_bytes": explicit_bytes,
|
|
"residual_bytes": residual_bytes,
|
|
"byte_gain": byte_gain,
|
|
"status": status,
|
|
}
|
|
result["result_hash"] = sha256_text(stable_json({k: v for k, v in result.items() if k != "result_hash"}))
|
|
return result
|
|
|
|
|
|
def main() -> int:
|
|
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
results = [run_fixture(fixture) for fixture in FIXTURES]
|
|
with TABLE.open("w", encoding="utf-8") as handle:
|
|
for result in results:
|
|
handle.write(json.dumps(result, sort_keys=True) + "\n")
|
|
|
|
status_values = sorted({result["status"] for result in results})
|
|
receipt = {
|
|
"schema": "pde_tiny_replay_receipt_v1",
|
|
"generated_at_utc": datetime.now(timezone.utc).isoformat(),
|
|
"fixture_count": len(results),
|
|
"table": rel(TABLE),
|
|
"status_counts": {
|
|
status: sum(1 for result in results if result["status"] == status)
|
|
for status in status_values
|
|
},
|
|
"results": results,
|
|
"decision": "HOLD",
|
|
"claim_boundary": (
|
|
"Tiny PDE-style replay fixture only. It tests deterministic local "
|
|
"advection replay, wrong-boundary negative controls, residual "
|
|
"accounting, and byte-law diagnostics; it is not PDEBench data ingest, "
|
|
"not a PDEBench benchmark score, and not a compression benchmark."
|
|
),
|
|
}
|
|
receipt["receipt_hash"] = sha256_text(stable_json({k: v for k, v in receipt.items() if k != "receipt_hash"}))
|
|
RECEIPT.write_text(json.dumps(receipt, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
|
print(
|
|
json.dumps(
|
|
{
|
|
"receipt": rel(RECEIPT),
|
|
"table": rel(TABLE),
|
|
"receipt_hash": receipt["receipt_hash"],
|
|
"status_counts": receipt["status_counts"],
|
|
},
|
|
indent=2,
|
|
sort_keys=True,
|
|
)
|
|
)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|