245 lines
14 KiB
Python
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()
|