强化学习第一版
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
"""Offline audit of official RL practice runs (Q3/Q4); never connects to simulator.
|
||||
|
||||
Checks the copied official .result.json/.jlog, our session.jsonl and summary.json:
|
||||
package sha256, enter/exit, accepted timestamps inside official window, unique
|
||||
request ids, clear-success channel count == official jammer_count, summary
|
||||
consistency, and virtual time recomputation with integer microsecond accumulation.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def save_json(path: Path, value: dict) -> None:
|
||||
path.write_text(json.dumps(value, ensure_ascii=False, indent=2,
|
||||
allow_nan=False) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def audit(folder: Path) -> dict:
|
||||
records = [json.loads(line) for line in
|
||||
(folder / "session.jsonl").read_text(encoding="utf-8").splitlines()]
|
||||
events = [e for e in records if e.get("event") == "accepted"]
|
||||
summary = json.loads((folder / "summary.json").read_text(encoding="utf-8"))
|
||||
official_paths = list(folder.glob("*.result.json"))
|
||||
if len(official_paths) != 1 or not events:
|
||||
raise ValueError("Expected one official result and nonempty session evidence")
|
||||
official = json.loads(official_paths[0].read_text(encoding="utf-8"))
|
||||
package = official_paths[0].with_name(
|
||||
official_paths[0].name.replace(".result.json", ".jlog"))
|
||||
checks: dict = {}
|
||||
|
||||
checks["official_problem_matches_summary"] = (
|
||||
official["problem_no"] in (3, 4)
|
||||
and summary["strategy"] in ("rl", "rl_q4")
|
||||
and 10 <= official["jammer_count"] <= 16
|
||||
and official["omnidirectional_jammer_count"] + official["directional_jammer_count"]
|
||||
== official["jammer_count"])
|
||||
checks["official_package_sha256_matches"] = (
|
||||
hashlib.sha256(package.read_bytes()).hexdigest() == official["package_sha256"])
|
||||
checks["normal_enter_and_exit"] = (
|
||||
events[0]["path"] == "/enter" and events[-1]["path"] == "/exit"
|
||||
and events[-1]["response"].get("exit_reason") == "user_exit")
|
||||
start_ms = datetime.fromisoformat(official["window_started_at_utc"]).timestamp() * 1000
|
||||
end_ms = datetime.fromisoformat(official["ended_at_utc"]).timestamp() * 1000
|
||||
checks["responses_within_official_run_window"] = all(
|
||||
start_ms <= e["response"]["real_timestamp_ms"] <= end_ms + 1 for e in events)
|
||||
ids = [e["request"]["request_id"] for e in events]
|
||||
checks["unique_accepted_request_ids"] = len(ids) == len(set(ids))
|
||||
clears = [e for e in events if e["path"] == "/clear"]
|
||||
successes = [e for e in clears if e["response"].get("clear_result") == "success"]
|
||||
cleared = sorted({e["request"]["channel"] for e in successes})
|
||||
checks["all_official_sources_cleared"] = len(cleared) == official["jammer_count"]
|
||||
checks["summary_completed_and_consistent"] = (
|
||||
bool(summary["completed"])
|
||||
and sorted(summary["cleared_channels"]) == cleared
|
||||
and summary["unresolved_channels"] == []
|
||||
and summary["anomalies"] == [])
|
||||
|
||||
position, channel, virtual_us = (0.0, 0.0), 1, 0
|
||||
mismatches = 0
|
||||
for event in events:
|
||||
request, response, path = event["request"], event["response"], event["path"]
|
||||
distance, switches, action_s = 0.0, 0, 0
|
||||
if path in ("/measure", "/clear"):
|
||||
target = (request["position"]["x"], request["position"]["y"])
|
||||
distance = math.dist(position, target)
|
||||
position = target
|
||||
if path == "/measure":
|
||||
switches = int(channel != request["channel"])
|
||||
channel = request["channel"]
|
||||
action_s = 5
|
||||
else:
|
||||
action_s = 5 if response["clear_result"] == "success" else 3
|
||||
virtual_us += round(distance / 5 * 1_000_000) + (switches + action_s) * 1_000_000
|
||||
if round(response["virtual_time_s"] * 1_000_000) != virtual_us:
|
||||
mismatches += 1
|
||||
checks["all_timestamps_match_microsecond_recomputation"] = mismatches == 0
|
||||
real_s = (events[-1]["response"]["real_timestamp_ms"]
|
||||
- events[0]["response"]["real_timestamp_ms"]) / 1000
|
||||
checks["within_real_and_virtual_limits"] = (
|
||||
real_s < events[0]["response"]["remaining_real_duration_s"]
|
||||
and virtual_us / 1_000_000 < events[0]["response"]["max_virtual_duration_s"])
|
||||
|
||||
report = {
|
||||
"passed": all(checks.values()),
|
||||
"source": "official_practice",
|
||||
"strategy": summary["strategy"],
|
||||
"problem": official["problem_no"],
|
||||
"case_code": official["case_code"],
|
||||
"official_jammer_count": official["jammer_count"],
|
||||
"directional_jammer_count": official["directional_jammer_count"],
|
||||
"cleared_channels": cleared,
|
||||
"accepted_requests_including_enter_exit": len(events),
|
||||
"measures": len([e for e in events if e["path"] == "/measure"]),
|
||||
"clear_attempts": len(clears),
|
||||
"clear_successes": len(successes),
|
||||
"virtual_time_s": virtual_us / 1_000_000,
|
||||
"real_elapsed_server_s": real_s,
|
||||
"checks": checks,
|
||||
"limits": "仅验证本官方演练案例;不触碰正式测试,不解读官方加密日志内容。",
|
||||
}
|
||||
save_json(folder / "verification.json", report)
|
||||
manifest = {p.name: {"bytes": p.stat().st_size,
|
||||
"sha256": hashlib.sha256(p.read_bytes()).hexdigest()}
|
||||
for p in sorted(folder.iterdir()) if p.is_file()
|
||||
and p.name != "manifest.json"}
|
||||
save_json(folder / "manifest.json", manifest)
|
||||
return report
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("folder", type=Path)
|
||||
args = parser.parse_args()
|
||||
report = audit(args.folder)
|
||||
print(json.dumps({"passed": report["passed"], "case_code": report["case_code"],
|
||||
"problem": report["problem"], "checks": report["checks"]},
|
||||
ensure_ascii=False, indent=2))
|
||||
raise SystemExit(0 if report["passed"] else 1)
|
||||
Reference in New Issue
Block a user