From 98daef54ca999d74819f0336caa69958a85eaac8 Mon Sep 17 00:00:00 2001 From: Huang Qi Date: Tue, 12 May 2026 00:19:39 +0800 Subject: [PATCH] test: capture mouse generate() golden output (pre-migration) --- scripts/build_golden_mouse.py | 49 +++++++++++++++++++++++++++++++ tests/unit/data/golden_mouse.npz | Bin 0 -> 18962 bytes 2 files changed, 49 insertions(+) create mode 100644 scripts/build_golden_mouse.py create mode 100644 tests/unit/data/golden_mouse.npz diff --git a/scripts/build_golden_mouse.py b/scripts/build_golden_mouse.py new file mode 100644 index 0000000..a30dfa3 --- /dev/null +++ b/scripts/build_golden_mouse.py @@ -0,0 +1,49 @@ +"""One-shot script to capture golden mouse trajectories from the current torch +implementation. Run BEFORE the migration so we can verify the numpy/ORT rewrite +in Phase 4 produces equivalent output. + +Output: tests/unit/data/golden_mouse.npz +""" +from __future__ import annotations + +import random +import sys +from pathlib import Path + +# Allow running as `uv run python scripts/build_golden_mouse.py` from project root. +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) + +import numpy as np +import torch + +from ai_mouse import generate + +CASES: list[tuple[tuple[int, int], tuple[int, int]]] = [ + ((100, 200), (900, 400)), # horizontal 800px + ((500, 500), (500, 100)), # vertical 400px upward + ((200, 600), (800, 200)), # 720px diagonal + ((100, 100), (130, 110)), # very short 31px + ((50, 50), (1500, 900)), # very long 1700px + ((400, 300), (500, 300)), # short horizontal 100px + ((300, 300), (700, 700)), # 45° diagonal + ((600, 400), (200, 100)), # reverse diagonal +] +SEEDS = (0, 1, 2, 3) + + +def main() -> None: + out: dict[str, np.ndarray] = {} + for case_idx, (start, end) in enumerate(CASES): + for seed in SEEDS: + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + pts = generate(start=start, end=end) + out[f"case{case_idx}_seed{seed}"] = np.array(pts, dtype=np.int64) + out_path = Path("tests/unit/data/golden_mouse.npz") + np.savez_compressed(out_path, **out) + print(f"Wrote {len(out)} golden traces to {out_path}") + + +if __name__ == "__main__": + main() diff --git a/tests/unit/data/golden_mouse.npz b/tests/unit/data/golden_mouse.npz new file mode 100644 index 0000000000000000000000000000000000000000..079f08c7fd85bf6df1f1af5203243039da9e4604 GIT binary patch literal 18962 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 literal 0 HcmV?d00001