Files
digital-drosophila/models/male-cns-lif/apl-timing-lab-v1/test_calibration.py
T
2026-09-30 12:08:25 +08:00

245 lines
14 KiB
Python

"""Synthetic CPU/file-fixture tests only; no real records, Torch, or Brian."""
import copy
import json
from pathlib import Path
import tempfile
import types
import unittest
from unittest.mock import patch
import numpy as np
import pandas as pd
import calibration as cal
HERE = Path(__file__).resolve().parent
LEGACY = cal.load_legacy(HERE.parent / "author-apl-lab-v2/calibration.py")
CFG = json.loads((HERE / "config.json").read_text(encoding="utf-8"))
def save_json(path, value):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(value, allow_nan=False), encoding="utf-8")
def records():
odors = sorted(LEGACY.ORIGINAL_CAL_IDS)
return [dict(name=f"cal-{mode}-{index:02d}-s{seed}", mode=mode, odor_index=index,
odor_id=odor, seed=seed, requests=0)
for mode in LEGACY.ORIGINAL_MODES for index, odor in enumerate(odors) for seed in LEGACY.ORIGINAL_SEEDS]
def timing_files(directory, delay, steps=20):
generated = np.arange(steps * 4064, dtype=np.float32).reshape(steps, 4064) / np.float32(10000)
stream = np.concatenate((np.zeros((delay, 4064), np.float32), generated))
applied, pending = stream[:steps].copy(), stream[steps:].copy()
state = np.arange(steps * 2, dtype=np.float32).reshape(steps, 2)
np.save(directory / "apl-applied.float32.npy", applied)
np.save(directory / "apl-pending-tail.float32.npy", pending)
audit = dict(pass_all=True, apl_delay_steps=delay, steps=steps, pending_generated_count=min(steps, delay),
pending_initial_zero_prefix=max(delay-steps, 0), pending_application_tick_start=steps,
pending_application_tick_stop_exclusive=steps+delay, pending_generated_tick_start=max(0, steps-delay),
pending_generated_tick_stop_exclusive=steps, initial_padding_positive_zero=True, sample_bits_preserved=True,
brain_tail_advanced=False, generated_trace="apl-inhibition.float32.npy", applied_trace="apl-applied.float32.npy",
pending_trace="apl-pending-tail.float32.npy", pending_raw_sha256=cal.raw_hash(pending),
pending_queue_drained=delay == 0, finite_generated_sequence_only=True,
future_apl_decay_or_feedback_generated=False, closed_loop_branch_integrals_claimed_equal=False,
biological_delay_measurement_claimed=False, final_apl_state_float32=state[-1].tolist(),
final_apl_state_u32_bits=state[-1].view(np.uint32).tolist(), final_apl_state_nonzero=bool(np.any(state[-1] != 0)))
save_json(directory / "apl-timing-audit.json", audit)
save_json(directory / "summary.json", dict(apl_delay_steps=delay, apl_timing=audit))
trial = dict(apl={"apl-inhibition.float32.npy": generated, "apl-state.float32.npy": state})
return dict(steps=steps, apl_delay_steps=delay), trial
def control_files(root, record_history=True):
new, old, case = root / "new", root / "old", root / "case"
for directory in (new, old, case):
directory.mkdir()
spec = dict(name="synthetic", steps=3, apl_delay_steps=0, record_history=record_history)
save_json(case / "spec.json", spec)
for index, directory in enumerate((new, old)):
summary = dict(case="synthetic", steps=3, completed_ticks=3, complete=True, pass_all=True,
nodes=2, edges=3, precision="float64", apl_fast_edges_zeroed=1, kc_targets_present=1,
effective_weights_raw_sha256="a" * 64, build_wall_seconds=index,
input_sha256={"spec.json": str(index)}, output_budget_bytes=123+index)
save_json(directory / "summary.json", summary)
state = {key: np.zeros(0 if key in ("step", "neuron_idx") else 2, dtype) for key, dtype in cal.STATE_DTYPES.items()}
np.savez(directory / "state.npz", **state)
for name, width in cal.APL_FILES.items():
np.save(directory / name, np.zeros((3, width), np.float32))
for name in ("tick-state-hashes.jsonl", "queue.jsonl"):
(directory / name).write_text("\n".join(json.dumps(dict(tick=t, same=True)) for t in range(3)), encoding="utf-8")
(directory / "requests.csv").write_text(",".join(cal.REQUEST_FIELDS) + "\n", encoding="utf-8")
save_json(directory / "apl-component.json", dict(ok=True, environment={"synthetic": True}))
if record_history:
for key, dtype in (("v", "float64"), ("g", "float64"), ("ref", "int32")):
for name in (f"{key}-history.{dtype}.npy", f"preAPL-{key}.{dtype}.npy"):
np.save(directory / name, np.zeros((3, 2), dtype))
return new, old, case
def fake_trial(output, row, delay):
state = {name: np.zeros(1, dtype) for name, dtype in cal.STATE_DTYPES.items()}
counts = np.zeros(1000, np.int32)
if delay == 18:
counts[row["odor_index"] * 50:(row["odor_index"] + 1) * 50] = 1
return dict(state=state, apl={name: np.zeros((1, width), np.float32) for name, width in cal.APL_FILES.items()},
hashes=[], queues=[], requests=[], component={}, kc_counts=counts, expected_external_events=10., external_events=0,
record=dict(case=row["name"], requested=0), output=output,
timing=dict(applied=np.zeros((1, 4064), np.float32), pending=np.zeros((delay, 4064), np.float32),
audit=dict(synthetic=True), report=dict(pass_all=True)))
class CalibrationTimingTests(unittest.TestCase):
def test_all_original_inventory_and_pair_specific_gates_are_reused(self):
rows = records()
odors = LEGACY.validate_inventory(rows, CFG)
runs = {(r["mode"], r["odor_id"], r["seed"]): fake_trial(Path("synthetic"), r, 18) for r in rows}
report = LEGACY.summarize_mode(LEGACY.ORIGINAL_MODES[0], odors, LEGACY.ORIGINAL_SEEDS, runs, CFG["gates"])
self.assertTrue(report["gate"])
self.assertEqual((report["within_distance_count"], report["between_distance_count"], report["pair_count"]), (60, 75, 15))
self.assertTrue(all(r["within_distance_count"] == 20 and r["between_distance_count"] == 5 for r in report["pairs"]))
self.assertFalse(hasattr(LEGACY, "EXP"))
with self.assertRaises(ValueError):
LEGACY.validate_inventory(rows[:-1], CFG)
def test_direct_slices_cover_zero_delay_boundary_and_short_window(self):
for delay in (0, 18):
for steps in (1, 17, 18, 19, 37):
with self.subTest(delay=delay, steps=steps), tempfile.TemporaryDirectory() as tmp:
spec, trial = timing_files(Path(tmp), delay, steps)
result = cal.validate_timing(Path(tmp), spec, trial)
try:
self.assertTrue(result["report"]["pass_all"])
self.assertEqual(result["pending"].shape, (delay, 4064))
finally:
result["applied"]._mmap.close()
result["pending"]._mmap.close()
def test_tail_or_application_bit_corruption_fails(self):
for filename in ("apl-applied.float32.npy", "apl-pending-tail.float32.npy"):
with self.subTest(filename=filename), tempfile.TemporaryDirectory() as tmp:
root = Path(tmp); spec, trial = timing_files(root, 18)
value = np.load(root / filename)
value[-1, 1] = np.nextafter(value[-1, 1], np.float32(np.inf))
np.save(root / filename, value)
with self.assertRaisesRegex(ValueError, "partition"):
cal.validate_timing(root, spec, trial)
def test_negative_zero_padding_and_fabricated_future_audit_fail(self):
with tempfile.TemporaryDirectory() as tmp:
root = Path(tmp); spec, trial = timing_files(root, 18, 1)
value = np.load(root / "apl-applied.float32.npy")
value[0, 0] = np.float32(-0.)
np.save(root / "apl-applied.float32.npy", value)
with self.assertRaisesRegex(ValueError, "positive zero"):
cal.validate_timing(root, spec, trial)
for key, value in (("brain_tail_advanced", True), ("final_apl_state_nonzero", False),
("pending_initial_zero_prefix", 1), ("pass_all", 1)):
with self.subTest(key=key), tempfile.TemporaryDirectory() as tmp:
root = Path(tmp); spec, trial = timing_files(root, 18, 20)
audit = cal.read_json(root / "apl-timing-audit.json"); audit[key] = value
save_json(root / "apl-timing-audit.json", audit)
with self.assertRaisesRegex(ValueError, "audit disagrees"):
cal.validate_timing(root, spec, trial)
def test_delay0_control_ignores_runtime_and_budget_metadata(self):
with tempfile.TemporaryDirectory() as tmp:
new, old, case = control_files(Path(tmp))
result = cal.control_identity(new, old, case)
self.assertTrue(result["pass_all"])
self.assertFalse(result["adapter_paths_budgets_and_runtime_metadata_compared"])
self.assertIn("preAPL-g.float64.npy", result["checks"])
def test_control_signed_zero_history_and_missing_trace_fail(self):
with tempfile.TemporaryDirectory() as tmp:
new, old, case = control_files(Path(tmp))
with np.load(new / "state.npz") as archive:
state = {key: archive[key].copy() for key in archive.files}
state["v"][0] = -0.
np.savez(new / "state.npz", **state)
result = cal.control_identity(new, old, case)
self.assertFalse(result["checks"]["state/v"])
self.assertFalse(result["pass_all"])
with tempfile.TemporaryDirectory() as tmp:
new, old, case = control_files(Path(tmp))
np.save(new / "preAPL-g.float64.npy", np.ones((3, 2), np.float64))
self.assertFalse(cal.control_identity(new, old, case)["pass_all"])
(new / "apl-drive.float32.npy").unlink()
with self.assertRaises(FileNotFoundError):
cal.control_identity(new, old, case)
def test_control_rejects_delay18_and_incomplete_results(self):
with tempfile.TemporaryDirectory() as tmp:
new, old, case = control_files(Path(tmp), False)
spec = cal.read_json(case / "spec.json"); spec["apl_delay_steps"] = 18
save_json(case / "spec.json", spec)
with self.assertRaisesRegex(ValueError, "only for explicit delay0"):
cal.control_identity(new, old, case)
spec["apl_delay_steps"] = 0; save_json(case / "spec.json", spec)
summary = cal.read_json(new / "summary.json"); summary["complete"] = False
save_json(new / "summary.json", summary)
with self.assertRaisesRegex(ValueError, "incomplete"):
cal.control_identity(new, old, case)
def test_repeat_includes_applied_pending_and_audit(self):
trial = fake_trial(Path("synthetic"), records()[0], 18)
self.assertTrue(cal.timing_repeat(trial, copy.deepcopy(trial), LEGACY)["pass_all"])
for key in ("applied", "pending", "audit"):
bad = copy.deepcopy(trial)
if key == "audit": bad["timing"][key]["synthetic"] = False
else: bad["timing"][key][0, 0] = 1
self.assertFalse(cal.timing_repeat(trial, bad, LEGACY)["pass_all"])
def test_both_arms_keep_full_inventory_despite_control_repr_failure(self):
rows = records(); odors = LEGACY.validate_inventory(rows, CFG)
by_name = {row["name"]: row for row in rows}
calls = []
def read_new(legacy, output, case, spec, kc, cfg):
calls.append(str(output))
return fake_trial(output, by_name[case.name], spec["apl_delay_steps"])
with patch.object(cal, "_case_spec", side_effect=lambda case, old, row, delay: dict(apl_delay_steps=delay)), \
patch.object(cal, "_read_new", side_effect=read_new), \
patch.object(cal, "_provenance", return_value={}), \
patch.object(cal, "control_identity", return_value=dict(case="synthetic", pass_all=True, checks={})):
reports = [cal.collect_arm("delay"+str(delay), delay, rows, odors, LEGACY, CFG,
Path("synthetic-exp"), Path("synthetic-ag"), np.arange(4064, dtype=np.int32)) for delay in (0,18)]
self.assertEqual(len(calls), 144)
self.assertTrue(all(r["execution_gate_pass"] for r in reports))
self.assertFalse(reports[0]["original_representation_gate_pass"])
self.assertTrue(reports[1]["original_representation_gate_pass"])
self.assertEqual([r["valid_base_trials"] for r in reports], [60, 60])
self.assertEqual([r["checked_repeats"] for r in reports], [12, 12])
self.assertEqual(len(reports[0]["control_checks"]), 72)
def test_none_recomputation_is_deterministic_and_never_writes(self):
rows = records(); odors = sorted(LEGACY.ORIGINAL_CAL_IDS)
panel = pd.DataFrame(dict(split=["calibration"]*6+["heldout"]*6,
odor_id=odors+["static-only-"+str(n) for n in range(6)], mapped_response_sum=[1.]*12))
encoder = dict(panel_count=12, cal_count=6, seeds=list(LEGACY.ORIGINAL_SEEDS),
requested_before_any_dynamics=True, formal_AB_run=False, heldout_run=False, median_mapped_response_sum=1.)
with tempfile.TemporaryDirectory() as tmp:
ctx = types.ModuleType("context")
ctx.EXP, ctx.AG, ctx.ROOT, ctx.CFG, ctx.check = Path(tmp)/"exp", Path(tmp)/"ag", Path(tmp), CFG, lambda: None
def fake_arm(arm, *args):
return dict(arm=arm, numerical_integrity_pass=True, exact_repeat_pass=True,
delay0_control_identity_pass=True if arm == "delay0" else None,
original_representation_gate_pass=False, failures=[], modes={"physiological": {"gate": False}})
with patch.dict("sys.modules", {"context": ctx}), patch.object(cal, "load_legacy", return_value=LEGACY), \
patch.object(cal, "read_json", side_effect=lambda p: rows if Path(p).name == "calibration-cases.json" else encoder), \
patch.object(cal, "file_hash", return_value="same"), patch.object(pd, "read_parquet", return_value=panel), \
patch.object(cal.np, "load", return_value=np.arange(4064, dtype=np.int32)), \
patch.object(cal, "collect_arm", side_effect=fake_arm):
first, second = cal.summarize(None), cal.summarize(None)
self.assertEqual(first, second)
self.assertTrue(first["execution_gate_pass"])
self.assertFalse(first["pass_all"])
json.dumps(first, allow_nan=False)
self.assertEqual(list(Path(tmp).iterdir()), [])
if __name__ == "__main__":
unittest.main()