feat(SR): complete article-grade symbolic regression evidence

Freeze the contract-audited discovery, closed-loop validation, robustness, plotting, and manuscript evidence so the SR section is reproducible and ready for paper development.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Frank14f
2026-07-21 20:06:13 +08:00
co-authored by Cursor
parent ca8ee5f238
commit eac8c0018e
1039 changed files with 292934 additions and 1496 deletions
+91
View File
@@ -0,0 +1,91 @@
#!/usr/bin/env python3
"""Verify recorded PPO actions by replaying the policy on causal recorded states."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from typing import Any, Sequence
import numpy as np
from SR_analysis.configs import get_scene, model_path_for_scene
from SR_analysis.stage_1_infer import illusion_observation, load_existing_norm, normalize_raw_observation
from SR_analysis.utils.cfd_interface import load_ppo_model
from SR_analysis.utils.provenance import atomic_write_json, hash_file
SCHEMA_VERSION = "sr-policy-replay-parity-v1"
def replay(scene: str, trajectory: Path, *, model_device: str = "cpu") -> dict[str, Any]:
cfg = get_scene(scene)
norm, norm_path = load_existing_norm(scene, cfg)
model_path = model_path_for_scene(scene)
if model_path is None:
raise FileNotFoundError(f"no PPO model configured for {scene}")
model = load_ppo_model(model_path, device=model_device, s_dim=int(cfg["s_dim"]))
with np.load(trajectory, allow_pickle=False) as data:
sensors = np.asarray(data["sensors"], dtype=np.float64)
forces = np.asarray(data["forces"], dtype=np.float64)
actions = np.asarray(data["actions_norm" if "actions_norm" in data else "actions"], dtype=np.float64)
targets = np.asarray(data["target_forces"], dtype=np.float64) if "target_forces" in data else None
if len(actions) < 2:
raise ValueError("policy replay requires at least two recorded actions")
raw = np.column_stack((sensors, forces))
predicted = []
for index in range(1, len(actions)):
state = raw[index - 1]
if cfg["scene_id"] == "illusion":
if targets is None:
raise ValueError("Illusion policy replay requires target_forces")
observation = illusion_observation(state, norm, targets[index])
else:
observation = normalize_raw_observation(state, norm)
action, _ = model.predict(observation, deterministic=True)
predicted.append(np.asarray(action, dtype=np.float64).reshape(3))
predicted_array = np.asarray(predicted)
recorded = actions[1:]
residual = predicted_array - recorded
max_abs = np.max(np.abs(residual), axis=0)
rmse = np.sqrt(np.mean(residual**2, axis=0))
tolerance = 2e-6
return {
"schema_version": SCHEMA_VERSION,
"scene": scene,
"status": "passed" if float(np.max(max_abs)) <= tolerance else "failed",
"semantics": "recorded post-state i-1 is replayed to predict recorded normalized action i; first action is excluded because its pre-state is not stored",
"tolerance": tolerance,
"n_compared": int(len(recorded)),
"action_layout": list(cfg["action_layout"]),
"max_abs_error": max_abs.tolist(),
"rmse": rmse.tolist(),
"sources": {
"trajectory": {"path": str(trajectory), "sha256": hash_file(trajectory)},
"model": {"path": str(model_path), "sha256": hash_file(Path(model_path))},
"norm": {"path": str(norm_path), "sha256": hash_file(norm_path)},
},
"interpretation": "This checks policy observation/action wiring without requiring separately initialized CFD trajectories to be pointwise identical.",
}
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--scene", required=True)
parser.add_argument("--trajectory", type=Path, required=True)
parser.add_argument("--model-device", default="cpu")
parser.add_argument("--output", type=Path, required=True)
return parser
def main(argv: Sequence[str] | None = None) -> int:
args = build_parser().parse_args(argv)
report = replay(args.scene, args.trajectory.resolve(), model_device=args.model_device)
atomic_write_json(args.output.resolve(), report)
print(json.dumps(report, indent=2, sort_keys=True))
return 0 if report["status"] == "passed" else 1
if __name__ == "__main__":
raise SystemExit(main())