diff --git a/experiments/perception/worker/streaming_profile_stage1/pilot_projection_parity_probe.py b/experiments/perception/worker/streaming_profile_stage1/pilot_projection_parity_probe.py new file mode 100644 index 0000000..2ae39e9 --- /dev/null +++ b/experiments/perception/worker/streaming_profile_stage1/pilot_projection_parity_probe.py @@ -0,0 +1,156 @@ +"""CPU-only numerical diagnosis on a bounded source prefix, no model execution. + +Frozen observations select ranges to compare; they never feed a new graph. +Probe changes only storage alignment of identical pose values, not geometry math. +""" + +import argparse +import hashlib +import json +import time +from datetime import UTC, datetime +from pathlib import Path +from types import SimpleNamespace + +import numpy as np +import run_joint_pilot as legacy +from pilot_graph import calibration + +from k1link.perception.geometry_math import ( + project_map_points_kb4, + quaternion_xyzw_to_rotation_matrix, +) +from k1link.perception.streaming_sensors import normalized_sensor + + +def aligned_pose(pose, offset): + # Force a known address modulo 64, preserving bytes and C order. + position, quaternion = pose + storage = np.empty(128, np.uint8) + start = (offset - storage.ctypes.data) % 64 + q = np.ndarray((4,), dtype=np.float64, buffer=storage, offset=start) + q[:] = quaternion + return position, q + + +def run(args): + root = Path(args.output) + root.mkdir() + report = { + "created_utc": datetime.now(UTC).isoformat(), + "started_monotonic_ns": time.monotonic_ns(), + "scope": "CPU-only offline bounded numerical diagnosis; not latency qualification", + "numpy_version": np.__version__, + "model_runs": 0, + "frames": [], + } + with Path(args.reference).open() as stream: + reference = [json.loads(next(stream)) for _ in range(args.frames)] + projection = calibration(args.calibration) + + class Sink: + error = None + + def put(self, bundle): + row = {"sequence": bundle["sequence"], "available": bundle["available"]} + report["frames"].append(row) + if not bundle["available"]: + return True + position, quaternion = bundle["pose"] + raw = position.tobytes() + quaternion.tobytes() + wire_pose = normalized_sensor("pose", 1, 1, raw).value + variants = { + "archive": bundle["pose"], + "wire": wire_pose, + "owned_copy": tuple(np.array(a, copy=True) for a in wire_pose), + "separate_bytes": (np.frombuffer(raw[:24], " if modality != "pose" or len(raw) != 56: raise ValueError("normalized pose layout outside bound") values = np.frombuffer(raw, " 0.01: + # The quaternion begins at byte 24 of the wire body. On the qualified x86 + # NumPy runtime, its 8-mod-16 address selects a different dot/norm reduction + # and changes two downstream ranges by one ULP. Own a tiny aligned copy, + # matching the archive reader's numeric layout without changing any values + # or the projection/norm algorithm. Covered by the cache scratch allowance. + quaternion = np.array(values[3:], copy=True) + if quaternion.ctypes.data % 16: + raise ValueError("unqualified quaternion numeric buffer alignment") + quaternion.setflags(write=False) + if not np.isfinite(values).all() or abs(float(np.linalg.norm(quaternion)) - 1) > 0.01: raise ValueError("invalid source pose") - return SensorEvent(time_ns, "pose", sequence, (values[:3], values[3:])) + return SensorEvent(time_ns, "pose", sequence, (values[:3], quaternion)) class CausalSensorWindow: diff --git a/tests/test_perception_binary_bridge.py b/tests/test_perception_binary_bridge.py index 175615d..2a1e582 100644 --- a/tests/test_perception_binary_bridge.py +++ b/tests/test_perception_binary_bridge.py @@ -187,6 +187,21 @@ def test_cloud_validation_checks_later_bounded_chunks(): normalized_sensor("lidar", 1, 100, struct.pack("