"""Read-only CPU accounting for the sealed AH replay callback. Source/sign lanes are conditional, non-feedback bookkeeping, not additional neurons, conductances, energies, or a whole-brain causal intervention. The caller supplies anatomical groups and must independently verify the original events/state and due/pending coverage. No files, Torch, or simulation entry points are used here. """ from collections.abc import Mapping import json import numpy as np DT_MS = .1 COEFF_KEYS = ("gd", "c0", "cg", "cv", "threshold", "reset", "seed_volt") FLOAT_KEYS = ("old_v", "old_g", "v_integrated", "g_decayed", "v_threshold", "v_after_reset", "g_after_reset", "v_pre_apl", "g_pre_apl", "delta_si", "v", "g") INT_KEYS = ("ref_before", "ref_after_reset", "ref_pre_apl", "ref") BOOL_KEYS = ("available", "request", "request_accepted", "request_rejected", "fired") def require(value, message): if not value: raise ValueError(message) def bit_equal(a, b): return (a.dtype == b.dtype and a.shape == b.shape and np.array_equal(np.ascontiguousarray(a).view(np.uint8), np.ascontiguousarray(b).view(np.uint8))) class MBONAccounting: """callback(tick, stage); finish() -> (per_target, per_edge, JSON summary). Group arrays have shape (N,G), sign lanes (N,G,2), with sign order positive, negative. Negative increments/integrals retain their negative sign. Histories use (T,N), or (T,N,G,2) for history_group_g. Target indices are incoming.dst_local, not global IDs; the caller joins the verified target list. Float64 lanes retain their own canonical additions; summing lanes is not the runtime's interleaved accumulation, so residuals are reported without correcting them or assigning them to an anatomical source. """ def __init__(self, incoming, groups, group_names, coeff, steps): require(isinstance(steps, (int, np.integer)) and not isinstance(steps, (bool, np.bool_)) and 0 < steps <= np.iinfo(np.int32).max, "steps must be a positive int32-range integer") require(isinstance(group_names, tuple) and group_names and all(isinstance(x, str) and x for x in group_names) and len(set(group_names)) == len(group_names), "group_names must be a nonempty tuple of unique names") require(isinstance(coeff, Mapping), "coeff must be a mapping") self.coeff = {} for key in COEFF_KEYS: value = coeff.get(key) require(not isinstance(value, (bool, np.bool_)) and isinstance(value, (int, float, np.integer, np.float64)) and np.isfinite(value), "Missing/non-double/nonfinite coefficient: " + key) self.coeff[key] = np.float64(value) require(self.coeff["seed_volt"] > self.coeff["threshold"], "seed_volt must exceed threshold") require("dt_ms" not in coeff or coeff["dt_ms"] == DT_MS, "AH time step is fixed at .1 ms") require(isinstance(incoming.target_count, (int, np.integer)) and 0 < incoming.target_count <= 166700, "Invalid incoming target count") self.n, self.steps, self.names = int(incoming.target_count), int(steps), group_names self.e = len(incoming.edge_id) for name, dtype in (("src_global", "int32"), ("dst_local", "int32"), ("edge_id", "int64"), ("weights", "float64")): value = np.asarray(getattr(incoming, name)) require(value.dtype == np.dtype(dtype) and value.shape == (self.e,), "Invalid incoming " + name) setattr(self, name, value.copy()) require(np.all((self.src_global >= 0) & (self.src_global < 166700)) and np.all(self.src_global[1:] >= self.src_global[:-1]), "Noncanonical incoming sources") require(np.all(self.edge_id >= 0) and np.all(self.edge_id[1:] > self.edge_id[:-1]), "Noncanonical edge IDs") require(np.all((self.dst_local >= 0) & (self.dst_local < self.n)) and np.isfinite(self.weights).all(), "Invalid incoming destination/weight") codes = np.asarray(groups) require(codes.dtype == np.int32 and codes.shape == (self.e,) and np.all((codes >= 0) & (codes < len(self.names))), "groups must be int32 per incoming row") self.groups = codes.copy() self.ticks, self.finished, self.previous = 0, False, None shape = (self.n, len(self.names)) self.counts = {key: np.zeros(shape, np.int64) for key in ("due_count", "accepted_count", "rejected_count", "accepted_zero_count", "rejected_zero_count")} self.increments = {key: np.zeros(shape, np.float64) for key in ("accepted_positive_V", "accepted_negative_V", "rejected_positive_V", "rejected_negative_V")} self.edge_due = np.zeros(self.e, np.int64) self.edge_accepted = np.zeros(self.e, np.int64) self.spike_count = np.zeros(self.n, np.int32) self.first = np.full(self.n, -1, np.int32) self.requests = {key: np.zeros(self.n, np.int64) for key in ("request_count", "request_accepted_count", "request_rejected_count")} self.sg = np.zeros(shape + (2,), np.float64) self.sv = np.zeros_like(self.sg) self.bg = np.zeros(self.n, np.float64) self.bv = np.zeros(self.n, np.float64) self.integral_g = np.zeros_like(self.sg) self.integral_v = np.zeros_like(self.sg) self.max_g_residual = np.zeros(self.n, np.float64) self.max_v_residual = np.zeros(self.n, np.float64) self.history_v = np.empty((self.steps, self.n), np.float64) self.history_g = np.empty_like(self.history_v) self.history_ref = np.empty((self.steps, self.n), np.int32) self.history_group_g = np.empty((self.steps,) + self.sg.shape, np.float64) self.history_baseline_g = np.empty_like(self.history_v) self.history_g_residual = np.empty_like(self.history_v) def _validate(self, tick, s): require(not self.finished and isinstance(tick, (int, np.integer)) and not isinstance(tick, (bool, np.bool_)) and tick == self.ticks and tick < self.steps, "Missing, duplicate or out-of-order callback") require(isinstance(s, Mapping), "stage must be a mapping") for keys, dtype in ((FLOAT_KEYS, np.float64), (INT_KEYS, np.int32), (BOOL_KEYS, np.bool_)): for key in keys: value = s.get(key) require(isinstance(value, np.ndarray) and value.shape == (self.n,) and value.dtype == dtype and np.isfinite(value).all(), "Missing/invalid stage field: " + key) h = s.get("h32") require(isinstance(h, np.ndarray) and h.dtype == np.float32 and h.shape == (self.n,) and np.all(h == 0) and np.all(s["delta_si"] == 0), "MBON requires zero graded APL h/delta") require(np.all((s["ref_before"] >= 0) & (s["ref_before"] <= 22)), "Invalid refractory value") if self.previous is not None: require(all(bit_equal(s[a], self.previous[b]) for a, b in (("old_v", "v"), ("old_g", "g"), ("ref_before", "ref"))), "Discontinuous observed state") else: require(np.all(s["ref_before"] == 0), "AH replay starts nonrefractory") ref = np.maximum(s["ref_before"] - np.int32(1), np.int32(0)) available = ref == 0 require(np.array_equal(s["available"], available), "Availability mismatch") require(np.array_equal(s["request_accepted"], s["request"] & available) and np.array_equal(s["request_rejected"], s["request"] & ~available), "Request guard mismatch") c = self.coeff v, g = s["old_v"].copy(), s["old_g"].copy() g[available] = np.multiply(c["gd"], s["old_g"][available]) v[available] = np.add(c["c0"], np.add(np.multiply(c["cg"], s["old_g"][available]), np.multiply(c["cv"], s["old_v"][available]))) require(bit_equal(v, s["v_integrated"]) and bit_equal(g, s["g_decayed"]), "Integration mismatch") v[s["request_accepted"]] = c["seed_volt"] require(bit_equal(v, s["v_threshold"]), "Request override mismatch") fired = available & (v > c["threshold"]) require(np.array_equal(s["fired"], fired), "Strict threshold mismatch") v[fired], g[fired], ref[fired] = c["reset"], np.float64(0), np.int32(22) for key, value in (("v_after_reset", v), ("g_after_reset", g), ("ref_after_reset", ref)): require(bit_equal(s[key], value), "Reset mismatch: " + key) due, accepted = s.get("due_edge_indices"), s.get("arrival_accepted") require(isinstance(due, np.ndarray) and due.dtype == np.int64 and due.ndim == 1 and np.all((due >= 0) & (due < self.e)) and np.all(due[1:] > due[:-1]), "Noncanonical due edge rows") require(isinstance(s.get("due_edge_id"), np.ndarray) and bit_equal(s["due_edge_id"], self.edge_id[due]), "Due edge-ID mismatch") require(isinstance(accepted, np.ndarray) and accepted.dtype == np.bool_ and accepted.shape == due.shape and np.array_equal(accepted, ref[self.dst_local[due]] == 0), "Arrival acceptance mismatch") require(tick >= 18 or not len(due), "Arrival before delay 18") rows = due[accepted] np.add.at(g, self.dst_local[rows], self.weights[rows]) for key, value in (("g_pre_apl", g), ("v_pre_apl", v), ("ref_pre_apl", ref), ("v", v), ("ref", ref)): require(bit_equal(s[key], value), "Arrival/final mismatch: " + key) require(bit_equal(s["g"], np.subtract(g, s["delta_si"])), "Final g mismatch") return due, accepted def _residual(self, voltage, g): # No repair: anatomical lanes are never contaminated with roundoff. vr = voltage - np.add(self.bv, self.sv.sum(axis=(1, 2))) gr = g - np.add(self.bg, self.sg.sum(axis=(1, 2))) self.max_v_residual = np.maximum(self.max_v_residual, np.abs(vr)) self.max_g_residual = np.maximum(self.max_g_residual, np.abs(gr)) return gr def __call__(self, tick, s): due, accepted = self._validate(tick, s) if self.previous is None: self.bv, self.bg = s["old_v"].copy(), s["old_g"].copy() c, available, fired = self.coeff, s["available"], s["fired"] self.sv[available] = np.add(np.multiply(c["cg"], self.sg[available]), np.multiply(c["cv"], self.sv[available])) self.bv[available] = np.add(c["c0"], np.add(np.multiply(c["cg"], self.bg[available]), np.multiply(c["cv"], self.bv[available]))) self.sg[available] = np.multiply(c["gd"], self.sg[available]) self.bg[available] = np.multiply(c["gd"], self.bg[available]) self._residual(s["v_integrated"], s["g_decayed"]) req = s["request_accepted"] self.sv[req], self.bv[req] = 0., c["seed_volt"] self._residual(s["v_threshold"], s["g_decayed"]) self.sv[fired], self.sg[fired] = 0., 0. self.bv[fired], self.bg[fired] = c["reset"], 0. self.first[(self.first < 0) & fired] = np.int32(tick) self.spike_count += fired.astype(np.int32) for key, stage_key in (("request_count", "request"), ("request_accepted_count", "request_accepted"), ("request_rejected_count", "request_rejected")): self.requests[key] += s[stage_key].astype(np.int64) dst, codes, weights = self.dst_local[due], self.groups[due], self.weights[due] self.edge_due[due] += 1 self.edge_accepted[due[accepted]] += 1 for key, keep in (("due_count", np.ones(len(due), bool)), ("accepted_count", accepted), ("rejected_count", ~accepted), ("accepted_zero_count", accepted & (weights == 0)), ("rejected_zero_count", ~accepted & (weights == 0))): np.add.at(self.counts[key], (dst[keep], codes[keep]), 1) for key, keep in (("accepted_positive_V", accepted & (weights > 0)), ("accepted_negative_V", accepted & (weights < 0)), ("rejected_positive_V", ~accepted & (weights > 0)), ("rejected_negative_V", ~accepted & (weights < 0))): np.add.at(self.increments[key], (dst[keep], codes[keep]), weights[keep]) nonzero = accepted & (weights != 0) # add.at is sequential for repeated lane indices, preserving every # lane's relative canonical edge order. Never pre-sum edge weights. np.add.at(self.sg, (dst[nonzero], codes[nonzero], (weights[nonzero] < 0).astype(np.int32)), weights[nonzero]) gr = self._residual(s["v"], s["g"]) self.integral_g += np.multiply(self.sg, np.float64(DT_MS)) self.integral_v += np.multiply(self.sv, np.float64(DT_MS)) for value in (self.sg, self.sv, self.bg, self.bv, self.integral_g, self.integral_v, self.max_v_residual, self.max_g_residual, *self.increments.values()): require(np.isfinite(value).all(), "Nonfinite source accounting") self.history_v[tick], self.history_g[tick], self.history_ref[tick] = s["v"], s["g"], s["ref"] self.history_group_g[tick] = self.sg self.history_baseline_g[tick], self.history_g_residual[tick] = self.bg, gr self.previous = {key: s[key].copy() for key in ("v", "g", "ref")} self.ticks += 1 def finish(self): require(not self.finished and self.ticks == self.steps and self.previous is not None, "Observer must cover exactly all ticks before finish") require(np.array_equal(self.counts["due_count"], self.counts["accepted_count"] + self.counts["rejected_count"]), "Group count conservation mismatch") for key, edge in (("due_count", self.edge_due), ("accepted_count", self.edge_accepted)): grouped = np.zeros_like(self.counts[key]) np.add.at(grouped, (self.dst_local, self.groups), edge) require(np.array_equal(grouped, self.counts[key]), "Per-edge/group count mismatch") data = {"target_local": np.arange(self.n, dtype=np.int32), "spike_count": self.spike_count.copy(), "first_spike_tick": self.first.copy(), **{key: value.copy() for key, value in self.requests.items()}, **{key: value.copy() for key, value in self.counts.items()}, **{key: value.copy() for key, value in self.increments.items()}, **{"final_" + key: value.copy() for key, value in self.previous.items()}, "final_group_g": self.sg.copy(), "final_group_v": self.sv.copy(), "g_integral_V_ms": self.integral_g.sum(axis=2), "g_sign_integral_V_ms": self.integral_g.copy(), "v_sign_integral_V_ms": self.integral_v.copy(), "max_g_lane_residual_V": self.max_g_residual.copy(), "max_v_lane_residual_V": self.max_v_residual.copy(), "history_v": self.history_v.copy(), "history_g": self.history_g.copy(), "history_ref": self.history_ref.copy(), "history_group_g": self.history_group_g.copy(), "history_baseline_g": self.history_baseline_g.copy(), "history_g_residual": self.history_g_residual.copy()} edges = {"edge_id": self.edge_id.copy(), "source_neuron_idx": self.src_global.copy(), "target_local": self.dst_local.copy(), "group": self.groups.copy(), "weight_V": self.weights.copy(), "due_count": self.edge_due.copy(), "accepted_count": self.edge_accepted.copy(), "rejected_count": self.edge_due - self.edge_accepted} groups = {name: {**{key: int(value[:, gi].sum()) for key, value in self.counts.items()}, **{key: float(value[:, gi].sum()) for key, value in self.increments.items()}, "g_integral_V_ms": float(self.integral_g[:, gi].sum()), "g_positive_integral_V_ms": float(self.integral_g[:, gi, 0].sum()), "g_negative_integral_V_ms": float(self.integral_g[:, gi, 1].sum())} for gi, name in enumerate(self.names)} summary = {"complete": True, "pass_all": True, "pass_all_scope": "Observer callback coverage and internal count/state-accounting checks only", "steps": self.steps, "callback_count": self.ticks, "targets": self.n, "incoming_edges": self.e, "group_names": list(self.names), "sign_order": ["positive", "negative"], "dt_ms": DT_MS, "due_count": int(self.edge_due.sum()), "accepted_count": int(self.edge_accepted.sum()), "rejected_count": int((self.edge_due - self.edge_accepted).sum()), "groups": groups, "max_g_lane_residual_V": float(self.max_g_residual.max(initial=0.)), "max_v_lane_residual_V": float(self.max_v_residual.max(initial=0.)), "residual_policy": "Observed state minus uncorrected float64 lane sum; no fitted tolerance or anatomical reassignment", "integral_contract": "Sum of end-of-tick source g or v lanes times dt_ms; units V*ms, not conductance or energy", "increment_contract": "Nominal accepted/rejected signed per-edge increments; negative fields retain negative sign", "lane_contract": "Observed availability controls decay/integration; observed request/reset clears voltage/source history; fired clears g; canonical accepted adds only", "pending_coverage_checked_by_observer": False, "original_events_verified_by_observer": False, "caller_must_verify_original_events_final_and_queue_coverage": True, "nonfeedback": True, "parameter_changes": False, "learning": False, "functional_transfer_claim": False, "whole_brain_intervention_claim": False} # Includes aggregate overflows: a finite per-target array alone must # never permit an Infinity/NaN JSON report with pass_all=True. json.dumps(summary, allow_nan=False) self.finished = True return data, edges, summary