Files
digital-drosophila/models/male-cns-lif/phase4d.py
T

536 lines
34 KiB
Python

#!/usr/bin/env python3
"""Phase 4D orchestration: stable Brain I/O API, timing, readout and regression."""
from __future__ import annotations
import argparse
import hashlib
import json
import math
import os
import platform
import shutil
import time
from collections import Counter
from pathlib import Path
from typing import Any
import numpy as np
import pyarrow as pa
import pyarrow.parquet as pq
import torch
import yaml
from brain_runtime import (
ACTIVITY_STREAM_VERSION, API_VERSION, INPUT_BATCH_VERSION,
BrainRuntime, InputBatch, InputEvent, VisualAdapterV1,
)
def sha256(path: Path, chunk: int = 8 << 20) -> str:
h = hashlib.sha256()
with path.open("rb") as f:
while data := f.read(chunk): h.update(data)
return h.hexdigest()
def write_json(path: Path, value: Any) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(value, indent=2, sort_keys=True) + "\n", encoding="utf-8")
def np_json(value: Any) -> Any:
if isinstance(value, np.ndarray): return value.tolist()
if isinstance(value, np.generic): return value.item()
raise TypeError(type(value).__name__)
def metadata_populations(runtime: BrainRuntime) -> dict[str, np.ndarray]:
return {k: v.copy() for k, v in runtime.output_populations.items()}
def freeze_populations(exp: Path, runtime: BrainRuntime) -> dict[str, Any]:
expressions = {
"descending": "annotation_superclass in {'descending_neuron','descending_neuron_tbc'}",
"motor_related": "annotation_superclass in {'vnc_motor','cb_motor'}",
"ascending": "annotation_superclass in {'ascending_neuron','sensory_ascending','sensory_ascending_tbc','efferent_ascending'}",
}
nt = runtime.table["neurotransmitter"].to_pylist()
result: dict[str, Any] = {}
for name, nodes in metadata_populations(runtime).items():
table = pa.table({
"neuron_idx": pa.array(nodes, type=pa.int32()),
"body_id": pa.array(runtime.body_id[nodes], type=pa.uint64()),
"superclass": pa.array([runtime.superclass[i] for i in nodes], type=pa.string()),
"type": pa.array([runtime.neuron_type[i] for i in nodes], type=pa.string()),
"class": pa.array([runtime.neuron_class[i] for i in nodes], type=pa.string()),
"neurotransmitter": pa.array([nt[i] for i in nodes], type=pa.string()),
})
pq.write_table(table, exp / "populations" / f"{name}.parquet", compression="zstd")
nts = Counter("<null>" if nt[i] is None else str(nt[i]) for i in nodes)
result[name] = {
"selection_expression": expressions[name], "count": int(len(nodes)),
"neurotransmitter_statistics": dict(sorted(nts.items())),
"membership_file": str(exp / "populations" / f"{name}.parquet"),
}
write_json(exp / "populations/summary.json", result)
return result
def audit_visual_sides(exp: Path, runtime: BrainRuntime, adapter: VisualAdapterV1) -> dict[str, Any]:
values = runtime.table["annotation_rootSide"].to_pylist() if "annotation_rootSide" in runtime.table.column_names else [None] * runtime.n
result: dict[str, Any] = {}
for mode in ("engineering-first-order", "engineering-second-order"):
nodes = adapter.population(mode); c = Counter("<null>" if values[i] is None else str(values[i]) for i in nodes)
coverage = 1.0 - c.get("<null>", 0) / len(nodes)
reliable = coverage >= 0.90 and c.get("L", 0) > 0 and c.get("R", 0) > 0
result[mode] = {"field": "annotation_rootSide", "counts": dict(c), "non_null_coverage": coverage, "left_right_patterns_enabled": reliable}
write_json(exp / "visual-adapter/left-right-audit.json", result)
return result
def freeze_contracts(exp: Path, cfg: dict[str, Any], runtime: BrainRuntime, adapter: VisualAdapterV1) -> dict[str, Any]:
input_schema = {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "MaleCNS InputBatch",
"version": INPUT_BATCH_VERSION,
"type": "object",
"required": ["version", "batch_id", "events"],
"properties": {
"version": {"const": INPUT_BATCH_VERSION},
"batch_id": {"type": "string"},
"events": {
"type": "array",
"items": {
"type": "object",
"required": ["target_neuron_idx", "stimulation_mode", "value_kind", "value", "start_ms", "duration_ms", "source_id", "channel_id"],
"properties": {
"target_neuron_idx": {"type": "array", "items": {"type": "integer", "minimum": 0, "maximum": 166699}},
"stimulation_mode": {"enum": ["spike_injection", "external_synaptic_drive"]},
"value_kind": {"enum": ["binary", "scalar_intensity", "poisson_rate_hz", "signed_modulation"]},
"value": {"oneOf": [{"type": "number"}, {"type": "array", "items": {"type": "number"}}]},
"start_ms": {"type": "number", "minimum": 0},
"duration_ms": {"type": "number", "exclusiveMinimum": 0},
"source_id": {"type": "string"},
"channel_id": {"type": "string"},
"amplitude_mv": {"type": "number"},
},
},
},
},
"timestamp_unit": "biological ms",
"external_drive_is_connectome_transmission": False,
}
write_json(exp / "configs/input-batch.schema.json", input_schema)
mode_records: dict[str, Any] = {}
for mode, nodes in adapter.modes.items():
path = exp / "visual-adapter" / f"{mode}.parquet"
pq.write_table(pa.table({"neuron_idx": pa.array(nodes.astype(np.int32), type=pa.int32()), "body_id": pa.array(runtime.body_id[nodes], type=pa.uint64())}), path, compression="zstd")
spec = cfg["visual_adapter"]["modes"][mode]
mode_records[mode] = {"count": int(len(nodes)), "membership_file": str(path), **spec}
write_json(exp / "visual-adapter/membership-summary.json", mode_records)
readout = {
"api_version": API_VERSION, "methods": ["read_spikes", "read_population", "read_output", "fixed_temporal_bins"],
"features": ["spike count vector", "firing-rate vector", "active mask", "population aggregate rate", "excitatory/inhibitory activity", "descending feature vector", "motor-related feature vector"],
"aggregations": ["per-neuron", "per-type", "per-class"], "fixed_bins_ms": cfg["readout"]["bins_ms"],
"action_decoder": False,
}
write_json(exp / "readout/readout-contract.json", readout)
return {"input_batch_schema": str(exp / "configs/input-batch.schema.json"), "visual_modes": mode_records, "readout_contract": readout}
def patterns(nodes: np.ndarray, cfg: dict[str, Any]) -> dict[str, np.ndarray]:
rng = np.random.default_rng(int(cfg["synthetic_patterns"]["deterministic_seed"]))
order = rng.permutation(len(nodes))
sparse_n = max(1, int(round(len(nodes) * float(cfg["synthetic_patterns"]["sparse_fraction"]))))
dense_n = max(1, int(round(len(nodes) * float(cfg["synthetic_patterns"]["dense_fraction"]))))
moving_n = max(1, int(round(len(nodes) * float(cfg["synthetic_patterns"]["moving_fraction"]))))
def vector(selection: np.ndarray, rate: float) -> np.ndarray:
out = np.zeros(len(nodes), dtype=np.float32); out[selection] = rate; return out
rate = float(cfg["visual_adapter"]["synthetic_rate_hz"])
return {
"sparse-A": vector(order[:sparse_n], rate),
"sparse-B": vector(order[sparse_n:2*sparse_n], rate),
"dense": vector(order[:dense_n], rate),
"moving": vector(order[2*sparse_n:2*sparse_n+moving_n], rate),
"zero": np.zeros(len(nodes), dtype=np.float32),
}
def direct_batch(nodes: np.ndarray, mode: str, rate_hz: float, start_ms: float, duration_ms: float, source: str) -> InputBatch:
return InputBatch(events=(InputEvent(
target_neuron_idx=nodes.astype(np.int64), stimulation_mode="spike_injection",
value_kind="poisson_rate_hz", value=float(rate_hz), start_ms=start_ms,
duration_ms=duration_ms, source_id=source, channel_id=mode,
metadata={"biological_fidelity": "reference_population", "external_drive_is_connectome_transmission": False},
),), batch_id=f"{source}:{mode}:{start_ms}")
def feature(runtime: BrainRuntime, window: float) -> np.ndarray:
d = runtime.read_population("descending", window)["spike_counts"]
m = runtime.read_population("motor_related", window)["spike_counts"]
return np.concatenate([d, m]).astype(np.float32)
def output_stats(runtime: BrainRuntime, window: float) -> dict[str, Any]:
d = runtime.read_population("descending", window); m = runtime.read_population("motor_related", window)
return {
"descending_active": d["active_neurons"], "descending_spikes": d["total_spikes"],
"motor_active": m["active_neurons"], "motor_spikes": m["total_spikes"],
"descending_rate_hz": d["aggregate_rate_hz"], "motor_rate_hz": m["aggregate_rate_hz"],
}
def population_distances(runtime: BrainRuntime, sources: np.ndarray) -> np.ndarray:
return runtime.runtime_module.p4b.directed_distances(runtime.indptr_np, runtime.indices_np, sources.astype(np.int64), runtime.n)
def propagation_depth(runtime: BrainRuntime, distance: np.ndarray) -> int:
active = runtime.spike_counts.cpu().numpy() > 0
values = distance[active & (distance >= 0)]
return int(values.max(initial=0))
def make_source_batch(cfg: dict[str, Any], runtime: BrainRuntime, adapter: VisualAdapterV1,
source: str, start: float, duration: float, pattern_cache: dict[str, dict[str, np.ndarray]]) -> tuple[InputBatch, np.ndarray]:
if source.startswith("engineering-"):
mode = source
p = pattern_cache[mode]["sparse-A"]
batch = adapter.encode(mode, p, start, duration, "phase4d-window", "sparse-A")
targets = adapter.population(mode)[p != 0]
return batch, targets
mask = runtime.population_masks[source]
nodes = np.flatnonzero(mask).astype(np.int64)
rate = 10.0 if source == "auditory" else 50.0
return direct_batch(nodes, source, rate, start, duration, "phase4d-window"), nodes
def window_experiments(exp: Path, cfg: dict[str, Any], runtime: BrainRuntime,
adapter: VisualAdapterV1, pattern_cache: dict[str, dict[str, np.ndarray]]) -> dict[str, Any]:
records: list[dict[str, Any]] = []; distances: dict[str, np.ndarray] = {}
for source in cfg["window_experiment"]["sources"]:
_, targets = make_source_batch(cfg, runtime, adapter, source, 0.0, 5.0, pattern_cache)
distances[source] = population_distances(runtime, targets)
for window in cfg["window_experiment"]["windows_ms"]:
for seed in cfg["window_experiment"]["seeds"]:
outcomes = []
for repeat in range(2):
runtime.reset(int(seed)); batch, _ = make_source_batch(cfg, runtime, adapter, source, 0.0, float(window), pattern_cache)
torch.cuda.synchronize(); started = time.perf_counter(); step_result = runtime.step(batch, float(window)); torch.cuda.synchronize(); wall = time.perf_counter() - started
stats = output_stats(runtime, float(window)); f = feature(runtime, float(window))
outcomes.append((runtime.read_spikes(), runtime.v.cpu().numpy().copy(), runtime.g.cpu().numpy().copy(), f, stats, step_result, wall))
a, b = outcomes
deterministic = np.array_equal(a[0]["step"], b[0]["step"]) and np.array_equal(a[0]["neuron_idx"], b[0]["neuron_idx"]) and np.array_equal(a[3], b[3])
input_count = int(a[5]["new_spikes"] if source in ("auditory", "olfactory") else a[5]["new_external_drive_events"])
rec = {
"source": source, "window_ms": float(window), "seed": int(seed),
"wall_latency_seconds": a[6], "max_theoretical_control_hz": 1.0 / a[6],
"realtime_factor_wall_over_biological": a[6] / (float(window) / 1000.0),
"input_spikes_or_drive_events": input_count,
"total_spikes": int(len(a[0]["neuron_idx"])),
"propagation_depth": propagation_depth(runtime, distances[source]),
**a[4], "feature_l2_norm": float(np.linalg.norm(a[3])),
"repeat_spike_events_exact": deterministic,
"repeat_feature_exact": bool(np.array_equal(a[3], b[3])),
"repeat_final_voltage_max_abs_error": float(np.max(np.abs(a[1] - b[1]))),
"repeat_final_g_max_abs_error": float(np.max(np.abs(a[2] - b[2]))),
}
records.append(rec)
write_json(exp / "latency/window-trials.json", records)
summary: dict[str, Any] = {"trial_count": len(records), "all_repeat_deterministic": all(x["repeat_spike_events_exact"] for x in records)}
for source in cfg["window_experiment"]["sources"]:
rows = [x for x in records if x["source"] == source]
summary[source] = {}
for window in cfg["window_experiment"]["windows_ms"]:
r = [x for x in rows if x["window_ms"] == float(window)]
summary[source][str(window)] = {
"wall_latency_seconds_mean": float(np.mean([x["wall_latency_seconds"] for x in r])),
"max_theoretical_control_hz_mean": float(np.mean([x["max_theoretical_control_hz"] for x in r])),
"descending_active_mean": float(np.mean([x["descending_active"] for x in r])),
"motor_active_mean": float(np.mean([x["motor_active"] for x in r])),
"feature_l2_norm_mean": float(np.mean([x["feature_l2_norm"] for x in r])),
}
def shortest(key: str) -> float | None:
candidates = sorted({x["window_ms"] for x in records if x["source"].startswith("engineering-") and x[key] > 0})
return candidates[0] if candidates else None
summary["shortest_engineering_descending_signal_ms"] = shortest("descending_active")
summary["shortest_engineering_motor_signal_ms"] = shortest("motor_active")
write_json(exp / "latency/summary.json", summary)
return {"records": records, "summary": summary}
def continuous_control(exp: Path, cfg: dict[str, Any], runtime: BrainRuntime,
adapter: VisualAdapterV1, pattern_cache: dict[str, dict[str, np.ndarray]]) -> dict[str, Any]:
output: dict[str, Any] = {}
duration = float(cfg["continuous_control"]["biological_duration_ms"])
sequence = cfg["continuous_control"]["sequence"]
mode = "engineering-first-order"
for period in cfg["continuous_control"]["periods_ms"]:
period = float(period); runtime.reset(int(cfg["continuous_control"]["seed"]))
intervals: list[dict[str, Any]] = []; previous = None
total_wall = 0.0
for k, start in enumerate(np.arange(0.0, duration, period)):
pattern_name = sequence[k % len(sequence)]
values = pattern_cache[mode][pattern_name]
batch = adapter.encode(mode, values, float(start), period, "continuous-control", pattern_name)
torch.cuda.synchronize(); t0 = time.perf_counter(); step_result = runtime.step(batch, period); torch.cuda.synchronize(); wall = time.perf_counter() - t0; total_wall += wall
f = feature(runtime, period); stats = output_stats(runtime, period)
recent = runtime.read_spikes(period); adapter_nodes = adapter.population(mode)
target_spikes = int(np.count_nonzero(np.isin(recent["neuron_idx"], adapter_nodes)))
latency = None
ev = runtime.read_spikes(period)
output_members = np.concatenate([runtime.output_populations["descending"], runtime.output_populations["motor_related"]])
omask = np.isin(ev["neuron_idx"], output_members)
if np.any(omask): latency = float(ev["timestamp_ms"][omask].min() - start)
intervals.append({
"interval": k, "start_ms": float(start), "end_ms": float(start + period), "pattern": pattern_name,
"wall_seconds": wall, "response_latency_ms": latency, **stats,
"feature_norm": float(np.linalg.norm(f)),
"feature_change_l2": None if previous is None else float(np.linalg.norm(f - previous)),
"input_spikes": step_result["new_spikes"], "drive_events": step_result["new_external_drive_events"],
"adapter_target_spikes": target_spikes,
})
previous = f
zero = [x for x in intervals if x["pattern"] == "zero"]
change_latencies = [x["response_latency_ms"] for x in intervals if x["response_latency_ms"] is not None]
output[str(int(period))] = {
"period_ms": period, "continuous_state_without_reset": True, "interval_count": len(intervals),
"wall_seconds": total_wall, "biological_ms": duration,
"median_response_latency_ms": float(np.median(change_latencies)) if change_latencies else None,
"max_response_latency_ms": float(np.max(change_latencies)) if change_latencies else None,
"zero_input_descending_spikes": int(sum(x["descending_spikes"] for x in zero)),
"zero_input_motor_spikes": int(sum(x["motor_spikes"] for x in zero)),
"zero_input_adapter_target_spikes": int(sum(x["adapter_target_spikes"] for x in zero)),
"zero_input_intervals_with_activity": int(sum((x["descending_spikes"] + x["motor_spikes"]) > 0 for x in zero)),
"intervals": intervals,
}
write_json(exp / "continuous-control" / f"period-{int(period)}ms.json", output[str(int(period))])
write_json(exp / "continuous-control/summary.json", {k: {x: v[x] for x in v if x != "intervals"} for k, v in output.items()})
return output
def metric_pair(a: np.ndarray, b: np.ndarray) -> dict[str, float]:
an, bn = float(np.linalg.norm(a)), float(np.linalg.norm(b))
cosine = float(np.dot(a, b) / (an * bn)) if an and bn else (1.0 if an == bn else 0.0)
if np.std(a) and np.std(b): corr = float(np.corrcoef(a, b)[0, 1])
else: corr = 1.0 if np.array_equal(a, b) else 0.0
aa, bb = a > 0, b > 0; union = np.count_nonzero(aa | bb)
return {"cosine_distance": 1.0 - cosine, "euclidean_distance": float(np.linalg.norm(a - b)), "correlation": corr, "active_population_overlap_jaccard": float(np.count_nonzero(aa & bb) / union) if union else 1.0}
def separability(exp: Path, cfg: dict[str, Any], runtime: BrainRuntime,
adapter: VisualAdapterV1, pattern_cache: dict[str, dict[str, np.ndarray]], side_audit: dict[str, Any]) -> dict[str, Any]:
mode = "engineering-first-order"; pats = dict(pattern_cache[mode])
pats.pop("zero")
if side_audit[mode]["left_right_patterns_enabled"]:
root_side = runtime.table["annotation_rootSide"].to_pylist(); nodes = adapter.population(mode); rate = float(cfg["visual_adapter"]["synthetic_rate_hz"])
pats["left"] = np.asarray([rate if root_side[i] == "L" else 0.0 for i in nodes], dtype=np.float32)
pats["right"] = np.asarray([rate if root_side[i] == "R" else 0.0 for i in nodes], dtype=np.float32)
features: dict[str, list[np.ndarray]] = {}
trial_rows: list[dict[str, Any]] = []
for name, values in pats.items():
features[name] = []
for seed in (44301, 44302, 44303):
runtime.reset(seed); batch = adapter.encode(mode, values, 0.0, 100.0, "separability", name)
runtime.step(batch, 100.0); f = feature(runtime, 100.0); features[name].append(f)
trial_rows.append({"pattern": name, "seed": seed, "active_channels": int(np.count_nonzero(values)), "feature_norm": float(np.linalg.norm(f)), **output_stats(runtime, 100.0)})
means = {k: np.mean(v, axis=0) for k, v in features.items()}
pairwise: dict[str, Any] = {}
names = sorted(means)
for i, a in enumerate(names):
for b in names[i+1:]: pairwise[f"{a}__{b}"] = metric_pair(means[a], means[b])
within = [float(np.linalg.norm(x - means[k])) for k, xs in features.items() for x in xs]
between = [v["euclidean_distance"] for v in pairwise.values()]
matrix = np.stack([x for k in names for x in features[k]])
centered = matrix - matrix.mean(axis=0, keepdims=True)
u, s, _ = np.linalg.svd(centered, full_matrices=False)
coords = u[:, :2] * s[:2]
labels = [k for k in names for _ in features[k]]
pca_table = pa.table({"pattern": labels, "pc1": coords[:, 0], "pc2": coords[:, 1]})
pq.write_table(pca_table, exp / "separability/pca-coordinates.parquet", compression="zstd")
result = {
"classifier_trained": False, "action_decoder_created": False,
"patterns": names, "trial_statistics": trial_rows, "pairwise": pairwise,
"within_condition_distance_mean": float(np.mean(within)),
"between_condition_distance_mean": float(np.mean(between)),
"between_to_within_ratio": float(np.mean(between) / np.mean(within)) if np.mean(within) else None,
"all_pairwise_mean_vectors_distinct": all(v["euclidean_distance"] > 0 for v in pairwise.values()),
"pca_usage": "offline visualization analysis only; not an action decoder",
}
write_json(exp / "separability/summary.json", result)
return result
def api_tests(exp: Path, runtime: BrainRuntime) -> dict[str, Any]:
nodes = np.flatnonzero(runtime.population_masks["auditory"]).astype(np.int64)
batch20 = direct_batch(nodes, "auditory", 10, 0.0, 20.0, "api-test")
runtime.reset(44400); runtime.step(batch20, 20.0); one = runtime.read_spikes(); one_v = runtime.v.cpu().numpy().copy()
runtime.reset(44400); runtime.step(batch20, 10.0); checkpoint = runtime.checkpoint_state(); runtime.step(batch20, 10.0); two = runtime.read_spikes(); two_v = runtime.v.cpu().numpy().copy()
runtime.restore_state(checkpoint); runtime.step(batch20, 10.0); replay = runtime.read_spikes(); replay_v = runtime.v.cpu().numpy().copy()
per_neuron = runtime.read_output({"population": "descending", "aggregation": "per-neuron"}, 20.0)
per_type = runtime.read_output({"population": "descending", "aggregation": "per-type"}, 20.0)
per_class = runtime.read_output({"population": "motor_related", "aggregation": "per-class"}, 20.0)
bins = {str(x): runtime.fixed_temporal_bins("descending", float(x), 20.0)["spike_counts"].tolist() for x in runtime.cfg["readout"]["bins_ms"] if float(x) <= 20.0}
result = {
"reset_same_seed_continuous_chunk_spikes_exact": bool(np.array_equal(one["step"], two["step"]) and np.array_equal(one["neuron_idx"], two["neuron_idx"])),
"continuous_step_does_not_reset_clock": runtime.simulation_time_ms == 20.0,
"checkpoint_restore_spikes_exact": bool(np.array_equal(two["step"], replay["step"]) and np.array_equal(two["neuron_idx"], replay["neuron_idx"])),
"checkpoint_restore_voltage_exact": bool(np.array_equal(two_v, replay_v)),
"single_vs_chunk_voltage_max_abs_error": float(np.max(np.abs(one_v - two_v))),
"timestamps_present": "timestamp_ms" in replay,
"per_neuron_readout_shape": int(len(per_neuron["neuron_idx"])),
"per_type_aggregation_labels": int(len(per_type["features"])),
"per_class_aggregation_labels": int(len(per_class["features"])),
"fixed_temporal_bins_tested": bins,
"readout_modes_passed": len(per_neuron["neuron_idx"]) == len(runtime.output_populations["descending"]) and len(per_type["features"]) > 0 and len(per_class["features"]) > 0,
"all_passed": False,
}
result["all_passed"] = all(result[k] for k in ("reset_same_seed_continuous_chunk_spikes_exact", "continuous_step_does_not_reset_clock", "checkpoint_restore_spikes_exact", "checkpoint_restore_voltage_exact", "timestamps_present", "readout_modes_passed"))
write_json(exp / "audit/api-tests.json", result)
return result
def regression(exp: Path, cfg: dict[str, Any], runtime: BrainRuntime) -> dict[str, Any]:
root = Path(cfg["paths"]["phase4c_root"]) / "regression/reference"
results: dict[str, Any] = {}; tolerance = float(cfg["regression"]["float_absolute_tolerance"])
for spec in cfg["regression"]["reference_trials"]:
name = spec["name"]; ref_dir = root / name
events = pq.read_table(ref_dir / "spike-events.parquet", columns=["step", "neuron_idx"])
ref_steps = events["step"].to_numpy(); ref_nodes = events["neuron_idx"].to_numpy()
ref_counts = np.load(ref_dir / "per-neuron-spike-counts.int32.npy")
ref_v = np.load(ref_dir / "final-voltage.float32.npy"); ref_g = np.load(ref_dir / "final-g.float32.npy")
nodes = np.flatnonzero(runtime.population_masks[spec["population"]]).astype(np.int64)
batch = direct_batch(nodes, spec["population"], float(spec["rate_hz"]), 0.0, float(spec["duration_ms"]), "phase4c-regression")
runtime.reset(int(spec["seed"])); t0 = time.perf_counter(); runtime.step(batch, float(spec["duration_ms"])); wall = time.perf_counter() - t0
got = runtime.read_spikes(); counts = runtime.spike_counts.cpu().numpy()
vd = np.abs(runtime.v.cpu().numpy() - ref_v); gd = np.abs(runtime.g.cpu().numpy() - ref_g)
record = {
"spike_sequence_exact": bool(np.array_equal(ref_steps, got["step"]) and np.array_equal(ref_nodes, got["neuron_idx"])),
"spike_counts_exact": bool(np.array_equal(ref_counts, counts)),
"final_voltage_max_abs_error": float(vd.max(initial=0)), "final_voltage_mean_abs_error": float(vd.mean()),
"final_g_max_abs_error": float(gd.max(initial=0)), "final_g_mean_abs_error": float(gd.mean()),
"state_within_phase4c_tolerance": bool(vd.max(initial=0) <= tolerance and gd.max(initial=0) <= tolerance),
"wall_seconds": wall, "event_count": int(len(got["neuron_idx"])),
}
record["passed"] = record["spike_sequence_exact"] and record["spike_counts_exact"] and record["state_within_phase4c_tolerance"]
results[name] = record
write_json(exp / "regression" / f"{name}.json", record)
write_json(exp / "regression/summary.json", {"all_passed": all(x["passed"] for x in results.values()), "trials": results})
return results
def stream_contract(exp: Path, runtime: BrainRuntime) -> dict[str, Any]:
schema = {
"$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MaleCNS Activity Packet",
"contract_version": ACTIVITY_STREAM_VERSION, "type": "object",
"required": ["contract_version", "simulation_time_ms", "sequence_id", "spike_neuron_idx", "population_aggregates", "active_neuron_count", "input_channel_metadata"],
"properties": {
"simulation_time_ms": {"type": "number"}, "sequence_id": {"type": "integer"},
"spike_neuron_idx": {"type": "array", "items": {"type": "integer"}},
"spike_timestamp_ms": {"type": "array", "items": {"type": "number"}},
"population_aggregates": {"type": "object"}, "active_neuron_count": {"type": "integer"},
"input_channel_metadata": {"type": "object"}, "representation": {"const": "event-only"},
},
"dense_time_by_neuron_matrix_forbidden": True,
"supported_modes": ["event-only stream", "temporal aggregation", "saved-event replay"],
}
write_json(exp / "activity-stream/activity-packet.schema.json", schema)
packet = runtime.activity_packet(20.0, {"source": "contract-test"})
path = exp / "activity-stream/replay.jsonl"
path.write_text(json.dumps(packet, default=np_json) + "\n", encoding="utf-8")
replay = json.loads(path.read_text().splitlines()[0])
result = {"contract_frozen": True, "version": ACTIVITY_STREAM_VERSION, "event_only": True, "replay_exact": replay == json.loads(json.dumps(packet, default=np_json)), "schema": str(exp / "activity-stream/activity-packet.schema.json")}
write_json(exp / "activity-stream/replay-test.json", result)
return result
def freeze_io(exp: Path, cfg: dict[str, Any], code_dir: Path, api_tests_result: dict[str, Any]) -> dict[str, Any]:
root = Path(cfg["paths"]["model_root"]) / "io-v1"; root.mkdir(parents=True, exist_ok=True)
for name in ("VERSION.json", "MANIFEST.json", "checksums.sha256"):
path = root / name
if path.exists(): path.chmod(0o644)
sources = [code_dir / "brain_runtime.py", code_dir / "phase4d.py", code_dir / "phase4d.yaml"]
for src in sources:
dst = root / src.name
if dst.exists(): dst.chmod(0o644)
shutil.copy2(src, dst); dst.chmod(0o444)
version = {
"name": cfg["names"]["io_api"], "api_version": API_VERSION,
"input_batch_version": INPUT_BATCH_VERSION, "activity_stream_version": ACTIVITY_STREAM_VERSION,
"runtime_dependency": cfg["names"]["runtime"], "game_agnostic": True,
"api_methods": ["reset", "step", "read_spikes", "read_population", "read_output", "get_state_summary", "checkpoint_state", "restore_state"],
"continuous_gpu_state": True, "api_tests": api_tests_result,
"prohibitions": cfg["prohibitions"],
}
write_json(root / "VERSION.json", version); (root / "VERSION.json").chmod(0o444)
files = sorted(p for p in root.iterdir() if p.is_file() and p.name not in ("MANIFEST.json", "checksums.sha256"))
manifest = {"artifact": "io-v1", "files": [{"path": p.name, "bytes": p.stat().st_size, "sha256": sha256(p)} for p in files]}
write_json(root / "MANIFEST.json", manifest); (root / "MANIFEST.json").chmod(0o444)
targets = files + [root / "MANIFEST.json"]
(root / "checksums.sha256").write_text("".join(f"{sha256(p)} {p.name}\n" for p in targets), encoding="utf-8"); (root / "checksums.sha256").chmod(0o444)
return version
def seal(exp: Path, cfg: dict[str, Any], code: list[Path], input_files: list[Path], summary: dict[str, Any]) -> None:
controls = {exp / "manifests/manifest.json", exp / "manifests/checksums.sha256"}
outputs = sorted(p for p in exp.rglob("*") if p.is_file() and p not in controls)
manifest = {
"phase": "4D", "status": summary["status"], "created_unix_time": time.time(),
"software": {"python": platform.python_version(), "torch": torch.__version__, "numpy": np.__version__, "pyarrow": pa.__version__},
"code": [{"path": str(p), "sha256": sha256(p)} for p in code],
"immutable_inputs": [{"path": str(p), "sha256": sha256(p)} for p in input_files],
"outputs": [{"path": str(p), "bytes": p.stat().st_size, "sha256": sha256(p)} for p in outputs],
"prohibitions": cfg["prohibitions"],
}
write_json(exp / "manifests/manifest.json", manifest); targets = outputs + [exp / "manifests/manifest.json"]
(exp / "manifests/checksums.sha256").write_text("".join(f"{sha256(p)} {p.relative_to(exp)}\n" for p in targets), encoding="utf-8")
def main() -> None:
ap = argparse.ArgumentParser(); ap.add_argument("--config", required=True, type=Path); args = ap.parse_args()
cfg = yaml.safe_load(args.config.read_text(encoding="utf-8")); exp = Path(cfg["paths"]["experiment_root"])
for sub in ("configs", "populations", "visual-adapter", "readout", "latency", "continuous-control", "separability", "activity-stream", "regression", "audit", "compiler-reports/extension-build", "manifests"):
(exp / sub).mkdir(parents=True, exist_ok=True)
shutil.copy2(args.config, exp / "configs/phase4d.yaml")
runtime_root = Path(cfg["paths"]["runtime_root"]); phase4c = Path(cfg["paths"]["phase4c_root"])
immutable = [runtime_root / "VERSION.json", runtime_root / "checksums.sha256", phase4c / "manifests/checksums.sha256", phase4c / "visual-audit/summary.json"]
before = {str(p): sha256(p) for p in immutable}
runtime = BrainRuntime(args.config, exp / "audit/extension-build")
adapter = VisualAdapterV1(cfg, phase4c)
population_summary = freeze_populations(exp, runtime)
contracts = freeze_contracts(exp, cfg, runtime, adapter)
side = audit_visual_sides(exp, runtime, adapter)
pattern_cache = {mode: patterns(adapter.population(mode), cfg) for mode in ("engineering-first-order", "engineering-second-order")}
pattern_summary = {mode: {name: int(np.count_nonzero(v)) for name, v in pats.items()} for mode, pats in pattern_cache.items()}
write_json(exp / "visual-adapter/synthetic-patterns.json", pattern_summary)
write_json(exp / "visual-adapter/modes.json", cfg["visual_adapter"])
api = api_tests(exp, runtime)
windows = window_experiments(exp, cfg, runtime, adapter, pattern_cache)
continuous = continuous_control(exp, cfg, runtime, adapter, pattern_cache)
sep = separability(exp, cfg, runtime, adapter, pattern_cache, side)
reg = regression(exp, cfg, runtime)
stream = stream_contract(exp, runtime)
after = {str(p): sha256(p) for p in immutable}
if before != after: raise RuntimeError("Phase 4C/runtime-v1 immutable input changed")
reg_pass = all(x["passed"] for x in reg.values())
status = "PASS" if api["all_passed"] and reg_pass and stream["contract_frozen"] else "FAILED"
summary = {
"status": status, "brain_runtime_api_frozen": api["all_passed"], "api_tests": api,
"visual_adapter_modes_complete": True, "output_populations": population_summary,
"contracts": contracts,
"window_experiments": windows["summary"],
"continuous_control": {k: {x: v[x] for x in v if x != "intervals"} for k, v in continuous.items()},
"separability": sep, "activity_stream": stream,
"phase4c_regression_all_passed": reg_pass, "phase4c_regression": reg,
"immutable_inputs_unchanged": True, "left_right_audit": side,
"no_stable_retro_rom_buttons_training_or_web": True,
}
write_json(exp / "audit/summary.json", summary)
code_dir = Path(__file__).resolve().parent
io_version = freeze_io(exp, cfg, code_dir, api); summary["io_version"] = io_version
write_json(exp / "audit/summary.json", summary)
seal(exp, cfg, [code_dir / "brain_runtime.py", Path(__file__).resolve(), args.config.resolve()], immutable, summary)
if status != "PASS": raise RuntimeError("Phase 4D validation failed; see audit/summary.json")
if __name__ == "__main__": main()