20 Commits

Author SHA1 Message Date
Digital Drosophila Archive b33e7ea047 Seal Phase 4AP isolated delta interface PASS, not learning 2026-09-30 18:36:01 +08:00
Digital Drosophila Archive 0bcce98332 Add isolated Phase 4AP interface coordinator and negative tests 2026-09-30 18:19:04 +08:00
Digital Drosophila Archive 8e9f8f4d56 Seal AO interface failure and verified isolated postprocessing diagnosis 2026-09-30 17:57:02 +08:00
Digital Drosophila Archive 4ff241bdc9 Add bounded two-epoch conditioning interface and exact controls 2026-09-30 17:36:27 +08:00
Digital Drosophila Archive c187d7d5a6 Prepare unregistered conditioning evaluation input and update adapters 2026-09-30 17:09:40 +08:00
Digital Drosophila Archive aeccb7d0cc Seal Phase 4AN exact continuation engineering evidence 2026-09-30 16:46:21 +08:00
Digital Drosophila Archive de61cf14b1 Seal Phase 4AM whole-brain plastic interface audit without learning claim 2026-09-30 16:11:14 +08:00
Digital Drosophila Archive 6d5f66bcc3 Audit fixed D18 credit and conditional MBON transfer (Phase 4AL) 2026-09-30 13:58:39 +08:00
Digital Drosophila Archive c6444255fe Seal Phase 4AK frozen D18 independent validation 2026-09-30 13:18:18 +08:00
Digital Drosophila Archive cb6937666f Seal Phase 4AJ fixed APL timing hypothesis audit 2026-09-30 12:08:25 +08:00
Digital Drosophila Archive 8d6b063aaf Include sealed Phase 4AI unit-test evidence log 2026-09-30 10:46:34 +08:00
Digital Drosophila Archive b2cd81c7b9 Audit conditional PN recruitment and graded APL source timing 2026-09-30 10:45:48 +08:00
Digital Drosophila Archive 9437bbff79 Seal Phase 4AH conditional KC drive audit and source accounting 2026-09-30 09:59:18 +08:00
Digital Drosophila Archive ff91a74193 Seal Phase 4AG author-APL audit and fixed CAL failure 2026-09-30 09:26:21 +08:00
Digital Drosophila Archive 7dfe5d2d87 Seal Phase4AF exact short fullgraph author GPU gate and APL integration audit 2026-09-30 08:14:16 +08:00
Digital Drosophila Archive 1eb4c52cf7 Seal Phase4AE same-precision GPU numerical gate and audit limits 2026-09-30 07:50:57 +08:00
Digital Drosophila Archive 92241aea02 Validate isolated author LIF semantics without changing frozen models 2026-09-30 07:23:09 +08:00
Digital Drosophila Archive 5008cd85ca Contextualize isolated feedback motifs with archived whole-brain input accounting 2026-09-30 01:07:42 +08:00
Digital Drosophila Archive 6fc326ccd1 Audit frozen LIF semantics and real recurrent motifs without learning changes 2026-09-30 01:00:16 +08:00
Digital Drosophila Archive 3213aada79 Audit calyx-specific PN contact scope without changing frozen baseline 2026-09-30 00:27:22 +08:00
10903 changed files with 1734286 additions and 14 deletions
+82 -14
View File
@@ -1,19 +1,87 @@
# 当前研究状态 — Phase 4AA
# Digital Drosophila — 当前状态
最新封存结果:**PASS-APL-PN-ANATOMICAL-LOCALIZATION / NO-DYNAMICS-CANDIDATE**。
初始化 README 与原 registry 快照仍按原字节保留;它们描述初始化时的 Phase 4Z 截止状态。最新结论请从本文件进入。
更新:2026-09-30。独立分支:`codex/lif-author-semantics-lab`。
- [本轮完整报告](docs/progress/phase4aa-apl-pn-scope.md)
- [本轮证据与最终结果](registry/phase4aa-apl-pn-scope/evidence/audit/final-summary.json)
- [新模型/审计源码](models/male-cns-lif/apl-pn-scope-audit-v1/PROTOCOL.md)
- [外部数据官方校验](registry/phase4aa-apl-pn-scope/evidence/external-resources/synaptic-partners/download-verification.json)
## 最近已封存结果
新增事实:268 条 APL→PN 边、4,600 contacts;3,820 contacts 在官方 CA(L/R),731 仍为 CentralBrain-unspecified。
七个重点 PN 的 APL 输入集中在 calyx,而其局部 ALLN 回路主要位于触角叶。受体、末梢作用系数与功能因果仍未确认。
Phase 4AP:**PASS-EXACT-PROCESS-ISOLATED-DELTA-INTERFACE-NOT-LEARNING**。
5/5 frozen-v2 trials 事件/计数/V/g 精确一致;230,239 个旧科学文件哈希不变。
没有训练,没有新动力学候选,顶层 gates 仍是 5/10(50%)。
下一步是预先定义 compartment/terminal-specific upstream 假设和对照,不直接改冻结模型,不调学习率来制造通过。
12/12 个槽位完成(明确导入 1 条 AO 轨迹,新增 11 次神经运行);复用原两组输入,未重新抽样。
6/6 reference/light 比较与 6/6 跨 arm 对照精确通过;D0/frozen 保持零更新,D1 两轮分别有 90/79 条目标 compartment 边更新,跨 compartment 为 0。第二轮实际安装第一轮 90 条非零 delta。旧 28 套完整性与 AO/诊断/AN/AM 封存前后通过,原 AO 失败记录不变。
官方 syn-partners 附加数据为 6,777,179,098 bytes,在新实验 external-resources 目录;raw 不变,未下载 EM。
Git 只保存代码、报告和 manifest;新增完整配对数据尚未异机备份。
40/40 服务器接口测试及 14/14 发布工具测试通过;无 NaN/Inf。仍没有 A/B 功能学习评估或 learned candidate,两个 A epoch 的总放电数也没有展示对照差异。下一步集中完成 retention 更新边界、完整学习门与端到端预算准备,再进入真实正常 acquisition;不再以接口 PASS 替代学习。
[AP 正式结果与下一步](docs/progress/phase4ap-interface-status.md) · [正式状态](registry/phase4ap-conditioning-interface-v2/evidence/audit/final-status.json)
## 前一项接口中止
Phase 4AO:**FAIL-POSTPROCESS-MODULE-IDENTITY**,学习效果尚未判断。
登记 12 条两轮 delta 衔接验证,仅第一条 reference 神经轨迹完成并封存(120 ms、36,539 spikes、无 NaN/Inf);随后因两个同源 loader 的缓存归属冲突停止,完整流程完成数为 0/12。未重跑轨迹、未覆盖源码、未启动完整 conditioning。
独立 CPU 进程后处理诊断已通过:同一轨迹产生 90 条目标 compartment 非零 delta,跨 compartment 改动为 0;未安装新权重,不能据此认定学习成功。AN/AM 封存与 28 套旧完整性再次通过。下一步单独登记进程隔离协调器,不能恢复或改写本次已封存 AO。
[AO 结果、原因与后续边界](docs/progress/phase4ao-interface-status.md) · [正式失败状态](registry/phase4ao-conditioning-interface/evidence/audit/final-status.json)
## 前一项工程验证
Phase 4AN:**PASS-EXACT-LIGHT-CONTINUATION-ENGINEERING-NOT-LEARNING**。
固定 zero/static25 输入下,32/32 次运行及 74 项比较通过;分段续跑保留精确事件、末态和延迟队列,独立 CSR 审计覆盖真实非零跨段到达。AM 双封存及 28 套旧完整性记录再次通过。没有训练,未生成 learned candidate;结论只覆盖注册的 100 ms 输入及固定切点,不是普遍动力学证明。
light 的 100 ms 核心模拟约 2.15–2.19 s,单条输出约 2.60 MB,尚未达到实时。整个 32-call 执行流程约 433.97 s;首次编译、校验和保存都包含在该流程时间内。
[AN 结果及预算边界](docs/progress/phase4an-interpretation.md)。注册 SHA:`7317441126f191ccc6e6d28438870b3921537ebe282a6acb163716a690057945`;实验 manifest SHA:`e8952a48cd3ea6a93c811a1183a1f7b79e19646299924e7688e5f393737a9aa2`。
## 全脑固定权重接口
Phase 4AM:**PASS-EXACT-WHOLEBRAIN-PLASTIC-INTERFACE-NOT-LEARNING**。
独立建立 D18 whole-brain plastic-overlay 接口,不覆盖或替换旧 reference/runtime。
75/75 服务器单元测试通过;完整性链 28 个根运行前后全部通过,五组旧参考重新运行全部精确。
预注册 SHA-256:`465886b78ada08092c2c83de278844707499718977fb6dc6a7608391da0e5304`。
- 零 delta 门完成:120 个固定主输入及 24 次技术重复,共 **144/144 与 Phase 4AK D18 精确一致**。
- 同一库存 static25 的 144 次闭环运行完成,24 次技术重复精确一致;真实反馈重新计算,不钳制源事件。
- static25 是原 float32 候选权重的 25% floor 经明确 SI 精度桥接,不是学习结果,也不声称等于 float64 基础权重的精确 25%。
- 120/120 主试验的 MBON、实际 downstream、descending、motor 事件序列及逐细胞计数有变化;12 个 mask 目标的计数变化为 119/120、事件变化为 120/120;KC 事件变化 120/120、计数变化 32/120。这不是每个细胞都变化,也不是学习或行为 PASS。
- 两阶段都不训练,未产生 learned candidate。zero/static25 阶段墙时分别约 1665.34/1471.04 秒;主试验最大已分配显存 526,523,392 bytes。
运行目录:`experiments/phase4am-wholebrain-plastic-interface/`。
[AM 结果解释](docs/progress/phase4am-interpretation.md) · [正式状态](registry/phase4am-wholebrain-plastic-interface/evidence/audit/final-status.json) · [预注册设计](models/male-cns-lif/wholebrain-plastic-interface-v1/PROTOCOL.md)
## 前序结论保持不变
Phase 4AL:**PASS-CONDITIONAL-CREDIT-TRANSFER-AUDIT-NOT-LEARNING**。
固定 D18 的 120 条主轨迹及 24 次重复全部 MBON 基线逐位复现;60 组气味对都有各自特有的 KC/候选边。固定 25% 减弱在 120/120 主试验中改变了 MBON count 或首次 latency,但那是钳制源事件的条件性回放,不是真实全脑反馈、不代表气味特异记忆或响应上界。
14,232 条 mask 边、12 个 mask-recipient MBON 和全部 97 个 MBON 保留。
Phase 4AK D18 表征验证 PASS 原样保留。1.8 ms 为工程 APL 时序假设,不是实测延迟;matched_energy 匹配预期而非每次实际事件数;旧 1212 条非 KC fast-APL 出边未被 graded 路径替代的限制仍存在。
[AL 结果解释](docs/progress/phase4al-interpretation.md) · [AL 正式状态](registry/phase4al-mb-credit-transfer/evidence/audit/final-status.json) · [AK 结果解释](docs/progress/phase4ak-interpretation.md)
## 当前准备与学习边界
Phase 4AN 的有限工程门已封存;21 份实际使用源码已按 SHA 锁定。AO 进一步登记了包含科学准备代码的 51 份源快照,实验以接口失败封存。AP 使用独立目录的 5 份新源码完成进程隔离门,旧 51 源不变;lab 整个目录仍未封存,完整科学条件化协议尚未登记执行,没有学习候选。
评估清单和完整条件化政策仍是科学草案;完整 63 位输入、单轮更新桥及 fresh-reset 跨轮 delta 实际安装已通过有限 AO/AP 证据链,不能等同于完整学习。历史准备记录见[条件化准备进度与限制](docs/progress/conditioning-preparation-2026-09-30.md),当前接口结果以 AP 报告为准。
服务器 CPU 合成测试 119/119 通过,0 跳过;21 个 AN 注册源测试前后 SHA 均未变。当前续跑器禁止父子段更换 overlay,因此“保留末态并使用新 delta”的 retention 更新边界仍需新增接口验证,不是现有工程 PASS 已覆盖的能力。
完整 conditioning 草案为 68,000 epochs、10,760 生物秒(含 idle),新显式评估政策再列出 9,440 次 probes / 1,132.8 生物秒,总计 11,892.8 生物秒。这是未执行的条件性计划库存,不是工期预算。真实 CUDA 输入检查在 AO 通过,后处理冲突由独立 AP 接口解决。仍需反转/连续保持功能门、实际末态与新 delta 衔接及完整端到端资源预算,不直接启动大批量训练。
目标仍是“学习可以使用”,当前没有达到。接口验证或静态权重效果不能替代真实条件化。
后续须预注册固定 olfactory A/B、具体 DAN type/compartment、至少五个互不重叠训练种子流及独立 evaluation streams;保留原 eligibility-v2、人工 US 与实际 DAN 放电的明确区分,以及配对/控制、反转、延迟奖励、保持等功能验证。
继续冻结 raw/base CSR/W_syn/sign、既有 APL 参数、eligibility-v2、14,232-edge mask 和全部已封存产物。不调参挽救结果,不接游戏、视觉、decoder、RL 或 Web。
AM 已正式封存并在服务器发布 3,020 份小证据;本地已按发布收据逐项验收 3,040 个文件(含控制与清单文件)。AN 的 599 个小证据文件已逐项本地验收;620 个实际 Git blobs 校验通过并推送为 `aeccb7d0ccdcf6788e0a8de60e7ab96f70dbe734`。Git 同步范围仅为源码、文档及小证据。大型轨迹保留在服务器,小证据同步不等于全量异机备份。
模型 manifest SHA-256:`7edeb251ecbeac5a64805fefe171a0a0bf8bba2675919ef922cc1a329c203ea8`。
实验 manifest SHA-256:`9e24b682935a9b18e05db7a933080c5f63ddbeb8a0c85cc0df1cfe1d06d88ab4`。
正式状态 SHA-256:`18b12c832e156bd6e5ba950f48a49fb908c62104b91bb3e78213f523c8fdc8f9`。
AP 新登记源码 commit:`0bcce983324ecfe1c75826a23e94ff932ad5e883`。
AP 实验 manifest SHA:`a40e433541a6c02f7ad95622e96646da9a90a93e4e43cb3abfde3846b2554f00`。
AP registry 共 356 份小文件已本地逐项 SHA 验收。Git 只同步源码、文档和小证据,不包含服务器大型轨迹。
@@ -0,0 +1,56 @@
# 独立条件化分支:准备进度与边界
状态:**未注册的科学实现草案,不是 learning PASS,不是 learned candidate**。
已完成的 Phase 4AN 工程证据另行封存并推送至
`aeccb7d0ccdcf6788e0a8de60e7ab96f70dbe734`:32/32 次 GPU 运行、74 项精确比较通过。
599 个小证据文件已下载到本地逐项验收,共 5,508,335 bytes;620 个实际 Git blobs
(含 21 个注册源文件)核对通过。大体积轨迹仍在服务器,不是全量异机备份。
## 本次补齐的实现
1. 评估清单:完整重建训练计划和独立评估种子来源;同一训练重复内复用 A/B
评估输入作配对比较,不能把反复 probe 当成更多训练重复。
2. 显式评估政策:CS 为 0–100 ms,观察到 120 ms;保留 0/1/2/5/10/20/50
检查点。控制组核对实际有序 CS 前缀及源种子,不只核对数量。
3. 输入接口:保留原离散 float32 Bernoulli 抽样、PN 列顺序和完整 63 位种子;
必须指定 CUDA 设备和抽样上限。CS/US 重叠默认报错,显式布尔合并才允许并记录冲突。
4. 单轮更新桥:复用固定 SHA 的 AM/J 原实现,从本轮真实稀疏事件计算 eligibility,
在完整 epoch 结束后返回下一轮 delta;只计算,不安装权重,不改 base。
这里的输入单元测试使用 CPU/mock,不代表已经实测 CUDA 随机序列或高位种子的作用。
单轮更新测试使用合成事件,不是已经运行条件化。人工 D 指令与实际 DAN 放电仍是两项证据。
attempted update、实际 delta 改变和已达 depression floor 分别统计。
服务器 CPU 合成测试:**119/119 通过,0 跳过**,测试框架记录耗时 241.205 s。
其中包含原 Torch CPU eligibility 表达式与 NumPy 路径的合成数值比较,不是 CUDA 比较。
运行时隐藏全部 CUDA 设备;没有真实脑输入、网络模拟或 conditioning。21 个 AN 注册源在
测试前后均另行校验保持原 SHA。
## 对齐不等于所有条件相同
非配对控制的中间奖励次数、经过时间可以与配对组不同;随机奖励的中间奖励次数也可能不同。
这些差异单独记录,不称为全量匹配。DAN-only 的 CS 被有意移除,不能声称 CS exposure 相同。
反转两臂各按自己的强化机会取点,但保留原始 acquisition 的气味方向与 pre baseline。
所有检查点都在完整 epoch 及其边界更新之后,不是在 US tick 当场插入 probe。
该政策条件性列出 9,440 次评估(1,132.8 生物秒),加已有训练/控制/连续 idle 共
11,892.8 生物秒;这是完整草案的计划库存,不是已执行数量,也不是工期预算。
完整批量训练尚未启动。
## 下一步仍然缺少
- 把每个真实输入、delta-before/after、状态和队列绑定外部 SHA 与祖先记录的完整协调器。
- 在指定 4090 上预先登记有限输入/更新衔接验证,实测完整种子、参考一致性和实际开销。
- 完成反转与连续 retention 的功能门实现,并核算完整存储、时间上限和停止条件。
- retention 还有明确接口缺口:当前冻结续跑器要求子段 overlay 与父检查点完全相同。
最后训练 epoch 的末态属于 delta-before,边界更新却产生 delta-after;不能把这组
“原神经末态 + 新权重”伪装成已经验证的同权重续跑。必须在新文件中明确实现并有限验证
更新边界的状态交接,不能修改封存续跑器来绕过约束。
- 以上通过后才登记执行 acquisition 及全部控制;若失败,保留失败证据,不通过改参数补救。
全部新增科学代码仍是 DRAFT;源文件清单与测试记录保存于
`models/male-cns-lif/olfactory-conditioning-lab-v1/draft-source-inventory.json`。
该记录不是实验注册或目录封存。既有 21 个 AN 注册源按其原清单单独核验,不纳入新草案清单。
不运行游戏、RL、decoder、视觉、Web 或 3D;不改 frozen reference/runtime、图、符号、
W_syn、APL 标定、eligibility-v2 或 14,232-edge mask。
@@ -0,0 +1,48 @@
# 小反馈环在全脑中的位置:充分性不等于唯一原因
这是对既有封存记录的只读复核,不是新的训练阶段或新模型。
使用六个旧校准气味、seed 131101 的全部 frozen_reference 记录,没有运行新模拟,也没有使用 held-out 输入。
## 新量化结果
晚期时窗为 500–1,000 ms,下表逐气味统计后列范围。
比例分母为该目标的全部正突触到达权重之和,不是净输入、g 轨迹、电压贡献或因果责任。
| 目标 | 五节点小回路内部正输入比例 | 正输入来源神经元数 | 累计80%正输入需要的来源数 |
|---|---:|---:|---:|
| ALLN 1197 / body11289 | 8.96%–8.99% | 197 | 49 |
| ALLN 1381 / body11478 | 7.86%–7.89% | 214 | 51 |
| ALLN 1511 / body11620 | 7.57%–7.60% | 205 | 52 |
| VA6 PN 133666 / body527577 | 10.18%–10.22% | 119 | 31 |
| KC 82312 / body109321 | 36.16%–36.39% | 8 | 4 |
因此,4AC 的小回路能在隔离条件下持续放电,但其成员在全脑里接收了大量回路外输入。
不能据此把某两条边定为唯一病因,或者认为只修两枚细胞就能解决学习问题。
“回路外”仅表示不属于所选五节点;这些来源仍可能受该小回路反馈影响,**并非已经证明独立于该回路**,也不是外部刺激。
## 同时公开已有条件回放,避免只挑支持某个解释的结果
| 目标 | 基线晚期 spike | 忽略ALLN到达 | 忽略ALPN到达 |
|---|---:|---:|---:|
| ALLN 1197 | 228 | 217–218 | 227 |
| ALLN 1381 | 227–228 | 227–228 | 227 |
| ALLN 1511 | 228 | 219–221 | 227–228 |
| VA6 PN 133666 | 212–214 | 0 | 208–210 |
| KC 82312 | 60–61 | 60–61 | 0 |
这些结果来自已封存 Phase 4Z,不是本轮重新模拟;回放固定其他已记录输入和 APL,不能替代实时全脑干预。
ALLN 原本已接近模型不应期限制,放电计数相同不等于膜状态或输入没有影响。
PN→KC 中有些比例并不占绝大多数的输入仍能决定阈值跨越,不能按比例大小直接删边。
4Z 当时没有孤立回路自持的证据;4AC 已补上数学模型下的孤立充分性。
二者合起来仍没有证明该小回路在全脑中的必要性、唯一性或真实果蝇中的同样动力学。
## 对下一步的实际影响
独立新模型实验若获授权,应先核对原作者算子,再检验分布式局部反馈与输入特异性;不把两神经元回路上的改善直接外推全脑学习。
仍不得靠提高抑制、改符号、调学习率/阈值或扩大mask来追求通过。
在此之前,本轮不会启动替代动力学、conditioning、游戏或decoder。
来源与逐试次完整表:`registry/feedback-context-review-20260930/`。
9个输入文件均对照原有封存manifest核验,前后字节一致;13条小回路边与旧事件会计的源、目标、count逐条一致。
全部输出有manifest和SHA-256。后续更新应新增材料,不重写已封存数据。
@@ -0,0 +1,52 @@
# Phase 4AB — calyx contact-scope diagnostic
Status: COMPLETE-SCOPE-COUNTERFACTUAL / NO-DYNAMICS-CANDIDATE.
Diagnostic interventions only; no calibrated biological inhibition, no training, no parameter winner.
Eligible PNs: 229/259. CA mask: 20263 edges / 337099 contacts.
Affected KCs: 3760. Mixed-ROI affected edges: 3323; retained other contacts: 28975.
Broader PN→KC control: 21882 edges / 384555 contacts. All-fast-PN-output control: 116211 edges / 1268111 contacts.
| Odor | Condition | Active KC | KC late spikes | KC82312 late | VA6 late |
|---|---|---:|---:|---:|---:|
| ethyl (R)-(-)-3-hydroxybutanoate | frozen_reference | 160 | 114 | 60 | 213 |
| ethyl (R)-(-)-3-hydroxybutanoate | calyx_PN_KC_contact_block | 1 | 39 | 0 | 214 |
| ethyl (R)-(-)-3-hydroxybutanoate | all_PN_KC_block | 1 | 39 | 0 | 214 |
| ethyl (R)-(-)-3-hydroxybutanoate | whole_PN_output_block | 0 | 0 | 0 | 0 |
| 3-penten-2-one | frozen_reference | 172 | 118 | 60 | 213 |
| 3-penten-2-one | calyx_PN_KC_contact_block | 2 | 39 | 0 | 213 |
| 3-penten-2-one | all_PN_KC_block | 1 | 39 | 0 | 213 |
| 3-penten-2-one | whole_PN_output_block | 0 | 0 | 0 | 0 |
| (2R)-hexan-2-ol | frozen_reference | 144 | 117 | 61 | 213 |
| (2R)-hexan-2-ol | calyx_PN_KC_contact_block | 1 | 39 | 0 | 213 |
| (2R)-hexan-2-ol | all_PN_KC_block | 1 | 39 | 0 | 213 |
| (2R)-hexan-2-ol | whole_PN_output_block | 0 | 0 | 0 | 0 |
| gamma-propyl-gamma-butyrolactone | frozen_reference | 151 | 117 | 60 | 212 |
| gamma-propyl-gamma-butyrolactone | calyx_PN_KC_contact_block | 2 | 39 | 0 | 212 |
| gamma-propyl-gamma-butyrolactone | all_PN_KC_block | 1 | 40 | 0 | 212 |
| gamma-propyl-gamma-butyrolactone | whole_PN_output_block | 0 | 0 | 0 | 0 |
| 2-methyl butyl acetate | frozen_reference | 139 | 118 | 61 | 213 |
| 2-methyl butyl acetate | calyx_PN_KC_contact_block | 1 | 39 | 0 | 212 |
| 2-methyl butyl acetate | all_PN_KC_block | 1 | 39 | 0 | 212 |
| 2-methyl butyl acetate | whole_PN_output_block | 0 | 0 | 0 | 0 |
| ethyl (S)-(+)-3-hydroxybutanoate | frozen_reference | 163 | 119 | 61 | 214 |
| ethyl (S)-(+)-3-hydroxybutanoate | calyx_PN_KC_contact_block | 1 | 39 | 0 | 214 |
| ethyl (S)-(+)-3-hydroxybutanoate | all_PN_KC_block | 1 | 39 | 0 | 214 |
| ethyl (S)-(+)-3-hydroxybutanoate | whole_PN_output_block | 0 | 0 | 0 | 0 |
Late means 500–1,000 ms; 120 ms old calibration odor input; one seed, six old odors. No held-out generalization claim.
Identical scheduled requests across conditions. Delivered request-associated output differences versus reference: 459 (summed over all comparisons). See per-trial table; this is state/refractory feedback, not a changed RNG.
## Interpretation limits
CA selection uses exact primary_post labels plus matched APL→PN/ROI metadata, not bouton identities or inferred receptors. Unknown ROIs are not reclassified.
Whole-PN control removes fast output, not somatic spikes or the frozen graded APL input. It is not a complete PN knockout.
Reduction/silencing is not restored information or associative memory. No condition becomes a formal model. Fixed-event replay freezes other recorded events/APL; dynamic trials allow natural recurrent feedback.
Local-inhibition motivation: [Prisco et al.](https://doi.org/10.7554/eLife.74172), [Amin et al.](https://doi.org/10.7554/eLife.56954). These sources do not establish the complete-block operator as physiological.
## Verification
Six original trials reproduced exactly (whole spike events, watched state and final counts/V/g). Four first-odor repeats exact. Five deterministic-v2 frozen reference trials exact. Finite state throughout.
Original 230,239 files and both Phase 4AA manifests rechecked before/after. Base CSR/count/sign, frozen LIF/APL, eligibility-v2 and 14,232 plastic mask preserved.
Timing includes diagnostic CPU/GPU observation overhead and is not a runtime speed benchmark. ComfyUI was not stopped or unloaded.
Top-level acceptance gates remain 5/10 (50%); anatomical diagnosis is not evidence of learning success.
+36
View File
@@ -0,0 +1,36 @@
# Phase 4AB 机制解读
正式状态:**COMPLETE-SCOPE-COUNTERFACTUAL / NO-DYNAMICS-CANDIDATE**。
这一轮区分了“PN→KC 传入位置”与“维持 PN 放电的上游反馈”。没有修复或批准新的 APL 生理模型,也没有训练。
| 诊断范围 | 活跃 KC(6 个旧气味) | 目标 KC 晚期 spikes | VA6 PN 晚期 spikes |
|---|---:|---:|---:|
| 原模型 | 139–172 | 60–61 | 212–214 |
| 仅明确 calyx 接触 | 1–2 | 0 | 212–214 |
| 同批 PN 的全部 KC 输出 | 1 | 0 | 212–214 |
| 同批 PN 的全部快速输出 | 0 | 0 | 0 |
晚期窗口是 500–1,000 ms。每个气味沿用 seed 131101;总计 24 组诊断、4 次精确重复,不是 5-seed 学习验证。
## 能说明什么
仅 calyx 接触阻断后,目标 KC82312 的晚期 spikes 范围为 0,VA6 仍为 212–214。
同时 KC 总活跃数降为 1–2,原模型为 139–172。不能把这种接近静默的结果包装成编码或记忆改善。
即使两个局部阻断条件的事件序列相同,其电压/g 仍可能不同;逐气味比较见 narrow-vs-allKC.csv。
宽范围 PN 快速输出阻断影响反馈路径,不等价于局部 calyx 调制;它也没有关闭 PN 胞体或 frozen graded APL 的 PN 输入。
## 仍不能说明什么
完全阻断只是工程极端对照,不是 APL 的实测释放抑制比例。没有估计 receptor、bouton、局部扩散范围或时间常数。
未使用 held-out 气味,未检验学习、保持、反转或动作输出。不得选取这次“让活动更少”的操作作为正式脑模型。
剩余 late KC 的 ID/type 已单独保存;其来源不能仅凭残余计数猜测。
## 下一步边界
先继续 upstream feedback / compartment-specific physiology 的证据约束,区分 calyx 信号传递与触角叶持续放电,再确定可检验的局部动力学假设。
不能靠增加整体抑制、调 eta/threshold、扩大 plastic mask 或让 KC 全静默宣称修复。当前不进入学习、游戏或视觉。
相关原始研究:[Prisco et al., 2021](https://doi.org/10.7554/eLife.74172)、[Amin et al., 2020](https://doi.org/10.7554/eLife.56954)。它们支持研究局部 APL 作用,不直接验证本实验完全阻断幅度。
顶层验收仍为 5/10(50%);本轮推进的是机制定位与可重复诊断能力。最终完整性状态见 regression/final-integrity.json。
+71
View File
@@ -0,0 +1,71 @@
# Phase 4AC:反馈环路足以持续放电,尚未得到学习修复
状态:`COMPLETE-SEMANTICS-AUDIT / LEARNING-NOT-ACHIEVED`。
## 这次真正增加的证据
从已有异常传播路径选取真实 MaleCNS 神经元和 13 条真实连接。
只施加一次初始脉冲,随后无外部输入,观察 1 s。所有真实回路测试继续使用冻结动力学。
| 小回路 | 总放电数 | 500–1,000 ms 放电数 |
|---|---:|---:|
| 两枚 ALLN 互相连接 | 473 | 238 |
| 三枚 ALLN | 1,064 | 535 |
| 三枚 ALLN + VA6 PN + KC | 1,483 | 747 |
| 只保留四条真实前向连接的对照 | 3 | 0 |
| 五神经元回路,无初始输入 | 0 | 0 |
最小互相连接的两枚神经元是:
- neuron_idx 1381 / body_id 11478 → neuron_idx 1511 / body_id 11620:235 contacts。
- neuron_idx 1511 / body_id 11620 → neuron_idx 1381 / body_id 11478:283 contacts。
- 两者 metadata 均为 ALLN / lLN1_bc,递质 annotation 和 ground truth 均为 acetylcholine。未改变符号。
它们在冻结 LIF 下,从一次输入即可相互维持放电到 1 s 观察期末。
五神经元回路的 VA6 PN(133666 / 527577)有 297 次放电,KC(82312 / 109321)有 80 次放电。
这把“持续反馈驱动 KC”缩小到可逐步检查的真实局部回路。
**限定结论:**这是隔离回路中的充分性证据,不是全脑必要性证据;外部抑制、分级 APL 及其他回路在这里不参与。
前向对照移除了反馈连接,只是诊断 harness,不是提交了一个删边新模型。1 s 持续不等于证明无限持续。
## 原作者语义差异,不等于已找到修复
[Shiu 作者固定版本代码](https://github.com/philshiu/Drosophila_brain_model/blob/91bdd1e7dcf193f3e7ca5a8933497fcef63b7960/model.py)
在 spike 后清零 g,v/g 的不应期更新受限,使用 linear 积分和严格 > 阈值;刺激细胞的 Poisson 输入及不应期也与本项目不同。
本项目的冻结版本明确记录了保留 g、不应期继续衰减/接收输入、Euler 积分等适配选择。
因此不能把它说成 CUDA 引入的新错误,也不能把“g 清零”称为严格复现原作者模型。
本次单细胞 component tests 有意保留冻结的其他数学语义,仅分别比较 g reset 和 refractory gate。
真实 13 条连接强度加一个单突触 fixture 下,冻结策略、reset-only、reset+gate 的单次输入 spike 数相同(0 或 1)。
单独冻结不应期 g、但不清零 g,反而在 283-contact fixture 中产生 2 次 spike,而其他三种策略为 1 次。
人工持续输入停止后,冻结策略有 4 次尾随 spike,reset-only 有 1 次、reset+gate 有 0 次,gate-only 则有 14 次。
这些结果表明组件选择确实会改变响应,但不支持“随便加一个不应期限制就能解决”。
两个强连接各自仍能从一次输入触发一次响应,所以也不能仅凭单细胞 reset 测试宣称真实反馈环已被消除。
所有替代组件仅运行于人工单细胞 fixture,没有部署到 MaleCNS 全脑或训练实验。
[Brian2 2.5.1 固定实现](https://github.com/brian-team/brian2/blob/577bb35ec677947d6f3d4af367a8a4b3b88815ee/brian2/groups/neurongroup.py)
在默认非 legacy 设置下,不应期是 22 steps;第 23 step 才积分某些新到达输入属于调度顺序,不是不应期延长。
原作者模型、license、环境文件、固定 commit、SHA-256 与源码位置均已记录;尚未执行独立 Brian2 oracle。
## 验证
- 7 项单元测试通过;17 组单细胞 fixture × 4 策略均有限且重复一致。
- 五个真实小回路的全部事件、计数、每步 V/g/ref、最终状态和环形队列 CPU/GPU 精确一致。
- 五组 deterministic-v2 全脑参考 trial 的事件、计数、最终 V/g 精确一致。
- 逐条核对真实 edge_id、源 CSR 行、目标和原始 count;准备输入另有 SHA-256。
- 完整性终检覆盖原快照 230,239 项,以及 Phase 4AA / 4AB 的模型与实验 manifest。
- GPU 诊断含构建/观察/回归共 95.398 s;本进程 peak allocated VRAM 285,994,496 bytes。不是性能 benchmark,不含 ComfyUI 驻留显存。
- 保留旧加载器只读 NumPy→Torch 警告;未修改加载器,完整性和回归另行验证。
## 学习目标与下一道关口
当前没有新的 learned model,没有训练,也没有重新宣称学习 PASS。
可用学习仍须在独立评价种子上证明 A 相对中性 B 的特异性、MBON/downstream 功能变化及完整对照;权重变化、稀疏化或静默都不能替代。
下一步应先在明确授权的新模型分支中验证作者算子与有生理依据的局部反馈机制,并用独立 oracle 区分每一项语义。
不能将减少放电自动选为正确模型;还必须保留输入区别、可传播性和后续关联记忆能力。
不改 raw、CSR、原始突触数、已定递质符号、冻结版本、APL calibration、eligibility-v2 或 plastic mask。
不进入游戏、decoder、RL 或视觉路线。
Git 只同步源代码、小报告与校验清单。完整数据仍在服务器,不能声称已完成异机大数据备份。
+83
View File
@@ -0,0 +1,83 @@
# Phase 4AC — LIF semantics and unchanged-dynamics motif audit
Status: COMPLETE-SEMANTICS-AUDIT / LEARNING-NOT-ACHIEVED.
No alternative dynamics deployed to MaleCNS; no conditioning, learned candidate or new formal runtime.
## Author model versus frozen adapted model
Pinned author model resets g on a spike and declares v/g `(unless refractory)`, uses linear integration, strict > threshold and voltage Poisson input with zero refractory on stimulated cells.
The frozen adapted model retains g, decays/accepts events during refractory, uses explicit Euler and >= threshold, and forced sensory spikes respect refractory.
These are documented model choices, not a newly established GPU regression. g is an additive voltage-valued drive, not a measured conductance.
W_syn=0.275 is transferred from a free parameter calibrated in the original FlyWire feeding model, not a measured universal MaleCNS synaptic efficacy.
## Synthetic single-cell component tests
All impulse amplitudes derive from the complete unique contact counts of the predeclared 13 real motif edges plus a one-contact fixture; other boundary/sustained cases are explicitly synthetic unit tests.
These ablations retain frozen Euler arithmetic/scheduling and are NOT complete Brian2 replication. No successful amplitude or policy was selected after seeing results.
| Single-impulse fixture | Frozen | Reset g only | Refractory gate only | Reset + gate |
|---|---:|---:|---:|---:|
| one_impulse_contacts_1 | 0 | 0 | 0 | 0 |
| one_impulse_contacts_104 | 0 | 0 | 0 | 0 |
| one_impulse_contacts_172 | 1 | 1 | 1 | 1 |
| one_impulse_contacts_210 | 1 | 1 | 1 | 1 |
| one_impulse_contacts_226 | 1 | 1 | 1 | 1 |
| one_impulse_contacts_235 | 1 | 1 | 1 | 1 |
| one_impulse_contacts_259 | 1 | 1 | 1 | 1 |
| one_impulse_contacts_283 | 1 | 1 | 2 | 1 |
| one_impulse_contacts_43 | 0 | 0 | 0 | 0 |
| one_impulse_contacts_57 | 0 | 0 | 0 | 0 |
| one_impulse_contacts_64 | 0 | 0 | 0 | 0 |
| one_impulse_contacts_70 | 0 | 0 | 0 | 0 |
| one_impulse_contacts_76 | 0 | 0 | 0 | 0 |
| one_impulse_contacts_95 | 0 | 0 | 0 | 0 |
Reset-only and combined policies can produce at most one spike from a single isolated input by construction. This does not establish biological correctness or whole-brain learning improvement.
## Real anatomical motifs — frozen mathematics ONLY
One forced seed spike at step 0 except the no-input control; no subsequent input; observed for 1 s. Late window=500–1,000 ms.
The recurrent pair/trio/five are induced subgraphs. The feedforward control selects four existing edges and removes feedback only within this isolated diagnostic harness.
External inhibition, graded APL and other whole-brain inputs are absent. A sustained isolated motif is evidence of sufficiency in this harness, NOT necessity in the complete brain.
| Motif | neuron_idx | Total spikes | Late spikes | Last ms |
|---|---:|---:|---:|---:|
| pair | 1381 | 237 | 119 | 999.3 |
| pair | 1511 | 236 | 119 | 997.5 |
| trio | 1197 | 355 | 179 | 999.3 |
| trio | 1381 | 355 | 178 | 997.8 |
| trio | 1511 | 354 | 178 | 997.4 |
| five | 1197 | 370 | 185 | 998.8 |
| five | 1381 | 369 | 185 | 997.4 |
| five | 1511 | 367 | 186 | 999.5 |
| five | 82312 | 80 | 41 | 990.3 |
| five | 133666 | 297 | 150 | 999.5 |
| feedforward | 1197 | 1 | 0 | 10.0 |
| feedforward | 1381 | 1 | 0 | 0.0 |
| feedforward | 1511 | 1 | 0 | 4.9 |
| feedforward | 82312 | 0 | 0 | none |
| feedforward | 133666 | 0 | 0 | none |
| no_input | 1197 | 0 | 0 | none |
| no_input | 1381 | 0 | 0 | none |
| no_input | 1511 | 0 | 0 | none |
| no_input | 82312 | 0 | 0 | none |
| no_input | 133666 | 0 | 0 | none |
## Verification and boundaries
Seven unit tests; all five real motifs CPU/GPU event, count, final V/g/refractory, queue and timestep history exact; five archived deterministic-v2 full-brain trials exact.
Every selected edge_id, source CSR row, destination and original weight validated; generated prepared inputs hashed. All original snapshot files and Phase 4AA/4AB model/experiment manifests checked before and after.
Diagnostic wall time including compilation and observation: 95.398 s. Peak allocated process VRAM: 285994496 bytes. Not a runtime-speed benchmark.
Original author code was inspected, not executed; no Brian2 oracle run and no new package installation. ComfyUI was not stopped or unloaded.
## Decision
The usable-learning gate remains unmet: independent evaluation, A-vs-neutral-B specificity in MBON/downstream, multiple training seeds and conditioning controls still required.
Before any full-network alternative, obtain explicit separate model authorization and distinguish each semantic component; do not claim g reset alone reproduces the author implementation.
No evidence here permits changing eta, thresholds, gain, frozen APL calibration, transmitter signs or the plastic mask.
## Primary provenance
[Shiu et al. 2024](https://www.nature.com/articles/s41586-024-07763-9)
[Pinned author implementation](https://github.com/philshiu/Drosophila_brain_model/blob/91bdd1e7dcf193f3e7ca5a8933497fcef63b7960/model.py)
Downloaded source, MIT license, environment specification, exact commit, SHA-256 and source clauses retained under external-resources and audit.
@@ -0,0 +1,71 @@
# Phase 4AD 作者动力学语义实验室
状态:`COMPLETE-ORACLE-VALIDATED-LAB-ONLY`。
本轮仅有预声明的小回路与算子实验;没有整脑替代动力学运行、conditioning、学习成功或新学习候选。
检查以原始事件、状态轨迹和预注册误差界限重算。缺失、失败、非有限值或初始事件丢失均不能通过;放电减少或静默本身不构成成功。
核查通过 58/58 项;失败或不完整 0 项。
冻结历史完整性:通过。
源码与输入预注册一致性:通过。
| 回路 | 语义 | 精度 | 总spikes | late spikes |
|---|---|---|---:|---:|
| pair | frozen | float32 | 473 | 238 |
| pair | reset_g_only | float32 | 223 | 111 |
| pair | refractory_gate_only | float32 | 635 | 321 |
| pair | reset_and_refractory | float32 | 223 | 111 |
| trio | frozen | float32 | 1064 | 535 |
| trio | reset_g_only | float32 | 565 | 283 |
| trio | refractory_gate_only | float32 | 1100 | 552 |
| trio | reset_and_refractory | float32 | 469 | 235 |
| five | frozen | float32 | 1483 | 747 |
| five | reset_g_only | float32 | 868 | 433 |
| five | refractory_gate_only | float32 | 1510 | 763 |
| five | reset_and_refractory | float32 | 634 | 318 |
| feedforward | frozen | float32 | 3 | 0 |
| feedforward | reset_g_only | float32 | 3 | 0 |
| feedforward | refractory_gate_only | float32 | 3 | 0 |
| feedforward | reset_and_refractory | float32 | 3 | 0 |
| no_input | frozen | float32 | 0 | 0 |
| no_input | reset_g_only | float32 | 0 | 0 |
| no_input | refractory_gate_only | float32 | 0 | 0 |
| no_input | reset_and_refractory | float32 | 0 | 0 |
| pair | author_complete | float64 | 213 | 106 |
| pair | author_complete | float32 | 213 | 106 |
| trio | author_complete | float64 | 448 | 224 |
| trio | author_complete | float32 | 448 | 224 |
| five | author_complete | float64 | 610 | 306 |
| five | author_complete | float32 | 610 | 306 |
| feedforward | author_complete | float64 | 3 | 0 |
| feedforward | author_complete | float32 | 3 | 0 |
| no_input | author_complete | float64 | 0 | 0 |
| no_input | author_complete | float32 | 0 | 0 |
作者Brian2与独立NumPy比较:
| 实验 | 结果 | 事件一致 | 最大V/g误差 mV | 首次事件分歧step |
|---|---|---|---:|---:|
| author:pair:float64 | 通过 | True | 7.105427357601002e-14 | None |
| author:pair:float32 | 通过 | True | 2.41696834564209e-05 | None |
| author:trio:float64 | 通过 | True | 8.526512829121202e-14 | None |
| author:trio:float32 | 通过 | True | 4.25875186920166e-05 | None |
| author:five:float64 | 通过 | True | 3.836930773104541e-13 | None |
| author:five:float32 | 通过 | True | 0.0002123713493347168 | None |
| author:feedforward:float64 | 通过 | True | 3.765876499528531e-13 | None |
| author:feedforward:float32 | 通过 | True | 0.00020179152488708496 | None |
| author:no_input:float64 | 通过 | True | 7.105427357601002e-15 | None |
| author:no_input:float32 | 通过 | True | 1.0728836059570312e-06 | None |
float32与float64交叉比较仅记录精度影响,允许保留分歧,不能用于掩盖各自与独立oracle的失败。
- precision_cross_record:pair:事件一致=True,最大误差=3.733467101341148e-05 mV,首次事件分歧step=None。
- precision_cross_record:trio:事件一致=True,最大误差=3.733467101341148e-05 mV,首次事件分歧step=None。
- precision_cross_record:five:事件一致=True,最大误差=0.00019546693161487383 mV,首次事件分歧step=None。
- precision_cross_record:feedforward:事件一致=True,最大误差=0.0005722045887850413 mV,首次事件分歧step=None。
- precision_cross_record:no_input:事件一致=True,最大误差=0.0 mV,首次事件分歧step=None。
所有失败轨迹和错误文件原样保留;本简报没有选择获胜变体。
小回路缺少外部整脑输入与graded APL,不能证明整脑因果必要性、生物真实性或信息保持。初始诊断seed也不是作者的感官Poisson接口。
环境为Linux宿主,作者记录为Windows;Python补丁版本与环境差异见environment记录,不能称为二进制相同或原论文整脑复现。
后续整脑嗅觉比较仍须核查固定输入、实际送达事件、持续活动和信息保持;可用学习仍需至少5个训练seed、独立评估、MBON/downstream的A对中性B特异性及acquisition/reversal/retention/delayed-reward对照。
封存排除 .venv 与 __pycache__,保留环境安装报告;manifest列出payload哈希,checksums另含manifest,不存在自哈希循环。
+54
View File
@@ -0,0 +1,54 @@
# 独立模型分支首轮结果:实现正确,不等于学习修复
用户明确授权独立新模型分支测试动力学假设。分支为 `codex/lif-author-semantics-lab`,
模型目录 `models/male-cns-lif/author-semantics-lab-v1/`,实验目录 `experiments/phase4ad-author-semantics/`。
Phase 1–4AC 保持原样;没有替换已有候选、训练、调学习率、扩大mask或连接游戏。
## 已验证的结果
正式状态 `COMPLETE-ORACLE-VALIDATED-LAB-ONLY`,58/58审计项通过。
实际运行固定作者代码的 `create_model`,并与独立解析积分实现对照,而非仅比较两份自写程序。
8项算子/边界fixture各测试float64与float32;5个固定真实motif各测试两种精度,分别重复。
各精度内的spike事件、计数和不应期逐步一致,重复运行逐数组精确一致。
五个motif的float32与float64事件也一致,但不能外推到全脑高入度累加。
float64最大V/g差约3.84e-13 mV;float32独立实现相对Brian2最大差约2.12e-4 mV。
| 真实回路 | 旧冻结模型1秒总spike | 完整作者语义总spike | 作者语义后500ms spike |
|---|---:|---:|---:|
| 两个ALLN | 473 | 213 | 106 |
| 三个ALLN | 1,064 | 448 | 224 |
| 三ALLN + VA6 PN + KC | 1,483 | 610 | 306 |
| 前向真实边对照 | 3 | 3 | 0 |
| 无刺激 | 0 | 0 | 0 |
**持续循环没有因恢复作者语义而消失。** 放电减少不是学习成功,也没有据此挑选获胜参数。
单独限制不应期内g更新甚至提高了这些回路的放电;不能把单一算子改动当作通用修复。
小回路省略了大部分全脑输入和graded APL,不能证明全脑问题完全由这些连接引起。
此前全脑背景复核显示,三个ALLN的晚期正到达权重约91%以上来自所选五节点之外;这也不是因果责任百分比。
## 作者参考及边界
- 官方代码:`philshiu/Drosophila_brain_model`,commit `91bdd1e7dcf193f3e7ca5a8933497fcef63b7960`,MIT。
- [原作者论文](https://www.nature.com/articles/s41586-024-07763-9);[固定代码版本](https://github.com/philshiu/Drosophila_brain_model/tree/91bdd1e7dcf193f3e7ca5a8933497fcef63b7960)。
- Brian2 2.5.1,独立Linux环境;作者记录为Windows/Python3.10.11,此处Linux/Python3.10.12,不能称为二进制相同。
- 原始g单位为volt,是加性输入状态,不是电导;reset中的局部`w=0`不会清零真实Synapses权重。
- 原`poi`接口另做了零时长编译审计:向v加入68.75mV、150Hz、N=1,并将目标不应期置零。它不是本轮共同初始seed,也不是已验证的新嗅觉接口。
- 安装只发生在新实验`.venv`,保存下载URL与归档SHA-256;MarkupSafe1.1.1使用源归档,其他核心包使用wheel。未改旧科学环境或ComfyUI。
## 下一关
1. 独立GPU实现须补足高入度、正负抵消、逐边加法顺序、非零初始g、阈值临界值与延迟队列边界测试;禁止用`g+sum(w)`擅自代替作者逐边写入。
2. 在短时全图上对照事件及状态,再开展固定DoOR嗅觉CAL。保持既有输入请求,不顺手切换为作者的rfc=0输入接口;分别统计请求、因不应期拒绝与实际放电。
3. CAL通过后才能使用独立seed及新odor验证。不能靠低活跃度或held-out调参授予成功。
4. 真正conditioning须重新执行D(t)=0、frozen与随机奖励路径,并真正推进retention等待时间;旧脚本中复用基线/新建状态的检查不能替代这些端到端验证。
5. 全部学习结论仍以MBON/downstream的刺激特异性、acquisition/reversal/retention/delayed reward为准,至少5个training seeds与独立evaluation seeds。
## 完整性和保存
原快照230,239项及4AA、4AB、4AC、背景复核产物前后SHA-256无变化。
旧deterministic-v2五个全脑冻结trial重新执行,事件、计数、最终V/g逐数组相同。
4090回归峰值已分配显存285,994,496字节;这不是新动力学全脑性能benchmark。
新模型11个payload、新实验565个payload已独立封存,环境目录不纳入payload。
Git同步代码、小报告和校验清单;大数据及完整状态轨迹仍在服务器,不能称为完整异机备份。
详见[完整结果](phase4ad-author-semantics.md)、[封存核验](../../registry/phase4ad-author-semantics/seal-verification.json)。
+37
View File
@@ -0,0 +1,37 @@
# Phase 4AE GPU作者语义数值门禁
状态:`PASS-ISOLATED-GPU-NUMERICAL-GATE`。
仅验证固定小网络,尚未证明全脑等价、生物学正确或学习可用。未训练、未修改冻结输入或旧模型。
| case | precision | events | max V/g error V | exact whole history | pass |
|---|---|---:|---:|---|---|
| fanin_bursts | float64 | 1539 | 0.0 | True | True |
| fanin_bursts | float32 | 1539 | 0.0 | True | True |
| highest_indegree | float64 | 101 | 0.0 | True | True |
| highest_indegree | float32 | 101 | 0.0 | True | True |
| mixed_high_indegree | float64 | 106 | 0.0 | True | True |
| mixed_high_indegree | float32 | 106 | 0.0 | True | True |
| motif_feedforward | float64 | 3 | 0.0 | True | True |
| motif_feedforward | float32 | 3 | 0.0 | True | True |
| motif_five | float64 | 60 | 0.0 | True | True |
| motif_five | float32 | 60 | 0.0 | True | True |
| motif_no_input | float64 | 0 | 0.0 | True | True |
| motif_no_input | float32 | 0 | 0.0 | True | True |
| motif_pair | float64 | 22 | 0.0 | True | True |
| motif_pair | float32 | 22 | 0.0 | True | True |
| motif_trio | float64 | 45 | 0.0 | True | True |
| motif_trio | float32 | 45 | 0.0 | True | True |
| ordered_cancellation | float64 | 32 | 0.0 | True | True |
| ordered_cancellation | float32 | 32 | 0.0 | True | True |
| release_selfloop | float64 | 8 | 0.0 | True | True |
| release_selfloop | float32 | 8 | 0.0 | True | True |
| signed_random | float64 | 400 | 0.0 | True | True |
| signed_random | float32 | 400 | 0.0 | True | True |
| threshold_rounding | float64 | 4 | 0.0 | True | True |
| threshold_rounding | float32 | 3 | 0.0 | True | True |
每项GPU执行3次,检查原始事件、输入请求实际送达、逐目标到达顺序及guard、计数、不应期和完整状态。
大整数、随机图、重复/零边属于纯数值夹具,不是新增MaleCNS连接或生理假设。真实子图使用全部既有诱导边、原contact count与冻结transmitter sign。
原始冻结完整性与旧五组全脑deterministic-v2回归再次核验;该旧回归PASS不等于新动力学全脑PASS。
没有根据活动强度选择参数;尚须短时全图对照及嗅觉信息保持测试。
+51
View File
@@ -0,0 +1,51 @@
# Phase 4AE:独立GPU后端通过固定数值压力集
状态:`PASS-ISOLATED-GPU-NUMERICAL-GATE`。独立分支仍为 `codex/lif-author-semantics-lab`。
这不是 learned candidate,也不是全脑或长期动力学等价声明。
## 具体推进
- 新增双精度CUDA后端,按已验证作者表达式逐次舍入,禁用FMA和fast-math。
- 保留精确18-step delay与22-step refractory;只展开当时放电源的真实出边,不逐步扫描全部edge。
- 突触从目标当前g开始逐条累加,不能先求边权和再加;刚放电的目标拒绝同tick输入。
- 将实际请求、允许注入、不应期拒绝分开统计。没有采用作者poi接口的rfc=0策略。
- Brian2实际队列由只读代理观测;每个oracle再做无代理复跑,证明观测工具没有改变输出。
固定12组case × float64/float32 × 3次GPU执行,**72/72通过**。
全部状态history逐bit一致,V/g最大绝对差为0;事件、计数、不应期、请求送达、逐目标到达顺序和接受标记均一致。
三次GPU重复逐数组相同,24组Brian oracle的观测/无观测对照均通过。
这些是整个短轨迹的对照,不是仅比较总spike数或末态。
## 覆盖范围和未覆盖项
5个合成夹具覆盖有序正负抵消、256源fan-in、同tick输入与不应期释放、自环/队列回绕、阈值可表示数邻域,以及固定seed随机有符号网络。
极大整数、重复/零边只用于明确标记的数值夹具,不是真实MaleCNS新连接或生理参数。
2个真实128-neuron诱导子图按入度和原contact count选取,保持所有真实内部边与sign。
两者中心都是全图最高入度节点neuron_idx=5/body_id=10009/type=CT1,入度11,526;伙伴组成不同。
这是数值压力测试,不是两个独立中心的证据,也不是视觉编码实验。
另有原4AD五个固定真实motif的100ms前缀。还没有覆盖所有全图累加场景和长时间反馈。
## 精度差异不能隐藏
作者float64与作者float32在阈值临界夹具产生4次和3次事件,首次分歧在tick0。
两套GPU分别精确复制了各自参考,但**float32不能因此称为float64的等价加速**。
本轮没有放宽事件门槛,没有根据活动强度选模型。下一次全图首先使用作者默认float64,以减少精度混淆。
[完整交叉精度记录](../../registry/phase4ae-author-runtime/cross-precision-description.json)。
## 下一步与学习门槛
下一关:166,700节点/25,582,938边完整图的短时float64逐步对照:无输入10ms、固定单seed50ms、固定五seed50ms。
采用连续运行和流式状态记录,不保存dense spike矩阵;比较实际队列摘要及所有细胞的每tick状态。
通过后才进行固定DoOR嗅觉CAL,并独立审计原graded APL与新语义的组合。
只有信息保持、held-out区分和真实conditioning功能/对照通过,才能讨论学习候选;不能从本轮数值PASS跳到学习PASS。
## 完整性与运行信息
原230,239项及4AA–4AD、背景复核前后hash检查通过,旧五个deterministic-v2全脑参考再次精确一致。
新模型11个payload、新实验916个payload独立封存。ComfyUI未修改,科学环境未升级。
72次GPU诊断总wall约15.93s;诊断峰值allocated VRAM约5.45MB。
这些数值来自小图并包含诊断同步,**不是全脑性能或实时性承诺**;旧全脑回归峰值约286MB也不是新动力学性能。
大数据/完整状态只留服务器;Git同步源码、小报告、出处与checksum,不等于完整异机备份。
详见[完整实验报告](phase4ae-author-runtime.md)、[预声明](../../models/male-cns-lif/author-runtime-lab-v1/PROTOCOL.md)、[封存校验](../../registry/phase4ae-author-runtime/seal-verification.json)。
+53
View File
@@ -0,0 +1,53 @@
# 下一关:author LIF + frozen legacy graded APL 的显式兼容审计
本文件为只读设计审计,未执行新APL试验、CAL或训练,不属于4AF数值PASS的覆盖范围。
## 已核源码与历史参数
旧实现:`models/male-cns-lif/phase4p_revalidate.py`,SHA256
`c7e693a2da70acdce4f53af5c2853e52e8333acc93f88a46a5e8083eac639346`。
固定配置:`models/male-cns-lif/phase4l.yaml`,SHA256
`9b8bcb7e031bf9063033a1854a439a7cd0bf6730301c2d2d02ca99a76f098d6e`。
根代理只读检查服务器历史锁文件:
`experiments/phase4j-mb-physiology-repair/calibration/locked-parameters.json`,574B,SHA256
`1894cc4b4082ba9b2d069edf87c5eccb75292aa11947ad9c48acf661037ff3e7`。
文件明确calibration_only=true、formal_or_heldout_used_for_selection=false、parameters_locked=true。
旧72格CAL选择gain=.01、normalization=1、tau=20ms;3个配置有效,选中mean_fraction=.0400467519685。
本次只核锁文件及来源,没有重新运行其历史CAL,不声称这些参数在新动力学中仍已生理验证。
## 旧overlay实际合同
APL由实际KC/ALPN spike事件驱动,不读取注入请求,不以APL点神经元自身spike驱动。
输入矩阵是KC∪ALPN→APL的正raw count;除以全部有效输入raw总和/具有任意APL输入连接的唯一source数。
输出矩阵是APL→KC raw count,除以非零矩阵元素均值。
两矩阵、APL状态及旧torch.mv/matmul均为float32。decay=f32(exp(-.1/20));每tick乘decay再加当前实际spikes的输入;输出乘.01,旧单位是mV/state/step。
没有额外delay、dt/tau驱动缩放或state截顶。
旧顺序是LIF→实际放电/接受forcing→快边排队→KC trace→APL→无条件减KC的g。
所有5,845条APL源快出边都被overlay清零;graded仅回填KC。已有4Z审计中1,212条非KC出边/13,712contacts/999targets没有graded回填。
兼容审计不得顺手缩窄该mask或恢复非KC边,解剖base文件永远只读;该已知范围限制必须保留在解释中。
## 与新author语义的交界不能静默处理
最小移植假设是:完成author groups/thresholds/synapses/resets之后,在end无条件执行原APL写入,再采样状态。
这不是作者原始APL模型,也不意味着新组合已被4AF验证。
1. 刚spike的KC先reset g=0,随后APL可以写入负g。
2. refractory KC仍接收APL,而author g在refractory期间冻结,因此负g可能累积到释放时。旧后端此时g仍衰减,行为不等价。
3. 改成guarded on_pre、检查not_refractory或挪到reset前,都属于另一个假设,不可称旧overlay原样移植。
4. float64主状态不授权APL自动变float64。须保留旧float32矩阵/状态/算术并明确最后mV→SI转换;归约次序或精度变化另立数值合同,不能假定torch与NumPy逐bit相同。
5. Brian赋值API是否真正实现上述无条件写入,必须以边界fixture实测;不能从API名称推断。
## CAL前固定fixture与门禁
- 零输入和独立trial reset,无跨trial残留。
- 各一个PN/KC脉冲与双APL汇合,核对当前tick驱动、下一tick膜效应和20ms尾迹。
- 自然spike/接受请求/拒绝请求/两者重合:每个实际事件只计一次。
- KC reset与refractory age0/1/21/22:保存overlay前后g/ref与实际写入行为。
- 快突触到达与APL同tick:快边guard原样、APL顺序独立。
- KC/非KC范围、双APL高fan-in、非整数规范化和SI转换,防止1000倍单位错误。
真实子图保留全图归一化常数,不按截取子图重算。保存APL/KC/ALPN有序身份、全部fast edge mask、原矩阵与规范化float32字节hash、归一化常数、参数/dtype/调度及基础/overlay权重hash。
逐tick比较实际事件、请求接受拒绝、APL drive/state/inhibition、overlay前后g/ref。新组合需要独立oracle和重复运行检查;不是要求新整网轨迹与旧模型相同。
先语义fixture,再固定同输入CAL;不碰heldout、不调gain、不以安静或稀疏作为成功标准。只有信息保持与功能性学习门禁通过才能推进学习候选。
@@ -0,0 +1,21 @@
# Phase 4AF:短时完整图数值对照
状态:`PASS-SHORT-FULLGRAPH-NUMERICAL-GATE`。
完整166,700节点/25,582,938边,原synaptic-contact总数124,177,617。
作者默认float64;新分支只读复用4AE CUDA算术与未修改作者Brian2 create_model。
无APL叠加、无Poisson forcing、无训练。只有tick0固定请求,所有原始边/符号/W_syn保留。
| trial | biological ms | events | active neurons | per-tick exact gate |
|---|---:|---:|---:|---|
| no_input | 10 | 0 | 0 | True |
| single | 50 | 24398 | 9225 | True |
| five | 50 | 24983 | 9170 | True |
每tick比较所有细胞原始V/g bit、ref、spike events、实际输入以及原队列edge/guard顺序SHA256。
完整CPU状态保留,GPU逐tick状态hash由独立文件审计再次重算核对;未保存dense spike matrix。
未执行:[];执行异常:[]。
GPU wall/VRAM含逐tick同步、CPU拷贝和hash,仅是诊断成本,不是实时性能benchmark。
原冻结校验与旧五组deterministic-v2参考回归另列;旧回归PASS不代表新动力学学习PASS。
三个短轨迹一致也不证明长期全脑行为、生物学正确、嗅觉区分或学习成功。
下一步:Explicit fixed APL/author semantics integration audit, then fixed DoOR CAL without learning
+57
View File
@@ -0,0 +1,57 @@
# Phase 4AF:短时全脑作者语义数值门禁通过
正式状态:`PASS-SHORT-FULLGRAPH-NUMERICAL-GATE`。
这是独立 `codex/lif-author-semantics-lab` 分支的数值验证,不是学习候选。
## 实际结果
完整166,700节点、25,582,938条原始有向边、124,177,617个synaptic contacts。
217个孤立节点与101条self-loop保留;sign未变,包括178个NULL与2,999个unclear的sign=0。
W_syn=.275mV/contact,作者默认float64,所有动力学常量保持本分支预注册值。
| 固定试验 | 生物时间 | 放电事件 | 活跃神经元 | 实际边到达 | 接受的到达 | 逐tick精确对照 |
|---|---:|---:|---:|---:|---:|---|
| 无输入 | 10ms | 0 | 0 | 0 | 0 | PASS |
| tick0请求1381 | 50ms | 24,398 | 9,225 | 9,501,728 | 8,173,086 | PASS |
| tick0请求固定五节点 | 50ms | 24,983 | 9,170 | 9,776,853 | 8,442,581 | PASS |
五节点是1197、1381、1511、82312、133666。全试验只有tick0请求,不是持续Poisson驱动。
所有请求均实际触发放电。CPU与GPU完整事件序列、每细胞计数、每tick V/g原始bit、不应期、原始queue edge/guard顺序均一致;状态最大差0,无NaN/Inf。
1,100个tick ×166,700个细胞逐一比较,不是仅检查末态或总spike数。
独立文件审计重新从CPU完整memmap计算hash,与GPU每tick原始状态摘要核对。
真实输入graph保留canonical CSR slot作为edge_id。作者create_model实际加载的全部i/j与全部SI权重逐块验证;GPU复用实测作者权重及实际生成的系数。
GPU仅fan-out实际放电源的出边,稳定按target分组并保留目标内原顺序,从已有g逐条累加,不另行求和。
## 解释边界
- 只有三个短时轨迹,不能外推长期全脑等价或生理正确。
- 本轮明确未启用APL overlay、未训练、未触碰heldout,不能当作正式嗅觉CAL。
- 两个刺激条件的输入数量不同且不是odor对照,不能据活动差异声称separability。
- fullgraph streaming queue proxy保留原对象/顺序,并核对完整delay与计数;没有另跑全图无代理重复。4AE的小图wrapped/unwrapped控制已通过,但不是全图复跑证据。
- float32不被宣称为float64等价加速;4AE阈值临界夹具已有跨精度事件差异。
## 诊断成本,不是性能候选
GPU含逐tickCPU拷贝、hash和同步的simulation wall:0.566s/3.383s/3.414s。
最大allocated VRAM320,670,208B,约305.8MiB。首次构建约58.79s,单列记录。
此实现为严格诊断,不是实时运行benchmark;不能把上述时间换成正式runtime实时性结论。
完整状态与图留服务器,新增payload约5.11GB;Git仅同步源码、小证据和checksum,不等于异机全量备份。
## 完整性和异常
原230,239项冻结字节、4AA–4AE及背景复核的前后hash全部PASS;旧五组deterministic-v2 frozen参考重新运行,事件/计数/末V/g全部精确一致。
新model11项、experiment129项payload已封存,publication再核manifest通过。
实验manifest SHA256:`0646b5fc232ee44912f1c3a60d600355f5a6d97dff7cf59fccea612d822fb899`。
部署时新experiment父目录不可写,首次prepare尚未生成protocol即中止;仅为本次新leaf目录配置所有权后重试,未改旧目录权限或数据。
Windows本地测试遇UTF-8配置默认GBK读取问题,已在预注册前修复。4项协议单测通过,纯queue摘要另有14项本地检查通过。
旧参考代码出现PyTorch对只读NumPy tensor构造的既有warning;未修改旧代码。GPU复制运行、冻结checksum和参考结果均通过。
科学试验无失败,无参数/输入/容差重选。
发布时CSV的标准CRLF被Git默认whitespace检查提示;保留封存原始字节,使用允许CR-at-EOL的检查,其余空白检查仍启用,未重写证据文件。
## 下一关
先明确并验证author LIF与frozen legacy graded APL的组合调度、refractory写入和float32→SI单位合同,再进行固定DoOR嗅觉CAL。
之后才允许独立seed、新odor以及credit/functional learning gate。仍没有learning candidate,未进入游戏。
详见[完整报告](phase4af-author-fullgraph.md)、[下一关只读设计审计](phase4af-apl-next-gate.md)、[封存校验](../../registry/phase4af-author-fullgraph/seal-verification.json)。
+14
View File
@@ -0,0 +1,14 @@
# Phase 4AG: author LIF + unchanged legacy graded APL
Status: `FAIL-FIXED-CAL-REPRESENTATION`.
Numerical closed-loop gate: True; original complete fixed six-CAL gate: False.
The independent Brian LIF and candidate use independent state but share the APL arithmetic component. Original frozen APL AST replay and a float64 error audit are separately recorded.
Author LIF uses float64; APL retains float32, tau20ms/gain0.01/normalization1, full original matrices and order. No learning/parameter search.
The explicitly hypothesized unconditional end-APL write includes refractory KC. Original fast APL mask leaves1,212 non-KC edges unreplaced; this scope limitation was not silently fixed.
Old checksums and five frozen reference trials: True.
Successfully compared cases: [{'case': 'apl_only', 'pass_all': True}, {'case': 'arrival_collision', 'pass_all': True}, {'case': 'cal-matched_energy-00-s51101', 'pass_all': True}, {'case': 'cal-physiological-00-s51101', 'pass_all': True}, {'case': 'high_fanin', 'pass_all': True}, {'case': 'kc_ref_boundary', 'pass_all': True}, {'case': 'natural_request', 'pass_all': True}, {'case': 'pn_pulse', 'pass_all': True}, {'case': 'two_sources', 'pass_all': True}, {'case': 'zero', 'pass_all': True}].
Detailed CAL, exact comparisons, component errors, event/request traces and execution exceptions are linked from audit/final-status.json.
Wall/VRAM here include per-tick CPU synchronization, IPC and hashes. They are diagnostic costs, not runtime-performance benchmarks.
No heldout dynamic outputs, formal A/B, learning, game, reward, decoder or new candidate.
Next gate: Audit first failure in this explicitly declared hypothesis; no gain search, no heldout tuning, no conditioning
+14
View File
@@ -0,0 +1,14 @@
# Phase 4AG: author LIF + unchanged legacy graded APL
Status: `INCOMPLETE-NUMERICAL-EXECUTION`.
Numerical closed-loop gate: False; original complete fixed six-CAL gate: False.
The independent Brian LIF and candidate use independent state but share the APL arithmetic component. Original frozen APL AST replay and a float64 error audit are separately recorded.
Author LIF uses float64; APL retains float32, tau20ms/gain0.01/normalization1, full original matrices and order. No learning/parameter search.
The explicitly hypothesized unconditional end-APL write includes refractory KC. Original fast APL mask leaves1,212 non-KC edges unreplaced; this scope limitation was not silently fixed.
Old checksums and five frozen reference trials: True.
Successfully compared cases: [].
Detailed CAL, exact comparisons, component errors, event/request traces and execution exceptions are linked from audit/final-status.json.
Wall/VRAM here include per-tick CPU synchronization, IPC and hashes. They are diagnostic costs, not runtime-performance benchmarks.
No heldout dynamic outputs, formal A/B, learning, game, reward, decoder or new candidate.
Next gate: Audit first failure in this explicitly declared hypothesis; no gain search, no heldout tuning, no conditioning
@@ -0,0 +1,91 @@
# Phase 4AG:设计、证据范围与限制
本文是独立于已登记模型和实验文件的解释性文档,不是预注册协议的修订,也不是最终实验报告。状态快照日期:2026-09-30。
在本说明对应的检查节点,r2 的 8 个固定小型测试场景已完成每场景 3 次 GPU 运行及 1 次 Brian 对照,数值门禁通过;两个预先指定的全图 100 ms Brian 对照也已通过。后续 60 次 CAL 基础运行和 12 次重复检查仍在进行中。本文不宣布 CAL 通过或失败,更不宣布学习成功。正式状态应以各阶段原始审计记录及最终封存报告为准。
## 本阶段到底测试什么
Phase 4AG 测试一个明确的新组合:在 MaleCNS 原有全图上,将已经核对过作者语义的 float64 LIF 动力学,与项目旧版 float32 graded APL 模块连接起来,先检查实现是否符合声明,再检查固定旧 CAL 输入下的嗅觉表征是否满足完整原门槛。
全图仍为 166,700 个神经元、25,582,938 条规范化有向边。原始连接计数、递质符号、W_syn、旧 APL 参数以及 eligibility-v2 的 14,232 边掩码不修改。本阶段不训练,不搜索增益、阈值、刺激强度或时间窗,不新增连接,不做行为、奖励或游戏演示。
作者语义来源是已归档的 Shiu 等人代码,而不是重新选取的最新版本:GitHub commit `91bdd1e7dcf193f3e7ca5a8933497fcef63b7960`,归档 `model.py` 的 SHA-256 为 `fc45837d7122c6ce2a7f3f2f23c515992e4b232aadb919efabb72337fac88e4e`。[固定提交的作者代码](https://github.com/philshiu/Drosophila_brain_model/blob/91bdd1e7dcf193f3e7ca5a8933497fcef63b7960/model.py) 对应 Shiu 等人的论文 [A Drosophila computational brain model reveals sensorimotor processing](https://www.nature.com/articles/s41586-024-07763-9)(Nature,2024)。本项目使用不同的连接组及额外的旧 APL 工程模块,因此不能称为该论文或作者完整模型的严格复现。
## 混合精度与每一步的明确顺序
LIF 的 `v`、`g` 和解剖边权使用 float64、SI 伏特;这里的 `g` 是作者方程中以伏特表示的状态量,不应仅凭变量名解释成电导。LIF 核心复用已封存的 CUDA 运算,不修改数学语义。固定步长为 0.1 ms,解剖传递延迟为 18 步,不应期为 22 步。
APL 则保留旧环境中的 float32 矩阵、状态和运算序列。输入矩阵始终是 `2 × 166700`,输出矩阵始终是 `2 × 4064`;即使测试小型诱导子图,也不裁剪矩阵或重算归一化。每次独立运行从零 APL 状态开始。APL 输入是本步实际产生的二值放电,而不是外部请求:被不应期拒绝的请求不能被当作放电反馈。
每步先完成 LIF 核心、请求处理、真实延迟到达和复位的声明调度,再在 `end` 执行旧 APL。APL 衰减与增加保持分开的 eager 操作:
```text
s32.mul_(float(float32(exp(-0.1 / 20.0))))
drive32 = torch.mv(I32, actual_spikes32)
s32.add_(drive32)
h32 = torch.matmul(s32, O32) * float32(0.01)
delta64 = h32.to(float64) * float64(0.001)
g64[KC] = g64[KC] - delta64
```
其中 `h32` 沿用旧模块的 mV 语义。必须先拓宽为 float64,再乘 0.001 转成伏特,最后单独减去;不能先在 float32 中乘 0.001,也不能将 `mul_`、`add_` 或最后的转换与减法融合成另一条运算路径。tau=20 ms、gain=0.01、normalization=1 均不调整,也不额外加入 APL 延迟、裁剪或 `dt/tau` 缩放。
APL 不改变原环境的默认 TF32/矩阵乘精度/CuBLAS 设置,而是记录实际设置、版本和设备,并核对组件输出。保留“数学上等价”的表达式并不足以保证逐位相同;PyTorch 官方说明明确指出,浮点运算顺序、后端和版本都可能影响结果。[PyTorch 数值精度说明](https://docs.pytorch.org/docs/2.14/notes/numerical_accuracy.html)、[可复现性说明](https://docs.pytorch.org/docs/2.14/notes/randomness.html) 在此用于解释工程风险,不作为改变冻结环境的理由;文档不能替代实验记录中的实际安装版本和设备信息。
## 不应期中的 APL 写入是被检验的假设
本组合在复位后的 `end` 阶段,无条件向所有对应 KC 的 `g` 写入 APL 抑制,包括刚放电或仍处于不应期的 KC。这里没有补加 `ref == 0` 条件。
这必须与作者核心的普通解剖输入区分:作者方程中带有 `unless refractory` 的状态在不应期冻结,普通突触更新受相应保护;本分支的 APL 是显式的末尾直接状态写入,不是把它伪装成普通受保护突触。[Brian 2.5.1 不应期文档](https://brian2.readthedocs.io/en/2.5.1/user/refractoriness.html) 解释了不应期和状态冻结的区别;具体执行依据仍是已归档作者代码及本项目保存的实际生成代码。
由这套代码顺序可以推得:APL 写入的负 `g` 可能在不应期内继续累积,而该期间作者核心不会按通常的 `g` 方程衰减它。这个组合效应是此次被检验的显式工程假设,不是已确认的生理机制,也不是作者原模型的主张。若改成不应期屏蔽、写入后再次清零或更换写入阶段,就已经是另一项假设,不能作为此次结果不好时的即时“修复”。
## 5,845 条 fast APL 掩码及 1,212 条未替换边
旧 APL 模块的兼容规则是:将全部 5,845 条原始 APL fast 出边的有效权重置零,然后仅向 KC 提供 graded 替代。置零只发生在新运行时的内存副本中;磁盘上的原始图、计数、符号和基础权重不改写,边身份也不删除。
其中 1,212 条出边的目标不是 KC,因此其 fast 作用被关闭后,没有获得本模块的 graded 替代。这是已知且保留的覆盖缺口。不能把该组合描述成“所有 APL 输出均被等价替换”,也不能为了得到更好的结果悄悄恢复这些边或新增非 KC 的 graded 通路。这两个数字描述的是本项目图中的有向边计数,不是新增的生物学结论。
## 三类数值证据分别能说明什么
| 检查 | 能支持的结论 | 不能支持的结论 |
| --- | --- | --- |
| Brian 闭环对照 | Brian 自己推进 LIF、产生实际放电,独立进程中的 APL 状态据此更新;与 GPU 比较逐步状态、事件、请求、队列顺序与接受掩码、APL drive/state/h | APL 算法本身完全独立实现,或所有输入下的普遍等价 |
| 原代码 AST 影子重放 | 从冻结旧初始化代码重建矩阵,并提取旧更新语句;用已记录的真实放电重放,检查组件字节是否保持一致 | 新的独立全脑闭环证明,或摆脱共同 Torch/CUDA 底层原语的验证 |
| float64 算术测量与误差界 | 在明确的非负矩阵、正常有限运算等前提下,量化 float32 组件相对独立 float64 测量的偏差,检查预先定义的误差界 | 用 float64 替换 APL、事后放宽容差,或用误差界替代逐位旧组件一致性 |
Brian 的 APL worker 不接收候选 GPU 的抑制轨迹,而只接收 Brian 自己产生的实际放电;它有独立的零初始状态,并通过握手核对矩阵哈希与运行环境。但候选与 worker 共享 APL 组件实现,所以准确名称是“共享 APL 组件的闭环 Brian 对照”,不能写成“全部组件独立的 CPU oracle”。
AST 影子又提供一层不同的代码来源检查,但仍使用相同的 Torch/CUDA 原语。float64 测量不反馈到任一脑模型,其误差界不根据观测误差拟合。各证据应并列阅读,不能互相替代。
8 个固定小型场景检验零输入、真实 PN/KC 输入、不应期边界、自然放电与请求重合、延迟到达、APL mask 和高 fan-in 等情形;每场景 3 次 GPU 运行检查精确重复。两个全图 probe 是预先指定的第一个旧 CAL 气味、首个原始 seed、两种编码模式,各 100 ms。通过这些检查只说明已测试场景符合本组合的声明,不证明所有气味、时间尺度或后续学习任务都有效。同步、IPC、逐步哈希和诊断保存的耗时也不是性能基准。
## CAL 必须通过完整原 4L 门槛
CAL 设计固定为原 6 个校准气味 × 5 个原始 seed(51101–51105)× 2 种模式(`physiological`、`matched_energy`),共 60 次基础运行,每次 100 ms;每个气味/模式的首个 seed 再运行一次,共 12 次重复。它们不是额外的训练 seed。
输入在任何轨迹运行前保存,保留旧 PN 编码、目标/随机数列顺序。matched-energy 的参考值仍取原冻结 12 气味 panel 的中位数,不能换成 6 CAL 的中位数,也不能换成后续其他 panel。读取这份静态参考数据不等于读取 heldout 动态结果。
每种模式都必须同时满足以下原始条件,两种模式都通过才满足表征门槛:
- KC 活跃比例的平均值在闭区间 3%–9%。
- 单次运行的最小活跃比例严格大于 0,最大值严格小于 50%。
- 同气味跨 seed 的平均活跃集 Jaccard,严格大于不同气味同 seed 的平均 Jaccard。
- 不同气味同 seed 的平均欧氏距离,严格大于同气味跨 seed 的平均欧氏距离。
- 至少 3 对气味通过成对分离检查:该对气味在相同 seed 下的 5 个距离均值,严格大于这两个气味各自全部 10 个跨 seed 距离合并后的 20 项均值。
距离来自原始 KC spike-count 向量,欧氏距离先转 float64,不另做向量归一化;Jaccard 使用是否放电的布尔活跃集。6 CAL 每种模式有 15 对气味、60 项 within 距离和 75 项 between 距离。成对比较的基线不是全部气味混在一起的平均 within 距离;只检查平均稀疏率与“至少 3 对”的旧简化 `r4` 不能代替完整原 4L 门槛。
本阶段另加输出完整性、有限值和 12 次精确重复要求;缺失文件、失败运行、NaN 或全静默都不能当成通过。原 4L 虽记录 finite,但没有将它写进原最终 gate,因此这里应明确称为新增的完整性前置检查,而非改写历史。
即使最终 CAL 通过,含义也仅限于这组固定校准输入下的表征检查。它不等于 heldout 泛化、刺激特异性信用分配、记忆、条件化或可用学习;本阶段没有训练或生成新的候选模型结论。后续学习验证仍需在授权范围内另行登记并通过专门门槛,不能由本阶段的数值一致性推导出来。
## 为什么保留 v1,并单独运行 r2
第一次登记的 v1 在启动 APL worker 时,对科学虚拟环境的 Python 路径调用了 `resolve()`,跟随符号链接到了系统解释器,丢失预期包环境。异常发生在首个 Brian tick 之前,错误记录的 `last_complete_tick` 为 -1;v1 已保留源代码、部分输出和故障记录,并以 `INCOMPLETE-NUMERICAL-EXECUTION` 封存。
这不是已观测到的动力学或科学假设失败,也不能反过来称作数值通过。r2 使用新模型目录 `author-apl-lab-v2` 和新实验目录 `phase4ag-author-apl-r2`,保留虚拟环境的调用入口路径,只修执行入口及相应记录/检查,不更改方程、运算精度、掩码、刺激、门槛、参数或测试选择。全部声明流程从新状态重跑,不覆盖或挑选性省略 v1 的记录。
本文所述已通过的 r2 数值门禁与仍在进行的 CAL 是两件事。是否完成、是否通过,以及允许得出的结论,最终都必须回到对应原始证据和封存状态,而不是依据本解释文档升级。
+85
View File
@@ -0,0 +1,85 @@
# Phase 4AG:独立动力学分支的正式结果
更新:2026-09-30。实验:`phase4ag-author-apl-r2`;模型:`author-apl-lab-v2`;Git 分支:`codex/lif-author-semantics-lab`。
## 结论
正式状态:**FAIL-FIXED-CAL-REPRESENTATION**。
本轮完成作者 float64 LIF 与冻结旧 float32 graded APL 的显式组合测试。数值一致性、数据完整性和精确重复检查通过;固定 CAL 的完整原门槛未通过。没有训练,没有新学习候选,不升级原 reference/runtime,也不修改旧模型。
两种输入模式唯一未达标条件都是 KC 平均活跃比例低于预先固定的 3%–9%。这不证明约 1.2% 的活跃比例在生物学上错误,也不能据此认定 APL 是原因。
## 固定 CAL:60 次基础运行及 12 次重复
使用原 6 个 CAL 气味、原 5 个 seed、两种输入模式,每次 100 ms;每个气味/模式首个 seed 再运行一次。未读取 held-out 动态结果,未做正式 A/B conditioning。
| 指标 | physiological | matched_energy |
| --- | ---: | ---: |
| KC 平均活跃比例 | 1.271325% | 1.233596% |
| 单次最少/最多活跃 KC(共 4,064) | 38 / 79 | 36 / 72 |
| 同气味跨 seed 平均 Jaccard | 0.509072 | 0.516431 |
| 不同气味同 seed 平均 Jaccard | 0.460955 | 0.481702 |
| 同气味平均欧氏距离 | 5.811443 | 5.671828 |
| 不同气味平均欧氏距离 | 6.205091 | 5.932021 |
| 成对距离判据通过数 | 12 / 15 | 13 / 15 |
| 完整原 CAL 门槛 | FAIL | FAIL |
其余原条件全部通过:单次最小活跃比例大于零、最大值小于 50%、同气味 Jaccard 大于不同气味、不同气味欧氏距离大于同气味、至少 3 对气味满足原成对距离判据。该判据使用每对气味自己的 20 项 within 距离与 5 项 same-seed between 距离,不是全气味混合基线。
60/60 基础运行完整、有限;12/12 重复的事件、状态、逐 tick 哈希、APL 轨迹、请求及队列均精确一致。未见 NaN/Inf。12/15 和 13/15 不是学习成功率、统计显著性或 held-out 泛化结论。
matched-energy 保持原冻结 12 气味静态 panel 中位数及原随机输入算法;它匹配期望输入量,不保证每次随机运行实际接受事件相等。其期望事件数 CV 约 6.48e-8,实际接受事件 CV 为 0.134355;不得称作实际输入事件数严格匹配实验。
## 数值证据与完整性
- 8 个固定真实诱导子图场景,各 3 次 GPU 和 1 次 Brian 闭环对照;16 个 GPU 重复比较通过。
- 两个预指定完整全图 100 ms probe,逐 tick 的 v/g/ref、放电事件、请求、延迟队列及 APL drive/state/h 精确一致。
- 10 组原 APL AST 组件重放/误差审计通过。两个 Python 环境分别通过 29 项协议/汇总/解释器入口单元测试。
- 全图保留 166,700 神经元、25,582,938 条边,原始 contact weight sum 为 124,177,617;原始磁盘 CSR 不改。
- 原 230,239 项冻结清单及后续已封存目录全部校验通过;旧五组 deterministic-v2 参考的事件、计数、最终 v/g 再次精确通过。
- 新 r2 模型 17 项、新实验 1,718 项已封存并再次验证。实验封存前 payload 为 2,956,599,228 字节(约 2.75 GiB)。
Brian 独立推进 LIF,但 APL worker 与候选共享 APL 算术组件;AST 重放也使用相同底层 Torch/CUDA 原语。因此是“共享 APL 组件的闭环对照”,不是全部组件独立的 CPU oracle,也不是任意输入/长期全脑普遍等价证明。float64 误差测量不反馈到模型。
诊断包含逐步 CPU 同步、哈希、IPC 和保存,耗时不代表正式 runtime 性能;没有由本轮产生新的实时运行候选。
## 已声明的假设与保留的问题
APL 保留旧 float32 矩阵、tau=20 ms、gain=0.01、normalization=1;LIF 为作者 float64 语义。APL 在 reset 后的 end 阶段无条件写入 KC g,包括不应期,先拓宽 float64 再由 mV 转 SI。作者核心在不应期冻结 g,与末尾 APL 写入结合可能产生累积,但本轮尚未定位低 KC 覆盖率的原因。
旧 APL 规则在独立运行的内存权重副本中关闭 5,845 条 fast APL 出边,只向 KC 提供 graded 替代。其中 1,212 条非 KC 边(13,712 contacts)未获替代。该覆盖缺口原样披露,不静默恢复边或修改归一化。新分支不是作者原始完整模型的严格复现。
首次 v1 因虚拟环境 Python 符号链接被错误解析到系统解释器而在首个 Brian tick 前中止,正式保存为 `INCOMPLETE-NUMERICAL-EXECUTION`。r2 只修执行入口及检查,另建目录从头运行;全部 68 组输入请求与 v1 一致。失败代码、日志和结果保留,没有覆盖或删除。
## 下一步:先解释失败,不追逐通过率
只用现有 60 次 CAL 的记录,先登记一份只读影子记账诊断:
1. 分解请求数、实际接受量和 PN 实际放电。
2. 按真实边及 18-step delay 重建 PN→KC 兴奋性投递、拒绝、不应期和 reset。
3. 区分活跃/静默 KC,审计 APL 写入时相、累积量与 g 的关系。
4. 先验证重建与已保存事件/最终状态一致,再讨论机制;不足以重建的证据明确标记缺失。
这不是一次新脑模拟或参数搜索。不改 gain、刺激、阈值、APL 参数、mask 或通过条件;不以本次 CAL 选择后续最佳参数。任何新的动力学假设须另立协议和目录。表征、独立 seed/新气味、信用分配、隔离功能及全脑功能检查通过之后,才有条件进入真正学习验证。
## 封存与证据入口
- [正式 r2 报告](phase4ag-author-apl-r2.md)
- [原始最终状态](../../registry/phase4ag-author-apl-r2/evidence/audit/final-status.json)
- [CAL 原始汇总](../../registry/phase4ag-author-apl-r2/evidence/calibration/summary.json)
- [旧数据完整性](../../registry/phase4ag-author-apl-r2/evidence/regression/old-integrity-after.json)
- [旧五组参考回归](../../registry/phase4ag-author-apl-r2/evidence/regression/frozen-five.json)
- [新封存校验](../../registry/phase4ag-author-apl-r2/seal-verification.json)
- [含来源链接的设计/限制历史快照](phase4ag-design-and-limits.md)
- [保留的 v1 执行失败报告](phase4ag-author-apl.md)
r2 模型 manifest SHA-256:`208c00961b9d895d14ac050bc23fbc18db49d0df1fcf5c20d4c3eaa8e15ff7ff`。
r2 实验 manifest SHA-256:`21593297c40bee58516d4d7fd16e9d8d20ffdea5f8e0652fa5dd4e903b4d96ee`。
Git 发布代码、文档及小型证据;完整数组和事件文件仍在服务器实验目录。Git 同步不等于全量异机数据备份。
## 仓库发布检查
原仓库 681 项文件校验零差异,仓库审计单元测试通过,暂存内容的数据/密钥/大文件检查通过。标准空白检查发现两个已封存 `oracle_apl.py` 各有一个文件末尾空行;为保留登记字节未做格式改写。仅关闭末尾空行规则并允许标准 CSV CRLF 后,其余空白检查通过。这是格式例外,不是数值容差或科学门槛例外。
+75
View File
@@ -0,0 +1,75 @@
# Phase 4AH:KC 输入记账把问题缩小到了哪里
更新:2026-09-30。正式状态:**PASS-CONDITIONAL-KC-DRIVE-AUDIT**。
这里的 PASS 仅表示对既有轨迹的条件重建和输入账目通过验证。Phase 4AG 的 `FAIL-FIXED-CAL-REPRESENTATION` 不变,仍没有学习候选。本阶段不运行新脑实验、不训练、不调参数、不使用 held-out,也未使用 GPU。
## 关键结果
全部 8 个小型场景、60 次 CAL 基础记录和 12 次重复,共 80 份记录通过重建。KC 放电由重建代码独立计算,未用原 KC 放电强制复位;80 份事件、计数及最终 V/g/ref 精确一致,8 个小型场景的逐 tick pre/post-APL 状态也精确一致。12 份重复的诊断统计相同。
完整 CAL 没有逐 KC 状态历史,只有全脑每 tick 哈希。因此不能声称完整 CAL 的每 tick KC V/g 都与独立保存的原历史逐位验证。记录中的上游放电和 APL h 是重建的条件输入,不是重新模拟出来的独立证据。
下表每列汇总 30 次 CAL:6 气味 × 5 seed。KC 比例按“神经元×试验”计数,时间比例按“神经元×试验×tick”计数,不是跨试验去重后的神经元数。
| 指标 | physiological | matched_energy |
| --- | ---: | ---: |
| 外部请求 / 接受 | 3,203 / 2,195 | 2,936 / 2,038 |
| 实际全部 ALPN 放电 | 154,514 | 153,049 |
| 当次非设计目标 ALPN 放电 | 138,679(89.75%) | 137,431(89.80%) |
| 静默 KC 中收到 PN 兴奋输入的比例 | 93.3455% | 93.3481% |
| 静默 KC 中收到任意兴奋输入的比例 | 100% | 100% |
| PN 占已接受兴奋增量总量的比例 | 89.1612% | 89.4183% |
| PN→KC 到达边事件拒绝率 | 0.03649% | 0.03731% |
| 从未放电 KC 的不应期 tick 数 | 0 | 0 |
| APL 累计写入量 / 已接受兴奋增量 | 3.0516 | 3.0539 |
| KC 末尾状态 g 为负的时间比例 | 91.8452% | 91.8721% |
每个气味的设计目标为 33–55 个 ALPN;六气味设计目标并集为 76 个,实际放电 ALPN 并集为 556 个(两种模式均如此)。设计目标、实际请求、接受请求和实际放电是不同集合,均已分别保存。没有把实际输入事件数强行匹配,也没有把“未与请求同 tick 的放电”直接命名为噪声或独立自然活动。
## 哪些解释已被排除,哪些还没有
在这些已记录的 100 ms CAL 中,可排除字面意义的“KC 完全没收到兴奋输入”。也可排除“从未放电的 KC 因自身不应期拒收或不应期内 APL 累积,才不能首次放电”:它们没有进入过不应期。
不应期内 APL 写入仅占全体 APL 累计写入约 0.0193% / 0.0192%。这不支持把“屏蔽不应期 APL 写入”当成本轮覆盖率失败的直接主要解释;但没有做干预,不能排除已活跃细胞的时序或网络间接效应。
尚不能排除:兴奋输入过晚、不够同步、缺少气味特异结构、广泛反馈再招募,或它们与持续 APL 写入的相互作用。静默 KC 最接近阈值时的距离中位数约 6.697 / 6.703 mV;该值描述当前轨迹,不用于调整阈值。
APL 的约 3.05 倍是跨时间、神经元和试验累计状态增量的记账比值,不是瞬时 E/I 比、生物学抑制强度比例,也不是可据此倒算的新 gain。`g` 在该作者方程中以伏特表示,不是电导。源分账采用真实 availability/reset 条件;不能将其当作移除 APL 后的全脑反事实。
## 身份、浮点和证据范围
源类别从实际 schema 建立互斥分组:KC 4,064、APL 2、ALPN 686、MBON 97、解剖 DAN 340、仅 dopamine 标注的其他类别 52、other 160,143、unclassified 1,316。两枚 DPM 在 other 中明确标记,不因 dopamine 标注被归作 DAN;340 个 DAN 中有 2 个的当前 NT 字段不是 dopamine。没有依据名称前缀猜身份或删除未知项。
重建保留原始浮点位、18-step 延迟、22-step 不应期、严格阈值及逐边累加顺序。APL fast-edge 掩码原样保留在独立内存副本;磁盘原边权不改。按来源和符号分账不反馈到状态更新;舍入残差单独记录。
- 47 项合成测试在本地与服务器通过。
- 实际 g 阶段账目的最大闭合残差为 2.17e-19 V,在记录的运算误差界内。
- 来源状态分账最大残差为 6.11e-16 V;积分最大残差为 7.46e-14 V·ms。重建事件/最终状态自身仍要求逐位一致,没有放宽容差。
- 原 230,239 项及全部后续已封存目录校验通过。五组旧参考本阶段未重新运行;引用的是上一轮已封存且本次校验未变的 PASS 记录。
- CPU 条件记账合计约 133.34 s;这是审计耗时,不是脑模型实时性能。
- 新模型 11 项、新实验 415 项已封存;封存前实验 payload 81,395,186 字节。完整分账表留在服务器,Git 只发布代码、小型证据及 SHA-256。
## 下一步,不从比值反推参数
优先检验可证伪的机制问题:**非设计目标 ALPN 的广泛再招募是否先于 KC 响应,并通过 PN→APL / PN→KC 形成跨气味共享输入?**
先继续使用已有 60 次 CAL,做 ALPN 的局部条件重建、真实先后时序和设计/非设计来源的 PN→APL 分账。若时序或贡献不支持该假设,明确否定,不挑选支持案例。
旧 APL 的单位意图已核实:[原 4J 配置](../../models/male-cns-lif/phase4j.yaml) 明写 `gain_grid_mv_per_state_step`,[原 4J 实现](../../models/male-cns-lif/phase4j.py) 有意每 tick 把滤波后的抑制写入 g,4P 延续这一行为。所以不能称它为“遗漏 dt 的实现错误”,也不能偷偷把 .01 换解释成 tonic mV。后续可研究不同时间算子的结构假设,但需新单位契约和不依赖 CAL 的解析匹配对照,不能只是把累计抑制改小。[研究边界与来源](phase4ah-next-hypotheses.md)
这仍不是学习训练或新的全脑动力学实验。任何因果干预或新的 APL 动力学语义必须另立独立分支协议,保留原结果,提前固定对照和判据,不做 gain 搜索,不改旧模型、输入、mask、eligibility 或阈值。
## 证据入口
- [正式审计报告](phase4ah-kc-drive-audit.md)
- [原始最终状态](../../registry/phase4ah-kc-drive-audit/evidence/audit/final-status.json)
- [全部基础 CAL 输入账目](../../registry/phase4ah-kc-drive-audit/evidence/audit/calibration-drive-summary.csv)
- [可重复计算的解释性统计及输入 SHA](../../registry/phase4ah-kc-drive-audit/interpretation-metrics.json)
- [解释性统计生成代码](../../tools/report_phase4ah.py)
- [冻结文件校验](../../registry/phase4ah-kc-drive-audit/evidence/regression/old-integrity-after.json)
- [新封存校验](../../registry/phase4ah-kc-drive-audit/seal-verification.json)
模型 manifest SHA-256:`fa89cb0a6e2dc77462057b672ffbcfabbe74b893d8f70e4b41d8b5202de15530`。
实验 manifest SHA-256:`fb30ca09068d5d8dc1dc9972e00f674c5dc3aa49c7117d630607b5d9067927db`。
+16
View File
@@ -0,0 +1,16 @@
# Phase 4AH — conditional KC drive audit
Status: `PASS-CONDITIONAL-KC-DRIVE-AUDIT`.
80 existing records reconstructed; 8 fixture pre/post histories and 72 CAL event/final states exact.
12 repeated CAL records produced identical accounting. No new brain simulation, GPU use, tuning or learning.
Full prior frozen integrity passed. Five reference simulations were not rerun; the sealed prior PASS is referenced by SHA.
Previous CAL failure remains unchanged. Conditional replay is not an APL-removal counterfactual.
|Mode|Mean active KC fraction|Requests|Accepted requests|ALPN accepted excitatory increment sum (V)|APL write sum (V)|
|---|---:|---:|---:|---:|---:|
|physiological|0.01271325|3203|2195|46379.7565|158735.25|
|matched_energy|0.01233596|2936|2038|45928.6416|156859.684|
Increment sums span 30 trials × 4064 KC × time; not instantaneous conductance or causal percentages.
See audit/final-status.json, audit/calibration-drive-summary.csv and trials/*/per-kc.parquet for detailed evidence.
+45
View File
@@ -0,0 +1,45 @@
# Phase 4AH 后的研究边界:先定位,再做独立干预
日期:2026-09-30。本页是研究备忘,不是已执行或已通过的新实验协议。Phase 4AH 的条件审计 PASS 和 Phase 4AG 的固定 CAL FAIL 均不改变。
## 立即优先:既有轨迹中的 ALPN 再招募
可证伪的问题是:非设计 ALPN 再招募的时序是否先于 KC 响应;这些源在当前 PN→APL / PN→KC 输入中是否占主要部分。先对全部 60 次原 CAL 做来源和时序分账,不能仅拿全程累计比例作为答案。仍使用既有输入/放电,不生成新全脑轨迹;零贡献、反向时序或跨气味不同的结果也完整报告。
## 值得研究但尚未执行:APL 时间算子
旧模型的设计不是缺少一个 dt 因子。[phase4j.yaml](../../models/male-cns-lif/phase4j.yaml) 使用 `gain_grid_mv_per_state_step`;[phase4j.py](../../models/male-cns-lif/phase4j.py) 每步将 20 ms 滤波状态产生的抑制加到 g;[phase4p_revalidate.py](../../models/male-cns-lif/deterministic-runtime-v2/phase4p_revalidate.py) 保持该语义。原 4J 文件 SHA-256 分别为 `b35e4332a91b8489f69348cedf5ac675e9c3902c7e8c7beec5d053773c6529a3` 和 `abb4574da85f00bd9ef61024c65993ef81d42651ff8d8d63c15dd69c6222471e`,与 frozen 子目录副本相同。
一个未来的独立结构假设可以比较“滤波后的逐步 g 增量”与“独立连续驱动状态”的时间响应,而不是把 gain 调小。两者变量的单位及调度不同,不能把旧 `.01 mV/state/step` 直接当作 `.01 mV/state`,再宣称只改变了算法实现。
根据已冻结的离散更新式,在无放电、无不应期、恒定每步抑制增量 H 的线性诊断条件下,由代码推导(不是文献实测):
```text
g_next = gd*g - H
V_next = c0 + cg*g + cv*V
g_steady = -H/(1-gd)
V_base = c0/(1-cv)
V_steady - V_base = -cg*H/((1-cv)*(1-gd))
```
若以后选用 DC 匹配,应在新协议中预先固定这一匹配规则,使用冻结系数而不是重算常数,并先通过零输入、阶跃、脉冲、有限脉冲列、reset/ref22 边界的独立验证。不能看到 CAL 后再换成更有利的匹配标准。连续驱动可能使早期抑制更强,不能预设其改善编码。固定 trace 对照也不能代替闭环干预。
## 生物学依据能支持到哪里
Shiu 等人的 LIF 模型明确忽略非脉冲神经元和受体动力学。因此本项目的 graded APL 不是论文提供的“作者 APL 算子”,也不能由该论文直接获得 MaleCNS APL 参数。[Shiu et al., Nature 2024](https://pmc.ncbi.nlm.nih.gov/articles/PMC11446845/)
Amin 等人的局部刺激与成像显示 APL 活动和对 KC 的抑制具有空间局部性,为研究局部 APL 模型提供依据,但不能直接指定当前 MaleCNS 的每条边强度。[Amin et al., eLife 2020](https://pmc.ncbi.nlm.nih.gov/articles/PMC7541083/)
Prisco 等人结合 EM 和体内成像,研究了 calyx 中 APL 对 PN bouton 与 KC dendrite 的作用及区域化响应。这支持区分末梢与全神经元作用范围;不等于允许把 PN 整个细胞的输出统一抑制。[Prisco et al., eLife 2021](https://pmc.ncbi.nlm.nih.gov/articles/PMC8741211/)
这些证据不提供本数据集逐边受体、局部时间常数和 mV 转换系数。缺项继续标记 unknown,不人工补齐。本次主代理核验了上述公开原始来源;eLife 直连出现浏览器验证时使用其 PMC 原文/作者摘要,不把搜索结果中的其他论文当作替代数据。
## 不重走的路
- 不因累计 APL/兴奋比值约 3.05 就将 gain 除以 3;那是结果导向调参。
- 不因静默比例高就改 KC/MBON 阈值、提高输入或降低验收标准。
- 不将 APL→PN 的解剖接触直接解释为 whole-PN 抑制或同 bouton 的有效抑制。
- 不顺手恢复/改写 1,212 条未被 graded 替代的非 KC fast APL 边;若测试其作用,另立明确机制对照。
- 不根据少放电、多放电或稀疏率单项选择候选。表征、泛化、信用分配和功能性记忆仍须分别验证。
本页没有新增边、模型参数、learned weights 或行为成功声明。
+89
View File
@@ -0,0 +1,89 @@
# Phase 4AI:PN 再招募与 APL 来源审计
正式状态:`PASS-CONDITIONAL-PN-APL-SOURCE-AUDIT`。这是审计通过,不是表征或学习通过。
## 核验范围
74 项合成测试通过;固定 8 个小场景、60 个 CAL 主记录、12 个技术重复,共 80 份既有 Phase 4AG-r2 记录。PN 的完整放电事件、计数、最终 V/g/ref 逐位一致;8 个小场景的每步 pre/post 状态一致;12 对统计重复一致。CAL 没有独立保存逐 PN 的每步状态,不能把最终状态/事件验证称为完整逐步历史验证。
额外独立复核了每个首发前真实边事件的 source spike、18-step delay、真实 canonical edge、权重位值、到达时刻、接受状态、严格首发前条件。跨批唯一性与从原始 source events 重新推导的逐边期望数量均一致,无漏项或重复。
没有运行新全脑实验、使用 GPU、改参数、改权重、训练或访问 held-out 动态结果。全程只对既有记录做条件重建与非反馈分账;这不是独立全脑 oracle,也不是删掉某条通路的反事实。
## 1. 非设计 PN 的活动先于 KC
“非设计”仅表示该 trial 静态刺激目标集合以外,不等于噪声、错误神经元或污染。
|指标|physiological|matched_energy|
|---|---:|---:|
|非设计 PN 首次活动早于首个 KC 的主记录|30/30|30/30|
|首个非设计 PN tick 范围|40–223|45–216|
|首个 KC tick 范围|111–322|126–294|
|首次活动前已有非设计 PN 活动的 active KC neuron-trials|1550/1550|1504/1504|
|首次活动前已有真实非设计 PN→KC 到达边事件|1539/1550|1496/1504|
|非设计 PN 放电 / 全部 PN 放电|138679/154514|137431/153049|
tick 是保存记录的整数时间索引,dt=0.1 ms;这里给出的是记录内时间,不是相对每个外部刺激 onset 的延迟。上表多 trial 合计不能当作不同神经元数量。
## 2. 首发前 PN 输入来自哪里
限定对象为已经放电的非设计 PN:14967 / 14939 neuron-trials,两种模式各涉及 547 个不同 PN。
|首发前接受的正权重增量来源|physiological|matched_energy|
|---|---:|---:|
|ALLN|65.7040%|65.7683%|
|ALPN|27.7791%|27.8722%|
|其他已注释神经元|5.2174%|5.0328%|
|KC|0.00124%|0.00105%|
ALLN 是 metadata 中精确的 `annotation_class == ALLN`,不是 ALIN;没有根据类型前缀补齐身份。来源表同时保留负权重与零权重。
这些占比是首发前**名义正增量的累计份额**,不是净电流、净去极化或因果贡献。非反馈 V 账本中,ALLN 在首发阈值检查前的平均正/负项约为 +8.93/−5.85 mV(净约 +3.08 mV),而 ALPN 约为 +4.43/−0.11 mV(净约 +4.32 mV)。不能因 ALLN 正增量占比最大就声称其净去极化最大。
这个统计窗口截至每个 PN 自身首发,不是全部截至全网首个 KC,不能拿 66% 直接解释最早一批 PN 的启动。最早非设计 PN 先于首个 KC,排除了此前 KC spikes 启动这一最早群体的解释;之后的再招募与反馈仍可存在。当前只直接覆盖 ALLN→PN 来边,不是 PN→ALLN→PN 动态闭环、必要性或唯一因果路径证明;后续必须保留负项、时间过滤、其他通路和从未激活 PN 对照。
## 3. graded APL 的来源
冻结 APL 输入矩阵是非负 raw-contact 归一化工程映射,不是实际 signed PN→APL LIF 电流,不能称为测得的 dopamine/电导或生理量。
|non-design ALPN 来源份额|physiological|matched_energy|
|---|---:|---:|
|整个记录累计 h 写入|73.9038%|73.9797%|
|每个 active KC 首发严格之前的 h 合计|66.5249%|66.7294%|
|全网首个 KC 严格之前、全部 KC 的 h 合计|62.8646%|62.4176%|
全网首个 KC 之前的 KC 来源为 0,其余来自 design ALPN。在零初态、由 KC spikes 驱动的算子下,这是结构性结果,不能当成独立证明“KC 反馈无作用”。整窗 KC 来源仍占约 4.72% / 4.64%,每只 active KC 自身首发前占约 7.53% / 7.32%。这些均不证明 PN/APL 是 KC 稀疏度失败的原因。
三组 float64 合计与保存的 float32 drive/state/h 在预先推导的逐 tick 数值误差界内;这是数学来源分账,不是 bitwise CUDA APL replay。累计份额仍是描述统计,未构造累计来源份额的误差区间,不宣称“主导份额经严格误差界证明”。
## 4. 共同活动很强,但不能据此宣布气味信息为零
主比较固定全部 686 个 ALPN 维度;次比较固定六种 CAL 刺激目标并集 76 个 PN 之外的共同 610 维。每模式固定 60 within-seed-pair 与 75 between-odor/same-seed 比较;技术重复不充当新 seed。
|固定 686 维指标:within / between|physiological|matched_energy|
|---|---:|---:|
|Cosine distance|0.002812 / 0.003146|0.002936 / 0.003291|
|Pearson correlation|0.993240 / 0.992438|0.992964 / 0.992107|
|Active-set Jaccard|0.982743 / 0.980222|0.982590 / 0.979699|
|Euclidean distance|22.7359 / 26.6852|25.3697 / 25.2796|
共同活动与小的气味差异可以并存。尤其 matched-energy 的 Euclidean between 不高于 within;不同指标并不一致。这不是无信息的统计证明,也不是学习可用性、held-out 泛化、分类器或显著性检验。
## 结论与下一步
原 Phase 4AG `FAIL-FIXED-CAL-REPRESENTATION` 完全不变,未产生学习候选。本轮减少了机制不确定性,没有把“出现差异”当作成功。
下一步先用固定 60 CAL 的已有记录,核对最早非设计 PN 群及首个 KC 前窗口,分开 design/non-design ALPN 与 ALLN 的正负输入,并查 PN→ALLN 方向的真实带时延先行边。不能挑出现所需结论的 cohort,也不能把 shortest path 当动态路径。
再按独立预声明协议检验一个时间算子假设:原 graded APL 当步末写入,与固定平移 18 步的工程对照。不能称为实测生理修正,不能调 gain、threshold 或 eta,不能扫描最佳 delay。先验证固定序列的按位平移与末端样本完整性,再决定是否进入闭环;详细边界见 [下一步假设](phase4ai-next-hypotheses.md)。
## 完整性和保存位置
- 原始登记 230239 个文件及后续 Phase 4AA–4AH 各冻结目录 checksum 全通过。旧五组 reference 本轮未重跑;上一轮封存 PASS 记录按 SHA 校验未变。
- 新模型目录:`models/male-cns-lif/pn-recruitment-audit-v1/`,16 个 payload 文件,170860 bytes。
- 新实验目录:`experiments/phase4ai-pn-recruitment-audit/`,734 个 payload 文件,1101594284 bytes,约 1.10 GB。纯 CPU 审计时间合计 726.84 秒,不是脑实时性能 benchmark。
- 模型 manifest SHA-256:`a53443ac124e9bebc813867a5015d77276c2bd3edf89cd606a57d54756fe0dd7`。
- 实验 manifest SHA-256:`12c6f2e9929b3f7084e8b39b90c8851185febbc0afbb7031f9eebb4c41d2731d`。
- Git 仅发布代码、257 份小证据(约 5.85 MB)、文档与校验;完整新事件数据仍在服务器,不是异机全量备份。
解释指标由 `tools/report_phase4ai.py` 从已封存表只读导出,保存于 `registry/phase4ai-pn-recruitment-audit/interpretation-metrics.json` 并附独立 SHA;不修改原封存 manifest 或科学 gate。
+36
View File
@@ -0,0 +1,36 @@
# Phase 4AI 后的最小时间算子假设(尚未执行)
这是后续独立分支的设计建议,不是已经注册或完成的实验,也不是生理正确性结论。Phase 1–4AI 的代码、数据、参数与结论不因此改变;学习门仍关闭。
先补一项窄范围只读时序检查:在固定 60 CAL 中保留同时首发的全部最早非设计 PN,窗口截至首个 KC,分开 design/non-design PN 与 ALLN 的正负来源;核实 PN→ALLN 方向的真实先行边,必要时仅条件重建 ALLN 的接受状态。Phase 4AI 已验证 ALLN→PN 输入,但未证明动态 PN→ALLN→PN 闭环。此检查不运行新全脑实验,也不用于选择“最佳延迟”。
## 当前可以由代码确认的时间契约
现有 graded APL 组件在 PN/KC 于 tick `s` 放电后,当步更新其状态并在 `s` 末写入 KC 的 `g`。这次写入最早影响 `s+1` 的 threshold。真实直接 PN→KC 边在 `s+18` 的 threshold 之后到达,最早影响 `s+19` 的 threshold。
这是两个算子的调度差异,不足以证明该差异就是失败原因。APL 原参数的单位是每状态每步增量,不是“漏乘 dt”;不能把原数值直接重新解释为 tonic 电位、也不能根据累计抑制/兴奋比反推 gain。
## 唯一建议的最小对照
在新的独立目录和预声明协议中,只比较原 `delay=0` 与固定 `delay=18 steps`:
`h_apply[t] = 0 (t<18), otherwise h_generated[t-18]`。
其余全部保持原样:APL 状态递推、float32 位值、I/O 映射与归一化、gain、fast-APL mask、LIF 参数、connectome、sign、外部请求文件。不扫描“最佳延迟”,不选效果好的 seed,不训练。18 步来自现有解剖事件队列的工程对齐,不是测得的 MaleCNS APL 生理延迟。
注意:整条 `h` 延迟也会延迟 KC→APL 反馈,不是 PN-only 干预。解剖边到达仍受 refractory 保护,APL 写入仍不受该保护;时间对齐不等于两种作用完全等价。
## 两层验证不可混淆
1. 固定现有上游 spike/h 序列:按位平移 h,前补零并显式保留记录末端再延迟的 18 步。验证记录内每一个 h 样本无损、无漏、不循环移位,保持完整已生成序列的累计抑制量;不得把它称为未知未来的完整衰减尾部。
2. 如继续全脑闭环:只能声明同一请求与同一算子参数。放电变化会改变后续 APL drive/state/h,不能声称两条件实际抑制总量仍相同,更不能事后重新归一化。报告末端状态和未排空事件,保留原固定 CAL 与后续学习门。
先完成零输入、单 PN 脉冲、有限脉冲列、末端脉冲及 reset/refractory 碰撞的 CPU/GPU oracle 检查。`delay=0` 必须重现原记录;任何差异均先停,不进入 CAL。若唯一 delay 改动后完整 CAL 仍失败,则“单独消除这项调度领先足以修复 CAL”的假设不成立;即使通过,也不等于生理正确、泛化通过或学习成功。
## 一手文献边界
- [Shiu et al., Nature 2024](https://www.nature.com/articles/s41586-024-07763-9) 使用固定 1.8 ms 的突触延迟,并讨论统一 spiking LIF 对 non-spiking 生理过程的限制。这不等于解剖上删除 APL,不能写成 MaleCNS/APL 实测值。
- [Amin et al., eLife 2020](https://elifesciences.org/articles/56954.pdf) 支持 APL 非脉冲活动及局部 KC 抑制;约 5 Hz 成像不足以解析其推测的毫秒级传播,不能据此指定精确 MaleCNS 延迟。
- [Prisco et al., eLife 2021](https://pmc.ncbi.nlm.nih.gov/articles/PMC8741211/) 支持 calyx 中 PN/APL/KC 的局部关系和响应归一化,不给出这些 MaleCNS 路径的毫秒延迟。
因此 0、1.8、3.6 ms 均不得宣称是由这些文献确定的 MaleCNS APL 生理参数。此建议只用于可证伪、单因素、可回归的工程动力学分支。
+79
View File
@@ -0,0 +1,79 @@
# Phase 4AJ:固定 graded-APL 时序分支
日期:2026-09-30。正式状态:`PASS-FIXED-CAL-APL-TIMING-HYPOTHESIS`。
这表示固定校准门通过,不是 held-out 泛化、关联记忆或“学习已经可用”。没有产生候选模型,也没有替换正式 runtime。
## 唯一干预与独立性
以封存的 Phase 4AG-r2 为对照,只比较完整 graded-APL 输出 h 在生成当步施加(D0),或延迟固定 18 tick / 1.8 ms 施加(D18)。这是工程时序假设,不是测得的 MaleCNS APL 生理延迟;PN 与 KC 来源的 h 一起延迟。
未改变 raw、CSR、原始 contact count、W_syn、符号、LIF 参数、APL tau/gain、eligibility-v2 或 14232-edge plastic mask。独立分支继续保留既有 5845 条 fast-APL 输出置零约定,其中 1212 条非 KC 边仍未被 graded 算子替代。没有静默修补这一局限。
两臂同一 case 的输入请求字节相同;受不应期影响,实际接受事件和闭环生成的 h 可不同。`matched_energy` 匹配的是预期输入量,并非不同气味的实际接受事件数完全相等。
## 固定 CAL 结果
每臂 6 气味 × 2 模式 × 5 seeds = 60 条主轨迹,另有 12 次精确重复;每条为 100 ms。两个臂均完整执行,未按结果删去条件。
| 指标 | D0 生理输入 | D18 生理输入 | D0 匹配预期输入 | D18 匹配预期输入 |
|---|---:|---:|---:|---:|
| 平均 KC 活跃比例 | 1.2713% | 3.4482% | 1.2336% | 3.4072% |
| 最小–最大活跃比例 | 0.9350–1.9439% | 2.7067–4.6752% | 0.8858–1.7717% | 2.7067–4.6014% |
| 同/异气味 Jaccard | .509072 / .460955 | .516363 / .480098 | .516431 / .481702 | .529681 / .495694 |
| 同/异气味 Euclidean distance | 5.811443 / 6.205091 | 9.493907 / 9.972922 | 5.671828 / 5.932021 | 9.263882 / 9.684475 |
| 通过的气味对 | 12/15 | 11/15 | 13/15 | 11/15 |
| 原六项门槛 | FAIL:平均活跃比例 | PASS | FAIL:平均活跃比例 | PASS |
原门槛保持:平均 KC fraction 在 3%–9%,所有运行非零且小于 50%,同气味 Jaccard 高于异气味,异气味欧氏距离高于同气味,至少 3 个气味对通过。平均门槛不要求每一条轨迹都达到 3%。每模式 60 个 within 比较、75 个 between 比较;每个气味对使用自己的 within 基准。
**不能把本结果解释为分离能力全面提高。** 可分气味对数量反而由 12/15、13/15 降为 11/15;欧氏距离还受活跃维度与计数影响。通过的是预先固定的完整 CAL 判据,不是显著性、记忆或生物学真实性证明。
顶层 `calibration.pass_all` 为 false,因为它要求两个臂的表示门都通过;D0 的已知表示失败没有改变。实际执行看 `execution_gate_pass=true`;正式时序假设结论由完整数值门与 D18 门决定,没有把 D0 失败改写为成功。
## 数值与完整性
- 模型合成测试本地和服务器均 65/65;发布工具 12 项、描述工具 6 项,合计 18/18,在本地和服务器均通过。
- 60 份封存对照中,420 个 ALLN 的事件、计数及最终 V/g/ref 条件重建通过。
- 固定生成序列 68 × 2 = 136 项平移检查通过。初始正零与未消费尾部样本按位保留,不额外推进脑来清空尾部。
- 两臂各 8 个 fixture 与 2 个全图 probe,共 20 组 Brian LIF/GPU 与 APL 组件检查通过;32 组 fixture 技术重复通过。
- 两臂 120 条 CAL 主轨迹及 24 次重复完整,D0 的 72 次 CAL 对照精确复现旧结果。
- 旧五组冻结参考新运行的事件序列、计数和最终 V/g 均逐位一致。原登记 230239 项与后续 Phase 4AA–4AI 各封存目录均校验通过,无 mismatch。
Brian 独立执行 LIF、产生自己的 spikes 并维护独立 FIFO,但 APL 算术仍共享已冻结 Torch 组件;另有 AST replay/舍入界组件审计。不能称全组件独立 CPU 验证或普遍等价证明。当前仅验证了固定短轨迹,不代表任意时间长度的稳定性。
旧 reference 加载只读 NumPy 数组时发出 PyTorch 警告;未为此修改封存代码。五组回归仍精确,冻结文件校验通过。诊断耗时包含同步、哈希和进程通信,不是生产运行时速度。
仓库格式审查保留 3 处非功能性提醒:已封存 `compare_timing.py:611`、`gpu_timing.py:453` 的末尾空行,以及 `test_calibration.py:206` 的行末空格。没有为了通过格式检查改写已登记/封存源代码;这些提醒不是数值失败,也不应报告成“格式检查零提醒”。
## 最早非设计 PN:补齐的是带时序先行证据
以下只来自旧 AG-r2 的 60 条对照轨迹,**不是新 D18 的来源归因**。窗口严格早于 earliest cohort 各自首发以及全网首个 KC;所有同 tick 首发 PN 均纳入。
| 指标 | 生理输入 | 匹配预期输入 |
|---|---:|---:|
| 最早非设计 PN 早于首个 KC | 30/30 | 30/30 |
| 最早 cohort neuron-occurrences | 36 | 34 |
| 接受到该 cohort 的 ALLN→PN edge-events | 85 | 91 |
| 其中 ALLN 本次放电前、上次 reset 后有 design PN→ALLN 接受事件 | 85 | 91 |
| 保存的时序 join pairs | 274 | 320 |
| design ALPN 名义正增量合计(SI V) | 2.546500 | 2.189825 |
| ALLN 名义正增量合计(SI V) | 1.411025 | 1.446500 |
| ALLN 名义负增量绝对值合计(SI V) | .191950 | .209550 |
这里既有直接 PN 来边,也有符合实际延迟/接受条件的 PN→ALLN→PN 先行链。名义正增量最大的并非 ALLN;不能沿用 4AI 另一群体/窗口的约 66% 数字。85/91 是带时间的边事件数,不是唯一边数;274/320 是可共享先行事件的 join pairs,不是独立因果重复。负权重事件不构成兴奋性招募证据。
这些结果排除“尚未发生的 KC spike 启动最早 PN”这一解释,但不证明某条边的必要性、充分性、唯一原因,亦不证明气味信息全部丢失。ALLN 是 annotation class,不是 nonspiking 身份。
## 保存与下一关
- 新模型:`models/male-cns-lif/apl-timing-lab-v1/`。
- 新实验:`experiments/phase4aj-apl-timing/`。
- 模型 payload 21 文件、275408 bytes;实验 payload 4954 文件、6991917799 bytes(约 6.99 GB)。这不包含 manifest/checksums 两个控制文件。
- 模型 manifest SHA-256:`52b05dd1ff30b6b51ff960fe95904532f5c147731a83f0b5c31f98ca7e53c216`。
- 实验 manifest SHA-256:`7f490ada0db30785c61954d8b92147378ddc8bc16b229fe3808bbe501caff44a`。
- 发布复制 1957 个小证据/控制文件、8673739 bytes(约 8.67 MB);另有发布收据、索引与只读解释文件,不将它们混入上述复制数量。
- [正式状态](../../registry/phase4aj-apl-timing/evidence/audit/final-status.json)、[CAL](../../registry/phase4aj-apl-timing/evidence/calibration/summary.json)、[旧回归](../../registry/phase4aj-apl-timing/evidence/regression/frozen-five.json)、[封存校验](../../registry/phase4aj-apl-timing/seal-verification.json)。
- [只读解释指标](../../registry/phase4aj-apl-timing/interpretation-metrics.json)另附 SHA,不修改科学 manifest 或原 publication receipt。
完整事件数据留在服务器;Git 只同步代码、小报告和校验,不是全量异机备份。下一步见 [独立验证计划](phase4aj-next-validation.md),本阶段没有执行其轨迹,没有训练/条件化、held-out 动态访问、游戏、decoder、RL 或 Web。
+43
View File
@@ -0,0 +1,43 @@
# Phase 4AJ 后:冻结 D18 的独立验证计划
状态:**待新阶段预注册与执行**。本文件是计划,不是已通过的结果。
Phase 4AJ 固定 CAL 已通过,下一关应检验外推,不能继续扫描 delay/gain 或直接宣称学习可用。
## 固定设计
只使用已封存 D18;动力学、100 ms 窗口、输入编码、APL 算术/队列、符号、CSR、mask 与原判据全部固定。
| 验证块 | 固定输入 | 主运行 | 技术重复 |
|---|---|---:|---:|
| 独立种子 | 原 6 个 CAL 气味 × 5 个新 seeds × 2 模式 | 60 | 12 |
| 校准未用气味 | 静态面板后 6 个气味 × 同 5 个新 seeds × 2 模式 | 60 | 12 |
在任何新脑轨迹之前,锁定两个块的输入、种子、分析、停止规则和 SHA。先完成独立种子块,只有完整通过才解锁第二块;失败就封存,不换 seed/气味重试。第二块固定首气味/首种子的两种模式作新增 Brian 全图对照,不能按结果挑选。
每个“验证块 × 模式”分别通过原六项完整 CAL 门,四项全部通过;不许合并 12 个气味的平均值来挽救失败。逐位技术重复、有限 h 平移/pending、数值完整性和旧冻结回归仍必须通过。重复不是新随机样本;跨气味共享种子用于原配对统计,两块不应描述为独立随机流或生物重复。
## 静态输入与泄漏边界
允许读取原 `phase4l-olfactory-grounding` 的以下静态文件并核对已登记 SHA:
- `odor-encoder/frozen-odor-panel.parquet`
- `odor-encoder/mapped-glomerular-vectors.npz`
- `odor-encoder/selection.json`
- `receptor-mapping/olfactory-mapping.parquet`
原行序、split、气味身份、glomeruli 顺序、PN 映射、RNG 列序和零响应规则保持不变。匹配输入基准继续用全 12 气味静态中位数 `2.556107997894287`,不得对任一六气味子集重算。
禁止提前读取旧 `kc-representation`、整个 12 气味动态输出、`eligible-edges`、`plasticity-magnitude`、`conditioning` 或混合这些结果的综合报告;不能先打开混合表再过滤。静态 A/B 身份也不能用于挑选有利气味替代完整验证块。
旧 4L 代码曾遍历全 12 气味。因此后六个只叫**“未参与 AG/AJ 校准的气味”**,不能说项目历史从未模拟过。新分支验证是对固定新模型的外推测试,不是完全未被研究过的生物样本。
先通过仅配置/输入清单的审计确定新 seed namespace,连同显式派生规则检查重用。`52101–52105` 已在 4Q/4R 使用,`51301–51305` 是旧学习评估种子,`512xx` 存在 train_seed+pairing 派生范围;不指定未经查证的新值,不无依据承诺全历史绝对独立。
## 实现约束与结果范围
旧 AG `validate_inventory` 硬编码原 CAL seeds/IDs,`read_trial` 记录也硬编码 calibration。新阶段须新增明确 cohort 的适配器,复用来源固定的纯指标与数值校验;不能改旧 globals、伪装成原 CAL 或改封存源码。
计划依据:仓库 `models/male-cns-lif/phase4l.py` 的静态编码/原指标(约 149、199、204 行),`phase4p_revalidate.py` 的 PN drive(约 226 行),`author-apl-lab-v2/calibration.py` 的指标/inventory(约 77、96、243、268 行),以及封存的 AG `protocol/encoder-audit.json`。行号仅帮助定位,实际以 SHA 登记版本为准。
即使全部通过,下一关仍是 credit specificity、真实 KC→MBON 功能传递、全脑输出与带控制的 conditioning;不产生 learned candidate,不接游戏、RL 或 decoder。1.8 ms 仍是工程假设,不因此成为实测生物学参数。
+120
View File
@@ -0,0 +1,120 @@
# Phase 4AK:冻结 D18 的验证与解释边界
状态:**已完成并封存,`PASS-FROZEN-D18-INDEPENDENT-VALIDATION`。** 两块共 120 个主运行、24 次精确重复及全部预声明门禁通过。本文依据本地已下载、哈希校验的新 AK 最终证据解释结果;这是冻结 D18 分支的表征验证 PASS,不是学习成功或 learned candidate。
## 本阶段检验什么
检验已经固定的 AJ D18 分支,能否在预声明的新种子和未参与 AG/AJ 校准的六个气味上,继续满足完整原 4L 表征判据。本阶段没有再次选择 delay 或调整 gain,也没有训练、更新塑性权重或产生 learned candidate。
两块输入、稀疏请求、源码 SHA、分析规则与停止规则已在任何新脑轨迹前锁定:
| 验证块 | 固定输入 | 主运行 | 技术重复 |
|---|---|---:|---:|
| `seed_validation` | 原六个 CAL 气味 × 五个预声明种子 × 两种输入模式 | 60 | 12 |
| `novel_to_aj` | 原静态面板后六个气味 × 同五个种子 × 两种模式 | 60 | 12 |
每次仍为 100 ms;模式为 `physiological` 与 `matched_energy`。每气味、每模式重复首种子,重复用于逐位完整性检查,不是额外随机样本。只有种子块的数值、重复及全部原表征门同时通过,才允许启动第二块。未解锁、未执行的条件不记为 PASS;失败不换种子或气味重试。
冻结的动力学包括:float64 LIF、float32 legacy graded APL、`dt=0.1 ms`、普通突触延迟 18 步、不应期 22 步、原图与符号/权重/阈值,以及 APL `tau=20 ms`、`gain=0.01`、`normalization=1`。整条生成的 graded-APL `h` 延后 18 步应用,包含其依赖的 PN/KC 实际放电反馈;不是只延后某一种来源。
APL 仍在步末、reset 之后无条件写入 KC 的 `g`,不新增不应期守卫;仍先把 `h32` 提升为 float64,再乘 SI 换算系数,最后单独相减。保存起始正零填充及窗口末尾尚未应用的队列槽,不推进额外脑时间来清空尾部。这里的 1.8 ms 是被冻结的工程假设,不是经本阶段测量的生物学参数。
## 原六项门禁,不以汇总平均值补救失败
每个“验证块 × 模式”分别保留以下六项条件:
1. 平均 KC 活跃比例处于闭区间 `[3%, 9%]`。
2. 所有主运行的 KC 活跃比例最小值严格大于 0。
3. 所有主运行的最大值严格小于 50%。
4. 同气味 Jaccard 均值大于异气味 Jaccard 均值。
5. 异气味欧氏距离均值大于同气味欧氏距离均值。
6. 至少 3/15 对气味通过各自的分离判据。
第六项不是用全体气味的共同基线:每对气味的五个同种子跨气味距离,对照这两个气味各十个种子间距离,合计二十个 within 距离。每个模式共 60 个 within 比较、75 个 between 比较;这些成对统计不是 60/75 个独立生物样本。
四个分组须分别通过,不合并十二气味均值来挽救某一分组。原数值完整性、逐位技术重复、generated/applied/pending 时序检查、固定对照、oracle/component 检查、旧冻结完整性及五个参考回归仍是必要条件。科学判据失败与执行不完整分别报告,不调阈值、不换观察窗口、不扫描参数。
## 种子与气味的“新”,各有明确范围
五个种子为 `1073741825–1073741829`,即 `2^30` 后的首五个正整数。选择依据是预声明静态 namespace 审计与固定算术规则,不依据活动量、可分性或运行成败。
静态审计列出了 **217 个本地文件快照**及其哈希;其中 **43 项**有明确的远端路径和 SHA 映射。封存 `prepare.py` 在写入预注册文件前,遍历 `seed-audit.json.inspected_files` 中非空的 `remote_path`,逐项断言远端文件哈希等于该行 `sha256`,再将其合入 `preregistered.json.inputs`。本次本地交叉复核确认:43 项全部出现在预注册的 51 项输入清单中,`path/sha256` **43/43 匹配、0 项不符**;预注册同时记录 `before_new_requests_and_brain_trajectories=true`。没有臆造独立的“43 项 PASS”字段或远端复查日志。
对应的 SHA-256 为:`model/seed-audit.json` → `e14c0deb94432787aa1cac7618254aeb3db0bcd5b1d8328e20428496d38b220a`;`model/prepare.py` → `d8b8315f8800b3efdc7548620f0fae85da21a12b753b9985dd623bd529e2c50f`;`protocol/preregistered.json` → `c9cda32a74b45df192824405e65b98571b6febcddd5f63d78e5edefac619b300`。43 项不是完整远端历史,217 项也不是所有历史执行的输入注册表。
审计考虑了列出的配置与已解释派生规则,但不覆盖未列出的 server-only 文件、CLI 覆写、终端历史、其他分支/版本、外部调用者或其他用户运行。因此准确说法是“在声明的静态审计范围内未发现重用”,不是“全历史绝对独立”。新整数也不证明 PRNG 流在统计上独立。跨气味、模式及两块继续共享同一组种子,是配对设计,不是彼此独立的生物重复。
旧 4L 代码曾遍历完整十二气味面板。因此后六气味只称 **“未参与 AG/AJ 校准的气味”**,不能称“项目历史从未模拟的气味”。本阶段可读取固定面板、外部响应向量、静态 selection 与 PN 映射;不能提前解析旧 heldout 动态结果或混合结果表来挑选输入。完整性哈希读取不透明文件字节,也不授权解析那些旧结果。
## matched energy 匹配的是预期输入
输入编码、PN 目标及 RNG 列顺序沿用原规则。`matched_energy` 仍使用完整原十二气味面板的固定中位数 `2.556107997894287`,不对任一六气味子集重算,也不按脑活动重新缩放。
此模式匹配的是编码器定义下的**预期请求输入量**,不是每次实际生成的请求数、实际接受的请求数或闭环全脑总活动。随机抽样会造成实现值变化;不应期状态也影响请求接受。不能把“matched”解释为各次实际事件、有效输入或抑制积分严格相同,更不能事后补发请求以强制相同。
## 数值验证能证明到哪里
新阶段直接调用 SHA 固定的封存 AJ 数值实现,不修改旧模块 globals 或动力学。本阶段完成了两个原 D18 全图输入的逐位身份对照,以及每个验证块首气味、首种子、两种模式的四个 Brian 全图 probes,均通过;六份对应的 component 审计全部通过。probe 的 GPU 运行计入对应六十个主运行,不能重复算为独立样本。
Brian 一侧独立推进 LIF、实际放电和 FIFO,但 graded APL 算术有意共享冻结的 legacy 组件,并另做原始操作的 component/AST 审计。有限 probes 不能被表述为所有输入、所有硬件或全组件独立 CPU/GPU 等价证明。旧八夹具属于源代码固定的继承证据,不声称本阶段重新运行了八夹具。
旧 fast-APL 屏蔽仍覆盖 5,845 条出边,graded 替代只作用于 KC;其中 **1,212 条非 KC 出边没有 graded 替代**。本阶段没有修复这一作用范围缺口。即使验证通过,也不证明 upstream AL 环路已得到生物学确认,不证明单一来源具有因果必要性。
## 最终结果
以下四模式表来自封存的 `validation/<cohort>/summary.json` 及模式摘要。显示值作舍入,门禁按未舍入数据计算。四个分组均通过原六项条件;3–9% 约束是各分组的**均值**范围,不要求每个运行都至少 3%。
| 验证块 | 模式 | KC 比例均值 / 最小 / 最大 | 同 / 异气味 Jaccard | within / between 欧氏距离 | 通过气味对 | 完整六门 |
|---|---|---|---|---|---|---|
| `seed_validation` | physiological | 3.4670% / 2.4360% / 4.4291% | .543794 / .487243 | 9.106586 / 9.867235 | 12/15 | PASS |
| `seed_validation` | matched_energy | 3.4564% / 2.5098% / 4.2815% | .523960 / .498134 | 9.350120 / 9.710761 | 11/15 | PASS |
| `novel_to_aj` | physiological | 3.2767% / 2.4114% / 4.2077% | .511063 / .444272 | 9.307078 / 10.158885 | 14/15 | PASS |
| `novel_to_aj` | matched_energy | 3.2579% / 2.4114% / 4.2077% | .523955 / .449042 | 9.102812 / 10.059135 | 14/15 | PASS |
- 最终状态为 `PASS-FROZEN-D18-INDEPENDENT-VALIDATION`;`numerical_gate_pass`、`seed_validation_pass`、`novel_to_aj_pass` 均为 true。
- 计划、实际完成及有效聚合的主运行均为 **120**;精确重复 **24/24**。两块各完成 60+12,没有以技术重复增加种子样本数。
- `novel_dynamics_executed=true`、`novel_unlock_policy_violation=false`,`stopped=[]`:种子块通过后解锁第二块,没有已记录的违规解锁或停止事件。
- D18 身份对照 **2/2**、Brian probes **4/4**、component 审计 **6/6**、独立重算的重复检查 **24/24** 通过。此处数量仍受前述有限 probes、共享 APL 算术的证明范围约束。
- `regression/old-integrity-after.json` 对原清单 **230,239** 个文件及后续 **AA–AJ** 纳入链条的模型、实验和相关 registry 全部给出 `pass=true`、空 `mismatches`。按原完整性契约排除缓存、venv 等项目;不能把它改述为整台服务器所有文件均被检查。
- `regression/frozen-five.json` 的 `pass_all=true`;五个旧 deterministic-v2 参考为 auditory-10hz、auditory-100hz、olfactory-50hz、mechanosensory-50hz、gustatory-50hz。每项的 `step/neuron_idx/counts/v/g` 均 `exact=true`,记录的 dtype/shape 一致。这验证旧参考未漂移,不把旧 float32 参考误说成 D18 新动力学的额外 oracle。
### 测试及保留的警告
封存的服务器 `regression/unit-tests.log` 明确记录 **48 tests / OK**,配套 JSON 为 `exit_code=0`、`pass_all=true`;日志 SHA 为 `5206333f1a31fc62671ebe6bdba02f3b2b2f0303f6009e905d7ca94bdc2a666f`。
本轮执行会话另外记录:本地模型测试 **48/48**,本地与服务器发布/下载工具测试各 **51/51**(本地 28.230 s、服务器 1.642 s)。这些本地及工具测试结果只有会话控制台记录,**未纳入科学 seal,也没有对应的独立仓库日志文件**;不得虚构证据路径。这些是操作与合成测试,不替代科学门禁。
同一轮 `verify_frozen.py` 控制台仍出现旧 `phase4c.py:308` 的 `torch.as_tensor` 读取只读 NumPy 数组警告;原源码未因本阶段而修改,警告保留,不写成“无警告”。同一进程的五个参考检查均逐位通过。警告的原始记录在本轮执行会话中,未纳入独立封存日志;逐位参考结果则保存在上述封存 JSON。
本轮 Git 格式检查也有非数值提醒:默认规则返回 2,报告 16,237 项,其中 16,236 项是封存 `requests.csv` 的 CRLF 换行被识别为尾空白。以一次性 `core.whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol` 识别 CRLF 后,仅剩已登记 `models/male-cns-lif/apl-timing-validation-v1/seed-audit.json:9314` 的末尾空行。没有修改仓库配置或任何封存字节来消除提醒;不能写成“格式检查零提醒”。其余新模型、工具及文档无空白格式异常。实际暂存的 1,305 个模型/registry Git blobs 已按外部回执锚与封存清单逐一校验通过,格式提醒不改变科学 PASS。
### 封存、发布与本地证据
发布器记录对模型与实验完整 payload 在复制前后重新验证:模型 **17 个文件、526,864 B**;实验 **2,899 个文件、6,154,144,988 B**。这是 manifest payload 数量和字节数,按封存契约不含自引用 seal 控制文件。
发布回执 `copied_evidence_files=1283`、`copied_evidence_bytes=4895616`,即复制了 **1,283 个小证据/控制文件、4,895,616 B**。随后本地下载校验覆盖 **1,302 个文件,另加发布回执**;`selected_bytes=6591818`,该字节数包含回执。两份 manifest 自校验和每个实际下载文件的 SHA 均通过。发布/下载的这些计数口径不同,不能相加当作科学样本数。
| 证据 | SHA-256 |
|---|---|
| 最终 `audit/final-status.json` | `c49181086ecbd19511b9f1e783afea8f66d0f74348a7b70d7f6c5fa99b4337fc` |
| 模型 `model/manifest.json` | `3206a8666718b4a99e09b8384c87dd25895b5d7038d23fad7b93e40379183ccb` |
| 实验 `manifest.json` | `25eb7e467eb17c3fa83ffee2e4e82b754f161fd8891e515bed23eeb500c5656d` |
| 发布回执 `registry/publication-receipt.json`,亦为下载器必填的外部锚 | `37e85d7f264b844d481aa290918a10c56dfbecdfc7786862166f91d361bf4e62` |
这些哈希已在本地重新计算并与回执/下载校验记录交叉核对。五参考报告 SHA 为 `020fc362e70c4c0670e200783a8d1682f167f862e59840e8b8d80a4688e22433`;旧完整性报告 SHA 为 `273d4581cb15fb5da851ce19ee005abc15b265fbad4bd0a5bd8738e307fec2d0`。
发布成功与小证据下载校验不是科学 PASS;小文件证据包不是完整轨迹备份。本地没有下载并重新哈希全部大型轨迹,完整远端 payload 的前后验证由发布回执记录。正式科学 PASS 来自新阶段原始证据重算和最终门禁,而不是复制成功。
本阶段所有预声明验证块已执行并通过;没有用合并均值挽救失败模式,也没有因结果替换气味、种子或参数。结果支持冻结 D18 在这组新种子及校准未用气味上的表征外推,不支持更宽的全输入、全部硬件、真实生理机制或学习能力声明。
## 即使全部通过,也不等于学习完成
本阶段未更新 eligibility-v2,未改变 14,232 条塑性边 mask,未执行 conditioning,未生成 learned candidate,也未连接游戏、decoder、RL 或 reward 接口。最终记录中 `learning_achieved=false`、`candidate_generated=false`、`full_scientific_goal_achieved=false`。
**下一关 credit specificity 与真实 KC→MBON 功能传递尚未执行。** 后续还须独立验证全脑刺激特异输出,以及带控制的 conditioning;这些是后续门禁,不是本阶段已经取得的结果,不因本轮 PASS 而自动解锁为学习成功。
## 稳定依据与填表来源
稳定设计依据为模型目录 `models/male-cns-lif/apl-timing-validation-v1/` 下的 `PROTOCOL.md`、`config.json`、`SEED-AUDIT.md`、`seed-audit.json` 与 `validation.py`。原指标定义来自固定 SHA 的 AG `calibration.py` 与旧 4L `representation`;时序及重复检查来自固定 SHA 的 AJ 实现。
表格与封存结论仅使用新实验 `experiments/phase4ak-apl-timing-validation/` 下的 `validation/<cohort>/summary.json`、各模式摘要、相关 audit/regression 证据及最终 seal。发布凭据在 `registry/phase4ak-apl-timing-validation/`,已校验的本地小证据位于 `23-ai-gpu/reports/phase4ak-apl-timing-validation/`;工具测试和旧 NumPy 警告的会话来源另行明确标注。以封存哈希和外部回执锚确认版本,不以文件名、阶段名称或本文替代证据。
+74
View File
@@ -0,0 +1,74 @@
# Phase 4AL — KC credit / MBON 条件性传递审计
日期:2026-09-30。上一提交:`c6444255fe90fe1bdd5b862e63265587c15df442`。
正式状态:`PASS-CONDITIONAL-CREDIT-TRANSFER-AUDIT-NOT-LEARNING`。
这里的 PASS 指算术、身份和覆盖审计通过,不是学习通过。
## 实际完成
- 保留固定 D18,读取全部 120 条 AK 主轨迹和 24 条技术重复,不挑气味、种子或 compartment。
- 全部 144 次 MBON 条件基线重构的事件、逐神经元计数、最终 V/g/ref 与封存 AK 逐位一致。
- 对实际 KC 发放只读重放冻结 float32 eligibility-v2,在 tick 900 更新后采样,包含该 tick 发放;这是虚拟 gate,没有输入 DAN,没有写入 plastic_delta。
- 全部基线通过后,才执行一次预定的全既有 mask 25% 减弱。只改临时权重副本;所有上游/反馈发放钳制,目标 MBON 的阈值、复位和 refractory 独立重算。
- 24 次技术重复的基线、credit、分解和条件性结果全部精确一致;不把它们当成额外独立种子。
## 真实边范围
全图 166,700 neurons / 25,582,938 edges。4,064 KC、97 MBON;MBON 共 86,039 条入边,其中全部 KC→MBON 61,210 条。冻结候选 mask 为 14,232 条,目标只有 12 个 MBON。
| compartment 原始字符串 | 候选边 | MBON 目标 |
|---|---:|---:|
| `B2B'2a` | 4,346 | 2 |
| `a1` | 3,651 | 4 |
| `y2a'1` | 4,126 | 4 |
| `y5B'2a` | 2,109 | 2 |
95 条 DAN→MBON 边具有已封存的显式 compartment 原文匹配。这是 annotation token 与实际边的依据,不是突触 ROI 的独立定位。其他身份没有凭名称补齐;120 条 fast-APL→MBON 入边仍依冻结分支约定置零,未在本轮修正。
## 结果与边界
| 分组 | 各自特有 KC/候选边的气味对 | 候选边 active-set Jaccard 均值 | 25% 条件性试验改变 count 或首次 latency |
|---|---:|---:|---:|
| seed_validation / physiological | 15/15 | 0.57575 | 30/30 |
| seed_validation / matched_energy | 15/15 | 0.61094 | 30/30 |
| novel_to_aj / physiological | 15/15 | 0.54014 | 30/30 |
| novel_to_aj / matched_energy | 15/15 | 0.57905 | 30/30 |
分类使用各条件五种子中至少三次 trace>0。Jaccard 比较完整 A-active/B-active 集合,包含 shared,不再把互斥 specific 集合的零交集误当特异性证据。60 对均非空;共享成分仍明显。这里只验证每侧存在 specific KC/边,没有设新的整体学习成功阈值。
候选边占全部 97 个 MBON 的已接受正向名义输入增量,四组逐试验比例均值为 **1.075%–1.115%**。这个全 MBON 分母不能当作 12 个塑性目标的输入比例。
补充的封存后描述性复算:固定这 12 个既有候选目标,以每个 trial 的 `sum(accepted_plastic_positive_V)/sum(accepted_total_positive_V)` 求比例,再按组取平均,得到 **11.14%–11.46%**。12×120=1,440 个目标/试验单元中,964 个 count 或首次 latency 改变;其余 85 个 MBON 的这些指标没有改变。此复算只解释分母,不是新增或替代门槛,未改动封存报告。
该复算输入为 `experiments/phase4al-mb-credit-transfer/audit/per-MBON-primary.parquet`,SHA-256 `fd194e5af084527798b2a651bbc0b16eb772f208ccbf1aae5b1ef3e7520c7b30`。使用 `candidate_target == true` 的全部行,按 `cohort, mode, name` 分组;没有择优子集。
这些量是模型中已接受边增量或 source-state 的记账,不是能量、真实电导或 dopamine 浓度。分组 g 记账的最大舍入残差为 5.274e-16 SI V,未回写状态或归给某个神经元来源。
**可作出的判断:** 在这个固定条件回放中,14,232 边的改变能够影响 MBON 功能性发放;不能说 MBON 对它们完全无响应。
**尚不能作出的判断:** 25% 一致减弱不是气味特异训练得到的 delta,不是响应上界,且 MBON→DAN/MBON/其他反馈没有在反事实中闭环重算。因此不能声称关联记忆、行为学习或完整全脑 credit 已通过,也不能自动解锁 conditioning。
## 完整性与工程交付
- 29/29 服务器合成测试通过,包括冻结 NumPy AST / Torch CPU trace 的逐位比较;本地此前缺 Torch 的跳过项在服务器已执行。
- 五组旧 deterministic-v2 参考重新运行,事件/count/final V/g 全部逐位一致。这不是宣称新 D18 与旧动力学等价。
- 原有 230,239 个登记文件和完整性链共 26 个根全部通过;旧 frozen/reference 产物零差异。
- 封存前重新核验所有输出清单/哈希,144 次基线与原始 AK、24 次重复、60 对身份和全部汇总绑定。
- 模型 payload 14 文件 / 109,946 bytes;实验 payload 2,166 文件 / 1,336,493,035 bytes。
- 发布/下载/Git blob 验证工具 51/51 合成测试通过(本地和服务器)。Git 和本地证据同步不含大型轨迹,**不是全量异机备份**。
- 准备阶段仅遇到新实验目录创建权限,已在任何注册/科学计算前处理,并记录于模型 `PREPARATION.md`;旧目录权限未改变。
- 原样保存的编译日志有两行行尾空格,导致 `git diff --check` 返回 2;不为排版修改封存字节。它不是数值回归失败;实际 Git blob 已逐个对照 SHA 校验。
- 旧 `phase4c.py:308` 仍提示只读 NumPy 数组转 Torch 的警告;本轮没有改旧实现。五组输出仍逐位一致,旧文件校验无变化,警告原样保留。
模型 manifest SHA-256:`72e4b4e2c53c258939ca355f31eeba2cd6381e126a61efeea651d8bac8df5328`。
实验 manifest SHA-256:`a22de7d85cbfe760070ff55f5666e74475a3335c63bbd37b41241a94be7e3eea`。
## 下一关
先建立单独、预注册的 whole-brain plastic-overlay 验证:零更新必须逐位等同 D18;使用真实 compartment mapping 和固定 eligibility-v2;明确人工 reinforcement 接口,记录实际 KC/DAN 状态与每条边的信用。随后才在新分支评价独立种子的 CS+/CS− 前后 MBON/downstream 差异、完整反馈、零更新/未配对等控制与保持。不能由本轮条件性敏感性直接宣布学习可用。
保持 raw/base CSR/W_syn/sign、APL 设置、eligibility-v2、mask 和所有既有封存字节只读。没有游戏、视觉、decoder、RL 或 Web。
文献支持、工程假设和不适用边界见 [EVIDENCE.md](../../models/male-cns-lif/mb-credit-transfer-audit-v1/EVIDENCE.md)。正式结果见 [final-status](../../registry/phase4al-mb-credit-transfer/evidence/audit/final-status.json)。上一轮 D18 表征结果仍见 [Phase 4AK](phase4ak-interpretation.md)。
+54
View File
@@ -0,0 +1,54 @@
# Phase 4AM — D18 全脑塑性权重接口
日期:2026-09-30。正式状态:`PASS-EXACT-WHOLEBRAIN-PLASTIC-INTERFACE-NOT-LEARNING`。
本轮通过的是固定权重接口、闭环运行与记录的一致性验证,不是学习或行为验证。实际运行和正式封存已完成;服务器发布了 3,020 份小证据,本地已按发布收据逐项验收 3,040 个文件(含控制与清单文件)。Git 发布范围仅为源码、文档及小证据。
## 已完成的固定门
- zero:120 个固定主输入及 24 次技术重复,共 144/144 与封存 Phase 4AK D18 精确一致;覆盖状态、事件、计数、延迟队列、请求接受及 APL generated/applied/pending 记录。
- static25:同一完整库存共 144 次闭环运行完成,24 次技术重复精确一致。每条轨迹的上游、反馈和目标发放都重新计算,没有沿用 AL 的钳制源事件。
- 五组旧 deterministic-v2 参考重新运行全部精确;28 个旧完整性根运行前后全部通过。旧参考回归不表示新 D18 与旧动力学等价。
- zero / static25 阶段墙时分别为 1665.339973549002 / 1471.0373302119988 秒。主试验报告的最大已分配显存为 526,523,392 bytes;不是全机内存或全部进程峰值。
每阶段统计样本仍为 120 个主试验,24 次重复不增加独立样本数。两种输入模式和两个原定 cohort 均保留;`novel_to_aj` 仅指相对于 AJ 新增,不宣称历史从未见过。`matched_energy` 仍匹配预期随机输入,不保证每次实际事件数相同。
## 静态干预的实际含义
候选 mask 保持 14,232 条边,目标为 12 个 MBON;报告同时覆盖全部 97 个 MBON。原 raw/base CSR、sign、W_syn、APL 参数、eligibility-v2 与 mask 均未改变。
static25 使用原 float32 候选 base 的 `-.25 * base_candidate_mv` floor,安装时仅对非零 delta 行按独立运算加入 `float64(delta32) * .001` SI 增量。它不是 float64 D18 基础权重的精确 25%,不是训练所得 delta,也不是最大功能效应上界。每个试验开始前固定 delta,试验内不更新权重。
以下比较均为 static25 相对于 zero,在全部 120 个主试验上的描述性结果:
| 群体 | 事件序列改变的试验 | 至少一个细胞计数改变的试验 |
|---|---:|---:|
| 全部 MBON | 120/120 | 120/120 |
| 实际 MBON downstream | 120/120 | 120/120 |
| descending | 120/120 | 120/120 |
| motor | 120/120 | 120/120 |
| 12 个 mask-recipient MBON | 120/120 | 119/120 |
| KC | 120/120 | 32/120 |
这些数值不是“每个细胞都改变”,也不必表示群体总 spike count 改变。它们说明固定候选边干预能在本模型的真实全脑反馈中影响发放;不能推出气味特异关联记忆、正确行为方向、感知或运动能力。AL 的非零条件回放使用不同精度干预并钳制反馈,因此不能充当本轮非零结果的严格算术 oracle。
## 未跨越的边界
D18 的 1.8 ms APL 延迟仍是工程时序假设,不是实测生理延迟。既有 1,212 条非 KC fast-APL 出边置零、而未由 graded 路径替代的限制未修正。早期 Brian 闭环对照共享 APL 组件,不是所有组件独立实现的 CPU 等价证明。本轮没有重新标定这些假设。
没有训练、没有 learned candidate、没有学习 PASS;不接游戏、视觉、decoder、RL 或 Web。条件化仍需单独预注册实际 cue/US、冻结 eligibility-v2、独立评估种子、未配对等控制及真实时间保持,不能把静态响应当作已获得记忆。
下一项 AN 目前仅有 **UNREGISTERED** 工程计划:32 calls、11,074 ticks,用于精简报告运行与 checkpoint 续跑的精确对照;实际脑运行数为 0。学习草案也未登记,没有由本轮结果自动解锁训练或产生候选。
## 证据与交付
[正式状态](../../registry/phase4am-wholebrain-plastic-interface/evidence/audit/final-status.json) · [科学汇总](../../registry/phase4am-wholebrain-plastic-interface/evidence/audit/scientific-summary.json) · [固定协议](../../models/male-cns-lif/wholebrain-plastic-interface-v1/PROTOCOL.md) · [发布收据](../../registry/phase4am-wholebrain-plastic-interface/publication-receipt.json)
- 预注册 SHA-256:`465886b78ada08092c2c83de278844707499718977fb6dc6a7608391da0e5304`
- 科学汇总 SHA-256:`03f229fc0768d38bb7c2a3c558dbd68c2c3a622cbf96b1b16aef2819b6b67b77`
- 正式状态 SHA-256:`18b12c832e156bd6e5ba950f48a49fb908c62104b91bb3e78213f523c8fdc8f9`
- 模型 manifest SHA-256:`7edeb251ecbeac5a64805fefe171a0a0bf8bba2675919ef922cc1a329c203ea8`
- 实验 manifest SHA-256:`9e24b682935a9b18e05db7a933080c5f63ddbeb8a0c85cc0df1cfe1d06d88ab4`
- 发布收据 SHA-256:`7bb7c8edc1d1c09e9c5aa37c0fb367431ee9b8afe83dbcaff0f3cec5d22017f7`
大型轨迹保留在服务器。小证据发布不等于全量异机备份;Git 暂存载荷及提交载荷须另外使用发布收据 SHA 校验,不能由本地下载成功推断远端 Git 已同步。
+49
View File
@@ -0,0 +1,49 @@
# Phase 4AN — 有限轻记录与连续状态工程验证
日期:2026-09-30。正式状态:`PASS-EXACT-LIGHT-CONTINUATION-ENGINEERING-NOT-LEARNING`。
这是独立 D18 分支上的有限运行器验证,不是学习、记忆保持或生理模型通过。全部注册的 32 次 GPU 调用已执行,74 项比较通过;最终重新计算分析结果完全相同,AM 双封存与 28 套旧完整性记录运行后通过。AN 没有重新执行五组旧 reference,而是保留 AM 本轮已重新运行并通过的封存证据。
## 固定范围
166,700 neurons、25,582,938 edges,原图和 mask 不变。只使用 AM 原计划第一条 primary 的 100 ms 输入及其精确切片,分别保持 `zero`、`static25` 固定 overlay;没有新抽气味/seed、训练或试验内权重更新。
每个 overlay 包括完整 reference、两次完整 light、三个 reference 前缀,以及 reference/light 各一条段长 `[5,13,1,481,500]` 的连续链。共 11,074 ticks、1.1074 累计生物秒。完整执行流程墙时 433.968245 秒,包括首次编译、校验、进程启动、保存与续跑封存,不包括之后的分析和最终封存。
## 一致性与非空覆盖
两种 overlay 的完整新 reference 与各自 AM 输出精确一致。完整 light、技术重复和分段链的事件、计数、最终 V/g/ref、APL 末态、规范化 spike ring 和 APL pending 均符合注册比较。reference 另比较完整逐步状态哈希、APL history 和队列,并用原 CSR 独立重建队列顺序、接受掩码、局部时钟哈希和不应期状态。
两种 overlay 均有真实跨切点且非零权重、被接受的突触到达。例如 canonical edge 783780:source neuron_idx 522 在 tick 7 发放,target neuron_idx 82 在 tick 25 接收到达,跨过 tick 18 切点;原 SI effective weight 为 0.006875 V。该记录仅证明测试覆盖真实 carry,不证明唯一因果或生物学必要性。另核实同一预定切点存在 spike carry 与非零 APL pending。
light 不记录完整逐步 V/g/ref/APL/队列 history,未将缺失观测补为零或假称逐步浮点全量独立验证。该结论只适用于本次固定输入、固定 overlay 和预定切点,不是所有气味、任意长度或任意 parent 状态的普遍等价证明。
## 实测成本
| 100 ms 完整试验 | reference | light |
|---|---:|---:|
| 核心模拟墙时 | 5.456–5.509 s | 2.153–2.192 s |
| 每条封存输出 | 35.688–35.697 MB | 2.597–2.606 MB |
| 分配显存峰值 | 518,003,712 bytes | 518,003,712 bytes |
light 的运行加即时检查点封存约 5.827–5.854 s;这个数不含随后进程外核验。首次 reference 编译约 59.231 s,后续 build/cache 约 0.46 s。以上是小规模顺序试验,未测 GPU/CPU utilization,不能写成零。一次只读 CPU 比较与早期 light 运行有时间重叠,因此这不是隔离式或普适性能 benchmark,也未达到实时运行。
`state.npz` 与 terminal queue 的 ZIP entry 均实际检查为无损压缩。封存前输出预算计数为 221,057,911 bytes,低于注册的 8 GiB 上限;该数字不包含随后生成的最终 manifest/checksum 控制文件。
## 继续学习前的边界
仅本工程实验被封存;lab 整个目录未封存,实际使用的 21 份源码/测试/协议已按 SHA 锁定并保存快照。后续不得改写它们后沿用此结论。scientific conditioning 草案尚未登记、没有训练、没有 learned candidate。
当前草案已有 68,000 epochs:30,000×120 ms、30,000×180 ms 和 8,000×120 ms,总计 9,960 生物秒;另有 80 条 10 s 连续 idle,总计 10,760 生物秒。evaluation/probe inventory 尚未完整,所以这仍不是全量预算。仅按本次 100 ms 样本线性算术外推,核心模拟约 64.35–65.52 小时,运行及即时封存约 174.16–174.97 小时;气味活动、长度、缓存和 I/O 不同可能改变成本,不能当作可靠工期承诺。
下一步须先补齐 evaluation/reversal/retention 集成与有限预算,再登记小规模机制验证。小规模验证不能代替五个训练 seeds、独立 evaluation seeds、全部控制及完整科学门。不得调整参数挽救 PASS;没有自动解锁游戏、RL、decoder 或视觉。
## 锚点
- 注册:`7317441126f191ccc6e6d28438870b3921537ebe282a6acb163716a690057945`
- 分析:`d5ad47a85e4c22e8a482b26330957a821e394022658531a914c9080187454d03`
- 正式状态:`16630d0d666a2467c56b647d021cbdb627a553795f6afcd7f7eb496a2737d815`
- 实验 manifest:`e8952a48cd3ea6a93c811a1183a1f7b79e19646299924e7688e5f393737a9aa2`
- checksums:`7c22aee142affae52dd5792d655e5839db14380ae84993f99a50bdce53a4135c`
服务器目录:`experiments/phase4an-engineering-validation/`。原始大数组和轨迹仍保存在服务器;小证据/Git 交付不等于全量异机备份。
@@ -0,0 +1,65 @@
# Phase 4AO:两轮权重接口中止,后处理隔离诊断通过
更新:2026-09-30。独立分支 `codex/lif-author-semantics-lab`。
正式结果为 **FAIL-POSTPROCESS-MODULE-IDENTITY**。这是执行接口失败,不是
嗅觉学习或动力学假设的否定证据。完整 conditioning 没有启动,没有 learned candidate。
## 实际完成与未完成
预登记 12 条短调用:D1 / D0 / frozen × reference / light × 两个 120 ms fresh-reset epoch。
master 为 20260930,固定第一 PAM15 block;所选两个连续 epoch 均为 A 气味。
D0/frozen 仍共享同一 CS 和人工 DAN 请求,只改变边界更新命令。没有选择性重抽种子。
- 新增协调器的服务器 CPU 合成测试 61/61 通过,0 跳过。
- 实际 CUDA 抽样与固定原 L 的抽样表达式一致;完整 63 位种子的高位影响已检查。
- 两轮固定输入分别有 78/65 个 CS 请求,各有 4 个 US 请求。
- 第一条 reference 全脑轨迹完成:166,700 neurons、25,582,938 edges、1200 ticks、
36,539 spikes,所有有限值检查通过。82 个请求中 55 个接受、27 个因实际状态拒绝。
- 核心 reference 模拟 6.514 s;该次完整 runtime 66.935 s,其中编译/缓存准备 59.222 s。
最大已分配显存 518,003,712 bytes。不可把这条含首次编译结果称为优化基准。
- 轨迹已立即封存,但其后处理失败。因此是 **1 条神经轨迹完成、0/12 条完整流程完成**,
不是 1/12 整体门通过;其余神经调用没有运行。
## 原因和隔离诊断
普通 `runtime_light` 与 continuation 内部加载的另一个同源实例各有私有模块缓存,
却共享同一全局 helper 名。第二实例正确拒绝了未由其缓存认证的现有模块。
没有绕过该安全检查、修改冻结 loader 或重跑已完成轨迹。
原 61 个测试没有覆盖“两个真实 loader 同进程组合”这一边界;修复诊断新增实际 loader
进程隔离测试,能复现冲突,并验证干净进程加载成功、伪模块和错误 SHA 仍被拒绝。
在独立 CPU 进程、独立目录 `experiments/phase4ao-postprocess-isolation/` 中,原 E
后处理使用完全相同的 sealed 轨迹成功。实际 KC events 为 137;从完整 14,232-edge
mask 中,有 90 条属于目标 compartment 的边产生非零 delta,跨 compartment 改动为 0。
这些 delta **未安装到脑、未用于下一轮、不是学习成功证据**。原 AO 状态保持 FAIL。
后处理隔离与发布工具的服务器合成测试最终共 19/19 通过;发布测试另修正了仅适配本地
目录的 fixture 路径错误,未修改生产模型或已登记源码。
## 冻结完整性
AN 与 AM 的完整封存重新校验通过;继承的 28 套旧完整性检查通过。
原 21 个 AN 源、前一批 20 个科学准备源和本次登记的全部 51 源文件均未修改。
五组旧参考使用已封存 AM 证据,本次没有重新执行,不混称为重新回归。
## 下一步
为独立进程后处理建立新的有限预登记;保留这次中止与诊断结果,不续写或重启已封存 AO,
不因结果调整 seed、输入、eta、阈值或脑参数。先验证跨 epoch 的 delta 实际安装和所有
reference/light/零更新对照,再处理新权重与连续 retention 状态的交接。之后才有条件
登记至少五个训练种子、独立评估种子及完整功能控制。游戏、RL、decoder、视觉和 Web
仍不在范围内。
## 来源与保存范围
代码版本:`4ff241bdc96319823f5fc83f80312468f5208a5c`。
注册 SHA:`9e2ed05879ce279da7dc0b4cac09a44d67665c230b56db94e2ca39c645bdc250`。
实验 manifest SHA:`dcfb24338a39ce0bb4d0bf5fe3c92a1907fb63536b4c57856c2f40203996f979`。
正式状态 SHA:`f8fff2cb7d4eb0abfc9653c989781c0310b6ad7ec42cce4949bae1a15fd793d8`。
隔离诊断 manifest SHA:`202efff603a05016b3f530df9eb1d3c52e1c4119dbc4372ad7b75c6ca69013a2`。
AO 小证据 registry 已发布 110 份来源文件,连同控制与索引共 117 个文件,本地逐项
SHA-256 验收通过;隔离诊断的完整 10 个小文件也已本地验收。Git 同步源码、文档、
AO 小证据与诊断 JSON,原始大型轨迹和完整约 83.8 MB 紧凑语义计划仍以服务器保存为准,
不得把 Git 小证据同步称为全量异机备份。
@@ -0,0 +1,43 @@
{
"CUDA_VISIBLE_DEVICES": "",
"after_overlay_sha256": "b89e407a5d93b5f1901f901b00428dc19bd20cee2d81e57b117a2fa68d200a48",
"authority_sha256": "9c86c505d6156ca4ba0496105a7fde0556c0a05bfbd68dec6e7ec7c1865cdb60",
"before_overlay_sha256": "0b219eab09c30dc3af31fef7e6395a9bec1234090abbb72db096da833fed82c5",
"candidate_generated": false,
"checkpoint_manifest_sha256": "e2ad8068bcc8450840ff4c5fb5fbe6a39a1960cd5869b5e16096fb579df28a3a",
"counts": {
"actual_KC_events": 137,
"actual_bitwise_changed_edges": 90,
"actual_off_compartment_bitwise_changed_edges": 0,
"actual_value_changed_edges": 90,
"candidates": 14232,
"events": 36539,
"original_apply_v2_executed": true,
"original_updated_edges_attempted": 90,
"sampled_eligible_selected_already_at_floor": 0,
"sampled_eligible_selected_edges": 90,
"selected_at_floor_after": 0,
"selected_at_floor_before": 0,
"selected_compartment_edges": 2109,
"selected_newly_at_floor": 0
},
"diagnostic_script_sha256": "b1070733f70adee166bb7ae0da31f60c75dcaeaf31436ba1dc7d575b91ac5d81",
"interpretation": "The same pinned E succeeds in a fresh CPU process without the competing ordinary runtime loader cache. This is post-hoc diagnosis, not completion of AO.",
"learning_success_claimed": false,
"new_brain_runs": 0,
"old_trajectory_rerun": false,
"original_12_call_gate_passed": false,
"original_protocol_remains_stopped": true,
"postprocess_source_sha256": "757935a4815d9f625640df685184ed3fe44a8845323562796da7aa43cbb194e1",
"registration_sha256": "9e2ed05879ce279da7dc0b4cac09a44d67665c230b56db94e2ca39c645bdc250",
"result_files_sha256": {
"/data/digital-drosophila/experiments/phase4ao-postprocess-isolation/postprocess/chain-receipt.json": "874e932264f1f6a84b0724f97e9c2833c16a9da744e6c9171c8a7587ce1cef58",
"/data/digital-drosophila/experiments/phase4ao-postprocess-isolation/postprocess/delta-after.npz": "b89e407a5d93b5f1901f901b00428dc19bd20cee2d81e57b117a2fa68d200a48",
"/data/digital-drosophila/experiments/phase4ao-postprocess-isolation/postprocess/overlay-manifest.json": "38dabc55ea0569843ee70f13cf570832ecaa8f1ee7f26a7420e7ebc3ea86f6bd",
"/data/digital-drosophila/experiments/phase4ao-postprocess-isolation/postprocess/update-receipt.json": "d0a660b4e87a786275852c1d759e2750f42d18b354780a2e4a1036b3b3be5056"
},
"status": "PASS-ISOLATED-POSTPROCESS-DIAGNOSTIC-ONLY",
"stopped_sha256": "45b096d034cc171039b95de69a97538eaf61a9bf4068a47e4e0a2cb16d0a9736",
"wall_seconds": 4.321050373000617,
"weights_installed": false
}
@@ -0,0 +1,45 @@
{
"files": [
{
"bytes": 4209,
"path": "diagnose_postprocess_isolation.py",
"sha256": "b1070733f70adee166bb7ae0da31f60c75dcaeaf31436ba1dc7d575b91ac5d81"
},
{
"bytes": 2578,
"path": "diagnostic-receipt.json",
"sha256": "cefe84ac1642285b2c815a1f2a03677be064dd38125024f638eda4892cf477b3"
},
{
"bytes": 8118,
"path": "finalize_failed_phase4ao.py",
"sha256": "a68f25ac6dc9e7b1aff1f8999aad9ee7531576696dd16b6ceb8e847b66dcb6d1"
},
{
"bytes": 44415,
"path": "postprocess/chain-receipt.json",
"sha256": "874e932264f1f6a84b0724f97e9c2833c16a9da744e6c9171c8a7587ce1cef58"
},
{
"bytes": 32303,
"path": "postprocess/delta-after.npz",
"sha256": "b89e407a5d93b5f1901f901b00428dc19bd20cee2d81e57b117a2fa68d200a48"
},
{
"bytes": 1085,
"path": "postprocess/overlay-manifest.json",
"sha256": "38dabc55ea0569843ee70f13cf570832ecaa8f1ee7f26a7420e7ebc3ea86f6bd"
},
{
"bytes": 7637,
"path": "postprocess/update-receipt.json",
"sha256": "d0a660b4e87a786275852c1d759e2750f42d18b354780a2e4a1036b3b3be5056"
},
{
"bytes": 2728,
"path": "test_postprocess_isolation.py",
"sha256": "93e1552bf26b7da0799812d2b38e5ce99c8a3b5811fe97527f99d2ef19a4071d"
}
],
"root": "/data/digital-drosophila/experiments/phase4ao-postprocess-isolation"
}
@@ -0,0 +1,87 @@
# Phase 4AP:进程隔离与两轮 delta 安装精确通过
更新:2026-09-30。独立分支 `codex/lif-author-semantics-lab`。
正式封存状态:**PASS-EXACT-PROCESS-ISOLATED-DELTA-INTERFACE-NOT-LEARNING**。
这是训练执行接口通过,不是嗅觉记忆、行为学习或 learned candidate。
## 完成范围
12/12 个登记槽位完成:1 条明确导入的 AO 已封存神经轨迹,加 11 次新神经运行。
第一条仅在新的 CPU 子进程重算后处理,没有重跑大脑;原 AO 继续保持
`FAIL-POSTPROCESS-MODULE-IDENTITY`,没有被恢复、覆盖或改判。
两组已封存输入逐字节复用,新增抽样次数为 0。覆盖 D1/D0/frozen × reference/light
× 两个 120 ms fresh-reset epoch;两个 epoch 均为固定 A 气味、同一 PAM15 compartment。
新神经运行合计 1.32 生物秒,连同导入轨迹覆盖 1.44 生物秒。
epoch 间只继承本 arm/mode 的 delta,不继承神经末态。
- 40/40 服务器 CPU/实际 loader 子进程契约测试通过;发布工具另 14/14 通过。
- 6/6 reference/light 比较通过:实际事件序列、计数、可观测末态、终端延迟队列和 delta 精确一致。
- 6/6 已登记跨 arm 对照通过;D0/frozen 的所有 delta 保持精确正零。
- 第一轮 D1 有 90 条、第二轮有 79 条边实际更新;每轮跨 compartment 改动均为 0。
- 第二轮 reference 和 light 均实际安装本模式第一轮的 90 条非零 delta。
- 有效权重 SHA 从冻结 base、fast-APL mask 和实际 delta 独立计算,不采用报告自证。
- 所有运行有限值检查通过;未出现 NaN/Inf。各轮 4 个 DAN 请求均接受,实际对应 DAN 放电 4 次。
第一轮 36,539 spikes / 7,409 active neurons;第二轮 33,390 spikes / 7,080 active neurons。
三个 arm 在这两轮的总 spike/active 数相同;不能把非零 delta 或下一轮安装成功解释为
气味特异学习。没有 A/B 评估、acquisition、反转、延迟奖励或 retention 结果。
## 实现和边界
新 brain 与 update 均为真正新启动的 Python 进程。CPU update 在导入科学模块前隐藏
CUDA,且只加载原 E 入口;不清除模块缓存,不绕过冻结 loader 的身份验证。
worker 的输入、输出全量 SHA 清单、实际退出码、日志、checkpoint、authority 和父 delta
共同绑定。错误、超时或部分产物均禁止自动重试。原 51 份冻结源没有改动。
人工 scheduled D 仍是 unconditioned-signal 接口,不是实测 dopamine 浓度,也没有用
实际 DAN 请求接受与否乘改更新命令。原 eligibility-v2、14,232-edge mask、全脑图、
sign、LIF、W_syn 和既有 APL 参数均未修改。原 fast-APL 非 KC 出边限制仍存在。
light 未记录的逐 timestep 中间 V/g/ref 不声称已逐位观察。
## 性能和成本口径
同一 120 ms 输入,light 核心模拟约 2.44–2.58 s;含 runtime 内准备约 4.04–4.14 s。
六个 light 槽位记录的流程时间约 18.51–18.82 s,包括独立 brain/update 子进程和当轮
验收,但不包含槽位计时开始前的父链检查以及整个最终审计,不能当作完整训练预算。
新 reference 首次运行含约一分钟编译,亦不可当作稳态模拟耗时。
全部槽位流程约 344.82 s(依据启动 UTC 与完成文件时间戳估计,非核心计时器;不包含
prepare 和最终完整性审计)。最大已分配显存 518,003,712 bytes,约 494 MiB。
只使用登记的单张 RTX 4090,未停止或驱逐三个 ComfyUI 服务。
后续必须从父进程启动前计到子进程退出和验收后,计入哈希、图加载、CUDA 启动、CPU
更新与压缩。worker 自身计时开始于输入验证之后,不可漏算前置成本。当前数字不能直接
外推全部训练,也不是实时性能 PASS。
## 完整性与保存
AO、独立隔离诊断、AN、AM 封存以及 28 套继承的旧完整性检查,前后均通过。
五组旧 reference 使用 AM 已封存证据;本次没有重新执行这五组,不混称为新回归。
AP 实验封存 472 份 payload、237,871,144 bytes(另有 manifest/checksums)。
发布 348 份小型来源证据;registry 共 356 文件、9,402,548 bytes,本地逐项 SHA 验收通过。
大型神经轨迹、二进制状态和编译缓存留在服务器;Git 小证据同步不是全量异机备份。
源码 commit:`0bcce983324ecfe1c75826a23e94ff932ad5e883`。
注册 SHA:`02a03b536a9f14196ad4b92fa9565b592732c6c863e72eeaee89b3b0ea8ed37d`。
实验 manifest SHA:`a40e433541a6c02f7ad95622e96646da9a90a93e4e43cb3abfde3846b2554f00`。
正式状态 SHA:`26de8371867d55253358a4be698de896445712e49e6eee8d99ce852fd0bf43ab`。
## 下一步:集中准备真实学习验证
不继续反复扩展两轮接口试验。将剩余准备收拢为一个有界登记包:
1. 新增独立的“真实末态 + 唯一已验证 delta-after”衔接器,旧 continuation 不改。
保留电压、电流、不应期、spike/APL 队列和绝对时钟;base + delta 只安装一次。
零更新与旧续跑精确一致;非零边界用连续 reference 与恢复/light 路径比较,并确认
实际非空 pending arrival 覆盖变化候选边。没有覆盖就报告 NOT-COVERED。
2. 在观察学习结果前完成 reversal/retention 判定,并把磁盘回执、训练/评估种子、
完整控制臂和 population 权威接入已有 acquisition 判定函数。
3. 用有限实测给完整科学计划登记 walltime/输出容量/资源停机界限,再进入正常 acquisition。
正常阶段库存为 30,000 epochs + 3,920 probes;这不是本次已执行工作。
禁止用核心模拟时间替代端到端成本,不新增付费资源或无上限运行。
目标仍是“学习可以使用”,尚未达到。不因这次接口 PASS 宣称成功,不调参或换 seed
挽救结果,不接游戏、视觉、decoder、RL、Web 或 3D。
@@ -0,0 +1,72 @@
# Phase 4AJ: a single graded-APL timing hypothesis
Independent branch authorized by the human. All earlier models and data remain
read-only. The learning goal remains unmet; neither an audit nor fixed-CAL PASS
constitutes usable learning.
## Fixed intervention
Use the exact sealed AG author-style float64 LIF and float32 legacy graded APL.
Compare h applied at its generating tick with the identical generated operator
applied 18 steps later. No other change: dt=0.1 ms, anatomical delay=18 steps,
refractory=22 steps, tau_m=20 ms, tau_syn=5 ms, W_syn=0.275 mV, original signs,
threshold/rest/reset, all canonical IDs/edges, legacy APL tau=20 ms and gain=0.01.
The unchanged fast-APL zero mask includes 1,212 non-KC edges not replaced by the
graded operator. The branch does not silently fix this limitation.
This is engineering scheduling parity, not evidence of a measured 1.8 ms graded
APL delay. Whole h is delayed, including KC feedback; it is not a PN-only
intervention. APL still subtracts unconditionally at end-of-step, including
refractory KC, whereas ordinary synaptic arrivals are guarded by refractory.
Equal arrival time is not equivalent biological action.
## Stages and gates
1. Exact conditional reconstruction of all 420 metadata-defined ALLN in all
60 sealed CAL r0 records. Audit every simultaneous earliest non-design PN,
before first KC, and duration-matched never-active PN controls. PN→ALLN→PN
witnesses must be actual accepted timed edges; distinguish signed weights,
reset windows and zeroed edges. No shortest paths, unique-cause or necessity
claims. Unknown antecedents are retained and do not falsify numerical audit.
2. Fixed stored h trace shift audit: no loss, duplication, amplitude arithmetic
or brain simulation. Initial +0 padding and chronological unconsumed tail
explicitly retained. No extra brain/APL tail advance or future-decay claim.
3. Both arms: eight fixed real-edge fixtures, three fresh GPU repeats, independent
Brian LIF/own spikes/own FIFO, legacy APL component audit. Delay0 must reproduce
sealed AG scientific outputs bitwise.
4. Both arms: the same two fullgraph first-seed CAL probes, independent Brian
comparison and APL component audit. Numerical failure stops later execution.
5. Both arms: every original six-odor × two-mode × five-seed CAL, plus first-seed
repeat for each odor/mode. Exact source input files, not regenerated random
inputs. All results retained. Known baseline representation failure does not
skip treatment; no seed selection, threshold/gain search or gate relaxation.
6. Recompute comparisons from raw evidence, old checksums and five frozen
reference regressions. Seal truthful outcome with SHA-256 and source version.
## Interpretation limits
Generated h depends on changed closed-loop spikes, so branch inhibition integrals
need not match. Fixed-trace conservation is a transport check, not proof of
equal closed-loop dose. Accepted request counts can also change with refractory
state, despite byte-identical requested input schedules.
Brian state integration is independent but APL arithmetic is intentionally a
shared frozen component. Original operator AST replay and rounding audit remain
separate; no universal CPU/GPU equivalence is claimed from sampled fixtures.
CAL gate retains original 3–9% mean KC fraction, all-run limits, within/between
Jaccard and Euclidean gates, and minimum odor-pair count in both input modes.
Passing fixed CAL is not heldout generalization or associative memory. Further
progress requires independent seeds/novel odors, credit specificity, isolated and
whole-brain functional readouts, then conditioning with proper controls.
No training, eta/threshold/sign tuning, plastic mask expansion, heldout dynamic
access, visual input, decoder, RL, game, Web or new candidate in this experiment.
## Literature scope
Shiu et al. 2024, DOI 10.1038/s41586-024-07763-9, supplies the spiking-LIF
scheduling reference, not a measured MaleCNS graded-APL delay. Amin et al. 2020,
DOI 10.7554/eLife.56954, and Prisco et al. 2021 (PMC8741211) motivate local graded
APL/calyx interaction but do not determine this millisecond delay value. Prior
sealed source/literature audits retain versions and provenance.
@@ -0,0 +1,513 @@
"""Conditional audit of the earliest non-design ALPN cohort in 60 sealed CALs.
CPU only. No new network trajectory, learning, parameter change, heldout input,
or shortest-path attribution. Full ALLN inputs and compact outgoing witnesses
are retained separately so a potentially large temporal join is not expanded.
"""
from __future__ import annotations
from collections import defaultdict
from pathlib import Path
import traceback
import numpy as np
import pandas as pd
N = 166700
E = 25582938
DELAY = 18
BUDGET = 2 * 1024**3
MODES = ('physiological', 'matched_energy')
SEEDS = tuple(range(51101, 51106))
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 a.tobytes() == b.tobytes()
def first_ticks(ticks, nodes, targets, n=N):
first = np.full(n, np.iinfo(np.int32).max, np.int32)
np.minimum.at(first, nodes, ticks)
first[first == np.iinfo(np.int32).max] = -1
return first[targets]
def select_cohort(pn, first_pn, design, first_kc, steps):
"""Static-design complement, ALL ties, never choose by antecedent outcome."""
require(pn.dtype == np.int32 and first_pn.dtype == np.int32 and pn.shape == first_pn.shape,
'PN identity/first-tick schema mismatch')
require(np.all(np.diff(pn) > 0) and np.isin(design, pn).all(), 'Invalid PN/design IDs')
require(np.all((first_pn >= -1) & (first_pn < steps)), 'PN first tick outside trial')
require(first_kc == -1 or 0 <= first_kc < steps, 'KC first tick outside trial')
non_design = ~np.isin(pn, design)
observed = first_pn[non_design & (first_pn >= 0)]
earliest = int(observed.min()) if len(observed) else -1
cohort = pn[non_design & (first_pn == earliest)] if earliest >= 0 else np.empty(0, np.int32)
cutoff = int(first_kc) if first_kc >= 0 else int(steps)
return dict(cohort=cohort, earliest_tick=earliest, pre_kc_stop_exclusive=cutoff,
pre_kc_window_censored=first_kc < 0,
matched_stop_exclusive=min(cutoff, earliest) if earliest >= 0 else cutoff,
cohort_before_first_KC=bool(earliest >= 0 and first_kc >= 0 and earliest < first_kc),
cohort_relation_to_first_KC=('no_non_design_spike' if earliest < 0 else
'KC_unobserved' if first_kc < 0 else 'before' if earliest < first_kc else
'same_tick' if earliest == first_kc else 'after'))
def predecessor_counts(incoming_ticks, incoming_weights, source_tick, previous_source_tick):
"""Strict temporal antecedents. Old-reset history is reported separately."""
ticks, weights = np.asarray(incoming_ticks), np.asarray(incoming_weights)
require(ticks.ndim == weights.ndim == 1 and ticks.shape == weights.shape,
'Predecessor arrays differ')
require(np.isfinite(weights).all() and np.all(np.diff(ticks) >= 0), 'Bad predecessor sequence')
require(-1 <= previous_source_tick < source_tick, 'Bad previous/source spike order')
prior = ticks < source_tick
surviving = prior & (ticks > previous_source_tick)
return dict(all_prior_design_PN_events=int(prior.sum()),
since_last_reset_design_PN_events=int(surviving.sum()),
since_last_reset_nonzero_design_PN_events=int(np.count_nonzero(surviving & (weights != 0))),
since_last_reset_positive_events=int(np.count_nonzero(surviving & (weights > 0))),
since_last_reset_negative_events=int(np.count_nonzero(surviving & (weights < 0))),
since_last_reset_zero_events=int(np.count_nonzero(surviving & (weights == 0))),
since_last_reset_positive_weight_SI=float(np.maximum(weights[surviving], 0).sum(dtype=np.longdouble)),
since_last_reset_negative_abs_weight_SI=float(np.maximum(-weights[surviving], 0).sum(dtype=np.longdouble)),
prior_reset_excluded_events=int(np.count_nonzero(prior & ~surviving)))
def source_labels(global_ids, role, design_mask):
result = role[global_ids].astype(object).copy()
alpn = result == 'ALPN'
result[alpn & design_mask[global_ids]] = 'design_ALPN'
result[alpn & ~design_mask[global_ids]] = 'non_design_ALPN'
return result
def file_budget(root):
size = sum(p.stat().st_size for p in root.rglob('*') if p.is_file())
require(size <= BUDGET, 'Origin audit exceeds 2 GiB; no truncation/resampling allowed')
return size
class Sink:
def __init__(self, path, schema, budget_root):
import pyarrow.parquet as pq
require(not path.exists(), 'Output exists: ' + str(path))
self.writer = pq.ParquetWriter(path, schema, compression='zstd')
self.schema, self.rows, self.root = schema, 0, budget_root
def write(self, columns):
import pyarrow as pa
table = pa.Table.from_pydict(columns, schema=self.schema)
if table.num_rows:
self.writer.write_table(table)
self.rows += table.num_rows
file_budget(self.root)
def close(self):
self.writer.close()
file_budget(self.root)
def event_schema():
import pyarrow as pa
return pa.schema([
('edge_id', pa.int64()), ('source_neuron_idx', pa.int32()), ('target_neuron_idx', pa.int32()),
('source_body_id', pa.uint64()), ('target_body_id', pa.uint64()),
('source_spike_tick', pa.int32()), ('arrival_tick', pa.int32()),
('source_event_key', pa.int64()), ('weight_SI', pa.float64()), ('weight_sign', pa.int32()),
('source_group', pa.string()), ('accepted', pa.bool_()), ('ref_at_arrival', pa.int32()),
('target_previous_spike_tick', pa.int32()), ('before_first_any_KC', pa.bool_())])
class ALLNObserver:
"""Save every accepted incoming event, including frozen-zero edges."""
def __init__(self, targets, incoming, role, design_mask, body, steps, cutoff, sink):
self.targets, self.incoming = targets, incoming
self.role, self.design, self.body = role, design_mask, body
self.steps, self.cutoff, self.sink = steps, cutoff, sink
self.last = np.full(len(targets), -1, np.int32)
self.callbacks = self.due = self.accepted = self.rejected = 0
self.groups = defaultdict(lambda: dict(due=0, accepted=0, rejected=0, positive=0, negative=0, zero=0))
self.design_ticks = defaultdict(list)
self.design_weights = defaultdict(list)
def __call__(self, tick, stage):
require(tick == self.callbacks and tick < self.steps, 'ALLN callback coverage mismatch')
require(np.all(stage['h32'] == 0) and np.all(stage['delta_si'] == 0), 'ALLN received graded APL')
require(not np.any(stage['request']), 'CAL request targeted ALLN rather than PN')
require(bit_equal(stage['g'], stage['g_pre_apl']), 'Unexpected ALLN post-APL change')
due, accepted = stage['due_edge_indices'], stage['arrival_accepted']
require(np.array_equal(accepted, stage['ref_after_reset'][self.incoming.dst_local[due]] == 0),
'ALLN arrival acceptance differs from post-reset ref guard')
require(tick >= DELAY or not len(due), 'Premature ALLN event')
self.last[stage['fired']] = tick
labels = source_labels(self.incoming.src_global[due], self.role, self.design)
weight = self.incoming.weights[due]
for label in np.unique(labels):
mask = labels == label
item = self.groups[str(label)]
item['due'] += int(mask.sum())
item['accepted'] += int(np.count_nonzero(mask & accepted))
item['rejected'] += int(np.count_nonzero(mask & ~accepted))
for name, select in (('positive', weight > 0), ('negative', weight < 0), ('zero', weight == 0)):
item[name] += int(np.count_nonzero(mask & accepted & select))
selected = due[accepted]
src = self.incoming.src_global[selected]
local = self.incoming.dst_local[selected]
dst = self.targets[local]
w = self.incoming.weights[selected]
selected_labels = labels[accepted]
count = len(selected)
self.sink.write(dict(edge_id=self.incoming.edge_id[selected], source_neuron_idx=src,
target_neuron_idx=dst, source_body_id=self.body[src], target_body_id=self.body[dst],
source_spike_tick=np.full(count, tick - DELAY, np.int32),
arrival_tick=np.full(count, tick, np.int32),
source_event_key=np.int64(tick - DELAY) * N + src.astype(np.int64),
weight_SI=w, weight_sign=np.sign(w).astype(np.int32), source_group=selected_labels,
accepted=np.ones(count, bool), ref_at_arrival=stage['ref_after_reset'][local],
target_previous_spike_tick=self.last[local], before_first_any_KC=np.full(count, tick < self.cutoff, bool)))
# At most all accepted design-PN events are retained in RAM. Full event
# rows are already streamed; this compact index never expands path pairs.
for target in np.unique(dst[selected_labels == 'design_ALPN']):
mask = (dst == target) & (selected_labels == 'design_ALPN')
self.design_ticks[int(target)].extend([tick] * int(mask.sum()))
self.design_weights[int(target)].extend(w[mask].tolist())
self.callbacks += 1
self.due += len(due)
self.accepted += count
self.rejected += int(np.count_nonzero(~accepted))
def report(self):
require(self.callbacks == self.steps and self.due == self.accepted + self.rejected,
'Incomplete ALLN replay observer')
require(self.accepted == self.sink.rows, 'ALLN event sink row mismatch')
return dict(callbacks=self.callbacks, ALLN_targets=len(self.targets), due_events=self.due,
accepted_events=self.accepted, rejected_events=self.rejected,
source_groups=dict(self.groups), graded_APL_h_zero=True,
accepted_zero_weight_rows_preserved=True)
def _window_add(stats, frame, mask, labels):
for label in np.unique(labels[mask]):
chosen = mask & (labels == label)
weights = frame.weight_SI.to_numpy()[chosen]
item = stats.setdefault(str(label), dict(events=0, positive_events=0, negative_events=0,
positive_weight_SI=0.0, negative_abs_weight_SI=0.0))
item['events'] += len(weights)
item['positive_events'] += int(np.count_nonzero(weights > 0))
item['negative_events'] += int(np.count_nonzero(weights < 0))
item['positive_weight_SI'] += float(np.maximum(weights, 0).sum(dtype=np.longdouble))
item['negative_abs_weight_SI'] += float(np.maximum(-weights, 0).sum(dtype=np.longdouble))
def _read_npz(path):
with np.load(path, allow_pickle=False) as file:
return {key: file[key].copy() for key in file.files}
def main():
# Lazy import makes all selection/join helpers testable without a server.
import pyarrow as pa
import pyarrow.parquet as pq
from context import (ROOT, EXP, AG, AG_MODEL, AI, AI_MODEL, AH_MODEL, COEFF,
load_module, read, save, digest, check)
check()
require(read(AI / 'audit/final-status.json')['status'] == 'PASS-CONDITIONAL-PN-APL-SOURCE-AUDIT',
'AI is not successfully sealed')
require(read(AI / 'audit/final-status.json')['pass_all'] is True, 'AI seal failed')
outroot = EXP / 'origin-audit'
outroot.mkdir(parents=True, exist_ok=False)
receipts = []
try:
sealed_roots = (AI, AI_MODEL, AG, AG_MODEL, AH_MODEL)
sealed_inventory = {root: {r['path']: r for r in read(root / 'manifest.json')['files']}
for root in sealed_roots}
verified_hashes = {}
def input_hash(path):
path = Path(path)
if path in verified_hashes:
return verified_hashes[path]
actual = digest(path)
for root in sealed_roots:
if path.is_relative_to(root) and path.name not in ('manifest.json', 'checksums.sha256'):
key = path.relative_to(root).as_posix()
require(key in sealed_inventory[root], 'Input absent from frozen seal: ' + str(path))
frozen = sealed_inventory[root][key]
require(actual == frozen['sha256'] and path.stat().st_size == frozen['bytes'],
'Input differs from sealed digest/bytes: ' + str(path))
break
verified_hashes[path] = actual
return actual
# Verify entry-point metadata and code before importing the frozen code.
for path in (AI / 'protocol/inventory.json', AI / 'protocol/neuron-source-groups.parquet',
AG / 'protocol/calibration-cases.json', AH_MODEL / 'replay_core.py',
AI_MODEL / 'validate_events.py', AG_MODEL / 'calibration.py'):
input_hash(path)
inventory = [row for row in read(AI / 'protocol/inventory.json')
if row['kind'] == 'calibration' and row['repeat'] == 0]
require(len(inventory) == 60 and len({r['case'] for r in inventory}) == 60,
'Expected exactly the fixed 60 distinct CAL r0 inputs')
reference_cases = read(AG / 'protocol/calibration-cases.json')
require({r['case'] for r in inventory} == {r['name'] for r in reference_cases},
'AI CAL inventory differs from AG CAL inventory')
specifications = {r['case']: read(AG / 'cases' / r['case'] / 'spec.json') for r in inventory}
cells = {(s['mode'], s['odor_id'], s['seed']) for s in specifications.values()}
odors = sorted({s['odor_id'] for s in specifications.values()})
require(len(odors) == 6 and cells == {(m, o, seed) for m in MODES for o in odors for seed in SEEDS},
'CAL identity grid incomplete or includes repeats/heldout')
meta_path = AI / 'protocol/neuron-source-groups.parquet'
meta = pd.read_parquet(meta_path)
require(len(meta) == N and np.array_equal(meta.neuron_idx.to_numpy(), np.arange(N)),
'Metadata global identity mismatch')
require(meta.audit_source_group.notna().all() and meta.body_id.dtype == np.uint64,
'Invalid frozen role/body metadata')
role, body = meta.audit_source_group.to_numpy(), meta.body_id.to_numpy()
alln = np.flatnonzero(role == 'ALLN').astype(np.int32)
pn = np.load(AG / 'apl-bundle/pn_globals.npy')
kc = np.load(AG / 'apl-bundle/kc_globals.npy')
apl = np.load(AG / 'apl-bundle/apl_globals.npy')
require(len(alln) == 420 and len(pn) == 686 and len(kc) == 4064 and len(apl) == 2,
'Frozen role population sizes differ')
require(np.array_equal(pn, np.flatnonzero(role == 'ALPN').astype(np.int32)), 'ALPN role IDs differ')
require((meta.iloc[alln].annotation_class == 'ALLN').all(), 'ALLN role is not exact annotation class')
graph = AG / 'graphs/full'
arrays = {k: np.load(graph / (k + '.npy'), mmap_mode='r')
for k in ('nodes', 'src', 'dst', 'edge_id', 'weights')}
require(bit_equal(arrays['nodes'], np.arange(N, dtype=np.int32)), 'Full graph global node order differs')
require(len(arrays['edge_id']) == E, 'Full graph edge count differs')
for start in range(0, E, 1000000):
stop = min(E, start + 1000000)
require(np.array_equal(arrays['edge_id'][start:stop], np.arange(start, stop, dtype=np.int64)),
'Full graph edge IDs not canonical identity')
core = load_module('frozen_ah_alln_replay_aj', AH_MODEL / 'replay_core.py')
validate = load_module('sealed_ai_event_validation_aj', AI_MODEL / 'validate_events.py')
cal = load_module('sealed_ag_state_validation_aj', AG_MODEL / 'calibration.py')
lookup = np.full(N, -1, np.int32)
lookup[alln] = np.arange(len(alln), dtype=np.int32)
selected = np.flatnonzero(lookup[arrays['dst']] >= 0)
src = arrays['src'][selected]
weights = arrays['weights'][selected].copy()
weights[np.isin(src, apl)] = 0.0
incoming = core.IncomingIndex(src, lookup[arrays['dst'][selected]], arrays['edge_id'][selected], weights, len(alln))
# Only incoming PN graph views are required to independently validate AI rows.
pnedges = np.flatnonzero(np.isin(arrays['dst'], pn))
pnweights = arrays['weights'][pnedges].copy()
pnweights[np.isin(arrays['src'][pnedges], apl)] = 0.0
shared_inputs = [meta_path, COEFF, AH_MODEL / 'replay_core.py', AI_MODEL / 'validate_events.py',
AG_MODEL / 'calibration.py', AI / 'manifest.json', AI / 'checksums.sha256',
AG / 'manifest.json', AG / 'checksums.sha256']
shared_inputs += [graph / (key + '.npy') for key in arrays]
shared_inputs += [AG / 'apl-bundle' / (name + '_globals.npy') for name in ('pn', 'kc', 'apl')]
save(outroot / 'shared-inputs.json', [dict(path=str(p.relative_to(ROOT)), bytes=p.stat().st_size,
sha256=input_hash(p)) for p in shared_inputs])
save(outroot / 'inventory.json', [dict(**r, mode=specifications[r['case']]['mode'],
odor_id=specifications[r['case']]['odor_id'], seed=specifications[r['case']]['seed']) for r in inventory])
for row in inventory:
name = row['case']
require(Path(name).name == name and '/' not in name and '\\' not in name, 'Invalid case path')
case = AG / 'cases' / name
source = AG / 'gpu' / (name + '-r0')
require(ROOT / row['source'] == source, 'Inventory source differs from fixed CAL r0 source')
previous = AI / 'trials' / (name + '-r0')
dest = outroot / name
dest.mkdir(exist_ok=False)
spec = specifications[name]
for path in (source / 'state.npz', source / 'summary.json', case / 'spec.json', case / 'requests.npz',
case / 'pn-drive.npz', previous / 'accepted-prefirst-edge-events.parquet',
previous / 'per-pn.parquet', previous / 'summary.json'):
input_hash(path)
require(spec['steps'] == 1000 and spec['duration_ms'] == 100.0, 'CAL duration changed')
require(not (case / 'arrays.npz').exists(), 'Unexpected CAL initial-state override')
source_summary = read(source / 'summary.json')
require(source_summary['complete'] is True and source_summary['completed_ticks'] == spec['steps'],
'Incomplete source simulation')
ai_summary = read(previous / 'summary.json')
require(ai_summary['pass_all'] is True and all(ai_summary['exact'].values()), 'AI exactness failed')
state = _read_npz(source / 'state.npz')
event_keys = cal.validate_state(state, N, spec['steps'])
requests = _read_npz(case / 'requests.npz')
drive = _read_npz(case / 'pn-drive.npz')
design = np.sort(drive['targets'])
require(design.dtype == np.int32 and len(np.unique(design)) == len(design) and
np.isin(design, pn).all(), 'Design identities invalid')
require(len(design) == spec['target_count'] and drive['rates_hz'].dtype == np.float32 and
drive['rates_hz'].shape == design.shape and np.all(drive['rates_hz'] > 0),
'Static PN design count/rate schema differs')
require(np.isin(requests['neuron_idx'], design).all(), 'Request outside static odor design')
design_mask = np.zeros(N, bool)
design_mask[design] = True
first_pn = first_ticks(state['step'], state['neuron_idx'], pn)
observed_kc = first_ticks(state['step'], state['neuron_idx'], kc)
first_kc = int(observed_kc[observed_kc >= 0].min()) if np.any(observed_kc >= 0) else -1
selection = select_cohort(pn, first_pn, design, first_kc, spec['steps'])
cohort = selection.pop('cohort')
cohort_mask = np.zeros(N, bool)
cohort_mask[cohort] = True
never_mask = np.zeros(N, bool)
never_mask[pn[first_pn < 0]] = True
saved_pn = pd.read_parquet(previous / 'per-pn.parquet')
require(np.array_equal(saved_pn.neuron_idx, pn) and np.array_equal(saved_pn.first_spike_tick, first_pn),
'Sealed AI PN first-spike identity mismatch')
cutoff = selection['pre_kc_stop_exclusive']
window_stats = {key: {} for key in ('cohort_pre_KC_and_pre_first', 'never_active_pre_KC',
'never_active_non_design_pre_KC', 'never_active_matched_cohort_window',
'never_active_non_design_matched_cohort_window')}
outgoing_chunks = []
cohort_chunks = []
rows_seen, previous_event_key = 0, -1
counts_per_pn = np.zeros(len(pn), np.int64)
for batch in pq.ParquetFile(previous / 'accepted-prefirst-edge-events.parquet').iter_batches(batch_size=65536):
frame = batch.to_pandas()
columns = {k: frame[k].to_numpy() for k in validate.COLUMN_DTYPES}
audit = validate.validate_batch(columns, edge_ids=arrays['edge_id'][pnedges],
srcglobals=arrays['src'][pnedges], dstglobals=arrays['dst'][pnedges], weights=pnweights,
target_globals=pn, target_first=first_pn, source_event_keys=event_keys)
key = frame.arrival_tick.to_numpy().astype(np.int64) * E + frame.edge_id.to_numpy()
require(not len(key) or (key[0] > previous_event_key and np.all(np.diff(key) > 0)),
'AI event order/uniqueness violated across batches')
if len(key):
previous_event_key = int(key[-1])
require(np.all(frame.arrival_tick.to_numpy() < spec['steps']), 'AI event beyond trial')
labels = source_labels(frame.source_neuron_idx.to_numpy(), role, design_mask)
require(np.array_equal(frame.source_group, role[frame.source_neuron_idx.to_numpy()]), 'AI source role differs')
require(np.array_equal(frame.target_is_design, design_mask[frame.target_neuron_idx.to_numpy()]),
'AI target design differs')
targets = frame.target_neuron_idx.to_numpy()
pre = frame.arrival_tick.to_numpy() < cutoff
matched = frame.arrival_tick.to_numpy() < selection['matched_stop_exclusive']
cohort_sel = cohort_mask[targets] & pre
masks = dict(cohort_pre_KC_and_pre_first=cohort_sel,
never_active_pre_KC=never_mask[targets] & pre,
never_active_non_design_pre_KC=never_mask[targets] & ~design_mask[targets] & pre,
never_active_matched_cohort_window=never_mask[targets] & matched,
never_active_non_design_matched_cohort_window=never_mask[targets] & ~design_mask[targets] & matched)
for key, mask in masks.items():
_window_add(window_stats[key], frame, mask, labels)
# The fixed earliest cohort normally makes these small, but the
# on-disk ceiling remains hard and no row may be sampled away.
if np.any(cohort_sel):
selected_frame = frame.loc[cohort_sel].copy()
selected_frame['audit_source_group'] = labels[cohort_sel]
cohort_chunks.append(selected_frame)
out_sel = cohort_sel & (role[frame.source_neuron_idx.to_numpy()] == 'ALLN')
if np.any(out_sel):
outgoing_chunks.append(frame.loc[out_sel].copy())
counts_per_pn += audit['per_target_count']
rows_seen += audit['count']
require(rows_seen == ai_summary['observer']['first_arrival_record_count'], 'AI antecedent rows incomplete')
require(np.array_equal(counts_per_pn, saved_pn[[g + '_accepted_nonzero_before_first_edges'
for g in ai_summary['observer']['source_group_names']]].sum(axis=1).to_numpy()),
'AI per-PN antecedent completeness differs')
saved_event_schema = pq.ParquetFile(previous / 'accepted-prefirst-edge-events.parquet').schema_arrow
cohort_table = (pd.concat(cohort_chunks, ignore_index=True) if cohort_chunks else
pa.Table.from_batches([], schema=saved_event_schema).to_pandas().assign(audit_source_group=pd.Series(dtype=str)))
cohort_table.to_parquet(dest / 'cohort-all-source-antecedents.parquet', index=False, compression='zstd')
output = (pd.concat(outgoing_chunks, ignore_index=True) if outgoing_chunks else
pa.Table.from_batches([], schema=saved_event_schema).to_pandas())
sink = Sink(dest / 'ALLN-all-accepted-incoming.parquet', event_schema(), outroot)
observer = ALLNObserver(alln, incoming, role, design_mask, body, spec['steps'], cutoff, sink)
try:
result = core.replay(np.full(len(alln), spec['model']['resting_potential_mv'], np.float64) * np.float64(.001),
np.zeros(len(alln), np.float64), read(COEFF), spec['steps'], alln, requests,
dict(step=state['step'], neuron_idx=state['neuron_idx']), incoming,
np.zeros((spec['steps'], len(alln)), np.float32), observer)
finally:
sink.close()
observed = np.isin(state['neuron_idx'], alln)
exact = {k: bit_equal(result[k], state[k][alln]) for k in ('v', 'g', 'ref', 'counts')}
exact.update({k: bit_equal(result[k], state[k][observed]) for k in ('step', 'neuron_idx')})
require(all(exact.values()), 'Conditional ALLN replay differs from full AG events/final states: ' + str(exact))
with (dest / 'ALLN-replay-final.npz').open('xb') as stream:
np.savez_compressed(stream, **result)
join_rows = []
alln_source_spikes = {int(node): state['step'][state['neuron_idx'] == node]
for node in np.unique(output.source_neuron_idx.to_numpy())}
for record in output.to_dict('records'):
target = int(record['source_neuron_idx']) # Intermediate ALLN.
tick = int(record['source_spike_tick'])
spikes = alln_source_spikes[target]
pos = int(np.searchsorted(spikes, tick))
require(pos < len(spikes) and spikes[pos] == tick, 'ALLN outgoing source event absent')
last = int(spikes[pos - 1]) if pos else -1
predecessors = predecessor_counts(np.asarray(observer.design_ticks[target], np.int32),
np.asarray(observer.design_weights[target], np.float64), tick, last)
join_rows.append(dict(**record, ALLN_previous_spike_tick=last,
ALLN_source_event_key=tick * N + target, source_body_id=int(body[target]),
target_body_id=int(body[int(record['target_neuron_idx'])]), **predecessors,
witness_status=('timed_design_PN_antecedent_since_last_reset' if
predecessors['since_last_reset_nonzero_design_PN_events'] else 'no_direct_design_PN_antecedent_since_last_reset')))
# Add declared columns even if the fixed cohort has no ALLN antecedent.
join_extra = dict(ALLN_previous_spike_tick='int32', ALLN_source_event_key='int64',
source_body_id='uint64', target_body_id='uint64', all_prior_design_PN_events='int64',
since_last_reset_design_PN_events='int64', since_last_reset_positive_events='int64',
since_last_reset_nonzero_design_PN_events='int64',
since_last_reset_negative_events='int64', since_last_reset_zero_events='int64',
since_last_reset_positive_weight_SI='float64', since_last_reset_negative_abs_weight_SI='float64',
prior_reset_excluded_events='int64', witness_status='object')
witnesses = pd.DataFrame(join_rows) if join_rows else output.copy()
for key, dtype in join_extra.items():
witnesses[key] = witnesses[key].astype(dtype) if key in witnesses else pd.Series(dtype=dtype)
witnesses.to_parquet(dest / 'ALLN-to-cohort-PN-witness-join.parquet', index=False, compression='zstd')
per_pn = meta.iloc[pn].copy()
per_pn['first_spike_tick'] = first_pn
per_pn['design_target'] = design_mask[pn]
per_pn['earliest_non_design_cohort'] = cohort_mask[pn]
per_pn['never_active'] = first_pn < 0
per_pn.to_parquet(dest / 'PN-population-and-cohort.parquet', index=False, compression='zstd')
per_alln = meta.iloc[alln].copy()
per_alln['first_spike_tick'] = result['first_spike']
per_alln['spike_count'] = result['counts']
per_alln.to_parquet(dest / 'ALLN-population.parquet', index=False, compression='zstd')
witness_rows = int((witnesses.since_last_reset_nonzero_design_PN_events > 0).sum())
inputs = [source / 'state.npz', source / 'summary.json', case / 'spec.json', case / 'requests.npz',
case / 'pn-drive.npz', previous / 'accepted-prefirst-edge-events.parquet',
previous / 'per-pn.parquet', previous / 'summary.json']
report = dict(case=name, repeat=0, mode=spec['mode'], odor_id=spec['odor_id'], seed=spec['seed'],
pass_all=True, exact=exact, ALLN_replay=observer.report(), first_any_KC_tick=first_kc,
**selection, cohort_neurons=int(len(cohort)), cohort_neuron_idx=cohort.tolist(),
cohort_body_id=[int(x) for x in body[cohort]], never_active_PN=int(never_mask.sum()),
never_active_non_design_PN=int(np.count_nonzero(never_mask & ~design_mask)),
window_source_accounting=window_stats, AI_antecedent_rows_checked=rows_seen,
cohort_ALLN_outgoing_events=len(output), outgoing_events_with_since_reset_design_antecedent=witness_rows,
outgoing_events_without_since_reset_design_antecedent=len(output) - witness_rows,
compact_join_pair_count=int(witnesses.since_last_reset_nonzero_design_PN_events.sum()),
no_direct_antecedent_is_not_unexplained_wholebrain=True,
join_contract='same trial; incoming.target_neuron_idx=outgoing.source_neuron_idx; incoming.source_group=design_ALPN; '
'incoming.weight_SI != 0; '
'outgoing.ALLN_previous_spike_tick < incoming.arrival_tick < outgoing.source_spike_tick; '
'outgoing.arrival_tick < cohort first spike and first-any-KC cutoff; both legs exactly 18 ticks; '
'all incoming rows accepted at ref=0; signs retained; zero legs not causal transmission',
accounting_scope='Accepted nominal SI weight sums, not membrane contribution, necessity or unique cause; '
'prior-reset antecedents retained only as history; since-reset nonzero weights can still cancel/round away',
window_scope='Cohort first-spike antecedents are censored at their first spike; never-active pre-KC windows are longer. '
'Use matched_cohort_window for duration-matched comparisons. If KC never fires, full trial is marked censored.',
new_brain_simulation=False, GPU_used=False, candidate_generated=False,
CAL_independent_ALLN_per_tick_history_available=False,
input_sha256={str(p.relative_to(ROOT)): input_hash(p) for p in inputs})
save(dest / 'summary.json', report)
save(dest / 'output-hashes.json', [dict(path=p.name, bytes=p.stat().st_size, sha256=digest(p))
for p in sorted(dest.iterdir()) if p.is_file()])
receipts.append(dict(case=name, repeat=0, mode=spec['mode'], odor_id=spec['odor_id'],
seed=spec['seed'], ALLN_targets=420, exact=exact, pass_all=True,
summary_sha256=digest(dest / 'summary.json')))
file_budget(outroot)
print(name, '420 ALLN conditional exact; earliest cohort', len(cohort), 'PASS', flush=True)
require(len(receipts) == 60, 'Incomplete origin audit inventory')
save(outroot / 'summary.json', dict(pass_all=True, status='PASS-CONDITIONAL-EARLIEST-AL-ORIGIN-AUDIT',
trials=receipts, fixed_CAL_r0_count=60, ALLN_per_trial=420, new_brain_simulation=False,
GPU_used=False, no_cartesian_witness_expansion=True, truncated=False,
unique_cause_proven=False, necessity_proven=False, output_budget_bytes=BUDGET,
meaning='Exact conditional ALLN reconstruction and timed anatomical antecedent audit, not a biological causal gate'))
file_budget(outroot)
except Exception as error:
save(outroot / 'failure.json', dict(pass_all=False, error=type(error).__name__, message=str(error),
traceback=traceback.format_exc(), completed=receipts, new_brain_simulation=False))
raise
if __name__ == '__main__':
main()
@@ -0,0 +1,368 @@
"""Read-only two-arm CAL aggregation using the sealed, full original 4L gate.
No trajectory is generated here. Representation failure never selects an arm
or suppresses the other arm. Timing checks use direct slices, not either
runtime's queue, and old scientific outputs are never modified.
"""
from __future__ import annotations
import csv
import hashlib
import importlib.util
import json
from pathlib import Path
import sys
import numpy as np
LEGACY_SHA256 = "edb9cb2d890471fd07afd88c959ef3540b0cd40af490fac3f26396b5e7f5bf9c"
STATE_DTYPES = {"step": np.int32, "neuron_idx": np.int32, "counts": np.int32,
"v": np.float64, "g": np.float64, "ref": np.int32}
APL_FILES = {"apl-drive.float32.npy": 2, "apl-state.float32.npy": 2,
"apl-inhibition.float32.npy": 4064}
REQUEST_FIELDS = ("tick", "neuron_idx", "attempted", "accepted", "rejected")
_DEFAULT_OUTPUT = object()
def require(ok, message):
if not ok:
raise ValueError(message)
def read_json(path):
return json.loads(Path(path).read_text(encoding="utf-8"))
def file_hash(path):
value = hashlib.sha256()
with Path(path).open("rb") as stream:
for block in iter(lambda: stream.read(8 << 20), b""):
value.update(block)
return value.hexdigest()
def raw_hash(value):
return hashlib.sha256(np.ascontiguousarray(value).tobytes()).hexdigest()
def bit_equal(a, b):
return bool(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)))
def load_legacy(path=None):
"""Load the sealed pure functions, without rebinding any old global/path."""
if path is None:
from context import AG_MODEL
path = AG_MODEL / "calibration.py"
path = Path(path)
require(file_hash(path) == LEGACY_SHA256, "Sealed AG calibration source changed")
spec = importlib.util.spec_from_file_location("sealed_ag_calibration_for_aj", path)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
return module
def _jsonl(path):
with Path(path).open(encoding="utf-8") as stream:
return [json.loads(line) for line in stream if line.strip()]
def _request_rows(path):
with Path(path).open(encoding="utf-8", newline="") as stream:
reader = csv.DictReader(stream)
require(tuple(reader.fieldnames or ()) == REQUEST_FIELDS, "Request schema mismatch")
return [{key: int(row[key]) for key in REQUEST_FIELDS} for row in reader]
def _component(directory):
gpu, oracle = directory / "apl-component.json", directory / "apl-worker-handshake.json"
require(gpu.is_file() != oracle.is_file(), "Exactly one backend APL provenance file is required")
return read_json(gpu) if gpu.is_file() else read_json(oracle)["handshake"]
def control_identity(newdir, olddir, case):
"""Compare delay0 scientific evidence with sealed AG, for fixtures or CAL.
case is the NEW case directory. Summary paths, budgets, build/wall times and
new adapter metadata are deliberately not compared. Missing evidence raises;
numerical differences return pass_all=False with each failed check retained.
"""
newdir, olddir, case = Path(newdir), Path(olddir), Path(case)
spec = read_json(case / "spec.json")
require(type(spec.get("apl_delay_steps")) is int and spec["apl_delay_steps"] == 0,
"Control identity is defined only for explicit delay0")
fresh, old = read_json(newdir / "summary.json"), read_json(olddir / "summary.json")
require(all(row.get("complete") is True and row.get("pass_all") is True for row in (fresh, old)),
"Cannot compare incomplete/failed control evidence")
require(all(row.get("steps") == spec["steps"] and row.get("completed_ticks") == spec["steps"] and
row.get("case", row.get("name")) == spec["name"] for row in (fresh, old)),
"Control case identity/completion changed")
checks = {}
with np.load(newdir / "state.npz", allow_pickle=False) as aa, np.load(olddir / "state.npz", allow_pickle=False) as bb:
require(set(aa.files) == set(bb.files) == set(STATE_DTYPES), "Control state schema mismatch")
for name, dtype in STATE_DTYPES.items():
first, second = aa[name], bb[name]
require(first.dtype == second.dtype == dtype and first.ndim == second.ndim == 1 and
np.isfinite(first).all() and np.isfinite(second).all(), "Invalid control state: " + name)
checks["state/" + name] = bit_equal(first, second)
for name, width in APL_FILES.items():
first, second = (np.load(folder / name, mmap_mode="r", allow_pickle=False) for folder in (newdir, olddir))
require(first.dtype == second.dtype == np.float32 and first.shape == second.shape == (spec["steps"], width)
and np.isfinite(first).all() and np.isfinite(second).all(), "Invalid control APL trace: " + name)
checks[name] = bit_equal(first, second)
for name in ("tick-state-hashes.jsonl", "queue.jsonl"):
first, second = _jsonl(newdir / name), _jsonl(olddir / name)
require(len(first) == len(second) == spec["steps"] and all(
[row.get("tick") for row in rows] == list(range(spec["steps"])) for rows in (first, second)),
"Incomplete control tick record: " + name)
checks[name] = first == second
checks["requests.csv"] = _request_rows(newdir / "requests.csv") == _request_rows(olddir / "requests.csv")
checks["APL_component"] = _component(newdir) == _component(olddir)
require(isinstance(old.get("effective_weights_raw_sha256"), str) and
len(old["effective_weights_raw_sha256"]) == 64, "Missing old effective-weight evidence")
checks["effective_weights_raw_sha256"] = fresh.get("effective_weights_raw_sha256") == old["effective_weights_raw_sha256"]
for key in ("nodes", "edges", "precision", "apl_fast_edges_zeroed", "kc_targets_present"):
require(key in fresh and key in old, "Missing control summary scientific field: " + key)
checks["summary/" + key] = fresh[key] == old[key]
if spec["record_history"]:
for prefix in ("", "preAPL-"):
for field, dtype in (("v", "float64"), ("g", "float64"), ("ref", "int32")):
name = f"{prefix}{field}-history.{dtype}.npy" if not prefix else f"{prefix}{field}.{dtype}.npy"
first, second = (np.load(folder / name, mmap_mode="r", allow_pickle=False) for folder in (newdir, olddir))
checks[name] = bit_equal(first, second)
# CPU oracle also saves actual effective Brian weights. GPU has only the
# raw effective-weight digest, already compared above.
if (newdir / "weights.npy").exists() or (olddir / "weights.npy").exists():
require((newdir / "weights.npy").is_file() and (olddir / "weights.npy").is_file(),
"Control backend weight-file presence differs")
checks["weights.npy"] = bit_equal(np.load(newdir / "weights.npy", mmap_mode="r"),
np.load(olddir / "weights.npy", mmap_mode="r"))
return {"pass_all": bool(all(checks.values())), "case": spec["name"], "checks": checks,
"scope": "Six state arrays, all tick hashes/queues/requests, generated APL, component, effective weights and fixture pre/post histories",
"adapter_paths_budgets_and_runtime_metadata_compared": False}
def validate_timing(output, spec, trial):
"""Independently verify raw timing files and recorded audit, without a queue."""
output = Path(output)
steps, delay = spec["steps"], spec["apl_delay_steps"]
require(type(delay) is int and delay in (0, 18), "Invalid timing arm")
generated = trial["apl"]["apl-inhibition.float32.npy"]
applied = np.load(output / "apl-applied.float32.npy", mmap_mode="r", allow_pickle=False)
pending = np.load(output / "apl-pending-tail.float32.npy", mmap_mode="r", allow_pickle=False)
for name, value, shape in (("generated", generated, (steps, 4064)),
("applied", applied, (steps, 4064)), ("pending", pending, (delay, 4064))):
require(value.dtype == np.float32 and value.shape == shape and np.isfinite(value).all() and
np.all(value >= 0), "Invalid timing array " + name)
warmup, consumed, prefix = min(steps, delay), max(steps - delay, 0), max(delay - steps, 0)
require(np.all(applied[:warmup].view(np.uint32) == 0) and np.all(pending[:prefix].view(np.uint32) == 0),
"Timing initial padding must be positive zero")
require(bit_equal(applied[warmup:], generated[:consumed]) and bit_equal(pending[prefix:], generated[consumed:]),
"Timing transport is not an exact finite generated-sequence partition")
audit = read_json(output / "apl-timing-audit.json")
summary = read_json(output / "summary.json")
expected = {"pass_all": True, "apl_delay_steps": delay, "steps": steps,
"pending_generated_count": min(steps, delay), "pending_initial_zero_prefix": prefix,
"pending_application_tick_start": steps, "pending_application_tick_stop_exclusive": steps + delay,
"pending_generated_tick_start": consumed, "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": 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_state = trial["apl"]["apl-state.float32.npy"][-1]
expected.update(final_apl_state_float32=final_state.tolist(),
final_apl_state_u32_bits=final_state.view(np.uint32).tolist(),
final_apl_state_nonzero=bool(np.any(final_state != 0)))
for key, value in expected.items():
require(key in audit and audit[key] == value and type(audit[key]) is type(value),
"Timing audit disagrees with independent data: " + key)
require(summary.get("apl_delay_steps") == delay and summary.get("apl_timing") == audit,
"Timing audit differs from GPU summary")
return {"applied": applied, "pending": pending, "audit": audit,
"report": {"pass_all": True, "apl_delay_steps": delay, "steps": steps,
"generated_applied_pending_bits_exact": True, "pending_generated_count": min(steps, delay),
"pending_initial_zero_prefix": prefix, "brain_tail_advanced": False}}
def timing_repeat(first, repeat, legacy):
result = legacy.exact_repeat(first, repeat)
result["checks"].update(apl_applied=bit_equal(first["timing"]["applied"], repeat["timing"]["applied"]),
apl_pending=bit_equal(first["timing"]["pending"], repeat["timing"]["pending"]),
timing_audit=first["timing"]["audit"] == repeat["timing"]["audit"])
result["pass_all"] = bool(all(result["checks"].values()))
result["scope"] += "; plus delayed applied h, finite pending tail and timing audit"
return result
def _case_spec(case, old_case, row, delay):
spec = read_json(case / "spec.json")
old = read_json(old_case / "spec.json")
require(type(spec.get("apl_delay_steps")) is int and spec["apl_delay_steps"] == delay,
"Case arm/delay mismatch")
require(set(spec) == set(old) | {"apl_delay_steps"}, "Unexpected case fields")
require(all(spec[key] == value for key, value in old.items() if key not in ("budget_root", "output_budget_bytes")),
"A scientific case field changed in addition to APL output delay")
require(spec["name"] == row["name"] and spec["kind"] == "calibration" and spec["steps"] == 1000 and
spec["duration_ms"] == 100.0 and spec["dt_ms"] == .1 and spec["training"] is False and
all(spec[key] == row[key] for key in ("mode", "odor_id", "odor_index", "seed")), "Invalid fixed CAL case")
for name in ("requests.npz", "pn-drive.npz"):
require(file_hash(case / name) == file_hash(old_case / name), "Frozen CAL input bytes changed: " + name)
return spec
def _read_new(legacy, output, case, spec, kc_globals, cfg):
trial = legacy.read_trial(output, case, spec, kc_globals, cfg["neurons"], cfg["edges"])
trial["timing"] = validate_timing(output, spec, trial)
return trial
def _provenance(output, name, repeat):
return {"case": name, "repeat": repeat, "sha256": {fname: file_hash(output / fname) for fname in
("state.npz", "summary.json", "tick-state-hashes.jsonl", "queue.jsonl", "requests.csv", "apl-component.json",
*APL_FILES, "apl-applied.float32.npy", "apl-pending-tail.float32.npy", "apl-timing-audit.json")}}
def collect_arm(arm, delay, records, odors, legacy, cfg, exp, ag, kc_globals):
failures, runs, rows, repeats, controls, provenance, timings, modes = [], {}, [], [], [], [], [], {}
for row in records:
name, first, spec = row["name"], None, None
case = exp / "cases" / arm / name
try:
spec = _case_spec(case, ag / "cases" / name, row, delay)
except Exception as error:
failures.append(dict(stage="case_spec", case=name, type=type(error).__name__, message=str(error)))
for repeat_index in ([0, 1] if row["seed"] == legacy.ORIGINAL_SEEDS[0] else [0]):
output = exp / "gpu" / arm / (name + "-r" + str(repeat_index))
try:
require(spec is not None, "Case spec unavailable")
trial = _read_new(legacy, output, case, spec, kc_globals, cfg)
require(trial["record"]["requested"] == row["requests"], "Inventory request count changed")
timings.append(dict(case=name, repeat=repeat_index, **trial["timing"]["report"]))
provenance.append(_provenance(output, name, repeat_index))
if repeat_index == 0:
first = trial
runs[(row["mode"], row["odor_id"], row["seed"])] = {key: first[key] for key in
("kc_counts", "expected_external_events", "external_events")}
rows.append(first["record"])
else:
require(first is not None, "Baseline unavailable for exact repeat")
report = dict(case=name, **timing_repeat(first, trial, legacy))
repeats.append(report)
require(report["pass_all"], "Exact repetition differs: " + ", ".join(
key for key, value in report["checks"].items() if not value))
if delay == 0:
control = control_identity(output, ag / "gpu" / (name + "-r" + str(repeat_index)), case)
controls.append(dict(repeat=repeat_index, **control))
require(control["pass_all"], "Delay0 differs from sealed AG: " + ", ".join(
key for key, value in control["checks"].items() if not value))
except Exception as error:
failures.append(dict(stage="raw_trial" if repeat_index == 0 else "repeat_trial", case=name,
repeat=repeat_index, type=type(error).__name__, message=str(error)))
# Each complete mode is still described even if the other mode/arm failed.
for mode in legacy.ORIGINAL_MODES:
needed = {(mode, odor, seed) for odor in odors for seed in legacy.ORIGINAL_SEEDS}
if needed.issubset(runs):
try:
modes[mode] = legacy.summarize_mode(mode, odors, legacy.ORIGINAL_SEEDS, runs, cfg["gates"])
except Exception as error:
failures.append(dict(stage="representation_calculation", mode=mode, type=type(error).__name__, message=str(error)))
numerical = bool(len(runs) == 60 and len(timings) == 72 and not any(
row["stage"] != "representation_calculation" for row in failures))
repeat_pass = bool(len(repeats) == 12 and all(row["pass_all"] for row in repeats))
control_pass = bool(delay != 0 or (len(controls) == 72 and all(row["pass_all"] for row in controls)))
representation = bool(len(modes) == 2 and all(row["gate"] for row in modes.values()))
execution = bool(numerical and repeat_pass and control_pass)
return {"arm": arm, "apl_delay_steps": delay, "pass_all": bool(execution and representation),
"execution_gate_pass": execution, "numerical_integrity_pass": numerical, "exact_repeat_pass": repeat_pass,
"control_identity_applicable": delay == 0, "delay0_control_identity_pass": control_pass if delay == 0 else None,
"original_representation_gate_pass": representation, "expected_base_trials": 60, "valid_base_trials": len(runs),
"expected_repeats": 12, "checked_repeats": len(repeats), "checked_timing_trials": len(timings),
"modes": modes, "runs": rows, "repeats": repeats, "timing_checks": timings,
"control_checks": controls, "failures": failures, "input_output_provenance": provenance}
def summarize(out_json=_DEFAULT_OUTPUT):
"""Default writes new evidence exclusively; out_json=None is pure recomputation."""
from context import EXP, AG, ROOT, CFG, check
target = EXP / "calibration/summary.json" if out_json is _DEFAULT_OUTPUT else (
None if out_json is None else Path(out_json))
require(target is None or not target.exists(), "Refusing existing calibration summary")
arms, failures, odors, encoder = {}, [], [], None
try:
check()
legacy = load_legacy()
require(CFG["delays_steps"] == [0, 18], "Fixed timing arms changed")
records = read_json(EXP / "protocol/calibration-cases.json")
require(file_hash(EXP / "protocol/calibration-cases.json") == file_hash(AG / "protocol/calibration-cases.json"),
"Original CAL inventory bytes changed")
odors = legacy.validate_inventory(records, CFG)
encoder = read_json(EXP / "protocol/encoder-audit.json")
require(file_hash(EXP / "protocol/encoder-audit.json") == file_hash(AG / "protocol/encoder-audit.json"),
"Frozen encoder audit changed")
require(encoder["panel_count"] == 12 and encoder["cal_count"] == 6 and
encoder["seeds"] == list(legacy.ORIGINAL_SEEDS) and encoder["requested_before_any_dynamics"] is True and
encoder["formal_AB_run"] is False and encoder["heldout_run"] is False, "Invalid frozen encoder scope")
import pandas as pd
panel = pd.read_parquet(ROOT / "experiments/phase4l-olfactory-grounding/odor-encoder/frozen-odor-panel.parquet")
require(len(panel) == 12 and set(panel[panel.split == "calibration"].odor_id) == legacy.ORIGINAL_CAL_IDS and
float(np.median(panel.mapped_response_sum)) == encoder["median_mapped_response_sum"],
"Static original 12-panel median/identities changed; no heldout trajectories are read")
kc = np.load(AG / "apl-bundle/kc_globals.npy", allow_pickle=False)
require(kc.dtype == np.int32 and kc.shape == (4064,) and np.all(np.diff(kc) > 0) and
np.all((kc >= 0) & (kc < CFG["neurons"])), "Invalid frozen KC identity")
for delay in (0, 18):
arm = "delay" + str(delay)
try:
arms[arm] = collect_arm(arm, delay, records, odors, legacy, CFG, EXP, AG, kc)
except Exception as error:
failures.append(dict(stage="arm", arm=arm, type=type(error).__name__, message=str(error)))
except Exception as error:
failures.append(dict(stage="prerequisites", type=type(error).__name__, message=str(error)))
for arm, data in arms.items():
failures.extend(dict(arm=arm, **row) for row in data["failures"])
complete = set(arms) == {"delay0", "delay18"}
numerical = bool(complete and all(row["numerical_integrity_pass"] for row in arms.values()) and not failures)
repeated = bool(complete and all(row["exact_repeat_pass"] for row in arms.values()))
control = bool("delay0" in arms and arms["delay0"]["delay0_control_identity_pass"])
represented = bool(complete and all(row["original_representation_gate_pass"] for row in arms.values()))
execution = bool(numerical and repeated and control)
result = {"phase": "4AJ", "pass_all": bool(execution and represented), "execution_gate_pass": execution,
"numerical_integrity_pass": numerical, "exact_repeat_pass": repeated, "delay0_control_identity_pass": control,
"original_representation_gate_pass": represented,
"original_representation_gate_pass_by_arm": {arm: row["original_representation_gate_pass"] for arm, row in arms.items()},
"expected_base_trials_per_arm": 60, "expected_repeats_per_arm": 12,
"expected_delay0_AG_comparisons": 72, "arms": arms, "failures": failures, "odor_ids": odors,
"encoder_audit": encoder, "legacy_calibration_sha256": LEGACY_SHA256,
"scope": "Both fixed timing arms, full original 4L CAL gate; no heldout or learning claim",
"representation_failure_is_not_numerical_failure": True,
"selection_or_tuning_performed": False, "both_arms_retained_regardless_of_representation": True,
"closed_loop_generated_h_integrals_forced_equal": False,
"pending_is_finite_generated_sequence_not_complete_future_decay": True,
"candidate_generated": False, "training": False, "heldout_dynamic_access": False,
"shared_apl_component_oracle_limit": True, "independent_oracle_equivalence_claim": False}
if target is not None:
outputs = {target: result}
for arm, data in arms.items():
directory = target.parent / arm
outputs[directory / "summary.json"] = data
for mode, metrics in data["modes"].items():
outputs[directory / (mode + ".json")] = metrics
require(all(not path.exists() for path in outputs), "Refusing existing arm/mode summary")
for path, value in outputs.items():
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("x", encoding="utf-8") as stream:
json.dump(value, stream, ensure_ascii=False, indent=2, allow_nan=False)
stream.write("\n")
return result
if __name__ == "__main__":
result = summarize()
print(json.dumps({key: result[key] for key in ("pass_all", "execution_gate_pass",
"delay0_control_identity_pass", "original_representation_gate_pass_by_arm")}), flush=True)
@@ -0,0 +1,22 @@
d96aef0107f7b0791d16e475b749da418b8a38d2c56a94e0779de0cd6581a7de PROTOCOL.md
7201871477a29ede31c7d6c6bf1c92700da3db5505e67ccfa7cb43126b8464b9 al_origin_audit.py
fb15ddeaa108305c8de697bbae36b23ab0414a7c58db51c66dce9feb4a048a0d calibration.py
9010f070fba9b7c9cf2d86187ee2abc57f3ac606ebc08a42baad4f3922b51734 compare_timing.py
0b720e23aa7988b2b443e14951082b1ce9b061a183b7f858c0e0f3c0fc6fb25e config.json
06d4994af3729d653263391ff3a3604f7c919e78562604e5c86acfa292d60ba0 context.py
0a2dbf9e5f889e9dd3491d036e6f92c17417a84482c5e1e49134c0993f7d68f2 finalize.py
af1975ba5e5e700208c0a598d3cbe648a3cf10885c6231239b6e4b28f76d173b gpu_timing.py
39d8c47c94bc2faddf016864a43e7715907fb987f56f7b27098060a88851f6be oracle_timing.py
bba71bcd52dcb78d9ae0fa93a8a43173a4669ecef038dce18ce7d82edd9bce50 prepare.py
d93e4fe2df542ce5a0f0adb5aceada583dc8c921f0159f426e50428d79d67a1d run_case.py
6f26c626acf9ef8e6fae7902af0cbf0bd176eb322529ca8aa203a9700716c889 run_suite.py
46f380dac340acc91f226968bb493475a31777f8290fb20f9145a97c9009d845 shift_audit.py
4b75a39d36090b0a66cc7ad4b370ac785713fb58c366df2efcc55152d612fc2b test_al_origin_audit.py
307a2848bf6d05aaa8105bb3558be2a74425894f96a4a2bd20af8b82cb8b6e25 test_calibration.py
cbae93c993ac9aa99bcce68ae2131c7f938f8a63e89779f8d3d79e36bf268dee test_protocol.py
bfc0d9e17410c2c52ea1d9a5259c92964f16b118dbae8cecad258697b67e4bdc tests/__init__.py
71876b36eef88c198aa8e833af547dbe772001c71b010707b656c165c8b54031 tests/test_compare_timing.py
4a375444dc732c3538df8aa4b81e43b5418754fcebebb0d02c16faad03d43195 tests/test_timing_queue.py
54df6d4818e2a0c26e96fb0aaf5d9b71cd964981706da937562d48af79aca14e timing_queue.py
97d8a240b08baaca935f9c0278978883005dcd6fdbb4ca0d948074ef79fd349c verify_frozen.py
52b05dd1ff30b6b51ff960fe95904532f5c147731a83f0b5c31f98ca7e53c216 manifest.json
@@ -0,0 +1,611 @@
"""Fail-closed byte-exact audit of fixed-delay shared-APL closed-loop runs.
Comparison is independent of either backend's stored PASS. No tolerance is
used, wall-clock performance fields are excluded, and reports contain no wall
timestamp. Scientific delay/tick metadata are checked explicitly.
"""
from __future__ import annotations
import csv
import hashlib
import json
import math
from pathlib import Path
import re
import struct
import numpy as np
N_GLOBAL = 166700
STATE_KEYS = ('step', 'neuron_idx', 'counts', 'v', 'g', 'ref')
REQUEST_FIELDS = ('tick', 'neuron_idx', 'attempted', 'accepted', 'rejected')
HASH_FIELDS = {'tick', 'v_sha256', 'g_sha256', 'ref_sha256'}
QUEUE_FIELDS = {'tick', 'count', 'accepted_count', 'ordered_edge_sha256',
'accepted_mask_sha256', 'joint_sha256'}
BUNDLE_FILES = ('input_matrix.npy', 'output_matrix.npy', 'kc_globals.npy', 'apl_globals.npy')
COEFFICIENTS = ('gd', 'c0', 'cg', 'cv', 'threshold', 'reset', 'seed_volt')
def require(condition, message):
if not condition:
raise ValueError(message)
def file_hash(path):
h = hashlib.sha256()
with Path(path).open('rb') as source:
for block in iter(lambda: source.read(8 << 20), b''):
h.update(block)
return h.hexdigest()
def raw_hash(array, dtype=None):
return hashlib.sha256(np.ascontiguousarray(array, dtype=dtype).tobytes()).hexdigest()
def save(path, report):
if path is None:
return
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
with path.open('x', encoding='utf-8') as target:
json.dump(report, target, indent=2, sort_keys=True, allow_nan=False)
target.write('\n')
def _read_json(path, used):
used.add(Path(path))
return json.loads(Path(path).read_text(encoding='utf-8'))
def _read_jsonl(path, used):
used.add(Path(path))
with Path(path).open(encoding='utf-8') as source:
return [json.loads(line) for line in source if line.strip()]
def _read_array(path, used):
used.add(Path(path))
return np.load(path, mmap_mode='r', allow_pickle=False)
def _check(checks, name, condition):
checks[name] = bool(condition)
def _bit_mask(a, b):
if a.dtype.kind == 'f':
unsigned = np.dtype('uint'+str(a.dtype.itemsize*8))
return np.ascontiguousarray(a).view(unsigned) != np.ascontiguousarray(b).view(unsigned)
return a != b
def _compare_array(name, a, b, checks, differences, dtype=None, shape=None):
a, b = np.asarray(a), np.asarray(b)
schema = a.shape == b.shape and a.dtype == b.dtype and \
(dtype is None or a.dtype == np.dtype(dtype)) and (shape is None or a.shape == shape)
_check(checks, name+'.schema', schema)
if not schema:
differences[name] = {'left_shape': list(a.shape), 'right_shape': list(b.shape),
'left_dtype': str(a.dtype), 'right_dtype': str(b.dtype), 'expected_shape': None if shape is None else list(shape),
'expected_dtype': None if dtype is None else str(np.dtype(dtype))}
_check(checks, name+'.bitwise_exact', False)
return False
finite = bool(np.isfinite(a).all() and np.isfinite(b).all())
_check(checks, name+'.finite', finite)
mask = _bit_mask(a, b)
exact = not bool(np.any(mask))
_check(checks, name+'.bitwise_exact', exact)
if not exact or not finite:
flat = np.flatnonzero(mask.ravel())
detail = {'mismatching_elements': int(len(flat)),
'first_positions': [list(map(int, np.unravel_index(int(index), a.shape))) for index in flat[:5]],
'left_nonfinite': int(np.count_nonzero(~np.isfinite(a))),
'right_nonfinite': int(np.count_nonzero(~np.isfinite(b)))}
if finite and a.size:
error = np.abs(a.astype(np.float64)-b.astype(np.float64))
detail.update(max_abs_error=float(error.max()), mean_abs_error=float(error.mean()))
if a.dtype.kind == 'f' and len(flat):
unsigned = np.dtype('uint'+str(a.dtype.itemsize*8))
av = np.ascontiguousarray(a).view(unsigned).ravel()
bv = np.ascontiguousarray(b).view(unsigned).ravel()
detail['first_bit_patterns'] = [{'left': hex(int(av[index])), 'right': hex(int(bv[index]))} for index in flat[:5]]
differences[name] = detail
return exact and finite
def _sha(value):
return isinstance(value, str) and re.fullmatch('[0-9a-f]{64}', value) is not None
def _read_requests(path, steps, used):
used.add(Path(path))
with Path(path).open(encoding='utf-8', newline='') as source:
reader = csv.DictReader(source)
require(tuple(reader.fieldnames or ()) == REQUEST_FIELDS, 'Request CSV schema mismatch: '+str(path))
rows = [{key: int(row[key]) for key in REQUEST_FIELDS} for row in reader]
previous = (-1, -1)
for row in rows:
key = row['tick'], row['neuron_idx']
require(previous < key and 0 <= key[0] < steps and 0 <= key[1] < N_GLOBAL,
'Request rows must be sorted, unique, and in range: '+str(path))
require(row['attempted'] == 1 and row['accepted'] in (0, 1) and row['rejected'] == 1-row['accepted'],
'Request accounting is incomplete: '+str(path))
previous = key
return rows
def _load_run(directory, role, n, edges, steps, record_history, name, delay, used, checks):
directory = Path(directory)
summary = _read_json(directory/'summary.json', used)
_check(checks, role+'.summary_complete', summary.get('complete') is True and summary.get('pass_all') is True and
summary.get('steps') == steps and summary.get('completed_ticks') == steps and
summary.get('nodes') == n and summary.get('edges') == edges and summary.get('precision') == 'float64')
is_cpu = role == 'cpu'
_check(checks, role+'.case_name', summary.get('name' if is_cpu else 'case') == name)
_check(checks, role+'.history_mode', summary.get('history_recorded' if is_cpu else 'record_history') is record_history)
_check(checks, role+'.apl_precision', summary.get('APL_precision' if is_cpu else 'apl_precision') == 'float32')
_check(checks, role+'.no_error_marker', not (directory/'error.json').exists())
used.add(directory/'state.npz')
with np.load(directory/'state.npz', allow_pickle=False) as source:
require(set(source.files) == set(STATE_KEYS), 'State NPZ keys changed: '+str(directory))
state = {key: source[key].copy() for key in STATE_KEYS}
for key, dtype in (('v', 'float64'), ('g', 'float64'), ('ref', 'int32'), ('counts', 'int32')):
require(state[key].shape == (n,) and state[key].dtype == np.dtype(dtype), 'Invalid final '+key+': '+str(directory))
require(state['step'].dtype == state['neuron_idx'].dtype == np.int32 and state['step'].ndim == 1 and
state['step'].shape == state['neuron_idx'].shape, 'Invalid sparse event schema: '+str(directory))
require(bool(np.all((state['step'] >= 0) & (state['step'] < steps))) and
bool(np.all((state['neuron_idx'] >= 0) & (state['neuron_idx'] < N_GLOBAL))), 'Sparse event range error')
event_keys = state['step'].astype(np.int64)*N_GLOBAL+state['neuron_idx']
_check(checks, role+'.events_sorted_unique', len(event_keys) < 2 or np.all(np.diff(event_keys) > 0))
_check(checks, role+'.count_nonnegative_total', np.all(state['counts'] >= 0) and int(state['counts'].sum()) == len(event_keys))
_check(checks, role+'.ref_range', np.all((state['ref'] >= 0) & (state['ref'] <= 22)))
_check(checks, role+'.reported_events', summary.get('spikes' if is_cpu else 'total_spikes') == len(event_keys))
hashes = _read_jsonl(directory/'tick-state-hashes.jsonl', used)
require(len(hashes) == steps and [row.get('tick') for row in hashes] == list(range(steps)), 'Incomplete tick hash coverage')
require(all(set(row) == HASH_FIELDS and all(_sha(row[key]) for key in HASH_FIELDS-{'tick'}) for row in hashes),
'Invalid tick state hash schema')
queues = _read_jsonl(directory/'queue.jsonl', used)
require(len(queues) == steps and [row.get('tick') for row in queues] == list(range(steps)), 'Incomplete queue coverage')
require(all(set(row) == QUEUE_FIELDS and type(row['count']) is int and type(row['accepted_count']) is int and
0 <= row['accepted_count'] <= row['count'] <= edges and
all(_sha(row[key]) for key in QUEUE_FIELDS-{'tick', 'count', 'accepted_count'}) for row in queues),
'Invalid queue row schema/count/hash')
for key in ('v', 'g', 'ref'):
_check(checks, role+'.last_hash_'+key, hashes[-1][key+'_sha256'] == raw_hash(state[key], '<i4' if key == 'ref' else '<f8'))
requests = _read_requests(directory/'requests.csv', steps, used)
requested, accepted = len(requests), sum(row['accepted'] for row in requests)
_check(checks, role+'.request_summary', summary.get('requests' if is_cpu else 'requested') == requested and
summary.get('applicable_requests' if is_cpu else 'accepted_requests') == accepted and
summary.get('ref_rejected_requests' if is_cpu else 'rejected_requests') == requested-accepted)
apl = {field: _read_array(directory/('apl-'+field+'.float32.npy'), used) for field in ('drive', 'state', 'inhibition', 'applied')}
for field, width in (('drive', 2), ('state', 2), ('inhibition', 4064), ('applied', 4064)):
require(apl[field].dtype == np.float32 and apl[field].shape == (steps, width), 'Invalid APL '+field+' history schema')
_check(checks, role+'.apl_positive_'+field, np.all(apl[field] >= 0))
pending = _read_array(directory/'apl-pending-tail.float32.npy', used)
require(pending.dtype == np.float32 and pending.shape == (delay, 4064), 'Invalid pending APL queue schema')
timing = _read_json(directory/'apl-timing-audit.json', used)
_check(checks, role+'.delay_summary', type(summary.get('apl_delay_steps')) is int and summary['apl_delay_steps'] == delay)
histories, pre = {}, {}
for field, dtype in (('v', 'float64'), ('g', 'float64'), ('ref', 'int32')):
files = (directory/(field+'-history.'+dtype+'.npy'), directory/('preAPL-'+field+'.'+dtype+'.npy'))
if record_history:
histories[field], pre[field] = (_read_array(path, used) for path in files)
require(all(array.dtype == np.dtype(dtype) and array.shape == (steps, n) for array in (histories[field], pre[field])),
'Small pre/post history schema mismatch')
_check(checks, role+'.history_hashes_'+field, all(row[field+'_sha256'] == raw_hash(histories[field][tick])
for tick, row in enumerate(hashes)))
_check(checks, role+'.history_final_'+field, not np.any(_bit_mask(histories[field][-1], state[field])))
else:
_check(checks, role+'.no_dense_'+field, not any(path.exists() for path in files))
if is_cpu:
component = _read_json(directory/'apl-worker-handshake.json', used)['handshake']
else:
component = _read_json(directory/'apl-component.json', used)
_check(checks, role+'.component_summary_consistent', summary.get('apl_component') == component)
return dict(directory=directory, summary=summary, state=state, hashes=hashes, queues=queues,
requests=requests, apl=apl, pending=pending, timing=timing,
histories=histories, pre=pre, component=component)
def _pair_outputs(left, right, checks, differences, n, steps, record_history):
for field in STATE_KEYS:
shape = None if field in ('step', 'neuron_idx') else (n,)
dtype = 'float64' if field in ('v', 'g') else 'int32'
_compare_array('state.'+field, left['state'][field], right['state'][field], checks, differences, dtype, shape)
for field, width in (('drive', 2), ('state', 2), ('inhibition', 4064), ('applied', 4064)):
_compare_array('apl.'+field, left['apl'][field], right['apl'][field], checks, differences, 'float32', (steps, width))
_compare_array('apl.pending', left['pending'], right['pending'], checks, differences, 'float32', left['pending'].shape)
for field in ('hashes', 'queues', 'requests', 'component'):
same = left[field] == right[field]
_check(checks, field+'.parsed_exact', same)
if not same:
if isinstance(left[field], list):
first = next((i for i, (a, b) in enumerate(zip(left[field], right[field])) if a != b), None)
differences[field] = {'left_count': len(left[field]), 'right_count': len(right[field]),
'first_differing_row': first,
'left_row': None if first is None else left[field][first],
'right_row': None if first is None else right[field][first]}
else:
differences[field] = {'left': left[field], 'right': right[field]}
if record_history:
for stage in ('histories', 'pre'):
for field, dtype in (('v', 'float64'), ('g', 'float64'), ('ref', 'int32')):
_compare_array(stage+'.'+field, left[stage][field], right[stage][field], checks, differences, dtype, (steps, n))
def _queue_digest(tick, ids, accepted):
ids = np.ascontiguousarray(ids, dtype='<i8').tobytes()
mask = np.ascontiguousarray(accepted, dtype=np.uint8).tobytes()
return {'tick': tick, 'count': len(mask), 'accepted_count': int(np.count_nonzero(accepted)),
'ordered_edge_sha256': hashlib.sha256(ids).hexdigest(),
'accepted_mask_sha256': hashlib.sha256(mask).hexdigest(),
'joint_sha256': hashlib.sha256(b'phase4af-queue-v1\0'+struct.pack('<qq', tick, len(mask))+ids+mask).hexdigest()}
def _independent_event_accounting(run, role, graph, requested, steps, checks, differences):
nodes, ptr = graph['nodes'], graph['ptr']
n = len(nodes)
state = run['state']
local = np.searchsorted(nodes, state['neuron_idx'])
require(np.all(local < n) and np.array_equal(nodes[local], state['neuron_idx']), 'Actual spike outside graph identity')
_check(checks, role+'.events_per_neuron_counts', np.array_equal(np.bincount(local, minlength=n), state['counts']))
actual_request_pairs = [(row['tick'], row['neuron_idx']) for row in run['requests']]
_check(checks, role+'.requests_match_frozen_input', actual_request_pairs == requested)
require(actual_request_pairs == requested, 'Actual request population/time differs from frozen input')
bounds = np.searchsorted(state['step'], np.arange(steps+1))
request_ticks = np.asarray([row['tick'] for row in run['requests']], np.int32)
rbounds = np.searchsorted(request_ticks, np.arange(steps+1))
request_nodes = np.asarray([row['neuron_idx'] for row in run['requests']], np.int32)
request_local = np.searchsorted(nodes, request_nodes)
require(np.all(request_local < n) and np.array_equal(nodes[request_local], request_nodes), 'Request outside graph')
last = np.full(n, -1_000_000_000, np.int64)
degrees = np.diff(ptr)
expected_counts = np.zeros(steps, np.int64)
arrival_tick = state['step'].astype(np.int64)+18
valid = arrival_tick < steps
np.add.at(expected_counts, arrival_tick[valid], degrees[local[valid]])
_check(checks, role+'.delayed_all_edges_count', np.array_equal(expected_counts, [row['count'] for row in run['queues']]))
request_ok, delivered_ok, ref_ok, queue_ok, reset_ok = True, True, True, True, True
first = {}
for tick in range(steps):
fired = local[bounds[tick]:bounds[tick+1]]
lo, hi = rbounds[tick:tick+2]
targets = request_local[lo:hi]
accepted = (tick-last[targets]) >= 22
for index, ok in zip(range(lo, hi), accepted):
row = run['requests'][index]
if row['accepted'] != int(ok) or row['rejected'] != int(not ok):
request_ok = False
first.setdefault('request_ref_mismatch', {'tick': tick, 'neuron_idx': row['neuron_idx']})
if not np.isin(targets[accepted], fired).all() or np.isin(targets[~accepted], fired).any():
delivered_ok = False
first.setdefault('request_delivery_mismatch', tick)
last[fired] = tick
ref = np.maximum(22-(tick-last), 0).astype(np.int32)
if raw_hash(ref, '<i4') != run['hashes'][tick]['ref_sha256']:
ref_ok = False
first.setdefault('ref_hash_mismatch', tick)
if run['pre']:
if len(fired) and not np.array_equal(np.ascontiguousarray(run['pre']['g'][tick, fired]).view(np.uint64), np.zeros(len(fired), np.uint64)):
reset_ok = False
first.setdefault('pre_apl_spike_reset_mismatch', tick)
due = local[bounds[tick-18]:bounds[tick-17]] if tick >= 18 else np.empty(0, np.int64)
chunks = [np.arange(ptr[source], ptr[source+1], dtype=np.int64) for source in due]
indices = np.concatenate(chunks) if chunks else np.empty(0, np.int64)
expected_queue = _queue_digest(tick, graph['edge_id'][indices], (ref[graph['dst'][indices]] == 0).astype(np.uint8))
if expected_queue != run['queues'][tick]:
queue_ok = False
first.setdefault('queue_reconstruction_mismatch', tick)
_check(checks, role+'.request_refractory_gate', request_ok)
_check(checks, role+'.accepted_spikes_rejected_absent', delivered_ok)
_check(checks, role+'.all_ref_hashes_from_actual_events', ref_ok)
if run['pre']:
_check(checks, role+'.small_queue_independent_reconstruction', queue_ok)
_check(checks, role+'.spike_g_reset_before_apl', reset_ok)
if first:
differences[role+'.independent_accounting'] = first
def _check_apl_application(run, role, nodes, kc, checks, differences):
if not run['pre']:
return
common, local_kc, bundle_kc = np.intersect1d(nodes, kc, assume_unique=True, return_indices=True)
_compare_array(role+'.apl_keeps_voltage', run['pre']['v'], run['histories']['v'], checks, differences, 'float64')
_compare_array(role+'.apl_keeps_ref', run['pre']['ref'], run['histories']['ref'], checks, differences, 'int32')
expected = np.array(run['pre']['g'], copy=True)
delta = run['apl']['applied'][:, bundle_kc].astype(np.float64)*np.float64(.001)
expected[:, local_kc] = expected[:, local_kc]-delta
_compare_array(role+'.apl_unconditional_g_write', expected, run['histories']['g'], checks, differences, 'float64')
def _timing_sequence_checks(generated, applied, pending, delay, role, checks, differences):
"""Independent slice-based reconstruction; does not import either queue."""
require(type(delay) is int and delay in (0, 18), 'Invalid fixed APL delay')
for key, value in (('generated', generated), ('applied', applied), ('pending', pending)):
require(isinstance(value, np.ndarray) and value.ndim == 2 and value.dtype == np.float32,
'Invalid timing array '+key)
steps, width = generated.shape
require(width > 0 and applied.shape == (steps, width) and pending.shape == (delay, width),
'Timing sequence dimensions do not partition the declared window')
_check(checks, role+'.timing_finite_nonnegative',
all(np.isfinite(value).all() and np.all(value >= 0) for value in (generated, applied, pending)))
consumed = max(steps-delay, 0)
expected_applied = np.zeros_like(generated)
if consumed:
expected_applied[delay:] = generated[:consumed]
expected_pending = np.zeros((delay, width), dtype=np.float32)
generated_pending = min(steps, delay)
if generated_pending:
expected_pending[delay-generated_pending:] = generated[consumed:]
_compare_array(role+'.fixed_delay_applied', applied, expected_applied, checks, differences,
'float32', (steps, width))
_compare_array(role+'.fixed_delay_pending', pending, expected_pending, checks, differences,
'float32', (delay, width))
_check(checks, role+'.finite_sequence_row_conservation', consumed+generated_pending == steps)
def _timing_metadata_checks(run, role, delay, steps, checks):
"""Validate declared limits against actual queue and generated APL state."""
timing, summary = run['timing'], run['summary']
count, prefix = min(steps, delay), max(delay-steps, 0)
expected = {'apl_delay_steps': delay, 'steps': steps, 'pending_generated_count': count,
'generated_rows': steps, 'applied_generated_rows': max(steps-delay, 0),
'pending_initial_zero_prefix': prefix, 'pending_application_tick_start': steps,
'pending_application_tick_stop_exclusive': steps+delay,
'pending_generated_tick_start': max(steps-delay, 0),
'pending_generated_tick_stop_exclusive': steps}
_check(checks, role+'.timing_integer_metadata',
all(type(timing.get(key)) is int and timing[key] == value for key, value in expected.items()))
_check(checks, role+'.pending_hash_metadata', timing.get('pending_raw_sha256') == raw_hash(run['pending'], '<f4'))
_check(checks, role+'.pending_shape_metadata', timing.get('pending_shape') == [delay, 4064])
_check(checks, role+'.pending_summary_counts',
type(summary.get('pending_generated_count')) is int and summary['pending_generated_count'] == count and
type(summary.get('pending_initial_zero_prefix')) is int and summary['pending_initial_zero_prefix'] == prefix and
summary.get('pending_tail_shape') == [delay, 4064] and
summary.get('future_generated_decay_tail_included') is False)
state = np.asarray(run['apl']['state'][-1], dtype=np.float32)
state_values, state_bits = timing.get('final_apl_state_float32'), timing.get('final_apl_state_u32_bits')
valid_state = isinstance(state_values, list) and len(state_values) == 2 and isinstance(state_bits, list) and len(state_bits) == 2
if valid_state:
try:
value = np.asarray(state_values, dtype=np.float32)
valid_state = np.array_equal(value.view(np.uint32), state.view(np.uint32)) and \
all(type(x) is int for x in state_bits) and state_bits == state.view(np.uint32).tolist()
except (ValueError, TypeError, OverflowError):
valid_state = False
_check(checks, role+'.final_apl_state_metadata', valid_state and
timing.get('final_apl_state_nonzero') is bool(np.any(state != 0)))
if role == 'cpu':
_check(checks, role+'.no_extra_brain_or_apl_ticks',
type(timing.get('brain_steps_after_window')) is int and timing['brain_steps_after_window'] == 0 and
type(timing.get('APL_generation_steps_after_window')) is int and timing['APL_generation_steps_after_window'] == 0 and
timing.get('future_generated_decay_tail_included') is False and
summary.get('future_generated_decay_tail_included') is False and
summary.get('APL_worker_ticks') == steps)
_check(checks, role+'.timing_summary_metadata',
summary.get('pending_generated_count') == count and
summary.get('pending_initial_zero_prefix') == prefix and
summary.get('pending_tail_shape') == [delay, 4064])
else:
_check(checks, role+'.no_extra_brain_or_apl_ticks',
timing.get('brain_tail_advanced') is False and
timing.get('future_apl_decay_or_feedback_generated') is False and
timing.get('finite_generated_sequence_only') is True and
timing.get('closed_loop_branch_integrals_claimed_equal') is False and
timing.get('biological_delay_measurement_claimed') is False)
_check(checks, role+'.timing_summary_metadata', summary.get('apl_timing') == timing)
def _finish(report, checks, differences, used, out_json):
report['checks'] = {name: bool(value) for name, value in checks.items()}
report['differences'] = differences
report['pass_all'] = bool(checks) and all(checks.values()) and 'error' not in report
report['failed_checks'] = sorted(name for name, value in checks.items() if not value)
report['evidence_sha256'] = {str(path): file_hash(path) for path in sorted(used) if path.is_file()}
save(out_json, report)
return report
def compare(case_dir, gpu_dir, cpu_dir, out_json=None):
"""Strict independent closed-loop comparison; out_json=None is read-only."""
case_dir, gpu_dir, cpu_dir = Path(case_dir), Path(gpu_dir), Path(cpu_dir)
if out_json is not None:
require(not Path(out_json).exists(), 'Refusing existing comparison report')
checks, differences, used = {}, {}, set()
report = {'kind': 'shared-APL-component closed-loop byte-exact comparison', 'pass_all': False,
'case_dir': str(case_dir), 'gpu_dir': str(gpu_dir), 'cpu_dir': str(cpu_dir),
'tolerance': None, 'signed_zero_included': True, 'timing_fields_compared': False,
'independent_CPU_all_components_claim': False, 'finite_generated_sequence_accounting_only': True,
'cross_delay_closed_loop_integrals_claimed_equal': False, 'biological_delay_measurement_claimed': False,
'scientific_apl_delay_fields_compared': True}
try:
spec = _read_json(case_dir/'spec.json', used)
steps, history = spec['steps'], spec['record_history']
delay = spec['apl_delay_steps']
require(type(delay) is int and delay in (0, 18), 'Explicit fixed delay 0 or 18 required')
require(type(steps) is int and steps > 0 and type(history) is bool and spec['dt_ms'] == .1,
'Invalid fixed case clock/history schema')
graph_dir, bundle_dir = Path(spec['graph_dir']), Path(spec['apl_bundle_dir'])
graph = {field: _read_array(graph_dir/(field+'.npy'), used) for field in
('nodes', 'edge_id', 'src', 'dst', 'ptr', 'signed_raw', 'weights')}
nodes = graph['nodes']
n, edges = len(nodes), len(graph['edge_id'])
require(n > 0 and edges > 0 and nodes.dtype == np.int32 and nodes.ndim == 1 and np.all((nodes >= 0) & (nodes < N_GLOBAL)) and
np.all(np.diff(nodes) > 0), 'Invalid canonical node identities')
require(graph['ptr'].dtype == np.int64 and graph['ptr'].shape == (n+1,) and graph['ptr'][0] == 0 and
graph['ptr'][-1] == edges and np.all(np.diff(graph['ptr']) >= 0), 'Invalid CSR')
for key, dtype in (('edge_id', 'int64'), ('src', 'int32'), ('dst', 'int32'), ('signed_raw', 'int64'), ('weights', 'float64')):
require(graph[key].dtype == np.dtype(dtype) and graph[key].shape == (edges,), 'Invalid graph '+key)
require(np.array_equal(graph['src'], np.repeat(np.arange(n, dtype=np.int32), np.diff(graph['ptr']))) and
np.all((graph['dst'] >= 0) & (graph['dst'] < n)), 'Invalid source/destination row mapping')
require(history == (n < 512) and (n < 512 or n == N_GLOBAL), 'Invalid small/full history declaration')
require(np.all(graph['edge_id'] >= 0) and np.all(np.diff(graph['edge_id']) > 0),
'Original canonical edge IDs must be unique and increasing')
if n == N_GLOBAL:
require(edges == 25582938 and np.array_equal(nodes, np.arange(n, dtype=np.int32)) and
np.array_equal(graph['edge_id'], np.arange(edges, dtype=np.int64)), 'Full canonical graph identity changed')
bundle = {name: _read_array(bundle_dir/name, used) for name in BUNDLE_FILES}
kc, apl_ids = bundle['kc_globals.npy'], bundle['apl_globals.npy']
require(kc.dtype == apl_ids.dtype == np.int32 and kc.shape == (4064,) and apl_ids.shape == (2,), 'Invalid APL/KC identities')
require(np.all((kc >= 0) & (kc < N_GLOBAL)) and np.all(np.diff(kc) > 0) and
np.all((apl_ids >= 0) & (apl_ids < N_GLOBAL)) and np.all(np.diff(apl_ids) > 0) and
not np.intersect1d(kc, apl_ids).size, 'APL/KC identities overlap or are invalid')
for key, shape in (('input_matrix.npy', (2, N_GLOBAL)), ('output_matrix.npy', (2, 4064))):
require(bundle[key].dtype == np.float32 and bundle[key].shape == shape and
np.isfinite(bundle[key]).all() and np.all(bundle[key] >= 0), 'Invalid normalized APL matrix')
gpu = _load_run(gpu_dir, 'gpu', n, edges, steps, history, spec['name'], delay, used, checks)
cpu = _load_run(cpu_dir, 'cpu', n, edges, steps, history, spec['name'], delay, used, checks)
_pair_outputs(gpu, cpu, checks, differences, n, steps, history)
used.add(case_dir/'requests.npz')
with np.load(case_dir/'requests.npz', allow_pickle=False) as source:
require(set(source.files) == {'tick', 'neuron_idx'} and source['tick'].dtype == source['neuron_idx'].dtype == np.int32,
'Fixed request NPZ schema changed')
require(source['tick'].shape == source['neuron_idx'].shape and source['tick'].ndim == 1, 'Invalid sparse request shape')
requested = list(zip(map(int, source['tick']), map(int, source['neuron_idx'])))
for role, run in (('gpu', gpu), ('cpu', cpu)):
_independent_event_accounting(run, role, graph, requested, steps, checks, differences)
_check_apl_application(run, role, nodes, kc, checks, differences)
_timing_sequence_checks(run['apl']['inhibition'], run['apl']['applied'], run['pending'],
delay, role, checks, differences)
_timing_metadata_checks(run, role, delay, steps, checks)
# Independently derive the effective clone. Original graph weights stay read-only.
cpu_weights = _read_array(cpu_dir/'weights.npy', used)
require(cpu_weights.dtype == np.float64 and cpu_weights.shape == (edges,), 'CPU effective weight schema mismatch')
expected_hash, base_hash, mask_hash = hashlib.sha256(), hashlib.sha256(), hashlib.sha256()
weight_ok, mask_count = True, 0
for start in range(0, edges, 1 << 20):
stop = min(edges, start+(1 << 20))
original = np.asarray(graph['weights'][start:stop])
require(np.isfinite(original).all(), 'Nonfinite original weights')
raw_expected = graph['signed_raw'][start:stop]*(.275*.001)
require(not np.any(_bit_mask(original, raw_expected)), 'Original SI weights differ from unaltered signed contacts')
mask = np.isin(nodes[graph['src'][start:stop]], apl_ids)
expected = original.copy()
expected[mask] = np.float64(0)
mask_count += int(mask.sum())
expected_hash.update(np.ascontiguousarray(expected, dtype='<f8').tobytes())
base_hash.update(np.ascontiguousarray(original, dtype='<f8').tobytes())
mask_hash.update(np.ascontiguousarray(graph['edge_id'][start:stop][mask], dtype='<i8').tobytes())
weight_ok &= not np.any(_bit_mask(expected, cpu_weights[start:stop]))
expected_sha = expected_hash.hexdigest()
_check(checks, 'cpu.effective_weights_independent_bytes', weight_ok)
for role, run in (('gpu', gpu), ('cpu', cpu)):
_check(checks, role+'.effective_weights_raw_sha', run['summary'].get('effective_weights_raw_sha256') == expected_sha)
_check(checks, role+'.apl_fast_edge_count', run['summary'].get('apl_fast_edges_zeroed') == mask_count)
_check(checks, role+'.kc_target_count', run['summary'].get('kc_targets_present') == len(np.intersect1d(nodes, kc)))
mask_audit = _read_json(cpu_dir/'apl-mask-audit.json', used)
_check(checks, 'cpu.mask_provenance', mask_audit['count'] == mask_count and
mask_audit['ordered_original_edge_id_sha256'] == mask_hash.hexdigest() and
mask_audit['base_weight_raw_bytes_sha256'] == base_hash.hexdigest() and
mask_audit['effective_weights_raw_sha256'] == expected_sha and mask_audit['base_graph_files_modified'] is False)
case_hashes = {name: file_hash(case_dir/name) for name in ('spec.json', 'requests.npz')}
if (case_dir/'arrays.npz').exists():
case_hashes['arrays.npz'] = file_hash(case_dir/'arrays.npz')
used.add(case_dir/'arrays.npz')
baseline_coeff = _read_json(Path(spec['coefficients_path']), used)
actual_coeff = _read_json(cpu_dir/'coefficients.json', used)
_check(checks, 'cpu.actual_author_coefficients_exact', all(float(actual_coeff[key]).hex() == float(baseline_coeff[key]).hex()
for key in COEFFICIENTS))
audit = _read_json(cpu_dir/'input-audit.json', used)
expected_graph_hashes = {name: file_hash(graph_dir/name) for name in
tuple(field+'.npy' for field in graph)+('completeness.csv', 'connectivity.parquet')}
bundle_hashes = {name: file_hash(bundle_dir/name) for name in BUNDLE_FILES}
_check(checks, 'cpu.read_actual_case', audit['spec'] == spec and audit['case_hashes'] == case_hashes)
_check(checks, 'cpu.graph_hashes', audit['graph_hashes'] == expected_graph_hashes)
_check(checks, 'cpu.bundle_hashes', audit['bundle_hashes'] == bundle_hashes)
_check(checks, 'cpu.no_candidate_trace_input', audit.get('candidate_trace_used_as_input') is False and
cpu['summary'].get('candidate_trace_used_as_input') is False)
_check(checks, 'cpu.worker_source_hash', audit['legacy_apl_worker_sha256'] == file_hash(spec['legacy_apl_worker']))
_check(checks, 'cpu.coefficient_input_hash', audit['coefficients_sha256'] == file_hash(spec['coefficients_path']))
gpu_hashes = dict(case_hashes, **{'base_weights.npy': file_hash(graph_dir/'weights.npy'),
'coefficients.json': file_hash(spec['coefficients_path'])})
_check(checks, 'gpu.input_hashes', gpu['summary']['input_sha256'] == gpu_hashes)
for role, run in (('gpu', gpu), ('cpu', cpu)):
component = run['component']
_check(checks, role+'.actual_component_bundle_bytes', component['files_sha256'] == bundle_hashes and
component['array_sha256'] == {name: raw_hash(value) for name, value in bundle.items()})
_check(checks, role+'.component_dimensions_clock', component.get('ok') is True and
component['protocol'] == 'phase4ag-apl-v1' and component['n_neurons'] == N_GLOBAL and
component['n_apl'] == 2 and component['n_kc'] == 4064 and component['dt_ms'] == .1)
decay = np.float32(math.exp(-.1/20.0))
gain = np.float32(.01)
_check(checks, role+'.frozen_apl_constants', component['decay_f32_bits'] == f'{int(decay.view(np.uint32)):08x}' and
component['gain_f32_bits'] == f'{int(gain.view(np.uint32)):08x}')
env = component['environment']
_check(checks, role+'.component_precision_environment', env['cuda_matmul_allow_tf32'] is False and
env['float32_matmul_precision'] == 'highest' and env['precision_configuration_changed_by_component'] is False and
'4090' in env['device_name'])
environment = _read_json(cpu_dir/'environment.json', used)
_check(checks, 'cpu.pinned_environment', environment['packages']['brian2'] == '2.5.1' and
environment['packages']['numpy'] == '1.22.3' and environment['packages']['sympy'] == '1.12' and
environment['Torch_imported_into_Brian'] is False and environment['author_precision'] == 'float64')
queue_audit = _read_json(cpu_dir/'queue-audit.json', used)
_check(checks, 'cpu.queue_observer_coverage', queue_audit['peek_calls'] == queue_audit['advance_calls'] == steps and
queue_audit['same_peek_object_returned'] is True and queue_audit['zero_weight_and_refractory_rejected_edges_retained'] is True)
_check(checks, 'cpu.sidecar_complete', cpu['summary']['APL_worker_exit_status'] == 0 and cpu['summary']['APL_worker_ticks'] == steps)
report.update(case=spec['name'], steps=steps, nodes=n, edges=edges, record_history=history, apl_delay_steps=delay,
total_spikes=len(gpu['state']['step']), active_neurons=int(np.count_nonzero(gpu['state']['counts'])),
requested=len(requested), accepted_requests=sum(row['accepted'] for row in gpu['requests']),
rejected_requests=sum(row['rejected'] for row in gpu['requests']),
arriving_edges=sum(row['count'] for row in gpu['queues']),
accepted_arriving_edges=sum(row['accepted_count'] for row in gpu['queues']),
apl_fast_edges_zeroed=mask_count, effective_weights_raw_sha256=expected_sha,
component_environment=gpu['component']['environment'],
limits=['APL Torch primitives are shared; original AST component validation is a separate required gate.',
'Small cases preserve and independently hash all pre/post states; full cases compare all-tick instrumented state hashes without saving dense whole-brain histories.',
'For full cases intermediate finite checks are performed by the instrumented backends; this file independently inspects final states and all APL traces.',
'Fixed-delay checks conserve this run\'s finite generated sample sequence, including pending initial zeros; no tail brain advancement or equality of different closed-loop branches is claimed.',
'This is exact agreement for the declared trajectory, not physiological validity or learning.'])
except Exception as error:
report['error'] = {'type': type(error).__name__, 'message': str(error)}
return _finish(report, checks, differences, used, out_json)
def compare_gpu_repeats(first, second, out_json=None):
"""Repeat equality only; the first run's independent oracle gate is separate."""
first, second = Path(first), Path(second)
if out_json is not None:
require(not Path(out_json).exists(), 'Refusing existing repeat report')
checks, differences, used = {}, {}, set()
report = {'kind': 'fresh-GPU-run exact repeat comparison', 'first': str(first), 'second': str(second),
'pass_all': False, 'tolerance': None, 'signed_zero_included': True, 'timing_fields_compared': False,
'scientific_apl_delay_fields_compared': True,
'scope': 'Scientific outputs, recording integrity and input hashes; independent case/graph audit belongs to compare()'}
try:
summary = _read_json(first/'summary.json', used)
n, edges, steps, name, history = (summary[key] for key in ('nodes', 'edges', 'steps', 'case', 'record_history'))
delay = summary['apl_delay_steps']
require(type(delay) is int and delay in (0, 18), 'Explicit repeat APL delay required')
require(type(n) is int and type(edges) is int and type(steps) is int and n > 0 and edges > 0 and steps > 0 and
type(history) is bool and history == (n < 512), 'Invalid repeat dimensions')
left = _load_run(first, 'first_gpu', n, edges, steps, history, name, delay, used, checks)
right = _load_run(second, 'second_gpu', n, edges, steps, history, name, delay, used, checks)
_pair_outputs(left, right, checks, differences, n, steps, history)
for role, run in (('first_gpu', left), ('second_gpu', right)):
_timing_sequence_checks(run['apl']['inhibition'], run['apl']['applied'], run['pending'],
delay, role, checks, differences)
_timing_metadata_checks(run, role, delay, steps, checks)
stable = ('case', 'complete', 'pass_all', 'steps', 'completed_ticks', 'nodes', 'edges', 'precision',
'apl_precision', 'state_units', 'total_spikes', 'requested', 'accepted_requests', 'rejected_requests',
'arriving_edges', 'accepted_arriving_edges', 'counts_match_sparse_events', 'all_finite', 'record_history',
'apl_fast_edges_zeroed', 'kc_targets_present', 'effective_weights_raw_sha256', 'apl_schedule',
'apl_si_conversion', 'build', 'sealed_ae_backend_sha256', 'learning', 'input_sha256',
'apl_delay_steps', 'apl_timing', 'source_provenance', 'pending_generated_count',
'pending_initial_zero_prefix', 'pending_tail_shape', 'future_generated_decay_tail_included')
for key in stable:
_check(checks, 'summary.'+key, key in left['summary'] and key in right['summary'] and
left['summary'][key] == right['summary'][key])
if not checks['summary.'+key]:
differences['summary.'+key] = {'first': left['summary'].get(key), 'second': right['summary'].get(key)}
report.update(case=name, steps=steps, nodes=n, edges=edges, record_history=history, apl_delay_steps=delay,
total_spikes=len(left['state']['step']),
explicit_exclusions=['wall_seconds', 'diagnostic_simulation_seconds', 'build_or_cache_seconds',
'peak_allocated_vram_bytes', 'peak_reserved_vram_bytes'])
except Exception as error:
report['error'] = {'type': type(error).__name__, 'message': str(error)}
return _finish(report, checks, differences, used, out_json)
@@ -0,0 +1,24 @@
{
"phase": "4AJ",
"name": "apl-timing-lab-v1",
"human_authorization": "允许独立新模型分支测试动力学假设",
"gpu_uuid": "GPU-79f3a85d-adce-7833-7003-6488140ca596",
"neurons": 166700,
"edges": 25582938,
"raw_weight_sum": 124177617,
"delays_steps": [0, 18],
"dt_ms": 0.1,
"apl": {"tau_ms": 20.0, "gain": 0.01, "normalization": 1.0},
"fixtures": ["zero", "pn_pulse", "kc_ref_boundary", "two_sources", "arrival_collision", "natural_request", "apl_only", "high_fanin"],
"fixture_repeats": 3,
"calibration": {"split": "calibration", "odor_count": 6, "modes": ["physiological", "matched_energy"], "seeds": [51101,51102,51103,51104,51105], "duration_ms": 100.0, "median_scope": "original frozen 12-odor panel", "full_oracle_probes": ["cal-physiological-00-s51101", "cal-matched_energy-00-s51101"], "repeat_first_seed_each_odor": true},
"gates": {"sparse_min_fraction": 0.03, "sparse_max_fraction": 0.09, "max_fraction_strict": 0.5, "min_fraction_strict": 0.0, "minimum_separable_odor_pairs": 3, "same_jaccard_gt_between": true, "between_euclidean_gt_within": true, "both_modes_required": true, "finite_required": true, "repeat_exact_required": true},
"output_budget_bytes": 25769803776,
"origin_audit_budget_bytes": 2147483648,
"training": false,
"heldout_dynamic_access": false,
"candidate_generation": false,
"hypothesis": "Only delay the entire generated graded-APL h by 18 exact steps; zero delay is a fresh replay of sealed AG control. Engineering scheduling parity, not measured MaleCNS physiology. No change to I/O, gain, state update, fast-APL zero mask, neuron coefficients, inputs or biological observation window.",
"tail_contract": "pending tail is the next D queue slots, shape(D,4064); if T<D its initial zero prefix is not generated future output. Do not advance the brain or APL after the original window. Closed-loop h totals are not forced to match.",
"selection_policy": "Both arms and all fixed CAL cases retained regardless of representation outcome. Stop later scientific execution on numerical/oracle/integrity failure. No scan, tuning, favorable seed or result selection."
}
@@ -0,0 +1,92 @@
"""Independent APL scheduling hypothesis; every earlier artifact is read-only."""
import hashlib
import importlib.util
import json
import sys
from pathlib import Path
ROOT = Path('/data/digital-drosophila')
MODEL = Path(__file__).resolve().parent
EXP = ROOT / 'experiments/phase4aj-apl-timing'
AI_MODEL = ROOT / 'models/male-cns-lif/pn-recruitment-audit-v1'
AI = ROOT / 'experiments/phase4ai-pn-recruitment-audit'
AH_MODEL = ROOT / 'models/male-cns-lif/kc-drive-audit-v1'
AG_MODEL = ROOT / 'models/male-cns-lif/author-apl-lab-v2'
AG = ROOT / 'experiments/phase4ag-author-apl-r2'
META = ROOT / 'datasets/male-cns-v1.0/processed/neuron-only/neuron-index/unified-metadata.parquet'
COEFF = ROOT / 'experiments/phase4af-author-fullgraph/oracle/no_input/coefficients.json'
CFG = json.loads((MODEL / 'config.json').read_text(encoding='utf-8'))
def load_module(name, path):
spec = importlib.util.spec_from_file_location(name, path)
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
spec.loader.exec_module(module)
return module
def digest(path):
h = hashlib.sha256()
with Path(path).open('rb') as f:
for block in iter(lambda: f.read(8 << 20), b''):
h.update(block)
return h.hexdigest()
def read(path):
return json.loads(Path(path).read_text(encoding='utf-8'))
def save(path, value):
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
with path.open('x', encoding='utf-8') as f:
json.dump(value, f, indent=2, ensure_ascii=False, allow_nan=False)
f.write('\n')
def sources():
return {p.relative_to(MODEL).as_posix(): digest(p) for p in sorted(MODEL.rglob('*')) if p.is_file()
and '__pycache__' not in p.parts and p.name not in ('manifest.json', 'checksums.sha256')}
def integrity():
previous = load_module('sealed_ai_context_aj', AI_MODEL / 'context.py')
result = previous.integrity()
sys.path.insert(0, str(ROOT / 'models/male-cns-lif/terminal-scope-diagnostic-v1'))
from diagnostic import manifest_check
for path in (AI_MODEL, AI):
result[str(path.relative_to(ROOT))] = manifest_check(path, digest)
assert all(r['pass'] for r in result.values())
return result
def check():
registered = read(EXP / 'protocol/preregistered.json')
assert registered['sources'] == sources(), 'Registered sources changed'
for row in registered['inputs']:
assert digest(ROOT / row['path']) == row['sha256'], row['path']
for row in read(EXP / 'protocol/prepared-hashes.json'):
assert digest(EXP / row['path']) == row['sha256'], row['path']
return registered
def budget():
size = sum(p.stat().st_size for p in EXP.rglob('*') if p.is_file())
assert size < CFG['output_budget_bytes'], 'Output budget exceeded; preserve partial work'
return size
def seal(root):
rows = [dict(path=str(p.relative_to(root)), bytes=p.stat().st_size, sha256=digest(p))
for p in sorted(root.rglob('*')) if p.is_file() and '__pycache__' not in p.parts]
save(root / 'manifest.json', dict(root=str(root), files=rows))
with (root / 'checksums.sha256').open('x') as f:
for row in rows:
f.write(row['sha256'] + ' ' + row['path'] + '\n')
f.write(digest(root / 'manifest.json') + ' manifest.json\n')
def bit_equal(a, b):
return a.dtype == b.dtype and a.shape == b.shape and a.tobytes() == b.tobytes()
@@ -0,0 +1,156 @@
"""Recheck raw evidence and seal this explicit scheduling hypothesis, not learning."""
from context import ROOT, MODEL, EXP, AG, CFG, check, save, read, digest, integrity, budget, seal
def optional(path):
return read(path) if path.exists() else None
def main():
from compare_timing import compare, compare_gpu_repeats
from calibration import control_identity, summarize
check(); budget()
arms = ['delay' + str(delay) for delay in CFG['delays_steps']]
expected_cases = CFG['fixtures'] + CFG['calibration']['full_oracle_probes']
comparisons, repeats, controls, components = {}, {}, {}, {}
for arm in arms:
for name in expected_cases:
path = EXP / 'audit' / f'compare-{arm}-{name}.json'
if path.exists():
actual = compare(EXP / 'cases' / arm / name, EXP / 'gpu' / arm / (name + '-r0'), EXP / 'oracle' / arm / name, None)
assert actual == read(path), 'Changed raw oracle evidence: ' + arm + '/' + name
comparisons[arm + '/' + name] = actual['pass_all']
path = EXP / 'component-audit' / arm / (name + '.json')
if path.exists():
report = read(path)
assert set(report.get('input_sha256', {})) == {'state.npz', 'summary.json',
'apl-drive.float32.npy', 'apl-state.float32.npy', 'apl-inhibition.float32.npy'}
for filename, sha in report['input_sha256'].items():
assert digest(EXP / 'gpu' / arm / (name + '-r0') / filename) == sha
assert set(report.get('matrix_checks', {})) == {'input_matrix', 'output_matrix', 'input_raw', 'output_raw',
'kc_globals', 'apl_globals', 'pn_globals', 'apl_out_ids', 'input_scale', 'output_scale'}
assert set(report.get('ast_replay_bitwise_exact', {})) == {'drive', 'state', 'inhibition'}
assert set(report.get('float64_measurement', {})) == {'drive', 'state', 'inhibition'}
actual_pass = bool(not report.get('error') and all(report['matrix_checks'].values()) and
all(report['ast_replay_bitwise_exact'].values()) and report['theoretical_bound']['applicable'] and
all(metric['bound_violations'] == 0 for metric in report['float64_measurement'].values()))
assert report['pass_all'] == actual_pass
components[arm + '/' + name] = actual_pass
for name in CFG['fixtures']:
for repeat in range(1, CFG['fixture_repeats']):
path = EXP / 'audit' / f'repeat-{arm}-{name}-r{repeat}.json'
if path.exists():
actual = compare_gpu_repeats(EXP / 'gpu' / arm / (name + '-r0'), EXP / 'gpu' / arm / f'{name}-r{repeat}', None)
assert actual == read(path), 'Changed raw repeat evidence'
repeats[f'{arm}/{name}-r{repeat}'] = actual['pass_all']
for name in expected_cases:
path = EXP / 'audit' / f'control-{name}.json'
if path.exists():
actual = control_identity(EXP / 'gpu/delay0' / (name + '-r0'), AG / 'gpu' / (name + '-r0'), EXP / 'cases/delay0' / name)
assert actual == read(path), 'Changed delay0 control evidence'
controls[name] = actual['pass_all']
origin = optional(EXP / 'origin-audit/summary.json')
cal_records = read(EXP / 'protocol/calibration-cases.json')
origin_complete = False
if origin:
expected_origin = {row['name']: row for row in cal_records}
assert len(expected_origin) == len(cal_records) == 60
assert len(origin['trials']) == 60 and {row['case'] for row in origin['trials']} == set(expected_origin)
for row in origin['trials']:
original = expected_origin[row['case']]
assert row['repeat'] == 0 and row['ALLN_targets'] == 420 and row['pass_all']
assert set(row['exact']) == {'step', 'neuron_idx', 'counts', 'v', 'g', 'ref'} and all(row['exact'].values())
assert all(row[key] == original[key] for key in ('mode', 'odor_id', 'seed'))
origin_complete = True
for row in origin['trials']:
trial = EXP / 'origin-audit' / row['case']
assert digest(trial / 'summary.json') == row['summary_sha256']
for payload in read(trial / 'output-hashes.json'):
assert digest(trial / payload['path']) == payload['sha256']
for filename, sha in read(trial / 'summary.json')['input_sha256'].items():
assert digest(ROOT / filename) == sha
shift = optional(EXP / 'audit/shift-gate.json')
shift_complete = False
if shift:
expected_shift = {(name, delay) for name in CFG['fixtures'] + [row['name'] for row in cal_records] for delay in CFG['delays_steps']}
assert len(shift['records']) == len(expected_shift) == 136
assert {(row['case'], row['delay_steps']) for row in shift['records']} == expected_shift
assert all(row['pass_all'] for row in shift['records'])
shift_complete = True
from shift_audit import transport
import numpy as np
for row in shift['records']:
source = AG / 'gpu' / (row['case'] + '-r0') / 'apl-inhibition.float32.npy'
assert digest(source) == row['input_sha256']
_, _, actual = transport(np.load(source, mmap_mode='r', allow_pickle=False), row['delay_steps'])
assert all(row[key] == value for key, value in actual.items())
cal = optional(EXP / 'calibration/summary.json')
if cal is not None:
assert summarize(out_json=None) == cal, 'CAL scientific evidence changed'
expected = {arm + '/' + name for arm in arms for name in expected_cases}
expected_repeats = {f'{arm}/{name}-r{repeat}' for arm in arms for name in CFG['fixtures'] for repeat in range(1, CFG['fixture_repeats'])}
numerical = bool(origin_complete and origin['pass_all'] and shift_complete and shift['pass_all'] and
set(comparisons) == set(components) == expected and set(repeats) == expected_repeats and
set(controls) == set(expected_cases) and all(comparisons.values()) and all(components.values()) and
all(repeats.values()) and all(controls.values()))
gates = {name: optional(EXP / 'audit' / (name + '-gate.json')) for name in ('fixtures', 'probes', 'calibration')}
numerical = numerical and all(gates[name] and gates[name]['pass_all'] for name in ('fixtures', 'probes'))
cal_execution = bool(cal and cal['execution_gate_pass'] and gates['calibration'] and gates['calibration']['pass_all'])
treatment_pass = bool(cal and cal.get('arms', {}).get('delay18', {}).get('original_representation_gate_pass', False))
baseline_pass = bool(cal and cal.get('arms', {}).get('delay0', {}).get('original_representation_gate_pass', False))
frozen = read(EXP / 'regression/frozen-five.json')
after = integrity()
save(EXP / 'regression/old-integrity-after.json', after)
oldpass = bool(frozen['pass_all'] and all(row['pass'] for row in after.values()))
if not oldpass:
status = 'FAIL-FROZEN-INTEGRITY-OR-REGRESSION'
elif numerical and cal_execution:
status = 'PASS-FIXED-CAL-APL-TIMING-HYPOTHESIS' if treatment_pass else 'FAIL-FIXED-CAL-APL-TIMING-HYPOTHESIS'
elif (any(not passed for group in (comparisons, components, repeats, controls) for passed in group.values()) or
any(report is not None and not report['pass_all'] for report in (origin, shift, *gates.values())) or
cal is not None and not cal['execution_gate_pass']):
status = 'FAIL-NUMERICAL-OR-CONTROL-GATE'
else:
status = 'INCOMPLETE-NUMERICAL-OR-CAL-EXECUTION'
measurements = []
for path in sorted((EXP / 'gpu').glob('*/*/summary.json')):
summary = read(path)
measurements.append(dict(arm=path.parent.parent.name, run=path.parent.name,
**{key: summary[key] for key in ('case', 'total_spikes', 'accepted_requests', 'nodes', 'edges',
'diagnostic_simulation_seconds', 'peak_allocated_vram_bytes')}))
result = dict(status=status, numerical_gate_pass=bool(numerical), full_CAL_execution_gate_pass=cal_execution,
delay0_representation_pass=baseline_pass, delay18_representation_pass=treatment_pass,
origin_audit=origin, fixed_trace_shift=shift, gates=gates, comparisons=comparisons,
repeats=repeats, controls=controls, components=components, calibration=cal,
stopped=[dict(path=str(path.relative_to(EXP)), report=read(path)) for path in sorted((EXP / 'audit').glob('stopped-*.json'))],
old_frozen_integrity_and_five_reference_pass=oldpass, measurements=measurements,
unchanged_APL_parameters=CFG['apl'], explicit_hypothesis=CFG['hypothesis'],
delay_steps=CFG['delays_steps'], biological_delay_measured=False,
APL_nonKC_fast_edges_unreplaced=1212, shared_APL_arithmetic_oracle_limitation=True,
whole_brain_equal_inhibition_integral_claim=False, universal_equivalence_claim=False,
heldout_generalization_tested=False, learning_achieved=False, candidate_generated=False,
payload_bytes_before_manifest=budget(),
next_gate='Independent seeds and novel-odor representation; then credit specificity and functional learning' if numerical and cal_execution and treatment_pass
else 'Report the first failed gate for this fixed hypothesis; no tuning or conditioning promotion')
save(EXP / 'audit/final-status.json', result)
with (EXP / 'REPORT.md').open('x', encoding='utf-8') as stream:
stream.write('\n'.join(['# Phase 4AJ — fixed graded-APL timing branch', '', f'Status: `{status}`.', '',
f'Numerical gate: {numerical}. Complete both CAL arms: {cal_execution}.',
f'Original representation gate: delay0={baseline_pass}; delay18={treatment_pass}.',
'Only generated h application time changes: zero versus 18 steps. No brain gain, input, learning or mask change.',
'This is an engineering scheduling hypothesis, not measured MaleCNS APL delay. It delays PN- and KC-derived h together.',
'Finite stored generated samples are preserved in applied output or pending tail; the brain is not advanced to flush the tail.',
'Closed-loop generated h and accepted requests can differ between arms; equal total inhibition is not assumed.',
'Independent Brian LIF and candidate share legacy Torch APL arithmetic; component and separate delay-queue audits qualify this limit.',
'Original fast APL mask still leaves 1,212 non-KC edges unreplaced. No silent scope change.',
'The origin audit identifies timed real-edge antecedents, not unique or necessary biological causes.',
f'Frozen checksums and five reference trials: {oldpass}.',
'Costs include diagnostic synchronization, IPC, hashes and tracing; these are not production runtime benchmarks.',
'No heldout trajectories, conditioning, learned model, reward interface, game, decoder or candidate.',
'Next gate: ' + result['next_gate'], '']))
check(); seal(MODEL); seal(EXP)
print(status, flush=True)
if __name__ == '__main__':
main()
@@ -0,0 +1,453 @@
"""Phase 4AJ isolated fixed-delay graded-APL timing branch.
Copied from sealed AG-r2 gpu_apl.py; only dynamics change is a 0/18-step
float32 output delay before the unchanged unconditional end-stage g write.
The sealed LegacyAPL and AE CUDA operators are loaded explicitly, unmodified.
Generated h is still logged separately. No extra brain/tail ticks are run.
This is engineering schedule parity, not a measured biological delay claim.
"""
from functools import lru_cache
import csv
import difflib
import importlib.util
import hashlib
import json
import math
from pathlib import Path
import time
import traceback
import sys
import numpy as np
import torch
from timing_queue import audit_sequence
SOURCE_ROOT = Path(__file__).resolve().parent
AE_MODEL = SOURCE_ROOT.parent / "author-runtime-lab-v1"
AF_MODEL = SOURCE_ROOT.parent / "author-fullgraph-lab-v1"
AG_MODEL = SOURCE_ROOT.parent / "author-apl-lab-v2"
N_NEURONS = 166700
SEALED_SHA256 = {
"ag_gpu": "69f5d893f47dafff4ef7c3186c3df0b9014666b32c8f4e943b57016bec92b18a",
"ag_worker": "21ceec65fe42581dc55872010e0025d660e80358905f1cf4df1dadf341a3b291",
"ae_backend": "03758d07572f4b44d272059d9308fac534268ad201b57bdd77d69fee95e67278",
"af_queue": "d72003d98f0f1624b12126eff50bd361c43d888f4a64d90ba9247a58976f1961",
}
COEFFICIENT_NAMES = ("gd", "c0", "cg", "cv", "threshold", "reset", "seed_volt")
REQUEST_FIELDS = ("tick", "neuron_idx", "attempted", "accepted", "rejected")
def require(condition, message):
if not condition:
raise ValueError(message)
def write_json(path, value):
with Path(path).open("x", encoding="utf-8") as output:
json.dump(value, output, indent=2, allow_nan=False)
output.write("\n")
def raw_hash(value, dtype):
return hashlib.sha256(np.ascontiguousarray(value, dtype=dtype).tobytes()).hexdigest()
def file_sha256(path):
digest = hashlib.sha256()
with Path(path).open("rb") as source:
for block in iter(lambda: source.read(8 << 20), b""):
digest.update(block)
return digest.hexdigest()
def load_source(path, name, expected_hash):
"""Load a sealed source under a unique name; never patch its globals."""
path = Path(path)
require(file_sha256(path) == expected_hash, "Sealed source changed: " + str(path))
spec = importlib.util.spec_from_file_location(name, path)
require(spec is not None and spec.loader is not None, "Cannot load sealed module")
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
try:
spec.loader.exec_module(module)
except BaseException:
sys.modules.pop(name, None)
raise
return module
@lru_cache(maxsize=1)
def sealed_apl():
return load_source(AG_MODEL / "legacy_apl_worker.py", "phase4aj_sealed_ag_worker",
SEALED_SHA256["ag_worker"])
def source_audit(out_dir):
sources = {"ag_gpu": AG_MODEL / "gpu_apl.py", "ag_worker": AG_MODEL / "legacy_apl_worker.py",
"ae_backend": AE_MODEL / "gpu_backend.py", "af_queue": AF_MODEL / "oracle_full.py"}
actual = {key: file_sha256(path) for key, path in sources.items()}
require(actual == SEALED_SHA256, "Sealed implementation hash mismatch")
diff_path = out_dir / "sealed-gpu-source.diff"
with diff_path.open("x", encoding="utf-8", newline="\n") as output:
output.writelines(difflib.unified_diff(
sources["ag_gpu"].read_text(encoding="utf-8").splitlines(keepends=True),
Path(__file__).read_text(encoding="utf-8").splitlines(keepends=True),
fromfile="sealed-author-apl-lab-v2/gpu_apl.py",
tofile="new-apl-timing-lab-v1/gpu_timing.py"))
audit = {"sealed_source_sha256": actual, "candidate_sha256": file_sha256(__file__),
"source_diff_sha256": file_sha256(diff_path),
"module_globals_patched": False,
"only_dynamics_change": "fixed zero-initialized 0/18-step h32 delay before unchanged end g write",
"diagnostic_additions": ["generated/applied/pending trace split", "fixed-sequence bitwise audit",
"source provenance and final APL state disclosure"]}
write_json(out_dir / "source-audit.json", audit)
return audit
@lru_cache(maxsize=1)
def sealed_backend():
return load_source(AE_MODEL / "gpu_backend.py", "phase4aj_sealed_ae_backend", SEALED_SHA256["ae_backend"])
@lru_cache(maxsize=1)
def queue_function():
return load_source(AF_MODEL / "oracle_full.py", "phase4aj_sealed_af_queue", SEALED_SHA256["af_queue"]).queue_summary
@lru_cache(maxsize=4)
def load_graph(graph_directory):
root = Path(graph_directory)
require(root.is_absolute(), "graph_dir must be absolute")
graph = {}
for name, dtype in (("nodes", np.int32), ("edge_id", np.int64), ("src", np.int32),
("dst", np.int32), ("signed_raw", np.int64), ("ptr", np.int64),
("weights", np.float64)):
value = np.load(root / (name + ".npy"), mmap_mode="r", allow_pickle=False)
require(value.dtype == dtype and value.ndim == 1, "Graph dtype/rank mismatch: " + name)
graph[name] = value
nodes, edges = graph["nodes"], graph["edge_id"]
n, e = len(nodes), len(edges)
require(0 < n <= N_NEURONS and bool(np.all((nodes >= 0) & (nodes < N_NEURONS))) and
bool(np.all(np.diff(nodes) > 0)), "Global node IDs must be sorted unique")
require(n < 512 or (n == N_NEURONS and np.array_equal(nodes, np.arange(N_NEURONS, dtype=np.int32))),
"Only small fixtures or the intact frozen full graph are permitted")
require(n != N_NEURONS or e == 25582938, "Full graph edge count changed")
for name in ("src", "dst", "signed_raw", "weights"):
require(graph[name].shape == (e,), "Graph edge array length mismatch: " + name)
ptr = graph["ptr"]
require(ptr.shape == (n + 1,) and ptr[0] == 0 and ptr[-1] == e and
bool(np.all(np.diff(ptr) >= 0)), "Invalid graph CSR")
require(np.array_equal(graph["src"], np.repeat(np.arange(n, dtype=np.int32), np.diff(ptr))),
"Source order does not match CSR")
# Global edge IDs need not equal local row indices in a fixture.
for start in range(0, e, 1 << 20):
stop = min(start + (1 << 20), e)
require(bool(np.all((graph["dst"][start:stop] >= 0) & (graph["dst"][start:stop] < n))),
"Local destination out of range")
require(bool(np.isfinite(graph["weights"][start:stop]).all()), "Nonfinite base SI weights")
require(np.array_equal(np.sign(graph["weights"][start:stop]), np.sign(graph["signed_raw"][start:stop])),
"Base weight sign/zero pattern differs from frozen raw contacts")
lo = max(0, start - 1)
require(bool(np.all(edges[start:stop] >= 0)) and bool(np.all(np.diff(edges[lo:stop]) > 0)),
"Global edge IDs must retain canonical increasing source/edge order")
return graph
def load_inputs(case_dir):
spec = json.loads((case_dir / "spec.json").read_text(encoding="utf-8"))
for name in ("name", "steps", "dt_ms", "duration_ms", "model", "graph_dir", "apl",
"apl_bundle_dir", "coefficients_path", "record_history", "apl_delay_steps"):
require(name in spec, "Missing case field: " + name)
require(type(spec["apl_delay_steps"]) is int and spec["apl_delay_steps"] in (0, 18),
"apl_delay_steps must be integer 0 or 18")
steps = spec["steps"]
require(type(steps) is int and 0 < steps <= 1000 and float(spec["dt_ms"]) == .1 and
float(spec["duration_ms"]) == steps * .1, "Unexpected steps/dt/duration")
require(type(spec["record_history"]) is bool, "record_history must be Boolean")
require(spec["apl"] == {"tau_ms": 20, "gain": .01, "normalization": 1}, "Frozen APL parameters changed")
for name in ("graph_dir", "apl_bundle_dir", "coefficients_path"):
require(Path(spec[name]).is_absolute(), "Input path must be absolute: " + name)
model = spec["model"]
for name in ("resting_potential_mv", "threshold_mv", "reset_potential_mv", "synaptic_delay_ms",
"refractory_ms", "w_syn_mv_per_anatomical_synapse"):
require(name in model and math.isfinite(float(model[name])), "Invalid model field: " + name)
require(float(model["synaptic_delay_ms"]) == 1.8 and float(model["refractory_ms"]) == 2.2 and
float(model["w_syn_mv_per_anatomical_synapse"]) == .275, "Frozen delay/ref/W_syn changed")
coeff = json.loads(Path(spec["coefficients_path"]).read_text(encoding="utf-8"))
for name in COEFFICIENT_NAMES:
require(name in coeff and math.isfinite(float(coeff[name])), "Invalid author coefficient: " + name)
require(coeff["threshold"] == float(model["threshold_mv"]) * .001 and
coeff["reset"] == float(model["reset_potential_mv"]) * .001, "Coefficient threshold/reset mismatch")
graph = load_graph(str(Path(spec["graph_dir"]).resolve()))
n = len(graph["nodes"])
require(spec["record_history"] == (n < 512), "Fixtures need dense history; full graph must not duplicate dense histories")
with np.load(case_dir / "requests.npz", allow_pickle=False) as source:
require(set(source.files) == {"tick", "neuron_idx"}, "Request sparse schema changed")
ticks, requested = source["tick"].copy(), source["neuron_idx"].copy()
require(ticks.dtype == np.int32 and requested.dtype == np.int32 and ticks.ndim == 1 and
ticks.shape == requested.shape, "Invalid sparse request dtype/shape")
require(bool(np.all((ticks >= 0) & (ticks < steps))), "Request tick outside trial")
if len(ticks) > 1:
require(bool(np.all((ticks[1:] > ticks[:-1]) |
((ticks[1:] == ticks[:-1]) & (requested[1:] > requested[:-1])))),
"Requests must be sorted unique by tick/global neuron")
local = np.searchsorted(graph["nodes"], requested)
require(bool(np.all(local < n)) and np.array_equal(graph["nodes"][local], requested),
"Requested neuron absent from graph")
initial = {"initial_v_mv": np.full(n, float(model["resting_potential_mv"]), dtype=np.float64),
"initial_g_mv": np.zeros(n, dtype=np.float64)}
initial_path = case_dir / "arrays.npz"
if initial_path.exists():
with np.load(initial_path, allow_pickle=False) as source:
require(set(source.files).issubset(initial), "Unexpected initial-state array")
for name in source.files:
value = source[name]
require(value.dtype == np.float64 and value.shape == (n,) and bool(np.isfinite(value).all()),
"Invalid initial state: " + name)
initial[name] = value.copy()
return spec, graph, coeff, ticks, requested, local, initial
def new_array(path, dtype, shape):
require(not Path(path).exists(), "Refusing existing output: " + str(path))
return np.lib.format.open_memmap(path, mode="w+", dtype=dtype, shape=shape)
def run_gpu(case_dir, out_dir, build_root):
"""Run fresh candidate state; never consume oracle/candidate APL traces.
pass_all denotes internal recording/finite integrity only. Independent
comparison and the original complete representation gate are separate.
"""
case_dir, out_dir = Path(case_dir), Path(out_dir)
require(not out_dir.exists(), "Refusing existing output directory: " + str(out_dir))
out_dir.mkdir(parents=True, exist_ok=False)
start, tick, completed = time.perf_counter(), -1, 0
maps = {}
try:
source_provenance = source_audit(out_dir)
spec, graph, coeff, request_ticks, request_nodes, request_local, initial = load_inputs(case_dir)
require(torch.cuda.is_available() and torch.cuda.device_count() == 1 and
"4090" in torch.cuda.get_device_name(), "Only the declared single visible RTX4090 is permitted")
ext, build = sealed_backend().build_extension(build_root)
build_done = time.perf_counter()
apl = sealed_apl().LegacyAPL(spec["apl_bundle_dir"], spec["dt_ms"])
write_json(out_dir / "apl-component.json", apl.metadata)
device = apl.device
torch.cuda.reset_peak_memory_stats(device)
n, e, steps = len(graph["nodes"]), len(graph["edge_id"]), spec["steps"]
def upload(value, dtype):
return torch.from_numpy(np.array(value, copy=True, order="C")).to(device=device, dtype=dtype).contiguous()
indptr, dst = upload(graph["ptr"], torch.int64), upload(graph["dst"], torch.int32)
global_nodes_gpu = upload(graph["nodes"], torch.int64)
base_weights = upload(graph["weights"], torch.float64)
weights = base_weights.clone()
del base_weights
local_apl = np.flatnonzero(np.isin(graph["nodes"], apl.apl_globals)).astype(np.int64)
apl_out_mask = np.isin(graph["src"], local_apl)
if bool(np.any(apl_out_mask)):
weights[upload(apl_out_mask, torch.bool)] = 0.0
effective_hash = hashlib.sha256()
for offset in range(0, e, 1 << 20):
effective_hash.update(weights[offset:offset + (1 << 20)].cpu().numpy().astype("<f8", copy=False).tobytes())
common_kc, local_kc, full_kc = np.intersect1d(graph["nodes"], apl.kc_globals, assume_unique=True, return_indices=True)
kc_local_gpu, kc_full_gpu = upload(local_kc, torch.int64), upload(full_kc, torch.int64)
v = upload(initial["initial_v_mv"] * .001, torch.float64)
g = upload(initial["initial_g_mv"] * .001, torch.float64)
ref = torch.zeros(n, device=device, dtype=torch.int32)
counts = torch.zeros(n, device=device, dtype=torch.int32)
requests = torch.zeros(n, device=device, dtype=torch.uint8)
ring = torch.zeros((19, n), device=device, dtype=torch.uint8)
apl_delay = spec["apl_delay_steps"]
apl_ring = torch.zeros((apl_delay, 4064), device=device, dtype=torch.float32)
maps["apl_applied"] = new_array(out_dir / "apl-applied.float32.npy", np.float32, (steps, 4064))
for name, width in (("drive", 2), ("state", 2), ("inhibition", 4064)):
maps["apl_" + name] = new_array(out_dir / ("apl-" + name + ".float32.npy"), np.float32, (steps, width))
if spec["record_history"]:
for name, dtype in (("v", np.float64), ("g", np.float64), ("ref", np.int32)):
maps[name] = new_array(out_dir / (name + "-history." + np.dtype(dtype).name + ".npy"), dtype, (steps, n))
maps["pre_" + name] = new_array(out_dir / ("preAPL-" + name + "." + np.dtype(dtype).name + ".npy"), dtype, (steps, n))
event_steps, event_nodes = [], []
accepted_requests_total, due_total, accepted_due_total = 0, 0, 0
queue_summary = queue_function()
simulation_start = time.perf_counter()
with (out_dir / "queue.jsonl").open("x", encoding="utf-8", buffering=1) as queue_output, \
(out_dir / "tick-state-hashes.jsonl").open("x", encoding="utf-8", buffering=1) as hash_output, \
(out_dir / "requests.csv").open("x", encoding="utf-8", newline="", buffering=1) as request_output:
writer = csv.DictWriter(request_output, fieldnames=REQUEST_FIELDS)
writer.writeheader()
for tick in range(steps):
requests.zero_()
begin, end = np.searchsorted(request_ticks, (tick, tick + 1))
if end > begin:
requested_local_gpu = upload(request_local[begin:end], torch.int64)
requests[requested_local_gpu] = 1
accepted = (ref[requested_local_gpu] <= 1).to(torch.uint8).cpu().numpy()
accepted_requests_total += int(accepted.sum())
writer.writerows({"tick": tick, "neuron_idx": int(node), "attempted": 1,
"accepted": int(ok), "rejected": 1 - int(ok)}
for node, ok in zip(request_nodes[begin:end], accepted))
spikes = ring[tick % 19]
ext.state_step(v, g, ref, requests, spikes, counts,
*[float(coeff[name]) for name in COEFFICIENT_NAMES], 22)
expanded_global = np.empty(0, dtype=np.int64)
accepted_cpu = np.empty(0, dtype=np.uint8)
if tick >= 18:
due = ring[(tick - 18) % 19]
sources = torch.nonzero(due, as_tuple=False).flatten().contiguous()
if sources.numel():
degrees = indptr[sources + 1] - indptr[sources]
offsets = (torch.cumsum(degrees, dim=0) - degrees).contiguous()
edge_count = int(degrees.sum().item())
expanded = torch.empty(edge_count, device=device, dtype=torch.int64)
ext.fill_edges(indptr, sources, offsets, expanded)
if edge_count:
destination = dst[expanded]
# Actual active fanout order, BEFORE stable target grouping.
expanded_global = graph["edge_id"][expanded.cpu().numpy()].copy()
accepted_cpu = (ref[destination.long()] == 0).to(torch.uint8).cpu().numpy().copy()
order = torch.argsort(destination, stable=True)
ordered_edges, ordered_targets = expanded[order].contiguous(), destination[order]
boundary = torch.ones(edge_count, device=device, dtype=torch.bool)
boundary[1:] = ordered_targets[1:] != ordered_targets[:-1]
starts = torch.nonzero(boundary, as_tuple=False).flatten().contiguous()
targets = ordered_targets[starts].contiguous()
ext.apply_arrivals(ordered_edges, starts, targets, weights, g, ref)
queue = queue_summary(tick, expanded_global, accepted_cpu)
queue_output.write(json.dumps(queue, allow_nan=False) + "\n")
due_total += queue["count"]
accepted_due_total += queue["accepted_count"]
if spec["record_history"]:
for name, value in (("v", v), ("g", g), ("ref", ref)):
maps["pre_" + name][tick] = value.cpu().numpy()
if n == N_NEURONS:
full_spikes = spikes
else:
apl.spikes.zero_()
apl.spikes[global_nodes_gpu] = spikes
full_spikes = apl.spikes
drive, apl_state, h = apl.advance(full_spikes)
if apl_delay == 0:
applied_h = h # Exact legacy identity; no extra arithmetic.
else:
slot = tick % apl_delay
applied_h = apl_ring[slot].clone()
apl_ring[slot].copy_(h)
# Mixed precision contract: widen f32 h EXACTLY, THEN multiply
# in f64, THEN subtract in f64. Do not guard refractory KCs.
delta_si = applied_h[kc_full_gpu].to(torch.float64) * 0.001
g[kc_local_gpu] = g[kc_local_gpu] - delta_si
apl_cpu = {"drive": drive.cpu().numpy().copy(), "state": apl_state.cpu().numpy().copy(),
"inhibition": h.cpu().numpy().copy(), "applied": applied_h.cpu().numpy().copy()}
for name, value in apl_cpu.items():
maps["apl_" + name][tick] = value
actual = {"v": v.cpu().numpy().copy(), "g": g.cpu().numpy().copy(),
"ref": ref.cpu().numpy().copy()}
finite = all(bool(np.isfinite(value).all()) for value in list(actual.values()) + list(apl_cpu.values()))
row = {"tick": tick, **{name + "_sha256": raw_hash(value, "<i4" if name == "ref" else "<f8")
for name, value in actual.items()}}
hash_output.write(json.dumps(row, allow_nan=False) + "\n")
if spec["record_history"]:
for name, value in actual.items():
maps[name][tick] = value
fired_local = torch.nonzero(spikes, as_tuple=False).flatten().cpu().numpy()
if len(fired_local):
event_steps.append(np.full(len(fired_local), tick, dtype=np.int32))
event_nodes.append(graph["nodes"][fired_local].copy())
completed += 1
if not finite:
with (out_dir / "first-failure-state.npz").open("xb") as target:
np.savez_compressed(target, tick=np.array(tick, dtype=np.int32), **actual,
**{"apl_" + name: value for name, value in apl_cpu.items()})
require(False, "Nonfinite state; first failure saved")
torch.cuda.synchronize(device)
def joined(values):
return np.concatenate(values).astype(np.int32, copy=False) if values else np.empty(0, dtype=np.int32)
state = {"step": joined(event_steps), "neuron_idx": joined(event_nodes), "counts": counts.cpu().numpy(),
"v": v.cpu().numpy(), "g": g.cpu().numpy(), "ref": ref.cpu().numpy()}
with (out_dir / "state.npz").open("xb") as target:
np.savez_compressed(target, **state)
event_locals = np.searchsorted(graph["nodes"], state["neuron_idx"])
counts_exact = np.array_equal(np.bincount(event_locals, minlength=n), state["counts"])
require(counts_exact and completed == steps, "Sparse events/counts/completed ticks mismatch")
for value in maps.values():
value.flush()
# Save the queue state, not an invented future APL/brain decay trace.
if apl_delay:
head = steps % apl_delay
ring_cpu = apl_ring.cpu().numpy()
pending = np.concatenate((ring_cpu[head:], ring_cpu[:head]), axis=0)
else:
pending = np.empty((0, 4064), dtype=np.float32)
with (out_dir / "apl-pending-tail.float32.npy").open("xb") as target:
np.save(target, pending, allow_pickle=False)
timing = audit_sequence(maps["apl_inhibition"], maps["apl_applied"], pending, apl_delay)
final_apl_state = apl.state.cpu().numpy().copy()
timing.update({
"generated_rows": steps,
"applied_generated_rows": max(steps - apl_delay, 0),
"pending_shape": [apl_delay, 4064],
"pending_application_tick_start": steps,
"pending_application_tick_stop_exclusive": steps + apl_delay,
"pending_generated_tick_start": max(0, steps - apl_delay),
"pending_generated_tick_stop_exclusive": steps,
"generated_trace": "apl-inhibition.float32.npy",
"applied_trace": "apl-applied.float32.npy",
"pending_trace": "apl-pending-tail.float32.npy",
"pending_raw_sha256": raw_hash(pending, "<f4"),
"final_apl_state_float32": final_apl_state.tolist(),
"final_apl_state_u32_bits": final_apl_state.view(np.uint32).tolist(),
"final_apl_state_nonzero": bool(np.any(final_apl_state != 0)),
"pending_queue_drained": apl_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,
})
write_json(out_dir / "apl-timing-audit.json", timing)
summary = {"case": spec["name"], "complete": True, "pass_all": True,
"pass_all_scope": "internal finite/recording/event-count integrity only; independent equivalence not claimed",
"steps": steps, "completed_ticks": completed, "nodes": n, "edges": e, "precision": "float64",
"apl_precision": "float32", "state_units": "SI volts", "total_spikes": len(state["step"]),
"requested": len(request_nodes), "accepted_requests": accepted_requests_total,
"rejected_requests": len(request_nodes) - accepted_requests_total,
"arriving_edges": due_total, "accepted_arriving_edges": accepted_due_total,
"counts_match_sparse_events": bool(counts_exact), "all_finite": True,
"record_history": spec["record_history"], "apl_fast_edges_zeroed": int(apl_out_mask.sum()),
"kc_targets_present": len(common_kc), "effective_weights_raw_sha256": effective_hash.hexdigest(),
"apl_component": apl.metadata, "apl_schedule": "end, after threshold/reset and guarded arrivals, unconditional all KC",
"apl_si_conversion": "applied h32 -> float64 -> multiply float64 0.001 -> separate float64 subtraction",
"apl_delay_steps": apl_delay, "apl_timing": timing, "source_provenance": source_provenance,
"pending_generated_count": min(steps, apl_delay),
"pending_initial_zero_prefix": max(apl_delay - steps, 0),
"pending_tail_shape": [apl_delay, 4064], "future_generated_decay_tail_included": False,
"build": build, "sealed_ae_backend_sha256": file_sha256(AE_MODEL / "gpu_backend.py"),
"shared_apl_component_oracle_limitation": True, "oracle_validation_claim": False,
"learning": False, "performance_runtime_claim": False, "cpu_sync_each_tick": True,
"build_or_cache_seconds": build_done - start,
"diagnostic_simulation_seconds": time.perf_counter() - simulation_start,
"wall_seconds": time.perf_counter() - start,
"peak_allocated_vram_bytes": int(torch.cuda.max_memory_allocated(device)),
"peak_reserved_vram_bytes": int(torch.cuda.max_memory_reserved(device)),
"input_sha256": {"spec.json": file_sha256(case_dir / "spec.json"),
"requests.npz": file_sha256(case_dir / "requests.npz"),
"base_weights.npy": file_sha256(Path(spec["graph_dir"]) / "weights.npy"),
"coefficients.json": file_sha256(spec["coefficients_path"])}}
if (case_dir / "arrays.npz").exists():
summary["input_sha256"]["arrays.npz"] = file_sha256(case_dir / "arrays.npz")
write_json(out_dir / "summary.json", summary)
return summary
except Exception as error:
for value in maps.values():
value.flush()
write_json(out_dir / "error.json", {"complete": False, "pass_all": False,
"tick_in_progress": tick, "completed_ticks": completed,
"type": type(error).__name__, "message": str(error), "traceback": traceback.format_exc()})
raise
@@ -0,0 +1,110 @@
{
"root": "/data/digital-drosophila/models/male-cns-lif/apl-timing-lab-v1",
"files": [
{
"path": "PROTOCOL.md",
"bytes": 4272,
"sha256": "d96aef0107f7b0791d16e475b749da418b8a38d2c56a94e0779de0cd6581a7de"
},
{
"path": "al_origin_audit.py",
"bytes": 33399,
"sha256": "7201871477a29ede31c7d6c6bf1c92700da3db5505e67ccfa7cb43126b8464b9"
},
{
"path": "calibration.py",
"bytes": 22786,
"sha256": "fb15ddeaa108305c8de697bbae36b23ab0414a7c58db51c66dce9feb4a048a0d"
},
{
"path": "compare_timing.py",
"bytes": 41221,
"sha256": "9010f070fba9b7c9cf2d86187ee2abc57f3ac606ebc08a42baad4f3922b51734"
},
{
"path": "config.json",
"bytes": 2149,
"sha256": "0b720e23aa7988b2b443e14951082b1ce9b061a183b7f858c0e0f3c0fc6fb25e"
},
{
"path": "context.py",
"bytes": 3436,
"sha256": "06d4994af3729d653263391ff3a3604f7c919e78562604e5c86acfa292d60ba0"
},
{
"path": "finalize.py",
"bytes": 11254,
"sha256": "0a2dbf9e5f889e9dd3491d036e6f92c17417a84482c5e1e49134c0993f7d68f2"
},
{
"path": "gpu_timing.py",
"bytes": 27083,
"sha256": "af1975ba5e5e700208c0a598d3cbe648a3cf10885c6231239b6e4b28f76d173b"
},
{
"path": "oracle_timing.py",
"bytes": 55279,
"sha256": "39d8c47c94bc2faddf016864a43e7715907fb987f56f7b27098060a88851f6be"
},
{
"path": "prepare.py",
"bytes": 5970,
"sha256": "bba71bcd52dcb78d9ae0fa93a8a43173a4669ecef038dce18ce7d82edd9bce50"
},
{
"path": "run_case.py",
"bytes": 2855,
"sha256": "d93e4fe2df542ce5a0f0adb5aceada583dc8c921f0159f426e50428d79d67a1d"
},
{
"path": "run_suite.py",
"bytes": 6161,
"sha256": "6f26c626acf9ef8e6fae7902af0cbf0bd176eb322529ca8aa203a9700716c889"
},
{
"path": "shift_audit.py",
"bytes": 2114,
"sha256": "46f380dac340acc91f226968bb493475a31777f8290fb20f9145a97c9009d845"
},
{
"path": "test_al_origin_audit.py",
"bytes": 9998,
"sha256": "4b75a39d36090b0a66cc7ad4b370ac785713fb58c366df2efcc55152d612fc2b"
},
{
"path": "test_calibration.py",
"bytes": 14734,
"sha256": "307a2848bf6d05aaa8105bb3558be2a74425894f96a4a2bd20af8b82cb8b6e25"
},
{
"path": "test_protocol.py",
"bytes": 10402,
"sha256": "cbae93c993ac9aa99bcce68ae2131c7f938f8a63e89779f8d3d79e36bf268dee"
},
{
"path": "tests/__init__.py",
"bytes": 76,
"sha256": "bfc0d9e17410c2c52ea1d9a5259c92964f16b118dbae8cecad258697b67e4bdc"
},
{
"path": "tests/test_compare_timing.py",
"bytes": 9226,
"sha256": "71876b36eef88c198aa8e833af547dbe772001c71b010707b656c165c8b54031"
},
{
"path": "tests/test_timing_queue.py",
"bytes": 5825,
"sha256": "4a375444dc732c3538df8aa4b81e43b5418754fcebebb0d02c16faad03d43195"
},
{
"path": "timing_queue.py",
"bytes": 4443,
"sha256": "54df6d4818e2a0c26e96fb0aaf5d9b71cd964981706da937562d48af79aca14e"
},
{
"path": "verify_frozen.py",
"bytes": 2725,
"sha256": "97d8a240b08baaca935f9c0278978883005dcd6fdbb4ca0d948074ef79fd349c"
}
]
}
@@ -0,0 +1,890 @@
"""Phase 4AJ graded-APL output-timing adapter of the sealed Phase 4AG oracle.
Brian has no Torch dependency. A separate, pinned science-Python process
executes the unchanged legacy float32 APL operations from Brian's own spikes.
This is independent LIF/scheduling validation with a shared APL numerical
component, NOT an all-components-independent CPU oracle. Only generated h
transport is changed: h[t-D] is written at end(t), D in {0,18}. The original
Brian equations, anatomical delay, refractory policy and queue proxy stay as
in the sealed source. No future brain or APL generation ticks are run.
"""
from __future__ import annotations
import csv
import hashlib
import importlib.metadata
import json
import math
import os
import platform
import queue
import struct
import subprocess
import sys
import threading
import time
import types
from contextlib import ExitStack
from pathlib import Path
import numpy as np
BLOCK_BYTES = 8 << 20
BASE_ORACLE_PATH = Path("/data/digital-drosophila/models/male-cns-lif/author-apl-lab-v2/oracle_apl.py")
BASE_ORACLE_SHA256 = "357a7d3debb5abc34a8714c0233b456547a154d9d5855d28661b4f01019a80ea"
LEGACY_WORKER_PATH = Path("/data/digital-drosophila/models/male-cns-lif/author-apl-lab-v2/legacy_apl_worker.py")
LEGACY_WORKER_SHA256 = "21ceec65fe42581dc55872010e0025d660e80358905f1cf4df1dadf341a3b291"
PROTOCOL = "phase4ag-apl-v1"
AUTHOR_PATH = Path("/data/digital-drosophila/experiments/phase4ad-author-semantics/external-resources/model.py")
AUTHOR_SHA256 = "fc45837d7122c6ce2a7f3f2f23c515992e4b232aadb919efabb72337fac88e4e"
AE_PATH = Path("/data/digital-drosophila/models/male-cns-lif/author-runtime-lab-v1/oracle_stress.py")
AE_SHA256 = "32eb1c42383068ce52701d2139a376ce155ad7072cde019949f8ca2d55492409"
AF_PATH = Path("/data/digital-drosophila/models/male-cns-lif/author-fullgraph-lab-v1/oracle_full.py")
AF_SHA256 = "d72003d98f0f1624b12126eff50bd361c43d888f4a64d90ba9247a58976f1961"
EVENT_DTYPE = np.dtype([("step", "<i4"), ("neuron_idx", "<i4")])
BUNDLE_FILES = ("input_matrix.npy", "output_matrix.npy", "kc_globals.npy", "apl_globals.npy")
_PROCESS_USED = False
def _check(condition, message):
if not condition:
raise ValueError(message)
def _save(path, value):
with Path(path).open("x", encoding="utf-8") as handle:
json.dump(value, handle, indent=2, sort_keys=True, allow_nan=False)
handle.write("\n")
def _digest(path):
result = hashlib.sha256()
with Path(path).open("rb") as handle:
for block in iter(lambda: handle.read(BLOCK_BYTES), b""):
result.update(block)
return result.hexdigest()
def _array_hash(array, dtype):
return hashlib.sha256(np.ascontiguousarray(array, dtype=dtype).tobytes()).hexdigest()
def _load_checked(path, expected, name):
data = Path(path).read_bytes()
_check(hashlib.sha256(data).hexdigest() == expected, f"Pinned source hash mismatch: {path}")
module = types.ModuleType(name)
module.__file__ = str(path)
exec(compile(data, str(path), "exec"), module.__dict__)
return module
def _python_entry(path):
"""A venv is selected by its invocation path, not the resolved ELF target."""
entry = Path(path).absolute()
_check(entry.is_file(), f"Missing declared Python entry: {entry}")
return entry
def _new_memmap(path, dtype, shape):
_check(not Path(path).exists(), f"Refusing to overwrite output: {path}")
return np.lib.format.open_memmap(path, mode="w+", dtype=dtype, shape=shape)
def _budget(root, limit, reserve=0):
total = 0
for directory, _, filenames in os.walk(root, followlinks=False):
for filename in filenames:
total += (Path(directory) / filename).stat(follow_symlinks=False).st_size
_check(total + int(reserve) <= limit,
f"Output budget exceeded: {total}+{reserve}>{limit}; inputs and duration were not adjusted")
return total
class _APLDelayFIFO:
"""Independent list transport; no Brian/Torch import, arithmetic, or feedback.
Start with D distinct positive-zero vectors. On tick t, append a copy of
generated h[t], then pop the oldest vector. The remaining D vectors are
pending applications at ticks T..T+D-1 after T steps, NOT new future output.
"""
def __init__(self, delay_steps):
_check(type(delay_steps) is int and delay_steps in (0, 18),
"apl_delay_steps must be an explicit integer 0 or 18")
self.delay_steps = delay_steps
self.tick = 0
self.finished = False
self.queue = [np.zeros(4064, dtype=np.float32) for _ in range(delay_steps)]
def step(self, tick, generated):
_check(not self.finished and type(tick) is int and tick == self.tick,
"APL FIFO ticks must be consecutive and cannot follow finish")
value = np.asarray(generated)
_check(value.dtype == np.dtype("float32") and value.shape == (4064,) and
np.isfinite(value).all() and np.all(value >= 0),
"APL FIFO requires one finite nonnegative float32 full-KC vector")
self.queue.append(value.copy())
applied = self.queue.pop(0)
_check(len(self.queue) == self.delay_steps, "APL FIFO length changed")
self.tick += 1
return applied
def finish(self, steps):
_check(not self.finished and type(steps) is int and steps == self.tick,
"APL FIFO did not cover every requested tick")
self.finished = True
if not self.queue:
return np.empty((0, 4064), dtype=np.float32)
return np.stack(self.queue).astype(np.float32, copy=False)
class _PipeReader:
"""One bounded reader thread, with timeout/EOF checks for every frame."""
def __init__(self, pipe, timeout):
self.pipe, self.timeout = pipe, float(timeout)
self.chunks = queue.Queue(maxsize=8)
self.buffer = bytearray()
self.thread = threading.Thread(target=self._pump, daemon=True)
self.thread.start()
def _pump(self):
try:
while True:
chunk = os.read(self.pipe.fileno(), 65536)
self.chunks.put(chunk)
if not chunk:
return
except BaseException as error:
self.chunks.put(error)
def _fill(self, deadline):
remaining = deadline - time.monotonic()
if remaining <= 0:
raise TimeoutError("APL sidecar response timed out")
try:
chunk = self.chunks.get(timeout=remaining)
except queue.Empty as error:
raise TimeoutError("APL sidecar response timed out") from error
if isinstance(chunk, BaseException):
raise RuntimeError("APL sidecar stdout reader failed") from chunk
if not chunk:
raise EOFError("APL sidecar ended before a complete response")
self.buffer.extend(chunk)
def read(self, size):
deadline = time.monotonic() + self.timeout
while len(self.buffer) < size:
self._fill(deadline)
result = bytes(self.buffer[:size])
del self.buffer[:size]
return result
def line(self):
deadline = time.monotonic() + self.timeout
while b"\n" not in self.buffer:
_check(len(self.buffer) < 1 << 20, "APL sidecar handshake exceeds 1 MiB")
self._fill(deadline)
end = self.buffer.index(b"\n") + 1
result = bytes(self.buffer[:end])
del self.buffer[:end]
return result
class _APLWorker:
def __init__(self, python, script, bundle_dir, stderr, timeout=180):
self.command = [str(python), "-B", str(script), "--bundle-dir", str(bundle_dir), "--dt-ms", "0.1"]
self.process = subprocess.Popen(self.command, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=stderr, bufsize=0, shell=False)
self.reader = _PipeReader(self.process.stdout, timeout)
self.tick = 0
try:
self.hello = json.loads(self.reader.line().decode("utf-8"))
_check(self.hello.get("ok") is True, "APL sidecar did not acknowledge initialization")
_check(self.hello.get("protocol") == PROTOCOL, "Unexpected APL sidecar protocol")
for key, value in (("n_neurons", 166700), ("n_apl", 2), ("n_kc", 4064)):
_check(self.hello.get(key) == value, f"APL sidecar changed {key}")
_check(self.hello.get("dt_ms") == .1, "APL sidecar changed dt")
expected_decay = f"{int(np.float32(math.exp(-.1 / 20.)).view(np.uint32)):08x}"
expected_gain = f"{int(np.float32(.01).view(np.uint32)):08x}"
_check(self.hello.get("decay_f32_bits") == expected_decay and self.hello.get("gain_f32_bits") == expected_gain,
"APL sidecar decay/gain differs from the frozen float32 scalars")
_check(self.hello.get("files_sha256") == {name: _digest(bundle_dir / name) for name in BUNDLE_FILES},
"APL sidecar bundle hashes differ from the independently read bundle")
except BaseException:
self.abort()
raise
def step(self, tick, global_spikes):
_check(tick == self.tick, "APL sidecar request ticks must be consecutive")
nodes = np.asarray(global_spikes)
_check(nodes.ndim == 1 and nodes.dtype == np.dtype("int32"), "APL input spikes must be int32 globals")
_check(not len(nodes) or (nodes[0] >= 0 and nodes[-1] < 166700 and np.all(np.diff(nodes) > 0)),
"APL input spikes must be sorted, unique, and in the frozen global range")
packet = struct.pack("<qQ", int(tick), len(nodes)) + np.ascontiguousarray(nodes, dtype="<i4").tobytes()
view = memoryview(packet)
while view:
written = self.process.stdin.write(view)
if not written:
raise BrokenPipeError("APL sidecar stdin failed")
view = view[written:]
self.process.stdin.flush()
response_tick, byte_count = struct.unpack("<qQ", self.reader.read(16))
_check(response_tick == tick and byte_count == (2 + 2 + 4064) * 4,
"APL sidecar frame tick/length mismatch")
values = np.frombuffer(self.reader.read(byte_count), dtype="<f4")
_check(np.isfinite(values).all() and np.all(values >= 0), "APL sidecar returned invalid nonnegative f32 states")
self.tick += 1
return values[:2], values[2:4], values[4:]
def finish(self, steps):
_check(self.tick == steps, "APL sidecar did not process every tick")
self.process.stdin.close()
status = self.process.wait(timeout=30)
_check(status == 0, f"APL sidecar exited unsuccessfully: {status}")
self.reader.thread.join(timeout=5)
_check(not self.reader.thread.is_alive(), "APL stdout did not reach EOF")
extra = bytes(self.reader.buffer)
while not self.reader.chunks.empty():
chunk = self.reader.chunks.get_nowait()
_check(not isinstance(chunk, BaseException), "APL stdout reader failed after the last frame")
extra += chunk
_check(not extra, "APL sidecar emitted unrequested trailing stdout bytes")
self.process.stdout.close()
return status
def abort(self):
if self.process.poll() is None:
self.process.terminate()
try:
self.process.wait(timeout=5)
except subprocess.TimeoutExpired:
self.process.kill()
self.process.wait(timeout=5)
for handle in (self.process.stdin, self.process.stdout):
if handle is not None and not handle.closed:
handle.close()
def _graph_inputs(directory):
arrays = {}
definitions = {"nodes": "int32", "edge_id": "int64", "src": "int32",
"dst": "int32", "signed_raw": "int64", "ptr": "int64", "weights": "float64"}
for name, dtype in definitions.items():
value = np.load(directory / (name + ".npy"), mmap_mode="r", allow_pickle=False)
_check(value.ndim == 1 and value.dtype == np.dtype(dtype), f"Invalid graph array {name}")
arrays[name] = value
nodes, edge_ids = arrays["nodes"], arrays["edge_id"]
n, edges = len(nodes), len(edge_ids)
_check(0 < n <= 166700 and edges > 0, "A case needs real global nodes and explicit nonempty connectivity")
_check(nodes[0] >= 0 and nodes[-1] < 166700 and np.all(np.diff(nodes) > 0), "Invalid global node order")
for name in ("src", "dst", "signed_raw", "weights"):
_check(arrays[name].shape == (edges,), f"Graph array {name} has the wrong shape")
pointer = arrays["ptr"]
_check(pointer.shape == (n + 1,) and pointer[0] == 0 and pointer[-1] == edges and
np.all(np.diff(pointer) >= 0), "Invalid graph CSR pointer")
source_counts = np.zeros(n, np.int64)
identity_edges = True
previous_source, previous_edge = -1, -1
width = BLOCK_BYTES // 8
for begin in range(0, edges, width):
stop = min(edges, begin + width)
source, target, ids = arrays["src"][begin:stop], arrays["dst"][begin:stop], edge_ids[begin:stop]
_check(np.all((source >= 0) & (source < n)) and np.all((target >= 0) & (target < n)),
"Graph edge endpoint is outside the local node array")
_check(np.all(ids >= 0), "Graph edge IDs must be nonnegative")
_check(source[0] > previous_source or (source[0] == previous_source and ids[0] > previous_edge),
"Graph edge blocks are not in canonical source/edge order")
_check(np.all((source[1:] > source[:-1]) |
((source[1:] == source[:-1]) & (ids[1:] > ids[:-1]))),
"Graph edges are not in canonical source/edge order")
previous_source, previous_edge = int(source[-1]), int(ids[-1])
identity_edges &= np.array_equal(ids, np.arange(begin, stop, dtype=np.int64))
source_counts += np.bincount(source, minlength=n)
_check(np.isfinite(arrays["weights"][begin:stop]).all(), "Nonfinite graph weights")
_check(np.array_equal(source_counts, np.diff(pointer)), "CSR pointer and source rows disagree")
if not identity_edges:
_check(len(np.unique(edge_ids)) == edges, "Original edge IDs must be unique")
for name in ("completeness.csv", "connectivity.parquet"):
_check((directory / name).is_file(), f"Missing unchanged author input: {name}")
if n == 166700:
_check(edges == 25582938 and identity_edges and np.array_equal(nodes, np.arange(n, dtype=np.int32)),
"A full probe must use the unchanged complete canonical graph")
return arrays, identity_edges
def _requests(case_dir, nodes, steps):
with np.load(case_dir / "requests.npz", allow_pickle=False) as archive:
_check(set(archive.files) == {"tick", "neuron_idx"}, "Unexpected sparse request schema")
ticks, requested = archive["tick"].copy(), archive["neuron_idx"].copy()
_check(ticks.dtype == requested.dtype == np.dtype("int32") and ticks.ndim == requested.ndim == 1 and
ticks.shape == requested.shape, "Requests must be equal-length int32 vectors")
_check(np.all((ticks >= 0) & (ticks < steps)), "Request time outside the case")
_check(not len(ticks) or np.all((ticks[1:] > ticks[:-1]) |
((ticks[1:] == ticks[:-1]) & (requested[1:] > requested[:-1]))),
"Requests must be sorted and unique by tick/global node")
local = np.searchsorted(nodes, requested)
_check(np.all(local < len(nodes)) and np.array_equal(nodes[local], requested),
"Request references a global neuron absent from this case")
counts = np.bincount(ticks, minlength=steps).astype(np.int32)
pointer = np.concatenate((np.zeros(1, np.int64), np.cumsum(counts, dtype=np.int64)))
return requested, local.astype(np.int32), pointer, counts
class _QueueProxy:
def __init__(self, original, get_tick, available, arrays, identity_edges,
due_counts, spike_ring, delay_steps, handle, records, summarize):
self._original_queue, self._get_tick = original, get_tick
self._available, self._arrays, self._identity_edges = available, arrays, identity_edges
self._due_counts, self._spike_ring, self._delay_steps = due_counts, spike_ring, delay_steps
self._handle, self._records, self._summarize = handle, records, summarize
def peek(self, *args, **kwargs):
original = self._original_queue.peek(*args, **kwargs)
local_edges = np.asarray(original)
tick = self._get_tick()
_check(tick == len(self._records["rows"]), "Queue peek ticks must be consecutive")
_check(local_edges.ndim == 1 and np.all((local_edges >= 0) & (local_edges < len(self._arrays["edge_id"]))),
"Original queue contains an invalid local edge index")
_check(len(local_edges) == self._due_counts[tick % len(self._due_counts)],
"Queue arrivals differ from the fixed-delay outgoing degree of actual spikes")
fired_then = np.zeros(len(self._arrays["nodes"]), dtype=bool)
if tick >= self._delay_steps:
fired_then[self._spike_ring[(tick - self._delay_steps) % len(self._spike_ring)]] = True
def accepted(begin, stop):
part = local_edges[begin:stop]
_check(np.all(fired_then[self._arrays["src"][part]]), "Arrival lacks a presynaptic spike at author delay")
return self._available[self._arrays["dst"][part]]
# Only the observed ID view changes; the queue is returned verbatim.
edge_ids = local_edges if self._identity_edges else self._arrays["edge_id"][local_edges]
summary = self._summarize(tick, edge_ids, accepted)
self._handle.write(json.dumps(summary, sort_keys=True) + "\n")
self._records["rows"].append(summary)
self._records["peek_calls"] += 1
return original
def advance(self, *args, **kwargs):
self._records["advance_calls"] += 1
return self._original_queue.advance(*args, **kwargs)
def __getattr__(self, name):
return getattr(self._original_queue, name)
def run_case(case_dir: Path, out_dir: Path) -> dict:
"""Run one continuous case, with exclusive outputs and no candidate trace input.
Graph inputs are the AF array/author-table schema plus original weights.npy.
requests.npz contains sparse tick/neuron_idx int32 vectors. Optional
arrays.npz contains initial_v_mv/initial_g_mv float64 vectors only.
Full probes write state hashes, sparse events and APL traces, not dense
whole-brain histories. Each case requires a fresh process.
"""
global _PROCESS_USED
_check(not _PROCESS_USED, "Every oracle case requires a fresh process")
_PROCESS_USED = True
case_dir, out_dir = Path(case_dir).resolve(strict=True), Path(out_dir).resolve()
spec = json.loads((case_dir / "spec.json").read_text(encoding="utf-8"))
graph_dir = Path(spec["graph_dir"]).resolve(strict=True)
bundle_dir = Path(spec["apl_bundle_dir"]).resolve(strict=True)
worker_path = Path(spec["legacy_apl_worker"]).resolve(strict=True)
_check(worker_path == LEGACY_WORKER_PATH.resolve(strict=True),
"The APL worker must remain the sealed Phase4AG-v2 worker")
_check(_digest(worker_path) == LEGACY_WORKER_SHA256, "Frozen Phase4AG-v2 APL worker changed")
_check(_digest(BASE_ORACLE_PATH) == BASE_ORACLE_SHA256, "Sealed oracle source baseline changed")
science_python = _python_entry(spec["science_python"])
author_path = Path(spec.get("author_path", AUTHOR_PATH)).resolve(strict=True)
ae_path = Path(spec.get("ae_oracle_path", AE_PATH)).resolve(strict=True)
af_path = Path(spec.get("af_oracle_path", AF_PATH)).resolve(strict=True)
coefficients_path = Path(spec["coefficients_path"]).resolve(strict=True)
steps = int(spec["steps"])
apl_delay_steps = spec["apl_delay_steps"]
_check(type(apl_delay_steps) is int and apl_delay_steps in (0, 18),
"apl_delay_steps must be an explicit integer 0 or 18")
_check(steps == spec["steps"] and 0 < steps <= np.iinfo(np.int32).max, "Invalid number of steps")
_check(float(spec["dt_ms"]) == .1 and np.isclose(float(spec["duration_ms"]), steps * .1, rtol=0, atol=1e-12),
"The frozen APL protocol requires dt_ms=0.1 and a matching duration")
_check(spec.get("precision", "float64") == "float64", "Author state must be float64")
_check(spec.get("training", False) is False and spec.get("poi_used", False) is False,
"Training and original poi are outside this gate")
_check(spec["apl"] == {"tau_ms": 20, "gain": .01, "normalization": 1}, "Frozen APL parameters changed")
record_history = spec["record_history"]
_check(isinstance(record_history, bool), "record_history must be a boolean")
budget_root = Path(spec.get("budget_root", out_dir.parent)).resolve()
budget_limit = int(spec.get("output_budget_bytes", 15 * 1024 ** 3))
_check(budget_limit > 0 and out_dir.is_relative_to(budget_root), "Invalid output budget/root")
out_dir.mkdir(parents=True, exist_ok=False)
mapped_files = []
saved_preferences, old_dt, worker = None, None, None
last_complete_tick = -1
try:
arrays, identity_edges = _graph_inputs(graph_dir)
nodes, n, edges = arrays["nodes"], len(arrays["nodes"]), len(arrays["edge_id"])
_check(n < 166700 or not record_history, "Full probes must not save dense V/g/ref histories")
bundle = {name: np.load(bundle_dir / (name + ".npy"), mmap_mode="r", allow_pickle=False)
for name in ("input_matrix", "output_matrix", "kc_globals", "apl_globals")}
for name, shape in (("input_matrix", (2, 166700)), ("output_matrix", (2, 4064))):
value = bundle[name]
_check(value.dtype == np.dtype("float32") and value.shape == shape and value.flags.c_contiguous,
f"Frozen APL {name} shape/dtype/layout changed")
_check(np.isfinite(value).all() and np.all(value >= 0), f"Invalid positive raw-normalized APL {name}")
for name, count in (("kc_globals", 4064), ("apl_globals", 2)):
value = bundle[name]
_check(value.dtype == np.dtype("int32") and value.shape == (count,) and value[0] >= 0 and
value[-1] < 166700 and np.all(np.diff(value) > 0), f"Frozen APL identity {name} changed")
_check(not np.intersect1d(bundle["kc_globals"], bundle["apl_globals"]).size, "APL and KC identities overlap")
kc_positions = np.searchsorted(nodes, bundle["kc_globals"])
present = kc_positions < n
present[present] &= nodes[kc_positions[present]] == bundle["kc_globals"][present]
kc_local, kc_in_bundle = kc_positions[present], np.flatnonzero(present)
requested_globals, request_local, request_ptr, request_count = _requests(case_dir, nodes, steps)
initial = None
if (case_dir / "arrays.npz").exists():
with np.load(case_dir / "arrays.npz", allow_pickle=False) as archive:
_check(set(archive.files) == {"initial_v_mv", "initial_g_mv"}, "Unexpected initial-state schema")
initial = {name: archive[name].copy() for name in archive.files}
for name, value in initial.items():
_check(value.dtype == np.dtype("float64") and value.shape == (n,) and np.isfinite(value).all(),
f"Invalid diagnostic initial state: {name}")
history_bytes = steps * n * 40 if record_history else 0
_budget(budget_root, budget_limit, history_bytes + steps * (2 + 2 + 4064 + 4064) * 4 +
apl_delay_steps * 4064 * 4 + edges * 8 + (64 << 20))
versions = {name: importlib.metadata.version(name) for name in
("brian2", "numpy", "pandas", "pyarrow", "sympy", "scipy", "cython")}
_save(out_dir / "environment.json", {"python": sys.version, "platform": platform.platform(),
"packages": versions, "codegen": "numpy", "author_precision": "float64",
"APL_precision": "float32 in separate science-Python process", "Torch_imported_into_Brian": False})
for name, required in (("brian2", "2.5.1"), ("numpy", "1.22.3"), ("sympy", "1.12")):
_check(versions[name] == required, f"{name} must remain pinned to {required}")
import brian2 as b2
import pandas as pd
from brian2.core.base import BrianObject
ae = _load_checked(ae_path, AE_SHA256, "phase4ag_sealed_ae_helpers")
af = _load_checked(af_path, AF_SHA256, "phase4ag_sealed_af_helpers")
author = _load_checked(author_path, AUTHOR_SHA256, "phase4ag_unchanged_author")
_check("torch" not in sys.modules, "Torch must not be imported into the pinned Brian process")
comp = pd.read_csv(graph_dir / "completeness.csv", index_col=0)
_check(np.array_equal(comp.index.to_numpy(), nodes) and
np.array_equal(comp["local_index"].to_numpy(), np.arange(n)), "Author CSV neuron identity differs")
del comp
graph_hashes = {name: _digest(graph_dir / name) for name in
tuple(key + ".npy" for key in arrays) + ("completeness.csv", "connectivity.parquet")}
bundle_hashes = {name: _digest(bundle_dir / name) for name in BUNDLE_FILES}
case_hashes = {name: _digest(case_dir / name) for name in ("spec.json", "requests.npz")}
if initial is not None:
case_hashes["arrays.npz"] = _digest(case_dir / "arrays.npz")
worker_hash = _digest(worker_path)
coefficient_hash = _digest(coefficients_path)
baseline_coefficients = json.loads(coefficients_path.read_text(encoding="utf-8"))
if "legacy_apl_worker_sha256" in spec:
_check(worker_hash == spec["legacy_apl_worker_sha256"], "APL worker differs from preregistered source")
_save(out_dir / "input-audit.json", {"spec": spec, "case_hashes": case_hashes,
"graph_hashes": graph_hashes, "bundle_hashes": bundle_hashes,
"author_sha256": AUTHOR_SHA256, "ae_sha256": AE_SHA256, "af_sha256": AF_SHA256,
"legacy_apl_worker_sha256": worker_hash, "coefficients_sha256": coefficient_hash,
"copied_oracle_source": str(BASE_ORACLE_PATH), "copied_oracle_sha256": BASE_ORACLE_SHA256,
"apl_delay_steps": apl_delay_steps, "only_scientific_change": "transport generated graded-APL h before the unchanged end write",
"candidate_trace_used_as_input": False,
"scope": "shared-APL-component closed-loop oracle, not all-components-independent CPU equivalence"})
saved_preferences = {key: b2.prefs[key] for key in
("codegen.target", "core.default_float_dtype", "legacy.refractory_timing")}
old_dt = b2.defaultclock.dt
b2.start_scope()
b2.prefs["codegen.target"] = "numpy"
b2.prefs["core.default_float_dtype"] = np.float64
b2.prefs["legacy.refractory_timing"] = False
b2.defaultclock.dt = .1 * b2.ms
parameters = dict(author.default_params)
_save(out_dir / "parameter-checks.json", ae._parameters_match(parameters, spec["model"], b2))
neu, syn, spikes = author.create_model(graph_dir / "completeness.csv", graph_dir / "connectivity.parquet", parameters)
_check(len(neu) == n and len(syn) == edges, "Author loaded an unexpected graph size")
_check(all(np.dtype(neu.variables[key].dtype) == np.float64 for key in ("v", "g")) and
np.dtype(syn.variables["w"].dtype) == np.float64, "Author states/weights are not float64")
effective = _new_memmap(out_dir / "weights.npy", "<f8", (edges,))
mapped_files.append(effective)
width, w_unit, mask_count = BLOCK_BYTES // 8, float(parameters["w_syn"] / b2.volt), 0
mask_hasher = hashlib.sha256()
base_hasher = hashlib.sha256()
effective_hasher = hashlib.sha256()
for begin in range(0, edges, width):
stop = min(edges, begin + width)
np.testing.assert_array_equal(np.asarray(syn.i[begin:stop]), arrays["src"][begin:stop])
np.testing.assert_array_equal(np.asarray(syn.j[begin:stop]), arrays["dst"][begin:stop])
original = np.asarray(syn.w_[begin:stop], dtype=np.float64).copy()
raw_expected = arrays["signed_raw"][begin:stop] * w_unit
_check(np.array_equal(original.view(np.uint64), raw_expected.view(np.uint64)) and
np.array_equal(original.view(np.uint64), arrays["weights"][begin:stop].view(np.uint64)),
"Actual original Brian weights differ from unchanged signed raw or AF base weights")
base_hasher.update(np.ascontiguousarray(original, dtype="<f8").tobytes())
mask = np.isin(nodes[arrays["src"][begin:stop]], bundle["apl_globals"])
mask_count += int(mask.sum())
mask_hasher.update(np.ascontiguousarray(arrays["edge_id"][begin:stop][mask], dtype="<i8").tobytes())
original[mask] = np.float64(0.0)
effective_hasher.update(np.ascontiguousarray(original, dtype="<f8").tobytes())
effective[begin:stop] = original
syn.w_[begin:stop] = original
if n == 166700:
_check(mask_count == 5845, "Full legacy APL fast-edge mask must contain exactly 5845 existing edges")
effective.flush()
_save(out_dir / "apl-mask-audit.json", {"count": mask_count, "ordered_original_edge_id_sha256": mask_hasher.hexdigest(),
"base_weight_raw_bytes_sha256": base_hasher.hexdigest(), "effective_weights_file_sha256": _digest(out_dir / "weights.npy"),
"effective_weights_raw_sha256": effective_hasher.hexdigest(),
"rule": "zero +0 all existing fast edges whose source GLOBAL neuron is in apl_globals; no graph edge removal",
"graded_targets": "only KC identities present in this LIF case", "KC_targets_in_case": len(kc_local),
"base_graph_files_modified": False, "fullgraph_required_mask_count": 5845})
if initial is not None:
neu.v = initial["initial_v_mv"] * b2.mV
neu.g = initial["initial_g_mv"] * b2.mV
v_raw = neu.variables["v"].get_value()
g_raw = neu.variables["g"].get_value()
last_raw = neu.variables["lastspike"].get_value()
available_raw = neu.variables["not_refractory"].get_value()
histories = {}
pre_apl_histories = {}
if record_history:
for name, dtype in (("v", "float64"), ("g", "float64"), ("ref", "int32")):
histories[name] = _new_memmap(out_dir / f"{name}-history.{dtype}.npy", np.dtype(dtype), (steps, n))
mapped_files.append(histories[name])
pre_apl_histories[name] = _new_memmap(out_dir / f"preAPL-{name}.{dtype}.npy", np.dtype(dtype), (steps, n))
mapped_files.append(pre_apl_histories[name])
apl_history = {}
for name, count in (("drive", 2), ("state", 2), ("inhibition", 4064)):
apl_history[name] = _new_memmap(out_dir / f"apl-{name}.float32.npy", "<f4", (steps, count))
mapped_files.append(apl_history[name])
applied_history = _new_memmap(out_dir / "apl-applied.float32.npy", "<f4", (steps, 4064))
mapped_files.append(applied_history)
apl_fifo = _APLDelayFIFO(apl_delay_steps)
_save(out_dir / "output-schema.json", {"history_recorded": record_history, "history_shape": [steps, n],
"state_hash_file": "tick-state-hashes.jsonl", "state_hash_encoding": "SHA256 of contiguous little-endian raw f64 V/g and i32 ref",
"APL_dtype": "float32", "APL_h_units": "mV; gain already applied in float32",
"APL_SI_conversion": "h.astype(float64) * float64(0.001), then separate float64 g subtraction",
"APL_write_schedule": "end, order=0, after original reset, unconditional raw g write; recorder end/order=1",
"APL_input": "Brian's own actual global spikes, never candidate spikes or candidate inhibition",
"APL_shapes": {"drive": [steps, 2], "state": [steps, 2], "inhibition": [steps, 4064],
"applied": [steps, 4064], "pending_tail": [apl_delay_steps, 4064]},
"apl_delay_steps": apl_delay_steps,
"APL_transport": "applied[t]=generated_h[t-D] for t>=D, positive zero otherwise; separate independent list FIFO",
"APL_inhibition_file_means": "generated h at the actual closed-loop Brian spike tick, not the delayed applied value",
"APL_pending_file": "apl-pending-tail.float32.npy",
"APL_pending_scope": "next D scheduled applications from recorded h plus unconsumed initial zero slots; not future generated decay",
"APL_pending_initial_zero_prefix": max(apl_delay_steps - steps, 0),
"APL_pending_generated_count": min(steps, apl_delay_steps),
"request_columns": ["tick", "neuron_idx", "attempted", "accepted", "rejected"],
"queue_protocol": "sealed Phase4AF queue_summary; original global edge IDs, including zero-weight/ref-rejected arrivals",
"state_npz": ["step", "neuron_idx", "counts", "v", "g", "ref"],
"complete_marker": "summary.json complete=true only after worker exit and all checks"})
delay_steps = int(round(float(parameters["t_dly"] / b2.ms) / .1))
ref_steps = int(round(float(parameters["t_rfc"] / b2.ms) / .1))
_check(delay_steps == 18 and ref_steps == 22, "Author delay/refractory changed")
queue_len = delay_steps + 1
due_counts = np.zeros(queue_len, np.int64)
spike_ring = [np.empty(0, np.int32) for _ in range(queue_len)]
outdegree = np.diff(arrays["ptr"])
request_seen = np.zeros(steps, np.uint8)
apl_seen = np.zeros(steps, np.uint8)
applicable_count = np.zeros(steps, np.int32)
rejected_count = np.zeros(steps, np.int32)
spike_count = np.zeros(steps, np.int32)
total_counts = np.zeros(n, np.int32)
records = {"rows": [], "peek_calls": 0, "advance_calls": 0, "installations": []}
last_ticks = np.zeros(n, np.int64)
final_ref = np.zeros(n, np.int32)
permitted = np.empty(0, np.int32)
total_events = 0
def tick_now():
return int(round(float(neu.clock.t / b2.second) / .0001))
def current_ref(tick):
seen = np.isfinite(last_raw) & (last_raw >= 0)
last_ticks.fill(0)
last_ticks[seen] = np.rint(last_raw[seen] / .0001).astype(np.int64)
result = np.where(seen, np.maximum(ref_steps - (tick - last_ticks), 0), 0).astype(np.int32)
_check(np.array_equal(result == 0, available_raw), "Ref history disagrees with author not_refractory")
return result
with ExitStack() as stack:
stderr = stack.enter_context((out_dir / "apl-worker.stderr.log").open("xb"))
worker = _APLWorker(science_python, worker_path, bundle_dir, stderr, float(spec.get("worker_timeout_seconds", 180)))
_save(out_dir / "apl-worker-handshake.json", {"command": worker.command, "handshake": worker.hello})
queue_file = stack.enter_context((out_dir / "queue.jsonl").open("x", encoding="utf-8"))
event_file = stack.enter_context((out_dir / "events.bin").open("xb"))
hash_file = stack.enter_context((out_dir / "tick-state-hashes.jsonl").open("x", encoding="utf-8"))
tick_file = stack.enter_context((out_dir / "ticks.jsonl").open("x", encoding="utf-8"))
requests_file = stack.enter_context((out_dir / "requests.csv").open("x", encoding="utf-8", newline=""))
request_writer = csv.DictWriter(requests_file, fieldnames=["tick", "neuron_idx", "attempted", "accepted", "rejected"])
request_writer.writeheader()
def request_operation():
nonlocal permitted
tick = tick_now()
_check(0 <= tick < steps and not request_seen[tick], "Invalid/duplicate common request tick")
request_seen[tick] = 1
begin, stop = request_ptr[tick:tick + 2]
local = request_local[begin:stop]
available = available_raw[local].copy()
permitted = local[available]
applicable_count[tick] = len(permitted)
rejected_count[tick] = len(local) - len(permitted)
for node, accepted in zip(requested_globals[begin:stop], available):
request_writer.writerow({"tick": tick, "neuron_idx": int(node), "attempted": 1,
"accepted": int(accepted), "rejected": int(not accepted)})
if len(permitted):
neu.v[permitted] = parameters["v_th"] + 1 * b2.mV
def apl_operation():
tick = tick_now()
_check(0 <= tick < steps and not apl_seen[tick] and request_seen[tick], "Invalid/duplicate APL tick")
active = np.asarray(neu.spikes, dtype=np.int32)
_check(not len(active) or np.all(np.diff(active) > 0), "Brian actual spikes are not canonical/unique")
_check(np.all(g_raw[active] == 0.0), "APL ran before the original author g reset")
if record_history:
pre_apl_histories["v"][tick] = v_raw
pre_apl_histories["g"][tick] = g_raw
pre_apl_histories["ref"][tick] = current_ref(tick)
drive, state, inhibition = worker.step(tick, np.asarray(nodes[active], dtype=np.int32))
apl_history["drive"][tick] = drive
apl_history["state"][tick] = state
apl_history["inhibition"][tick] = inhibition
applied = apl_fifo.step(tick, inhibition)
applied_history[tick] = applied
# These are separate array operations. Only h transport is new.
# Do not fuse conversion/subtraction or add a refractory guard.
delta_si = applied[kc_in_bundle].astype(np.float64) * np.float64(.001)
g_raw[kc_local] = g_raw[kc_local] - delta_si
apl_seen[tick] = 1
def record_end():
nonlocal last_complete_tick, total_events, final_ref
tick = tick_now()
_check(tick == last_complete_tick + 1 and tick < steps and apl_seen[tick], "End tick is incomplete/out of order")
_check(len(records["rows"]) == tick + 1, "End state lacks queue observation")
_check(np.isfinite(v_raw).all() and np.isfinite(g_raw).all(), "Nonfinite author/APL state")
final_ref = current_ref(tick)
if record_history:
histories["v"][tick], histories["g"][tick], histories["ref"][tick] = v_raw, g_raw, final_ref
active = np.asarray(neu.spikes, dtype=np.int32)
_check(np.isin(permitted, active).all(), "An applicable request did not produce a real spike")
spike_count[tick] = len(active)
total_counts[active] += 1
if len(active):
events = np.empty(len(active), EVENT_DTYPE)
events["step"], events["neuron_idx"] = tick, nodes[active]
event_file.write(memoryview(events).cast("B"))
total_events += len(active)
spike_ring[tick % queue_len] = active.copy()
due_counts[(tick + delay_steps) % queue_len] = int(outdegree[active].sum(dtype=np.int64))
hash_file.write(json.dumps({"tick": tick, "v_sha256": _array_hash(v_raw, "<f8"),
"g_sha256": _array_hash(g_raw, "<f8"), "ref_sha256": _array_hash(final_ref, "<i4")}, sort_keys=True) + "\n")
tick_file.write(json.dumps({"tick": tick, "spikes": len(active), "requests": int(request_count[tick]),
"applicable_requests": int(applicable_count[tick]), "ref_rejected_requests": int(rejected_count[tick]),
"event_sha256": _array_hash(nodes[active], "<i4"),
"due_arrivals": records["rows"][tick]["count"], "accepted_arrivals": records["rows"][tick]["accepted_count"],
"APL_drive_sha256": _array_hash(apl_history["drive"][tick], "<f4"),
"APL_state_sha256": _array_hash(apl_history["state"][tick], "<f4"),
"APL_inhibition_sha256": _array_hash(apl_history["inhibition"][tick], "<f4"),
"APL_applied_sha256": _array_hash(applied_history[tick], "<f4"),
"APL_applied_generated_tick": tick - apl_delay_steps if tick >= apl_delay_steps else None}, sort_keys=True) + "\n")
_budget(budget_root, budget_limit, reserve=1 << 20)
last_complete_tick = tick
if (tick + 1) % 100 == 0 or tick + 1 == steps:
for mapped in mapped_files:
mapped.flush()
for handle in (queue_file, event_file, hash_file, tick_file, requests_file):
handle.flush()
print(json.dumps({"oracle": spec["name"], "completed_ticks": tick + 1,
"spikes": total_events, "APL_worker_ticks": worker.tick}), flush=True)
class QueueInstaller(BrianObject):
def __init__(self):
super().__init__(clock=neu.clock, when="end", order=1_000_000, name="zz_apl_queue_installer")
def before_run(self, run_namespace):
installed = []
for code in syn.pre.code_objects:
if "_queue" not in code.namespace or "_queue.peek()" not in str(code.code):
continue
original = code.namespace["_queue"]
if isinstance(original, _QueueProxy):
original = original._original_queue
code.namespace["_queue"] = _QueueProxy(original, tick_now, available_raw, arrays, identity_edges,
due_counts, spike_ring, delay_steps, queue_file, records, af.queue_summary)
installed.append(code.name)
_check(len(installed) == 1, "Expected one original anatomical queue consumer")
records["installations"].append(installed[0])
objects = [neu, syn, spikes,
b2.NetworkOperation(request_operation, clock=neu.clock, when="before_thresholds", order=0, name="oracle_common_requests"),
b2.NetworkOperation(apl_operation, clock=neu.clock, when="end", order=0, name="oracle_legacy_apl_unconditional"),
b2.NetworkOperation(record_end, clock=neu.clock, when="end", order=1, name="oracle_after_apl_record"), QueueInstaller()]
network = b2.Network(*objects)
_save(out_dir / "schedule.json", {"schedule": list(network.schedule), "summary": str(network.scheduling_summary())})
network.run(0 * b2.ms, namespace={})
_save(out_dir / "compiled-code.json", ae._code_records(network))
compiled_coefficients = ae._coefficients(neu, parameters, b2, .0001)
coefficient_keys = ("gd", "c0", "cg", "cv", "threshold", "reset", "seed_volt")
_check(all(float(compiled_coefficients[key]).hex() == float(baseline_coefficients[key]).hex()
for key in coefficient_keys), "Compiled Brian coefficients differ from sealed AF")
_check(last_complete_tick == -1 and worker.tick == 0 and not records["rows"] and not request_seen.any(),
"Zero-duration compilation unexpectedly advanced state")
network.run(steps * .1 * b2.ms, namespace={})
_save(out_dir / "generated-code.json", ae._code_records(network))
worker_status = worker.finish(steps)
worker = None
_check(last_complete_tick == steps - 1 and np.all(request_seen == 1) and np.all(apl_seen == 1), "Incomplete trial")
pending_tail = apl_fifo.finish(steps)
warmup = min(steps, apl_delay_steps)
consumed = max(steps - apl_delay_steps, 0)
initial_zero_prefix = max(apl_delay_steps - steps, 0)
_check(np.all(applied_history[:warmup].view(np.uint32) == 0),
"Delayed APL warmup must contain positive zeros")
_check(np.array_equal(applied_history[warmup:].view(np.uint32),
apl_history["inhibition"][:consumed].view(np.uint32)),
"Applied h is not the exact delayed generated float32 sequence")
_check(pending_tail.shape == (apl_delay_steps, 4064) and pending_tail.dtype == np.float32,
"Pending APL tail shape/dtype changed")
_check(np.all(pending_tail[:initial_zero_prefix].view(np.uint32) == 0),
"Short-window pending prefix must contain unconsumed initial positive zeros")
_check(np.array_equal(pending_tail[initial_zero_prefix:].view(np.uint32),
apl_history["inhibition"][consumed:].view(np.uint32)),
"Pending tail does not exactly partition the finite generated h sequence")
with (out_dir / "apl-pending-tail.float32.npy").open("xb") as handle:
np.save(handle, pending_tail, allow_pickle=False)
_save(out_dir / "apl-timing-audit.json", {
"apl_delay_steps": apl_delay_steps, "steps": steps,
"generated_rows": steps, "applied_generated_rows": consumed,
"pending_generated_count": min(steps, apl_delay_steps),
"initial_zero_prefix": initial_zero_prefix,
"pending_initial_zero_prefix": initial_zero_prefix,
"pending_shape": [apl_delay_steps, 4064],
"pending_application_tick_start": steps,
"pending_application_tick_stop_exclusive": steps + apl_delay_steps,
"pending_generated_tick_start": consumed,
"pending_generated_tick_stop_exclusive": steps,
"positive_zero_warmup_exact": True, "transport_shift_exact": True,
"finite_generated_sequence_partition_exact": True,
"pending_raw_sha256": _array_hash(pending_tail, "<f4"),
"pending_file_sha256": _digest(out_dir / "apl-pending-tail.float32.npy"),
"brain_steps_after_window": 0, "APL_generation_steps_after_window": 0,
"brain_tail_advanced": False,
"final_apl_state_float32": np.asarray(apl_history["state"][-1], dtype=np.float32).tolist(),
"final_apl_state_u32_bits": np.asarray(apl_history["state"][-1], dtype=np.float32).view(np.uint32).tolist(),
"final_apl_state_nonzero": bool(np.any(apl_history["state"][-1] != 0)),
"future_generated_decay_tail_included": False,
"future_apl_decay_or_feedback_generated": False,
"closed_loop_branch_integrals_claimed_equal": False,
"delay_implementation": "independent list FIFO; no candidate or timing_queue imports",
"meaning": "Tail contains only already generated h and any remaining initial-zero padding; never a complete future closed-loop or decay tail",
})
_check(records["peek_calls"] == records["advance_calls"] == steps, "Incomplete queue audit")
_check(total_events == int(spikes.num_spikes) and np.array_equal(total_counts, np.asarray(spikes.count[:])),
"Sparse events disagree with original SpikeMonitor")
_check(np.array_equal(request_count, applicable_count + rejected_count), "Incomplete request accounting")
_check(np.all(np.asarray(neu.rfc[:] / b2.ms) == float(parameters["t_rfc"] / b2.ms)), "Author refractory duration changed")
for begin in range(0, edges, width):
stop = min(edges, begin + width)
_check(np.array_equal(np.asarray(syn.w_[begin:stop]).view(np.uint64), effective[begin:stop].view(np.uint64)),
"Effective synaptic weights changed during the trial")
event_values = np.memmap(out_dir / "events.bin", dtype=EVENT_DTYPE, mode="r", shape=(total_events,)) if total_events else np.empty(0, EVENT_DTYPE)
_check((out_dir / "events.bin").stat().st_size == total_events * 8, "Sparse event byte count mismatch")
for begin in range(0, total_events, width):
stop = min(total_events, begin + width)
spike_local = np.asarray(spikes.i[begin:stop], dtype=np.int32)
np.testing.assert_array_equal(event_values["neuron_idx"][begin:stop], nodes[spike_local])
times = np.rint(np.asarray(spikes.t[begin:stop] / b2.second) / .0001).astype(np.int32)
np.testing.assert_array_equal(event_values["step"][begin:stop], times)
_budget(budget_root, budget_limit, total_events * 8 + n * 24 + (8 << 20))
with (out_dir / "state.npz").open("xb") as handle:
np.savez_compressed(handle, step=event_values["step"], neuron_idx=event_values["neuron_idx"],
counts=total_counts, v=v_raw, g=g_raw, ref=final_ref)
with (out_dir / "tick-summary.npz").open("xb") as handle:
np.savez_compressed(handle, request_count=request_count, applicable_count=applicable_count,
rejected_count=rejected_count, spike_count=spike_count,
arrival_count=np.asarray([row["count"] for row in records["rows"]], np.int64),
accepted_arrival_count=np.asarray([row["accepted_count"] for row in records["rows"]], np.int64))
coefficients = ae._coefficients(neu, parameters, b2, .0001)
keys = ("gd", "c0", "cg", "cv", "threshold", "reset", "seed_volt")
_check(all(float(coefficients[key]).hex() == float(baseline_coefficients[key]).hex() for key in keys),
"Actual Brian coefficients differ from sealed AF coefficients")
_save(out_dir / "coefficients.json", coefficients)
_save(out_dir / "queue-audit.json", {"peek_calls": records["peek_calls"], "advance_calls": records["advance_calls"],
"installations": records["installations"], "same_peek_object_returned": True,
"original_edge_ids_not_sorted_or_filtered": True, "zero_weight_and_refractory_rejected_edges_retained": True,
"post_threshold_pre_synaptic_guard_observed": True, "forwarding_contract": "sealed AE/AF design",
"new_unwrapped_repeat_performed": False, "limit": "Current wrapper was not independently rerun without the queue proxy"})
for path, expected in ((author_path, AUTHOR_SHA256), (ae_path, AE_SHA256), (af_path, AF_SHA256),
(worker_path, worker_hash), (BASE_ORACLE_PATH, BASE_ORACLE_SHA256)):
_check(_digest(path) == expected, f"Source changed during the run: {path}")
_check(_digest(coefficients_path) == coefficient_hash, "Sealed coefficient reference changed during the run")
for directory, hashes in ((graph_dir, graph_hashes), (bundle_dir, bundle_hashes), (case_dir, case_hashes)):
for name, expected in hashes.items():
_check(_digest(directory / name) == expected, f"Read-only input changed during the run: {name}")
for mapped in mapped_files:
mapped.flush()
_check("torch" not in sys.modules, "Pinned Brian process unexpectedly imported Torch")
output_bytes = _budget(budget_root, budget_limit, 1 << 20)
summary = {"name": spec["name"], "complete": True, "precision": "float64", "APL_precision": "float32",
"backend": "shared-APL-component closed-loop Brian2 oracle", "steps": steps, "completed_ticks": last_complete_tick + 1,
"nodes": n, "edges": edges, "spikes": total_events, "requests": int(request_count.sum()),
"applicable_requests": int(applicable_count.sum()), "ref_rejected_requests": int(rejected_count.sum()),
"APL_fast_edges_zeroed": mask_count, "APL_worker_exit_status": worker_status, "APL_worker_ticks": steps,
"apl_fast_edges_zeroed": mask_count, "effective_weights_raw_sha256": effective_hasher.hexdigest(),
"kc_targets_present": len(kc_local), "apl_delay_steps": apl_delay_steps,
"APL_transport_shift_exact": True, "APL_finite_sequence_partition_exact": True,
"pending_generated_count": min(steps, apl_delay_steps),
"initial_zero_prefix": max(apl_delay_steps - steps, 0),
"pending_initial_zero_prefix": max(apl_delay_steps - steps, 0),
"pending_tail_shape": [apl_delay_steps, 4064], "future_generated_decay_tail_included": False,
"APL_applied_sha256": _digest(out_dir / "apl-applied.float32.npy"),
"APL_pending_tail_sha256": _digest(out_dir / "apl-pending-tail.float32.npy"),
"APL_timing_audit_sha256": _digest(out_dir / "apl-timing-audit.json"),
"candidate_trace_used_as_input": False, "independent_CPU_all_components_claim": False,
"history_recorded": record_history, "single_continuous_run": True, "no_training": True, "no_poi": True,
"source_and_inputs_unchanged": True, "pass_all": True,
"pass_all_scope": "Oracle construction, protocol and internal self-checks only; candidate comparison is a separate gate",
"scope": "Only this fixed trajectory; legacy Torch APL is a shared numerical component, not an independent CPU APL implementation",
"output_budget_bytes": budget_limit, "output_bytes_before_summary": output_bytes,
"state_hashes_sha256": _digest(out_dir / "tick-state-hashes.jsonl"), "queue_sha256": _digest(out_dir / "queue.jsonl"),
"events_sha256": _digest(out_dir / "events.bin"), "weights_sha256": _digest(out_dir / "weights.npy")}
_save(out_dir / "summary.json", summary)
return summary
except Exception as error:
for mapped in mapped_files:
mapped.flush()
_save(out_dir / "error.json", {"complete": False, "last_complete_tick": last_complete_tick,
"type": type(error).__name__, "message": str(error), "partial_files_preserved": True,
"inputs_or_duration_adjusted": False})
raise
finally:
if worker is not None:
worker.abort()
if saved_preferences is not None:
for key, value in saved_preferences.items():
b2.prefs[key] = value
b2.defaultclock.dt = old_dt
def run_oracle(case_dir: Path, out_dir: Path) -> dict:
"""Public timing-adapter alias; preserves the sealed run_case call shape."""
return run_case(case_dir, out_dir)
def main():
import argparse
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("case_dir", type=Path)
parser.add_argument("out_dir", type=Path)
args = parser.parse_args()
result = run_oracle(args.case_dir, args.out_dir)
print(json.dumps(result, sort_keys=True, allow_nan=False), flush=True)
if not result.get("complete") or not result.get("pass_all"):
raise SystemExit(1)
if __name__ == "__main__":
main()
@@ -0,0 +1,91 @@
"""Register a two-arm timing intervention before new trajectory outcomes."""
from datetime import datetime, timezone
import difflib
import platform
import shutil
import subprocess
import sys
import numpy as np
from context import (ROOT, MODEL, EXP, AG, AG_MODEL, AI, AI_MODEL, AH_MODEL, META,
COEFF, CFG, digest, read, save, sources, integrity, budget)
def copy_exact(src, dst):
dst.parent.mkdir(parents=True, exist_ok=True)
with src.open('rb') as a, dst.open('xb') as b:
shutil.copyfileobj(a, b)
assert digest(src) == digest(dst)
def main():
assert not EXP.exists() or not any(EXP.iterdir()), 'Never reuse a populated experiment'
assert shutil.disk_usage(EXP.parent).free > CFG['output_budget_bytes'] + 10 * 1024**3
assert read(AI / 'audit/final-status.json')['status'] == 'PASS-CONDITIONAL-PN-APL-SOURCE-AUDIT'
assert CFG['apl'] == read(AG_MODEL / 'config.json')['apl'] and CFG['delays_steps'] == [0, 18]
for sub in ('protocol', 'cases', 'gpu', 'oracle', 'audit', 'logs', 'regression', 'component-audit', 'calibration', 'extension-build'):
(EXP / sub).mkdir(parents=True, exist_ok=False)
command = [sys.executable, '-B', '-m', 'unittest', 'discover', '-v', '-s', str(MODEL), '-p', 'test_*.py']
tested = subprocess.run(command, cwd=MODEL, capture_output=True, text=True)
with (EXP / 'regression/unit-tests.log').open('x') as f:
f.write(tested.stdout + tested.stderr)
save(EXP / 'regression/unit-tests.json', dict(command=command, exit_code=tested.returncode,
pass_all=tested.returncode == 0, sha256=digest(EXP / 'regression/unit-tests.log')))
assert tested.returncode == 0, 'Unit tests failed; stop before registration'
inputs = [AI / 'manifest.json', AI / 'checksums.sha256', AI_MODEL / 'manifest.json',
AG / 'manifest.json', AG_MODEL / 'manifest.json', META, COEFF,
AH_MODEL / 'replay_core.py', AG_MODEL / 'legacy_apl_worker.py', AG_MODEL / 'gpu_apl.py',
AG_MODEL / 'oracle_apl.py', AG_MODEL / 'compare.py', AG_MODEL / 'calibration.py',
AG_MODEL / 'validate_components.py', AI / 'protocol/neuron-source-groups.parquet']
save(EXP / 'protocol/preregistered.json', dict(timestamp_utc=datetime.now(timezone.utc).isoformat(),
sources=sources(), config=CFG, inputs=[dict(path=str(p.relative_to(ROOT)), sha256=digest(p)) for p in inputs],
parent_commit=subprocess.check_output(['git', '-C', str(ROOT), 'rev-parse', 'HEAD'], text=True).strip(),
before_new_trajectories=True, prior_CAL_and_AI_outcomes_known=True,
single_factor='generated graded-APL h applied at t versus t+18; nothing else',
fixed_input_counts_and_amplitudes=True, actual_accepted_requests_may_change_due_to_closed_loop=True,
formal_learning_claim=False, oracle_limit='Independent Brian LIF state with shared legacy Torch APL arithmetic; separate component audit',
delay_biological_measurement=False, whole_brain_equal_total_inhibition_claim=False,
timing_test_no_full_future_tail_claim=True, source_diffs_are_review_material_not_equivalence_proof=True,
scope='Origin audit -> exact shift conservation -> two-arm fixtures -> fullgraph oracle probes -> complete two-arm fixed CAL -> frozen regression',
python=sys.version, numpy=np.__version__, machine=platform.machine()))
save(EXP / 'regression/old-integrity-before.json', integrity())
for old, new in (('gpu_apl.py', 'gpu_timing.py'), ('oracle_apl.py', 'oracle_timing.py'), ('compare.py', 'compare_timing.py')):
difference = ''.join(difflib.unified_diff((AG_MODEL / old).read_text().splitlines(True),
(MODEL / new).read_text().splitlines(True), fromfile=str(AG_MODEL / old), tofile=str(MODEL / new)))
with (EXP / 'protocol' / (new + '.diff')).open('x') as f:
f.write(difference)
records = read(AG / 'protocol/calibration-cases.json')
assert len(records) == 60 and len({r['name'] for r in records}) == 60
copy_exact(AG / 'protocol/calibration-cases.json', EXP / 'protocol/calibration-cases.json')
copy_exact(AG / 'protocol/encoder-audit.json', EXP / 'protocol/encoder-audit.json')
names = CFG['fixtures'] + [r['name'] for r in records]
inventory = []
for delay in CFG['delays_steps']:
arm = 'delay' + str(delay)
for sub in ('cases', 'gpu', 'oracle', 'component-audit', 'calibration'):
(EXP / sub / arm).mkdir(exist_ok=False)
for name in names:
src = AG / 'cases' / name
dst = EXP / 'cases' / arm / name
dst.mkdir(exist_ok=False)
spec = read(src / 'spec.json')
old_spec = dict(spec)
spec.update(apl_delay_steps=delay, budget_root=str(EXP), output_budget_bytes=CFG['output_budget_bytes'])
save(dst / 'spec.json', spec)
for key in set(old_spec) - {'budget_root', 'output_budget_bytes'}:
assert old_spec[key] == spec[key]
files = []
for fname in ('requests.npz', 'arrays.npz', 'pn-drive.npz'):
if (src / fname).exists():
copy_exact(src / fname, dst / fname)
files.append(dict(file=fname, sha256=digest(src / fname)))
inventory.append(dict(arm=arm, delay_steps=delay, name=name, kind=spec['kind'],
source_case=str(src.relative_to(ROOT)), unchanged_input_files=files))
save(EXP / 'protocol/case-inventory.json', inventory)
save(EXP / 'protocol/prepared-hashes.json', [dict(path=str(p.relative_to(EXP)), sha256=digest(p), bytes=p.stat().st_size)
for sub in ('protocol', 'cases') for p in sorted((EXP / sub).rglob('*')) if p.is_file() and p.name != 'prepared-hashes.json'])
budget()
print('REGISTERED 2 delays, 8 fixtures + 60 CAL each; exact original inputs; no new trajectory yet', flush=True)
if __name__ == '__main__':
main()
@@ -0,0 +1,59 @@
"""Exclusive-output fresh-process runner; original cases, one science GPU job."""
import argparse
import json
import os
import urllib.request
from context import ROOT, MODEL, EXP, AG, AG_MODEL, CFG, check, budget, read, load_module
def preflight():
os.environ['CUDA_VISIBLE_DEVICES'] = CFG['gpu_uuid']
os.environ['CUDA_HOME'] = '/usr/local/cuda'
os.environ['PATH'] = str(ROOT / 'models/male-cns-lif/.venv/bin') + ':/usr/local/cuda/bin:' + os.environ['PATH']
os.environ['MAX_JOBS'] = '2'
os.environ['TORCH_CUDA_ARCH_LIST'] = '8.9'
for port in (8188, 8189, 8190):
with urllib.request.urlopen(f'http://192.168.10.51:{port}/queue', timeout=5) as response:
queue = json.load(response)
assert not queue['queue_running'] and not queue['queue_pending'], 'ComfyUI busy: defer, never evict'
def main():
parser = argparse.ArgumentParser()
parser.add_argument('backend', choices=['gpu', 'oracle', 'component'])
parser.add_argument('arm', choices=['delay0', 'delay18'])
parser.add_argument('case')
parser.add_argument('--repeat', type=int, default=0)
args = parser.parse_args()
assert '/' not in args.case and '..' not in args.case and 0 <= args.repeat < 3
check(); budget()
assert read(EXP / 'origin-audit/summary.json')['pass_all']
assert read(EXP / 'audit/shift-gate.json')['pass_all']
preflight()
case = EXP / 'cases' / args.arm / args.case
assert case.is_dir() and read(case / 'spec.json')['apl_delay_steps'] == int(args.arm[5:])
if args.case not in CFG['fixtures']:
assert read(EXP / 'audit/fixtures-gate.json')['pass_all'], 'Fixture gate required before fullgraph execution'
if args.case not in CFG['calibration']['full_oracle_probes'] or args.repeat > 0:
assert read(EXP / 'audit/probes-gate.json')['pass_all'], 'Both fullgraph probe gates required before CAL'
out = EXP / 'gpu' / args.arm / f'{args.case}-r{args.repeat}'
if args.backend == 'gpu':
from gpu_timing import run_gpu
result = run_gpu(case, out, EXP / 'extension-build')
elif args.backend == 'oracle':
assert args.repeat == 0
from oracle_timing import run_case
result = run_case(case, EXP / 'oracle' / args.arm / args.case)
else:
assert args.repeat == 0
component = load_module('sealed_ag_component_aj', AG_MODEL / 'validate_components.py')
result = component.validate(out, AG / 'apl-bundle', EXP / 'component-audit' / args.arm / (args.case + '.json'))
budget()
print(json.dumps(dict(backend=args.backend, arm=args.arm, case=args.case, repeat=args.repeat,
complete=result.get('complete'), pass_all=result.get('pass_all')), allow_nan=False), flush=True)
if not result.get('pass_all', False):
raise SystemExit(1)
if __name__ == '__main__':
main()
@@ -0,0 +1,108 @@
"""Strict ordered numerical gates; both complete CAL arms even if representation fails."""
import argparse
import subprocess
import time
import traceback
from context import ROOT, MODEL, EXP, AG, CFG, check, save, read, budget
SCIENCE = ROOT / 'models/male-cns-lif/.venv/bin/python'
ORACLE = ROOT / 'experiments/phase4ad-author-semantics/environment/.venv/bin/python'
def child(backend, arm, name, repeat=0):
log = EXP / 'logs' / f'{backend}-{arm}-{name}-r{repeat}.log'
command = [str(ORACLE if backend == 'oracle' else SCIENCE), '-B', str(MODEL / 'run_case.py'),
backend, arm, name, '--repeat', str(repeat)]
print('START', backend, arm, name, repeat, flush=True)
started = time.perf_counter()
with log.open('x', encoding='utf-8') as stream:
result = subprocess.run(command, stdout=stream, stderr=subprocess.STDOUT, timeout=1800, check=False)
print('FINISH', backend, arm, name, repeat, 'exit', result.returncode,
'wall', round(time.perf_counter() - started, 2), flush=True)
if result.returncode:
raise RuntimeError(f'{backend} {arm}/{name} failed; preserve and inspect {log}')
def gate_case(arm, name, repeats):
from compare_timing import compare, compare_gpu_repeats
from calibration import control_identity
child('gpu', arm, name)
for repeat in range(1, repeats):
child('gpu', arm, name, repeat)
child('oracle', arm, name)
result = compare(EXP / 'cases' / arm / name, EXP / 'gpu' / arm / (name + '-r0'),
EXP / 'oracle' / arm / name, EXP / 'audit' / f'compare-{arm}-{name}.json')
assert result['pass_all'], f'Closed-loop exact comparison failed: {arm}/{name}'
for repeat in range(1, repeats):
report = compare_gpu_repeats(EXP / 'gpu' / arm / (name + '-r0'),
EXP / 'gpu' / arm / f'{name}-r{repeat}', EXP / 'audit' / f'repeat-{arm}-{name}-r{repeat}.json')
assert report['pass_all'], f'Exact repeat failed: {arm}/{name}/{repeat}'
if arm == 'delay0':
report = control_identity(EXP / 'gpu' / arm / (name + '-r0'), AG / 'gpu' / (name + '-r0'),
EXP / 'cases' / arm / name)
save(EXP / 'audit' / f'control-{name}.json', report)
assert report['pass_all'], f'Zero-delay control changed relative to sealed AG: {name}'
child('component', arm, name)
return dict(arm=arm, case=name, pass_all=True, gpu_repeats=repeats)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('stage', choices=['fixtures', 'probes', 'calibration'])
args = parser.parse_args()
check(); budget()
receipt = EXP / 'audit' / (args.stage + '-gate.json')
assert not receipt.exists()
assert read(EXP / 'origin-audit/summary.json')['pass_all']
assert read(EXP / 'audit/shift-gate.json')['pass_all']
arms = ['delay' + str(delay) for delay in CFG['delays_steps']]
try:
if args.stage == 'fixtures':
rows = [gate_case(arm, name, CFG['fixture_repeats']) for arm in arms for name in CFG['fixtures']]
save(receipt, dict(pass_all=True, cases=rows, scope='Both arms; fixed real-edge induced fixtures only'))
elif args.stage == 'probes':
assert read(EXP / 'audit/fixtures-gate.json')['pass_all']
rows = [gate_case(arm, name, 1) for arm in arms for name in CFG['calibration']['full_oracle_probes']]
save(receipt, dict(pass_all=True, cases=rows, scope='Both arms; same two original first-CAL fullgraph cases'))
else:
assert read(EXP / 'audit/fixtures-gate.json')['pass_all']
assert read(EXP / 'audit/probes-gate.json')['pass_all']
from calibration import summarize, control_identity
from compare_timing import compare_gpu_repeats
records = read(EXP / 'protocol/calibration-cases.json')
assert len(records) == 60
for arm in arms:
for record in records:
if record['name'] not in CFG['calibration']['full_oracle_probes']:
child('gpu', arm, record['name'])
name = record['name']
if arm == 'delay0':
control = control_identity(EXP / 'gpu' / arm / (name + '-r0'),
AG / 'gpu' / (name + '-r0'), EXP / 'cases' / arm / name)
save(EXP / 'audit' / f'cal-control-{name}-r0.json', control)
assert control['pass_all'], 'Zero-delay CAL control diverged: ' + name
if record['seed'] == CFG['calibration']['seeds'][0]:
child('gpu', arm, record['name'], 1)
repeat = compare_gpu_repeats(EXP / 'gpu' / arm / (name + '-r0'),
EXP / 'gpu' / arm / (name + '-r1'), EXP / 'audit' / f'cal-repeat-{arm}-{name}.json')
assert repeat['pass_all'], 'CAL exact repeat diverged: ' + arm + '/' + name
if arm == 'delay0':
control = control_identity(EXP / 'gpu' / arm / (name + '-r1'),
AG / 'gpu' / (name + '-r1'), EXP / 'cases' / arm / name)
save(EXP / 'audit' / f'cal-control-{name}-r1.json', control)
assert control['pass_all'], 'Zero-delay CAL repeat control diverged: ' + name
result = summarize()
save(receipt, dict(pass_all=result['execution_gate_pass'],
representation_pass_all=result['pass_all'], scope='Complete both fixed CAL arms; not heldout or learning',
summary='calibration/summary.json'))
assert result['execution_gate_pass'], 'CAL numerical/control/repeat gate failed'
except Exception as error:
save(EXP / 'audit' / ('stopped-' + args.stage + '.json'), dict(stage=args.stage,
type=type(error).__name__, message=str(error), traceback=traceback.format_exc(),
later_stages_not_permitted=True, partial_outputs_preserved=True, parameters_changed=False))
raise
budget()
if __name__ == '__main__':
main()
@@ -0,0 +1,44 @@
"""Fixed sealed-trace transport check; no closed-loop dynamics or gain search."""
import hashlib
import numpy as np
from context import AG, EXP, CFG, check, read, save, digest, budget
from timing_queue import TimingQueue, audit_sequence
def transport(generated, delay):
if generated.ndim != 2 or generated.dtype != np.float32:
raise ValueError('Expected stored float32 generated h')
queue = TimingQueue(delay, generated.shape[1])
applied = np.empty_like(generated)
for tick, row in enumerate(generated):
applied[tick] = queue.push(row, tick)
pending = queue.pending()
report = audit_sequence(generated, applied, pending, delay)
report.update(queue.metadata())
report['applied_bytes_sha256'] = hashlib.sha256(applied.tobytes()).hexdigest()
report['pending_bytes_sha256'] = hashlib.sha256(pending.tobytes()).hexdigest()
return applied, pending, report
def main():
check()
assert read(EXP / 'origin-audit/summary.json')['pass_all']
names = CFG['fixtures'] + [r['name'] for r in read(EXP / 'protocol/calibration-cases.json')]
records = []
for name in names:
path = AG / 'gpu' / (name + '-r0') / 'apl-inhibition.float32.npy'
generated = np.load(path, mmap_mode='r', allow_pickle=False)
assert generated.shape == (read(AG / 'cases' / name / 'spec.json')['steps'], 4064)
for delay in CFG['delays_steps']:
_, _, report = transport(generated, delay)
records.append(dict(case=name, delay_steps=delay, input_sha256=digest(path), **report))
save(EXP / 'audit/shift-gate.json', dict(pass_all=all(r['pass_all'] for r in records),
records=records, input_trace_count=len(names), no_new_brain_trajectory=True,
no_future_APL_advance=True, closed_loop_equal_integral_claim=False,
preservation='Every generated finite-window sample retained bitwise in applied or chronological pending slots; initial padding is +0'))
budget()
print('PASS: 68 fixed generated traces, 2 exact shifts; no new brain trajectories', flush=True)
if __name__ == '__main__':
main()
@@ -0,0 +1,196 @@
"""Pure synthetic selection, temporal joining, and streaming observer tests."""
import unittest
from types import SimpleNamespace
import importlib.util
import ast
from pathlib import Path
import numpy as np
import pandas as pd
from al_origin_audit import (select_cohort, predecessor_counts, first_ticks,
source_labels, ALLNObserver, _window_add, bit_equal)
class MemorySink:
def __init__(self):
self.rows = 0
self.calls = []
def write(self, data):
self.rows += len(data['edge_id'])
self.calls.append({k: np.asarray(v).copy() for k, v in data.items()})
class OriginTests(unittest.TestCase):
def test_main_does_not_shadow_callable_helpers(self):
tree = ast.parse((Path(__file__).parent / 'al_origin_audit.py').read_text(encoding='utf-8'))
helpers = {node.name for node in tree.body if isinstance(node, (ast.FunctionDef, ast.ClassDef))}
main = next(node for node in tree.body if isinstance(node, ast.FunctionDef) and node.name == 'main')
assigned = {node.id for node in ast.walk(main) if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Store)}
self.assertEqual(helpers & assigned, set())
def test_all_earliest_ties_and_static_design(self):
ids = np.arange(5, dtype=np.int32)
result = select_cohort(ids, np.array([1, 5, 5, 8, -1], np.int32),
np.array([0], np.int32), 20, 30)
np.testing.assert_array_equal(result['cohort'], [1, 2])
self.assertEqual(result['matched_stop_exclusive'], 5)
self.assertEqual(result['cohort_relation_to_first_KC'], 'before')
def test_no_non_design_activity_does_not_choose_never_active(self):
result = select_cohort(np.arange(3, dtype=np.int32), np.array([0, -1, -1], np.int32),
np.array([0], np.int32), 20, 30)
self.assertEqual(len(result['cohort']), 0)
self.assertEqual(result['earliest_tick'], -1)
def test_same_tick_is_not_before(self):
result = select_cohort(np.arange(2, dtype=np.int32), np.array([0, 20], np.int32),
np.array([0], np.int32), 20, 30)
self.assertFalse(result['cohort_before_first_KC'])
self.assertEqual(result['cohort_relation_to_first_KC'], 'same_tick')
def test_KC_absent_is_censored(self):
result = select_cohort(np.arange(2, dtype=np.int32), np.array([0, 20], np.int32),
np.array([0], np.int32), -1, 30)
self.assertTrue(result['pre_kc_window_censored'])
self.assertEqual(result['pre_kc_stop_exclusive'], 30)
self.assertFalse(result['cohort_before_first_KC'])
def test_after_KC_retains_cohort_without_selecting_a_different_one(self):
result = select_cohort(np.arange(2, dtype=np.int32), np.array([0, 20], np.int32),
np.array([0], np.int32), 10, 30)
self.assertEqual(result['cohort'].tolist(), [1])
self.assertEqual(result['cohort_relation_to_first_KC'], 'after')
self.assertEqual(result['matched_stop_exclusive'], 10)
def test_temporal_join_excludes_both_boundaries_and_prior_reset(self):
result = predecessor_counts(np.array([3, 5, 6, 9, 10, 11]),
np.array([1., 2., -3., 4., 5., 6.]), 10, 5)
self.assertEqual(result['all_prior_design_PN_events'], 4)
self.assertEqual(result['since_last_reset_design_PN_events'], 2)
self.assertEqual(result['prior_reset_excluded_events'], 2)
self.assertEqual(result['since_last_reset_positive_weight_SI'], 4.)
self.assertEqual(result['since_last_reset_negative_abs_weight_SI'], 3.)
def test_zero_weight_not_transmission(self):
result = predecessor_counts(np.array([2]), np.array([0.]), 3, -1)
self.assertEqual(result['since_last_reset_design_PN_events'], 1)
self.assertEqual(result['since_last_reset_nonzero_design_PN_events'], 0)
def test_no_direct_antecedent_valid_empty(self):
result = predecessor_counts(np.array([], np.int32), np.array([], np.float64), 20, -1)
self.assertEqual(result['since_last_reset_design_PN_events'], 0)
def test_reject_bad_temporal_order(self):
with self.assertRaises(ValueError):
predecessor_counts(np.array([3, 1]), np.ones(2), 10, 5)
with self.assertRaises(ValueError):
predecessor_counts(np.array([3]), np.ones(1), 10, 10)
def test_first_ticks_missing_and_repeated_events(self):
values = first_ticks(np.array([1, 3, 3], np.int32), np.array([2, 1, 2], np.int32),
np.arange(4, dtype=np.int32), n=4)
np.testing.assert_array_equal(values, [-1, 3, 1, -1])
def test_exact_role_mapping_unknown_stays_unknown(self):
labels = source_labels(np.arange(4), np.array(['ALPN', 'ALPN', 'ALLN', 'unclassified']),
np.array([True, False, False, False]))
self.assertEqual(labels.tolist(), ['design_ALPN', 'non_design_ALPN', 'ALLN', 'unclassified'])
def test_window_aggregation_preserves_sign_and_exclusion(self):
stats = {}
_window_add(stats, pd.DataFrame({'weight_SI': [1., -2., 9.]}),
np.array([True, True, False]), np.array(['ALLN'] * 3))
self.assertEqual(stats['ALLN']['events'], 2)
self.assertEqual(stats['ALLN']['positive_weight_SI'], 1.)
self.assertEqual(stats['ALLN']['negative_abs_weight_SI'], 2.)
def test_bit_equal_rejects_signed_zero(self):
self.assertFalse(bit_equal(np.array([0.]), np.array([-0.])))
@staticmethod
def observer():
sink = MemorySink()
incoming = SimpleNamespace(src_global=np.array([0, 1, 2], np.int32),
dst_local=np.array([0, 0, 1], np.int32), edge_id=np.arange(3, dtype=np.int64),
weights=np.array([.1, 0., -.2], np.float64))
observer = ALLNObserver(np.array([3, 4], np.int32), incoming,
np.array(['ALPN', 'APL', 'ALLN', 'ALLN', 'ALLN']),
np.array([True, False, False, False, False]), np.arange(5, dtype=np.uint64),
19, 19, sink)
return observer, sink
@staticmethod
def stage(due, accepted, ref=None):
return dict(h32=np.zeros(2, np.float32), delta_si=np.zeros(2), request=np.zeros(2, bool),
g=np.zeros(2), g_pre_apl=np.zeros(2), due_edge_indices=np.asarray(due, np.int64),
arrival_accepted=np.asarray(accepted, bool),
ref_after_reset=np.zeros(2, np.int32) if ref is None else ref,
fired=np.zeros(2, bool))
def test_observer_all_accepted_signs_and_zeros(self):
observer, sink = self.observer()
for tick in range(18):
observer(tick, self.stage([], []))
observer(18, self.stage([0, 1, 2], [True, True, True]))
report = observer.report()
self.assertEqual(sink.rows, 3)
self.assertEqual(report['source_groups']['APL']['zero'], 1)
self.assertEqual(sink.calls[-1]['source_spike_tick'].tolist(), [0, 0, 0])
self.assertEqual(observer.design_ticks[3], [18])
self.assertEqual(sink.calls[-1]['weight_sign'].tolist(), [1, 0, -1])
def test_observer_ref_guard_and_no_rejected_records(self):
observer, sink = self.observer()
for tick in range(18):
observer(tick, self.stage([], []))
stage = self.stage([0, 1, 2], [False, False, True], np.array([22, 0], np.int32))
stage['fired'][0] = True
observer(18, stage)
self.assertEqual(sink.rows, 1)
self.assertEqual(observer.report()['rejected_events'], 2)
self.assertEqual(observer.last.tolist(), [18, -1])
def test_observer_bad_acceptance_raises(self):
observer, _ = self.observer()
for tick in range(18):
observer(tick, self.stage([], []))
with self.assertRaises(ValueError):
observer(18, self.stage([0], [True], np.array([22, 0], np.int32)))
def test_observer_rejects_unexpected_input_and_graded_APL(self):
observer, _ = self.observer()
stage = self.stage([], [])
stage['request'][0] = True
with self.assertRaises(ValueError):
observer(0, stage)
stage['request'][0] = False
stage['h32'][0] = 1.
with self.assertRaises(ValueError):
observer(0, stage)
def test_frozen_replay_core_synthetic_integration(self):
module_spec = importlib.util.spec_from_file_location('origin_test_frozen_core',
Path(__file__).resolve().parent.parent / 'kc-drive-audit-v1/replay_core.py')
core = importlib.util.module_from_spec(module_spec)
module_spec.loader.exec_module(core)
incoming = core.IncomingIndex(np.array([0], np.int32), np.array([0], np.int32),
np.array([0], np.int64), np.array([1.], np.float64), 2)
sink = MemorySink()
observer = ALLNObserver(np.array([3, 4], np.int32), incoming,
np.array(['ALPN', 'APL', 'ALLN', 'ALLN', 'ALLN']),
np.array([True, False, False, False, False]), np.arange(5, dtype=np.uint64), 40, 30, sink)
coeff = dict(gd=.98, c0=-.00052, cg=.005, cv=.99, threshold=-.045, reset=-.052, seed_volt=-.044)
result = core.replay(np.full(2, -.052), np.zeros(2), coeff, 40, np.array([3, 4], np.int32),
dict(tick=np.array([], np.int32), neuron_idx=np.array([], np.int32)),
dict(step=np.array([0], np.int32), neuron_idx=np.array([0], np.int32)), incoming,
np.zeros((40, 2), np.float32), observer)
self.assertEqual(observer.report()['accepted_events'], 1)
self.assertGreater(int(result['first_spike'][0]), 18)
self.assertEqual(int(result['first_spike'][1]), -1)
self.assertEqual(observer.design_ticks[3], [18])
nonempty = [call for call in sink.calls if len(call['edge_id'])]
self.assertEqual(nonempty[0]['target_previous_spike_tick'].tolist(), [-1])
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,244 @@
"""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()
@@ -0,0 +1,199 @@
"""Synthetic orchestration/producer-contract checks; never launch a brain."""
import ast
import json
from pathlib import Path
import sys
import tempfile
from types import ModuleType
import unittest
from unittest.mock import patch
import numpy as np
import compare_timing
import oracle_timing
import run_suite
from shift_audit import transport
from timing_queue import audit_sequence
HERE = Path(__file__).resolve().parent
def fake_calibration_records():
return [dict(name=f'cal-{mode}-{odor:02d}-s{seed}', mode=mode, odor_id='odor'+str(odor), seed=seed)
for mode in ('physiological', 'matched_energy') for odor in range(6)
for seed in range(51101, 51106)]
def oracle_timing_dict(delay, generated, pending, final_state):
"""Evaluate only the actual producer's explicit metadata dict, no run call."""
tree = ast.parse((HERE / 'oracle_timing.py').read_text(encoding='utf-8'))
calls = [n for n in ast.walk(tree) if isinstance(n, ast.Call) and isinstance(n.func, ast.Name)
and n.func.id == '_save' and len(n.args) > 1 and isinstance(n.args[1], ast.Dict)
and any(isinstance(s, ast.Constant) and s.value == 'apl-timing-audit.json'
for s in ast.walk(n.args[0]))]
if len(calls) != 1:
raise AssertionError('Expected exactly one explicit oracle timing-metadata producer')
steps = len(generated)
namespace = dict(np=np, min=min, max=max, bool=bool, apl_delay_steps=delay, steps=steps,
consumed=max(steps-delay, 0), initial_zero_prefix=max(delay-steps, 0), pending_tail=pending,
apl_history={'state': np.asarray([final_state], np.float32)}, out_dir=Path('.'),
_array_hash=oracle_timing._array_hash, _digest=lambda _: '0'*64)
return eval(compile(ast.Expression(calls[0].args[1]), '<only metadata literal>', 'eval'), namespace)
class ProtocolTests(unittest.TestCase):
def test_two_independent_queues_match_both_arms_and_short_windows(self):
for delay in (0, 18):
for steps in (0, 1, 17, 18, 19, 37):
with self.subTest(delay=delay, steps=steps):
generated = ((np.arange(steps * 4064).reshape(steps, 4064) % 31)
.astype(np.float32) * np.float32(.001))
if steps:
generated[0, 0] = np.float32(-0.)
applied, pending, report = transport(generated, delay)
independent = oracle_timing._APLDelayFIFO(delay)
expected = np.empty_like(generated)
for tick, row in enumerate(generated):
expected[tick] = independent.step(tick, row)
tail = independent.finish(steps)
np.testing.assert_array_equal(applied.view(np.uint32), expected.view(np.uint32))
np.testing.assert_array_equal(pending.view(np.uint32), tail.view(np.uint32))
self.assertTrue(report['pass_all'])
def test_queue_rejects_off_by_one_and_lost_pending(self):
values = np.ones((19, 2), np.float32)
applied, pending, _ = transport(values, 18)
corrupt = applied.copy()
corrupt[17] = 1
with self.assertRaises(ValueError):
audit_sequence(values, corrupt, pending, 18)
with self.assertRaises(ValueError):
audit_sequence(values, applied, pending[:-1], 18)
def test_actual_oracle_metadata_matches_compare_contract(self):
for delay in (0, 18):
for steps in (1, 17, 18, 19, 37):
with self.subTest(delay=delay, steps=steps):
generated = np.full((steps, 4064), .25, np.float32)
_, pending, _ = transport(generated, delay)
final = np.array([.125, -0.], np.float32)
timing = oracle_timing_dict(delay, generated, pending, final)
summary = dict(pending_generated_count=min(delay, steps),
pending_initial_zero_prefix=max(delay-steps, 0), pending_tail_shape=[delay, 4064],
future_generated_decay_tail_included=False, APL_worker_ticks=steps)
run = dict(timing=timing, summary=summary, pending=pending,
apl={'state': np.asarray([final], np.float32)})
checks = {}
compare_timing._timing_metadata_checks(run, 'cpu', delay, steps, checks)
self.assertTrue(all(checks.values()), checks)
def test_bad_metadata_must_fail_without_fitted_tolerance(self):
generated = np.ones((3, 4064), np.float32)
_, pending, _ = transport(generated, 18)
final = np.array([.125, 0.], np.float32)
timing = oracle_timing_dict(18, generated, pending, final)
timing['pending_initial_zero_prefix'] += 1
run = dict(timing=timing, summary={}, pending=pending, apl={'state': np.asarray([final])})
checks = {}
compare_timing._timing_metadata_checks(run, 'cpu', 18, 3, checks)
self.assertFalse(checks['cpu.timing_integer_metadata'])
def _suite(self, stage, *, failed_read=None, execution=True, representation=False,
control=True, repeat=True):
records = fake_calibration_records()
saved, children = {}, []
def read(path):
path = str(path).replace('\\', '/')
if path.endswith('calibration-cases.json'):
return records
return {'pass_all': not (failed_read and path.endswith(failed_read))}
fake = ModuleType('calibration')
fake.summarize = lambda: dict(execution_gate_pass=execution, pass_all=representation)
fake.control_identity = lambda *args: dict(pass_all=control)
with tempfile.TemporaryDirectory() as directory:
with patch.object(run_suite, 'EXP', Path(directory)), patch.object(run_suite, 'check'), \
patch.object(run_suite, 'budget'), patch.object(run_suite, 'read', side_effect=read), \
patch.object(run_suite, 'save', side_effect=lambda path, result: saved.update({Path(path).name: result})), \
patch.object(run_suite, 'child', side_effect=lambda *args: children.append(args)), \
patch.object(run_suite, 'gate_case', side_effect=lambda arm, name, repeats:
dict(arm=arm, case=name, pass_all=True, gpu_repeats=repeats)), \
patch.object(compare_timing, 'compare_gpu_repeats', return_value=dict(pass_all=repeat)), \
patch.dict(sys.modules, {'calibration': fake}), patch.object(sys, 'argv', ['run_suite.py', stage]):
error = None
try:
run_suite.main()
except AssertionError as caught:
error = caught
return saved, children, error
def test_fixture_gate_covers_both_arms_all_cases(self):
saved, children, error = self._suite('fixtures')
self.assertIsNone(error)
self.assertEqual(children, [])
rows = saved['fixtures-gate.json']['cases']
self.assertEqual(len(rows), 16)
self.assertEqual({r['arm'] for r in rows}, {'delay0', 'delay18'})
self.assertTrue(all(r['gpu_repeats'] == 3 for r in rows))
def test_probe_stage_cannot_bypass_fixture_failure(self):
saved, children, error = self._suite('probes', failed_read='fixtures-gate.json')
self.assertIsNotNone(error)
self.assertEqual(children, [])
self.assertNotIn('probes-gate.json', saved)
def test_CAL_cannot_bypass_probe_failure(self):
saved, children, error = self._suite('calibration', failed_read='probes-gate.json')
self.assertIsNotNone(error)
self.assertEqual(children, [])
self.assertNotIn('calibration-gate.json', saved)
def test_representation_failure_does_not_select_or_stop_an_arm(self):
saved, children, error = self._suite('calibration', execution=True, representation=False)
self.assertIsNone(error)
self.assertEqual(len(children), 140) # (60 - 2 already-probed + 12 repeat) per arm.
self.assertEqual({row[1] for row in children}, {'delay0', 'delay18'})
self.assertTrue(saved['calibration-gate.json']['pass_all'])
self.assertFalse(saved['calibration-gate.json']['representation_pass_all'])
for arm in ('delay0', 'delay18'):
self.assertEqual(sum(row[1] == arm and len(row) == 4 and row[3] == 1 for row in children), 12)
def test_CAL_numerical_failure_stops_later_execution(self):
saved, _, error = self._suite('calibration', execution=False, representation=False)
self.assertIsNotNone(error)
self.assertFalse(saved['calibration-gate.json']['pass_all'])
self.assertTrue(saved['stopped-calibration.json']['later_stages_not_permitted'])
def test_control_divergence_stops_before_next_trial_or_other_arm(self):
saved, children, error = self._suite('calibration', control=False)
self.assertIsNotNone(error)
# The first r0 is a completed fullgraph probe; do not even run its r1.
self.assertEqual(children, [])
self.assertNotIn('calibration-gate.json', saved)
self.assertTrue(saved['stopped-calibration.json']['later_stages_not_permitted'])
def test_repeat_divergence_stops_before_next_trial_or_other_arm(self):
saved, children, error = self._suite('calibration', repeat=False)
self.assertIsNotNone(error)
self.assertEqual(len(children), 1)
self.assertEqual(children[0][1], 'delay0')
self.assertEqual(children[0][-1], 1)
self.assertNotIn('calibration-gate.json', saved)
self.assertTrue(saved['stopped-calibration.json']['later_stages_not_permitted'])
def test_origin_failure_prevents_any_new_fixture_run(self):
saved, children, error = self._suite('fixtures', failed_read='origin-audit/summary.json')
self.assertIsNotNone(error)
self.assertEqual(saved, {})
self.assertEqual(children, [])
def test_shift_failure_prevents_any_new_fixture_run(self):
saved, children, error = self._suite('fixtures', failed_read='shift-gate.json')
self.assertIsNotNone(error)
self.assertEqual(saved, {})
self.assertEqual(children, [])
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1 @@
"""Discoverable synthetic tests; no scientific execution during imports."""
@@ -0,0 +1,169 @@
"""Synthetic array-only comparator tests: no backend or scientific inputs."""
from pathlib import Path
import copy
import sys
import unittest
import numpy as np
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
import compare_timing as compare
def traces(delay, steps, width=3):
generated = np.arange(steps * width, dtype=np.float32).reshape(steps, width) * np.float32(.125)
full = np.concatenate((np.zeros((delay, width), dtype=np.float32), generated))
return generated, full[:steps].copy(), full[steps:].copy()
def sequence_result(generated, applied, pending, delay):
checks, differences = {}, {}
compare._timing_sequence_checks(generated, applied, pending, delay, 'test', checks, differences)
return checks, differences
def metadata_run(delay, steps, cpu=False):
generated, applied, pending = traces(delay, steps, 4064)
state = np.tile(np.array([.25, 1.125], np.float32), (steps, 1))
timing = dict(apl_delay_steps=delay, steps=steps, pending_generated_count=min(steps, delay),
generated_rows=steps, applied_generated_rows=max(steps-delay, 0), pending_shape=[delay, 4064],
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(steps-delay, 0), pending_generated_tick_stop_exclusive=steps,
pending_raw_sha256=compare.raw_hash(pending, '<f4'),
final_apl_state_float32=state[-1].tolist(),
final_apl_state_u32_bits=state[-1].view(np.uint32).tolist(), final_apl_state_nonzero=True,
brain_tail_advanced=False, future_apl_decay_or_feedback_generated=False,
finite_generated_sequence_only=True, closed_loop_branch_integrals_claimed_equal=False,
biological_delay_measurement_claimed=False, brain_steps_after_window=0,
APL_generation_steps_after_window=0, future_generated_decay_tail_included=False)
summary = dict(apl_timing=copy.deepcopy(timing), pending_generated_count=min(steps, delay),
pending_initial_zero_prefix=max(delay-steps, 0), pending_tail_shape=[delay, 4064],
future_generated_decay_tail_included=False, APL_worker_ticks=steps)
return dict(apl={'inhibition': generated, 'applied': applied, 'state': state}, pending=pending,
timing=timing, summary=summary)
class TimingComparisonTests(unittest.TestCase):
def test_delay_zero_and_18_partition(self):
for delay in (0, 18):
for steps in (1, 7, 18, 19, 54):
with self.subTest(delay=delay, steps=steps):
checks, differences = sequence_result(*traces(delay, steps), delay)
self.assertTrue(all(checks.values()), differences)
def test_one_tick_shift_rejected_independently(self):
generated, applied, pending = traces(18, 40)
applied[18:] = generated[1:23]
checks, _ = sequence_result(generated, applied, pending, 18)
self.assertFalse(checks['test.fixed_delay_applied.bitwise_exact'])
def test_pending_wrong_chronology_rejected(self):
generated, applied, pending = traces(18, 40)
checks, _ = sequence_result(generated, applied, pending[::-1].copy(), 18)
self.assertFalse(checks['test.fixed_delay_pending.bitwise_exact'])
def test_initial_zero_must_be_positive_bits(self):
generated, applied, pending = traces(18, 4)
pending.view(np.uint32)[0, 0] = 0x80000000
checks, _ = sequence_result(generated, applied, pending, 18)
self.assertFalse(checks['test.fixed_delay_pending.bitwise_exact'])
generated, applied, pending = traces(18, 22)
applied.view(np.uint32)[0, 0] = 0x80000000
checks, _ = sequence_result(generated, applied, pending, 18)
self.assertFalse(checks['test.fixed_delay_applied.bitwise_exact'])
def test_generated_signed_zero_preserved(self):
generated, applied, pending = traces(0, 1)
generated.view(np.uint32)[0, 0] = 0x80000000
applied[:] = generated
checks, _ = sequence_result(generated, applied, pending, 0)
self.assertTrue(all(checks.values()))
applied.view(np.uint32)[0, 0] = 0
checks, _ = sequence_result(generated, applied, pending, 0)
self.assertFalse(checks['test.fixed_delay_applied.bitwise_exact'])
def test_schema_and_delay_fail_closed(self):
generated, applied, pending = traces(18, 4)
for delay in (True, 1, 18.0):
with self.assertRaises(ValueError):
sequence_result(generated, applied, pending, delay)
with self.assertRaises(ValueError):
sequence_result(generated.astype(np.float64), applied, pending, 18)
with self.assertRaises(ValueError):
sequence_result(generated, applied, pending[-4:], 18)
def test_nonfinite_or_negative_generated_fails_even_if_shift_matches(self):
for value in (np.inf, np.nan, -1):
generated, applied, pending = traces(0, 2)
generated[0, 0] = value
applied[:] = generated
checks, _ = sequence_result(generated, applied, pending, 0)
self.assertFalse(checks['test.timing_finite_nonnegative'])
def test_both_backend_metadata_valid(self):
for role in ('gpu', 'cpu', 'first_gpu', 'second_gpu'):
for delay, steps in ((0, 25), (18, 7), (18, 25)):
run = metadata_run(delay, steps, cpu=role == 'cpu')
checks = {}
compare._timing_metadata_checks(run, role, delay, steps, checks)
self.assertTrue(all(checks.values()), checks)
def test_metadata_rejects_wrong_count_tail_advance_and_final_state(self):
for role in ('gpu', 'cpu'):
for change in ('count', 'tail', 'final', 'prefix', 'hash'):
run = metadata_run(18, 25, cpu=role == 'cpu')
if change == 'count':
run['timing']['pending_generated_count'] = 17
elif change == 'tail':
run['timing']['brain_steps_after_window' if role == 'cpu' else 'brain_tail_advanced'] = 1
elif change == 'final':
run['timing']['final_apl_state_u32_bits'][0] += 1
elif change == 'prefix':
run['timing']['pending_initial_zero_prefix'] = False
else:
run['timing']['pending_raw_sha256'] = '0' * 64
checks = {}
compare._timing_metadata_checks(run, role, 18, 25, checks)
self.assertFalse(all(checks.values()), (role, change))
def test_g_write_uses_applied_and_is_unconditional_during_ref(self):
nodes, kc = np.array([10, 12], np.int32), np.array([10], np.int32)
v = np.full((3, 2), -.06, np.float64)
ref = np.array([[22, 0], [21, 0], [20, 0]], np.int32)
before = np.array([[0, -.001], [-0., .001], [.002, -.003]], np.float64)
applied = np.array([[.25], [0], [1]], np.float32)
after = before.copy()
after[:, 0] -= applied[:, 0].astype(np.float64) * np.float64(.001)
run = dict(pre={'v': v, 'g': before, 'ref': ref}, histories={'v': v.copy(), 'g': after, 'ref': ref.copy()},
apl={'applied': applied, 'inhibition': np.full((3, 1), 99, np.float32)})
checks, differences = {}, {}
compare._check_apl_application(run, 'test', nodes, kc, checks, differences)
self.assertTrue(all(checks.values()), differences)
run['histories']['g'] = before.copy() # Hypothetical refractory guard must fail.
checks, differences = {}, {}
compare._check_apl_application(run, 'test', nodes, kc, checks, differences)
self.assertFalse(checks['test.apl_unconditional_g_write.bitwise_exact'])
def test_pair_comparison_includes_applied_and_pending(self):
def output():
generated, applied, pending = traces(18, 20)
return dict(state={'step': np.empty(0, np.int32), 'neuron_idx': np.empty(0, np.int32),
'counts': np.zeros(1, np.int32), 'ref': np.zeros(1, np.int32),
'v': np.zeros(1, np.float64), 'g': np.zeros(1, np.float64)},
apl={'drive': np.zeros((20, 2), np.float32), 'state': np.zeros((20, 2), np.float32),
'inhibition': np.pad(generated, ((0, 0), (0, 4061))),
'applied': np.pad(applied, ((0, 0), (0, 4061)))},
pending=np.pad(pending, ((0, 0), (0, 4061))),
hashes=[], queues=[], requests=[], component={}, histories={}, pre={})
left, right = output(), output()
right['apl']['applied'][0, 0] = 1
right['pending'][0, 0] += 1
checks, differences = {}, {}
compare._pair_outputs(left, right, checks, differences, 1, 20, False)
self.assertFalse(checks['apl.applied.bitwise_exact'])
self.assertFalse(checks['apl.pending.bitwise_exact'])
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,129 @@
"""Synthetic CPU-only checks; no Torch, data bundle, or scientific trial."""
from pathlib import Path
import sys
import unittest
import numpy as np
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from timing_queue import TimingQueue, audit_sequence
class TimingQueueTests(unittest.TestCase):
def sequence(self, delay, steps, width=3):
generated = np.arange(1, steps * width + 1, dtype=np.float32).reshape(steps, width)
queue = TimingQueue(delay, width)
applied = np.empty_like(generated)
for tick, row in enumerate(generated):
applied[tick] = queue.push(row, tick=tick)
return queue, generated, applied, queue.pending()
def test_delay_zero_identity(self):
queue, generated, applied, pending = self.sequence(0, 40)
self.assertTrue(np.array_equal(generated.view(np.uint32), applied.view(np.uint32)))
self.assertEqual(pending.shape, (0, 3))
self.assertTrue(audit_sequence(generated, applied, pending, 0)["pass_all"])
self.assertEqual(queue.metadata()["pending_generated_count"], 0)
def test_delay_18_boundary(self):
_, generated, applied, pending = self.sequence(18, 39)
self.assertTrue(np.all(applied[:18].view(np.uint32) == 0))
np.testing.assert_array_equal(applied[18], generated[0])
np.testing.assert_array_equal(applied[36], generated[18])
np.testing.assert_array_equal(pending, generated[-18:])
audit_sequence(generated, applied, pending, 18)
def test_short_sequence_keeps_initial_pending_slots(self):
for steps in (0, 1, 7, 17, 18, 19):
with self.subTest(steps=steps):
queue, generated, applied, pending = self.sequence(18, steps)
meta = audit_sequence(generated, applied, pending, 18)
self.assertEqual(pending.shape, (18, 3))
self.assertEqual(meta["pending_initial_zero_prefix"], max(18 - steps, 0))
self.assertEqual(meta["pending_generated_count"], min(18, steps))
self.assertEqual(queue.steps, steps)
self.assertTrue(np.all(pending[:max(18 - steps, 0)].view(np.uint32) == 0))
def test_no_alias_to_input_or_return_or_pending(self):
queue = TimingQueue(18, 1)
row = np.array([3], dtype=np.float32)
first = queue.push(row)
row[0] = 9
first[0] = 8
pending = queue.pending()
pending[:] = 12
for _ in range(17):
queue.push(np.zeros(1, dtype=np.float32))
self.assertEqual(queue.push(np.zeros(1, dtype=np.float32))[0], 3)
def test_zero_delay_return_owned(self):
row = np.array([2], dtype=np.float32)
value = TimingQueue(0, 1).push(row)
value[0] = 99
self.assertEqual(row[0], 2)
def test_signed_zero_subnormal_and_extreme_bits(self):
row = np.array([0x80000000, 1, 0x7f7fffff], dtype=np.uint32).view(np.float32)
for delay in (0, 18):
queue = TimingQueue(delay, 3)
generated = np.stack([row.copy() for _ in range(23)])
applied = np.stack([queue.push(x) for x in generated])
audit_sequence(generated, applied, queue.pending(), delay)
def test_reject_invalid_configuration(self):
for delay in (True, 1, -18, 18.0, np.int32(18)):
with self.assertRaises(ValueError):
TimingQueue(delay)
for width in (0, -1, True, 2.0):
with self.assertRaises(ValueError):
TimingQueue(18, width)
def test_reject_invalid_sample_without_advance(self):
queue = TimingQueue(18, 2)
bad = [np.ones(2, dtype=np.float64), np.ones((1, 2), dtype=np.float32),
np.ones(3, dtype=np.float32), [1, 2],
np.array([np.nan, 1], dtype=np.float32), np.array([np.inf, 1], dtype=np.float32),
np.array([-1, 1], dtype=np.float32)]
for row in bad:
with self.assertRaises(ValueError):
queue.push(row)
self.assertEqual(queue.steps, 0)
def test_tick_must_be_consecutive(self):
queue = TimingQueue(0, 1)
row = np.zeros(1, dtype=np.float32)
for tick in (1, True, -1, .0):
with self.assertRaises(ValueError):
queue.push(row, tick=tick)
queue.push(row, tick=0)
with self.assertRaises(ValueError):
queue.push(row, tick=0)
self.assertEqual(queue.steps, 1)
def test_audit_detects_shift_or_initial_negative_zero(self):
_, generated, applied, pending = self.sequence(18, 40)
applied[18, 0] += 1
with self.assertRaises(ValueError):
audit_sequence(generated, applied, pending, 18)
_, generated, applied, pending = self.sequence(18, 40)
applied.view(np.uint32)[0, 0] = 0x80000000
with self.assertRaises(ValueError):
audit_sequence(generated, applied, pending, 18)
def test_audit_rejects_invalid_schema(self):
_, generated, applied, pending = self.sequence(18, 2)
for g, a, p in ((generated.astype(np.float64), applied, pending),
(generated, applied[:1], pending), (generated, applied, pending[:2])):
with self.assertRaises(ValueError):
audit_sequence(g, a, p, 18)
def test_finite_sequence_sum_preserved_without_brain_tail(self):
queue, generated, applied, pending = self.sequence(18, 53)
np.testing.assert_array_equal(applied.sum(axis=0, dtype=np.float64) + pending.sum(axis=0, dtype=np.float64),
generated.sum(axis=0, dtype=np.float64))
self.assertEqual(queue.steps, 53)
self.assertFalse(queue.metadata()["brain_tail_advanced"])
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,87 @@
"""Pure NumPy reference for the fixed 0/18-step generated-APL output delay.
No brain dynamics, gain, float arithmetic or implicit tail advancement occurs
here. Pending rows are the next D application slots, including initial +0
padding if fewer than D samples have been generated.
"""
import numpy as np
class TimingQueue:
def __init__(self, delay_steps, width=4064):
if type(delay_steps) is not int or delay_steps not in (0, 18):
raise ValueError("delay_steps must be integer 0 or 18")
if type(width) is not int or width <= 0:
raise ValueError("width must be a positive integer")
self.delay_steps = delay_steps
self.width = width
self.steps = 0
self._ring = np.zeros((delay_steps, width), dtype=np.float32)
def push(self, generated, tick=None):
"""Return an owned f32 application row, without changing its bits."""
if tick is not None and (type(tick) is not int or tick != self.steps):
raise ValueError("tick must be the next consecutive integer tick")
if not isinstance(generated, np.ndarray) or generated.dtype != np.float32:
raise ValueError("generated must be a float32 ndarray")
if generated.shape != (self.width,) or not np.isfinite(generated).all():
raise ValueError("generated shape or finiteness invalid")
if np.any(generated < 0):
raise ValueError("generated inhibition must be nonnegative")
if self.delay_steps == 0:
applied = generated.copy()
else:
slot = self.steps % self.delay_steps
applied = self._ring[slot].copy()
self._ring[slot] = generated
self.steps += 1
return applied
def pending(self):
"""Owned rows in next-application order; always shape (D, width)."""
if self.delay_steps == 0:
return self._ring.copy()
head = self.steps % self.delay_steps
return np.concatenate((self._ring[head:], self._ring[:head]), axis=0)
def metadata(self):
return {"apl_delay_steps": self.delay_steps, "steps": self.steps,
"pending_generated_count": min(self.steps, self.delay_steps),
"pending_initial_zero_prefix": max(self.delay_steps - self.steps, 0),
"pending_application_tick_start": self.steps,
"pending_application_tick_stop_exclusive": self.steps + self.delay_steps,
"brain_tail_advanced": False}
def audit_sequence(generated, applied, pending, delay_steps):
"""Bitwise finite-sequence accounting; not a closed-loop integral claim.
Checks concat(applied, pending) == concat(D initial +0 rows, generated).
This preserves signed zeros and every stored sample, without assuming the
generated sequences of two different closed-loop branches are identical.
"""
if type(delay_steps) is not int or delay_steps not in (0, 18):
raise ValueError("delay_steps must be integer 0 or 18")
for name, value in (("generated", generated), ("applied", applied), ("pending", pending)):
if not isinstance(value, np.ndarray) or value.dtype != np.float32 or value.ndim != 2:
raise ValueError(name + " must be a rank-2 float32 ndarray")
if not np.isfinite(value).all() or np.any(value < 0):
raise ValueError(name + " must be finite nonnegative inhibition")
if generated.shape != applied.shape or pending.shape != (delay_steps, generated.shape[1]):
raise ValueError("Sequence shapes disagree")
steps = len(generated)
# Rowwise comparison avoids allocating a second T-by-K trace.
for tick in range(steps + delay_steps):
actual = applied[tick] if tick < steps else pending[tick - steps]
actual_bits = actual.view(np.uint32)
if tick < delay_steps:
ok = np.all(actual_bits == 0)
else:
ok = np.array_equal(actual_bits, generated[tick - delay_steps].view(np.uint32))
if not ok:
raise ValueError("Fixed-delay bitwise accounting failed at application tick " + str(tick))
return {"pass_all": True, "apl_delay_steps": delay_steps, "steps": steps,
"pending_generated_count": min(steps, delay_steps),
"pending_initial_zero_prefix": max(delay_steps - steps, 0),
"initial_padding_positive_zero": True, "sample_bits_preserved": True,
"brain_tail_advanced": False}
@@ -0,0 +1,55 @@
"""Run unchanged frozen reference into new output; never rewrite old evidence."""
import os
import sys
import time
import numpy as np
import pandas as pd
import yaml
from context import ROOT, EXP, CFG, save, check, bit_equal
def main():
check()
assert not (EXP / 'regression/frozen-five.json').exists()
rtpath = ROOT / 'models/male-cns-lif/deterministic-runtime-v2'
pc = yaml.safe_load((rtpath / 'phase4p.yaml').read_text())
os.environ['CUDA_VISIBLE_DEVICES'] = CFG['gpu_uuid']
os.environ['CUDA_HOME'] = '/usr/local/cuda'
os.environ['PATH'] = str(ROOT / 'models/male-cns-lif/.venv/bin') + ':/usr/local/cuda/bin:' + os.environ['PATH']
os.environ['MAX_JOBS'] = '2'
os.environ['TORCH_CUDA_ARCH_LIST'] = '8.9'
sys.path.insert(0, str(ROOT / 'models/male-cns-lif/terminal-scope-diagnostic-v1'))
from diagnostic import queues
queues()
sys.path.insert(0, str(ROOT / 'models/male-cns-lif'))
sys.path.insert(0, str(rtpath))
import torch
import phase4p
assert torch.cuda.mem_get_info()[0] > 2 * 1024**3
torch.cuda.reset_peak_memory_stats()
started = time.perf_counter()
runtime = phase4p.CanonicalRuntime(pc, rtpath, EXP)
rows = []
for spec in pc['reference_trials']:
queues()
base = ROOT / 'experiments/phase4p-deterministic-runtime/phase4c-v2/reference' / spec['name']
events = pd.read_parquet(base / 'spike-events.parquet')
reference = dict(step=events.step.to_numpy(), neuron_idx=events.neuron_idx.to_numpy(),
counts=np.load(base / 'per-neuron-spike-counts.int32.npy'),
v=np.load(base / 'final-voltage.float32.npy'), g=np.load(base / 'final-g.float32.npy'))
result = runtime.run(np.flatnonzero(runtime.pops[spec['population']]), spec['rate_hz'], spec['seed'], spec['duration_ms'])
row = dict(trial=spec['name'], exact={key: bool(bit_equal(value, result[key])) for key, value in reference.items()},
dtype_shape={key: dict(reference_dtype=str(value.dtype), actual_dtype=str(result[key].dtype),
reference_shape=list(value.shape), actual_shape=list(result[key].shape)) for key, value in reference.items()},
wall_seconds=result['metrics']['wall_seconds'])
rows.append(row)
print(row, flush=True)
passed = all(all(row['exact'].values()) for row in rows)
save(EXP / 'regression/frozen-five.json', dict(pass_all=passed, trials=rows,
wall_seconds=time.perf_counter() - started, peak_allocated_vram=int(torch.cuda.max_memory_allocated()),
oracle='Old frozen deterministic-v2 only; not this independent dynamics branch'))
assert passed
if __name__ == '__main__':
main()
@@ -0,0 +1,81 @@
# Phase 4AK — frozen D18 validation, not learning
Prerequisite: the entire Phase 4AJ fixed-CAL experiment was completed, sealed
and published at cb6937666f96b00ae8d435a2cfb2f417ad25c040.
Its PASS is not evidence of usable learning. This stage tests the next necessary
representation-generalization gate without adjusting the successful branch.
## No new brain dynamics
Call the exact SHA-pinned AJ GPU, Brian oracle, comparison and timing code from
their original absolute paths. Do not copy or patch their numerical functions,
globals, signs, weights, thresholds, APL gain/tau, refractory or delay queue.
Keep dt=0.1 ms, anatomical delay=18 steps, and whole generated graded-APL h
applied 18 steps later. Preserve positive-zero initialization and pending tail;
never advance brain time to drain the tail. Shared APL arithmetic limits the
oracle independence claim. The 5845 fast-APL output mask, including 1212
unreplaced non-KC edges, is unchanged. No biological measurement claim.
## Input registration and data boundary
Read only the four SHA-pinned original static 4L encoder files (panel, vectors,
selection, mapping) and pinned encoder configuration/source. Extract only the
unchanged pn_drive function AST; do not import or execute unrelated learning
experiments. Validate the extraction and request generator against all 60 old
AG CAL request/PN-drive arrays before generating any new brain trajectory.
Keep the original 12-odor median 2.556107997894287 and original target/RNG column
order. Matched energy is expected input, not exactly equal realized events.
Predeclare both 6-odor x2-mode x5-seed blocks, every sparse request schedule,
source hash, gate, and stop rule before any new brain trajectory. Seeds are the
fixed first five integers above 2^30, subject to the enumerated static collision
audit. They are not chosen using simulation outcomes. Do not claim exhaustive
historical uniqueness, statistical independence of RNG streams, or biological
replication. Same seed across odors preserves the existing paired comparisons.
The second six odors are novel to AG/AJ calibration, not never simulated in
project history: old 4L traversed the full panel. Never open old heldout dynamic
results, mixed old result tables or conditioning/plasticity reports to choose
inputs. Full frozen-integrity hashing may read opaque bytes for checksums; that
is not permission to parse those outcomes. Static A/B identities are not used
to select a favorable subset. No new resource download.
## Ordered execution
1. Freshly run the two original AJ D18 fullgraph probe inputs. Verify every
scientific output against sealed AJ, allowing only output budget/path
differences in spec. Do not fake D0 to use a D0-only helper. Old eight-fixture
proofs are source-pinned inherited evidence, not newly rerun fixture claims.
2. For original CAL odors on new seeds, fixed first odor/first seed in each mode
is a Brian fullgraph probe, with independent LIF/own spikes/FIFO and the
existing shared-APL component audit. Any numerical failure stops.
3. Complete the 60 seed-validation trajectories plus 12 exact repeats. Reuse
the two probe GPU runs rather than duplicate them as independent samples.
4. Only if the entire seed block passes numerical, repeat and original
representation gates, unlock the second block. Run the first static novel
odor/first seed in each mode as two additional Brian probes, then complete
that block's 60 trajectories and 12 repeats. All planned conditions remain
visible; gated unexecuted cases are NOT PASS and are reported as such.
5. Recompute raw evidence, rerun the five old frozen reference trials into new
output, verify every frozen artifact, and seal a truthful result.
Each cohort/mode separately retains every original six-part 4L gate: mean KC
fraction in [3%,9%], all runs >0 and <50%, same-odor Jaccard > different-odor,
between-odor Euclidean > within-odor, and at least 3 of 15 odor pairs passing
their own two-odor within baseline. Every mode has 60 within comparisons and
75 between comparisons; each pair has 20 within and 5 between. No pooled
12-odor rescue, seed replacement, post-hoc metric/window/gate changes or scans.
## Outcome scope
PASS-FROZEN-D18-INDEPENDENT-VALIDATION requires all four cohort/mode gates,
complete data, fresh controls, oracle/component checks, exact repeats and old
frozen integrity/reference PASS. Scientific failure remains FAIL; incomplete
execution is not re-labelled scientific success. Passing does not generate a
candidate, establish learning, prove delay biology or repair upstream AL loops.
Next required gates remain credit specificity, real KC-to-MBON functional
transfer, whole-brain stimulus-specific response, and controlled conditioning.
All outputs are new under phase4ak-apl-timing-validation. Previous Phase 1–4AJ,
base CSR/W_syn/signs, eligibility-v2 and the 14232-edge plastic mask remain
read-only. No training, reward interface, game, vision, decoder, RL or Web.
@@ -0,0 +1,64 @@
# Phase 4AK:仅静态种子审计
状态:`NO-COLLISION-FOUND-IN-DECLARED-STATIC-SCOPE`。这是输入准备审计,不是科学运行、表征验证或学习 PASS。
## 固定选择
使用 `2^30` 后的首五个正整数:
```text
1073741825, 1073741826, 1073741827, 1073741828, 1073741829
```
它们均小于 `2^31`。选择只依据静态声明的历史 namespace 与固定算术规则;没有生成随机输入来挑选、没有检查活动或 separability,也没有读取旧 held-out 动态结果。
新运行直接把这些整数传给原始 CUDA generator,不增加 odor、mode 或验证块偏移。两验证块、气味及模式继续按已提交计划共享同一组 seeds,以保留配对设计;技术重复重用同一 seed。这不意味着跨气味、模式或验证块的随机流彼此独立,也不是生物重复。运行后不得因结果不利换 seeds。
## 本次覆盖范围
先阅读已提交的 `phase4aj-next-validation.md`,随后只审计本地静态源码、配置及 AG/AJ 输入清单。机器记录见同目录 `seed-audit.json`:
- 217 个静态文件,每个记录 workspace-relative 路径、字节数和 SHA-256。
- 1,432 条 seed/RNG 相关源码或配置行保留准确行号;词法证据包括测试与非 RNG 的 `seed_node`,不把每一数字都当成真正 RNG seed。
- 检索范围为文件中列出的 12 个 source 根目录内 `.py/.yaml/.yml/.json`,排除名字含 manifest/checksum 的文件;另纳入已提交计划与明确允许的 AG/AJ protocol 静态文件。
- 完整文件文本未发现五个新种子的十进制字面值;已检查的配置及派生规则也未发现重用。
- AG 和 AJ 的 `protocol/calibration-cases.json` 均为 60 项,seeds 为 `51101–51105`,odor indices 为 `0–5`,两份文件 SHA 完全相同:`d91994c77db82cb40a258c92b222e0d7b28338ffe98764bd600988dae6f72754`。
没有导入或执行旧源码,没有运行 GPU/脑实验,没有访问网络或远程服务器,没有打开旧 `kc-representation`、`eligible-edges`、`plasticity-magnitude`、`conditioning` 或包含它们结果的综合报告。源码中的旧路径字符串是静态文本,不代表这些路径的输出被读取。
## 不能漏掉的派生规则
| 静态来源 | 已声明规则/占用范围 |
|---|---|
| 4A–4D | 配置中的 `41xxx–44xxx`;4C visual seed 加 `1/2/3/4/10+j`;4D 还内联 `44301–44303`。 |
| 4E | `45000 + SHA256(layer)前4字节模1000000`,再加 amplitude/rate/sparsity/window 派生偏移;保守保留完整 hash 输出范围,不读取旧最优条件。 |
| 4F/4G | `46101–46103`、`47001–47005`、`47101–47103`、`47201–47205`、`47300`、`47400`、`47901/47902`。4G 的 `stable_seed` 定义被记录,但其源码没有调用,不能宣称已执行。 |
| 4H–4K | 训练 seed 加 trial index;4J calibration base 加 odor index、evaluation seed 加 `odor_index*100`;4I 固定随机集合 seed `49301`;若干 DAN helper 接收 `seed+991`,显式 pulse 路径不实际抽样,仍保守记录。 |
| 4L–4Q | `51201–51205 + pairing(1..100)`,包括 `ts+pairing` 别名;评估 `51301–51305`;4N random-US 再加 `700000`。`512xx/513xx` 不可当作空白 namespace。 |
| 4P/4Q/4R | 旧 odor seed 有 `seed+odor_index*100`;`52101–52105` 和 `52201–52205` 已明确声明。random-US 包括 `930000/950000+actual`;4Q formal 还使用 `940000+train_seed*1000+pairing`。 |
| 4S | `54101–54105` 或 `55101–55105 + odor_index*100000`;control 加 `975000`;formal `[61000,62000,63000,64000,65000]+pairing`,评估 `71001–71005`。 |
| 4T | `86101–86120` 或 `87101–87120 + odor_index*1000000`;live-US RNG 加 `9700000`。 |
| 4U | `50000000 + odor_index*2000000 + seed`,seed 为 `118101–118120` 或 `119101–119120`;control 另加 `29000000`。按已声明最多 12 气味取保守 index `0..11`,最大列出参数为 `101119120`。 |
| 4V/W/Y/Z、4AB terminal scope | `80000000 + odor_index*1000000 + seed + block*1000003`;seed 包括 `131101–131103/141101`。1000 ms 以 120 ms 分块,保守含 `block=0..8`;offset 模式也先生成这些块再清零,不能忽略 RNG 使用。 |
| 4AE | 数值夹具固定 seed `410301`。 |
| AG/AJ、AH/AI | AG/AJ 每 case 直接使用 `51101–51105`,没有旧 4P 的 odor 偏移;AH/AI 使用既有轨迹重建,并非新 RNG 流。AF/motif 的 `seed_node(s)` 是 neuron IDs,不是 RNG seeds。 |
这些固定配置和已解释公式保守保留在 `[0, 200000000]` 排除区间;这不是说区间内所有整数都实际用过。新种子在该区间之外。完整规则、源码路径和原始行见 JSON。
## SHA 与远端核验契约
本地 `phase4l.yaml` 的 SHA 与 AG-r2 已登记 `olfactory-grounding-v1/phase4l.yaml` 相同;本地 `phase4p_revalidate.py` 与已登记 `deterministic-runtime-v2/phase4p_revalidate.py` 相同。
JSON 的 `inspected_files` 提供 `local_path/sha256/remote_path`。仅对有确切模型相对路径且 SHA 匹配预注册的 AG/AJ sources、两个上述输入 pin,以及明确的 experiment/protocol 副本填写 remote_path,共 43 项。remote_path 均相对于 `/data/digital-drosophila`。其他本地平铺副本一律为 null,不能猜服务器子目录。
主流程应在注册前对非 null 远端路径再次校验 SHA,并执行自身的旧文件及 manifest-chain 完整性检查;本静态审计不替代服务器完整性验证。
## 严格限制
1. 未审计未列出的 server-only 文件、终端历史、CLI 覆写、其他分支/历史版本、外部包或其他用户的运行;因此不能说全历史绝对未用过。
2. 配置中允许某 seed 不等于历史实际执行过;反之,任意 `reset(seed)` 或外部 caller 可以传入未在配置里列出的整数。词法检索与命名调用点复核不是完整 Python 数据流证明。
3. 没有完整历史执行输入注册表;只审计 AG/AJ 两份明确静态 CAL 清单,没有读取旧动态输出来反推使用情况。
4. 新整数不构成 PRNG 流统计独立性的数学证明。后六气味仅称“未用于 AG/AJ 校准”,不是项目历史从未运行过。
5. 主代理同时创建的 Phase 4AK 文件不属于历史检索范围,避免候选自身造成字面碰撞;本记录必须在新轨迹前纳入预注册。
结论仅为:这五个值在所列静态证据及配置派生范围内未发现重用,符合本轮预声明选择规则。未开始验证块、conditioning、参数扫描或候选升级。
@@ -0,0 +1,18 @@
2d3996933b6e5a31e6a737ade5f3ae6869ffd03e01002c793eccf9b4f71e987d PROTOCOL.md
35e8bfe1bff62f3a5d9295c785e1b8cec8a2393eaa67d6c683046e48f30feb56 SEED-AUDIT.md
1718d8b01ece24930ff138f25c88f2f0e0f1cf69ad0ba655e5a0de5083e64df2 config.json
5e4e500d5ec777bb8ae7ff77ac9a7279bfe995b1a17be2baededdbe065c98b73 context.py
0061689abb1832e963718bd836bc8a50009ee38b258143a753b4d59e63414925 encoder_inputs.py
7eb638c357cec7f5f85032312c50a616402b5a8a9ab5aa0268c181f6c3ae0ce5 finalize.py
d8b8315f8800b3efdc7548620f0fae85da21a12b753b9985dd623bd529e2c50f prepare.py
bba6c4a98c6edf1eaba60b8030a9eca646da7dd30b74b2a0c16e374efd022bfa run_case.py
3d9890f11f299c07956faa5c0a9ebe2ea28ade58d8acf01a8631c17025073345 run_suite.py
8a6629f8cd991cf309b508c670b3009737f9b5f5e1f72560fa5bd4b1ff0bc64d runtime_bridge.py
e14c0deb94432787aa1cac7618254aeb3db0bcd5b1d8328e20428496d38b220a seed-audit.json
f1b3b8a0ca9bc41152485c05fd5f24fb7bb1f76c6ea111ffb941ae1225d914fe test_encoder_inputs.py
a85466891352c15b3103d30e7229734ad6694c8a1347d5e0747da3315223c203 test_final_status.py
bc01a5ff38d79a7b66ab2eb9e6731164bb8a1e15b5b5c0c1655161c24e2c37cf test_runtime_bridge.py
03f5aacb5a1f9460d10b30744100a43c57e5488d32dada79c888529943c82cf0 test_validation.py
3464091a4cc2cba18946cb9c9b3d12a69bd3f79f1001096234b3a8467dc602c5 validation.py
a736b774e39ff0ad863e8efc720bd5f9ed7d30261776bb57f0a716a7052dba5a verify_frozen.py
3206a8666718b4a99e09b8384c87dd25895b5d7038d23fad7b93e40379183ccb manifest.json
@@ -0,0 +1,35 @@
{
"phase": "4AK",
"name": "apl-timing-validation-v1",
"human_authorization": "允许独立新模型分支测试动力学假设",
"gpu_uuid": "GPU-79f3a85d-adce-7833-7003-6488140ca596",
"neurons": 166700,
"edges": 25582938,
"raw_weight_sum": 124177617,
"apl_delay_steps": 18,
"dt_ms": 0.1,
"apl": {"tau_ms": 20.0, "gain": 0.01, "normalization": 1.0},
"validation": {
"seeds": [1073741825,1073741826,1073741827,1073741828,1073741829],
"modes": ["physiological", "matched_energy"],
"duration_ms": 100.0,
"odor_count": 6,
"repeat_first_seed_each_odor": true,
"cohorts": ["seed_validation", "novel_to_aj"],
"median_scope": "unchanged original frozen 12-odor panel",
"median_mapped_response_sum": 2.556107997894287,
"full_oracle_policy": "first static odor, first seed, each mode, for each cohort",
"unlock_novel": "Complete seed_validation execution, representation and repeat gates must pass before any novel-to-AJ brain trajectory"
},
"gates": {"sparse_min_fraction": 0.03, "sparse_max_fraction": 0.09, "max_fraction_strict": 0.5, "min_fraction_strict": 0.0, "minimum_separable_odor_pairs": 3, "same_jaccard_gt_between": true, "between_euclidean_gt_within": true, "both_modes_required": true, "finite_required": true, "repeat_exact_required": true},
"control_cases": ["cal-physiological-00-s51101", "cal-matched_energy-00-s51101"],
"output_budget_bytes": 25769803776,
"training": false,
"candidate_generation": false,
"old_heldout_dynamic_access": false,
"new_validation_dynamic_execution": true,
"historical_never_simulated_odor_claim": false,
"universal_seed_independence_claim": false,
"selection_policy": "Fixed source panel order, both cohorts and input schedules registered before any new trajectory. Stop on numerical failure or seed-block representation failure; retain all results, no replacement seeds/odors, no tuning, no pooled gate rescue.",
"hypothesis": "The already frozen AJ D18 operator generalizes to new audited seeds and six odors not used in AG/AJ calibration. No change whatsoever to dynamics, input transform, temporal window, graph, signs, APL mask or metric definitions."
}
@@ -0,0 +1,120 @@
"""A new validation envelope; sealed brain implementations remain read-only."""
import hashlib
import importlib.util
import json
import sys
from pathlib import Path
sys.dont_write_bytecode = True
ROOT = Path('/data/digital-drosophila')
MODEL = Path(__file__).resolve().parent
EXP = ROOT / 'experiments/phase4ak-apl-timing-validation'
AJ_MODEL = ROOT / 'models/male-cns-lif/apl-timing-lab-v1'
AJ = ROOT / 'experiments/phase4aj-apl-timing'
AG_MODEL = ROOT / 'models/male-cns-lif/author-apl-lab-v2'
AG = ROOT / 'experiments/phase4ag-author-apl-r2'
COEFF = ROOT / 'experiments/phase4af-author-fullgraph/oracle/no_input/coefficients.json'
STATIC = ROOT / 'experiments/phase4l-olfactory-grounding'
CFG = json.loads((MODEL / 'config.json').read_text(encoding='utf-8'))
PINS = {
'models/male-cns-lif/apl-timing-lab-v1/manifest.json': '52b05dd1ff30b6b51ff960fe95904532f5c147731a83f0b5c31f98ca7e53c216',
'experiments/phase4aj-apl-timing/manifest.json': '7f490ada0db30785c61954d8b92147378ddc8bc16b229fe3808bbe501caff44a',
'models/male-cns-lif/phase4l.py': 'e97d58d8c1f44920d0e953f8f5831ddc86fa0198784e86460e315de4116ac553',
'models/male-cns-lif/olfactory-grounding-v1/phase4l.yaml': '9b8bcb7e031bf9063033a1854a439a7cd0bf6730301c2d2d02ca99a76f098d6e',
'models/male-cns-lif/apl-timing-lab-v1/gpu_timing.py': 'af1975ba5e5e700208c0a598d3cbe648a3cf10885c6231239b6e4b28f76d173b',
'models/male-cns-lif/apl-timing-lab-v1/oracle_timing.py': '39d8c47c94bc2faddf016864a43e7715907fb987f56f7b27098060a88851f6be',
'models/male-cns-lif/apl-timing-lab-v1/compare_timing.py': '9010f070fba9b7c9cf2d86187ee2abc57f3ac606ebc08a42baad4f3922b51734',
'models/male-cns-lif/apl-timing-lab-v1/timing_queue.py': '54df6d4818e2a0c26e96fb0aaf5d9b71cd964981706da937562d48af79aca14e',
'models/male-cns-lif/apl-timing-lab-v1/calibration.py': 'fb15ddeaa108305c8de697bbae36b23ab0414a7c58db51c66dce9feb4a048a0d',
'models/male-cns-lif/author-apl-lab-v2/calibration.py': 'edb9cb2d890471fd07afd88c959ef3540b0cd40af490fac3f26396b5e7f5bf9c',
'models/male-cns-lif/author-apl-lab-v2/validate_components.py': '5cfc9a4505da6b8fb4e7d2617cdaedaa8475ed46a11ec9bdf0d4d25b1d22c2d3',
'experiments/phase4l-olfactory-grounding/odor-encoder/frozen-odor-panel.parquet': '907f16a56e024a8e2112b5751e53b0e6037b329fa110098af3d31b119c10a1a0',
'experiments/phase4l-olfactory-grounding/odor-encoder/mapped-glomerular-vectors.npz': 'f057563152e0fa22060080af13019f319e7f36563a775eff829bbc1929c451b0',
'experiments/phase4l-olfactory-grounding/odor-encoder/selection.json': '1b832becf9d08935716fe9ba5e3cd3e619e7d208dfb43c4fa197c969d095f113',
'experiments/phase4l-olfactory-grounding/receptor-mapping/olfactory-mapping.parquet': 'a01d27000533e9844458a4c559cac084f1c34ca20a1104e97e6a0f72b0cc93b1'
}
def digest(path):
result = hashlib.sha256()
with Path(path).open('rb') as stream:
for block in iter(lambda: stream.read(8 << 20), b''):
result.update(block)
return result.hexdigest()
def load_module(name, path, expected_hash=None):
path = Path(path)
data = path.read_bytes()
if expected_hash is not None:
assert hashlib.sha256(data).hexdigest() == expected_hash, str(path)
spec = importlib.util.spec_from_file_location(name, path)
assert spec and spec.loader
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
exec(compile(data, str(path), 'exec'), module.__dict__)
return module
def pinned(name, relative):
return load_module(name, ROOT / relative, PINS[relative])
def read(path):
return json.loads(Path(path).read_text(encoding='utf-8'))
def save(path, value):
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
with path.open('x', encoding='utf-8') as stream:
json.dump(value, stream, indent=2, ensure_ascii=False, allow_nan=False)
stream.write('\n')
def sources():
return {p.relative_to(MODEL).as_posix(): digest(p) for p in sorted(MODEL.rglob('*')) if p.is_file()
and '__pycache__' not in p.parts and p.name not in ('manifest.json', 'checksums.sha256')}
def integrity():
old = load_module('sealed_aj_context_ak', AJ_MODEL / 'context.py')
result = old.integrity()
sys.path.insert(0, str(ROOT / 'models/male-cns-lif/terminal-scope-diagnostic-v1'))
from diagnostic import manifest_check
for path in (AJ_MODEL, AJ):
result[str(path.relative_to(ROOT))] = manifest_check(path, digest)
assert all(row['pass'] for row in result.values())
return result
def check():
registered = read(EXP / 'protocol/preregistered.json')
assert registered['sources'] == sources(), 'Registered validation source changed'
assert registered['config'] == CFG
for row in registered['inputs']:
assert digest(ROOT / row['path']) == row['sha256'], row['path']
for row in read(EXP / 'protocol/prepared-hashes.json'):
assert digest(EXP / row['path']) == row['sha256'], row['path']
return registered
def budget():
size = sum(p.stat().st_size for p in EXP.rglob('*') if p.is_file())
assert size < CFG['output_budget_bytes'], 'Output budget exceeded; preserve partial evidence'
return size
def seal(root):
rows = [dict(path=p.relative_to(root).as_posix(), bytes=p.stat().st_size, sha256=digest(p))
for p in sorted(root.rglob('*')) if p.is_file() and '__pycache__' not in p.parts]
save(root / 'manifest.json', dict(root=str(root), files=rows))
with (root / 'checksums.sha256').open('x', encoding='utf-8') as stream:
for row in rows:
stream.write(row['sha256'] + ' ' + row['path'] + '\n')
stream.write(digest(root / 'manifest.json') + ' manifest.json\n')
def bit_equal(a, b):
return a.dtype == b.dtype and a.shape == b.shape and a.tobytes() == b.tobytes()
@@ -0,0 +1,52 @@
"""Static-only frozen encoder extraction and exact request-schedule generation."""
import ast
import hashlib
from pathlib import Path
from typing import Any
import numpy as np
def frozen_pn_drive(path, expected_sha):
"""Execute the exact one pure function, not unrelated historical experiments."""
import pandas as pd
source = Path(path).read_bytes()
assert hashlib.sha256(source).hexdigest() == expected_sha
tree = ast.parse(source, filename=str(path))
nodes = [node for node in tree.body if isinstance(node, ast.FunctionDef) and node.name == 'pn_drive']
assert len(nodes) == 1 and not nodes[0].decorator_list
module = ast.Module(body=nodes, type_ignores=[])
namespace = {'np': np, 'pd': pd, 'Any': Any}
exec(compile(module, str(path), 'exec'), namespace)
return namespace['pn_drive'], hashlib.sha256(ast.dump(nodes[0], include_attributes=False).encode()).hexdigest()
def requests_from_forced(forced, targets):
targets = np.asarray(targets)
assert targets.dtype == np.int32 and targets.ndim == 1 and len(np.unique(targets)) == len(targets)
assert forced.dtype == np.bool_ and forced.ndim == 2 and forced.shape[1] == len(targets)
ticks, columns = np.nonzero(forced)
requests = np.column_stack([ticks, targets[columns]]).astype(np.int32)
if len(requests):
requests = requests[np.lexsort((requests[:, 1], requests[:, 0]))]
assert np.all(np.diff(requests[:, 0].astype(np.int64) * 166700 + requests[:, 1]) > 0)
return requests
def make_requests(targets, rates, seed, steps=1000):
import torch
assert rates.dtype == np.float32 and rates.shape == targets.shape
assert np.isfinite(rates).all() and np.all(rates >= 0) and steps == 1000
original = rates * .1 / 1000.0
explicit = rates * np.float32(.1) / np.float32(1000.)
assert original.dtype == np.float32 and np.array_equal(original.view(np.uint32), explicit.view(np.uint32))
assert np.all(original <= 1)
generator = torch.Generator(device='cuda')
generator.manual_seed(int(seed))
probabilities = torch.as_tensor(original, dtype=torch.float32, device='cuda')
forced = (torch.rand((steps, len(targets)), generator=generator, device='cuda') < probabilities[None, :]).cpu().numpy()
return requests_from_forced(forced, targets)
def write_npz(path, **arrays):
with Path(path).open('xb') as stream:
np.savez_compressed(stream, **arrays)
@@ -0,0 +1,170 @@
"""Recompute the new evidence, preserve gated non-execution, then seal truthfully."""
from context import ROOT, MODEL, EXP, AJ, AJ_MODEL, AG, CFG, read, save, digest, check, integrity, budget, seal
def optional(path):
return read(path) if path.exists() else None
def decide_status(*, numerical, seed, novel, integrity_pass, reference_pass, reference_present,
known_numerical_failure=False, unauthorized_novel=False):
if not integrity_pass or (reference_present and not reference_pass):
return 'FAIL-FROZEN-INTEGRITY-OR-REGRESSION'
if known_numerical_failure or unauthorized_novel:
return 'FAIL-NUMERICAL-OR-EXECUTION-POLICY'
if not numerical or not reference_present or not seed or not seed['execution_gate_pass']:
return 'INCOMPLETE-VALIDATION-EXECUTION'
if not seed['representation_gate_pass']:
return 'FAIL-SEED-VALIDATION-REPRESENTATION'
if not novel or not novel['execution_gate_pass']:
return 'INCOMPLETE-VALIDATION-EXECUTION'
if not novel['representation_gate_pass']:
return 'FAIL-NOVEL-ODOR-REPRESENTATION'
return 'PASS-FROZEN-D18-INDEPENDENT-VALIDATION'
def component_report(group, name):
path = EXP / 'component-audit' / group / (name + '.json')
if not path.exists():
return None
report = read(path)
output = EXP / 'gpu' / group / (name + '-r0')
assert set(report.get('input_sha256', {})) == {'state.npz', 'summary.json',
'apl-drive.float32.npy', 'apl-state.float32.npy', 'apl-inhibition.float32.npy'}
for filename, checksum in report['input_sha256'].items():
assert digest(output / filename) == checksum
assert set(report.get('matrix_checks', {})) == {'input_matrix', 'output_matrix', 'input_raw', 'output_raw',
'kc_globals', 'apl_globals', 'pn_globals', 'apl_out_ids', 'input_scale', 'output_scale'}
assert set(report.get('ast_replay_bitwise_exact', {})) == {'drive', 'state', 'inhibition'}
assert set(report.get('float64_measurement', {})) == {'drive', 'state', 'inhibition'}
actual = bool(not report.get('error') and all(report['matrix_checks'].values()) and
all(report['ast_replay_bitwise_exact'].values()) and report['theoretical_bound']['applicable'] and
all(value['bound_violations'] == 0 for value in report['float64_measurement'].values()))
assert report['pass_all'] == actual
return actual
def main():
from pathlib import Path
import runtime_bridge as bridge
from validation import summarize
check(); budget()
controls_inventory, records = bridge.inventories(EXP, CFG)
controls, comparisons, components, repeats, summaries = {}, {}, {}, {}, {}
for row in controls_inventory:
name = row['name']
path = EXP / 'audit' / ('control-' + name + '.json')
if path.exists():
actual = bridge.control_identity(EXP / 'gpu/controls' / (name + '-r0'), Path(row['source_output']),
EXP / 'cases/controls' / name, Path(row['source_case']), None)
assert actual == read(path), 'Raw control evidence changed'
controls[name] = actual['pass_all']
component = component_report('controls', name)
if component is not None:
components['controls/' + name] = component
gates = {stage: optional(EXP / 'audit' / (stage + '-gate.json')) for stage in bridge.STAGES}
for cohort in CFG['validation']['cohorts']:
summary_path = EXP / 'validation' / cohort / 'summary.json'
if summary_path.exists():
actual = summarize(cohort, out_json=None)
assert actual == read(summary_path), 'Raw validation evidence changed: ' + cohort
summaries[cohort] = actual
for row in bridge.probe_rows(records, CFG, cohort):
name = row['name']
path = EXP / 'audit' / ('compare-' + cohort + '-' + name + '.json')
if path.exists():
actual = bridge.compare(EXP / 'cases' / cohort / name, EXP / 'gpu' / cohort / (name + '-r0'),
EXP / 'oracle' / cohort / name, None)
assert actual == read(path), 'Raw oracle evidence changed'
comparisons[cohort + '/' + name] = actual['pass_all']
component = component_report(cohort, name)
if component is not None:
components[cohort + '/' + name] = component
for row in bridge.cohort_rows(records, CFG, cohort):
if row['seed'] != CFG['validation']['seeds'][0]:
continue
name = row['name']
path = EXP / 'audit' / ('repeat-' + cohort + '-' + name + '.json')
if path.exists():
actual = bridge.compare_gpu_repeats(EXP / 'gpu' / cohort / (name + '-r0'),
EXP / 'gpu' / cohort / (name + '-r1'), None)
assert actual == read(path), 'Raw repeat evidence changed'
repeats[cohort + '/' + name] = actual['pass_all']
seed, novel = summaries.get('seed_validation'), summaries.get('novel_to_aj')
seed_pass = bool(seed and seed['execution_gate_pass'] and seed['representation_gate_pass'])
novel_paths = [str(path.relative_to(EXP)) for root in ('gpu', 'oracle', 'component-audit')
for path in (EXP / root / 'novel_to_aj').glob('*')]
unauthorized = bool(novel_paths and not seed_pass)
required_cohorts = ['seed_validation', 'novel_to_aj'] if seed_pass else ['seed_validation']
expected_controls = {row['name'] for row in controls_inventory}
expected_comparisons = {cohort + '/' + row['name'] for cohort in required_cohorts
for row in bridge.probe_rows(records, CFG, cohort)}
expected_components = expected_comparisons | {'controls/' + name for name in expected_controls}
expected_repeats = {cohort + '/' + row['name'] for cohort in required_cohorts
for row in bridge.cohort_rows(records, CFG, cohort) if row['seed'] == CFG['validation']['seeds'][0]}
required_stages = ['controls', 'seed-probes', 'seed-validation'] + (['novel-probes', 'novel-validation'] if seed_pass else [])
numerical = bool(set(controls) == expected_controls and set(comparisons) == expected_comparisons and
set(components) == expected_components and set(repeats) == expected_repeats and
all(all(values.values()) for values in (controls, comparisons, components, repeats)) and
all(gates[stage] and gates[stage]['pass_all'] for stage in required_stages) and
all(cohort in summaries and summaries[cohort]['execution_gate_pass'] for cohort in required_cohorts))
for cohort, summary in summaries.items():
stage = 'seed-validation' if cohort == 'seed_validation' else 'novel-validation'
if gates[stage]:
assert gates[stage]['execution_gate_pass'] == summary['execution_gate_pass']
assert gates[stage]['representation_gate_pass'] == summary['representation_gate_pass']
frozen = optional(EXP / 'regression/frozen-five.json')
integrity_result = integrity()
save(EXP / 'regression/old-integrity-after.json', integrity_result)
oldpass = all(row['pass'] for row in integrity_result.values())
failures = [read(path) for path in sorted((EXP / 'audit').glob('stopped-*.json'))]
known_failure = bool(any(not value for group in (controls, comparisons, components, repeats) for value in group.values()) or
any(gate is not None and not gate['pass_all'] for gate in gates.values()) or
any(not summary['execution_gate_pass'] for summary in summaries.values()) or
any(row.get('stop_kind') == 'execution_or_numerical_failure' for row in failures))
status = decide_status(numerical=numerical, seed=seed, novel=novel, integrity_pass=oldpass,
reference_present=frozen is not None, reference_pass=bool(frozen and frozen['pass_all']),
known_numerical_failure=known_failure, unauthorized_novel=unauthorized)
present_runs = []
for path in sorted((EXP / 'gpu').glob('*/*/summary.json')):
value = read(path)
present_runs.append(dict(group=path.parent.parent.name, run=path.parent.name,
complete=value.get('complete', False), pass_all=value.get('pass_all', False),
**{key: value.get(key) for key in ('case', 'nodes', 'edges', 'total_spikes',
'diagnostic_simulation_seconds', 'peak_allocated_vram_bytes')}))
completed_primary = [row for row in present_runs if row['group'] in CFG['validation']['cohorts']
and row['run'].endswith('-r0') and row['complete']]
result = dict(status=status, numerical_gate_pass=numerical, summaries=summaries, gates=gates,
controls=controls, comparisons=comparisons, components=components, repeats=repeats, stopped=failures,
seed_validation_pass=seed_pass, novel_to_aj_pass=bool(novel and novel['pass_all']),
novel_dynamics_executed=bool(novel_paths), novel_unlock_policy_violation=unauthorized,
planned_primary_cases=120, actual_primary_cases=len(completed_primary), measurements=present_runs,
aggregated_valid_primary_cases=sum(summary['valid_base_trials'] for summary in summaries.values()),
actual_checked_repeats=sum(summary['checked_repeats'] for summary in summaries.values()),
old_frozen_integrity_pass=oldpass, frozen_five_reference_pass=bool(frozen and frozen['pass_all']),
unchanged_sealed_runtime=True, dynamics_changed=False, old_heldout_dynamic_results_parsed=False,
novel_scope='Unused for AG/AJ calibration, not historically never simulated',
shared_APL_arithmetic_oracle_limitation=True, biological_delay_measured=False,
APL_nonKC_fast_edges_unreplaced=1212, learning_achieved=False, candidate_generated=False,
full_scientific_goal_achieved=False, payload_bytes_before_manifest=budget(),
next_gate='Credit specificity and real KC-to-MBON functional transfer before conditioning' if status.startswith('PASS-')
else 'Inspect the first failed gate without tuning this frozen branch or replacing validation inputs')
save(EXP / 'audit/final-status.json', result)
with (EXP / 'REPORT.md').open('x', encoding='utf-8') as stream:
stream.write('\n'.join(['# Phase 4AK — frozen D18 independent validation', '', f'Status: `{status}`.', '',
f'Numerical gate: {numerical}. Seed-validation pass: {seed_pass}. Novel-to-AJ pass: {result["novel_to_aj_pass"]}.',
f'Novel dynamics executed: {bool(novel_paths)}. Unauthorized unlock: {unauthorized}.',
'Both cohorts and all requested inputs were locked before trajectories; no tuning or gate changes.',
'Original sealed AJ runtime functions are used unchanged, including 1,212 unreplaced non-KC APL fast edges.',
'The second six odors were not used for AG/AJ calibration; old 4L had simulated the full panel.',
'Static seed audit is bounded, not proof of universally unused or statistically independent RNG streams.',
'Brian LIF/FIFO is independent; APL arithmetic is intentionally shared and separately component-audited.',
f'Old frozen integrity: {oldpass}. Five old reference trials: {result["frozen_five_reference_pass"]}.',
'No learning, plasticity update, candidate, game, decoder, RL or Web. This is not completion of the learning goal.',
'Next gate: ' + result['next_gate'], '']))
check(); seal(MODEL); seal(EXP)
print(status, flush=True)
if __name__ == '__main__':
main()
@@ -0,0 +1,90 @@
{
"root": "/data/digital-drosophila/models/male-cns-lif/apl-timing-validation-v1",
"files": [
{
"path": "PROTOCOL.md",
"bytes": 5002,
"sha256": "2d3996933b6e5a31e6a737ade5f3ae6869ffd03e01002c793eccf9b4f71e987d"
},
{
"path": "SEED-AUDIT.md",
"bytes": 6540,
"sha256": "35e8bfe1bff62f3a5d9295c785e1b8cec8a2393eaa67d6c683046e48f30feb56"
},
{
"path": "config.json",
"bytes": 2183,
"sha256": "1718d8b01ece24930ff138f25c88f2f0e0f1cf69ad0ba655e5a0de5083e64df2"
},
{
"path": "context.py",
"bytes": 5834,
"sha256": "5e4e500d5ec777bb8ae7ff77ac9a7279bfe995b1a17be2baededdbe065c98b73"
},
{
"path": "encoder_inputs.py",
"bytes": 2431,
"sha256": "0061689abb1832e963718bd836bc8a50009ee38b258143a753b4d59e63414925"
},
{
"path": "finalize.py",
"bytes": 11542,
"sha256": "7eb638c357cec7f5f85032312c50a616402b5a8a9ab5aa0268c181f6c3ae0ce5"
},
{
"path": "prepare.py",
"bytes": 12405,
"sha256": "d8b8315f8800b3efdc7548620f0fae85da21a12b753b9985dd623bd529e2c50f"
},
{
"path": "run_case.py",
"bytes": 3382,
"sha256": "bba6c4a98c6edf1eaba60b8030a9eca646da7dd30b74b2a0c16e374efd022bfa"
},
{
"path": "run_suite.py",
"bytes": 7914,
"sha256": "3d9890f11f299c07956faa5c0a9ebe2ea28ade58d8acf01a8631c17025073345"
},
{
"path": "runtime_bridge.py",
"bytes": 22443,
"sha256": "8a6629f8cd991cf309b508c670b3009737f9b5f5e1f72560fa5bd4b1ff0bc64d"
},
{
"path": "seed-audit.json",
"bytes": 376926,
"sha256": "e14c0deb94432787aa1cac7618254aeb3db0bcd5b1d8328e20428496d38b220a"
},
{
"path": "test_encoder_inputs.py",
"bytes": 2771,
"sha256": "f1b3b8a0ca9bc41152485c05fd5f24fb7bb1f76c6ea111ffb941ae1225d914fe"
},
{
"path": "test_final_status.py",
"bytes": 2040,
"sha256": "a85466891352c15b3103d30e7229734ad6694c8a1347d5e0747da3315223c203"
},
{
"path": "test_runtime_bridge.py",
"bytes": 23574,
"sha256": "bc01a5ff38d79a7b66ab2eb9e6731164bb8a1e15b5b5c0c1655161c24e2c37cf"
},
{
"path": "test_validation.py",
"bytes": 17829,
"sha256": "03f5aacb5a1f9460d10b30744100a43c57e5488d32dada79c888529943c82cf0"
},
{
"path": "validation.py",
"bytes": 21631,
"sha256": "3464091a4cc2cba18946cb9c9b3d12a69bd3f79f1001096234b3a8467dc602c5"
},
{
"path": "verify_frozen.py",
"bytes": 2417,
"sha256": "a736b774e39ff0ad863e8efc720bd5f9ed7d30261776bb57f0a716a7052dba5a"
}
]
}
@@ -0,0 +1,180 @@
"""Lock both validation cohorts before outcomes; read no old novel-odor dynamics."""
from datetime import datetime, timezone
import ast
import json
import platform
import shutil
import subprocess
import sys
import numpy as np
import pandas as pd
import yaml
from context import (ROOT, MODEL, EXP, AJ, AJ_MODEL, AG, CFG, PINS, STATIC,
read, save, digest, sources, integrity, budget, bit_equal)
from encoder_inputs import frozen_pn_drive, make_requests, write_npz
def copy_exact(source, target):
target.parent.mkdir(parents=True, exist_ok=True)
with source.open('rb') as source_stream, target.open('xb') as target_stream:
shutil.copyfileobj(source_stream, target_stream)
assert digest(source) == digest(target)
def main():
assert not EXP.exists() or not any(EXP.iterdir()), 'Never reuse a populated experiment'
assert shutil.disk_usage(EXP.parent).free > CFG['output_budget_bytes'] + 10 * 1024**3
for relative, expected in PINS.items():
assert digest(ROOT / relative) == expected, relative
previous = read(AJ / 'audit/final-status.json')
assert previous['status'] == 'PASS-FIXED-CAL-APL-TIMING-HYPOTHESIS'
assert previous['delay18_representation_pass'] and previous['old_frozen_integrity_and_five_reference_pass']
assert CFG['apl'] == read(AJ_MODEL / 'config.json')['apl']
assert CFG['gates'] == read(AJ_MODEL / 'config.json')['gates']
assert CFG['apl_delay_steps'] == 18 and not CFG['training'] and not CFG['candidate_generation']
seed_audit = read(MODEL / 'seed-audit.json')
assert seed_audit['proposed_seeds'] == CFG['validation']['seeds'] and seed_audit['collision_found'] is False
seed_sources = []
for row in seed_audit['inspected_files']:
if row.get('remote_path'):
path = ROOT / row['remote_path']
assert path.is_relative_to(ROOT) and '..' not in path.parts
assert digest(path) == row['sha256'], row['remote_path']
seed_sources.append(dict(path=path.relative_to(ROOT).as_posix(), sha256=row['sha256']))
assert seed_sources, 'At least exact-mapped static seed sources must be checked on server'
for name in ('protocol', 'cases', 'gpu', 'oracle', 'component-audit', 'audit', 'validation', 'regression', 'logs', 'extension-build'):
(EXP / name).mkdir(parents=True, exist_ok=False)
command = [sys.executable, '-B', '-m', 'unittest', 'discover', '-v', '-s', str(MODEL), '-p', 'test_*.py']
test = subprocess.run(command, cwd=MODEL, text=True, capture_output=True)
with (EXP / 'regression/unit-tests.log').open('x', encoding='utf-8') as stream:
stream.write(test.stdout + test.stderr)
save(EXP / 'regression/unit-tests.json', dict(command=command, exit_code=test.returncode,
pass_all=test.returncode == 0, sha256=digest(EXP / 'regression/unit-tests.log')))
assert test.returncode == 0
inputs = {relative: expected for relative, expected in PINS.items()}
for row in seed_sources:
inputs[row['path']] = row['sha256']
for path in (AJ / 'audit/final-status.json', AJ / 'protocol/preregistered.json',
AG / 'protocol/calibration-cases.json', AG / 'protocol/encoder-audit.json'):
inputs[path.relative_to(ROOT).as_posix()] = digest(path)
save(EXP / 'protocol/preregistered.json', dict(timestamp_utc=datetime.now(timezone.utc).isoformat(),
sources=sources(), config=CFG, inputs=[dict(path=path, sha256=sha) for path, sha in sorted(inputs.items())],
parent_commit=subprocess.check_output(['git', '-C', str(ROOT), 'rev-parse', 'HEAD'], text=True).strip(),
prior_AJ_CAL_outcomes_known=True, before_new_requests_and_brain_trajectories=True,
training=False, candidate_generated=False, historical_never_simulated_odor_claim=False,
seed_collision_audit_scope='Only enumerated static sources and explicitly evaluated derivations; no universal independence claim',
shared_seed_across_conditions=True, new_dynamic_scope='seed_validation then conditionally novel_to_aj',
source_engine='Unmodified SHA-pinned AJ backend functions, using original __file__ and globals',
oracle_limit='Independent Brian LIF and delay FIFO, shared frozen Torch APL component',
python=sys.version, machine=platform.machine(), numpy=np.__version__))
save(EXP / 'regression/old-integrity-before.json', integrity())
from run_case import preflight
preflight()
import torch
cfg_path = ROOT / 'models/male-cns-lif/olfactory-grounding-v1/phase4l.yaml'
oc = yaml.safe_load(cfg_path.read_text())
assert oc['odor_encoder']['duration_ms'] == CFG['validation']['duration_ms']
assert oc['odor_encoder']['modes'] == CFG['validation']['modes']
panel = pd.read_parquet(STATIC / 'odor-encoder/frozen-odor-panel.parquet')
assert len(panel) == 12 and panel.odor_id.is_unique
assert panel.split.tolist() == ['calibration'] * 6 + ['heldout'] * 6
median = float(np.median(panel.mapped_response_sum))
assert median == CFG['validation']['median_mapped_response_sum']
selection = read(STATIC / 'odor-encoder/selection.json')
mapping = pd.read_parquet(STATIC / 'receptor-mapping/olfactory-mapping.parquet')
with np.load(STATIC / 'odor-encoder/mapped-glomerular-vectors.npz', allow_pickle=False) as source:
assert set(source.files) == set(panel.odor_id) | {'glomeruli'}
assert source['glomeruli'].tolist() == selection['glomeruli_order']
vectors = {oid: source[oid].copy() for oid in panel.odor_id}
encoder_source = ROOT / 'models/male-cns-lif/phase4l.py'
drive, ast_sha = frozen_pn_drive(encoder_source, PINS[str(encoder_source.relative_to(ROOT))])
cached = {}
static_rows = {}
for cohort, frame in (('seed_validation', panel.iloc[:6]), ('novel_to_aj', panel.iloc[6:])):
static_rows[cohort] = [dict(odor_id=str(odor.odor_id), odor_index=index,
source_panel_split=str(odor.split)) for index, (_, odor) in enumerate(frame.iterrows())]
for mode in CFG['validation']['modes']:
for index, (_, odor) in enumerate(frame.iterrows()):
targets, rates, ignored_frame = drive(str(odor.odor_id), vectors[odor.odor_id], mapping,
selection['glomeruli_order'], mode, median, oc)
assert targets.dtype == np.int32 and rates.dtype == np.float32 and len(targets) > 0
assert len(np.unique(targets)) == len(targets) and np.all((targets >= 0) & (targets < CFG['neurons']))
assert np.isfinite(rates).all() and np.all(rates > 0)
cached[(cohort, mode, index)] = (targets, rates)
# Reproduce all 60 known CAL input arrays, without any old heldout trajectory.
control_rows = []
old_inventory = read(AG / 'protocol/calibration-cases.json')
assert len(old_inventory) == 60
for row in old_inventory:
targets, rates = cached[('seed_validation', row['mode'], row['odor_index'])]
old_case = AG / 'cases' / row['name']
spec = read(old_case / 'spec.json')
assert spec['odor_id'] == static_rows['seed_validation'][row['odor_index']]['odor_id']
with np.load(old_case / 'pn-drive.npz', allow_pickle=False) as old:
assert bit_equal(targets, old['targets']) and bit_equal(rates, old['rates_hz'])
requests = make_requests(targets, rates, row['seed'])
with np.load(old_case / 'requests.npz', allow_pickle=False) as old:
assert bit_equal(requests[:, 0], old['tick']) and bit_equal(requests[:, 1], old['neuron_idx'])
control_rows.append(dict(case=row['name'], pass_all=True, seed=row['seed'],
old_requests_sha256=digest(old_case / 'requests.npz'), old_drive_sha256=digest(old_case / 'pn-drive.npz'),
target_rate_and_request_arrays_bitwise=True))
save(EXP / 'protocol/encoder-control.json', dict(pass_all=True, cases=control_rows,
old_heldout_dynamic_access=False, comparison='All original 60 CAL request/drive arrays; no trajectory or RNG-column reorder'))
template = read(AJ / 'cases/delay18' / CFG['control_cases'][0] / 'spec.json')
assert template['apl_delay_steps'] == 18 and template['steps'] == 1000 and template['record_history'] is False
control_cases = []
for name in CFG['control_cases']:
source = AJ / 'cases/delay18' / name
target = EXP / 'cases/controls' / name
target.mkdir(parents=True, exist_ok=False)
spec = read(source / 'spec.json')
spec.update(budget_root=str(EXP), output_budget_bytes=CFG['output_budget_bytes'])
save(target / 'spec.json', spec)
for filename in ('requests.npz', 'pn-drive.npz'):
copy_exact(source / filename, target / filename)
control_cases.append(dict(name=name, source_case=str(source), source_output=str(AJ / 'gpu/delay18' / (name + '-r0'))))
save(EXP / 'protocol/control-cases.json', control_cases)
records = []
for cohort, frame in (('seed_validation', panel.iloc[:6]), ('novel_to_aj', panel.iloc[6:])):
for mode in CFG['validation']['modes']:
for index, (_, odor) in enumerate(frame.iterrows()):
targets, rates = cached[(cohort, mode, index)]
for seed in CFG['validation']['seeds']:
requests = make_requests(targets, rates, seed)
name = f'{cohort}-{mode}-{index:02d}-s{seed}'
target = EXP / 'cases' / cohort / name
target.mkdir(parents=True, exist_ok=False)
expected = float(rates.sum()) * 1000 * .1 / 1000.
spec = dict(template, name=name, kind='fullgraph', validation_cohort=cohort,
source_panel_split=str(odor.split), source_panel_row=int(odor.name),
odor_id=str(odor.odor_id), odor_name=str(odor.odor_name), mode=mode, seed=seed,
odor_index=index, expected_external_events=expected, target_count=len(targets),
rate_sum_hz=float(rates.sum()), budget_root=str(EXP), output_budget_bytes=CFG['output_budget_bytes'])
save(target / 'spec.json', spec)
write_npz(target / 'requests.npz', tick=requests[:, 0], neuron_idx=requests[:, 1])
write_npz(target / 'pn-drive.npz', targets=targets, rates_hz=rates)
records.append(dict(name=name, cohort=cohort, source_panel_split=str(odor.split),
source_panel_row=int(odor.name), mode=mode, odor_id=str(odor.odor_id), odor_index=index,
seed=seed, targets=len(targets), requests=len(requests), expected_external_events=expected,
rates_sum=float(rates.sum())))
assert len(records) == 120 and len({row['name'] for row in records}) == 120
save(EXP / 'protocol/validation-cases.json', records)
save(EXP / 'protocol/encoder-audit.json', dict(panel_count=12, cal_count=6, novel_to_aj_count=6,
median_mapped_response_sum=median, seeds=CFG['validation']['seeds'],
seeds_static_audit_sha256=digest(MODEL / 'seed-audit.json'), cohorts_static_panel_rows=static_rows,
requested_before_any_dynamics=True, historical_never_simulated_claim=False,
old_heldout_dynamic_access=False, seed_namespace_universally_independent_claim=False,
source_function='Unmodified AST node pn_drive from pinned phase4l.py; only np/pd/typing dependencies',
source_sha256=digest(encoder_source), function_ast_sha256=ast_sha, torch=torch.__version__, numpy=np.__version__,
control_60_original_CAL_arrays_exact=True, target_rng_column_order='Original function output, unchanged',
generation='Original float32 rates*.1/1000 GPU Bernoulli; same seed across conditions; sort only resulting sparse requests',
expected_not_realized_input_energy_matched=True, no_learning=True))
save(EXP / 'protocol/prepared-hashes.json', [dict(path=p.relative_to(EXP).as_posix(), sha256=digest(p), bytes=p.stat().st_size)
for directory in ('protocol', 'cases') for p in sorted((EXP / directory).rglob('*'))
if p.is_file() and p.name != 'prepared-hashes.json'])
budget()
print('REGISTERED 2 controls +120 fixed validation cases; 60 original input arrays exact; no brain trajectories', flush=True)
if __name__ == '__main__':
main()
@@ -0,0 +1,66 @@
"""One registered AK action per fresh process; no changes to frozen runtimes."""
import argparse
import json
import os
import urllib.request
from context import ROOT, EXP, CFG, check, budget, read
import runtime_bridge as bridge
def preflight():
# Establish visibility before the lazy runtime/component Torch import.
os.environ['CUDA_VISIBLE_DEVICES'] = CFG['gpu_uuid']
os.environ['CUDA_HOME'] = '/usr/local/cuda'
os.environ['PATH'] = str(ROOT / 'models/male-cns-lif/.venv/bin') + ':/usr/local/cuda/bin:' + os.environ['PATH']
os.environ['MAX_JOBS'] = '2'
os.environ['TORCH_CUDA_ARCH_LIST'] = '8.9'
for port in (8188, 8189, 8190):
with urllib.request.urlopen(f'http://192.168.10.51:{port}/queue', timeout=5) as response:
queue = json.load(response)
bridge.require(not queue['queue_running'] and not queue['queue_pending'], 'ComfyUI busy: defer, never evict')
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('backend', choices=['gpu', 'oracle', 'component'])
parser.add_argument('group', choices=bridge.GROUPS)
parser.add_argument('case')
parser.add_argument('--repeat', type=int, default=0)
args = parser.parse_args()
check(); budget()
row = bridge.authorize_case(EXP, CFG, args.group, args.case, args.backend, args.repeat)
case = EXP / 'cases' / args.group / args.case
spec = bridge.case_spec(case)
bridge.require(spec['name'] == args.case and spec['budget_root'] == str(EXP) and
spec['output_budget_bytes'] == CFG['output_budget_bytes'], 'Case identity/new budget differs')
if args.group == 'controls':
bridge.control_inputs(case, row['source_case'])
else:
bridge.require(spec.get('kind') == 'fullgraph' and spec.get('validation_cohort') == args.group and
all(spec[key] == row[key] for key in ('mode', 'odor_id', 'odor_index', 'seed')),
'New fullgraph case differs from its registered cohort cell')
output = EXP / 'gpu' / args.group / f'{args.case}-r{args.repeat}'
if args.backend == 'component':
summary = read(output / 'summary.json')
bridge.require(summary.get('complete') is True and summary.get('pass_all') is True and
summary.get('case') == args.case and summary.get('apl_delay_steps') == 18,
'Component audit needs a complete matching D18 GPU run')
preflight()
def execute():
if args.backend == 'gpu':
result = bridge.run_gpu(case, output, EXP / 'extension-build')
elif args.backend == 'oracle':
result = bridge.run_oracle(case, EXP / 'oracle' / args.group / args.case)
else:
result = bridge.component(output, spec['apl_bundle_dir'], EXP / 'component-audit' / args.group / (args.case + '.json'))
budget()
bridge.require(result.get('pass_all') is True, 'Runtime/component evidence did not pass its own integrity checks')
return result
result = bridge.guarded_action(EXP, args.backend, args.group, args.case, args.repeat, execute)
print(json.dumps(dict(backend=args.backend, group=args.group, case=args.case, repeat=args.repeat,
complete=result.get('complete'), pass_all=result.get('pass_all')), allow_nan=False), flush=True)
if __name__ == '__main__':
main()
@@ -0,0 +1,151 @@
"""Ordered fixed-D18 validation; representation failure never becomes execution failure.
Only the two predeclared first-odor/first-seed mode probes use Brian per cohort.
Their GPU r0 outputs are reused in the full 60-case block. No novel-to-AJ
trajectory can start until the complete seed block and its repeats pass.
"""
import argparse
import subprocess
import time
import traceback
from context import ROOT, MODEL, EXP, CFG, check, save, read, budget
import runtime_bridge as bridge
SCIENCE = ROOT / 'models/male-cns-lif/.venv/bin/python'
ORACLE = ROOT / 'experiments/phase4ad-author-semantics/environment/.venv/bin/python'
class RepresentationGateFailed(RuntimeError):
"""Completed valid trajectories did not pass the predeclared representation gate."""
def child(backend, group, name, repeat=0):
# Do not resolve either interpreter: the venv invocation path is meaningful.
interpreter = ORACLE if backend == 'oracle' else SCIENCE
bridge.require(interpreter.is_file(), 'Missing fixed runtime interpreter: ' + str(interpreter))
bridge.authorize_case(EXP, CFG, group, name, backend, repeat)
log = EXP / 'logs' / f'{backend}-{group}-{name}-r{repeat}.log'
log.parent.mkdir(parents=True, exist_ok=True)
command = [str(interpreter), '-B', str(MODEL / 'run_case.py'), backend, group, name, '--repeat', str(repeat)]
print('START', backend, group, name, repeat, flush=True)
started = time.perf_counter()
with log.open('x', encoding='utf-8') as stream:
result = subprocess.run(command, stdout=stream, stderr=subprocess.STDOUT, timeout=1800, check=False)
print('FINISH', backend, group, name, repeat, 'exit', result.returncode,
'wall', round(time.perf_counter() - started, 2), flush=True)
bridge.require(result.returncode == 0, f'{backend} {group}/{name} failed; preserve partial evidence and inspect {log}')
def control(row):
name = row['name']
child('gpu', 'controls', name)
case = EXP / 'cases/controls' / name
output = EXP / 'gpu/controls' / (name + '-r0')
report = bridge.control_identity(output, row['source_output'], case, row['source_case'],
EXP / 'audit' / ('control-' + name + '.json'))
bridge.require(report['pass_all'], 'Fresh fixed-D18 control differs from sealed AJ: ' + name)
child('component', 'controls', name)
return dict(case=name, group='controls', pass_all=True, fresh_gpu_runs=1, new_oracle_runs=0)
def probe(row):
name, group = row['name'], row['cohort']
child('gpu', group, name)
child('oracle', group, name)
result = bridge.compare(EXP / 'cases' / group / name, EXP / 'gpu' / group / (name + '-r0'),
EXP / 'oracle' / group / name, EXP / 'audit' / ('compare-' + group + '-' + name + '.json'))
bridge.require(result['pass_all'], 'Closed-loop fixed-D18 comparison failed: ' + name)
child('component', group, name)
return dict(case=name, group=group, pass_all=True, fresh_gpu_runs=1, new_oracle_runs=1)
def validation_block(cohort, records):
from validation import summarize
rows = bridge.cohort_rows(records, CFG, cohort)
probes = {row['name'] for row in bridge.probe_rows(records, CFG, cohort)}
repeated = []
for row in rows:
name = row['name']
if name not in probes:
child('gpu', cohort, name)
else:
comparison = read(EXP / 'audit' / ('compare-' + cohort + '-' + name + '.json'))
bridge.require(comparison.get('pass_all') is True and comparison.get('case') == name,
'Missing successful probe evidence for reused r0: ' + name)
if row['seed'] == CFG['validation']['seeds'][0]:
child('gpu', cohort, name, 1)
result = bridge.compare_gpu_repeats(EXP / 'gpu' / cohort / (name + '-r0'),
EXP / 'gpu' / cohort / (name + '-r1'), EXP / 'audit' / ('repeat-' + cohort + '-' + name + '.json'))
bridge.require(result['pass_all'], 'Fixed-input GPU repeat diverged: ' + name)
repeated.append(name)
bridge.require(len(rows) == 60 and len(repeated) == 12, 'Incomplete registered base/repeat block')
result = summarize(cohort)
return result, repeated
def run(stage):
bridge.require(stage in bridge.STAGES, 'Unknown stage')
check(); budget()
bridge.ensure_unstopped(EXP)
receipt = EXP / 'audit' / (stage + '-gate.json')
bridge.require(not receipt.exists() and not (EXP / 'audit' / ('stopped-' + stage + '.json')).exists(),
'Stage already has completion/stop evidence; do not rerun or overwrite')
controls, records = bridge.inventories(EXP, CFG)
try:
if stage == 'controls':
rows = [control(row) for row in controls]
result = dict(stage=stage, pass_all=True, cases=rows, scope='Same-input fresh D18 GPU identity with sealed AJ; no new model or Brian run')
else:
bridge.gate_pass(EXP, 'controls')
cohort = 'seed_validation' if stage.startswith('seed-') else 'novel_to_aj'
if cohort == 'novel_to_aj':
bridge.gate_pass(EXP, 'seed-validation', representation=True, cfg=CFG)
if stage.endswith('-probes'):
rows = [probe(row) for row in bridge.probe_rows(records, CFG, cohort)]
result = dict(stage=stage, pass_all=True, cases=rows,
scope='Two fixed first-odor first-seed mode probes; independent LIF with shared unchanged Torch APL component')
else:
bridge.gate_pass(EXP, 'seed-probes' if cohort == 'seed_validation' else 'novel-probes')
summary, repeats = validation_block(cohort, records)
execution = summary.get('execution_gate_pass') is True
representation = summary.get('representation_gate_pass') is True
if execution:
bridge.validate_summary_coverage(summary, EXP, CFG, cohort)
result = dict(stage=stage, cohort=cohort, pass_all=execution,
execution_gate_pass=execution, representation_gate_pass=representation,
base_count=60, repeat_count=len(repeats), repeat_cases=repeats,
summary='validation/' + cohort + '/summary.json',
summary_sha256=bridge.digest(EXP / 'validation' / cohort / 'summary.json'),
validation_inventory_sha256=bridge.digest(EXP / 'protocol/validation-cases.json'),
scope='Complete fixed representation block; no pooled rescue, learning, tuning, or historically-unseen-odor claim')
save(receipt, result)
if stage.endswith('-validation'):
bridge.require(result['execution_gate_pass'], 'Validation execution/numerical/integrity gate failed')
if not result['representation_gate_pass']:
raise RepresentationGateFailed('Completed fixed validation block failed representation; no later cohort is authorized')
budget()
return result
except Exception as error:
save(EXP / 'audit' / ('stopped-' + stage + '.json'), dict(stage=stage,
type=type(error).__name__, message=str(error), traceback=traceback.format_exc(),
stop_kind='representation_failure' if isinstance(error, RepresentationGateFailed) else 'execution_or_numerical_failure',
representation_failure_is_execution_failure=False,
later_stages_not_permitted=True, partial_outputs_preserved=True,
parameters_changed=False, replacement_seeds_or_odors_selected=False))
raise
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('stage', choices=bridge.STAGES)
args = parser.parse_args()
try:
run(args.stage)
except RepresentationGateFailed:
raise SystemExit(2)
if __name__ == '__main__':
main()
@@ -0,0 +1,396 @@
"""Phase 4AK orchestration only: call hash-pinned, unchanged AJ functions.
No LIF, APL, queue, or input-generation equation is implemented here. Fresh
processes resolve AJ's one unqualified import to the pinned AJ timing_queue.
The D18 control adapter compares evidence; it never changes a case to D0.
"""
from __future__ import annotations
import hashlib
import importlib.util
import json
from pathlib import Path
import re
import sys
import traceback
AJ_PINS = {
'gpu_timing.py': 'af1975ba5e5e700208c0a598d3cbe648a3cf10885c6231239b6e4b28f76d173b',
'oracle_timing.py': '39d8c47c94bc2faddf016864a43e7715907fb987f56f7b27098060a88851f6be',
'compare_timing.py': '9010f070fba9b7c9cf2d86187ee2abc57f3ac606ebc08a42baad4f3922b51734',
'timing_queue.py': '54df6d4818e2a0c26e96fb0aaf5d9b71cd964981706da937562d48af79aca14e',
}
COMPONENT_SHA256 = '5cfc9a4505da6b8fb4e7d2617cdaedaa8475ed46a11ec9bdf0d4d25b1d22c2d3'
COHORTS = ('seed_validation', 'novel_to_aj')
GROUPS = ('controls',) + COHORTS
STAGES = ('controls', 'seed-probes', 'seed-validation', 'novel-probes', 'novel-validation')
_BUDGET_KEYS = frozenset(('budget_root', 'output_budget_bytes'))
_LOADED = {}
def require(ok, message):
if not ok:
raise ValueError(message)
def read(path):
return json.loads(Path(path).read_text(encoding='utf-8'))
def digest(path):
result = hashlib.sha256()
with Path(path).open('rb') as stream:
for block in iter(lambda: stream.read(8 << 20), b''):
result.update(block)
return result.hexdigest()
def save(path, report):
if path is None:
return
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
with path.open('x', encoding='utf-8') as stream:
json.dump(report, stream, ensure_ascii=False, indent=2, sort_keys=True, allow_nan=False)
stream.write('\n')
def load_checked(name, path, expected_hash):
"""Execute the verified bytes with importlib metadata, without old pyc writes."""
path = Path(path).absolute()
data = path.read_bytes()
require(hashlib.sha256(data).hexdigest() == expected_hash, 'Sealed source SHA mismatch: ' + str(path))
if name in sys.modules:
existing = sys.modules[name]
require(Path(getattr(existing, '__file__', '')).absolute() == path and
_LOADED.get(name) == (path, expected_hash, existing),
'Refusing an existing unverified module name: ' + name)
return existing
spec = importlib.util.spec_from_file_location(name, path)
require(spec is not None and spec.loader is not None, 'Cannot create sealed module specification')
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
try:
exec(compile(data, str(path), 'exec'), module.__dict__)
except BaseException:
sys.modules.pop(name, None)
raise
# Keep verification metadata here, not in the sealed module's globals.
_LOADED[name] = (path, expected_hash, module)
return module
def sealed(filename, aj_model=None):
require(filename in AJ_PINS, 'Unregistered AJ module')
if aj_model is None:
from context import AJ_MODEL
aj_model = AJ_MODEL
directory = Path(aj_model)
if filename == 'gpu_timing.py':
load_checked('timing_queue', directory / 'timing_queue.py', AJ_PINS['timing_queue.py'])
name = 'phase4ak_sealed_aj_' + Path(filename).stem
return load_checked(name, directory / filename, AJ_PINS[filename])
def case_spec(case_dir):
spec = read(Path(case_dir) / 'spec.json')
require(isinstance(spec.get('name'), str) and re.fullmatch(r'[A-Za-z0-9_-]+', spec['name']), 'Unsafe case name')
require(type(spec.get('apl_delay_steps')) is int and spec['apl_delay_steps'] == 18, 'AK permits fixed D18 only')
require(spec.get('steps') == 1000 and type(spec['steps']) is int and spec.get('dt_ms') == .1 and
spec.get('duration_ms') == 100.0 and spec.get('record_history') is False,
'AK requires the unchanged fullgraph 100 ms window')
require(spec.get('training') is False and spec.get('poi_used', False) is False and
spec.get('precision') == 'float64' and spec.get('apl_precision') == 'float32',
'Frozen no-learning / no-poi / precision scope changed')
require(spec.get('apl') == {'tau_ms': 20, 'gain': .01, 'normalization': 1}, 'Frozen APL parameters changed')
for field in ('graph_dir', 'apl_bundle_dir', 'coefficients_path', 'science_python', 'legacy_apl_worker'):
require(field in spec and Path(spec[field]).is_absolute(), 'Missing absolute path: ' + field)
require(isinstance(spec.get('model'), dict), 'Missing original author parameter dictionary')
return spec
def _new_output(case_dir, out_dir):
spec = case_spec(case_dir)
output = Path(out_dir).absolute()
budget_root = Path(spec['budget_root']).absolute()
require(type(spec.get('output_budget_bytes')) is int and spec['output_budget_bytes'] > 0,
'Missing positive output budget')
require(output.is_relative_to(budget_root) and output != budget_root and not output.exists(),
'Output must be a new exclusive child of this case budget root')
return spec
def _receipt(output, backend, filename, aj_model):
module = sealed(filename, aj_model)
require(digest(module.__file__) == AJ_PINS[filename], 'Sealed runtime changed during invocation')
receipt = {'backend': backend, 'sealed_runtime': str(module.__file__),
'sealed_runtime_sha256': AJ_PINS[filename], 'apl_delay_steps': 18,
'old_module_scientific_globals_changed': False, 'dynamics_copied_or_reimplemented': False,
'scope': 'Unchanged AJ runtime called with new case/output/build arguments; not a new numerical model'}
save(Path(output) / 'runtime-bridge.json', receipt)
def run_gpu(case_dir, out_dir, build_root, *, aj_model=None):
spec = _new_output(case_dir, out_dir)
build_root = Path(build_root).absolute()
require(build_root.is_relative_to(Path(spec['budget_root']).absolute()) and
build_root != Path(spec['budget_root']).absolute(), 'Build cache must stay in the new experiment')
module = sealed('gpu_timing.py', aj_model)
result = module.run_gpu(Path(case_dir), Path(out_dir), build_root)
_receipt(out_dir, 'gpu', 'gpu_timing.py', aj_model)
return result
def run_oracle(case_dir, out_dir, *, aj_model=None):
_new_output(case_dir, out_dir)
require('torch' not in sys.modules, 'Pinned Brian process must not import Torch')
module = sealed('oracle_timing.py', aj_model)
result = module.run_case(Path(case_dir), Path(out_dir))
_receipt(out_dir, 'oracle', 'oracle_timing.py', aj_model)
return result
def compare(case_dir, gpu_dir, cpu_dir, out_json=None, *, aj_model=None):
case_spec(case_dir)
return sealed('compare_timing.py', aj_model).compare(case_dir, gpu_dir, cpu_dir, out_json)
def compare_gpu_repeats(first, second, out_json=None, *, aj_model=None):
require(all(read(Path(path) / 'summary.json').get('apl_delay_steps') == 18 for path in (first, second)),
'Repeat evidence must be fixed D18')
return sealed('compare_timing.py', aj_model).compare_gpu_repeats(first, second, out_json)
def component(output, bundle, out_json, *, ag_model=None):
if ag_model is None:
from context import AG_MODEL
ag_model = AG_MODEL
module = load_checked('phase4ak_sealed_ag_components', Path(ag_model) / 'validate_components.py', COMPONENT_SHA256)
return module.validate(Path(output), Path(bundle), Path(out_json))
def control_inputs(newcase, oldcase):
"""Only budget metadata may differ; all saved request/drive bytes are identical."""
newcase, oldcase = Path(newcase), Path(oldcase)
fresh, old = case_spec(newcase), case_spec(oldcase)
require({k: v for k, v in fresh.items() if k not in _BUDGET_KEYS} ==
{k: v for k, v in old.items() if k not in _BUDGET_KEYS},
'D18 control scientific specification changed beyond the two budget fields')
evidence = {str(folder / 'spec.json'): digest(folder / 'spec.json') for folder in (newcase, oldcase)}
files = ['requests.npz', 'pn-drive.npz']
require((newcase / 'arrays.npz').exists() == (oldcase / 'arrays.npz').exists(), 'Control initial-state presence changed')
if (newcase / 'arrays.npz').exists():
files.append('arrays.npz')
for name in files:
first, second = digest(newcase / name), digest(oldcase / name)
require(first == second, 'Control input byte mismatch: ' + name)
evidence[str(newcase / name)], evidence[str(oldcase / name)] = first, second
return fresh, old, evidence
def control_identity(newdir, olddir, newcase, oldcase, out_json=None, *, aj_model=None):
"""D18 scientific identity using unchanged AJ comparison primitives.
Unlike the AJ D0-vs-AG adapter, this checks real D18 applied/pending files.
Input SHA fields are checked against each real spec, not compared after
deleting metadata. Only build/cache paths and the two budget fields are
permitted to differ; all numerical/timing/component evidence stays exact.
"""
require(out_json is None or not Path(out_json).exists(), 'Refusing existing control report')
aj = sealed('compare_timing.py', aj_model)
checks, differences, used = {}, {}, set()
report = {'kind': 'fixed-D18 same-input sealed-AJ control identity', 'pass_all': False,
'new_output': str(newdir), 'old_output': str(olddir), 'new_case': str(newcase), 'old_case': str(oldcase),
'apl_delay_steps': 18, 'tolerance': None, 'signed_zero_included': True,
'dynamics_copied_or_reimplemented': False, 'old_globals_patched': False,
'independent_CPU_all_components_claim': False,
'allowed_case_metadata_differences': sorted(_BUDGET_KEYS),
'build_and_wall_metadata_compared': False}
try:
spec, old_spec, inputs = control_inputs(newcase, oldcase)
used.update(Path(path) for path in inputs)
checks['control_input_spec_and_bytes'] = True
steps, n, edges = spec['steps'], 166700, 25582938
left = aj._load_run(Path(newdir), 'fresh_gpu', n, edges, steps, False, spec['name'], 18, used, checks)
right = aj._load_run(Path(olddir), 'sealed_gpu', n, edges, steps, False, spec['name'], 18, used, checks)
aj._pair_outputs(left, right, checks, differences, n, steps, False)
for role, run, case, case_input in (('fresh_gpu', left, Path(newcase), spec),
('sealed_gpu', right, Path(oldcase), old_spec)):
aj._timing_sequence_checks(run['apl']['inhibition'], run['apl']['applied'], run['pending'],
18, role, checks, differences)
aj._timing_metadata_checks(run, role, 18, steps, checks)
expected = {name: digest(case / name) for name in ('spec.json', 'requests.npz')}
if (case / 'arrays.npz').exists():
expected['arrays.npz'] = digest(case / 'arrays.npz')
weight, coeff = Path(case_input['graph_dir']) / 'weights.npy', Path(case_input['coefficients_path'])
used.update((weight, coeff))
expected.update({'base_weights.npy': digest(weight), 'coefficients.json': digest(coeff)})
checks[role + '.actual_input_hashes'] = run['summary'].get('input_sha256') == expected
stable = ('case', 'complete', 'pass_all', 'steps', 'completed_ticks', 'nodes', 'edges', 'precision',
'apl_precision', 'state_units', 'total_spikes', 'requested', 'accepted_requests', 'rejected_requests',
'arriving_edges', 'accepted_arriving_edges', 'counts_match_sparse_events', 'all_finite', 'record_history',
'apl_fast_edges_zeroed', 'kc_targets_present', 'effective_weights_raw_sha256', 'apl_schedule',
'apl_si_conversion', 'sealed_ae_backend_sha256', 'learning', 'apl_delay_steps', 'apl_timing',
'source_provenance', 'pending_generated_count', 'pending_initial_zero_prefix', 'pending_tail_shape',
'future_generated_decay_tail_included')
for key in stable:
checks['summary.' + key] = key in left['summary'] and key in right['summary'] and left['summary'][key] == right['summary'][key]
checks['timing_audit.parsed_exact'] = left['timing'] == right['timing']
report.update(case=spec['name'], steps=steps, nodes=n, edges=edges,
scope='Six state arrays, every tick state/queue/request, generated/applied/pending APL, component and timing metadata')
except Exception as error:
report['error'] = {'type': type(error).__name__, 'message': str(error)}
return aj._finish(report, checks, differences, used, out_json)
def inventories(exp, cfg):
"""Validate static cells before choosing any dynamic case; no old dynamic read."""
exp = Path(exp)
controls = read(exp / 'protocol/control-cases.json')
records = read(exp / 'protocol/validation-cases.json')
require(isinstance(controls, list) and len(controls) == 2 and
[row['name'] for row in controls] == cfg['control_cases'], 'Unexpected control inventory')
for row in controls:
require(re.fullmatch(r'[A-Za-z0-9_-]+', row['name']) and
all(Path(row[key]).is_absolute() for key in ('source_case', 'source_output')), 'Invalid control identity/path')
design = cfg['validation']
require(design['cohorts'] == list(COHORTS) and len(design['seeds']) == 5 and len(set(design['seeds'])) == 5 and
design['modes'] == ['physiological', 'matched_energy'] and design['odor_count'] == 6 and
design['repeat_first_seed_each_odor'] is True, 'Fixed validation design changed')
require(isinstance(records, list) and len(records) == 120, 'Expected 120 predeclared cases')
cells, names = set(), set()
for row in records:
key = (row['cohort'], row['mode'], row['odor_index'], row['seed'])
require(re.fullmatch(r'[A-Za-z0-9_-]+', row['name']) and row['name'] not in names and key not in cells,
'Duplicate/unsafe case identity')
require(type(row['odor_index']) is int and type(row['seed']) is int, 'Noninteger odor/seed')
cells.add(key); names.add(row['name'])
expected = {(cohort, mode, oi, seed) for cohort in COHORTS for mode in design['modes']
for oi in range(6) for seed in design['seeds']}
require(cells == expected, 'Missing or substituted validation cell')
return controls, records
def cohort_rows(records, cfg, cohort):
require(cohort in COHORTS, 'Unknown validation cohort')
design = cfg['validation']
return sorted((row for row in records if row['cohort'] == cohort),
key=lambda row: (design['modes'].index(row['mode']), row['odor_index'], design['seeds'].index(row['seed'])))
def probe_rows(records, cfg, cohort):
rows = [row for row in cohort_rows(records, cfg, cohort)
if row['odor_index'] == 0 and row['seed'] == cfg['validation']['seeds'][0]]
require(len(rows) == 2 and [row['mode'] for row in rows] == cfg['validation']['modes'], 'Fixed probe selection changed')
return rows
def ensure_unstopped(exp):
markers = sorted((Path(exp) / 'audit').glob('stopped-*.json'))
require(not markers, 'A prior stop marker forbids all new scientific actions: ' + ', '.join(path.name for path in markers))
def guarded_action(exp, backend, group, name, repeat, action):
"""Persist failure after invoking an authorized scientific action, even standalone.
The caller performs input authorization and external idle preflight first.
A failure here is an execution/audit failure, not evidence of instability.
"""
require(backend in ('gpu', 'oracle', 'component') and group in GROUPS and
isinstance(name, str) and re.fullmatch(r'[A-Za-z0-9_-]+', name) and
type(repeat) is int and repeat in (0, 1), 'Invalid guarded action identity')
ensure_unstopped(exp)
try:
return action()
except Exception as error:
save(Path(exp) / 'audit' / f'stopped-case-{backend}-{group}-{name}-r{repeat}.json', {
'stage': 'case', 'backend': backend, 'group': group, 'case': name, 'repeat': repeat,
'type': type(error).__name__, 'message': str(error), 'traceback': traceback.format_exc(),
'stop_kind': 'execution_or_numerical_failure', 'scientific_action_invoked': True,
'numerical_instability_inferred_from_execution_error': False,
'later_stages_not_permitted': True, 'partial_outputs_preserved': True,
'parameters_changed': False, 'replacement_seeds_or_odors_selected': False})
raise
def validate_summary_coverage(summary, exp, cfg, cohort, *, representation=False):
"""Bind the unlock to this cohort's exact 60 base / 12 repeat / 72 timing cells."""
_, records = inventories(exp, cfg)
rows = cohort_rows(records, cfg, cohort)
expected = {row['name'] for row in rows}
repeated = {row['name'] for row in rows if row['seed'] == cfg['validation']['seeds'][0]}
timing = {(name, 0) for name in expected} | {(name, 1) for name in repeated}
require(summary.get('cohort') == cohort and summary.get('phase') == '4AK' and
summary.get('apl_delay_steps') == 18 and summary.get('seeds') == cfg['validation']['seeds'] and
summary.get('duration_ms') == 100.0, 'Validation summary identity/window differs')
require(summary.get('expected_base_trials') == summary.get('valid_base_trials') == 60 and
summary.get('expected_repeats') == summary.get('checked_repeats') == 12 and
summary.get('checked_timing_trials') == 72, 'Incomplete validation coverage')
base_rows, repeat_rows, timing_rows = (summary.get(key, []) for key in ('runs', 'repeats', 'timing_checks'))
require(len(base_rows) == 60 and {row['case'] for row in base_rows} == expected and
all(row.get('cohort') == cohort and row.get('validation_cohort') == cohort for row in base_rows),
'Base-trial identities differ from the fixed cohort inventory')
require(len(repeat_rows) == 12 and {row['case'] for row in repeat_rows} == repeated and
all(row.get('pass_all') is True for row in repeat_rows), 'Exact-repeat identities/coverage failed')
require(len(timing_rows) == 72 and {(row['case'], row['repeat']) for row in timing_rows} == timing and
all(type(row['repeat']) is int and row.get('pass_all') is True and row.get('apl_delay_steps') == 18
and row.get('steps') == 1000 for row in timing_rows), 'Timing identities/coverage failed')
proof = summary.get('input_output_provenance', [])
require(len(proof) == 72 and {(row['case'], row['repeat']) for row in proof} == timing,
'Per-run evidence provenance does not cover exactly the registered cells')
require(summary.get('prerequisite_input_sha256', {}).get('validation_inventory') ==
digest(Path(exp) / 'protocol/validation-cases.json'), 'Summary was derived from a different validation inventory')
require(summary.get('execution_gate_pass') is True and summary.get('numerical_integrity_pass') is True and
summary.get('exact_repeat_pass') is True, 'Validation execution/numerical/repeat gate failed')
require(set(summary.get('modes', {})) == set(cfg['validation']['modes']), 'Incomplete mode summaries')
if representation:
require(summary.get('representation_gate_pass') is True and summary.get('pass_all') is True and
all(summary['modes'][mode].get('gate') is True for mode in cfg['validation']['modes']),
'Seed representation summary does not authorize novel dynamics')
def gate_pass(exp, stage, *, representation=False, cfg=None):
report = read(Path(exp) / 'audit' / (stage + '-gate.json'))
require(report.get('stage') == stage and report.get('pass_all') is True, 'Required execution gate failed: ' + stage)
if representation:
require(stage == 'seed-validation', 'Only the complete seed block unlocks novel trajectories')
require(report.get('execution_gate_pass') is True and report.get('representation_gate_pass') is True,
'Complete seed representation/execution gate required before novel dynamics')
if cfg is None:
from context import CFG
cfg = CFG
path = Path(exp) / 'validation/seed_validation/summary.json'
require(report.get('cohort') == 'seed_validation' and
report.get('summary') == 'validation/seed_validation/summary.json' and
report.get('summary_sha256') == digest(path), 'Seed gate is not bound to this exact summary')
require(report.get('validation_inventory_sha256') == digest(Path(exp) / 'protocol/validation-cases.json'),
'Seed gate inventory digest differs')
validate_summary_coverage(read(path), exp, cfg, 'seed_validation', representation=True)
return report
def authorize_case(exp, cfg, group, name, backend, repeat):
ensure_unstopped(exp)
require(group in GROUPS and backend in ('gpu', 'oracle', 'component') and type(repeat) is int and repeat in (0, 1),
'Invalid runtime action')
controls, records = inventories(exp, cfg)
rows = controls if group == 'controls' else cohort_rows(records, cfg, group)
selected = [row for row in rows if row['name'] == name]
require(len(selected) == 1, 'Case not in the registered group inventory')
row = selected[0]
if group == 'controls':
require(repeat == 0 and backend in ('gpu', 'component'), 'Controls are single fresh GPU identity runs')
else:
gate_pass(exp, 'controls')
if group == 'novel_to_aj':
gate_pass(exp, 'seed-validation', representation=True, cfg=cfg)
probes = {item['name'] for item in probe_rows(records, cfg, group)}
probe_stage = 'seed-probes' if group == 'seed_validation' else 'novel-probes'
if name not in probes or repeat:
gate_pass(exp, probe_stage)
if backend in ('oracle', 'component'):
require(name in probes and repeat == 0, 'Oracle/component scope is the two fixed probes per cohort')
if repeat:
require(backend == 'gpu' and row['seed'] == cfg['validation']['seeds'][0], 'Only declared first-seed repeats')
return row
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,53 @@
import tempfile
import unittest
from pathlib import Path
import numpy as np
from encoder_inputs import frozen_pn_drive, requests_from_forced, write_npz
class EncoderInputTests(unittest.TestCase):
def test_exact_frozen_encoder_ast_on_synthetic_static_mapping(self):
import pandas as pd
local = Path(__file__).resolve().parents[1] / 'models/male-cns-lif/phase4l.py'
source = local if local.exists() else Path('/data/digital-drosophila/models/male-cns-lif/phase4l.py')
pin = 'e97d58d8c1f44920d0e953f8f5831ddc86fa0198784e86460e315de4116ac553'
function, ast_sha = frozen_pn_drive(source, pin)
self.assertEqual(len(ast_sha), 64)
mapping = pd.DataFrame(dict(glomerulus=['G2', 'G2', 'G1', 'G1'],
mapping_confidence=['exact', 'alias-normalized', 'exact', 'unknown'], neuron_idx=[3, 1, 7, 999]))
cfg = {'odor_encoder': {'max_total_rate_per_glomerulus_hz': 400}}
target, rates, _ = function('synthetic', np.array([.5, .25], np.float32), mapping,
['G2', 'G1'], 'matched_energy', 1.5, cfg)
np.testing.assert_array_equal(target, np.array([3, 1, 7], np.int32))
np.testing.assert_array_equal(rates, np.array([200, 200, 200], np.float32))
with self.assertRaises(AssertionError):
frozen_pn_drive(source, '0' * 64)
def test_rng_column_order_preserved_until_request_sort(self):
targets = np.array([10, 1, 3], np.int32)
forced = np.array([[True, True, False], [False, True, True]], np.bool_)
actual = requests_from_forced(forced, targets)
np.testing.assert_array_equal(actual, np.array([[0, 1], [0, 10], [1, 1], [1, 3]], np.int32))
np.testing.assert_array_equal(targets, np.array([10, 1, 3], np.int32))
def test_duplicate_targets_rejected_not_merged(self):
with self.assertRaises(AssertionError):
requests_from_forced(np.ones((2, 2), np.bool_), np.array([1, 1], np.int32))
def test_empty_sparse_schedule_has_exact_shape_and_dtype(self):
result = requests_from_forced(np.zeros((3, 2), np.bool_), np.array([2, 1], np.int32))
self.assertEqual(result.shape, (0, 2))
self.assertEqual(result.dtype, np.int32)
def test_npz_creation_is_exclusive(self):
with tempfile.TemporaryDirectory() as directory:
path = Path(directory) / 'schedule.npz'
write_npz(path, tick=np.array([1], np.int32))
with np.load(path, allow_pickle=False) as stored:
np.testing.assert_array_equal(stored['tick'], np.array([1], np.int32))
with self.assertRaises(FileExistsError):
write_npz(path, tick=np.array([2], np.int32))
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,39 @@
import unittest
from finalize import decide_status
class FinalStatusTests(unittest.TestCase):
def decide(self, **overrides):
args = dict(numerical=True, seed=dict(execution_gate_pass=True, representation_gate_pass=True),
novel=dict(execution_gate_pass=True, representation_gate_pass=True), integrity_pass=True,
reference_pass=True, reference_present=True)
args.update(overrides)
return decide_status(**args)
def test_complete_only_representation_pass_is_not_named_learning(self):
self.assertEqual(self.decide(), 'PASS-FROZEN-D18-INDEPENDENT-VALIDATION')
def test_seed_failure_without_novel_is_completed_scientific_failure(self):
self.assertEqual(self.decide(seed=dict(execution_gate_pass=True, representation_gate_pass=False), novel=None),
'FAIL-SEED-VALIDATION-REPRESENTATION')
def test_novel_gate_failure_is_preserved(self):
self.assertEqual(self.decide(novel=dict(execution_gate_pass=True, representation_gate_pass=False)),
'FAIL-NOVEL-ODOR-REPRESENTATION')
def test_missing_execution_or_reference_is_not_scientific_pass(self):
for changes in (dict(numerical=False), dict(novel=None), dict(reference_present=False), dict(seed=None)):
with self.subTest(changes=changes):
self.assertEqual(self.decide(**changes), 'INCOMPLETE-VALIDATION-EXECUTION')
def test_numerical_and_unlock_failure_are_not_representation_results(self):
self.assertEqual(self.decide(known_numerical_failure=True), 'FAIL-NUMERICAL-OR-EXECUTION-POLICY')
self.assertEqual(self.decide(unauthorized_novel=True), 'FAIL-NUMERICAL-OR-EXECUTION-POLICY')
def test_old_integrity_or_reference_fail_overrides_new_pass(self):
self.assertEqual(self.decide(integrity_pass=False), 'FAIL-FROZEN-INTEGRITY-OR-REGRESSION')
self.assertEqual(self.decide(reference_pass=False), 'FAIL-FROZEN-INTEGRITY-OR-REGRESSION')
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,409 @@
"""CPU-only synthetic tests: no Torch/Brian import, GPU, remote, or brain run."""
import copy
import hashlib
import importlib.util
import json
from pathlib import Path
import sys
import tempfile
import types
import unittest
from unittest import mock
import numpy as np
import runtime_bridge as bridge
HERE = Path(__file__).absolute().parent
AJ = HERE.parent / 'apl-timing-lab-v1'
def write_json(path, data):
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(data), encoding='utf-8')
def spec(root, name='cal-physiological-00-s51101'):
return dict(name=name, kind='calibration', steps=1000, dt_ms=.1, duration_ms=100.,
model={'fixed': True}, graph_dir=str(root / 'graph'), apl_bundle_dir=str(root / 'bundle'),
coefficients_path=str(root / 'coefficients.json'), science_python=str(root / 'venv/python'),
legacy_apl_worker=str(root / 'legacy_apl_worker.py'),
apl={'tau_ms': 20., 'gain': .01, 'normalization': 1.}, apl_delay_steps=18,
record_history=False, training=False, precision='float64', apl_precision='float32',
budget_root=str(root / 'old-exp'), output_budget_bytes=1024)
def inventory(root):
cfg = dict(control_cases=['control-phys', 'control-matched'], validation={
'cohorts': list(bridge.COHORTS), 'seeds': [101, 102, 103, 104, 105],
'modes': ['physiological', 'matched_energy'], 'odor_count': 6,
'repeat_first_seed_each_odor': True})
controls = [dict(name=name, source_case=str(root / 'old-cases' / name),
source_output=str(root / 'old-gpu' / name)) for name in cfg['control_cases']]
rows = [dict(cohort=cohort, mode=mode, odor_index=oi, seed=seed,
name=f'{cohort}-{mode}-{oi:02d}-s{seed}') for cohort in bridge.COHORTS
for mode in cfg['validation']['modes'] for oi in range(6) for seed in cfg['validation']['seeds']]
write_json(root / 'protocol/control-cases.json', controls)
write_json(root / 'protocol/validation-cases.json', rows)
return cfg, rows
def gate(root, stage, **values):
write_json(root / 'audit' / (stage + '-gate.json'), dict(stage=stage, pass_all=True, **values))
def seed_summary(root, cfg, rows):
base = bridge.cohort_rows(rows, cfg, 'seed_validation')
repeated = [row for row in base if row['seed'] == cfg['validation']['seeds'][0]]
pairs = [(row['name'], 0) for row in base] + [(row['name'], 1) for row in repeated]
return dict(phase='4AK', cohort='seed_validation', apl_delay_steps=18, duration_ms=100.,
seeds=cfg['validation']['seeds'], pass_all=True, execution_gate_pass=True,
representation_gate_pass=True, numerical_integrity_pass=True, exact_repeat_pass=True,
expected_base_trials=60, valid_base_trials=60, expected_repeats=12, checked_repeats=12,
checked_timing_trials=72, runs=[dict(case=row['name'], cohort='seed_validation',
validation_cohort='seed_validation') for row in base],
repeats=[dict(case=row['name'], pass_all=True) for row in repeated],
timing_checks=[dict(case=name, repeat=repeat, pass_all=True, apl_delay_steps=18, steps=1000)
for name, repeat in pairs], input_output_provenance=[dict(case=name, repeat=repeat) for name, repeat in pairs],
modes={mode: dict(gate=True) for mode in cfg['validation']['modes']},
prerequisite_input_sha256={'validation_inventory': bridge.digest(root / 'protocol/validation-cases.json')})
def bind_seed_gate(root, summary):
path = root / 'validation/seed_validation/summary.json'
write_json(path, summary)
gate(root, 'seed-validation', cohort='seed_validation', execution_gate_pass=True,
representation_gate_pass=True, summary='validation/seed_validation/summary.json',
summary_sha256=bridge.digest(path), validation_inventory_sha256=bridge.digest(root / 'protocol/validation-cases.json'))
class LoaderTests(unittest.TestCase):
def test_verified_import_preserves_file_and_globals_without_pyc(self):
with tempfile.TemporaryDirectory() as temporary:
path = Path(temporary) / 'sealed.py'
data = b'VALUE = 37\n'
path.write_bytes(data)
name = '_test_phase4ak_sealed'
try:
module = bridge.load_checked(name, path, hashlib.sha256(data).hexdigest())
self.assertEqual(module.VALUE, 37)
self.assertEqual(Path(module.__file__), path)
self.assertIs(bridge.load_checked(name, path, hashlib.sha256(data).hexdigest()), module)
self.assertNotIn('__phase4ak_loaded_sha256__', module.__dict__)
self.assertFalse((path.parent / '__pycache__').exists())
finally:
sys.modules.pop(name, None); bridge._LOADED.pop(name, None)
def test_sha_checked_before_execution(self):
with tempfile.TemporaryDirectory() as temporary:
path = Path(temporary) / 'sealed.py'
path.write_text('raise RuntimeError("must not execute")', encoding='utf-8')
with self.assertRaisesRegex(ValueError, 'SHA mismatch'):
bridge.load_checked('_test_bad_pin', path, '0' * 64)
self.assertNotIn('_test_bad_pin', sys.modules)
def test_existing_name_collision_is_not_silently_replaced(self):
with tempfile.TemporaryDirectory() as temporary:
path = Path(temporary) / 'sealed.py'
path.write_text('VALUE = 1', encoding='utf-8')
old = types.ModuleType('_test_collision')
sys.modules[old.__name__] = old
try:
with self.assertRaisesRegex(ValueError, 'unverified module'):
bridge.load_checked(old.__name__, path, bridge.digest(path))
self.assertIs(sys.modules[old.__name__], old)
finally:
sys.modules.pop(old.__name__, None)
def test_real_pure_sealed_module_load_does_not_import_torch_or_brian(self):
self.assertNotIn('torch', sys.modules)
self.assertNotIn('brian2', sys.modules)
compare = bridge.sealed('compare_timing.py', AJ)
self.assertEqual(bridge.digest(compare.__file__), bridge.AJ_PINS['compare_timing.py'])
self.assertTrue(callable(compare.compare))
self.assertNotIn('torch', sys.modules)
self.assertNotIn('brian2', sys.modules)
class InputTests(unittest.TestCase):
def setUp(self):
self.temporary = tempfile.TemporaryDirectory()
self.root = Path(self.temporary.name)
self.old, self.new = self.root / 'old', self.root / 'new'
self.old.mkdir(); self.new.mkdir()
self.old_spec = spec(self.root)
self.new_spec = dict(self.old_spec, budget_root=str(self.root / 'new-exp'), output_budget_bytes=2048)
write_json(self.old / 'spec.json', self.old_spec)
write_json(self.new / 'spec.json', self.new_spec)
for name in ('requests.npz', 'pn-drive.npz'):
for directory in (self.old, self.new):
(directory / name).write_bytes(b'identical synthetic saved input bytes')
def tearDown(self):
self.temporary.cleanup()
def test_control_allows_only_budget_difference(self):
fresh, old, evidence = bridge.control_inputs(self.new, self.old)
self.assertEqual(fresh['apl_delay_steps'], old['apl_delay_steps'])
self.assertEqual(len(evidence), 6)
changed = dict(self.new_spec, mode='changed')
write_json(self.new / 'spec.json', changed)
with self.assertRaisesRegex(ValueError, 'beyond the two budget fields'):
bridge.control_inputs(self.new, self.old)
def test_drive_and_request_bytes_both_checked(self):
for name in ('requests.npz', 'pn-drive.npz'):
with self.subTest(name=name):
original = (self.new / name).read_bytes()
(self.new / name).write_bytes(original + b'changed')
with self.assertRaisesRegex(ValueError, name):
bridge.control_inputs(self.new, self.old)
(self.new / name).write_bytes(original)
def test_real_d18_required_no_fake_d0(self):
for value in (0, True, 18.0):
with self.subTest(value=value):
write_json(self.new / 'spec.json', dict(self.new_spec, apl_delay_steps=value))
with self.assertRaisesRegex(ValueError, 'D18'):
bridge.control_inputs(self.new, self.old)
def test_initial_state_presence_and_bytes_checked(self):
(self.new / 'arrays.npz').write_bytes(b'a')
with self.assertRaisesRegex(ValueError, 'presence'):
bridge.control_inputs(self.new, self.old)
(self.old / 'arrays.npz').write_bytes(b'b')
with self.assertRaisesRegex(ValueError, 'arrays.npz'):
bridge.control_inputs(self.new, self.old)
def test_exclusive_output_and_new_budget_containment(self):
root = Path(self.new_spec['budget_root'])
root.mkdir()
out = root / 'gpu' / 'run'
bridge._new_output(self.new, out)
out.mkdir(parents=True)
with self.assertRaisesRegex(ValueError, 'exclusive'):
bridge._new_output(self.new, out)
with self.assertRaisesRegex(ValueError, 'exclusive'):
bridge._new_output(self.new, self.root / 'elsewhere')
def test_control_refuses_overwrite_before_reading_outputs(self):
report = self.root / 'report.json'
report.write_text('keep me', encoding='utf-8')
with self.assertRaisesRegex(ValueError, 'existing control'):
bridge.control_identity('missing-new', 'missing-old', self.new, self.old, report)
self.assertEqual(report.read_text(encoding='utf-8'), 'keep me')
class GateTests(unittest.TestCase):
def setUp(self):
self.temporary = tempfile.TemporaryDirectory()
self.root = Path(self.temporary.name)
self.cfg, self.rows = inventory(self.root)
def tearDown(self):
self.temporary.cleanup()
def test_exact_120_cells_and_fixed_two_probes(self):
controls, rows = bridge.inventories(self.root, self.cfg)
self.assertEqual(len(controls), 2)
for cohort in bridge.COHORTS:
probes = bridge.probe_rows(rows, self.cfg, cohort)
self.assertEqual(len(probes), 2)
self.assertTrue(all(row['odor_index'] == 0 and row['seed'] == 101 for row in probes))
def test_duplicate_or_replaced_cell_rejected(self):
rows = copy.deepcopy(self.rows)
rows[-1] = rows[0]
write_json(self.root / 'protocol/validation-cases.json', rows)
with self.assertRaises(ValueError):
bridge.inventories(self.root, self.cfg)
def test_controls_do_not_run_brian_or_repeats(self):
name = self.cfg['control_cases'][0]
bridge.authorize_case(self.root, self.cfg, 'controls', name, 'gpu', 0)
for backend, repeat in (('oracle', 0), ('gpu', 1)):
with self.assertRaises(ValueError):
bridge.authorize_case(self.root, self.cfg, 'controls', name, backend, repeat)
def test_probes_before_other_seed_runs(self):
gate(self.root, 'controls')
probe = bridge.probe_rows(self.rows, self.cfg, 'seed_validation')[0]
bridge.authorize_case(self.root, self.cfg, 'seed_validation', probe['name'], 'oracle', 0)
later = next(row for row in self.rows if row['cohort'] == 'seed_validation' and row['seed'] == 102)
with self.assertRaises(FileNotFoundError):
bridge.authorize_case(self.root, self.cfg, 'seed_validation', later['name'], 'gpu', 0)
gate(self.root, 'seed-probes')
bridge.authorize_case(self.root, self.cfg, 'seed_validation', later['name'], 'gpu', 0)
with self.assertRaises(ValueError):
bridge.authorize_case(self.root, self.cfg, 'seed_validation', later['name'], 'oracle', 0)
with self.assertRaises(ValueError):
bridge.authorize_case(self.root, self.cfg, 'seed_validation', later['name'], 'gpu', 1)
def test_novel_denied_on_representation_failure_even_execution_passes(self):
gate(self.root, 'controls')
gate(self.root, 'seed-validation', execution_gate_pass=True, representation_gate_pass=False)
probe = bridge.probe_rows(self.rows, self.cfg, 'novel_to_aj')[0]
with self.assertRaisesRegex(ValueError, 'representation'):
bridge.authorize_case(self.root, self.cfg, 'novel_to_aj', probe['name'], 'gpu', 0)
def test_novel_requires_both_gate_and_underlying_summary(self):
gate(self.root, 'controls')
probe = bridge.probe_rows(self.rows, self.cfg, 'novel_to_aj')[0]
summary = seed_summary(self.root, self.cfg, self.rows)
summary['representation_gate_pass'] = False
bind_seed_gate(self.root, summary)
with self.assertRaisesRegex(ValueError, 'summary'):
bridge.authorize_case(self.root, self.cfg, 'novel_to_aj', probe['name'], 'gpu', 0)
summary['representation_gate_pass'] = True
bind_seed_gate(self.root, summary)
bridge.authorize_case(self.root, self.cfg, 'novel_to_aj', probe['name'], 'gpu', 0)
def test_novel_rejects_summary_hash_or_cohort_misbinding(self):
gate(self.root, 'controls')
summary = seed_summary(self.root, self.cfg, self.rows)
bind_seed_gate(self.root, summary)
probe = bridge.probe_rows(self.rows, self.cfg, 'novel_to_aj')[0]
summary['cohort'] = 'novel_to_aj'
write_json(self.root / 'validation/seed_validation/summary.json', summary)
with self.assertRaisesRegex(ValueError, 'exact summary'):
bridge.authorize_case(self.root, self.cfg, 'novel_to_aj', probe['name'], 'gpu', 0)
bind_seed_gate(self.root, summary)
with self.assertRaisesRegex(ValueError, 'identity'):
bridge.authorize_case(self.root, self.cfg, 'novel_to_aj', probe['name'], 'gpu', 0)
def test_novel_rejects_replaced_case_repeat_or_timing_even_with_correct_counts(self):
gate(self.root, 'controls')
probe = bridge.probe_rows(self.rows, self.cfg, 'novel_to_aj')[0]
for key in ('runs', 'repeats', 'timing_checks', 'input_output_provenance'):
with self.subTest(key=key):
summary = seed_summary(self.root, self.cfg, self.rows)
summary[key][0]['case'] = 'not-a-registered-case'
bind_seed_gate(self.root, summary)
with self.assertRaises(ValueError):
bridge.authorize_case(self.root, self.cfg, 'novel_to_aj', probe['name'], 'gpu', 0)
def test_any_stop_marker_prevents_all_scientific_actions(self):
for kind in ('representation_failure', 'execution_or_numerical_failure'):
with self.subTest(kind=kind):
write_json(self.root / 'audit/stopped-seed-validation.json', {'stop_kind': kind})
for backend in ('gpu', 'oracle', 'component'):
with self.assertRaisesRegex(ValueError, 'stop marker'):
bridge.authorize_case(self.root, self.cfg, 'controls', self.cfg['control_cases'][0], backend, 0)
def test_standalone_action_failure_persists_stop_and_never_retries(self):
action = mock.Mock(side_effect=RuntimeError('synthetic failure; no science executed'))
with self.assertRaisesRegex(RuntimeError, 'synthetic failure'):
bridge.guarded_action(self.root, 'gpu', 'controls', 'control-phys', 0, action)
marker = self.root / 'audit/stopped-case-gpu-controls-control-phys-r0.json'
report = bridge.read(marker)
self.assertEqual(report['stop_kind'], 'execution_or_numerical_failure')
self.assertFalse(report['numerical_instability_inferred_from_execution_error'])
before = marker.read_bytes()
with self.assertRaisesRegex(ValueError, 'stop marker'):
bridge.guarded_action(self.root, 'gpu', 'controls', 'control-phys', 0, action)
self.assertEqual(action.call_count, 1)
self.assertEqual(marker.read_bytes(), before)
def test_successful_guarded_action_adds_no_stop(self):
expected = {'pass_all': True}
self.assertIs(bridge.guarded_action(self.root, 'gpu', 'controls', 'control-phys', 0, lambda: expected), expected)
bridge.ensure_unstopped(self.root)
class InvocationTests(unittest.TestCase):
def test_original_gpu_function_receives_new_paths_unchanged(self):
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
case, output, build = root / 'case', root / 'new-exp/gpu/run', root / 'new-exp/build'
data = spec(root)
data['budget_root'] = str(root / 'new-exp')
write_json(case / 'spec.json', data)
runtime = types.SimpleNamespace(run_gpu=mock.Mock(return_value={'pass_all': True}))
with mock.patch.object(bridge, 'sealed', return_value=runtime), mock.patch.object(bridge, '_receipt'):
result = bridge.run_gpu(case, output, build)
self.assertTrue(result['pass_all'])
runtime.run_gpu.assert_called_once_with(case, output, build)
def test_original_oracle_function_is_not_given_candidate_trace(self):
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
case, output = root / 'case', root / 'new-exp/oracle/run'
data = spec(root); data['budget_root'] = str(root / 'new-exp')
write_json(case / 'spec.json', data)
runtime = types.SimpleNamespace(run_case=mock.Mock(return_value={'pass_all': True}))
with mock.patch.object(bridge, 'sealed', return_value=runtime), mock.patch.object(bridge, '_receipt'):
bridge.run_oracle(case, output)
runtime.run_case.assert_called_once_with(case, output)
class ControlEvidenceTests(unittest.TestCase):
def test_real_sealed_comparator_accepts_complete_synthetic_d18_and_rejects_signed_zero_tail(self):
# Artifact construction only: these zero traces were not produced by any model.
aj = bridge.sealed('compare_timing.py', AJ)
timing = bridge.sealed('timing_queue.py', AJ)
with tempfile.TemporaryDirectory() as temporary:
root = Path(temporary)
cases, outputs = [root / name for name in ('old-case', 'new-case')], [root / name for name in ('old-out', 'new-out')]
base = spec(root)
(root / 'graph').mkdir()
np.save(root / 'graph/weights.npy', np.zeros(1, np.float64), allow_pickle=False)
write_json(root / 'coefficients.json', {'synthetic_only': True})
states = dict(v=np.zeros(166700, np.float64), g=np.zeros(166700, np.float64),
ref=np.zeros(166700, np.int32), counts=np.zeros(166700, np.int32),
step=np.empty(0, np.int32), neuron_idx=np.empty(0, np.int32))
generated = np.zeros((1000, 4064), np.float32)
pending = np.zeros((18, 4064), np.float32)
audit = timing.audit_sequence(generated, generated, pending, 18)
audit.update(generated_rows=1000, applied_generated_rows=982, pending_shape=[18, 4064],
pending_application_tick_start=1000, pending_application_tick_stop_exclusive=1018,
pending_generated_tick_start=982, pending_generated_tick_stop_exclusive=1000,
pending_raw_sha256=aj.raw_hash(pending), final_apl_state_float32=[0., 0.],
final_apl_state_u32_bits=[0, 0], final_apl_state_nonzero=False,
finite_generated_sequence_only=True, future_apl_decay_or_feedback_generated=False,
closed_loop_branch_integrals_claimed_equal=False, biological_delay_measurement_claimed=False)
hashes = [{**{name + '_sha256': aj.raw_hash(states[name]) for name in ('v', 'g', 'ref')}, 'tick': tick}
for tick in range(1000)]
queues = [aj._queue_digest(tick, np.empty(0, np.int64), np.empty(0, np.uint8)) for tick in range(1000)]
for index, (case, output) in enumerate(zip(cases, outputs)):
data = dict(base, budget_root=str(root / ('budget-' + str(index))), output_budget_bytes=10000 + index)
write_json(case / 'spec.json', data)
for name in ('requests.npz', 'pn-drive.npz'):
(case / name).write_bytes(b'synthetic-identical-input')
output.mkdir()
np.savez_compressed(output / 'state.npz', **states)
for name, value in (('drive', np.zeros((1000, 2), np.float32)), ('state', np.zeros((1000, 2), np.float32)),
('inhibition', generated), ('applied', generated), ('pending-tail', pending)):
np.save(output / ('apl-' + name + '.float32.npy'), value, allow_pickle=False)
for name, rows in (('tick-state-hashes.jsonl', hashes), ('queue.jsonl', queues)):
(output / name).write_text(''.join(json.dumps(row) + '\n' for row in rows), encoding='utf-8')
(output / 'requests.csv').write_text('tick,neuron_idx,attempted,accepted,rejected\n', encoding='utf-8')
component = {'synthetic_fixture': True}
write_json(output / 'apl-component.json', component)
write_json(output / 'apl-timing-audit.json', audit)
inputs = {name: bridge.digest(case / name) for name in ('spec.json', 'requests.npz')}
inputs.update({'base_weights.npy': bridge.digest(root / 'graph/weights.npy'),
'coefficients.json': bridge.digest(root / 'coefficients.json')})
summary = dict(case=base['name'], complete=True, pass_all=True, steps=1000, completed_ticks=1000,
nodes=166700, edges=25582938, precision='float64', apl_precision='float32', state_units='SI volts',
total_spikes=0, requested=0, accepted_requests=0, rejected_requests=0, arriving_edges=0,
accepted_arriving_edges=0, counts_match_sparse_events=True, all_finite=True, record_history=False,
apl_fast_edges_zeroed=5845, kc_targets_present=4064, effective_weights_raw_sha256='0' * 64,
apl_schedule='same synthetic schedule', apl_si_conversion='same synthetic conversion',
sealed_ae_backend_sha256='1' * 64, learning=False, apl_delay_steps=18, apl_timing=audit,
source_provenance={'same_sealed_source': True}, pending_generated_count=18,
pending_initial_zero_prefix=0, pending_tail_shape=[18, 4064], future_generated_decay_tail_included=False,
apl_component=component, input_sha256=inputs, build={'path': str(root / ('build-' + str(index)))})
write_json(output / 'summary.json', summary)
result = bridge.control_identity(outputs[1], outputs[0], cases[1], cases[0], aj_model=AJ)
self.assertTrue(result['pass_all'], result.get('error', result['failed_checks']))
pending[0, 0] = np.float32(-0.)
np.save(outputs[1] / 'apl-pending-tail.float32.npy', pending, allow_pickle=False)
failed = bridge.control_identity(outputs[1], outputs[0], cases[1], cases[0], aj_model=AJ)
self.assertFalse(failed['pass_all'])
self.assertIn('apl.pending.bitwise_exact', failed['failed_checks'])
self.assertIn('fresh_gpu.fixed_delay_pending.bitwise_exact', failed['failed_checks'])
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,298 @@
"""Synthetic-only validation tests: no historical outputs or brain execution."""
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 validation as val
HERE = Path(__file__).resolve().parent
LEGACY = val.load_frozen(HERE.parent / "author-apl-lab-v2/calibration.py", val.AG_SHA256, "ak_test_ag")
TIMING = val.load_frozen(HERE.parent / "apl-timing-lab-v1/calibration.py", val.AJ_SHA256, "ak_test_aj")
def config():
cfg = val.read(HERE / "config.json")
cfg["validation"]["seeds"] = [1001, 1002, 1003, 1004, 1005] # Synthetic, not proposed scientific seeds.
return cfg
def panel():
return [dict(odor_id=oid, odor_name=oid, split="calibration" if i < 6 else "heldout",
mapped_response_sum=val.MEDIAN)
for i, oid in enumerate(sorted(LEGACY.ORIGINAL_CAL_IDS) + ["synthetic-new-" + str(i) for i in range(6)])]
def records(cfg):
rows = []
pp = panel()
for ci, cohort in enumerate(val.COHORTS):
for mode in val.MODES:
for oi in range(6):
for seed in cfg["validation"]["seeds"]:
rows.append(dict(name=f"test-{mode}-{oi}-{seed}", cohort=cohort,
source_panel_split=val.SPLITS[cohort], mode=mode, odor_id=pp[6 * ci + oi]["odor_id"],
odor_index=oi, seed=seed, targets=1, requests=0))
return rows
def encoder(cfg, inventory):
return dict(panel_count=12, cal_count=6, novel_to_aj_count=6, median_mapped_response_sum=val.MEDIAN,
seeds=cfg["validation"]["seeds"], seeds_static_audit_sha256="a" * 64,
cohorts_static_panel_rows={cohort: [dict(odor_id=oid, odor_index=i, source_panel_split=val.SPLITS[cohort])
for i, oid in enumerate(inventory[cohort]["odor_ids"])] for cohort in val.COHORTS},
requested_before_any_dynamics=True, historical_never_simulated_claim=False)
def save(path, value):
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("x", encoding="utf-8") as stream:
json.dump(value, stream, allow_nan=False)
def make_raw_trial(root):
"""Tiny neuron state with the real full-width APL trace schema."""
output, case, bundle = root / "out", root / "case", root / "bundle"
output.mkdir(); case.mkdir(); bundle.mkdir()
steps, neurons = 20, 2
cfg = dict(neurons=neurons, edges=0)
for filename in ("input_matrix.npy", "output_matrix.npy", "kc_globals.npy", "apl_globals.npy"):
np.save(bundle / filename, np.zeros(1, np.int32))
spec = dict(name="synthetic", steps=steps, validation_cohort="novel_to_aj", source_panel_split="heldout",
apl_delay_steps=18, mode="physiological", odor_id="synthetic", odor_name="synthetic", seed=1001,
expected_external_events=1., rate_sum_hz=50., apl_bundle_dir=str(bundle))
save(case / "spec.json", spec)
np.savez(case / "requests.npz", tick=np.empty(0, np.int32), neuron_idx=np.empty(0, np.int32))
state = {"step": np.empty(0, np.int32), "neuron_idx": np.empty(0, np.int32),
"counts": np.zeros(neurons, np.int32), "v": np.zeros(neurons, np.float64),
"g": np.zeros(neurons, np.float64), "ref": np.zeros(neurons, np.int32)}
np.savez(output / "state.npz", **state)
hashes = [dict(tick=t, **{key + "_sha256": LEGACY.raw_hash(state[key]) for key in ("v", "g", "ref")}) for t in range(steps)]
queues = [dict(tick=t, count=0, accepted_count=0, ordered_edge_sha256="0" * 64,
accepted_mask_sha256="0" * 64, joint_sha256="0" * 64) for t in range(steps)]
for filename, rows in (("tick-state-hashes.jsonl", hashes), ("queue.jsonl", queues)):
(output / filename).write_text("".join(json.dumps(row) + "\n" for row in rows), encoding="utf-8")
(output / "requests.csv").write_text("tick,neuron_idx,attempted,accepted,rejected\n", encoding="utf-8")
for filename, width in LEGACY.APL_FILES.items():
np.save(output / filename, np.zeros((steps, width), np.float32))
np.save(output / "apl-applied.float32.npy", np.zeros((steps, 4064), np.float32))
pending = np.zeros((18, 4064), np.float32)
np.save(output / "apl-pending-tail.float32.npy", pending)
audit = dict(pass_all=True, apl_delay_steps=18, steps=steps, pending_generated_count=18,
pending_initial_zero_prefix=0, pending_application_tick_start=steps,
pending_application_tick_stop_exclusive=steps + 18, pending_generated_tick_start=steps - 18,
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=LEGACY.raw_hash(pending), pending_queue_drained=False,
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=[0., 0.], final_apl_state_u32_bits=[0, 0], final_apl_state_nonzero=False)
save(output / "apl-timing-audit.json", audit)
component = dict(ok=True, n_neurons=neurons, n_kc=2, n_apl=2, dt_ms=.1,
files_sha256={name: val.digest(bundle / name) for name in
("input_matrix.npy", "output_matrix.npy", "kc_globals.npy", "apl_globals.npy")})
save(output / "apl-component.json", component)
save(output / "summary.json", dict(complete=True, pass_all=True, all_finite=True, steps=steps,
completed_ticks=steps, nodes=neurons, edges=0, precision="float64", apl_precision="float32",
case=spec["name"], record_history=False, learning=False, requested=0, accepted_requests=0,
rejected_requests=0, total_spikes=0, apl_component=component, apl_delay_steps=18, apl_timing=audit,
input_sha256={name: val.digest(case / name) for name in ("spec.json", "requests.npz")}))
return output, case, spec, cfg
def fake_trial(row, cohort, silent=False):
counts = np.zeros(1000, np.int32)
if not silent:
counts[row["odor_index"] * 50:row["odor_index"] * 50 + 50] = 1
return dict(kc_counts=counts, expected_external_events=1., external_events=1,
record=dict(case=row["name"], mode=row["mode"], seed=row["seed"], odor_id=row["odor_id"],
requested=row["requests"], split=cohort, cohort=cohort, source_panel_split=val.SPLITS[cohort]),
timing=dict(report=dict(pass_all=True)), apl={})
class ValidationTests(unittest.TestCase):
def test_source_pins_and_globals_are_unchanged(self):
self.assertEqual(LEGACY.ORIGINAL_SEEDS, (51101, 51102, 51103, 51104, 51105))
self.assertFalse(hasattr(LEGACY, "EXP"))
self.assertFalse(hasattr(TIMING, "EXP"))
with self.assertRaisesRegex(ValueError, "SHA"):
val.load_frozen(HERE.parent / "author-apl-lab-v2/calibration.py", "0" * 64, "bad_pin")
def test_inventory_accepts_configured_seeds_and_keeps_static_halves(self):
cfg = config(); inv = val.validate_inventory(records(cfg), cfg, panel(), LEGACY)
self.assertEqual([len(inv[c]["records"]) for c in val.COHORTS], [60, 60])
self.assertEqual(inv["novel_to_aj"]["odor_ids"], ["synthetic-new-" + str(i) for i in range(6)])
val.validate_encoder(encoder(cfg, inv), inv, cfg)
self.assertEqual(LEGACY.ORIGINAL_SEEDS[0], 51101)
def test_inventory_rejects_missing_duplicate_mislabelled_and_unaudited_cells(self):
cfg = config()
variants = []
rr = records(cfg); variants.append(rr[:-1])
rr = records(cfg); rr[-1] = copy.deepcopy(rr[-2]); variants.append(rr)
for field, value in (("source_panel_split", "heldout"), ("odor_id", "wrong"),
("seed", 51101), ("name", "../outside"), ("odor_index", True), ("targets", 0)):
rr = records(cfg); rr[0][field] = value; variants.append(rr)
for rr in variants:
with self.subTest(first=rr[0]), self.assertRaises(ValueError):
val.validate_inventory(rr, cfg, panel(), LEGACY)
def test_no_gate_relaxation_or_subset_median(self):
for key, value in (("minimum_separable_odor_pairs", 1), ("sparse_min_fraction", .01),
("repeat_exact_required", False)):
cfg = config(); cfg["gates"][key] = value
with self.subTest(key=key), self.assertRaises(ValueError):
val.validate_inventory(records(cfg), cfg, panel(), LEGACY)
pp = panel()
for row in pp:
row["mapped_response_sum"] = 1.
with self.assertRaisesRegex(ValueError, "median"):
val.validate_inventory(records(config()), config(), pp, LEGACY)
def test_encoder_rejects_history_claim_or_changed_panel_rows(self):
cfg = config(); inv = val.validate_inventory(records(cfg), cfg, panel(), LEGACY)
for key, value in (("historical_never_simulated_claim", True), ("requested_before_any_dynamics", False),
("seeds_static_audit_sha256", ""), ("cohorts_static_panel_rows", {})):
ee = encoder(cfg, inv); ee[key] = value
with self.subTest(key=key), self.assertRaises(ValueError):
val.validate_encoder(ee, inv, cfg)
def test_encoder_actual_prepare_panel_row_extension(self):
cfg = config(); inv = val.validate_inventory(records(cfg), cfg, panel(), LEGACY)
ee = encoder(cfg, inv)
for ci, cohort in enumerate(val.COHORTS):
for oi, row in enumerate(ee["cohorts_static_panel_rows"][cohort]):
row["source_panel_row"] = ci * 6 + oi
val.validate_encoder(ee, inv, cfg)
ee["cohorts_static_panel_rows"]["novel_to_aj"][0]["source_panel_row"] = 0
with self.assertRaisesRegex(ValueError, "panel row"):
val.validate_encoder(ee, inv, cfg)
def test_fullgraph_case_matches_static_physics_and_exact_input_expectation(self):
cfg = config(); row = records(cfg)[60]
row.update(source_panel_row=6, expected_external_events=10., rates_sum=100.)
spec = dict(name=row["name"], kind="fullgraph", validation_cohort=row["cohort"],
source_panel_split=row["source_panel_split"], source_panel_row=6,
**{key: row[key] for key in ("mode", "odor_id", "odor_index", "seed")},
apl_delay_steps=18, steps=1000, dt_ms=.1, duration_ms=100., training=False, record_history=False,
model={"resting_potential_mv": -52.}, graph_dir="unchanged-graph", apl_bundle_dir="unchanged-bundle",
apl={"gain": .01}, coefficients_path="unchanged-coefficients", science_python="unchanged-entry",
legacy_apl_worker="unchanged-worker", precision="float64", apl_precision="float32",
target_count=1, rate_sum_hz=100., expected_external_events=10.)
with tempfile.TemporaryDirectory() as tmp:
case = Path(tmp)
save(case / "spec.json", spec)
np.savez(case / "pn-drive.npz", targets=np.array([10], np.int32), rates_hz=np.array([100.], np.float32))
np.savez(case / "requests.npz", tick=np.empty(0, np.int32), neuron_idx=np.empty(0, np.int32))
self.assertEqual(val.validate_case(case, row, cfg, spec), spec)
wrong = copy.deepcopy(spec); wrong["model"]["resting_potential_mv"] = -51.
with self.assertRaisesRegex(ValueError, "physical field"):
val.validate_case(case, row, cfg, wrong)
wrong_row = dict(row, targets=2)
with self.assertRaisesRegex(ValueError, "PN drive"):
val.validate_case(case, wrong_row, cfg, spec)
def test_real_legacy_reader_record_is_relabelled_without_globals_or_numerical_changes(self):
with tempfile.TemporaryDirectory() as tmp:
output, case, spec, cfg = make_raw_trial(Path(tmp))
trial = val.read_validation_trial(LEGACY, TIMING, output, case, spec, np.arange(2, dtype=np.int32), cfg)
try:
self.assertEqual(trial["record"]["split"], "novel_to_aj")
self.assertEqual(trial["record"]["source_panel_split"], "heldout")
self.assertFalse(trial["record"]["historical_never_simulated_claim"])
self.assertTrue(trial["timing"]["report"]["pass_all"])
self.assertEqual(LEGACY.ORIGINAL_SEEDS[0], 51101)
finally:
val.close_trial(trial)
def test_real_reader_still_rejects_missing_state_and_delay_zero(self):
with tempfile.TemporaryDirectory() as tmp:
output, case, spec, cfg = make_raw_trial(Path(tmp))
bad = dict(spec, apl_delay_steps=0)
with self.assertRaisesRegex(ValueError, "delay"):
val.read_validation_trial(LEGACY, TIMING, output, case, bad, np.arange(2, dtype=np.int32), cfg)
(output / "state.npz").unlink()
with self.assertRaises(FileNotFoundError):
val.read_validation_trial(LEGACY, TIMING, output, case, spec, np.arange(2, dtype=np.int32), cfg)
def collect(self, silent=False, broken_repeat=False, missing=False):
cfg = config(); inv = val.validate_inventory(records(cfg), cfg, panel(), LEGACY)
cohort = "seed_validation"; rows = inv[cohort]["records"]
byname = {row["name"]: row for row in rows}
accessed = []
def load(legacy, timing, output, case, spec, kc, config_arg):
accessed.append(str(output))
if missing and spec["name"] == rows[0]["name"]:
raise FileNotFoundError("synthetic missing evidence")
return fake_trial(byname[spec["name"]], cohort, silent)
timing = types.SimpleNamespace(timing_repeat=lambda *args: dict(pass_all=not broken_repeat,
checks=dict(apl_applied=not broken_repeat)))
with patch.object(val, "validate_case", side_effect=lambda case, row, *args: row), \
patch.object(val, "read_validation_trial", side_effect=load), \
patch.object(val, "evidence_hashes", return_value={"synthetic": True}):
result = val.collect_cohort(cohort, rows, inv[cohort]["odor_ids"], cfg, Path("synthetic"),
np.arange(2, dtype=np.int32), {}, LEGACY, timing)
return result, accessed
def test_full_60_plus_12_and_pair_specific_gate_without_other_cohort_read(self):
result, accessed = self.collect()
self.assertTrue(result["pass_all"])
self.assertEqual((result["valid_base_trials"], result["checked_repeats"], result["checked_timing_trials"]), (60, 12, 72))
self.assertEqual(len(accessed), 72)
self.assertFalse(any("novel_to_aj" in path for path in accessed))
for report in result["modes"].values():
self.assertEqual((report["pair_count"], report["within_distance_count"], report["between_distance_count"]), (15, 60, 75))
json.dumps(result, allow_nan=False)
def test_representation_failure_keeps_all_runs_and_is_not_execution_failure(self):
result, accessed = self.collect(silent=True)
self.assertTrue(result["execution_gate_pass"])
self.assertFalse(result["representation_gate_pass"])
self.assertFalse(result["pass_all"])
self.assertEqual(len(accessed), 72)
self.assertTrue(all(row["stage"] == "representation_gate" for row in result["failures"]))
def test_missing_evidence_and_repeat_failure_never_pass_execution(self):
for options in (dict(missing=True), dict(broken_repeat=True)):
with self.subTest(options=options):
result, _ = self.collect(**options)
self.assertFalse(result["execution_gate_pass"])
self.assertFalse(result["pass_all"])
self.assertTrue(result["failures"])
def test_none_recompute_is_deterministic_and_writes_nothing(self):
cfg = config(); rr = records(cfg); inv = val.validate_inventory(rr, cfg, panel(), LEGACY)
ee = encoder(cfg, inv)
ctx = types.SimpleNamespace(ROOT=Path("synthetic-root"), MODEL=Path("synthetic-model"), EXP=Path("synthetic-exp"),
AG_MODEL=Path("ag-model"), AJ_MODEL=Path("aj-model"), AG=Path("ag"), AJ=Path("aj"), CFG=cfg,
check=lambda: {}, save=lambda *args: self.fail("Read-only summarize wrote output"))
collected, _ = self.collect()
def read_fixture(path):
if path.name == "validation-cases.json": return rr
if path.name == "encoder-audit.json": return ee
if path.name == "spec.json": return dict(apl_delay_steps=18, training=False)
raise AssertionError("Unexpected input read: " + str(path))
def hash_fixture(path):
return val.PANEL_SHA256 if path.name == "frozen-odor-panel.parquet" else "a" * 64
with patch.dict("sys.modules", context=ctx), patch.object(val, "read", side_effect=read_fixture), \
patch.object(val, "digest", side_effect=hash_fixture), \
patch.object(val, "load_frozen", side_effect=[LEGACY, TIMING, LEGACY, TIMING]), \
patch.object(pd, "read_parquet", return_value=pd.DataFrame(panel())), \
patch.object(np, "load", return_value=np.arange(4064, dtype=np.int32)), \
patch.object(val, "collect_cohort", side_effect=lambda *args: copy.deepcopy(collected)):
first = val.summarize("seed_validation", None)
second = val.summarize("seed_validation", None)
self.assertEqual(first, second)
self.assertTrue(first["pass_all"])
json.dumps(first, allow_nan=False)
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,344 @@
"""Frozen-D18 validation cohorts; no simulation, fitting, or old heldout read.
Only the requested cohort's new trajectories are opened. The suite owns the
seed-validation -> novel-to-AJ unlock. Legacy modules are source-hash pinned,
loaded without writing bytecode, and never have their globals rebound.
"""
from __future__ import annotations
import hashlib
import json
from pathlib import Path
import re
import sys
import types
import numpy as np
AG_SHA256 = "edb9cb2d890471fd07afd88c959ef3540b0cd40af490fac3f26396b5e7f5bf9c"
AJ_SHA256 = "fb15ddeaa108305c8de697bbae36b23ab0414a7c58db51c66dce9feb4a048a0d"
PANEL_SHA256 = "907f16a56e024a8e2112b5751e53b0e6037b329fa110098af3d31b119c10a1a0"
COHORTS = ("seed_validation", "novel_to_aj")
SPLITS = dict(zip(COHORTS, ("calibration", "heldout")))
MODES = ("physiological", "matched_energy")
MEDIAN = 2.556107997894287
_DEFAULT_OUTPUT = object()
def require(ok, message):
if not ok:
raise ValueError(message)
def read(path):
return json.loads(Path(path).read_text(encoding="utf-8"))
def digest(path):
h = hashlib.sha256()
with Path(path).open("rb") as stream:
for block in iter(lambda: stream.read(8 << 20), b""):
h.update(block)
return h.hexdigest()
def load_frozen(path, expected, name):
path = Path(path)
source = path.read_bytes()
require(hashlib.sha256(source).hexdigest() == expected, "Frozen source SHA mismatch: " + str(path))
module = types.ModuleType(name)
module.__file__ = str(path)
sys.modules[name] = module
exec(compile(source, str(path), "exec"), module.__dict__)
return module
def validate_design(cfg):
design = cfg["validation"]
seeds = design["seeds"]
require(isinstance(seeds, list) and len(seeds) == 5 and len(set(seeds)) == 5 and
all(type(seed) is int and 0 <= seed < 2**63 for seed in seeds), "Need five explicitly audited seed integers")
require(design["cohorts"] == list(COHORTS) and design["modes"] == list(MODES) and
design["odor_count"] == 6 and design["duration_ms"] == 100.0 and
design["repeat_first_seed_each_odor"] is True, "Validation design changed")
require(type(cfg["apl_delay_steps"]) is int and cfg["apl_delay_steps"] == 18 and
cfg["neurons"] == 166700 and cfg["edges"] == 25582938 and cfg["training"] is False,
"Frozen D18/fullgraph/nonlearning scope changed")
gates = cfg["gates"]
require(gates["sparse_min_fraction"] == .03 and gates["sparse_max_fraction"] == .09 and
gates["max_fraction_strict"] == .5 and gates["min_fraction_strict"] == 0 and
gates["minimum_separable_odor_pairs"] == 3 and all(gates[key] is True for key in
("same_jaccard_gt_between", "between_euclidean_gt_within", "both_modes_required",
"finite_required", "repeat_exact_required")), "Original complete representation/integrity gates changed")
return seeds
def validate_inventory(records, cfg, panel_rows, legacy):
"""Static 120-row inventory, preserving original panel row order in each half."""
seeds = validate_design(cfg)
require(isinstance(records, list) and len(records) == 120, "Inventory must contain exactly 120 base cases")
require(len(panel_rows) == 12 and [row["split"] for row in panel_rows] == ["calibration"] * 6 + ["heldout"] * 6,
"Frozen static panel order/splits changed")
all_ids = [row["odor_id"] for row in panel_rows]
require(all(isinstance(oid, str) and oid for oid in all_ids) and len(set(all_ids)) == 12 and
set(all_ids[:6]) == legacy.ORIGINAL_CAL_IDS, "Frozen panel identities invalid")
require(float(np.median([row["mapped_response_sum"] for row in panel_rows])) == MEDIAN,
"Matched-energy reference must remain the original full-12 median")
result = {}
names, keys = set(), set()
for row in records:
require(row["cohort"] in COHORTS and row["mode"] in MODES, "Unknown cohort/mode")
require(type(row["odor_index"]) is int and 0 <= row["odor_index"] < 6 and
type(row["seed"]) is int and row["seed"] in seeds, "Invalid odor index/seed")
require(isinstance(row["name"], str) and re.fullmatch(r"[A-Za-z0-9_-]+", row["name"]), "Unsafe case name")
namekey = (row["cohort"], row["name"])
key = (row["cohort"], row["mode"], row["odor_index"], row["seed"])
require(namekey not in names and key not in keys, "Duplicate case name or experimental cell")
names.add(namekey); keys.add(key)
offset = 0 if row["cohort"] == "seed_validation" else 6
require(row["source_panel_split"] == SPLITS[row["cohort"]] and
row["odor_id"] == all_ids[offset + row["odor_index"]], "Cohort identity/order/source split mismatch")
if "source_panel_row" in row:
require(type(row["source_panel_row"]) is int and row["source_panel_row"] == offset + row["odor_index"],
"Inventory original panel row mismatch")
require(type(row["targets"]) is int and 0 < row["targets"] <= cfg["neurons"] and
type(row["requests"]) is int and row["requests"] >= 0, "Invalid inventory target/request counts")
expected = {(cohort, mode, oi, seed) for cohort in COHORTS for mode in MODES for oi in range(6) for seed in seeds}
require(keys == expected, "Inventory missing or replacing a predeclared cell")
for index, cohort in enumerate(COHORTS):
rows = [row for row in records if row["cohort"] == cohort]
rows.sort(key=lambda row: (MODES.index(row["mode"]), row["odor_index"], seeds.index(row["seed"])))
result[cohort] = {"records": rows, "odor_ids": all_ids[index * 6:(index + 1) * 6]}
return result
def validate_encoder(encoder, inventory, cfg):
require(encoder["panel_count"] == 12 and encoder["cal_count"] == 6 and encoder["novel_to_aj_count"] == 6 and
encoder["median_mapped_response_sum"] == MEDIAN and encoder["seeds"] == cfg["validation"]["seeds"] and
encoder["requested_before_any_dynamics"] is True and encoder["historical_never_simulated_claim"] is False,
"Frozen encoder/reference or validation scope changed")
require(isinstance(encoder["seeds_static_audit_sha256"], str) and
re.fullmatch(r"[0-9a-f]{64}", encoder["seeds_static_audit_sha256"]), "Missing seed audit SHA")
expected = {cohort: [dict(odor_id=oid, odor_index=index, source_panel_split=SPLITS[cohort])
for index, oid in enumerate(inventory[cohort]["odor_ids"])] for cohort in COHORTS}
actual = encoder["cohorts_static_panel_rows"]
require(set(actual) == set(COHORTS), "Encoder cohort set changed")
for ci, cohort in enumerate(COHORTS):
require(len(actual[cohort]) == 6, "Encoder cohort panel count changed")
for index, (row, wanted) in enumerate(zip(actual[cohort], expected[cohort])):
require(all(row.get(key) == value for key, value in wanted.items()),
"Encoder cohort panel rows differ from frozen identities")
if "source_panel_row" in row:
require(type(row["source_panel_row"]) is int and row["source_panel_row"] == ci * 6 + index,
"Encoder original panel row mismatch")
def validate_case(case, row, cfg, frozen_spec):
spec = read(case / "spec.json")
require(spec["name"] == row["name"] and spec["kind"] == "fullgraph" and
spec["validation_cohort"] == row["cohort"] and spec["source_panel_split"] == row["source_panel_split"] and
all(spec[key] == row[key] for key in ("mode", "odor_id", "odor_index", "seed")), "Spec differs from validation inventory")
require(type(spec["apl_delay_steps"]) is int and spec["apl_delay_steps"] == 18 and spec["steps"] == 1000 and
spec["dt_ms"] == .1 and spec["duration_ms"] == 100.0 and spec["training"] is False and
spec["record_history"] is False, "Fixed D18/window/nonlearning schema changed")
if "source_panel_row" in row or "source_panel_row" in spec:
expected_row = (0 if row["cohort"] == "seed_validation" else 6) + row["odor_index"]
require(type(spec.get("source_panel_row")) is int and spec["source_panel_row"] == expected_row and
row.get("source_panel_row", expected_row) == expected_row, "Spec original panel row mismatch")
for key in ("model", "graph_dir", "apl_bundle_dir", "apl", "coefficients_path", "science_python",
"legacy_apl_worker", "precision", "apl_precision", "dt_ms", "duration_ms", "steps"):
require(spec[key] == frozen_spec[key], "Frozen physical field changed: " + key)
with np.load(case / "pn-drive.npz", allow_pickle=False) as source:
require(set(source.files) == {"targets", "rates_hz"}, "PN drive schema changed")
targets, rates = source["targets"], source["rates_hz"]
require(targets.dtype == np.int32 and targets.ndim == 1 and len(targets) == row["targets"] and
len(np.unique(targets)) == len(targets) and np.all((targets >= 0) & (targets < cfg["neurons"])) and
rates.dtype == np.float32 and rates.shape == targets.shape and np.isfinite(rates).all() and np.all(rates > 0),
"Invalid PN drive identities/rates; no sorting or zero-channel insertion is allowed")
expected_events = float(rates.sum()) * spec["steps"] * .1 / 1000.
require(spec["target_count"] == row["targets"] and spec["rate_sum_hz"] == float(rates.sum()) and
spec["expected_external_events"] == expected_events and np.isfinite(expected_events) and expected_events > 0,
"PN rates/spec event expectation disagree")
if "expected_external_events" in row:
require(row["expected_external_events"] == expected_events, "Inventory expected events disagree")
if "rates_sum" in row:
require(row["rates_sum"] == float(rates.sum()), "Inventory rate sum disagrees")
with np.load(case / "requests.npz", allow_pickle=False) as source:
require(set(source.files) == {"tick", "neuron_idx"} and len(source["tick"]) == row["requests"] and
np.isin(source["neuron_idx"], targets).all(), "Request count/targets differ from prepared input")
return spec
def read_validation_trial(legacy, timing, output, case, spec, kc_globals, cfg):
"""Reuse all sealed checks; replace only the returned descriptive record."""
cohort = spec["validation_cohort"]
require(cohort in COHORTS and spec["source_panel_split"] == SPLITS[cohort] and
type(spec["apl_delay_steps"]) is int and spec["apl_delay_steps"] == 18, "Wrong validation cohort or delay")
trial = legacy.read_trial(output, case, spec, kc_globals, cfg["neurons"], cfg["edges"])
try:
trial["timing"] = timing.validate_timing(output, spec, trial)
except Exception:
close_trial(trial)
raise
trial["record"] = dict(trial["record"], split=cohort, cohort=cohort, validation_cohort=cohort,
source_panel_split=spec["source_panel_split"], historical_never_simulated_claim=False,
used_for_parameter_selection=False)
if "source_panel_row" in spec:
trial["record"]["source_panel_row"] = spec["source_panel_row"]
return trial
def close_trial(trial):
if trial is None:
return
arrays = list(trial.get("apl", {}).values())
arrays += [trial.get("timing", {}).get(key) for key in ("applied", "pending")]
for value in arrays:
mmap = getattr(value, "_mmap", None)
if mmap is not None and not mmap.closed:
mmap.close()
def evidence_hashes(output, case, name, repeat):
files = ("state.npz", "summary.json", "tick-state-hashes.jsonl", "queue.jsonl", "requests.csv", "apl-component.json",
"apl-drive.float32.npy", "apl-state.float32.npy", "apl-inhibition.float32.npy",
"apl-applied.float32.npy", "apl-pending-tail.float32.npy", "apl-timing-audit.json")
return {"case": name, "repeat": repeat,
"input_sha256": {key: digest(case / key) for key in ("spec.json", "requests.npz", "pn-drive.npz")},
"output_sha256": {key: digest(output / key) for key in files}}
def collect_cohort(cohort, records, odors, cfg, exp, kc_globals, frozen_spec, legacy, timing):
"""Aggregate one block even when its representation gate fails."""
seeds = cfg["validation"]["seeds"]
failures, runs, rows, repeats, timings, proof, modes = [], {}, [], [], [], [], {}
for row in records:
name, first, spec = row["name"], None, None
case = exp / "cases" / cohort / name
try:
spec = validate_case(case, row, cfg, frozen_spec)
except Exception as error:
failures.append(dict(stage="case_input", case=name, type=type(error).__name__, message=str(error)))
for repeat_index in ([0, 1] if row["seed"] == seeds[0] else [0]):
trial = None
try:
require(spec is not None, "Case input validation unavailable")
output = exp / "gpu" / cohort / (name + "-r" + str(repeat_index))
trial = read_validation_trial(legacy, timing, output, case, spec, kc_globals, cfg)
require(trial["record"]["requested"] == row["requests"], "Inventory/actual request count differs")
entry = evidence_hashes(output, case, name, repeat_index)
proof.append(entry)
timings.append(dict(case=name, repeat=repeat_index, **trial["timing"]["report"]))
if repeat_index == 0:
first = trial
runs[(row["mode"], row["odor_id"], row["seed"])] = {key: trial[key] for key in
("kc_counts", "expected_external_events", "external_events")}
rows.append(trial["record"])
else:
require(first is not None, "Baseline unavailable for exact repeat")
report = dict(case=name, **timing.timing_repeat(first, trial, legacy))
repeats.append(report)
require(report["pass_all"] is True, "Exact repeat differs: " + ", ".join(
key for key, value in report["checks"].items() if not value))
except Exception as error:
failures.append(dict(stage="raw_trial" if repeat_index == 0 else "repeat_trial", case=name,
repeat=repeat_index, type=type(error).__name__, message=str(error)))
finally:
if trial is not first:
close_trial(trial)
close_trial(first)
for mode in MODES:
expected = {(mode, odor, seed) for odor in odors for seed in seeds}
if expected.issubset(runs):
try:
report = legacy.summarize_mode(mode, odors, seeds, runs, cfg["gates"])
require(report["conditions"] == legacy.evaluate_gates(report, cfg["gates"]), "Original gate conjunction mismatch")
require(report["within_distance_count"] == 60 and report["between_distance_count"] == 75 and
report["pair_count"] == 15 and all(pair["within_distance_count"] == 20 and
pair["between_distance_count"] == 5 for pair in report["pairs"]), "Pair-specific denominator changed")
modes[mode] = report
if not report["gate"]:
failures.append(dict(stage="representation_gate", mode=mode,
failed_conditions=[key for key, value in report["conditions"].items() if not value]))
except Exception as error:
failures.append(dict(stage="representation_calculation", mode=mode, type=type(error).__name__, message=str(error)))
numerical = bool(len(runs) == 60 and len(timings) == 72 and not any(row["stage"] in
("case_input", "raw_trial", "repeat_trial") for row in failures))
repeated = bool(len(repeats) == 12 and all(row["pass_all"] is True for row in repeats))
execution = bool(numerical and repeated and not any(row["stage"] == "representation_calculation" for row in failures))
represented = bool(len(modes) == 2 and all(row["gate"] is True for row in modes.values()))
return dict(cohort=cohort, source_panel_split=SPLITS[cohort], pass_all=bool(execution and represented),
execution_gate_pass=execution, numerical_integrity_pass=numerical, exact_repeat_pass=repeated,
representation_gate_pass=represented, original_representation_gate_pass=represented,
expected_base_trials=60, valid_base_trials=len(runs), expected_repeats=12, checked_repeats=len(repeats),
checked_timing_trials=len(timings), modes=modes, runs=rows, repeats=repeats, timing_checks=timings,
failures=failures, input_output_provenance=proof)
def summarize(cohort, out_json=_DEFAULT_OUTPUT):
"""Default exclusive write; None recomputes deterministically without writes."""
require(cohort in COHORTS, "Unknown validation cohort")
import context as ctx
target = ctx.EXP / "validation" / cohort / "summary.json" if out_json is _DEFAULT_OUTPUT else (
None if out_json is None else Path(out_json))
require(target is None or not target.exists(), "Refusing existing cohort summary")
result = dict(cohort=cohort, source_panel_split=SPLITS[cohort], pass_all=False, execution_gate_pass=False,
numerical_integrity_pass=False, exact_repeat_pass=False, representation_gate_pass=False,
original_representation_gate_pass=False, expected_base_trials=60, valid_base_trials=0,
expected_repeats=12, checked_repeats=0, checked_timing_trials=0,
modes={}, runs=[], repeats=[], timing_checks=[], failures=[], input_output_provenance=[])
proof, odors, encoder = {}, [], None
try:
ctx.check()
legacy = load_frozen(ctx.AG_MODEL / "calibration.py", AG_SHA256, "phase4ak_frozen_ag_calibration")
timing = load_frozen(ctx.AJ_MODEL / "calibration.py", AJ_SHA256, "phase4ak_frozen_aj_calibration")
inventory_path = ctx.EXP / "protocol/validation-cases.json"
encoder_path = ctx.EXP / "protocol/encoder-audit.json"
panel_path = ctx.ROOT / "experiments/phase4l-olfactory-grounding/odor-encoder/frozen-odor-panel.parquet"
require(digest(panel_path) == PANEL_SHA256, "Frozen static panel SHA changed")
import pandas as pd
panel = pd.read_parquet(panel_path).to_dict(orient="records")
inventory = validate_inventory(read(inventory_path), ctx.CFG, panel, legacy)
encoder = read(encoder_path)
validate_encoder(encoder, inventory, ctx.CFG)
seed_audit = ctx.MODEL / "seed-audit.json"
require(digest(seed_audit) == encoder["seeds_static_audit_sha256"], "Seed-audit receipt/encoder mismatch")
kc_path = ctx.AG / "apl-bundle/kc_globals.npy"
kc = np.load(kc_path, allow_pickle=False)
require(kc.dtype == np.int32 and kc.shape == (4064,) and np.all(np.diff(kc) > 0) and
np.all((kc >= 0) & (kc < ctx.CFG["neurons"])), "Frozen KC identity invalid")
base_path = ctx.AJ / "cases/delay18/cal-physiological-00-s51101/spec.json"
base = read(base_path)
require(base["apl_delay_steps"] == 18 and base["training"] is False, "Wrong frozen physical reference")
proof = {"validation_inventory": digest(inventory_path), "encoder_audit": digest(encoder_path),
"static_panel": digest(panel_path), "seed_audit": digest(seed_audit),
"KC_identity": digest(kc_path), "frozen_D18_spec": digest(base_path),
"AG_calibration_source": AG_SHA256, "AJ_calibration_source": AJ_SHA256}
odors = inventory[cohort]["odor_ids"]
result = collect_cohort(cohort, inventory[cohort]["records"], odors, ctx.CFG, ctx.EXP, kc, base, legacy, timing)
except Exception as error:
result["failures"].append(dict(stage="prerequisites", type=type(error).__name__, message=str(error)))
result.update(phase="4AK", apl_delay_steps=18, seeds=ctx.CFG["validation"]["seeds"], duration_ms=100.0,
odor_ids=odors, encoder_audit=encoder, prerequisite_input_sha256=proof,
representation_failure_is_not_numerical_failure=True, old_module_globals_modified=False,
old_heldout_dynamic_access=False, historical_never_simulated_claim=False,
requested_cohort_only_dynamic_read=True, suite_owns_sequential_unlock=True,
shared_apl_component_oracle_limit=True, independent_oracle_equivalence_claim=False,
seed_namespace_claim="Declared static-audit scope only; not an unqualified all-history independence claim",
biological_delay_measurement_claimed=False, candidate_generated=False, training=False,
metric_source="SHA-pinned AG complete phase4l gate; SHA-pinned AJ timing/repeat checks")
# Serializability/finiteness must be established even for read-only finalization.
json.dumps(result, allow_nan=False, sort_keys=True)
if target is not None:
outputs = {target: result}
outputs.update({target.parent / (mode + ".json"): report for mode, report in result["modes"].items()})
require(all(not path.exists() for path in outputs), "Refusing existing cohort/mode output")
for path, value in outputs.items():
ctx.save(path, value)
return result
if __name__ == "__main__":
require(len(sys.argv) == 2, "Usage: validation.py seed_validation|novel_to_aj")
answer = summarize(sys.argv[1])
print(json.dumps({key: answer[key] for key in ("cohort", "pass_all", "execution_gate_pass", "representation_gate_pass")}))
@@ -0,0 +1,49 @@
"""Unchanged deterministic-v2 reference rerun, exclusively into this new stage."""
import os
import sys
import time
import numpy as np
import pandas as pd
import yaml
from context import ROOT, EXP, CFG, check, save, bit_equal
def main():
check()
assert not (EXP / 'regression/frozen-five.json').exists()
from run_case import preflight
preflight()
runtime_path = ROOT / 'models/male-cns-lif/deterministic-runtime-v2'
pc = yaml.safe_load((runtime_path / 'phase4p.yaml').read_text())
sys.path.insert(0, str(ROOT / 'models/male-cns-lif'))
sys.path.insert(0, str(runtime_path))
import torch
import phase4p
assert torch.cuda.mem_get_info()[0] > 2 * 1024**3
torch.cuda.reset_peak_memory_stats()
started = time.perf_counter()
runtime = phase4p.CanonicalRuntime(pc, runtime_path, EXP)
rows = []
for spec in pc['reference_trials']:
preflight()
reference_dir = ROOT / 'experiments/phase4p-deterministic-runtime/phase4c-v2/reference' / spec['name']
events = pd.read_parquet(reference_dir / 'spike-events.parquet')
reference = dict(step=events.step.to_numpy(), neuron_idx=events.neuron_idx.to_numpy(),
counts=np.load(reference_dir / 'per-neuron-spike-counts.int32.npy'),
v=np.load(reference_dir / 'final-voltage.float32.npy'), g=np.load(reference_dir / 'final-g.float32.npy'))
result = runtime.run(np.flatnonzero(runtime.pops[spec['population']]), spec['rate_hz'], spec['seed'], spec['duration_ms'])
row = dict(trial=spec['name'], exact={key: bool(bit_equal(value, result[key])) for key, value in reference.items()},
dtype_shape={key: dict(reference_dtype=str(value.dtype), actual_dtype=str(result[key].dtype),
reference_shape=list(value.shape), actual_shape=list(result[key].shape)) for key, value in reference.items()},
wall_seconds=result['metrics']['wall_seconds'])
rows.append(row)
print(row, flush=True)
passed = len(rows) == 5 and all(all(row['exact'].values()) for row in rows)
save(EXP / 'regression/frozen-five.json', dict(pass_all=passed, trials=rows,
wall_seconds=time.perf_counter() - started, peak_allocated_vram=int(torch.cuda.max_memory_allocated()),
scope='Old frozen deterministic-v2 five references only; not the new D18 hypothesis'))
assert passed
if __name__ == '__main__':
main()
@@ -0,0 +1,76 @@
# Phase4AG: author LIF + frozen legacy graded APL
Authorized independent hypothesis branch. All old source, raw connectome, signs,
W_syn, APL calibration, eligibility-v2 and 14,232-edge mask remain read-only.
No learning, gain/threshold changes, new edges, top-K, heldout activity, game or RL.
Author code provenance is the already archived MIT-licensed
https://github.com/philshiu/Drosophila_brain_model at
91bdd1e7dcf193f3e7ca5a8933497fcef63b7960; original model.py SHA-256
fc45837d7122c6ce2a7f3f2f23c515992e4b232aadb919efabb72337fac88e4e.
Associated paper: https://www.nature.com/articles/s41586-024-07763-9.
This new MaleCNS/APL combination is not a strict reproduction of that model.
The declared combination is author float64 LIF plus the exact old float32 graded
APL operator after synapses/resets at end. All 5,845 original APL fast out-edges
are zeroed only in the effective in-memory model, as in the legacy overlay.
Only KC receives graded replacement; known 1,212 non-KC edges remain unreplaced.
This existing scope limitation is not silently repaired in a compatibility test.
Use the original full normalized I[2,166700]/O[2,4064] float32 bytes and original
normalizers, even for induced real subgraphs. APL reads actual binary spikes,
never requests, and keeps independent float32 state. Preserve unfused operations:
state.mul_(float(f32(exp(-.1/20)))).add_(torch.mv(I, spikes_f32));
h32=torch.matmul(state,O)*f32(.01). Promote h32 to float64, multiply by float64
.001, then separately subtract from SI g. Do not alter TF32/default CuBLAS flags;
record them. No added APL delay, drive dt/tau scaling, truncation or clipping.
APL writes KC g unconditionally after author reset, including refractory KC.
Author g integration is frozen during refractory; therefore negative overlay g
may accumulate and differs from old dynamics. This is an explicit hypothesis,
not an assertion of original author or measured physiology. Guarded writes or
reset-before/after changes would be different hypotheses, not fixes to this one.
Eight fixed metadata/connectivity-selected fixtures cover zero/reset, real PN/KC
drive, current actual event feedback, duplicate natural/request event, 18-step
arrival vs22-step refractory boundary, full fast APL mask, non-KC scope and mixed
precision/high fan-in. No choice is made from runtime responses. Each GPU case
has3 independent fresh runs. A Brian2 author oracle starts from its own state,
computes its own actual spikes, and uses an isolated standard-I/O legacy-APL
worker with independent state. No candidate inhibition trace is fed into Brian.
All tick states, events, requests, queue order/guard, APL drive/state/h must agree
exactly. The APL component is shared, so this is NOT a fully independent CPU
oracle. Independently reconstruct old matrices using frozen initializer AST,
replay actual events through original update AST, require exact component bytes;
also quantify an independent float64 positive-sum arithmetic error bound. It is
not a replacement for exact legacy equivalence. No arithmetic bound is adjusted.
Only after all fixture gates pass, run two predeclared full-graph probes: first
old calibration odor, first original seed, both encoder modes. Compare each with
the independently running Brian + isolated APL worker. Save state hashes and sparse
events, not a time-by-all-neurons dense spike matrix. If a numerical gate fails,
stop CAL; keep diagnostic evidence and do not widen tolerance.
Then run the complete original6 CAL odors ×5 original seeds ×2 original modes,
100ms per run. Retain the ORIGINAL12-odor median for matched-energy encoding,
original pn_drive target/RNG column order, original evaluation seeds51101..51105.
Save Poisson requests before any trajectory. Only calibration dynamic cases are
used; formal A/B and heldout remain unrun. Repeat first seed for every odor/mode.
No per-odor pulse, amplitude, timing or threshold search. No learning.
Recompute the full original4L representation criteria on CAL only: mean KC active
fraction .03..09, min>0, max<.5, same-odor Jaccard>different, between Euclidean>
within, >=3 pairs whose mean between exceeds THAT PAIR's pooled within distances,
both modes. Add finiteness and exact repeat requirements. CAL PASS does not imply
heldout generalization, timing/credit specificity, memory or learning usability.
If CAL fails stop promotion and report it, not a least-bad candidate.
Before/after verify SHA-256 of all original230239 files and AA--AF seals; rerun original five
deterministic reference trials to new output. Archive code/env/source SHA,
matrices/norms/masks/identities, requests and all outputs. No published candidate.
Technical references (queried2026-09-30): Brian2 2.5.1 refractory documentation
https://brian2.readthedocs.io/en/2.5.1/user/refractoriness.html (actual generated code
remains authoritative); PyTorch numerical accuracy notes
https://docs.pytorch.org/docs/2.14/notes/numerical_accuracy.html (cross-backend
floating operations are not assumed bitwise equivalent).
@@ -0,0 +1,396 @@
"""Complete original Phase 4L representation metrics on fixed CAL inputs only.
No simulation, fitting, heldout trajectory access, or candidate generation is
performed here. The original 4L pair-specific within-odor baseline is retained;
the weaker Phase 4P r4 aggregate gate is deliberately not used.
"""
import csv
import hashlib
import itertools
import json
from pathlib import Path
import re
import numpy as np
STATE_DTYPES = {"step": np.int32, "neuron_idx": np.int32, "counts": np.int32,
"v": np.float64, "g": np.float64, "ref": np.int32}
REQUEST_FIELDS = ("tick", "neuron_idx", "attempted", "accepted", "rejected")
APL_FILES = {"apl-drive.float32.npy": 2, "apl-state.float32.npy": 2,
"apl-inhibition.float32.npy": 4064}
ORIGINAL_CAL_IDS = {
"OMSUIQOIVADKIM-RXMQYKEDSA-N", "LABTWGUMFABVFG-ARJAWSKDSA-N",
"QNVRIHYSUZMSGM-ZCFIWIBFSA-N", "VLSVVMPLPMNWBH-UHFFFAOYSA-N",
"XHIUFYZDQBSEMF-UHFFFAOYSA-N", "OMSUIQOIVADKIM-YFKPBYRVSA-N"}
ORIGINAL_MODES = ("physiological", "matched_energy")
ORIGINAL_SEEDS = (51101, 51102, 51103, 51104, 51105)
HEX_SHA = re.compile(r"[0-9a-f]{64}\Z")
_DEFAULT_OUTPUT = object()
def require(condition, message):
if not condition:
raise ValueError(message)
def read_json(path):
with Path(path).open(encoding="utf-8") as stream:
return json.load(stream)
def file_hash(path):
digest = hashlib.sha256()
with Path(path).open("rb") as stream:
for block in iter(lambda: stream.read(8 << 20), b""):
digest.update(block)
return digest.hexdigest()
def raw_hash(value):
return hashlib.sha256(np.ascontiguousarray(value).tobytes()).hexdigest()
def arrays_bitwise_equal(first, second):
"""Unlike array_equal, also reject different dtypes and signed-zero bits."""
return bool(first.dtype == second.dtype and first.shape == second.shape and
np.array_equal(np.ascontiguousarray(first).view(np.uint8),
np.ascontiguousarray(second).view(np.uint8)))
def pair_metrics(a, b):
"""Exact definitions copied from phase4i.pair_metrics/safe_corr/cosine."""
x, y = a.astype(np.float64), b.astype(np.float64)
aa, bb = a > 0, b > 0
union = int(np.count_nonzero(aa | bb))
intersection = int(np.count_nonzero(aa & bb))
denominator = float(np.linalg.norm(x) * np.linalg.norm(y))
cosine = 1.0 if denominator == 0 and np.array_equal(x, y) else (
0.0 if denominator == 0 else float(np.dot(x, y) / denominator))
correlation = (1.0 if np.array_equal(x, y) else 0.0) if np.std(x) == 0 or np.std(y) == 0 else float(np.corrcoef(x, y)[0, 1])
return {"active_intersection": intersection, "active_union": union,
"active_jaccard": 1.0 if union == 0 else float(intersection / union),
"cosine_similarity": cosine, "correlation": correlation,
"euclidean_distance": float(np.linalg.norm(x - y))}
def evaluate_gates(summary, gates):
"""Each conjunct in original phase4l.py:239, kept visible for audit."""
return {
"mean_sparsity_in_closed_interval": bool(float(gates["sparse_min_fraction"]) <=
summary["KC_active_fraction_mean"] <= float(gates["sparse_max_fraction"])),
"maximum_strictly_below_half": bool(summary["KC_active_fraction_max"] < 0.5),
"minimum_strictly_positive": bool(summary["KC_active_fraction_min"] > 0),
"same_jaccard_gt_different": bool(summary["same_odor_jaccard_mean"] > summary["different_odor_jaccard_mean"]),
"different_euclidean_gt_same": bool(summary["different_odor_euclidean_mean"] > summary["same_odor_euclidean_mean"]),
"at_least_original_pair_count": bool(summary["pairwise_separation_pass_count"] >= int(gates["minimum_separable_odor_pairs"]))}
def sample_cv(values):
"""Original pandas Series.std uses ddof=1. Undefined diagnostic -> null."""
values = np.asarray(values, dtype=np.float64)
mean = float(values.mean())
return None if mean == 0 else float(values.std(ddof=1) / mean)
def summarize_mode(mode, odor_ids, seeds, runs, gates):
within, within_j, between, between_j, between_cos, between_corr = [], [], [], [], [], []
pairs = []
for odor in odor_ids:
arrays = [runs[(mode, odor, seed)]["kc_counts"] for seed in seeds]
for first, second in itertools.combinations(arrays, 2):
metric = pair_metrics(first, second)
within.append(metric["euclidean_distance"])
within_j.append(metric["active_jaccard"])
for first_odor, second_odor in itertools.combinations(odor_ids, 2):
distances = []
for seed in seeds:
metric = pair_metrics(runs[(mode, first_odor, seed)]["kc_counts"],
runs[(mode, second_odor, seed)]["kc_counts"])
distances.append(metric["euclidean_distance"])
between.append(metric["euclidean_distance"])
between_j.append(metric["active_jaccard"])
between_cos.append(metric["cosine_similarity"])
between_corr.append(metric["correlation"])
pair_within = []
for odor in (first_odor, second_odor):
arrays = [runs[(mode, odor, seed)]["kc_counts"] for seed in seeds]
pair_within.extend(pair_metrics(first, second)["euclidean_distance"]
for first, second in itertools.combinations(arrays, 2))
cross_mean, within_mean = float(np.mean(distances)), float(np.mean(pair_within))
pairs.append({"odor_id_a": first_odor, "odor_id_b": second_odor,
"between_same_seed_mean": cross_mean, "within_this_pair_mean": within_mean,
"between_distance_count": len(distances), "within_distance_count": len(pair_within),
"gate": bool(cross_mean > within_mean)})
selected = [runs[(mode, odor, seed)] for odor in odor_ids for seed in seeds]
fractions = [int(np.count_nonzero(run["kc_counts"])) / len(run["kc_counts"]) for run in selected]
summary = {"KC_active_fraction_mean": float(np.mean(fractions)),
"KC_active_fraction_min": float(np.min(fractions)), "KC_active_fraction_max": float(np.max(fractions)),
"same_odor_jaccard_mean": float(np.mean(within_j)),
"different_odor_jaccard_mean": float(np.mean(between_j)),
"same_odor_euclidean_mean": float(np.mean(within)),
"different_odor_euclidean_mean": float(np.mean(between)),
"different_odor_cosine_mean": float(np.mean(between_cos)),
"different_odor_correlation_mean": float(np.mean(between_corr)),
"within_variance": float(np.var(within)), "between_distance_mean": float(np.mean(between)),
"pairwise_separation_pass_count": sum(row["gate"] for row in pairs), "pair_count": len(pairs),
"expected_event_count_cv": sample_cv([run["expected_external_events"] for run in selected]),
"actual_event_count_cv": sample_cv([run["external_events"] for run in selected]),
"within_distance_count": len(within), "between_distance_count": len(between),
"pairwise_baseline": "Each pair's two odors: 10+10 within-seed distances; never pooled across all odors",
"pairs": pairs}
summary["conditions"] = evaluate_gates(summary, gates)
summary["gate"] = bool(all(summary["conditions"].values()))
return summary
def validate_state(state, neurons, steps):
require(set(state) == set(STATE_DTYPES), "state.npz must have exactly the six declared arrays")
for name, dtype in STATE_DTYPES.items():
value = state[name]
require(value.dtype == dtype and value.ndim == 1, "Invalid state dtype/rank: " + name)
require(bool(np.isfinite(value).all()), "Nonfinite state: " + name)
if name not in ("step", "neuron_idx"):
require(value.shape == (neurons,), "Invalid state length: " + name)
ticks, nodes = state["step"], state["neuron_idx"]
require(ticks.shape == nodes.shape and bool(np.all((ticks >= 0) & (ticks < steps))) and
bool(np.all((nodes >= 0) & (nodes < neurons))), "Invalid sparse event indices")
keys = ticks.astype(np.int64) * neurons + nodes
require(bool(np.all(np.diff(keys) > 0)), "Sparse events not sorted unique by tick/global neuron")
require(np.array_equal(np.bincount(nodes, minlength=neurons), state["counts"]), "Counts disagree with sparse events")
require(bool(np.all((state["ref"] >= 0) & (state["ref"] <= 22))), "Final refractory outside frozen range")
return keys
def read_jsonl(path, steps, kind):
with Path(path).open(encoding="utf-8") as source:
rows = [json.loads(line) for line in source if line.strip()]
require(len(rows) == steps and [row.get("tick") for row in rows] == list(range(steps)),
"Missing/duplicate/reordered ticks in " + kind)
for row in rows:
names = ("v_sha256", "g_sha256", "ref_sha256") if kind == "state hashes" else (
"ordered_edge_sha256", "accepted_mask_sha256", "joint_sha256")
for name in names:
require(isinstance(row.get(name), str) and HEX_SHA.fullmatch(row[name]), "Invalid SHA256 in " + kind)
if kind == "queue":
require(type(row.get("count")) is int and type(row.get("accepted_count")) is int and
0 <= row["accepted_count"] <= row["count"], "Invalid queue counts")
return rows
def read_trial(output, case, spec, kc_globals, neurons, edges):
summary = read_json(output / "summary.json")
steps = spec["steps"]
require(summary.get("complete") is True and summary.get("pass_all") is True and
summary.get("all_finite") is True and summary.get("steps") == steps and
summary.get("completed_ticks") == steps and summary.get("nodes") == neurons and
summary.get("edges") == edges and summary.get("precision") == "float64" and
summary.get("apl_precision") == "float32" and summary.get("case") == spec["name"] and
summary.get("record_history") is False and summary.get("learning") is False,
"Incomplete/failed/wrong-scope GPU summary")
with np.load(output / "state.npz", allow_pickle=False) as source:
state = {name: source[name].copy() for name in source.files}
event_keys = validate_state(state, neurons, steps)
hashes = read_jsonl(output / "tick-state-hashes.jsonl", steps, "state hashes")
for name in ("v", "g", "ref"):
require(hashes[-1][name + "_sha256"] == raw_hash(state[name]), "Final state does not match last tick hash: " + name)
queues = read_jsonl(output / "queue.jsonl", steps, "queue")
apl = {}
for name, width in APL_FILES.items():
value = np.load(output / name, mmap_mode="r", allow_pickle=False)
require(value.dtype == np.float32 and value.shape == (steps, width) and
bool(np.isfinite(value).all()) and bool(np.all(value >= 0)), "Invalid full APL trace: " + name)
apl[name] = value
with (output / "requests.csv").open(encoding="utf-8", newline="") as source:
reader = csv.DictReader(source)
require(tuple(reader.fieldnames or ()) == REQUEST_FIELDS, "Request CSV schema mismatch")
request_rows = [{name: int(row[name]) for name in REQUEST_FIELDS} for row in reader]
with np.load(case / "requests.npz", allow_pickle=False) as source:
require(set(source.files) == {"tick", "neuron_idx"}, "Input request schema mismatch")
expected_ticks, expected_nodes = source["tick"], source["neuron_idx"]
require(expected_ticks.dtype == np.int32 and expected_nodes.dtype == np.int32 and
expected_ticks.ndim == 1 and expected_ticks.shape == expected_nodes.shape,
"Input request dtype/shape mismatch")
require(len(request_rows) == len(expected_ticks), "Requested event coverage mismatch")
require([row["tick"] for row in request_rows] == expected_ticks.tolist() and
[row["neuron_idx"] for row in request_rows] == expected_nodes.tolist(), "Requests differ from frozen input")
require(all(row["attempted"] == 1 and row["accepted"] in (0, 1) and
row["rejected"] == 1 - row["accepted"] for row in request_rows), "Invalid request acceptance bookkeeping")
requested_keys = expected_ticks.astype(np.int64) * neurons + expected_nodes
require(bool(np.all(np.diff(requested_keys) > 0)) and bool(np.all((expected_ticks >= 0) & (expected_ticks < steps))) and
bool(np.all((expected_nodes >= 0) & (expected_nodes < neurons))), "Input requests not sorted unique/in range")
actual_accepted = np.array([row["accepted"] for row in request_rows], dtype=np.uint8)
require(np.array_equal(np.isin(requested_keys, event_keys, assume_unique=True), actual_accepted.astype(bool)),
"Request accepted/rejected values disagree with actual spikes")
accepted = int(actual_accepted.sum())
require(summary.get("requested") == len(request_rows) and summary.get("accepted_requests") == accepted and
summary.get("rejected_requests") == len(request_rows) - accepted and
summary.get("total_spikes") == len(state["step"]), "Summary counts disagree with raw output")
component = read_json(output / "apl-component.json")
require(component.get("ok") is True and component.get("n_neurons") == neurons and
component.get("n_kc") == len(kc_globals) and component.get("n_apl") == 2 and
component.get("dt_ms") == .1 and summary.get("apl_component") == component,
"APL component provenance mismatch")
bundle = Path(spec["apl_bundle_dir"])
require(component.get("files_sha256") == {name: file_hash(bundle / name) for name in
("input_matrix.npy", "output_matrix.npy", "kc_globals.npy", "apl_globals.npy")}, "APL bundle hashes changed")
inputs = summary.get("input_sha256", {})
require(inputs.get("spec.json") == file_hash(case / "spec.json") and
inputs.get("requests.npz") == file_hash(case / "requests.npz"), "Case input provenance mismatch")
kc_counts = state["counts"][kc_globals].copy()
kc_event_mask = np.isin(state["neuron_idx"], kc_globals)
record = {"case": spec["name"], "mode": spec["mode"], "odor_id": spec["odor_id"],
"odor_name": spec["odor_name"], "seed": spec["seed"], "split": "calibration",
"KC_active": int(np.count_nonzero(kc_counts)), "KC_active_fraction": float(np.count_nonzero(kc_counts) / len(kc_globals)),
"KC_spikes": int(kc_counts.sum()), "KC_first_latency_ms":
float(state["step"][kc_event_mask][0] * .1) if bool(np.any(kc_event_mask)) else None,
"external_events": accepted, "expected_external_events": float(spec["expected_external_events"]),
"total_PN_rate_hz": float(spec["rate_sum_hz"]), "finite": True,
"total_spikes": len(state["step"]), "requested": len(request_rows)}
require(np.isfinite(record["expected_external_events"]) and record["expected_external_events"] > 0,
"CAL expected external events must be finite and positive")
return {"state": state, "hashes": hashes, "queues": queues, "apl": apl,
"requests": request_rows, "component": component, "kc_counts": kc_counts,
"expected_external_events": record["expected_external_events"], "external_events": accepted,
"record": record, "output": output}
def exact_repeat(first, repeat):
checks = {"state/" + name: arrays_bitwise_equal(first["state"][name], repeat["state"][name]) for name in STATE_DTYPES}
checks.update({name: arrays_bitwise_equal(first["apl"][name], repeat["apl"][name]) for name in APL_FILES})
checks.update(tick_state_hashes=first["hashes"] == repeat["hashes"],
queues=first["queues"] == repeat["queues"], requests=first["requests"] == repeat["requests"],
apl_component=first["component"] == repeat["component"])
return {"pass_all": bool(all(checks.values())), "checks": checks,
"scope": "All six state arrays, every tick all-neuron hashes, APL raw float32 traces, queues, requests and APL environment"}
def validate_inventory(records, cfg):
require(tuple(cfg["calibration"]["modes"]) == ORIGINAL_MODES and
tuple(cfg["calibration"]["seeds"]) == ORIGINAL_SEEDS and
cfg["calibration"]["duration_ms"] == 100.0 and cfg["calibration"]["odor_count"] == 6 and
cfg["calibration"]["split"] == "calibration" and
cfg["calibration"]["repeat_first_seed_each_odor"] is True, "Frozen CAL design changed")
gates = cfg["gates"]
require(gates["sparse_min_fraction"] == .03 and gates["sparse_max_fraction"] == .09 and
gates["minimum_separable_odor_pairs"] == 3 and gates["max_fraction_strict"] == .5 and
gates["min_fraction_strict"] == 0 and all(gates[key] is True for key in
("same_jaccard_gt_between", "between_euclidean_gt_within", "both_modes_required", "finite_required", "repeat_exact_required")),
"Original representation gates or additional integrity gates changed")
expected = {(mode, index, seed) for mode in ORIGINAL_MODES for index in range(6) for seed in ORIGINAL_SEEDS}
require(len(records) == 60 and {(row["mode"], row["odor_index"], row["seed"]) for row in records} == expected,
"CAL inventory must cover exactly 2 modes x 6 odors x 5 seeds")
odors = []
for index in range(6):
ids = {row["odor_id"] for row in records if row["odor_index"] == index}
require(len(ids) == 1, "Odor identity changes across seeds/modes")
odors.append(next(iter(ids)))
require(set(odors) == ORIGINAL_CAL_IDS, "CAL identities differ from the original frozen six")
for row in records:
require(row["name"] == f"cal-{row['mode']}-{row['odor_index']:02d}-s{row['seed']}", "Unexpected CAL case name")
return odors
def summarize(out_json=_DEFAULT_OUTPUT):
"""Recompute; default writes exclusively, out_json=None is strictly read-only."""
from context import EXP, ROOT, CFG, check
target = EXP / "calibration/summary.json" if out_json is _DEFAULT_OUTPUT else (
None if out_json is None else Path(out_json))
require(target is None or not target.exists(), "Refusing existing calibration summary")
failures, runs, run_records, repeats, provenance = [], {}, [], [], []
modes, odors = {}, []
prerequisites_ok = False
encoder = None
records = []
try:
check()
records = read_json(EXP / "protocol/calibration-cases.json")
odors = validate_inventory(records, CFG)
encoder = read_json(EXP / "protocol/encoder-audit.json")
require(encoder["panel_count"] == 12 and encoder["cal_count"] == 6 and
encoder["seeds"] == list(ORIGINAL_SEEDS) and encoder["requested_before_any_dynamics"] is True and
encoder["formal_AB_run"] is False and encoder["heldout_run"] is False, "Invalid frozen encoder scope")
# Only static original-panel metadata is read, never heldout trajectories.
import pandas as pd
original = pd.read_parquet(ROOT / "experiments/phase4l-olfactory-grounding/odor-encoder/frozen-odor-panel.parquet")
require(len(original) == 12 and set(original[original.split == "calibration"].odor_id) == ORIGINAL_CAL_IDS,
"Original static panel identity mismatch")
require(float(np.median(original.mapped_response_sum)) == encoder["median_mapped_response_sum"],
"Matched-energy reference is not the original frozen 12-panel median")
kc_globals = np.load(EXP / "apl-bundle/kc_globals.npy", allow_pickle=False)
require(kc_globals.dtype == np.int32 and kc_globals.shape == (4064,) and
bool(np.all(np.diff(kc_globals) > 0)) and bool(np.all((kc_globals >= 0) & (kc_globals < CFG["neurons"]))),
"Invalid frozen KC identities")
prerequisites_ok = True
except Exception as error:
failures.append({"stage": "prerequisites", "type": type(error).__name__, "message": str(error)})
if prerequisites_ok:
for row in records:
name = row["name"]
first = None
try:
case = EXP / "cases" / name
spec = read_json(case / "spec.json")
require(spec["name"] == name and spec["kind"] == "calibration" and spec["steps"] == 1000 and
spec["duration_ms"] == 100.0 and spec["dt_ms"] == .1 and spec["training"] is False and
all(spec[key] == row[key] for key in ("mode", "odor_id", "odor_index", "seed")),
"Case spec differs from fixed CAL inventory")
first = read_trial(EXP / "gpu" / (name + "-r0"), case, spec, kc_globals, CFG["neurons"], CFG["edges"])
require(first["record"]["requested"] == row["requests"], "Frozen inventory request count mismatch")
runs[(row["mode"], row["odor_id"], row["seed"])] = {key: first[key] for key in
("kc_counts", "expected_external_events", "external_events")}
run_records.append(first["record"])
provenance.append({"case": name, "repeat": 0, "state_npz_sha256": file_hash(first["output"] / "state.npz"),
"summary_sha256": file_hash(first["output"] / "summary.json")})
except Exception as error:
failures.append({"stage": "raw_trial", "case": name, "repeat": 0,
"type": type(error).__name__, "message": str(error)})
if row["seed"] == ORIGINAL_SEEDS[0]:
try:
require(first is not None, "Baseline unavailable for exact repeat")
repeat = read_trial(EXP / "gpu" / (name + "-r1"), case, spec, kc_globals, CFG["neurons"], CFG["edges"])
repeat_report = {"case": name, **exact_repeat(first, repeat)}
repeats.append(repeat_report)
provenance.append({"case": name, "repeat": 1, "state_npz_sha256": file_hash(repeat["output"] / "state.npz"),
"summary_sha256": file_hash(repeat["output"] / "summary.json")})
require(repeat_report["pass_all"], "Exact repeat differs: " + ", ".join(
key for key, value in repeat_report["checks"].items() if not value))
except Exception as error:
failures.append({"stage": "exact_repeat", "case": name, "repeat": 1,
"type": type(error).__name__, "message": str(error)})
if len(runs) == 60:
for mode in ORIGINAL_MODES:
try:
modes[mode] = summarize_mode(mode, odors, ORIGINAL_SEEDS, runs, CFG["gates"])
except Exception as error:
failures.append({"stage": "representation", "mode": mode,
"type": type(error).__name__, "message": str(error)})
integrity_pass = bool(prerequisites_ok and len(runs) == 60 and not any(row["stage"] in
("prerequisites", "raw_trial") for row in failures))
repeat_pass = bool(len(repeats) == 12 and all(row["pass_all"] for row in repeats) and
not any(row["stage"] == "exact_repeat" for row in failures))
representation_pass = bool(len(modes) == 2 and all(row["gate"] for row in modes.values()))
result = {"phase": "4AG", "scope": "Original fixed six CAL odors only; not heldout generalization or learning",
"pass_all": bool(integrity_pass and repeat_pass and representation_pass),
"numerical_integrity_pass": integrity_pass, "exact_repeat_pass": repeat_pass,
"original_representation_gate_pass": representation_pass,
"expected_base_trials": 60, "valid_base_trials": len(runs), "expected_repeats": 12,
"checked_repeats": len(repeats), "seeds": list(ORIGINAL_SEEDS), "duration_ms": 100.0,
"odor_ids": odors, "modes": modes, "runs": run_records, "repeats": repeats,
"failures": failures, "input_output_provenance": provenance, "encoder_audit": encoder,
"metric_source": "phase4l.representation (full original gate), phase4i.pair_metrics",
"finite_gate_note": "Added integrity prerequisite; original 4L recorded finite but omitted it from its gate",
"repeat_gate_note": "Additional exact repeat requirement; original metrics and numerical thresholds unchanged",
"shared_apl_component_oracle_limit": True, "independent_oracle_equivalence_claim": False,
"candidate_generated": False, "training": False, "heldout_dynamic_access": False}
if target is not None:
target.parent.mkdir(parents=True, exist_ok=True)
with target.open("x", encoding="utf-8") as output:
json.dump(result, output, ensure_ascii=False, indent=2, allow_nan=False)
output.write("\n")
return result
if __name__ == "__main__":
print(json.dumps({key: value for key, value in summarize().items() if key in
("pass_all", "numerical_integrity_pass", "exact_repeat_pass", "original_representation_gate_pass")}), flush=True)
@@ -0,0 +1,17 @@
c14c2d3c35e2b404c516befa66370723fba075516540214ae46e4104ff87e813 PROTOCOL.md
edb9cb2d890471fd07afd88c959ef3540b0cd40af490fac3f26396b5e7f5bf9c calibration.py
6e1616b086f667fa4e4b5087f500f8080281977ca9922e7b055acfddd2003bd5 compare.py
2aa6b4d777ff698018e1a6eaf571215208b8c874a4c848a6d632e2bd778c90e3 config.json
b8b1231d958a3ec935ec1d5a36e08cbd9bcd1127f4d4bb243a9051884a0e7a16 context.py
b6e3c67e668a971b544df32d76435ab5e537061b9fc2e8d9dedb5d2a726f5782 finalize.py
69f5d893f47dafff4ef7c3186c3df0b9014666b32c8f4e943b57016bec92b18a gpu_apl.py
21ceec65fe42581dc55872010e0025d660e80358905f1cf4df1dadf341a3b291 legacy_apl_worker.py
9b7f3e0b59f2117b94b41a6f542f37e6f7950138d324c905e8e0ac6cb7d17151 oracle_apl.py
197ccc6aae70566c4db4d4de17fa032e853b9bd9a04262905d6c71e12a930b6f prepare.py
afbe6d5a37c29bda66d38c470093584130d1852e67881c681662aec3c76b33c7 run_case.py
84c681030b0032119b5392d0c3f3c136a9c6b0d133eb548c40791a10bbbb8b63 run_suite.py
bab3136eecbc5bb09a985d715844ee845cb72b07930ce376bfb39be33bd1845a test_calibration.py
1a233f47943e01bbd845ac1dacdb1eec3f88c270c65a5f75bce1cf679b5de097 test_protocol.py
5cfc9a4505da6b8fb4e7d2617cdaedaa8475ed46a11ec9bdf0d4d25b1d22c2d3 validate_components.py
0d0e72b2f1348f6648124c8c34f75094f76fc5e1a281fbcca130a5fad2f35293 verify_frozen.py
6aa01a937f1f3c6504ee92e847cf7b3a884e88aa4ef37a68b0b7d4e7deed4bf2 manifest.json
@@ -0,0 +1,508 @@
"""Fail-closed byte-exact audit of the shared-APL closed-loop fixtures.
Comparison is independent of either backend's stored PASS. No tolerance is
used, timing fields are never compared, and reports contain no wall timestamp.
"""
from __future__ import annotations
import csv
import hashlib
import json
import math
from pathlib import Path
import re
import struct
import numpy as np
N_GLOBAL = 166700
STATE_KEYS = ('step', 'neuron_idx', 'counts', 'v', 'g', 'ref')
REQUEST_FIELDS = ('tick', 'neuron_idx', 'attempted', 'accepted', 'rejected')
HASH_FIELDS = {'tick', 'v_sha256', 'g_sha256', 'ref_sha256'}
QUEUE_FIELDS = {'tick', 'count', 'accepted_count', 'ordered_edge_sha256',
'accepted_mask_sha256', 'joint_sha256'}
BUNDLE_FILES = ('input_matrix.npy', 'output_matrix.npy', 'kc_globals.npy', 'apl_globals.npy')
COEFFICIENTS = ('gd', 'c0', 'cg', 'cv', 'threshold', 'reset', 'seed_volt')
def require(condition, message):
if not condition:
raise ValueError(message)
def file_hash(path):
h = hashlib.sha256()
with Path(path).open('rb') as source:
for block in iter(lambda: source.read(8 << 20), b''):
h.update(block)
return h.hexdigest()
def raw_hash(array, dtype=None):
return hashlib.sha256(np.ascontiguousarray(array, dtype=dtype).tobytes()).hexdigest()
def save(path, report):
if path is None:
return
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
with path.open('x', encoding='utf-8') as target:
json.dump(report, target, indent=2, sort_keys=True, allow_nan=False)
target.write('\n')
def _read_json(path, used):
used.add(Path(path))
return json.loads(Path(path).read_text(encoding='utf-8'))
def _read_jsonl(path, used):
used.add(Path(path))
with Path(path).open(encoding='utf-8') as source:
return [json.loads(line) for line in source if line.strip()]
def _read_array(path, used):
used.add(Path(path))
return np.load(path, mmap_mode='r', allow_pickle=False)
def _check(checks, name, condition):
checks[name] = bool(condition)
def _bit_mask(a, b):
if a.dtype.kind == 'f':
unsigned = np.dtype('uint'+str(a.dtype.itemsize*8))
return np.ascontiguousarray(a).view(unsigned) != np.ascontiguousarray(b).view(unsigned)
return a != b
def _compare_array(name, a, b, checks, differences, dtype=None, shape=None):
a, b = np.asarray(a), np.asarray(b)
schema = a.shape == b.shape and a.dtype == b.dtype and \
(dtype is None or a.dtype == np.dtype(dtype)) and (shape is None or a.shape == shape)
_check(checks, name+'.schema', schema)
if not schema:
differences[name] = {'left_shape': list(a.shape), 'right_shape': list(b.shape),
'left_dtype': str(a.dtype), 'right_dtype': str(b.dtype), 'expected_shape': None if shape is None else list(shape),
'expected_dtype': None if dtype is None else str(np.dtype(dtype))}
_check(checks, name+'.bitwise_exact', False)
return False
finite = bool(np.isfinite(a).all() and np.isfinite(b).all())
_check(checks, name+'.finite', finite)
mask = _bit_mask(a, b)
exact = not bool(np.any(mask))
_check(checks, name+'.bitwise_exact', exact)
if not exact or not finite:
flat = np.flatnonzero(mask.ravel())
detail = {'mismatching_elements': int(len(flat)),
'first_positions': [list(map(int, np.unravel_index(int(index), a.shape))) for index in flat[:5]],
'left_nonfinite': int(np.count_nonzero(~np.isfinite(a))),
'right_nonfinite': int(np.count_nonzero(~np.isfinite(b)))}
if finite and a.size:
error = np.abs(a.astype(np.float64)-b.astype(np.float64))
detail.update(max_abs_error=float(error.max()), mean_abs_error=float(error.mean()))
if a.dtype.kind == 'f' and len(flat):
unsigned = np.dtype('uint'+str(a.dtype.itemsize*8))
av = np.ascontiguousarray(a).view(unsigned).ravel()
bv = np.ascontiguousarray(b).view(unsigned).ravel()
detail['first_bit_patterns'] = [{'left': hex(int(av[index])), 'right': hex(int(bv[index]))} for index in flat[:5]]
differences[name] = detail
return exact and finite
def _sha(value):
return isinstance(value, str) and re.fullmatch('[0-9a-f]{64}', value) is not None
def _read_requests(path, steps, used):
used.add(Path(path))
with Path(path).open(encoding='utf-8', newline='') as source:
reader = csv.DictReader(source)
require(tuple(reader.fieldnames or ()) == REQUEST_FIELDS, 'Request CSV schema mismatch: '+str(path))
rows = [{key: int(row[key]) for key in REQUEST_FIELDS} for row in reader]
previous = (-1, -1)
for row in rows:
key = row['tick'], row['neuron_idx']
require(previous < key and 0 <= key[0] < steps and 0 <= key[1] < N_GLOBAL,
'Request rows must be sorted, unique, and in range: '+str(path))
require(row['attempted'] == 1 and row['accepted'] in (0, 1) and row['rejected'] == 1-row['accepted'],
'Request accounting is incomplete: '+str(path))
previous = key
return rows
def _load_run(directory, role, n, edges, steps, record_history, name, used, checks):
directory = Path(directory)
summary = _read_json(directory/'summary.json', used)
_check(checks, role+'.summary_complete', summary.get('complete') is True and summary.get('pass_all') is True and
summary.get('steps') == steps and summary.get('completed_ticks') == steps and
summary.get('nodes') == n and summary.get('edges') == edges and summary.get('precision') == 'float64')
is_cpu = role == 'cpu'
_check(checks, role+'.case_name', summary.get('name' if is_cpu else 'case') == name)
_check(checks, role+'.history_mode', summary.get('history_recorded' if is_cpu else 'record_history') is record_history)
_check(checks, role+'.apl_precision', summary.get('APL_precision' if is_cpu else 'apl_precision') == 'float32')
_check(checks, role+'.no_error_marker', not (directory/'error.json').exists())
used.add(directory/'state.npz')
with np.load(directory/'state.npz', allow_pickle=False) as source:
require(set(source.files) == set(STATE_KEYS), 'State NPZ keys changed: '+str(directory))
state = {key: source[key].copy() for key in STATE_KEYS}
for key, dtype in (('v', 'float64'), ('g', 'float64'), ('ref', 'int32'), ('counts', 'int32')):
require(state[key].shape == (n,) and state[key].dtype == np.dtype(dtype), 'Invalid final '+key+': '+str(directory))
require(state['step'].dtype == state['neuron_idx'].dtype == np.int32 and state['step'].ndim == 1 and
state['step'].shape == state['neuron_idx'].shape, 'Invalid sparse event schema: '+str(directory))
require(bool(np.all((state['step'] >= 0) & (state['step'] < steps))) and
bool(np.all((state['neuron_idx'] >= 0) & (state['neuron_idx'] < N_GLOBAL))), 'Sparse event range error')
event_keys = state['step'].astype(np.int64)*N_GLOBAL+state['neuron_idx']
_check(checks, role+'.events_sorted_unique', len(event_keys) < 2 or np.all(np.diff(event_keys) > 0))
_check(checks, role+'.count_nonnegative_total', np.all(state['counts'] >= 0) and int(state['counts'].sum()) == len(event_keys))
_check(checks, role+'.ref_range', np.all((state['ref'] >= 0) & (state['ref'] <= 22)))
_check(checks, role+'.reported_events', summary.get('spikes' if is_cpu else 'total_spikes') == len(event_keys))
hashes = _read_jsonl(directory/'tick-state-hashes.jsonl', used)
require(len(hashes) == steps and [row.get('tick') for row in hashes] == list(range(steps)), 'Incomplete tick hash coverage')
require(all(set(row) == HASH_FIELDS and all(_sha(row[key]) for key in HASH_FIELDS-{'tick'}) for row in hashes),
'Invalid tick state hash schema')
queues = _read_jsonl(directory/'queue.jsonl', used)
require(len(queues) == steps and [row.get('tick') for row in queues] == list(range(steps)), 'Incomplete queue coverage')
require(all(set(row) == QUEUE_FIELDS and type(row['count']) is int and type(row['accepted_count']) is int and
0 <= row['accepted_count'] <= row['count'] <= edges and
all(_sha(row[key]) for key in QUEUE_FIELDS-{'tick', 'count', 'accepted_count'}) for row in queues),
'Invalid queue row schema/count/hash')
for key in ('v', 'g', 'ref'):
_check(checks, role+'.last_hash_'+key, hashes[-1][key+'_sha256'] == raw_hash(state[key], '<i4' if key == 'ref' else '<f8'))
requests = _read_requests(directory/'requests.csv', steps, used)
requested, accepted = len(requests), sum(row['accepted'] for row in requests)
_check(checks, role+'.request_summary', summary.get('requests' if is_cpu else 'requested') == requested and
summary.get('applicable_requests' if is_cpu else 'accepted_requests') == accepted and
summary.get('ref_rejected_requests' if is_cpu else 'rejected_requests') == requested-accepted)
apl = {field: _read_array(directory/('apl-'+field+'.float32.npy'), used) for field in ('drive', 'state', 'inhibition')}
for field, width in (('drive', 2), ('state', 2), ('inhibition', 4064)):
require(apl[field].dtype == np.float32 and apl[field].shape == (steps, width), 'Invalid APL '+field+' history schema')
_check(checks, role+'.apl_positive_'+field, np.all(apl[field] >= 0))
histories, pre = {}, {}
for field, dtype in (('v', 'float64'), ('g', 'float64'), ('ref', 'int32')):
files = (directory/(field+'-history.'+dtype+'.npy'), directory/('preAPL-'+field+'.'+dtype+'.npy'))
if record_history:
histories[field], pre[field] = (_read_array(path, used) for path in files)
require(all(array.dtype == np.dtype(dtype) and array.shape == (steps, n) for array in (histories[field], pre[field])),
'Small pre/post history schema mismatch')
_check(checks, role+'.history_hashes_'+field, all(row[field+'_sha256'] == raw_hash(histories[field][tick])
for tick, row in enumerate(hashes)))
_check(checks, role+'.history_final_'+field, not np.any(_bit_mask(histories[field][-1], state[field])))
else:
_check(checks, role+'.no_dense_'+field, not any(path.exists() for path in files))
if is_cpu:
component = _read_json(directory/'apl-worker-handshake.json', used)['handshake']
else:
component = _read_json(directory/'apl-component.json', used)
_check(checks, role+'.component_summary_consistent', summary.get('apl_component') == component)
return dict(directory=directory, summary=summary, state=state, hashes=hashes, queues=queues,
requests=requests, apl=apl, histories=histories, pre=pre, component=component)
def _pair_outputs(left, right, checks, differences, n, steps, record_history):
for field in STATE_KEYS:
shape = None if field in ('step', 'neuron_idx') else (n,)
dtype = 'float64' if field in ('v', 'g') else 'int32'
_compare_array('state.'+field, left['state'][field], right['state'][field], checks, differences, dtype, shape)
for field, width in (('drive', 2), ('state', 2), ('inhibition', 4064)):
_compare_array('apl.'+field, left['apl'][field], right['apl'][field], checks, differences, 'float32', (steps, width))
for field in ('hashes', 'queues', 'requests', 'component'):
same = left[field] == right[field]
_check(checks, field+'.parsed_exact', same)
if not same:
if isinstance(left[field], list):
first = next((i for i, (a, b) in enumerate(zip(left[field], right[field])) if a != b), None)
differences[field] = {'left_count': len(left[field]), 'right_count': len(right[field]),
'first_differing_row': first,
'left_row': None if first is None else left[field][first],
'right_row': None if first is None else right[field][first]}
else:
differences[field] = {'left': left[field], 'right': right[field]}
if record_history:
for stage in ('histories', 'pre'):
for field, dtype in (('v', 'float64'), ('g', 'float64'), ('ref', 'int32')):
_compare_array(stage+'.'+field, left[stage][field], right[stage][field], checks, differences, dtype, (steps, n))
def _queue_digest(tick, ids, accepted):
ids = np.ascontiguousarray(ids, dtype='<i8').tobytes()
mask = np.ascontiguousarray(accepted, dtype=np.uint8).tobytes()
return {'tick': tick, 'count': len(mask), 'accepted_count': int(np.count_nonzero(accepted)),
'ordered_edge_sha256': hashlib.sha256(ids).hexdigest(),
'accepted_mask_sha256': hashlib.sha256(mask).hexdigest(),
'joint_sha256': hashlib.sha256(b'phase4af-queue-v1\0'+struct.pack('<qq', tick, len(mask))+ids+mask).hexdigest()}
def _independent_event_accounting(run, role, graph, requested, steps, checks, differences):
nodes, ptr = graph['nodes'], graph['ptr']
n = len(nodes)
state = run['state']
local = np.searchsorted(nodes, state['neuron_idx'])
require(np.all(local < n) and np.array_equal(nodes[local], state['neuron_idx']), 'Actual spike outside graph identity')
_check(checks, role+'.events_per_neuron_counts', np.array_equal(np.bincount(local, minlength=n), state['counts']))
actual_request_pairs = [(row['tick'], row['neuron_idx']) for row in run['requests']]
_check(checks, role+'.requests_match_frozen_input', actual_request_pairs == requested)
require(actual_request_pairs == requested, 'Actual request population/time differs from frozen input')
bounds = np.searchsorted(state['step'], np.arange(steps+1))
request_ticks = np.asarray([row['tick'] for row in run['requests']], np.int32)
rbounds = np.searchsorted(request_ticks, np.arange(steps+1))
request_nodes = np.asarray([row['neuron_idx'] for row in run['requests']], np.int32)
request_local = np.searchsorted(nodes, request_nodes)
require(np.all(request_local < n) and np.array_equal(nodes[request_local], request_nodes), 'Request outside graph')
last = np.full(n, -1_000_000_000, np.int64)
degrees = np.diff(ptr)
expected_counts = np.zeros(steps, np.int64)
arrival_tick = state['step'].astype(np.int64)+18
valid = arrival_tick < steps
np.add.at(expected_counts, arrival_tick[valid], degrees[local[valid]])
_check(checks, role+'.delayed_all_edges_count', np.array_equal(expected_counts, [row['count'] for row in run['queues']]))
request_ok, delivered_ok, ref_ok, queue_ok, reset_ok = True, True, True, True, True
first = {}
for tick in range(steps):
fired = local[bounds[tick]:bounds[tick+1]]
lo, hi = rbounds[tick:tick+2]
targets = request_local[lo:hi]
accepted = (tick-last[targets]) >= 22
for index, ok in zip(range(lo, hi), accepted):
row = run['requests'][index]
if row['accepted'] != int(ok) or row['rejected'] != int(not ok):
request_ok = False
first.setdefault('request_ref_mismatch', {'tick': tick, 'neuron_idx': row['neuron_idx']})
if not np.isin(targets[accepted], fired).all() or np.isin(targets[~accepted], fired).any():
delivered_ok = False
first.setdefault('request_delivery_mismatch', tick)
last[fired] = tick
ref = np.maximum(22-(tick-last), 0).astype(np.int32)
if raw_hash(ref, '<i4') != run['hashes'][tick]['ref_sha256']:
ref_ok = False
first.setdefault('ref_hash_mismatch', tick)
if run['pre']:
if len(fired) and not np.array_equal(np.ascontiguousarray(run['pre']['g'][tick, fired]).view(np.uint64), np.zeros(len(fired), np.uint64)):
reset_ok = False
first.setdefault('pre_apl_spike_reset_mismatch', tick)
due = local[bounds[tick-18]:bounds[tick-17]] if tick >= 18 else np.empty(0, np.int64)
chunks = [np.arange(ptr[source], ptr[source+1], dtype=np.int64) for source in due]
indices = np.concatenate(chunks) if chunks else np.empty(0, np.int64)
expected_queue = _queue_digest(tick, graph['edge_id'][indices], (ref[graph['dst'][indices]] == 0).astype(np.uint8))
if expected_queue != run['queues'][tick]:
queue_ok = False
first.setdefault('queue_reconstruction_mismatch', tick)
_check(checks, role+'.request_refractory_gate', request_ok)
_check(checks, role+'.accepted_spikes_rejected_absent', delivered_ok)
_check(checks, role+'.all_ref_hashes_from_actual_events', ref_ok)
if run['pre']:
_check(checks, role+'.small_queue_independent_reconstruction', queue_ok)
_check(checks, role+'.spike_g_reset_before_apl', reset_ok)
if first:
differences[role+'.independent_accounting'] = first
def _check_apl_application(run, role, nodes, kc, checks, differences):
if not run['pre']:
return
common, local_kc, bundle_kc = np.intersect1d(nodes, kc, assume_unique=True, return_indices=True)
_compare_array(role+'.apl_keeps_voltage', run['pre']['v'], run['histories']['v'], checks, differences, 'float64')
_compare_array(role+'.apl_keeps_ref', run['pre']['ref'], run['histories']['ref'], checks, differences, 'int32')
expected = np.array(run['pre']['g'], copy=True)
delta = run['apl']['inhibition'][:, bundle_kc].astype(np.float64)*np.float64(.001)
expected[:, local_kc] = expected[:, local_kc]-delta
_compare_array(role+'.apl_unconditional_g_write', expected, run['histories']['g'], checks, differences, 'float64')
def _finish(report, checks, differences, used, out_json):
report['checks'] = {name: bool(value) for name, value in checks.items()}
report['differences'] = differences
report['pass_all'] = bool(checks) and all(checks.values()) and 'error' not in report
report['failed_checks'] = sorted(name for name, value in checks.items() if not value)
report['evidence_sha256'] = {str(path): file_hash(path) for path in sorted(used) if path.is_file()}
save(out_json, report)
return report
def compare(case_dir, gpu_dir, cpu_dir, out_json=None):
"""Strict independent closed-loop comparison; out_json=None is read-only."""
case_dir, gpu_dir, cpu_dir = Path(case_dir), Path(gpu_dir), Path(cpu_dir)
if out_json is not None:
require(not Path(out_json).exists(), 'Refusing existing comparison report')
checks, differences, used = {}, {}, set()
report = {'kind': 'shared-APL-component closed-loop byte-exact comparison', 'pass_all': False,
'case_dir': str(case_dir), 'gpu_dir': str(gpu_dir), 'cpu_dir': str(cpu_dir),
'tolerance': None, 'signed_zero_included': True, 'timing_fields_compared': False,
'independent_CPU_all_components_claim': False}
try:
spec = _read_json(case_dir/'spec.json', used)
steps, history = spec['steps'], spec['record_history']
require(type(steps) is int and steps > 0 and type(history) is bool and spec['dt_ms'] == .1,
'Invalid fixed case clock/history schema')
graph_dir, bundle_dir = Path(spec['graph_dir']), Path(spec['apl_bundle_dir'])
graph = {field: _read_array(graph_dir/(field+'.npy'), used) for field in
('nodes', 'edge_id', 'src', 'dst', 'ptr', 'signed_raw', 'weights')}
nodes = graph['nodes']
n, edges = len(nodes), len(graph['edge_id'])
require(n > 0 and edges > 0 and nodes.dtype == np.int32 and nodes.ndim == 1 and np.all((nodes >= 0) & (nodes < N_GLOBAL)) and
np.all(np.diff(nodes) > 0), 'Invalid canonical node identities')
require(graph['ptr'].dtype == np.int64 and graph['ptr'].shape == (n+1,) and graph['ptr'][0] == 0 and
graph['ptr'][-1] == edges and np.all(np.diff(graph['ptr']) >= 0), 'Invalid CSR')
for key, dtype in (('edge_id', 'int64'), ('src', 'int32'), ('dst', 'int32'), ('signed_raw', 'int64'), ('weights', 'float64')):
require(graph[key].dtype == np.dtype(dtype) and graph[key].shape == (edges,), 'Invalid graph '+key)
require(np.array_equal(graph['src'], np.repeat(np.arange(n, dtype=np.int32), np.diff(graph['ptr']))) and
np.all((graph['dst'] >= 0) & (graph['dst'] < n)), 'Invalid source/destination row mapping')
require(history == (n < 512) and (n < 512 or n == N_GLOBAL), 'Invalid small/full history declaration')
require(np.all(graph['edge_id'] >= 0) and np.all(np.diff(graph['edge_id']) > 0),
'Original canonical edge IDs must be unique and increasing')
if n == N_GLOBAL:
require(edges == 25582938 and np.array_equal(nodes, np.arange(n, dtype=np.int32)) and
np.array_equal(graph['edge_id'], np.arange(edges, dtype=np.int64)), 'Full canonical graph identity changed')
bundle = {name: _read_array(bundle_dir/name, used) for name in BUNDLE_FILES}
kc, apl_ids = bundle['kc_globals.npy'], bundle['apl_globals.npy']
require(kc.dtype == apl_ids.dtype == np.int32 and kc.shape == (4064,) and apl_ids.shape == (2,), 'Invalid APL/KC identities')
require(np.all((kc >= 0) & (kc < N_GLOBAL)) and np.all(np.diff(kc) > 0) and
np.all((apl_ids >= 0) & (apl_ids < N_GLOBAL)) and np.all(np.diff(apl_ids) > 0) and
not np.intersect1d(kc, apl_ids).size, 'APL/KC identities overlap or are invalid')
for key, shape in (('input_matrix.npy', (2, N_GLOBAL)), ('output_matrix.npy', (2, 4064))):
require(bundle[key].dtype == np.float32 and bundle[key].shape == shape and
np.isfinite(bundle[key]).all() and np.all(bundle[key] >= 0), 'Invalid normalized APL matrix')
gpu = _load_run(gpu_dir, 'gpu', n, edges, steps, history, spec['name'], used, checks)
cpu = _load_run(cpu_dir, 'cpu', n, edges, steps, history, spec['name'], used, checks)
_pair_outputs(gpu, cpu, checks, differences, n, steps, history)
used.add(case_dir/'requests.npz')
with np.load(case_dir/'requests.npz', allow_pickle=False) as source:
require(set(source.files) == {'tick', 'neuron_idx'} and source['tick'].dtype == source['neuron_idx'].dtype == np.int32,
'Fixed request NPZ schema changed')
require(source['tick'].shape == source['neuron_idx'].shape and source['tick'].ndim == 1, 'Invalid sparse request shape')
requested = list(zip(map(int, source['tick']), map(int, source['neuron_idx'])))
for role, run in (('gpu', gpu), ('cpu', cpu)):
_independent_event_accounting(run, role, graph, requested, steps, checks, differences)
_check_apl_application(run, role, nodes, kc, checks, differences)
# Independently derive the effective clone. Original graph weights stay read-only.
cpu_weights = _read_array(cpu_dir/'weights.npy', used)
require(cpu_weights.dtype == np.float64 and cpu_weights.shape == (edges,), 'CPU effective weight schema mismatch')
expected_hash, base_hash, mask_hash = hashlib.sha256(), hashlib.sha256(), hashlib.sha256()
weight_ok, mask_count = True, 0
for start in range(0, edges, 1 << 20):
stop = min(edges, start+(1 << 20))
original = np.asarray(graph['weights'][start:stop])
require(np.isfinite(original).all(), 'Nonfinite original weights')
raw_expected = graph['signed_raw'][start:stop]*(.275*.001)
require(not np.any(_bit_mask(original, raw_expected)), 'Original SI weights differ from unaltered signed contacts')
mask = np.isin(nodes[graph['src'][start:stop]], apl_ids)
expected = original.copy()
expected[mask] = np.float64(0)
mask_count += int(mask.sum())
expected_hash.update(np.ascontiguousarray(expected, dtype='<f8').tobytes())
base_hash.update(np.ascontiguousarray(original, dtype='<f8').tobytes())
mask_hash.update(np.ascontiguousarray(graph['edge_id'][start:stop][mask], dtype='<i8').tobytes())
weight_ok &= not np.any(_bit_mask(expected, cpu_weights[start:stop]))
expected_sha = expected_hash.hexdigest()
_check(checks, 'cpu.effective_weights_independent_bytes', weight_ok)
for role, run in (('gpu', gpu), ('cpu', cpu)):
_check(checks, role+'.effective_weights_raw_sha', run['summary'].get('effective_weights_raw_sha256') == expected_sha)
_check(checks, role+'.apl_fast_edge_count', run['summary'].get('apl_fast_edges_zeroed') == mask_count)
_check(checks, role+'.kc_target_count', run['summary'].get('kc_targets_present') == len(np.intersect1d(nodes, kc)))
mask_audit = _read_json(cpu_dir/'apl-mask-audit.json', used)
_check(checks, 'cpu.mask_provenance', mask_audit['count'] == mask_count and
mask_audit['ordered_original_edge_id_sha256'] == mask_hash.hexdigest() and
mask_audit['base_weight_raw_bytes_sha256'] == base_hash.hexdigest() and
mask_audit['effective_weights_raw_sha256'] == expected_sha and mask_audit['base_graph_files_modified'] is False)
case_hashes = {name: file_hash(case_dir/name) for name in ('spec.json', 'requests.npz')}
if (case_dir/'arrays.npz').exists():
case_hashes['arrays.npz'] = file_hash(case_dir/'arrays.npz')
used.add(case_dir/'arrays.npz')
baseline_coeff = _read_json(Path(spec['coefficients_path']), used)
actual_coeff = _read_json(cpu_dir/'coefficients.json', used)
_check(checks, 'cpu.actual_author_coefficients_exact', all(float(actual_coeff[key]).hex() == float(baseline_coeff[key]).hex()
for key in COEFFICIENTS))
audit = _read_json(cpu_dir/'input-audit.json', used)
expected_graph_hashes = {name: file_hash(graph_dir/name) for name in
tuple(field+'.npy' for field in graph)+('completeness.csv', 'connectivity.parquet')}
bundle_hashes = {name: file_hash(bundle_dir/name) for name in BUNDLE_FILES}
_check(checks, 'cpu.read_actual_case', audit['spec'] == spec and audit['case_hashes'] == case_hashes)
_check(checks, 'cpu.graph_hashes', audit['graph_hashes'] == expected_graph_hashes)
_check(checks, 'cpu.bundle_hashes', audit['bundle_hashes'] == bundle_hashes)
_check(checks, 'cpu.no_candidate_trace_input', audit.get('candidate_trace_used_as_input') is False and
cpu['summary'].get('candidate_trace_used_as_input') is False)
_check(checks, 'cpu.worker_source_hash', audit['legacy_apl_worker_sha256'] == file_hash(spec['legacy_apl_worker']))
_check(checks, 'cpu.coefficient_input_hash', audit['coefficients_sha256'] == file_hash(spec['coefficients_path']))
gpu_hashes = dict(case_hashes, **{'base_weights.npy': file_hash(graph_dir/'weights.npy'),
'coefficients.json': file_hash(spec['coefficients_path'])})
_check(checks, 'gpu.input_hashes', gpu['summary']['input_sha256'] == gpu_hashes)
for role, run in (('gpu', gpu), ('cpu', cpu)):
component = run['component']
_check(checks, role+'.actual_component_bundle_bytes', component['files_sha256'] == bundle_hashes and
component['array_sha256'] == {name: raw_hash(value) for name, value in bundle.items()})
_check(checks, role+'.component_dimensions_clock', component.get('ok') is True and
component['protocol'] == 'phase4ag-apl-v1' and component['n_neurons'] == N_GLOBAL and
component['n_apl'] == 2 and component['n_kc'] == 4064 and component['dt_ms'] == .1)
decay = np.float32(math.exp(-.1/20.0))
gain = np.float32(.01)
_check(checks, role+'.frozen_apl_constants', component['decay_f32_bits'] == f'{int(decay.view(np.uint32)):08x}' and
component['gain_f32_bits'] == f'{int(gain.view(np.uint32)):08x}')
env = component['environment']
_check(checks, role+'.component_precision_environment', env['cuda_matmul_allow_tf32'] is False and
env['float32_matmul_precision'] == 'highest' and env['precision_configuration_changed_by_component'] is False and
'4090' in env['device_name'])
environment = _read_json(cpu_dir/'environment.json', used)
_check(checks, 'cpu.pinned_environment', environment['packages']['brian2'] == '2.5.1' and
environment['packages']['numpy'] == '1.22.3' and environment['packages']['sympy'] == '1.12' and
environment['Torch_imported_into_Brian'] is False and environment['author_precision'] == 'float64')
queue_audit = _read_json(cpu_dir/'queue-audit.json', used)
_check(checks, 'cpu.queue_observer_coverage', queue_audit['peek_calls'] == queue_audit['advance_calls'] == steps and
queue_audit['same_peek_object_returned'] is True and queue_audit['zero_weight_and_refractory_rejected_edges_retained'] is True)
_check(checks, 'cpu.sidecar_complete', cpu['summary']['APL_worker_exit_status'] == 0 and cpu['summary']['APL_worker_ticks'] == steps)
report.update(case=spec['name'], steps=steps, nodes=n, edges=edges, record_history=history,
total_spikes=len(gpu['state']['step']), active_neurons=int(np.count_nonzero(gpu['state']['counts'])),
requested=len(requested), accepted_requests=sum(row['accepted'] for row in gpu['requests']),
rejected_requests=sum(row['rejected'] for row in gpu['requests']),
arriving_edges=sum(row['count'] for row in gpu['queues']),
accepted_arriving_edges=sum(row['accepted_count'] for row in gpu['queues']),
apl_fast_edges_zeroed=mask_count, effective_weights_raw_sha256=expected_sha,
component_environment=gpu['component']['environment'],
limits=['APL Torch primitives are shared; original AST component validation is a separate required gate.',
'Small cases preserve and independently hash all pre/post states; full cases compare all-tick instrumented state hashes without saving dense whole-brain histories.',
'For full cases intermediate finite checks are performed by the instrumented backends; this file independently inspects final states and all APL traces.',
'This is exact agreement for the declared trajectory, not physiological validity or learning.'])
except Exception as error:
report['error'] = {'type': type(error).__name__, 'message': str(error)}
return _finish(report, checks, differences, used, out_json)
def compare_gpu_repeats(first, second, out_json=None):
"""Repeat equality only; the first run's independent oracle gate is separate."""
first, second = Path(first), Path(second)
if out_json is not None:
require(not Path(out_json).exists(), 'Refusing existing repeat report')
checks, differences, used = {}, {}, set()
report = {'kind': 'fresh-GPU-run exact repeat comparison', 'first': str(first), 'second': str(second),
'pass_all': False, 'tolerance': None, 'signed_zero_included': True, 'timing_fields_compared': False,
'scope': 'Scientific outputs, recording integrity and input hashes; independent case/graph audit belongs to compare()'}
try:
summary = _read_json(first/'summary.json', used)
n, edges, steps, name, history = (summary[key] for key in ('nodes', 'edges', 'steps', 'case', 'record_history'))
require(type(n) is int and type(edges) is int and type(steps) is int and n > 0 and edges > 0 and steps > 0 and
type(history) is bool and history == (n < 512), 'Invalid repeat dimensions')
left = _load_run(first, 'first_gpu', n, edges, steps, history, name, used, checks)
right = _load_run(second, 'second_gpu', n, edges, steps, history, name, used, checks)
_pair_outputs(left, right, checks, differences, n, steps, history)
stable = ('case', 'complete', 'pass_all', 'steps', 'completed_ticks', 'nodes', 'edges', 'precision',
'apl_precision', 'state_units', 'total_spikes', 'requested', 'accepted_requests', 'rejected_requests',
'arriving_edges', 'accepted_arriving_edges', 'counts_match_sparse_events', 'all_finite', 'record_history',
'apl_fast_edges_zeroed', 'kc_targets_present', 'effective_weights_raw_sha256', 'apl_schedule',
'apl_si_conversion', 'build', 'sealed_ae_backend_sha256', 'learning', 'input_sha256')
for key in stable:
_check(checks, 'summary.'+key, key in left['summary'] and key in right['summary'] and
left['summary'][key] == right['summary'][key])
if not checks['summary.'+key]:
differences['summary.'+key] = {'first': left['summary'].get(key), 'second': right['summary'].get(key)}
report.update(case=name, steps=steps, nodes=n, edges=edges, record_history=history,
total_spikes=len(left['state']['step']),
explicit_exclusions=['wall_seconds', 'diagnostic_simulation_seconds', 'build_or_cache_seconds',
'peak_allocated_vram_bytes', 'peak_reserved_vram_bytes'])
except Exception as error:
report['error'] = {'type': type(error).__name__, 'message': str(error)}
return _finish(report, checks, differences, used, out_json)
@@ -0,0 +1,22 @@
{
"phase": "4AG",
"name": "author-apl-lab-v1",
"human_authorization": "允许独立新模型分支测试动力学假设",
"gpu_uuid": "GPU-79f3a85d-adce-7833-7003-6488140ca596",
"neurons": 166700,
"edges": 25582938,
"raw_weight_sum": 124177617,
"precision": "float64",
"apl_precision": "float32",
"apl": {"tau_ms": 20.0, "gain": 0.01, "normalization": 1.0},
"hypothesis": "Author LIF plus unchanged legacy graded APL operator at end, after reset, unconditional KC g write. Mixed precision: h32 promoted to float64, then multiplied by float64 .001 SI, then subtracted. Not original author's APL model.",
"fixtures": ["zero", "pn_pulse", "kc_ref_boundary", "two_sources", "arrival_collision", "natural_request", "apl_only", "high_fanin"],
"fixture_repeats": 3,
"calibration": {"split": "calibration", "odor_count": 6, "modes": ["physiological", "matched_energy"], "seeds": [51101,51102,51103,51104,51105], "duration_ms": 100.0, "median_scope": "original frozen 12-odor panel", "full_oracle_probes": ["cal-physiological-00-s51101", "cal-matched_energy-00-s51101"], "repeat_first_seed_each_odor": true},
"gates": {"sparse_min_fraction": 0.03, "sparse_max_fraction": 0.09, "max_fraction_strict": 0.5, "min_fraction_strict": 0.0, "minimum_separable_odor_pairs": 3, "same_jaccard_gt_between": true, "between_euclidean_gt_within": true, "both_modes_required": true, "finite_required": true, "repeat_exact_required": true},
"training": false,
"heldout_dynamic_access": false,
"candidate_generation": false,
"output_budget_bytes": 16106127360,
"scope": "Semantic compatibility and fixed old CAL only. Shared-APL-component closed-loop Brian oracle plus independent arithmetic audit; never claim all-component independent CPU equivalence or learning success. No parameter/input/site/window selection from results."
}
@@ -0,0 +1,49 @@
import hashlib
import importlib.util
import json
from pathlib import Path
ROOT=Path('/data/digital-drosophila')
MODEL=Path(__file__).resolve().parent
EXP=ROOT/'experiments/phase4ag-author-apl'
AF_MODEL=ROOT/'models/male-cns-lif/author-fullgraph-lab-v1'
AF_EXP=ROOT/'experiments/phase4af-author-fullgraph'
AD_EXP=ROOT/'experiments/phase4ad-author-semantics'
CFG=json.loads((MODEL/'config.json').read_text(encoding='utf-8'))
def digest(path):
h=hashlib.sha256()
with Path(path).open('rb') as f:
for b in iter(lambda:f.read(8<<20),b''):h.update(b)
return h.hexdigest()
def save(path,value):
path=Path(path);path.parent.mkdir(parents=True,exist_ok=True)
with path.open('x',encoding='utf-8') as f:json.dump(value,f,indent=2,ensure_ascii=False,allow_nan=False);f.write('\n')
def sources():
return {p.name:digest(p) for p in sorted(MODEL.iterdir()) if p.is_file() and p.name not in ('manifest.json','checksums.sha256')}
def integrity():
spec=importlib.util.spec_from_file_location('frozen_af_context',AF_MODEL/'context.py')
mod=importlib.util.module_from_spec(spec);spec.loader.exec_module(mod)
result=mod.integrity()
import sys
sys.path.insert(0,str(ROOT/'models/male-cns-lif/terminal-scope-diagnostic-v1'))
from diagnostic import manifest_check
for p in (AF_MODEL,AF_EXP):result[str(p.relative_to(ROOT))]=manifest_check(p,digest)
assert all(r['pass'] for r in result.values())
return result
def check():
p=json.loads((EXP/'protocol/preregistered.json').read_text())
assert p['sources']==sources(),'Source changed after preregistration'
for row in p['inputs']:assert digest(ROOT/row['path'])==row['sha256'],row['path']
for row in json.loads((EXP/'protocol/prepared-hashes.json').read_text()):
assert digest(EXP/row['path'])==row['sha256'],row['path']
return p
def budget():
size=sum(p.stat().st_size for p in EXP.rglob('*') if p.is_file())
assert size<CFG['output_budget_bytes'],'New output resource budget exceeded'
return size
@@ -0,0 +1,90 @@
"""Seal a completed gate or preserved failure; never claim learning."""
import json
from context import ROOT,MODEL,EXP,CFG,check,save,digest,integrity,budget
def seal(root):
assert not (root/'manifest.json').exists() and not (root/'checksums.sha256').exists()
rows=[dict(path=str(p.relative_to(root)),bytes=p.stat().st_size,sha256=digest(p))
for p in sorted(root.rglob('*')) if p.is_file() and '__pycache__' not in p.parts]
save(root/'manifest.json',dict(root=str(root),files=rows))
with (root/'checksums.sha256').open('x') as f:
for row in rows:f.write(row['sha256']+' '+row['path']+'\n')
f.write(digest(root/'manifest.json')+' manifest.json\n')
def main():
from compare import compare,compare_gpu_repeats
check();budget();comparisons=[];repeats={};components={}
for p in sorted((EXP/'audit').glob('compare-*.json')):
name=p.stem[len('compare-'):]
actual=compare(EXP/'cases'/name,EXP/'gpu'/(name+'-r0'),EXP/'oracle'/name,None)
assert actual==json.loads(p.read_text()),'Changed raw closed-loop evidence: '+name
comparisons.append(dict(case=name,pass_all=actual['pass_all']))
for p in sorted((EXP/'audit').glob('repeat-*.json')):
name,repeat=p.stem[len('repeat-'):].rsplit('-r',1)
actual=compare_gpu_repeats(EXP/'gpu'/(name+'-r0'),EXP/'gpu'/f'{name}-r{repeat}',None)
assert actual==json.loads(p.read_text()),'Changed raw repeat evidence: '+name
repeats[f'{name}-r{repeat}']=actual['pass_all']
for p in (EXP/'component-audit').glob('*.json'):
result=json.loads(p.read_text())
components[p.stem]=result['pass_all']
for filename,sha in result.get('input_sha256',{}).items():
assert digest(EXP/'gpu'/(p.stem+'-r0')/filename)==sha
gates={}
for name in ('fixtures','probes','calibration'):
path=EXP/'audit'/(name+'-gate.json')
gates[name]=json.loads(path.read_text()) if path.exists() else None
calpath=EXP/'calibration/summary.json'
cal=json.loads(calpath.read_text()) if calpath.exists() else None
if cal is not None:
from calibration import summarize
assert summarize(out_json=None)==cal,'CAL raw evidence changed'
frozen=json.loads((EXP/'regression/frozen-five.json').read_text())
after=integrity();save(EXP/'regression/old-integrity-after.json',after)
stops=[dict(path=str(p.relative_to(EXP)),report=json.loads(p.read_text())) for p in sorted((EXP/'audit').glob('stopped-*.json'))]
expected_cases=CFG['fixtures']+CFG['calibration']['full_oracle_probes']
expected_repeats=[f'{name}-r{r}' for name in CFG['fixtures'] for r in range(1,CFG['fixture_repeats'])]
compared={x['case']:x['pass_all'] for x in comparisons}
missing=dict(comparisons=sorted(set(expected_cases)-set(compared)),
components=sorted(set(expected_cases)-set(components)),repeats=sorted(set(expected_repeats)-set(repeats)))
evidence_ok=(set(compared)==set(components)==set(expected_cases) and set(repeats)==set(expected_repeats) and
all(compared.values()) and all(components.values()) and all(repeats.values()))
numerical=evidence_ok and all(gates[x] is not None and gates[x]['pass_all'] for x in ('fixtures','probes'))
representation=bool(cal is not None and cal['pass_all'])
if numerical:status='PASS-FIXED-CAL-REPRESENTATION' if representation else 'FAIL-FIXED-CAL-REPRESENTATION' if cal is not None else 'INCOMPLETE-CAL-EXECUTION'
else:status='FAIL-NUMERICAL-OR-AUDIT-GATE' if any(not p for group in (compared,components,repeats) for p in group.values()) else 'INCOMPLETE-NUMERICAL-EXECUTION'
oldpass=bool(frozen['pass_all'] and all(r['pass'] for r in after.values()))
if not oldpass:status='FAIL-FROZEN-INTEGRITY-OR-REGRESSION'
measurements=[]
for p in sorted((EXP/'gpu').glob('*/summary.json')):
s=json.loads(p.read_text())
measurements.append({k:s[k] for k in ('case','total_spikes','accepted_requests','nodes','edges','diagnostic_simulation_seconds','peak_allocated_vram_bytes')})
result=dict(status=status,numerical_gate_pass=bool(numerical),fixed_CAL_representation_pass=representation,
gates=gates,closed_loop_comparisons=comparisons,component_results=components,repeat_results=repeats,
missing_numerical_evidence=missing,calibration=cal,stopped=stops,
old_frozen_integrity_and_five_reference_pass=oldpass,measurements=measurements,
unchanged_APL_parameters=CFG['apl'],author_LIF_precision='float64',legacy_APL_precision='float32',
explicit_hypothesis=CFG['hypothesis'],APL_nonKC_fast_edges_unreplaced=1212,
shared_APL_component_oracle_limitation=True,whole_brain_universal_equivalence_claim=False,
heldout_generalization_tested=False,formal_AB_tested=False,learning_achieved=False,candidate_generated=False,
payload_bytes_before_manifest=budget(),
next_gate='Independent seeds/novel-odor representation, then credit specificity; no learning promotion from CAL' if numerical and representation else
'Audit first failure in this explicitly declared hypothesis; no gain search, no heldout tuning, no conditioning')
save(EXP/'audit/final-status.json',result)
lines=['# Phase 4AG: author LIF + unchanged legacy graded APL','',f'Status: `{status}`.','',
f'Numerical closed-loop gate: {numerical}; original complete fixed six-CAL gate: {representation}.',
'The independent Brian LIF and candidate use independent state but share the APL arithmetic component. Original frozen APL AST replay and a float64 error audit are separately recorded.',
'Author LIF uses float64; APL retains float32, tau20ms/gain0.01/normalization1, full original matrices and order. No learning/parameter search.',
'The explicitly hypothesized unconditional end-APL write includes refractory KC. Original fast APL mask leaves1,212 non-KC edges unreplaced; this scope limitation was not silently fixed.',
f'Old checksums and five frozen reference trials: {oldpass}.',
f'Successfully compared cases: {comparisons}.',
'Detailed CAL, exact comparisons, component errors, event/request traces and execution exceptions are linked from audit/final-status.json.',
'Wall/VRAM here include per-tick CPU synchronization, IPC and hashes. They are diagnostic costs, not runtime-performance benchmarks.',
'No heldout dynamic outputs, formal A/B, learning, game, reward, decoder or new candidate.',
'Next gate: '+result['next_gate'],'']
with (EXP/'REPORT.md').open('x',encoding='utf-8') as f:f.write('\n'.join(lines))
check();seal(MODEL);seal(EXP);print(status,flush=True)
if __name__=='__main__':main()
@@ -0,0 +1,346 @@
"""Diagnostic author-float64 LIF plus frozen legacy-float32 APL overlay.
The sealed Phase 4AE CUDA operators are reused without modification. APL is
an explicitly mixed-precision engineering overlay, not an author-model claim.
All CUDA/CPU synchronization here is diagnostic; no performance claim is made.
"""
from functools import lru_cache
import csv
import hashlib
import json
import math
from pathlib import Path
import time
import traceback
import types
import numpy as np
import torch
from legacy_apl_worker import LegacyAPL, N_NEURONS, file_sha256, array_sha256
SOURCE_ROOT = Path(__file__).resolve().parent
AE_MODEL = SOURCE_ROOT.parent / "author-runtime-lab-v1"
AF_MODEL = SOURCE_ROOT.parent / "author-fullgraph-lab-v1"
COEFFICIENT_NAMES = ("gd", "c0", "cg", "cv", "threshold", "reset", "seed_volt")
REQUEST_FIELDS = ("tick", "neuron_idx", "attempted", "accepted", "rejected")
def require(condition, message):
if not condition:
raise ValueError(message)
def write_json(path, value):
with Path(path).open("x", encoding="utf-8") as output:
json.dump(value, output, indent=2, allow_nan=False)
output.write("\n")
def raw_hash(value, dtype):
return hashlib.sha256(np.ascontiguousarray(value, dtype=dtype).tobytes()).hexdigest()
def load_source(path, name):
module = types.ModuleType(name)
module.__file__ = str(path)
exec(compile(Path(path).read_bytes(), str(path), "exec"), module.__dict__)
return module
@lru_cache(maxsize=1)
def sealed_backend():
return load_source(AE_MODEL / "gpu_backend.py", "phase4ag_sealed_ae_backend")
@lru_cache(maxsize=1)
def queue_function():
return load_source(AF_MODEL / "oracle_full.py", "phase4ag_sealed_af_queue").queue_summary
@lru_cache(maxsize=4)
def load_graph(graph_directory):
root = Path(graph_directory)
require(root.is_absolute(), "graph_dir must be absolute")
graph = {}
for name, dtype in (("nodes", np.int32), ("edge_id", np.int64), ("src", np.int32),
("dst", np.int32), ("signed_raw", np.int64), ("ptr", np.int64),
("weights", np.float64)):
value = np.load(root / (name + ".npy"), mmap_mode="r", allow_pickle=False)
require(value.dtype == dtype and value.ndim == 1, "Graph dtype/rank mismatch: " + name)
graph[name] = value
nodes, edges = graph["nodes"], graph["edge_id"]
n, e = len(nodes), len(edges)
require(0 < n <= N_NEURONS and bool(np.all((nodes >= 0) & (nodes < N_NEURONS))) and
bool(np.all(np.diff(nodes) > 0)), "Global node IDs must be sorted unique")
require(n < 512 or (n == N_NEURONS and np.array_equal(nodes, np.arange(N_NEURONS, dtype=np.int32))),
"Only small fixtures or the intact frozen full graph are permitted")
require(n != N_NEURONS or e == 25582938, "Full graph edge count changed")
for name in ("src", "dst", "signed_raw", "weights"):
require(graph[name].shape == (e,), "Graph edge array length mismatch: " + name)
ptr = graph["ptr"]
require(ptr.shape == (n + 1,) and ptr[0] == 0 and ptr[-1] == e and
bool(np.all(np.diff(ptr) >= 0)), "Invalid graph CSR")
require(np.array_equal(graph["src"], np.repeat(np.arange(n, dtype=np.int32), np.diff(ptr))),
"Source order does not match CSR")
# Global edge IDs need not equal local row indices in a fixture.
for start in range(0, e, 1 << 20):
stop = min(start + (1 << 20), e)
require(bool(np.all((graph["dst"][start:stop] >= 0) & (graph["dst"][start:stop] < n))),
"Local destination out of range")
require(bool(np.isfinite(graph["weights"][start:stop]).all()), "Nonfinite base SI weights")
require(np.array_equal(np.sign(graph["weights"][start:stop]), np.sign(graph["signed_raw"][start:stop])),
"Base weight sign/zero pattern differs from frozen raw contacts")
lo = max(0, start - 1)
require(bool(np.all(edges[start:stop] >= 0)) and bool(np.all(np.diff(edges[lo:stop]) > 0)),
"Global edge IDs must retain canonical increasing source/edge order")
return graph
def load_inputs(case_dir):
spec = json.loads((case_dir / "spec.json").read_text(encoding="utf-8"))
for name in ("name", "steps", "dt_ms", "duration_ms", "model", "graph_dir", "apl",
"apl_bundle_dir", "coefficients_path", "record_history"):
require(name in spec, "Missing case field: " + name)
steps = spec["steps"]
require(type(steps) is int and 0 < steps <= 1000 and float(spec["dt_ms"]) == .1 and
float(spec["duration_ms"]) == steps * .1, "Unexpected steps/dt/duration")
require(type(spec["record_history"]) is bool, "record_history must be Boolean")
require(spec["apl"] == {"tau_ms": 20, "gain": .01, "normalization": 1}, "Frozen APL parameters changed")
for name in ("graph_dir", "apl_bundle_dir", "coefficients_path"):
require(Path(spec[name]).is_absolute(), "Input path must be absolute: " + name)
model = spec["model"]
for name in ("resting_potential_mv", "threshold_mv", "reset_potential_mv", "synaptic_delay_ms",
"refractory_ms", "w_syn_mv_per_anatomical_synapse"):
require(name in model and math.isfinite(float(model[name])), "Invalid model field: " + name)
require(float(model["synaptic_delay_ms"]) == 1.8 and float(model["refractory_ms"]) == 2.2 and
float(model["w_syn_mv_per_anatomical_synapse"]) == .275, "Frozen delay/ref/W_syn changed")
coeff = json.loads(Path(spec["coefficients_path"]).read_text(encoding="utf-8"))
for name in COEFFICIENT_NAMES:
require(name in coeff and math.isfinite(float(coeff[name])), "Invalid author coefficient: " + name)
require(coeff["threshold"] == float(model["threshold_mv"]) * .001 and
coeff["reset"] == float(model["reset_potential_mv"]) * .001, "Coefficient threshold/reset mismatch")
graph = load_graph(str(Path(spec["graph_dir"]).resolve()))
n = len(graph["nodes"])
require(spec["record_history"] == (n < 512), "Fixtures need dense history; full graph must not duplicate dense histories")
with np.load(case_dir / "requests.npz", allow_pickle=False) as source:
require(set(source.files) == {"tick", "neuron_idx"}, "Request sparse schema changed")
ticks, requested = source["tick"].copy(), source["neuron_idx"].copy()
require(ticks.dtype == np.int32 and requested.dtype == np.int32 and ticks.ndim == 1 and
ticks.shape == requested.shape, "Invalid sparse request dtype/shape")
require(bool(np.all((ticks >= 0) & (ticks < steps))), "Request tick outside trial")
if len(ticks) > 1:
require(bool(np.all((ticks[1:] > ticks[:-1]) |
((ticks[1:] == ticks[:-1]) & (requested[1:] > requested[:-1])))),
"Requests must be sorted unique by tick/global neuron")
local = np.searchsorted(graph["nodes"], requested)
require(bool(np.all(local < n)) and np.array_equal(graph["nodes"][local], requested),
"Requested neuron absent from graph")
initial = {"initial_v_mv": np.full(n, float(model["resting_potential_mv"]), dtype=np.float64),
"initial_g_mv": np.zeros(n, dtype=np.float64)}
initial_path = case_dir / "arrays.npz"
if initial_path.exists():
with np.load(initial_path, allow_pickle=False) as source:
require(set(source.files).issubset(initial), "Unexpected initial-state array")
for name in source.files:
value = source[name]
require(value.dtype == np.float64 and value.shape == (n,) and bool(np.isfinite(value).all()),
"Invalid initial state: " + name)
initial[name] = value.copy()
return spec, graph, coeff, ticks, requested, local, initial
def new_array(path, dtype, shape):
require(not Path(path).exists(), "Refusing existing output: " + str(path))
return np.lib.format.open_memmap(path, mode="w+", dtype=dtype, shape=shape)
def run_gpu(case_dir, out_dir, build_root):
"""Run fresh candidate state; never consume oracle/candidate APL traces.
pass_all denotes internal recording/finite integrity only. Independent
comparison and the original complete representation gate are separate.
"""
case_dir, out_dir = Path(case_dir), Path(out_dir)
require(not out_dir.exists(), "Refusing existing output directory: " + str(out_dir))
out_dir.mkdir(parents=True, exist_ok=False)
start, tick, completed = time.perf_counter(), -1, 0
maps = {}
try:
spec, graph, coeff, request_ticks, request_nodes, request_local, initial = load_inputs(case_dir)
require(torch.cuda.is_available() and torch.cuda.device_count() == 1 and
"4090" in torch.cuda.get_device_name(), "Only the declared single visible RTX4090 is permitted")
ext, build = sealed_backend().build_extension(build_root)
build_done = time.perf_counter()
apl = LegacyAPL(spec["apl_bundle_dir"], spec["dt_ms"])
write_json(out_dir / "apl-component.json", apl.metadata)
device = apl.device
torch.cuda.reset_peak_memory_stats(device)
n, e, steps = len(graph["nodes"]), len(graph["edge_id"]), spec["steps"]
def upload(value, dtype):
return torch.from_numpy(np.array(value, copy=True, order="C")).to(device=device, dtype=dtype).contiguous()
indptr, dst = upload(graph["ptr"], torch.int64), upload(graph["dst"], torch.int32)
global_nodes_gpu = upload(graph["nodes"], torch.int64)
base_weights = upload(graph["weights"], torch.float64)
weights = base_weights.clone()
del base_weights
local_apl = np.flatnonzero(np.isin(graph["nodes"], apl.apl_globals)).astype(np.int64)
apl_out_mask = np.isin(graph["src"], local_apl)
if bool(np.any(apl_out_mask)):
weights[upload(apl_out_mask, torch.bool)] = 0.0
effective_hash = hashlib.sha256()
for offset in range(0, e, 1 << 20):
effective_hash.update(weights[offset:offset + (1 << 20)].cpu().numpy().astype("<f8", copy=False).tobytes())
common_kc, local_kc, full_kc = np.intersect1d(graph["nodes"], apl.kc_globals, assume_unique=True, return_indices=True)
kc_local_gpu, kc_full_gpu = upload(local_kc, torch.int64), upload(full_kc, torch.int64)
v = upload(initial["initial_v_mv"] * .001, torch.float64)
g = upload(initial["initial_g_mv"] * .001, torch.float64)
ref = torch.zeros(n, device=device, dtype=torch.int32)
counts = torch.zeros(n, device=device, dtype=torch.int32)
requests = torch.zeros(n, device=device, dtype=torch.uint8)
ring = torch.zeros((19, n), device=device, dtype=torch.uint8)
for name, width in (("drive", 2), ("state", 2), ("inhibition", 4064)):
maps["apl_" + name] = new_array(out_dir / ("apl-" + name + ".float32.npy"), np.float32, (steps, width))
if spec["record_history"]:
for name, dtype in (("v", np.float64), ("g", np.float64), ("ref", np.int32)):
maps[name] = new_array(out_dir / (name + "-history." + np.dtype(dtype).name + ".npy"), dtype, (steps, n))
maps["pre_" + name] = new_array(out_dir / ("preAPL-" + name + "." + np.dtype(dtype).name + ".npy"), dtype, (steps, n))
event_steps, event_nodes = [], []
accepted_requests_total, due_total, accepted_due_total = 0, 0, 0
queue_summary = queue_function()
simulation_start = time.perf_counter()
with (out_dir / "queue.jsonl").open("x", encoding="utf-8", buffering=1) as queue_output, \
(out_dir / "tick-state-hashes.jsonl").open("x", encoding="utf-8", buffering=1) as hash_output, \
(out_dir / "requests.csv").open("x", encoding="utf-8", newline="", buffering=1) as request_output:
writer = csv.DictWriter(request_output, fieldnames=REQUEST_FIELDS)
writer.writeheader()
for tick in range(steps):
requests.zero_()
begin, end = np.searchsorted(request_ticks, (tick, tick + 1))
if end > begin:
requested_local_gpu = upload(request_local[begin:end], torch.int64)
requests[requested_local_gpu] = 1
accepted = (ref[requested_local_gpu] <= 1).to(torch.uint8).cpu().numpy()
accepted_requests_total += int(accepted.sum())
writer.writerows({"tick": tick, "neuron_idx": int(node), "attempted": 1,
"accepted": int(ok), "rejected": 1 - int(ok)}
for node, ok in zip(request_nodes[begin:end], accepted))
spikes = ring[tick % 19]
ext.state_step(v, g, ref, requests, spikes, counts,
*[float(coeff[name]) for name in COEFFICIENT_NAMES], 22)
expanded_global = np.empty(0, dtype=np.int64)
accepted_cpu = np.empty(0, dtype=np.uint8)
if tick >= 18:
due = ring[(tick - 18) % 19]
sources = torch.nonzero(due, as_tuple=False).flatten().contiguous()
if sources.numel():
degrees = indptr[sources + 1] - indptr[sources]
offsets = (torch.cumsum(degrees, dim=0) - degrees).contiguous()
edge_count = int(degrees.sum().item())
expanded = torch.empty(edge_count, device=device, dtype=torch.int64)
ext.fill_edges(indptr, sources, offsets, expanded)
if edge_count:
destination = dst[expanded]
# Actual active fanout order, BEFORE stable target grouping.
expanded_global = graph["edge_id"][expanded.cpu().numpy()].copy()
accepted_cpu = (ref[destination.long()] == 0).to(torch.uint8).cpu().numpy().copy()
order = torch.argsort(destination, stable=True)
ordered_edges, ordered_targets = expanded[order].contiguous(), destination[order]
boundary = torch.ones(edge_count, device=device, dtype=torch.bool)
boundary[1:] = ordered_targets[1:] != ordered_targets[:-1]
starts = torch.nonzero(boundary, as_tuple=False).flatten().contiguous()
targets = ordered_targets[starts].contiguous()
ext.apply_arrivals(ordered_edges, starts, targets, weights, g, ref)
queue = queue_summary(tick, expanded_global, accepted_cpu)
queue_output.write(json.dumps(queue, allow_nan=False) + "\n")
due_total += queue["count"]
accepted_due_total += queue["accepted_count"]
if spec["record_history"]:
for name, value in (("v", v), ("g", g), ("ref", ref)):
maps["pre_" + name][tick] = value.cpu().numpy()
if n == N_NEURONS:
full_spikes = spikes
else:
apl.spikes.zero_()
apl.spikes[global_nodes_gpu] = spikes
full_spikes = apl.spikes
drive, apl_state, h = apl.advance(full_spikes)
# Mixed precision contract: widen f32 h EXACTLY, THEN multiply
# in f64, THEN subtract in f64. Do not guard refractory KCs.
delta_si = h[kc_full_gpu].to(torch.float64) * 0.001
g[kc_local_gpu] = g[kc_local_gpu] - delta_si
apl_cpu = {"drive": drive.cpu().numpy().copy(), "state": apl_state.cpu().numpy().copy(),
"inhibition": h.cpu().numpy().copy()}
for name, value in apl_cpu.items():
maps["apl_" + name][tick] = value
actual = {"v": v.cpu().numpy().copy(), "g": g.cpu().numpy().copy(),
"ref": ref.cpu().numpy().copy()}
finite = all(bool(np.isfinite(value).all()) for value in list(actual.values()) + list(apl_cpu.values()))
row = {"tick": tick, **{name + "_sha256": raw_hash(value, "<i4" if name == "ref" else "<f8")
for name, value in actual.items()}}
hash_output.write(json.dumps(row, allow_nan=False) + "\n")
if spec["record_history"]:
for name, value in actual.items():
maps[name][tick] = value
fired_local = torch.nonzero(spikes, as_tuple=False).flatten().cpu().numpy()
if len(fired_local):
event_steps.append(np.full(len(fired_local), tick, dtype=np.int32))
event_nodes.append(graph["nodes"][fired_local].copy())
completed += 1
if not finite:
with (out_dir / "first-failure-state.npz").open("xb") as target:
np.savez_compressed(target, tick=np.array(tick, dtype=np.int32), **actual,
**{"apl_" + name: value for name, value in apl_cpu.items()})
require(False, "Nonfinite state; first failure saved")
torch.cuda.synchronize(device)
def joined(values):
return np.concatenate(values).astype(np.int32, copy=False) if values else np.empty(0, dtype=np.int32)
state = {"step": joined(event_steps), "neuron_idx": joined(event_nodes), "counts": counts.cpu().numpy(),
"v": v.cpu().numpy(), "g": g.cpu().numpy(), "ref": ref.cpu().numpy()}
with (out_dir / "state.npz").open("xb") as target:
np.savez_compressed(target, **state)
event_locals = np.searchsorted(graph["nodes"], state["neuron_idx"])
counts_exact = np.array_equal(np.bincount(event_locals, minlength=n), state["counts"])
require(counts_exact and completed == steps, "Sparse events/counts/completed ticks mismatch")
for value in maps.values():
value.flush()
summary = {"case": spec["name"], "complete": True, "pass_all": True,
"pass_all_scope": "internal finite/recording/event-count integrity only; independent equivalence not claimed",
"steps": steps, "completed_ticks": completed, "nodes": n, "edges": e, "precision": "float64",
"apl_precision": "float32", "state_units": "SI volts", "total_spikes": len(state["step"]),
"requested": len(request_nodes), "accepted_requests": accepted_requests_total,
"rejected_requests": len(request_nodes) - accepted_requests_total,
"arriving_edges": due_total, "accepted_arriving_edges": accepted_due_total,
"counts_match_sparse_events": bool(counts_exact), "all_finite": True,
"record_history": spec["record_history"], "apl_fast_edges_zeroed": int(apl_out_mask.sum()),
"kc_targets_present": len(common_kc), "effective_weights_raw_sha256": effective_hash.hexdigest(),
"apl_component": apl.metadata, "apl_schedule": "end, after threshold/reset and guarded arrivals, unconditional all KC",
"apl_si_conversion": "h32 -> float64 -> multiply float64 0.001 -> separate float64 subtraction",
"build": build, "sealed_ae_backend_sha256": file_sha256(AE_MODEL / "gpu_backend.py"),
"shared_apl_component_oracle_limitation": True, "oracle_validation_claim": False,
"learning": False, "performance_runtime_claim": False, "cpu_sync_each_tick": True,
"build_or_cache_seconds": build_done - start,
"diagnostic_simulation_seconds": time.perf_counter() - simulation_start,
"wall_seconds": time.perf_counter() - start,
"peak_allocated_vram_bytes": int(torch.cuda.max_memory_allocated(device)),
"peak_reserved_vram_bytes": int(torch.cuda.max_memory_reserved(device)),
"input_sha256": {"spec.json": file_sha256(case_dir / "spec.json"),
"requests.npz": file_sha256(case_dir / "requests.npz"),
"base_weights.npy": file_sha256(Path(spec["graph_dir"]) / "weights.npy"),
"coefficients.json": file_sha256(spec["coefficients_path"])}}
if (case_dir / "arrays.npz").exists():
summary["input_sha256"]["arrays.npz"] = file_sha256(case_dir / "arrays.npz")
write_json(out_dir / "summary.json", summary)
return summary
except Exception as error:
for value in maps.values():
value.flush()
write_json(out_dir / "error.json", {"complete": False, "pass_all": False,
"tick_in_progress": tick, "completed_ticks": completed,
"type": type(error).__name__, "message": str(error), "traceback": traceback.format_exc()})
raise
@@ -0,0 +1,175 @@
"""Frozen eager Torch float32 APL component and binary oracle sidecar.
This is the Phase 4P operator sequence, not an author-neuron implementation.
No precision/determinism flags are changed here. The full matrix dimensions
are retained even when the caller simulates a small neuronal fixture.
"""
import argparse
import hashlib
import json
import math
import os
from pathlib import Path
import struct
import sys
import traceback
import numpy as np
import torch
PROTOCOL = "phase4ag-apl-v1"
N_NEURONS, N_APL, N_KC = 166700, 2, 4064
BUNDLE_FILES = ("input_matrix.npy", "output_matrix.npy", "kc_globals.npy", "apl_globals.npy")
FRAME = struct.Struct("<qQ")
PAYLOAD_BYTES = (N_APL + N_APL + N_KC) * 4
def require(condition, message):
if not condition:
raise ValueError(message)
def file_sha256(path):
digest = hashlib.sha256()
with Path(path).open("rb") as stream:
for block in iter(lambda: stream.read(8 << 20), b""):
digest.update(block)
return digest.hexdigest()
def array_sha256(value):
return hashlib.sha256(np.ascontiguousarray(value).tobytes()).hexdigest()
def environment_metadata():
device = torch.cuda.current_device()
return {"torch": str(torch.__version__), "numpy": str(np.__version__),
"cuda": torch.version.cuda, "cudnn": torch.backends.cudnn.version(),
"device_name": torch.cuda.get_device_name(device), "device_index": device,
"device_capability": list(torch.cuda.get_device_capability(device)),
"deterministic_algorithms": torch.are_deterministic_algorithms_enabled(),
"cudnn_deterministic": torch.backends.cudnn.deterministic,
"cudnn_benchmark": torch.backends.cudnn.benchmark,
"cuda_matmul_allow_tf32": torch.backends.cuda.matmul.allow_tf32,
"cudnn_allow_tf32": torch.backends.cudnn.allow_tf32,
"float32_matmul_precision": torch.get_float32_matmul_precision(),
"CUBLAS_WORKSPACE_CONFIG": os.environ.get("CUBLAS_WORKSPACE_CONFIG"),
"precision_configuration_changed_by_component": False}
class LegacyAPL:
"""Independent zero-initialized APL state with original full-width matrices."""
def __init__(self, bundle_dir, dt_ms):
require(float(dt_ms) == 0.1, "Only frozen dt_ms=0.1 is allowed")
require(torch.cuda.is_available(), "CUDA is required for the legacy Torch component")
self.bundle_dir = Path(bundle_dir)
expected = {"input_matrix.npy": (np.float32, (N_APL, N_NEURONS)),
"output_matrix.npy": (np.float32, (N_APL, N_KC)),
"kc_globals.npy": (np.int32, (N_KC,)),
"apl_globals.npy": (np.int32, (N_APL,))}
arrays = {}
for name, (dtype, shape) in expected.items():
value = np.load(self.bundle_dir / name, allow_pickle=False)
require(value.dtype == dtype and value.shape == shape and value.flags.c_contiguous,
"APL bundle dtype/shape/layout mismatch: " + name)
require(bool(np.isfinite(value).all()), "Nonfinite APL bundle: " + name)
arrays[name] = value
for name in ("kc_globals.npy", "apl_globals.npy"):
ids = arrays[name]
require(bool(np.all((ids >= 0) & (ids < N_NEURONS))) and
bool(np.all(np.diff(ids) > 0)), "APL/KC globals must be sorted unique: " + name)
require(not np.intersect1d(arrays["kc_globals.npy"], arrays["apl_globals.npy"]).size,
"APL and KC identities overlap")
require(bool(np.all(arrays["input_matrix.npy"] >= 0)) and
bool(np.all(arrays["output_matrix.npy"] >= 0)), "APL raw-contact matrices must be nonnegative")
self.device = torch.device("cuda", torch.cuda.current_device())
self.input_gpu = torch.from_numpy(arrays["input_matrix.npy"].copy()).to(self.device)
self.output_gpu = torch.from_numpy(arrays["output_matrix.npy"].copy()).to(self.device)
self.kc_globals = arrays["kc_globals.npy"].copy()
self.apl_globals = arrays["apl_globals.npy"].copy()
self.state = torch.zeros(N_APL, dtype=torch.float32, device=self.device)
self.spikes = torch.zeros(N_NEURONS, dtype=torch.uint8, device=self.device)
self.decay = np.float32(math.exp(-float(dt_ms) / 20.0))
self.gain = np.float32(0.01)
self.metadata = {"ok": True, "protocol": PROTOCOL, "n_neurons": N_NEURONS,
"n_apl": N_APL, "n_kc": N_KC, "dt_ms": float(dt_ms),
"files_sha256": {name: file_sha256(self.bundle_dir / name) for name in BUNDLE_FILES},
"array_sha256": {name: array_sha256(value) for name, value in arrays.items()},
"decay_f32_bits": f"{int(self.decay.view(np.uint32)):08x}",
"gain_f32_bits": f"{int(self.gain.view(np.uint32)):08x}",
"environment": environment_metadata(),
"operator_sequence": "state.mul_(decay32); drive=mv(I32,spikes32); state.add_(drive); h=matmul(state,O32)*gain32",
"h_units": "legacy mV", "initial_state": "float32 zeros"}
@torch.no_grad()
def advance(self, spikes_u8):
require(spikes_u8.device == self.device and spikes_u8.dtype == torch.uint8 and
tuple(spikes_u8.shape) == (N_NEURONS,) and spikes_u8.is_contiguous(),
"APL expects full-width contiguous CUDA uint8 spikes")
# Preserve separate eager operations, including Python evaluation order
# in the frozen state.mul_(...).add_(torch.mv(...)) expression.
self.state.mul_(float(self.decay))
drive = torch.mv(self.input_gpu, spikes_u8.to(torch.float32))
self.state.add_(drive)
h = torch.matmul(self.state, self.output_gpu) * self.gain
return drive, self.state, h
def advance_global_fired(self, fired):
require(fired.dtype == np.int32 and fired.ndim == 1, "Global spikes must be int32 vector")
require(bool(np.all((fired >= 0) & (fired < N_NEURONS))) and
bool(np.all(np.diff(fired) > 0)), "Global spikes must be sorted unique and in range")
self.spikes.zero_()
if fired.size:
indices = torch.from_numpy(fired.copy()).to(device=self.device, dtype=torch.int64)
self.spikes[indices] = 1
return self.advance(self.spikes)
def read_exact(stream, count, boundary_eof=False):
result = bytearray()
while len(result) < count:
block = stream.read(count - len(result))
if not block:
if boundary_eof and not result:
return None
raise EOFError("Truncated APL request frame")
result.extend(block)
return bytes(result)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--bundle-dir", required=True)
parser.add_argument("--dt-ms", required=True, type=float)
args = parser.parse_args()
# stdout is exclusively the handshake line and binary response frames.
output, source = sys.stdout.buffer, sys.stdin.buffer
component = LegacyAPL(args.bundle_dir, args.dt_ms)
output.write((json.dumps(component.metadata, allow_nan=False) + "\n").encode("utf-8"))
output.flush()
expected_tick = 0
while True:
header = read_exact(source, FRAME.size, boundary_eof=True)
if header is None:
return
tick, count = FRAME.unpack(header)
require(tick == expected_tick and count <= N_NEURONS, "Invalid APL request tick/count")
fired = np.frombuffer(read_exact(source, count * 4), dtype="<i4").copy()
drive, state, h = component.advance_global_fired(fired)
arrays = [value.detach().cpu().numpy().astype("<f4", copy=False) for value in (drive, state, h)]
require(all(bool(np.isfinite(value).all()) for value in arrays), "Nonfinite APL output")
output.write(FRAME.pack(tick, PAYLOAD_BYTES))
for value in arrays:
output.write(value.tobytes())
output.flush()
expected_tick += 1
if __name__ == "__main__":
try:
main()
except Exception:
traceback.print_exc(file=sys.stderr)
sys.exit(1)
@@ -0,0 +1,85 @@
{
"root": "/data/digital-drosophila/models/male-cns-lif/author-apl-lab-v1",
"files": [
{
"path": "PROTOCOL.md",
"bytes": 5033,
"sha256": "c14c2d3c35e2b404c516befa66370723fba075516540214ae46e4104ff87e813"
},
{
"path": "calibration.py",
"bytes": 25414,
"sha256": "edb9cb2d890471fd07afd88c959ef3540b0cd40af490fac3f26396b5e7f5bf9c"
},
{
"path": "compare.py",
"bytes": 33632,
"sha256": "6e1616b086f667fa4e4b5087f500f8080281977ca9922e7b055acfddd2003bd5"
},
{
"path": "config.json",
"bytes": 1845,
"sha256": "2aa6b4d777ff698018e1a6eaf571215208b8c874a4c848a6d632e2bd778c90e3"
},
{
"path": "context.py",
"bytes": 2038,
"sha256": "b8b1231d958a3ec935ec1d5a36e08cbd9bcd1127f4d4bb243a9051884a0e7a16"
},
{
"path": "finalize.py",
"bytes": 6747,
"sha256": "b6e3c67e668a971b544df32d76435ab5e537061b9fc2e8d9dedb5d2a726f5782"
},
{
"path": "gpu_apl.py",
"bytes": 21206,
"sha256": "69f5d893f47dafff4ef7c3186c3df0b9014666b32c8f4e943b57016bec92b18a"
},
{
"path": "legacy_apl_worker.py",
"bytes": 8158,
"sha256": "21ceec65fe42581dc55872010e0025d660e80358905f1cf4df1dadf341a3b291"
},
{
"path": "oracle_apl.py",
"bytes": 46017,
"sha256": "9b7f3e0b59f2117b94b41a6f542f37e6f7950138d324c905e8e0ac6cb7d17151"
},
{
"path": "prepare.py",
"bytes": 13633,
"sha256": "197ccc6aae70566c4db4d4de17fa032e853b9bd9a04262905d6c71e12a930b6f"
},
{
"path": "run_case.py",
"bytes": 2116,
"sha256": "afbe6d5a37c29bda66d38c470093584130d1852e67881c681662aec3c76b33c7"
},
{
"path": "run_suite.py",
"bytes": 3700,
"sha256": "84c681030b0032119b5392d0c3f3c136a9c6b0d133eb548c40791a10bbbb8b63"
},
{
"path": "test_calibration.py",
"bytes": 8127,
"sha256": "bab3136eecbc5bb09a985d715844ee845cb72b07930ce376bfb39be33bd1845a"
},
{
"path": "test_protocol.py",
"bytes": 11764,
"sha256": "1a233f47943e01bbd845ac1dacdb1eec3f88c270c65a5f75bce1cf679b5de097"
},
{
"path": "validate_components.py",
"bytes": 24824,
"sha256": "5cfc9a4505da6b8fb4e7d2617cdaedaa8475ed46a11ec9bdf0d4d25b1d22c2d3"
},
{
"path": "verify_frozen.py",
"bytes": 2160,
"sha256": "0d0e72b2f1348f6648124c8c34f75094f76fc5e1a281fbcca130a5fad2f35293"
}
]
}
@@ -0,0 +1,740 @@
"""Phase 4AG shared-APL-component closed-loop Brian oracle.
Brian has no Torch dependency. A separate, pinned science-Python process
executes the unchanged legacy float32 APL operations from Brian's own spikes.
This is independent LIF/scheduling validation with a shared APL numerical
component, NOT an all-components-independent CPU oracle.
"""
from __future__ import annotations
import csv
import hashlib
import importlib.metadata
import json
import math
import os
import platform
import queue
import struct
import subprocess
import sys
import threading
import time
import types
from contextlib import ExitStack
from pathlib import Path
import numpy as np
BLOCK_BYTES = 8 << 20
PROTOCOL = "phase4ag-apl-v1"
AUTHOR_PATH = Path("/data/digital-drosophila/experiments/phase4ad-author-semantics/external-resources/model.py")
AUTHOR_SHA256 = "fc45837d7122c6ce2a7f3f2f23c515992e4b232aadb919efabb72337fac88e4e"
AE_PATH = Path("/data/digital-drosophila/models/male-cns-lif/author-runtime-lab-v1/oracle_stress.py")
AE_SHA256 = "32eb1c42383068ce52701d2139a376ce155ad7072cde019949f8ca2d55492409"
AF_PATH = Path("/data/digital-drosophila/models/male-cns-lif/author-fullgraph-lab-v1/oracle_full.py")
AF_SHA256 = "d72003d98f0f1624b12126eff50bd361c43d888f4a64d90ba9247a58976f1961"
EVENT_DTYPE = np.dtype([("step", "<i4"), ("neuron_idx", "<i4")])
BUNDLE_FILES = ("input_matrix.npy", "output_matrix.npy", "kc_globals.npy", "apl_globals.npy")
_PROCESS_USED = False
def _check(condition, message):
if not condition:
raise ValueError(message)
def _save(path, value):
with Path(path).open("x", encoding="utf-8") as handle:
json.dump(value, handle, indent=2, sort_keys=True, allow_nan=False)
handle.write("\n")
def _digest(path):
result = hashlib.sha256()
with Path(path).open("rb") as handle:
for block in iter(lambda: handle.read(BLOCK_BYTES), b""):
result.update(block)
return result.hexdigest()
def _array_hash(array, dtype):
return hashlib.sha256(np.ascontiguousarray(array, dtype=dtype).tobytes()).hexdigest()
def _load_checked(path, expected, name):
data = Path(path).read_bytes()
_check(hashlib.sha256(data).hexdigest() == expected, f"Pinned source hash mismatch: {path}")
module = types.ModuleType(name)
module.__file__ = str(path)
exec(compile(data, str(path), "exec"), module.__dict__)
return module
def _new_memmap(path, dtype, shape):
_check(not Path(path).exists(), f"Refusing to overwrite output: {path}")
return np.lib.format.open_memmap(path, mode="w+", dtype=dtype, shape=shape)
def _budget(root, limit, reserve=0):
total = 0
for directory, _, filenames in os.walk(root, followlinks=False):
for filename in filenames:
total += (Path(directory) / filename).stat(follow_symlinks=False).st_size
_check(total + int(reserve) <= limit,
f"Output budget exceeded: {total}+{reserve}>{limit}; inputs and duration were not adjusted")
return total
class _PipeReader:
"""One bounded reader thread, with timeout/EOF checks for every frame."""
def __init__(self, pipe, timeout):
self.pipe, self.timeout = pipe, float(timeout)
self.chunks = queue.Queue(maxsize=8)
self.buffer = bytearray()
self.thread = threading.Thread(target=self._pump, daemon=True)
self.thread.start()
def _pump(self):
try:
while True:
chunk = os.read(self.pipe.fileno(), 65536)
self.chunks.put(chunk)
if not chunk:
return
except BaseException as error:
self.chunks.put(error)
def _fill(self, deadline):
remaining = deadline - time.monotonic()
if remaining <= 0:
raise TimeoutError("APL sidecar response timed out")
try:
chunk = self.chunks.get(timeout=remaining)
except queue.Empty as error:
raise TimeoutError("APL sidecar response timed out") from error
if isinstance(chunk, BaseException):
raise RuntimeError("APL sidecar stdout reader failed") from chunk
if not chunk:
raise EOFError("APL sidecar ended before a complete response")
self.buffer.extend(chunk)
def read(self, size):
deadline = time.monotonic() + self.timeout
while len(self.buffer) < size:
self._fill(deadline)
result = bytes(self.buffer[:size])
del self.buffer[:size]
return result
def line(self):
deadline = time.monotonic() + self.timeout
while b"\n" not in self.buffer:
_check(len(self.buffer) < 1 << 20, "APL sidecar handshake exceeds 1 MiB")
self._fill(deadline)
end = self.buffer.index(b"\n") + 1
result = bytes(self.buffer[:end])
del self.buffer[:end]
return result
class _APLWorker:
def __init__(self, python, script, bundle_dir, stderr, timeout=180):
self.command = [str(python), "-B", str(script), "--bundle-dir", str(bundle_dir), "--dt-ms", "0.1"]
self.process = subprocess.Popen(self.command, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=stderr, bufsize=0, shell=False)
self.reader = _PipeReader(self.process.stdout, timeout)
self.tick = 0
try:
self.hello = json.loads(self.reader.line().decode("utf-8"))
_check(self.hello.get("ok") is True, "APL sidecar did not acknowledge initialization")
_check(self.hello.get("protocol") == PROTOCOL, "Unexpected APL sidecar protocol")
for key, value in (("n_neurons", 166700), ("n_apl", 2), ("n_kc", 4064)):
_check(self.hello.get(key) == value, f"APL sidecar changed {key}")
_check(self.hello.get("dt_ms") == .1, "APL sidecar changed dt")
expected_decay = f"{int(np.float32(math.exp(-.1 / 20.)).view(np.uint32)):08x}"
expected_gain = f"{int(np.float32(.01).view(np.uint32)):08x}"
_check(self.hello.get("decay_f32_bits") == expected_decay and self.hello.get("gain_f32_bits") == expected_gain,
"APL sidecar decay/gain differs from the frozen float32 scalars")
_check(self.hello.get("files_sha256") == {name: _digest(bundle_dir / name) for name in BUNDLE_FILES},
"APL sidecar bundle hashes differ from the independently read bundle")
except BaseException:
self.abort()
raise
def step(self, tick, global_spikes):
_check(tick == self.tick, "APL sidecar request ticks must be consecutive")
nodes = np.asarray(global_spikes)
_check(nodes.ndim == 1 and nodes.dtype == np.dtype("int32"), "APL input spikes must be int32 globals")
_check(not len(nodes) or (nodes[0] >= 0 and nodes[-1] < 166700 and np.all(np.diff(nodes) > 0)),
"APL input spikes must be sorted, unique, and in the frozen global range")
packet = struct.pack("<qQ", int(tick), len(nodes)) + np.ascontiguousarray(nodes, dtype="<i4").tobytes()
view = memoryview(packet)
while view:
written = self.process.stdin.write(view)
if not written:
raise BrokenPipeError("APL sidecar stdin failed")
view = view[written:]
self.process.stdin.flush()
response_tick, byte_count = struct.unpack("<qQ", self.reader.read(16))
_check(response_tick == tick and byte_count == (2 + 2 + 4064) * 4,
"APL sidecar frame tick/length mismatch")
values = np.frombuffer(self.reader.read(byte_count), dtype="<f4")
_check(np.isfinite(values).all() and np.all(values >= 0), "APL sidecar returned invalid nonnegative f32 states")
self.tick += 1
return values[:2], values[2:4], values[4:]
def finish(self, steps):
_check(self.tick == steps, "APL sidecar did not process every tick")
self.process.stdin.close()
status = self.process.wait(timeout=30)
_check(status == 0, f"APL sidecar exited unsuccessfully: {status}")
self.reader.thread.join(timeout=5)
_check(not self.reader.thread.is_alive(), "APL stdout did not reach EOF")
extra = bytes(self.reader.buffer)
while not self.reader.chunks.empty():
chunk = self.reader.chunks.get_nowait()
_check(not isinstance(chunk, BaseException), "APL stdout reader failed after the last frame")
extra += chunk
_check(not extra, "APL sidecar emitted unrequested trailing stdout bytes")
self.process.stdout.close()
return status
def abort(self):
if self.process.poll() is None:
self.process.terminate()
try:
self.process.wait(timeout=5)
except subprocess.TimeoutExpired:
self.process.kill()
self.process.wait(timeout=5)
for handle in (self.process.stdin, self.process.stdout):
if handle is not None and not handle.closed:
handle.close()
def _graph_inputs(directory):
arrays = {}
definitions = {"nodes": "int32", "edge_id": "int64", "src": "int32",
"dst": "int32", "signed_raw": "int64", "ptr": "int64", "weights": "float64"}
for name, dtype in definitions.items():
value = np.load(directory / (name + ".npy"), mmap_mode="r", allow_pickle=False)
_check(value.ndim == 1 and value.dtype == np.dtype(dtype), f"Invalid graph array {name}")
arrays[name] = value
nodes, edge_ids = arrays["nodes"], arrays["edge_id"]
n, edges = len(nodes), len(edge_ids)
_check(0 < n <= 166700 and edges > 0, "A case needs real global nodes and explicit nonempty connectivity")
_check(nodes[0] >= 0 and nodes[-1] < 166700 and np.all(np.diff(nodes) > 0), "Invalid global node order")
for name in ("src", "dst", "signed_raw", "weights"):
_check(arrays[name].shape == (edges,), f"Graph array {name} has the wrong shape")
pointer = arrays["ptr"]
_check(pointer.shape == (n + 1,) and pointer[0] == 0 and pointer[-1] == edges and
np.all(np.diff(pointer) >= 0), "Invalid graph CSR pointer")
source_counts = np.zeros(n, np.int64)
identity_edges = True
previous_source, previous_edge = -1, -1
width = BLOCK_BYTES // 8
for begin in range(0, edges, width):
stop = min(edges, begin + width)
source, target, ids = arrays["src"][begin:stop], arrays["dst"][begin:stop], edge_ids[begin:stop]
_check(np.all((source >= 0) & (source < n)) and np.all((target >= 0) & (target < n)),
"Graph edge endpoint is outside the local node array")
_check(np.all(ids >= 0), "Graph edge IDs must be nonnegative")
_check(source[0] > previous_source or (source[0] == previous_source and ids[0] > previous_edge),
"Graph edge blocks are not in canonical source/edge order")
_check(np.all((source[1:] > source[:-1]) |
((source[1:] == source[:-1]) & (ids[1:] > ids[:-1]))),
"Graph edges are not in canonical source/edge order")
previous_source, previous_edge = int(source[-1]), int(ids[-1])
identity_edges &= np.array_equal(ids, np.arange(begin, stop, dtype=np.int64))
source_counts += np.bincount(source, minlength=n)
_check(np.isfinite(arrays["weights"][begin:stop]).all(), "Nonfinite graph weights")
_check(np.array_equal(source_counts, np.diff(pointer)), "CSR pointer and source rows disagree")
if not identity_edges:
_check(len(np.unique(edge_ids)) == edges, "Original edge IDs must be unique")
for name in ("completeness.csv", "connectivity.parquet"):
_check((directory / name).is_file(), f"Missing unchanged author input: {name}")
if n == 166700:
_check(edges == 25582938 and identity_edges and np.array_equal(nodes, np.arange(n, dtype=np.int32)),
"A full probe must use the unchanged complete canonical graph")
return arrays, identity_edges
def _requests(case_dir, nodes, steps):
with np.load(case_dir / "requests.npz", allow_pickle=False) as archive:
_check(set(archive.files) == {"tick", "neuron_idx"}, "Unexpected sparse request schema")
ticks, requested = archive["tick"].copy(), archive["neuron_idx"].copy()
_check(ticks.dtype == requested.dtype == np.dtype("int32") and ticks.ndim == requested.ndim == 1 and
ticks.shape == requested.shape, "Requests must be equal-length int32 vectors")
_check(np.all((ticks >= 0) & (ticks < steps)), "Request time outside the case")
_check(not len(ticks) or np.all((ticks[1:] > ticks[:-1]) |
((ticks[1:] == ticks[:-1]) & (requested[1:] > requested[:-1]))),
"Requests must be sorted and unique by tick/global node")
local = np.searchsorted(nodes, requested)
_check(np.all(local < len(nodes)) and np.array_equal(nodes[local], requested),
"Request references a global neuron absent from this case")
counts = np.bincount(ticks, minlength=steps).astype(np.int32)
pointer = np.concatenate((np.zeros(1, np.int64), np.cumsum(counts, dtype=np.int64)))
return requested, local.astype(np.int32), pointer, counts
class _QueueProxy:
def __init__(self, original, get_tick, available, arrays, identity_edges,
due_counts, spike_ring, delay_steps, handle, records, summarize):
self._original_queue, self._get_tick = original, get_tick
self._available, self._arrays, self._identity_edges = available, arrays, identity_edges
self._due_counts, self._spike_ring, self._delay_steps = due_counts, spike_ring, delay_steps
self._handle, self._records, self._summarize = handle, records, summarize
def peek(self, *args, **kwargs):
original = self._original_queue.peek(*args, **kwargs)
local_edges = np.asarray(original)
tick = self._get_tick()
_check(tick == len(self._records["rows"]), "Queue peek ticks must be consecutive")
_check(local_edges.ndim == 1 and np.all((local_edges >= 0) & (local_edges < len(self._arrays["edge_id"]))),
"Original queue contains an invalid local edge index")
_check(len(local_edges) == self._due_counts[tick % len(self._due_counts)],
"Queue arrivals differ from the fixed-delay outgoing degree of actual spikes")
fired_then = np.zeros(len(self._arrays["nodes"]), dtype=bool)
if tick >= self._delay_steps:
fired_then[self._spike_ring[(tick - self._delay_steps) % len(self._spike_ring)]] = True
def accepted(begin, stop):
part = local_edges[begin:stop]
_check(np.all(fired_then[self._arrays["src"][part]]), "Arrival lacks a presynaptic spike at author delay")
return self._available[self._arrays["dst"][part]]
# Only the observed ID view changes; the queue is returned verbatim.
edge_ids = local_edges if self._identity_edges else self._arrays["edge_id"][local_edges]
summary = self._summarize(tick, edge_ids, accepted)
self._handle.write(json.dumps(summary, sort_keys=True) + "\n")
self._records["rows"].append(summary)
self._records["peek_calls"] += 1
return original
def advance(self, *args, **kwargs):
self._records["advance_calls"] += 1
return self._original_queue.advance(*args, **kwargs)
def __getattr__(self, name):
return getattr(self._original_queue, name)
def run_case(case_dir: Path, out_dir: Path) -> dict:
"""Run one continuous case, with exclusive outputs and no candidate trace input.
Graph inputs are the AF array/author-table schema plus original weights.npy.
requests.npz contains sparse tick/neuron_idx int32 vectors. Optional
arrays.npz contains initial_v_mv/initial_g_mv float64 vectors only.
Full probes write state hashes, sparse events and APL traces, not dense
whole-brain histories. Each case requires a fresh process.
"""
global _PROCESS_USED
_check(not _PROCESS_USED, "Every oracle case requires a fresh process")
_PROCESS_USED = True
case_dir, out_dir = Path(case_dir).resolve(strict=True), Path(out_dir).resolve()
spec = json.loads((case_dir / "spec.json").read_text(encoding="utf-8"))
graph_dir = Path(spec["graph_dir"]).resolve(strict=True)
bundle_dir = Path(spec["apl_bundle_dir"]).resolve(strict=True)
worker_path = Path(spec["legacy_apl_worker"]).resolve(strict=True)
science_python = Path(spec["science_python"]).resolve(strict=True)
author_path = Path(spec.get("author_path", AUTHOR_PATH)).resolve(strict=True)
ae_path = Path(spec.get("ae_oracle_path", AE_PATH)).resolve(strict=True)
af_path = Path(spec.get("af_oracle_path", AF_PATH)).resolve(strict=True)
coefficients_path = Path(spec["coefficients_path"]).resolve(strict=True)
steps = int(spec["steps"])
_check(steps == spec["steps"] and 0 < steps <= np.iinfo(np.int32).max, "Invalid number of steps")
_check(float(spec["dt_ms"]) == .1 and np.isclose(float(spec["duration_ms"]), steps * .1, rtol=0, atol=1e-12),
"The frozen APL protocol requires dt_ms=0.1 and a matching duration")
_check(spec.get("precision", "float64") == "float64", "Author state must be float64")
_check(spec.get("training", False) is False and spec.get("poi_used", False) is False,
"Training and original poi are outside this gate")
_check(spec["apl"] == {"tau_ms": 20, "gain": .01, "normalization": 1}, "Frozen APL parameters changed")
record_history = spec["record_history"]
_check(isinstance(record_history, bool), "record_history must be a boolean")
budget_root = Path(spec.get("budget_root", out_dir.parent)).resolve()
budget_limit = int(spec.get("output_budget_bytes", 15 * 1024 ** 3))
_check(budget_limit > 0 and out_dir.is_relative_to(budget_root), "Invalid output budget/root")
out_dir.mkdir(parents=True, exist_ok=False)
mapped_files = []
saved_preferences, old_dt, worker = None, None, None
last_complete_tick = -1
try:
arrays, identity_edges = _graph_inputs(graph_dir)
nodes, n, edges = arrays["nodes"], len(arrays["nodes"]), len(arrays["edge_id"])
_check(n < 166700 or not record_history, "Full probes must not save dense V/g/ref histories")
bundle = {name: np.load(bundle_dir / (name + ".npy"), mmap_mode="r", allow_pickle=False)
for name in ("input_matrix", "output_matrix", "kc_globals", "apl_globals")}
for name, shape in (("input_matrix", (2, 166700)), ("output_matrix", (2, 4064))):
value = bundle[name]
_check(value.dtype == np.dtype("float32") and value.shape == shape and value.flags.c_contiguous,
f"Frozen APL {name} shape/dtype/layout changed")
_check(np.isfinite(value).all() and np.all(value >= 0), f"Invalid positive raw-normalized APL {name}")
for name, count in (("kc_globals", 4064), ("apl_globals", 2)):
value = bundle[name]
_check(value.dtype == np.dtype("int32") and value.shape == (count,) and value[0] >= 0 and
value[-1] < 166700 and np.all(np.diff(value) > 0), f"Frozen APL identity {name} changed")
_check(not np.intersect1d(bundle["kc_globals"], bundle["apl_globals"]).size, "APL and KC identities overlap")
kc_positions = np.searchsorted(nodes, bundle["kc_globals"])
present = kc_positions < n
present[present] &= nodes[kc_positions[present]] == bundle["kc_globals"][present]
kc_local, kc_in_bundle = kc_positions[present], np.flatnonzero(present)
requested_globals, request_local, request_ptr, request_count = _requests(case_dir, nodes, steps)
initial = None
if (case_dir / "arrays.npz").exists():
with np.load(case_dir / "arrays.npz", allow_pickle=False) as archive:
_check(set(archive.files) == {"initial_v_mv", "initial_g_mv"}, "Unexpected initial-state schema")
initial = {name: archive[name].copy() for name in archive.files}
for name, value in initial.items():
_check(value.dtype == np.dtype("float64") and value.shape == (n,) and np.isfinite(value).all(),
f"Invalid diagnostic initial state: {name}")
history_bytes = steps * n * 40 if record_history else 0
_budget(budget_root, budget_limit, history_bytes + steps * (2 + 2 + 4064) * 4 + edges * 8 + (64 << 20))
versions = {name: importlib.metadata.version(name) for name in
("brian2", "numpy", "pandas", "pyarrow", "sympy", "scipy", "cython")}
_save(out_dir / "environment.json", {"python": sys.version, "platform": platform.platform(),
"packages": versions, "codegen": "numpy", "author_precision": "float64",
"APL_precision": "float32 in separate science-Python process", "Torch_imported_into_Brian": False})
for name, required in (("brian2", "2.5.1"), ("numpy", "1.22.3"), ("sympy", "1.12")):
_check(versions[name] == required, f"{name} must remain pinned to {required}")
import brian2 as b2
import pandas as pd
from brian2.core.base import BrianObject
ae = _load_checked(ae_path, AE_SHA256, "phase4ag_sealed_ae_helpers")
af = _load_checked(af_path, AF_SHA256, "phase4ag_sealed_af_helpers")
author = _load_checked(author_path, AUTHOR_SHA256, "phase4ag_unchanged_author")
_check("torch" not in sys.modules, "Torch must not be imported into the pinned Brian process")
comp = pd.read_csv(graph_dir / "completeness.csv", index_col=0)
_check(np.array_equal(comp.index.to_numpy(), nodes) and
np.array_equal(comp["local_index"].to_numpy(), np.arange(n)), "Author CSV neuron identity differs")
del comp
graph_hashes = {name: _digest(graph_dir / name) for name in
tuple(key + ".npy" for key in arrays) + ("completeness.csv", "connectivity.parquet")}
bundle_hashes = {name: _digest(bundle_dir / name) for name in BUNDLE_FILES}
case_hashes = {name: _digest(case_dir / name) for name in ("spec.json", "requests.npz")}
if initial is not None:
case_hashes["arrays.npz"] = _digest(case_dir / "arrays.npz")
worker_hash = _digest(worker_path)
coefficient_hash = _digest(coefficients_path)
baseline_coefficients = json.loads(coefficients_path.read_text(encoding="utf-8"))
if "legacy_apl_worker_sha256" in spec:
_check(worker_hash == spec["legacy_apl_worker_sha256"], "APL worker differs from preregistered source")
_save(out_dir / "input-audit.json", {"spec": spec, "case_hashes": case_hashes,
"graph_hashes": graph_hashes, "bundle_hashes": bundle_hashes,
"author_sha256": AUTHOR_SHA256, "ae_sha256": AE_SHA256, "af_sha256": AF_SHA256,
"legacy_apl_worker_sha256": worker_hash, "coefficients_sha256": coefficient_hash,
"candidate_trace_used_as_input": False,
"scope": "shared-APL-component closed-loop oracle, not all-components-independent CPU equivalence"})
saved_preferences = {key: b2.prefs[key] for key in
("codegen.target", "core.default_float_dtype", "legacy.refractory_timing")}
old_dt = b2.defaultclock.dt
b2.start_scope()
b2.prefs["codegen.target"] = "numpy"
b2.prefs["core.default_float_dtype"] = np.float64
b2.prefs["legacy.refractory_timing"] = False
b2.defaultclock.dt = .1 * b2.ms
parameters = dict(author.default_params)
_save(out_dir / "parameter-checks.json", ae._parameters_match(parameters, spec["model"], b2))
neu, syn, spikes = author.create_model(graph_dir / "completeness.csv", graph_dir / "connectivity.parquet", parameters)
_check(len(neu) == n and len(syn) == edges, "Author loaded an unexpected graph size")
_check(all(np.dtype(neu.variables[key].dtype) == np.float64 for key in ("v", "g")) and
np.dtype(syn.variables["w"].dtype) == np.float64, "Author states/weights are not float64")
effective = _new_memmap(out_dir / "weights.npy", "<f8", (edges,))
mapped_files.append(effective)
width, w_unit, mask_count = BLOCK_BYTES // 8, float(parameters["w_syn"] / b2.volt), 0
mask_hasher = hashlib.sha256()
base_hasher = hashlib.sha256()
effective_hasher = hashlib.sha256()
for begin in range(0, edges, width):
stop = min(edges, begin + width)
np.testing.assert_array_equal(np.asarray(syn.i[begin:stop]), arrays["src"][begin:stop])
np.testing.assert_array_equal(np.asarray(syn.j[begin:stop]), arrays["dst"][begin:stop])
original = np.asarray(syn.w_[begin:stop], dtype=np.float64).copy()
raw_expected = arrays["signed_raw"][begin:stop] * w_unit
_check(np.array_equal(original.view(np.uint64), raw_expected.view(np.uint64)) and
np.array_equal(original.view(np.uint64), arrays["weights"][begin:stop].view(np.uint64)),
"Actual original Brian weights differ from unchanged signed raw or AF base weights")
base_hasher.update(np.ascontiguousarray(original, dtype="<f8").tobytes())
mask = np.isin(nodes[arrays["src"][begin:stop]], bundle["apl_globals"])
mask_count += int(mask.sum())
mask_hasher.update(np.ascontiguousarray(arrays["edge_id"][begin:stop][mask], dtype="<i8").tobytes())
original[mask] = np.float64(0.0)
effective_hasher.update(np.ascontiguousarray(original, dtype="<f8").tobytes())
effective[begin:stop] = original
syn.w_[begin:stop] = original
if n == 166700:
_check(mask_count == 5845, "Full legacy APL fast-edge mask must contain exactly 5845 existing edges")
effective.flush()
_save(out_dir / "apl-mask-audit.json", {"count": mask_count, "ordered_original_edge_id_sha256": mask_hasher.hexdigest(),
"base_weight_raw_bytes_sha256": base_hasher.hexdigest(), "effective_weights_file_sha256": _digest(out_dir / "weights.npy"),
"effective_weights_raw_sha256": effective_hasher.hexdigest(),
"rule": "zero +0 all existing fast edges whose source GLOBAL neuron is in apl_globals; no graph edge removal",
"graded_targets": "only KC identities present in this LIF case", "KC_targets_in_case": len(kc_local),
"base_graph_files_modified": False, "fullgraph_required_mask_count": 5845})
if initial is not None:
neu.v = initial["initial_v_mv"] * b2.mV
neu.g = initial["initial_g_mv"] * b2.mV
v_raw = neu.variables["v"].get_value()
g_raw = neu.variables["g"].get_value()
last_raw = neu.variables["lastspike"].get_value()
available_raw = neu.variables["not_refractory"].get_value()
histories = {}
pre_apl_histories = {}
if record_history:
for name, dtype in (("v", "float64"), ("g", "float64"), ("ref", "int32")):
histories[name] = _new_memmap(out_dir / f"{name}-history.{dtype}.npy", np.dtype(dtype), (steps, n))
mapped_files.append(histories[name])
pre_apl_histories[name] = _new_memmap(out_dir / f"preAPL-{name}.{dtype}.npy", np.dtype(dtype), (steps, n))
mapped_files.append(pre_apl_histories[name])
apl_history = {}
for name, count in (("drive", 2), ("state", 2), ("inhibition", 4064)):
apl_history[name] = _new_memmap(out_dir / f"apl-{name}.float32.npy", "<f4", (steps, count))
mapped_files.append(apl_history[name])
_save(out_dir / "output-schema.json", {"history_recorded": record_history, "history_shape": [steps, n],
"state_hash_file": "tick-state-hashes.jsonl", "state_hash_encoding": "SHA256 of contiguous little-endian raw f64 V/g and i32 ref",
"APL_dtype": "float32", "APL_h_units": "mV; gain already applied in float32",
"APL_SI_conversion": "h.astype(float64) * float64(0.001), then separate float64 g subtraction",
"APL_write_schedule": "end, order=0, after original reset, unconditional raw g write; recorder end/order=1",
"APL_input": "Brian's own actual global spikes, never candidate spikes or candidate inhibition",
"APL_shapes": {"drive": [steps, 2], "state": [steps, 2], "inhibition": [steps, 4064]},
"request_columns": ["tick", "neuron_idx", "attempted", "accepted", "rejected"],
"queue_protocol": "sealed Phase4AF queue_summary; original global edge IDs, including zero-weight/ref-rejected arrivals",
"state_npz": ["step", "neuron_idx", "counts", "v", "g", "ref"],
"complete_marker": "summary.json complete=true only after worker exit and all checks"})
delay_steps = int(round(float(parameters["t_dly"] / b2.ms) / .1))
ref_steps = int(round(float(parameters["t_rfc"] / b2.ms) / .1))
_check(delay_steps == 18 and ref_steps == 22, "Author delay/refractory changed")
queue_len = delay_steps + 1
due_counts = np.zeros(queue_len, np.int64)
spike_ring = [np.empty(0, np.int32) for _ in range(queue_len)]
outdegree = np.diff(arrays["ptr"])
request_seen = np.zeros(steps, np.uint8)
apl_seen = np.zeros(steps, np.uint8)
applicable_count = np.zeros(steps, np.int32)
rejected_count = np.zeros(steps, np.int32)
spike_count = np.zeros(steps, np.int32)
total_counts = np.zeros(n, np.int32)
records = {"rows": [], "peek_calls": 0, "advance_calls": 0, "installations": []}
last_ticks = np.zeros(n, np.int64)
final_ref = np.zeros(n, np.int32)
permitted = np.empty(0, np.int32)
total_events = 0
def tick_now():
return int(round(float(neu.clock.t / b2.second) / .0001))
def current_ref(tick):
seen = np.isfinite(last_raw) & (last_raw >= 0)
last_ticks.fill(0)
last_ticks[seen] = np.rint(last_raw[seen] / .0001).astype(np.int64)
result = np.where(seen, np.maximum(ref_steps - (tick - last_ticks), 0), 0).astype(np.int32)
_check(np.array_equal(result == 0, available_raw), "Ref history disagrees with author not_refractory")
return result
with ExitStack() as stack:
stderr = stack.enter_context((out_dir / "apl-worker.stderr.log").open("xb"))
worker = _APLWorker(science_python, worker_path, bundle_dir, stderr, float(spec.get("worker_timeout_seconds", 180)))
_save(out_dir / "apl-worker-handshake.json", {"command": worker.command, "handshake": worker.hello})
queue_file = stack.enter_context((out_dir / "queue.jsonl").open("x", encoding="utf-8"))
event_file = stack.enter_context((out_dir / "events.bin").open("xb"))
hash_file = stack.enter_context((out_dir / "tick-state-hashes.jsonl").open("x", encoding="utf-8"))
tick_file = stack.enter_context((out_dir / "ticks.jsonl").open("x", encoding="utf-8"))
requests_file = stack.enter_context((out_dir / "requests.csv").open("x", encoding="utf-8", newline=""))
request_writer = csv.DictWriter(requests_file, fieldnames=["tick", "neuron_idx", "attempted", "accepted", "rejected"])
request_writer.writeheader()
def request_operation():
nonlocal permitted
tick = tick_now()
_check(0 <= tick < steps and not request_seen[tick], "Invalid/duplicate common request tick")
request_seen[tick] = 1
begin, stop = request_ptr[tick:tick + 2]
local = request_local[begin:stop]
available = available_raw[local].copy()
permitted = local[available]
applicable_count[tick] = len(permitted)
rejected_count[tick] = len(local) - len(permitted)
for node, accepted in zip(requested_globals[begin:stop], available):
request_writer.writerow({"tick": tick, "neuron_idx": int(node), "attempted": 1,
"accepted": int(accepted), "rejected": int(not accepted)})
if len(permitted):
neu.v[permitted] = parameters["v_th"] + 1 * b2.mV
def apl_operation():
tick = tick_now()
_check(0 <= tick < steps and not apl_seen[tick] and request_seen[tick], "Invalid/duplicate APL tick")
active = np.asarray(neu.spikes, dtype=np.int32)
_check(not len(active) or np.all(np.diff(active) > 0), "Brian actual spikes are not canonical/unique")
_check(np.all(g_raw[active] == 0.0), "APL ran before the original author g reset")
if record_history:
pre_apl_histories["v"][tick] = v_raw
pre_apl_histories["g"][tick] = g_raw
pre_apl_histories["ref"][tick] = current_ref(tick)
drive, state, inhibition = worker.step(tick, np.asarray(nodes[active], dtype=np.int32))
apl_history["drive"][tick] = drive
apl_history["state"][tick] = state
apl_history["inhibition"][tick] = inhibition
# These are separate array operations. Do not move the unit
# conversion into a fused subtract; do not guard by refractory.
delta_si = inhibition[kc_in_bundle].astype(np.float64) * np.float64(.001)
g_raw[kc_local] = g_raw[kc_local] - delta_si
apl_seen[tick] = 1
def record_end():
nonlocal last_complete_tick, total_events, final_ref
tick = tick_now()
_check(tick == last_complete_tick + 1 and tick < steps and apl_seen[tick], "End tick is incomplete/out of order")
_check(len(records["rows"]) == tick + 1, "End state lacks queue observation")
_check(np.isfinite(v_raw).all() and np.isfinite(g_raw).all(), "Nonfinite author/APL state")
final_ref = current_ref(tick)
if record_history:
histories["v"][tick], histories["g"][tick], histories["ref"][tick] = v_raw, g_raw, final_ref
active = np.asarray(neu.spikes, dtype=np.int32)
_check(np.isin(permitted, active).all(), "An applicable request did not produce a real spike")
spike_count[tick] = len(active)
total_counts[active] += 1
if len(active):
events = np.empty(len(active), EVENT_DTYPE)
events["step"], events["neuron_idx"] = tick, nodes[active]
event_file.write(memoryview(events).cast("B"))
total_events += len(active)
spike_ring[tick % queue_len] = active.copy()
due_counts[(tick + delay_steps) % queue_len] = int(outdegree[active].sum(dtype=np.int64))
hash_file.write(json.dumps({"tick": tick, "v_sha256": _array_hash(v_raw, "<f8"),
"g_sha256": _array_hash(g_raw, "<f8"), "ref_sha256": _array_hash(final_ref, "<i4")}, sort_keys=True) + "\n")
tick_file.write(json.dumps({"tick": tick, "spikes": len(active), "requests": int(request_count[tick]),
"applicable_requests": int(applicable_count[tick]), "ref_rejected_requests": int(rejected_count[tick]),
"event_sha256": _array_hash(nodes[active], "<i4"),
"due_arrivals": records["rows"][tick]["count"], "accepted_arrivals": records["rows"][tick]["accepted_count"],
"APL_drive_sha256": _array_hash(apl_history["drive"][tick], "<f4"),
"APL_state_sha256": _array_hash(apl_history["state"][tick], "<f4"),
"APL_inhibition_sha256": _array_hash(apl_history["inhibition"][tick], "<f4")}, sort_keys=True) + "\n")
_budget(budget_root, budget_limit, reserve=1 << 20)
last_complete_tick = tick
if (tick + 1) % 100 == 0 or tick + 1 == steps:
for mapped in mapped_files:
mapped.flush()
for handle in (queue_file, event_file, hash_file, tick_file, requests_file):
handle.flush()
print(json.dumps({"oracle": spec["name"], "completed_ticks": tick + 1,
"spikes": total_events, "APL_worker_ticks": worker.tick}), flush=True)
class QueueInstaller(BrianObject):
def __init__(self):
super().__init__(clock=neu.clock, when="end", order=1_000_000, name="zz_apl_queue_installer")
def before_run(self, run_namespace):
installed = []
for code in syn.pre.code_objects:
if "_queue" not in code.namespace or "_queue.peek()" not in str(code.code):
continue
original = code.namespace["_queue"]
if isinstance(original, _QueueProxy):
original = original._original_queue
code.namespace["_queue"] = _QueueProxy(original, tick_now, available_raw, arrays, identity_edges,
due_counts, spike_ring, delay_steps, queue_file, records, af.queue_summary)
installed.append(code.name)
_check(len(installed) == 1, "Expected one original anatomical queue consumer")
records["installations"].append(installed[0])
objects = [neu, syn, spikes,
b2.NetworkOperation(request_operation, clock=neu.clock, when="before_thresholds", order=0, name="oracle_common_requests"),
b2.NetworkOperation(apl_operation, clock=neu.clock, when="end", order=0, name="oracle_legacy_apl_unconditional"),
b2.NetworkOperation(record_end, clock=neu.clock, when="end", order=1, name="oracle_after_apl_record"), QueueInstaller()]
network = b2.Network(*objects)
_save(out_dir / "schedule.json", {"schedule": list(network.schedule), "summary": str(network.scheduling_summary())})
network.run(0 * b2.ms, namespace={})
_save(out_dir / "compiled-code.json", ae._code_records(network))
compiled_coefficients = ae._coefficients(neu, parameters, b2, .0001)
coefficient_keys = ("gd", "c0", "cg", "cv", "threshold", "reset", "seed_volt")
_check(all(float(compiled_coefficients[key]).hex() == float(baseline_coefficients[key]).hex()
for key in coefficient_keys), "Compiled Brian coefficients differ from sealed AF")
_check(last_complete_tick == -1 and worker.tick == 0 and not records["rows"] and not request_seen.any(),
"Zero-duration compilation unexpectedly advanced state")
network.run(steps * .1 * b2.ms, namespace={})
_save(out_dir / "generated-code.json", ae._code_records(network))
worker_status = worker.finish(steps)
worker = None
_check(last_complete_tick == steps - 1 and np.all(request_seen == 1) and np.all(apl_seen == 1), "Incomplete trial")
_check(records["peek_calls"] == records["advance_calls"] == steps, "Incomplete queue audit")
_check(total_events == int(spikes.num_spikes) and np.array_equal(total_counts, np.asarray(spikes.count[:])),
"Sparse events disagree with original SpikeMonitor")
_check(np.array_equal(request_count, applicable_count + rejected_count), "Incomplete request accounting")
_check(np.all(np.asarray(neu.rfc[:] / b2.ms) == float(parameters["t_rfc"] / b2.ms)), "Author refractory duration changed")
for begin in range(0, edges, width):
stop = min(edges, begin + width)
_check(np.array_equal(np.asarray(syn.w_[begin:stop]).view(np.uint64), effective[begin:stop].view(np.uint64)),
"Effective synaptic weights changed during the trial")
event_values = np.memmap(out_dir / "events.bin", dtype=EVENT_DTYPE, mode="r", shape=(total_events,)) if total_events else np.empty(0, EVENT_DTYPE)
_check((out_dir / "events.bin").stat().st_size == total_events * 8, "Sparse event byte count mismatch")
for begin in range(0, total_events, width):
stop = min(total_events, begin + width)
spike_local = np.asarray(spikes.i[begin:stop], dtype=np.int32)
np.testing.assert_array_equal(event_values["neuron_idx"][begin:stop], nodes[spike_local])
times = np.rint(np.asarray(spikes.t[begin:stop] / b2.second) / .0001).astype(np.int32)
np.testing.assert_array_equal(event_values["step"][begin:stop], times)
_budget(budget_root, budget_limit, total_events * 8 + n * 24 + (8 << 20))
with (out_dir / "state.npz").open("xb") as handle:
np.savez_compressed(handle, step=event_values["step"], neuron_idx=event_values["neuron_idx"],
counts=total_counts, v=v_raw, g=g_raw, ref=final_ref)
with (out_dir / "tick-summary.npz").open("xb") as handle:
np.savez_compressed(handle, request_count=request_count, applicable_count=applicable_count,
rejected_count=rejected_count, spike_count=spike_count,
arrival_count=np.asarray([row["count"] for row in records["rows"]], np.int64),
accepted_arrival_count=np.asarray([row["accepted_count"] for row in records["rows"]], np.int64))
coefficients = ae._coefficients(neu, parameters, b2, .0001)
keys = ("gd", "c0", "cg", "cv", "threshold", "reset", "seed_volt")
_check(all(float(coefficients[key]).hex() == float(baseline_coefficients[key]).hex() for key in keys),
"Actual Brian coefficients differ from sealed AF coefficients")
_save(out_dir / "coefficients.json", coefficients)
_save(out_dir / "queue-audit.json", {"peek_calls": records["peek_calls"], "advance_calls": records["advance_calls"],
"installations": records["installations"], "same_peek_object_returned": True,
"original_edge_ids_not_sorted_or_filtered": True, "zero_weight_and_refractory_rejected_edges_retained": True,
"post_threshold_pre_synaptic_guard_observed": True, "forwarding_contract": "sealed AE/AF design",
"new_unwrapped_repeat_performed": False, "limit": "Current wrapper was not independently rerun without the queue proxy"})
for path, expected in ((author_path, AUTHOR_SHA256), (ae_path, AE_SHA256), (af_path, AF_SHA256), (worker_path, worker_hash)):
_check(_digest(path) == expected, f"Source changed during the run: {path}")
_check(_digest(coefficients_path) == coefficient_hash, "Sealed coefficient reference changed during the run")
for directory, hashes in ((graph_dir, graph_hashes), (bundle_dir, bundle_hashes), (case_dir, case_hashes)):
for name, expected in hashes.items():
_check(_digest(directory / name) == expected, f"Read-only input changed during the run: {name}")
for mapped in mapped_files:
mapped.flush()
_check("torch" not in sys.modules, "Pinned Brian process unexpectedly imported Torch")
output_bytes = _budget(budget_root, budget_limit, 1 << 20)
summary = {"name": spec["name"], "complete": True, "precision": "float64", "APL_precision": "float32",
"backend": "shared-APL-component closed-loop Brian2 oracle", "steps": steps, "completed_ticks": last_complete_tick + 1,
"nodes": n, "edges": edges, "spikes": total_events, "requests": int(request_count.sum()),
"applicable_requests": int(applicable_count.sum()), "ref_rejected_requests": int(rejected_count.sum()),
"APL_fast_edges_zeroed": mask_count, "APL_worker_exit_status": worker_status, "APL_worker_ticks": steps,
"apl_fast_edges_zeroed": mask_count, "effective_weights_raw_sha256": effective_hasher.hexdigest(),
"kc_targets_present": len(kc_local),
"candidate_trace_used_as_input": False, "independent_CPU_all_components_claim": False,
"history_recorded": record_history, "single_continuous_run": True, "no_training": True, "no_poi": True,
"source_and_inputs_unchanged": True, "pass_all": True,
"pass_all_scope": "Oracle construction, protocol and internal self-checks only; candidate comparison is a separate gate",
"scope": "Only this fixed trajectory; legacy Torch APL is a shared numerical component, not an independent CPU APL implementation",
"output_budget_bytes": budget_limit, "output_bytes_before_summary": output_bytes,
"state_hashes_sha256": _digest(out_dir / "tick-state-hashes.jsonl"), "queue_sha256": _digest(out_dir / "queue.jsonl"),
"events_sha256": _digest(out_dir / "events.bin"), "weights_sha256": _digest(out_dir / "weights.npy")}
_save(out_dir / "summary.json", summary)
return summary
except Exception as error:
for mapped in mapped_files:
mapped.flush()
_save(out_dir / "error.json", {"complete": False, "last_complete_tick": last_complete_tick,
"type": type(error).__name__, "message": str(error), "partial_files_preserved": True,
"inputs_or_duration_adjusted": False})
raise
finally:
if worker is not None:
worker.abort()
if saved_preferences is not None:
for key, value in saved_preferences.items():
b2.prefs[key] = value
b2.defaultclock.dt = old_dt
@@ -0,0 +1,155 @@
"""Preregister exact legacy APL data and unmodified fixed CAL requests."""
from datetime import datetime,timezone
import json
import math
import os
from pathlib import Path
import shutil
import subprocess
import sys
import numpy as np
import pandas as pd
import yaml
from context import ROOT,MODEL,EXP,AF_MODEL,AF_EXP,AD_EXP,CFG,save,digest,sources,integrity,budget
def arr(path,value):
with Path(path).open('xb') as f:np.save(f,value,allow_pickle=False)
def graph(folder,nodes,full):
folder.mkdir();nodes=np.asarray(nodes,np.int32);ptr,dst,src,raw,base=full
if len(nodes)==CFG['neurons']:ids=np.arange(len(dst),dtype=np.int64)
else:
ids=np.concatenate([np.arange(ptr[s],ptr[s+1],dtype=np.int64) for s in nodes])
ids=ids[np.isin(dst[ids],nodes)]
lookup=np.full(CFG['neurons'],-1,np.int32);lookup[nodes]=np.arange(len(nodes),dtype=np.int32)
ss,dd=lookup[src[ids]],lookup[dst[ids]];pp=np.r_[np.int64(0),np.bincount(ss,minlength=len(nodes)).cumsum(dtype=np.int64)]
for name,value in dict(nodes=nodes,edge_id=ids,src=ss,dst=dd,ptr=pp,signed_raw=raw[ids],weights=base[ids]).items():arr(folder/(name+'.npy'),value)
pd.DataFrame({'local_index':np.arange(len(nodes),dtype=np.int32)},index=pd.Index(nodes,name='global_neuron_idx')).to_csv(folder/'completeness.csv')
pd.DataFrame({'Presynaptic_Index':ss,'Postsynaptic_Index':dd,'Excitatory x Connectivity':raw[ids],'edge_id':ids},copy=False).to_parquet(folder/'connectivity.parquet',index=False)
save(folder/'audit.json',dict(nodes=len(nodes),edges=len(ids),canonical_original_edge_ids=True,anatomical_weights_not_modified=True,
effective_APL_zeroing='Only in new runtime clone, never these original weight files'))
return nodes
def case(name,kind,steps,nodes,graphdir,requests,initial=None,extra=None):
folder=EXP/'cases'/name;folder.mkdir()
model=json.loads((AD_EXP/'protocol/preregistered.json').read_text())['config']['model']
spec=dict(name=name,kind=kind,steps=steps,dt_ms=.1,duration_ms=steps*.1,model=model,
graph_dir=str(graphdir),apl_bundle_dir=str(EXP/'apl-bundle'),apl=CFG['apl'],record_history=kind=='fixture',
coefficients_path=str(AF_EXP/'oracle/no_input/coefficients.json'),
science_python=str(ROOT/'models/male-cns-lif/.venv/bin/python'),legacy_apl_worker=str(MODEL/'legacy_apl_worker.py'),
budget_root=str(EXP),output_budget_bytes=CFG['output_budget_bytes'],precision='float64',apl_precision='float32',training=False)
if extra:spec.update(extra)
requests=np.asarray(requests,dtype=np.int32).reshape(-1,2)
if len(requests):
requests=requests[np.lexsort((requests[:,1],requests[:,0]))]
assert len(np.unique(requests.astype(np.int64)[:,0]*CFG['neurons']+requests[:,1]))==len(requests)
assert requests[:,0].min()>=0 and requests[:,0].max()<steps and np.isin(requests[:,1],nodes).all()
with (folder/'requests.npz').open('xb') as f:np.savez_compressed(f,tick=requests[:,0],neuron_idx=requests[:,1])
if kind=='fixture':
v=np.full(len(nodes),model['resting_potential_mv'],np.float64);g=np.zeros(len(nodes),np.float64)
if initial:
for node,value in initial.get('v',{}).items():v[np.flatnonzero(nodes==node)[0]]=value
for node,value in initial.get('g',{}).items():g[np.flatnonzero(nodes==node)[0]]=value
with (folder/'arrays.npz').open('xb') as f:np.savez_compressed(f,initial_v_mv=v,initial_g_mv=g)
save(folder/'spec.json',spec)
def main():
assert not (EXP/'protocol/preregistered.json').exists()
assert all(not (EXP/d).exists() or not any((EXP/d).iterdir()) for d in ('protocol','graphs','apl-bundle','cases','gpu','oracle'))
assert shutil.disk_usage(EXP.parent).free>30*1024**3
for d in ('protocol','apl-bundle','graphs','cases','gpu','oracle','component-audit','regression','calibration','audit','extension-build','logs'):(EXP/d).mkdir(parents=True,exist_ok=True)
can=ROOT/'datasets/male-cns-v1.0/processed/neuron-only';legacy=ROOT/'models/male-cns-lif';lp=legacy/'olfactory-grounding-v1/phase4l.yaml'
lock=ROOT/'experiments/phase4j-mb-physiology-repair/calibration/locked-parameters.json'
files=[AF_MODEL/'manifest.json',AF_EXP/'manifest.json',AF_EXP/'oracle/no_input/coefficients.json',
legacy/'deterministic-runtime-v2/phase4p_revalidate.py',lp,lock,can/'neuron-index/unified-metadata.parquet',can/'gpu/csr-weights.int64.npy',
legacy/'author-runtime-lab-v1/author_ext.cpp',legacy/'author-runtime-lab-v1/author_ext.cu',legacy/'author-runtime-lab-v1/gpu_backend.py',
legacy/'author-runtime-lab-v1/oracle_stress.py',AD_EXP/'external-resources/model.py',AF_MODEL/'oracle_full.py']
lroot=ROOT/'experiments/phase4l-olfactory-grounding'
files += [lroot/'odor-encoder'/x for x in ('frozen-odor-panel.parquet','mapped-glomerular-vectors.npz','selection.json')]
files += [lroot/'receptor-mapping/olfactory-mapping.parquet']
save(EXP/'protocol/preregistered.json',dict(timestamp_utc=datetime.now(timezone.utc).isoformat(),sources=sources(),config=CFG,
inputs=[dict(path=str(p.relative_to(ROOT)),sha256=digest(p)) for p in files],before_any_trajectory=True,
parent_commit=subprocess.check_output(['git','-C',str(ROOT),'rev-parse','HEAD'],text=True).strip()))
save(EXP/'regression/old-integrity-before.json',integrity())
locked=json.loads(lock.read_text());assert locked['parameters_locked'] and locked['calibration_only']
assert {k:locked['selected'][k] for k in ('gain','normalization','tau_ms')}==CFG['apl']
meta=pd.read_parquet(can/'neuron-index/unified-metadata.parquet').sort_values('neuron_idx').reset_index(drop=True)
assert len(meta)==CFG['neurons'] and np.array_equal(meta.neuron_idx,np.arange(CFG['neurons']))
cls=meta.annotation_class.fillna('').astype(str).to_numpy();typ=meta.annotation_type.fillna('').astype(str).to_numpy()
kc=np.flatnonzero(cls=='Kenyon_Cell').astype(np.int32);pn=np.flatnonzero(cls=='ALPN').astype(np.int32);apl=np.flatnonzero(typ=='APL').astype(np.int32)
assert len(kc)==4064 and len(apl)==2
fg=AF_EXP/'graph';ptr=np.load(fg/'ptr.npy',mmap_mode='r');dst=np.load(fg/'dst.npy',mmap_mode='r');src=np.load(fg/'src.npy',mmap_mode='r')
signed=np.load(fg/'signed_raw.npy',mmap_mode='r');base=np.load(AF_EXP/'oracle/no_input/weights.npy',mmap_mode='r');raw=np.load(can/'gpu/csr-weights.int64.npy',mmap_mode='r')
assert len(dst)==CFG['edges'] and int(raw.sum())==CFG['raw_weight_sum']
aplout=np.isin(src,apl);aplids=np.flatnonzero(aplout).astype(np.int64);assert len(aplids)==5845
I=np.zeros((2,len(meta)),np.float32);O=np.zeros((2,len(kc)),np.float32)
alook={int(v):i for i,v in enumerate(apl)};kl=np.full(len(meta),-1,np.int32);kl[kc]=np.arange(len(kc),dtype=np.int32)
allowed=np.isin(src,np.r_[kc,pn])&np.isin(dst,apl)
for eid in np.flatnonzero(allowed):I[alook[int(dst[eid])],int(src[eid])]+=float(raw[eid])
for eid in np.flatnonzero(aplout&np.isin(dst,kc)):O[alook[int(src[eid])],kl[dst[eid]]]+=float(raw[eid])
iscale=float(I[I>0].sum()/np.count_nonzero(np.any(I>0,axis=0)));oscale=float(O[O>0].mean());bundle=EXP/'apl-bundle'
for name,value in dict(input_matrix=I/iscale,output_matrix=O/oscale,input_raw=I,output_raw=O,kc_globals=kc,pn_globals=pn,apl_globals=apl,apl_out_ids=aplids).items():arr(bundle/(name+'.npy'),value)
save(bundle/'scales.json',dict(input_scale=iscale,output_scale=oscale))
save(bundle/'provenance.json',dict(canonical_root=str(can),source=str(legacy/'deterministic-runtime-v2/phase4p_revalidate.py'),source_sha256=digest(legacy/'deterministic-runtime-v2/phase4p_revalidate.py'),
parameters=CFG['apl'],lock_file=str(lock),lock_sha256=digest(lock),full_dimensions=[list(I.shape),list(O.shape)],
APL=len(apl),KC=len(kc),ALPN=len(pn),APL_fast_edges=len(aplids),APL_nonKC_edges=int(np.count_nonzero(aplout&~np.isin(dst,kc))),
APL_nonKC_contacts=int(raw[aplout&~np.isin(dst,kc)].sum()),normalization_recomputed_in_original_order=True,
raw_files_modified=False))
full=(ptr,dst,src,signed,base);fullnodes=graph(EXP/'graphs/full',np.arange(len(meta),dtype=np.int32),full)
pscore=I.sum(axis=0);pnrank=pn[np.lexsort((pn,-pscore[pn]))];kscore=O.sum(axis=0);kcrank=kc[np.lexsort((kc,-kscore))]
candidates=np.flatnonzero(np.isin(src,pn)&np.isin(dst,kc));best=int(candidates[np.argmax(raw[candidates])]);pairpn=int(src[best])
pe=np.arange(ptr[pairpn],ptr[pairpn+1],dtype=np.int64);pe=pe[np.isin(dst[pe],kc)];pe=pe[np.lexsort((dst[pe],-raw[pe]))]
collision_kc=np.unique(dst[pe[:3]]);assert len(collision_kc)==3
nonkc=aplids[~np.isin(dst[aplids],kc)];nonkc_target=int(dst[nonkc[np.argmax(raw[nonkc])]])
nodes=np.unique(np.r_[apl,pnrank[:16],kcrank[:16],pairpn,collision_kc,nonkc_target,[1197,1381,1511,82312,133666]]).astype(np.int32)
fixturegraph=EXP/'graphs/fixtures';graph(fixturegraph,nodes,full)
p=int(pnrank[0]);k=int(kcrank[0]);kc1,kc2,kc3=map(int,collision_kc)
designs=[('zero',100,[],None),('pn_pulse',300,[(0,p)],None),
('kc_ref_boundary',100,[(t,k) for t in (0,1,21,22,23,44)],None),
('two_sources',300,[(t,n) for t in (0,22,44,66,88) for n in (p,k)],None),
('arrival_collision',120,[(0,pairpn),(0,kc1),(18,kc2),(21,kc1)],None),
('natural_request',100,[(0,k)],dict(v={k:-44.0})),
('apl_only',100,[(0,int(a)) for a in apl],None),
('high_fanin',400,[(t,int(n)) for t in (0,22,44) for n in nodes if pscore[n]>0],dict(g={k:.123}))]
assert [v[0] for v in designs]==CFG['fixtures']
for name,steps,requests,initial in designs:case(name,'fixture',steps,nodes,fixturegraph,requests,initial)
meta.iloc[nodes][['neuron_idx','body_id','annotation_class','annotation_type','neurotransmitter']].to_csv(EXP/'protocol/fixture-identities.csv',index=False)
save(EXP/'protocol/fixture-selection.json',dict(pn=p,kc=k,pair_PN=pairpn,arrival_KCs=collision_kc.tolist(),real_PN_KC_edge=best,
nonKC_APL_target=nonkc_target,method='Static raw-count ranks and exact metadata; retain ALL existing induced edges and full APL matrices/norms',runtime_selection=False))
os.environ['CUDA_VISIBLE_DEVICES']=CFG['gpu_uuid'];sys.path.insert(0,str(legacy));sys.path.insert(0,str(legacy/'deterministic-runtime-v2'))
sys.path.insert(0,str(legacy/'terminal-scope-diagnostic-v1'));from diagnostic import queues
queues()
import torch
from phase4p_revalidate import door_inputs,make_drive
oc,panel,vectors,selection,mapping=door_inputs();cal=panel[panel.split=='calibration'].copy();assert len(panel)==12 and len(cal)==6
assert oc['odor_encoder']['evaluation_seeds']==CFG['calibration']['seeds']
assert float(oc['odor_encoder']['duration_ms'])==CFG['calibration']['duration_ms']
cal.to_parquet(EXP/'protocol/calibration-panel.parquet',index=False);calrecords=[]
for mode in CFG['calibration']['modes']:
for oi,(_,odor) in enumerate(cal.iterrows()):
targets,rates=make_drive(oc,panel,vectors,selection,mapping,odor.odor_id,mode)
assert len(np.unique(targets))==len(targets),'Original encoder emits duplicate PN targets; audit instead of silently merging'
rates=np.asarray(rates,np.float32);steps=round(CFG['calibration']['duration_ms']/.1)
for seed in CFG['calibration']['seeds']:
gen=torch.Generator(device='cuda');gen.manual_seed(seed)
original_probability=rates*.1/1000.0
explicit_probability=rates*np.float32(.1)/np.float32(1000.)
assert original_probability.dtype==np.float32 and np.array_equal(original_probability.view(np.uint32),explicit_probability.view(np.uint32))
probs=torch.as_tensor(original_probability,dtype=torch.float32,device='cuda')
forced=(torch.rand((steps,len(targets)),generator=gen,device='cuda')<probs[None,:]).cpu().numpy()
tt,cc=np.nonzero(forced);req=np.column_stack([tt,targets[cc]]).astype(np.int32)
name=f'cal-{mode}-{oi:02d}-s{seed}'
case(name,'calibration',steps,fullnodes,EXP/'graphs/full',req,extra=dict(odor_id=str(odor.odor_id),odor_name=str(odor.odor_name),
mode=mode,seed=seed,odor_index=oi,expected_external_events=float(rates.sum())*steps*.1/1000.,target_count=len(targets),rate_sum_hz=float(rates.sum())))
with (EXP/'cases'/name/'pn-drive.npz').open('xb') as f:np.savez_compressed(f,targets=targets,rates_hz=rates)
calrecords.append(dict(name=name,mode=mode,odor_index=oi,odor_id=str(odor.odor_id),seed=seed,requests=len(req),rates_sum=float(rates.sum())))
save(EXP/'protocol/calibration-cases.json',calrecords)
save(EXP/'protocol/encoder-audit.json',dict(panel_count=12,cal_count=6,median_mapped_response_sum=float(np.median(panel.mapped_response_sum)),
target_rng_column_order='Original pn_drive, no sorting before torch.rand',seeds=CFG['calibration']['seeds'],
requested_before_any_dynamics=True,formal_AB_run=False,heldout_run=False,torch=torch.__version__,numpy=np.__version__,
generation='Original rates*.1/1000 float32 GPU Bernoulli, independent per-case original seed'))
save(EXP/'protocol/prepared-hashes.json',[dict(path=str(p.relative_to(EXP)),bytes=p.stat().st_size,sha256=digest(p))
for d in ('graphs','apl-bundle','cases','protocol') for p in sorted((EXP/d).rglob('*')) if p.is_file() and p.name!='prepared-hashes.json'])
budget();print('PREPARED8 fixtures and60 fixed CAL inputs; no trajectories; frozen integrity PASS',flush=True)
if __name__=='__main__':main()
@@ -0,0 +1,48 @@
"""A fresh process per declared case; no concurrent scientific GPU jobs."""
import argparse
import json
import os
import sys
import urllib.request
from context import ROOT,MODEL,EXP,CFG,check,budget
def main():
parser=argparse.ArgumentParser()
parser.add_argument('backend',choices=['gpu','oracle','component'])
parser.add_argument('case')
parser.add_argument('--repeat',type=int,default=0)
args=parser.parse_args()
assert '/' not in args.case and '..' not in args.case and 0<=args.repeat<3
check();budget()
os.environ['CUDA_VISIBLE_DEVICES']=CFG['gpu_uuid']
os.environ['CUDA_HOME']='/usr/local/cuda'
os.environ['PATH']=str(ROOT/'models/male-cns-lif/.venv/bin')+':/usr/local/cuda/bin:'+os.environ['PATH']
os.environ['MAX_JOBS']='2';os.environ['TORCH_CUDA_ARCH_LIST']='8.9'
# The pinned Brian environment intentionally has neither Torch nor PyYAML.
# Keep this preflight standard-library-only; never install into that env.
for port in (8188,8189,8190):
with urllib.request.urlopen(f'http://192.168.10.51:{port}/queue',timeout=5) as response:
queue=json.load(response)
assert not queue['queue_running'] and not queue['queue_pending'],'ComfyUI busy: defer, never evict'
case=EXP/'cases'/args.case
assert case.is_dir()
out=EXP/'gpu'/f'{args.case}-r{args.repeat}'
if args.backend=='gpu':
from gpu_apl import run_gpu
result=run_gpu(case,out,EXP/'extension-build')
elif args.backend=='oracle':
assert args.repeat==0
from oracle_apl import run_case
result=run_case(case,EXP/'oracle'/args.case)
else:
assert args.repeat==0
from validate_components import validate
result=validate(out,EXP/'apl-bundle',EXP/'component-audit'/(args.case+'.json'))
budget()
print(json.dumps(dict(backend=args.backend,case=args.case,repeat=args.repeat,
complete=result.get('complete'),pass_all=result.get('pass_all')),allow_nan=False),flush=True)
if not result.get('pass_all',False):raise SystemExit(1)
if __name__=='__main__':main()
@@ -0,0 +1,68 @@
"""Ordered numerical gates before any full CAL; never tune from outcomes."""
import argparse
import json
from pathlib import Path
import subprocess
import time
import traceback
from context import ROOT,MODEL,EXP,CFG,check,save,budget
SCIENCE=ROOT/'models/male-cns-lif/.venv/bin/python'
ORACLE=ROOT/'experiments/phase4ad-author-semantics/environment/.venv/bin/python'
def child(backend,name,repeat=0):
log=EXP/'logs'/f'{backend}-{name}-r{repeat}.log'
cmd=[str(ORACLE if backend=='oracle' else SCIENCE),'-B',str(MODEL/'run_case.py'),backend,name,'--repeat',str(repeat)]
print('START',backend,name,repeat,flush=True);t0=time.perf_counter()
with log.open('x',encoding='utf-8') as f:
result=subprocess.run(cmd,stdout=f,stderr=subprocess.STDOUT,timeout=1800,check=False)
print('FINISH',backend,name,repeat,'exit',result.returncode,'wall',round(time.perf_counter()-t0,2),flush=True)
if result.returncode:raise RuntimeError(f'{backend} {name} failed; inspect {log}')
def gate_case(name,repeats):
from compare import compare,compare_gpu_repeats
child('gpu',name)
for r in range(1,repeats):child('gpu',name,r)
child('oracle',name)
result=compare(EXP/'cases'/name,EXP/'gpu'/(name+'-r0'),EXP/'oracle'/name,EXP/'audit'/('compare-'+name+'.json'))
assert result['pass_all'],f'Closed-loop exact comparison failed: {name}; no later CAL permitted'
for r in range(1,repeats):
report=compare_gpu_repeats(EXP/'gpu'/(name+'-r0'),EXP/'gpu'/f'{name}-r{r}',EXP/'audit'/f'repeat-{name}-r{r}.json')
assert report['pass_all'],f'Exact GPU repeat failed: {name}'
child('component',name)
return dict(case=name,pass_all=True,gpu_repeats=repeats)
def main():
parser=argparse.ArgumentParser();parser.add_argument('stage',choices=['fixtures','probes','calibration']);args=parser.parse_args()
check();budget();receipt=EXP/'audit'/(args.stage+'-gate.json');assert not receipt.exists()
try:
if args.stage=='fixtures':
rows=[gate_case(n,CFG['fixture_repeats']) for n in CFG['fixtures']]
save(receipt,dict(pass_all=True,cases=rows,scope='Fixed real-edge induced fixtures only'))
elif args.stage=='probes':
assert json.loads((EXP/'audit/fixtures-gate.json').read_text())['pass_all']
rows=[gate_case(n,1) for n in CFG['calibration']['full_oracle_probes']]
save(receipt,dict(pass_all=True,cases=rows,scope='Only two original first-CAL fixed fullgraph trajectories'))
else:
assert json.loads((EXP/'audit/fixtures-gate.json').read_text())['pass_all']
assert json.loads((EXP/'audit/probes-gate.json').read_text())['pass_all']
records=json.loads((EXP/'protocol/calibration-cases.json').read_text());assert len(records)==60
probes=CFG['calibration']['full_oracle_probes']
for rec in records:
if rec['name'] not in probes:child('gpu',rec['name'])
if rec['seed']==CFG['calibration']['seeds'][0]:child('gpu',rec['name'],1)
from calibration import summarize
result=summarize()
save(receipt,dict(pass_all=result['pass_all'],scope='Complete original six-CAL representation gate, not heldout or learning',summary='calibration/summary.json'))
if not result['pass_all']:raise SystemExit(2)
except Exception as e:
save(EXP/'audit'/('stopped-'+args.stage+'.json'),dict(stage=args.stage,type=type(e).__name__,message=str(e),traceback=traceback.format_exc(),
later_stages_not_permitted=True,partial_outputs_preserved=True,parameters_changed=False))
raise
budget()
if __name__=='__main__':main()
@@ -0,0 +1,142 @@
"""Local, synthetic tests only: no CUDA, scientific trajectories, or heldout data."""
import copy
import unittest
import numpy as np
from calibration import (ORIGINAL_MODES, ORIGINAL_SEEDS, ORIGINAL_CAL_IDS,
APL_FILES, STATE_DTYPES, arrays_bitwise_equal, evaluate_gates, exact_repeat, pair_metrics,
sample_cv, summarize_mode, validate_inventory, validate_state)
GATES = {"sparse_min_fraction": .03, "sparse_max_fraction": .09,
"minimum_separable_odor_pairs": 3, "max_fraction_strict": .5, "min_fraction_strict": 0.,
"same_jaccard_gt_between": True, "between_euclidean_gt_within": True,
"both_modes_required": True, "finite_required": True, "repeat_exact_required": True}
def synthetic_runs(silent=False):
result = {}
for mode in ORIGINAL_MODES:
for odor in range(6):
for seed in ORIGINAL_SEEDS:
counts = np.zeros(1000, dtype=np.int32)
if not silent:
counts[odor * 50:(odor + 1) * 50] = 1
result[(mode, str(odor), seed)] = {"kc_counts": counts,
"expected_external_events": 10., "external_events": 0 if silent else 10}
return result
class CalibrationTests(unittest.TestCase):
def test_complete_gate_and_original_pair_counts(self):
summary = summarize_mode(ORIGINAL_MODES[0], list(map(str, range(6))), ORIGINAL_SEEDS, synthetic_runs(), GATES)
self.assertTrue(summary["gate"])
self.assertEqual(summary["within_distance_count"], 60)
self.assertEqual(summary["between_distance_count"], 75)
self.assertEqual(summary["pair_count"], 15)
self.assertEqual(summary["pairwise_separation_pass_count"], 15)
self.assertTrue(all(row["within_distance_count"] == 20 and row["between_distance_count"] == 5 for row in summary["pairs"]))
def test_silent_is_not_pass(self):
summary = summarize_mode(ORIGINAL_MODES[0], list(map(str, range(6))), ORIGINAL_SEEDS, synthetic_runs(True), GATES)
self.assertFalse(summary["gate"])
self.assertFalse(summary["conditions"]["minimum_strictly_positive"])
self.assertFalse(summary["conditions"]["same_jaccard_gt_different"])
self.assertFalse(summary["conditions"]["different_euclidean_gt_same"])
self.assertEqual(summary["pairwise_separation_pass_count"], 0)
self.assertIsNone(summary["actual_event_count_cv"])
def test_every_original_conjunct_is_necessary(self):
baseline = summarize_mode(ORIGINAL_MODES[0], list(map(str, range(6))), ORIGINAL_SEEDS, synthetic_runs(), GATES)
changes = (("KC_active_fraction_mean", .029), ("KC_active_fraction_mean", .091),
("KC_active_fraction_max", .5), ("KC_active_fraction_min", 0.),
("same_odor_jaccard_mean", baseline["different_odor_jaccard_mean"]),
("different_odor_euclidean_mean", baseline["same_odor_euclidean_mean"]),
("pairwise_separation_pass_count", 2))
for key, value in changes:
with self.subTest(key=key, value=value):
modified = dict(baseline, **{key: value})
self.assertFalse(all(evaluate_gates(modified, GATES).values()))
for value in (.03, .09):
self.assertTrue(evaluate_gates(dict(baseline, KC_active_fraction_mean=value), GATES)["mean_sparsity_in_closed_interval"])
def test_pair_specific_not_global_baseline(self):
runs = synthetic_runs()
mode = ORIGINAL_MODES[0]
for odor in range(6):
for index, seed in enumerate(ORIGINAL_SEEDS):
counts = np.array([index + odor * 100] if odor < 2 else [10000 * odor + index * 1000], dtype=np.int32)
runs[(mode, str(odor), seed)]["kc_counts"] = counts
summary = summarize_mode(mode, list(map(str, range(6))), ORIGINAL_SEEDS, runs, GATES)
first_pair = summary["pairs"][0]
self.assertEqual(first_pair["within_this_pair_mean"], 2.)
self.assertEqual(first_pair["between_same_seed_mean"], 100.)
self.assertTrue(first_pair["gate"])
self.assertGreater(summary["same_odor_euclidean_mean"], 100.)
def test_original_metric_zero_and_count_semantics(self):
zero = np.zeros(3, dtype=np.int32)
self.assertEqual(pair_metrics(zero, zero)["active_jaccard"], 1.)
self.assertEqual(pair_metrics(zero, zero)["correlation"], 1.)
result = pair_metrics(np.array([2, 0, 0]), np.array([1, 0, 0]))
self.assertEqual(result["euclidean_distance"], 1.)
self.assertEqual(result["active_jaccard"], 1.)
self.assertAlmostEqual(sample_cv([1., 2., 3.]), .5)
def test_repeat_comparison_is_bits_and_dtype(self):
self.assertFalse(arrays_bitwise_equal(np.array([0.], np.float64), np.array([-0.], np.float64)))
self.assertFalse(arrays_bitwise_equal(np.array([1], np.int32), np.array([1], np.int64)))
self.assertTrue(arrays_bitwise_equal(np.array([1.], np.float32), np.array([1.], np.float32)))
def test_exact_repeat_covers_all_recorded_semantics(self):
first = {"state": {name: np.zeros(1, dtype) for name, dtype in STATE_DTYPES.items()},
"apl": {name: np.zeros((1, width), np.float32) for name, width in APL_FILES.items()},
"hashes": [{"tick": 0}], "queues": [{"tick": 0}],
"requests": [], "component": {"environment": {"tf32": False}}}
self.assertTrue(exact_repeat(first, copy.deepcopy(first))["pass_all"])
for category in ("state", "apl"):
for name in first[category]:
bad = copy.deepcopy(first)
bad[category][name].flat[0] = 1
with self.subTest(category=category, name=name):
self.assertFalse(exact_repeat(first, bad)["pass_all"])
for key in ("hashes", "queues", "requests", "component"):
bad = copy.deepcopy(first)
bad[key] = {} if isinstance(first[key], list) else []
with self.subTest(key=key):
self.assertFalse(exact_repeat(first, bad)["pass_all"])
def test_raw_state_rejects_nonfinite_duplicate_and_wrong_counts(self):
state = {"step": np.array([0], np.int32), "neuron_idx": np.array([1], np.int32),
"counts": np.array([0, 1], np.int32), "v": np.zeros(2, np.float64),
"g": np.zeros(2, np.float64), "ref": np.zeros(2, np.int32)}
validate_state(state, 2, 10)
for mutation in ("nan", "counts", "duplicate", "wrong_dtype"):
bad = copy.deepcopy(state)
if mutation == "nan": bad["g"][0] = np.nan
if mutation == "counts": bad["counts"][0] = 1
if mutation == "duplicate":
bad["step"] = np.array([0, 0], np.int32)
bad["neuron_idx"] = np.array([1, 1], np.int32)
bad["counts"][1] = 2
if mutation == "wrong_dtype": bad["v"] = bad["v"].astype(np.float32)
with self.subTest(mutation=mutation), self.assertRaises(ValueError):
validate_state(bad, 2, 10)
def test_inventory_rejects_missing_duplicate_or_heldout_identity(self):
odors = sorted(ORIGINAL_CAL_IDS)
records = [{"name": f"cal-{mode}-{index:02d}-s{seed}", "mode": mode, "odor_index": index,
"odor_id": odors[index], "seed": seed} for mode in ORIGINAL_MODES
for index in range(6) for seed in ORIGINAL_SEEDS]
cfg = {"calibration": {"modes": list(ORIGINAL_MODES), "seeds": list(ORIGINAL_SEEDS),
"duration_ms": 100., "odor_count": 6, "split": "calibration", "repeat_first_seed_each_odor": True}, "gates": GATES}
self.assertEqual(validate_inventory(records, cfg), odors)
for malformed in (records[:-1], records[:-1] + [records[0]],
[dict(row, odor_id="heldout") if row["odor_index"] == 0 else row for row in records]):
with self.assertRaises(ValueError):
validate_inventory(malformed, cfg)
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,266 @@
"""Local/remote pure protocol tests; no Brian, Torch, GPU or network execution.
Run with the already-provisioned Python and ``-B test_protocol.py``. The
sidecar process is mocked with in-memory stdin and an anonymous stdout pipe.
These tests validate transport and declared arithmetic/input contracts, not
the scientific trajectory or independent correctness of the Torch component.
"""
from __future__ import annotations
import hashlib
import io
import json
import math
import os
from pathlib import Path
import struct
import sys
import threading
import types
import unittest
from unittest import mock
import numpy as np
HERE = Path(__file__).resolve().parent
def load_no_cache(path, name):
module = types.ModuleType(name)
module.__file__ = str(path)
exec(compile(path.read_bytes(), str(path), "exec"), module.__dict__)
return module
ORACLE = load_no_cache(HERE / "oracle_apl.py", "phase4ag_protocol_oracle")
def handshake(**updates):
result = {"ok": True, "protocol": "phase4ag-apl-v1", "n_neurons": 166700,
"n_apl": 2, "n_kc": 4064, "dt_ms": .1,
"files_sha256": {name: "frozen-test-hash" for name in ORACLE.BUNDLE_FILES},
"decay_f32_bits": f"{int(np.float32(math.exp(-.1 / 20.)).view(np.uint32)):08x}",
"gain_f32_bits": f"{int(np.float32(.01).view(np.uint32)):08x}"}
result.update(updates)
return (json.dumps(result) + "\n").encode("utf-8")
def frame(tick=0, values=None, byte_count=None):
values = np.arange(4068, dtype="<f4") if values is None else np.asarray(values, dtype="<f4")
count = values.nbytes if byte_count is None else byte_count
return struct.pack("<qQ", tick, count) + values.tobytes()
class MemoryInput(io.BytesIO):
def close(self):
if not self.closed:
self.closed_data = self.getvalue()
super().close()
class FakeProcess:
"""The only use of OS descriptors is an anonymous read-only response pipe."""
def __init__(self, response, status=0, chunk_size=97):
read_fd, write_fd = os.pipe()
self.stdin = MemoryInput()
self.stdout = os.fdopen(read_fd, "rb", buffering=0)
self.status = status
self.terminated = False
def write_response():
try:
for begin in range(0, len(response), chunk_size):
view = memoryview(response[begin:begin + chunk_size])
while view:
view = view[os.write(write_fd, view):]
except (BrokenPipeError, OSError):
# Invalid-response tests deliberately close the reader early.
pass
finally:
os.close(write_fd)
self.thread = threading.Thread(target=write_response, daemon=True)
self.thread.start()
def poll(self):
return self.status
def wait(self, timeout=None):
return self.status
def terminate(self):
self.terminated = True
def kill(self):
self.terminated = True
def close(self):
if not self.stdin.closed:
self.stdin.close()
if not self.stdout.closed:
self.stdout.close()
self.thread.join(timeout=2)
class ProtocolTests(unittest.TestCase):
def create_worker(self, response, status=0):
process = FakeProcess(response, status=status)
self.addCleanup(process.close)
source_patch = mock.patch.object(ORACLE, "_digest", return_value="frozen-test-hash")
process_patch = mock.patch.object(ORACLE.subprocess, "Popen", return_value=process)
source_patch.start()
process_mock = process_patch.start()
self.addCleanup(source_patch.stop)
self.addCleanup(process_patch.stop)
worker = ORACLE._APLWorker(Path("science-python"), Path("legacy_apl_worker.py"), Path("bundle"), None, timeout=2)
self.addCleanup(worker.abort)
return worker, process, process_mock
def test_exact_handshake_frame_and_clean_eof(self):
worker, process, process_mock = self.create_worker(handshake() + frame())
globals_ = np.array([1, 40, 166699], dtype=np.int32)
drive, state, inhibition = worker.step(0, globals_)
values = np.arange(4068, dtype=np.float32)
np.testing.assert_array_equal(drive, values[:2])
np.testing.assert_array_equal(state, values[2:4])
np.testing.assert_array_equal(inhibition, values[4:])
request = process.stdin.getvalue()
self.assertEqual(struct.unpack("<qQ", request[:16]), (0, 3))
np.testing.assert_array_equal(np.frombuffer(request[16:], dtype="<i4"), globals_)
self.assertEqual(worker.finish(1), 0)
command = process_mock.call_args.args[0]
self.assertEqual(command, ["science-python", "-B", "legacy_apl_worker.py", "--bundle-dir", "bundle", "--dt-ms", "0.1"])
self.assertFalse(process_mock.call_args.kwargs["shell"])
def test_empty_spike_frame_still_advances_one_tick(self):
worker, process, _ = self.create_worker(handshake() + frame(values=np.zeros(4068, np.float32)))
arrays = worker.step(0, np.empty(0, np.int32))
self.assertTrue(all(np.all(value == 0) for value in arrays))
self.assertEqual(process.stdin.getvalue(), struct.pack("<qQ", 0, 0))
self.assertEqual(worker.finish(1), 0)
def test_two_consecutive_ticks(self):
worker, _, _ = self.create_worker(handshake() + frame(0) + frame(1))
worker.step(0, np.array([4], np.int32))
worker.step(1, np.array([8, 10], np.int32))
self.assertEqual(worker.finish(2), 0)
def test_rejects_wrong_protocol_or_dimensions(self):
for update in ({"protocol": "other"}, {"ok": False}, {"n_neurons": 42},
{"n_kc": 3}, {"dt_ms": .2}, {"gain_f32_bits": "00000000"},
{"files_sha256": {}}):
with self.subTest(update=update):
with self.assertRaises(ValueError):
self.create_worker(handshake(**update))
def test_rejects_wrong_tick_or_payload_length(self):
for response in (frame(tick=1), frame(byte_count=8)):
with self.subTest(response_header=response[:16]):
worker, _, _ = self.create_worker(handshake() + response)
with self.assertRaises(ValueError):
worker.step(0, np.empty(0, np.int32))
def test_rejects_truncated_response(self):
worker, _, _ = self.create_worker(handshake() + frame()[:-1])
with self.assertRaises(EOFError):
worker.step(0, np.empty(0, np.int32))
def test_rejects_nonfinite_or_negative_apl_payload(self):
for bad_value in (np.nan, np.inf, -1):
with self.subTest(value=bad_value):
values = np.zeros(4068, np.float32)
values[-1] = bad_value
worker, _, _ = self.create_worker(handshake() + frame(values=values))
with self.assertRaises(ValueError):
worker.step(0, np.empty(0, np.int32))
def test_rejects_invalid_spike_dtype_order_and_range(self):
for values in (np.array([1], np.int64), np.array([2, 1], np.int32),
np.array([1, 1], np.int32), np.array([-1], np.int32),
np.array([166700], np.int32)):
with self.subTest(values=values):
worker, process, _ = self.create_worker(handshake() + frame())
with self.assertRaises(ValueError):
worker.step(0, values)
self.assertEqual(process.stdin.getvalue(), b"")
def test_rejects_skipped_request_tick(self):
worker, process, _ = self.create_worker(handshake() + frame())
with self.assertRaises(ValueError):
worker.step(1, np.empty(0, np.int32))
self.assertEqual(process.stdin.getvalue(), b"")
def test_rejects_failed_exit_and_trailing_stdout(self):
for suffix, status in ((b"", 7), (b"unexpected", 0)):
with self.subTest(status=status, suffix=suffix):
worker, _, _ = self.create_worker(handshake() + frame() + suffix, status=status)
worker.step(0, np.empty(0, np.int32))
with self.assertRaises(ValueError):
worker.finish(1)
def test_pipe_reader_timeout(self):
read_fd, write_fd = os.pipe()
stream = os.fdopen(read_fd, "rb", buffering=0)
reader = ORACLE._PipeReader(stream, .05)
try:
with self.assertRaises(TimeoutError):
reader.read(1)
finally:
os.close(write_fd)
reader.thread.join(timeout=2)
stream.close()
self.assertFalse(reader.thread.is_alive())
class ArithmeticAndIdentityContractTests(unittest.TestCase):
def test_si_conversion_must_follow_float64_promotion(self):
h32 = np.array([.01, 1 / 7, 123.456], dtype=np.float32)
correct = h32.astype(np.float64) * np.float64(.001)
early_conversion = (h32 * np.float32(.001)).astype(np.float64)
self.assertFalse(np.array_equal(correct.view(np.uint64), early_conversion.view(np.uint64)))
for actual, original in zip(correct, h32):
self.assertEqual(actual.hex(), (float(original) * float(.001)).hex())
def test_declared_overlay_does_not_guard_refractory_targets(self):
before = np.array([0, -.002, .001], dtype=np.float64)
refractory = np.array([22, 21, 0], dtype=np.int32)
h32 = np.array([1, 2, 3], dtype=np.float32)
delta = h32.astype(np.float64) * np.float64(.001)
after = before - delta
self.assertTrue(np.all(after != before))
np.testing.assert_array_equal(refractory, [22, 21, 0])
self.assertEqual(after[0], -.001)
def test_af_queue_hash_keeps_original_noncontiguous_ids_and_rejections(self):
path = HERE.parent / "author-fullgraph-lab-v1" / "oracle_full.py"
self.assertEqual(hashlib.sha256(path.read_bytes()).hexdigest(), ORACLE.AF_SHA256)
af = load_no_cache(path, "phase4ag_protocol_af")
edges = np.array([81, 2, 500], dtype=np.int64)
accepted = np.array([1, 0, 1], dtype=np.uint8)
original_edges, original_mask = edges.copy(), accepted.copy()
result = af.queue_summary(18, edges, accepted, chunk_bytes=8)
packet = b"phase4af-queue-v1\0" + struct.pack("<qq", 18, 3) + edges.astype("<i8").tobytes() + accepted.tobytes()
self.assertEqual(result["joint_sha256"], hashlib.sha256(packet).hexdigest())
self.assertEqual((result["count"], result["accepted_count"]), (3, 2))
self.assertEqual(result, af.queue_summary(18, edges, accepted, chunk_bytes=8192))
np.testing.assert_array_equal(edges, original_edges)
np.testing.assert_array_equal(accepted, original_mask)
def test_empty_queue_hash_includes_tick(self):
af = load_no_cache(HERE.parent / "author-fullgraph-lab-v1" / "oracle_full.py", "phase4ag_empty_af")
first = af.queue_summary(0, np.empty(0, np.int64), np.empty(0, np.uint8))
second = af.queue_summary(1, np.empty(0, np.int64), np.empty(0, np.uint8))
self.assertEqual(first["ordered_edge_sha256"], hashlib.sha256(b"").hexdigest())
self.assertNotEqual(first["joint_sha256"], second["joint_sha256"])
def test_oracle_import_has_no_brian_or_torch_dependency(self):
before = set(sys.modules)
load_no_cache(HERE / "oracle_apl.py", "phase4ag_second_import")
added = set(sys.modules) - before
self.assertFalse(any(name == "brian2" or name.startswith("brian2.") or
name == "torch" or name.startswith("torch.") for name in added))
if __name__ == "__main__":
unittest.main(verbosity=2)
@@ -0,0 +1,431 @@
"""Independent extraction/replay of the frozen legacy APL component.
Only the initializer prefix before ``self.base`` and two original APL update
statements are executed. No old simulator is instantiated, no learning code is
executed, and no frozen artifact is written. The Torch replay is a component
oracle, not an independent CPU whole-brain closed-loop oracle.
"""
from __future__ import annotations
import argparse
import ast
import copy
from functools import lru_cache
import hashlib
import json
import math
from pathlib import Path
import struct
import types
import numpy as np
import pyarrow.parquet as pq
import torch
ROOT = Path('/data/digital-drosophila')
CANONICAL = ROOT/'datasets/male-cns-v1.0/processed/neuron-only'
SOURCE = ROOT/'models/male-cns-lif/deterministic-runtime-v2/phase4p_revalidate.py'
SOURCE_SHA256 = 'c7e693a2da70acdce4f53af5c2853e52e8333acc93f88a46a5e8083eac639346'
N, A, K = 166700, 2, 4064
BUNDLE_ARRAYS = {
'input_matrix': (np.float32, (A, N)), 'output_matrix': (np.float32, (A, K)),
'input_raw': (np.float32, (A, N)), 'output_raw': (np.float32, (A, K)),
'kc_globals': (np.int32, (K,)), 'apl_globals': (np.int32, (A,)),
'pn_globals': (np.int32, None), 'apl_out_ids': (np.int64, (5845,)),
}
def require(condition, message):
if not condition:
raise ValueError(message)
def digest(path):
h = hashlib.sha256()
with Path(path).open('rb') as source:
for block in iter(lambda: source.read(8 << 20), b''):
h.update(block)
return h.hexdigest()
def array_hash(value):
return hashlib.sha256(np.ascontiguousarray(value).tobytes()).hexdigest()
def bit_equal(a, b):
a, b = np.asarray(a), np.asarray(b)
return bool(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)))
def save(path, value):
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
with path.open('x', encoding='utf-8') as target:
json.dump(value, target, indent=2, sort_keys=True, allow_nan=False)
target.write('\n')
class ReadOnlyNamespace:
"""The extracted prefix can read rt, but cannot mutate or add rt fields."""
def __init__(self, **values):
object.__setattr__(self, '_values', types.MappingProxyType(values))
def __getattr__(self, name):
return self._values[name]
def __setattr__(self, name, value):
raise AttributeError('Read-only canonical runtime view')
def _code(nodes, filename):
module = ast.Module(body=copy.deepcopy(nodes), type_ignores=[])
return compile(ast.fix_missing_locations(module), str(filename), 'exec')
def _self_attribute(target, field):
return isinstance(target, ast.Attribute) and isinstance(target.value, ast.Name) and \
target.value.id == 'self' and target.attr == field
def extract_statements():
data = SOURCE.read_bytes()
require(hashlib.sha256(data).hexdigest() == SOURCE_SHA256, 'Frozen legacy source SHA-256 mismatch')
text = data.decode('utf-8')
tree = ast.parse(text, filename=str(SOURCE))
classes = [node for node in tree.body if isinstance(node, ast.ClassDef) and node.name == 'DeterministicAPLSim']
require(len(classes) == 1, 'Expected exactly one frozen DeterministicAPLSim')
methods = {node.name: node for node in classes[0].body if isinstance(node, ast.FunctionDef)}
init, run = methods['__init__'], methods['run']
cuts = [i for i, node in enumerate(init.body) if isinstance(node, ast.Assign) and
any(_self_attribute(target, 'base') for target in node.targets)]
require(len(cuts) == 1 and cuts[0] > 0, 'Missing/ambiguous self.base cutoff')
prefix = init.body[:cuts[0]]
# Executing no import or file-writing call is allowed in the extracted prefix.
require(not any(isinstance(node, (ast.Import, ast.ImportFrom, ast.With, ast.AsyncWith))
for stmt in prefix for node in ast.walk(stmt)), 'Unexpected side-effect construct in initializer prefix')
expressions = [node for node in ast.walk(run) if isinstance(node, ast.Expr) and
isinstance(node.value, ast.Call) and isinstance(node.value.func, ast.Attribute) and
node.value.func.attr == 'add_' and isinstance(node.value.func.value, ast.Call) and
isinstance(node.value.func.value.func, ast.Attribute) and
isinstance(node.value.func.value.func.value, ast.Name) and
node.value.func.value.func.value.id == 'apl_state' and node.value.func.value.func.attr == 'mul_']
inhibition = [node for node in ast.walk(run) if isinstance(node, ast.Assign) and
any(isinstance(target, ast.Name) and target.id == 'inhibition' for target in node.targets)]
decay = [node for node in ast.walk(run) if isinstance(node, ast.Assign) and
any(isinstance(target, ast.Name) and target.id == 'apl_decay' for target in node.targets)]
require(len(expressions) == len(inhibition) == len(decay) == 1, 'Ambiguous frozen APL operator extraction')
require(expressions[0].lineno < inhibition[0].lineno, 'Unexpected frozen APL update order')
rhs = inhibition[0].value
require(isinstance(rhs, ast.BinOp) and isinstance(rhs.op, ast.Mult), 'Unexpected inhibition gain expression')
gain_expression = ast.Expression(copy.deepcopy(rhs.right))
provenance = {'source': str(SOURCE), 'sha256': SOURCE_SHA256,
'initializer_line_start': prefix[0].lineno, 'initializer_line_end': prefix[-1].end_lineno,
'excluded_self_base_line': init.body[cuts[0]].lineno,
'decay_line': decay[0].lineno, 'state_update_line': expressions[0].lineno,
'inhibition_line': inhibition[0].lineno,
'initializer_source': '\n'.join(ast.get_source_segment(text, node) for node in prefix),
'decay_source': ast.get_source_segment(text, decay[0]),
'state_update_source': ast.get_source_segment(text, expressions[0]),
'inhibition_source': ast.get_source_segment(text, inhibition[0]),
'learning_initializer_suffix_executed': False, 'original_run_loop_executed': False}
return (_code(prefix, SOURCE), _code(decay, SOURCE),
_code([expressions[0], inhibition[0]], SOURCE),
compile(ast.fix_missing_locations(gain_expression), str(SOURCE), 'eval'), provenance)
def _canonical_files():
return {name: CANONICAL/path for name, path in {
'metadata': 'neuron-index/unified-metadata.parquet',
'indptr': 'gpu/csr-indptr.int64.npy', 'indices': 'gpu/csr-indices.int32.npy',
'raw': 'gpu/csr-weights.int64.npy'}.items()}
@lru_cache(maxsize=2)
def reconstruct(canonical_hashes, device_name):
"""Cache only reconstructions tied to exact canonical bytes and source hash."""
files = _canonical_files()
require(dict(canonical_hashes) == {name: digest(path) for name, path in files.items()},
'Canonical bytes changed before matrix reconstruction')
arrays = {name: np.load(files[name], mmap_mode='r', allow_pickle=False)
for name in ('indptr', 'indices', 'raw')}
require(arrays['indptr'].dtype == np.int64 and arrays['indices'].dtype == np.int32 and
arrays['raw'].dtype == np.int64, 'Canonical CSR dtypes changed')
require(arrays['indptr'].shape == (N + 1,) and arrays['indptr'][-1] == 25582938 and
arrays['indices'].shape == arrays['raw'].shape == (25582938,), 'Canonical graph shape changed')
require(int(arrays['raw'].sum()) == 124177617 and bool(np.all(arrays['raw'] > 0)), 'Canonical raw weights changed')
table = pq.read_table(files['metadata'])
require(table.num_rows == N, 'Canonical metadata count changed')
rt = ReadOnlyNamespace(n=N, dt=.1, device=torch.device(device_name), table=table,
indptr_np=arrays['indptr'], indices_np=arrays['indices'], raw_np=arrays['raw'])
view = types.SimpleNamespace()
init_code, decay_code, update_code, gain_code, provenance = extract_statements()
scope = {'self': view, 'rt': rt, 'np': np, 'torch': torch}
exec(init_code, scope)
require(not hasattr(view, 'base') and not hasattr(view, 'identity'), 'Initializer crossed the learning cutoff')
expected = {'input_matrix': view.input_gpu.detach().cpu().numpy().copy(),
'output_matrix': view.output_gpu.detach().cpu().numpy().copy(),
'input_raw': scope['input_matrix'], 'output_raw': scope['output_matrix'],
'kc_globals': view.kc, 'apl_globals': view.apl, 'pn_globals': view.pn,
'apl_out_ids': view.apl_out_ids}
for value in expected.values():
value.flags.writeable = False
return view, expected, provenance, (decay_code, update_code, gain_code)
class TorchObservationProxy:
"""Observe the result of the actual extracted torch.mv call unchanged."""
def __init__(self):
self.drive = None
self.calls = 0
def __getattr__(self, name):
return getattr(torch, name)
def mv(self, *args, **kwargs):
value = torch.mv(*args, **kwargs)
self.drive = value
self.calls += 1
return value
def _up(value):
return np.nextafter(np.asarray(value, dtype=np.float64), np.inf)
def _add(a, b):
return _up(np.asarray(a, dtype=np.float64) + np.asarray(b, dtype=np.float64))
def _mul(a, b):
return _up(np.asarray(a, dtype=np.float64) * np.asarray(b, dtype=np.float64))
def _gamma(count, unit_roundoff):
require(count * unit_roundoff < 1, 'Gamma bound is undefined')
# Outward rounding on the division; the denominator is rounded downward.
numerator = _mul(count, unit_roundoff)
denominator = np.nextafter(1.0 - numerator, -np.inf)
return _up(numerator / denominator)
def _positive_dot_upper(state, matrix):
result = np.zeros(matrix.shape[1], np.float64)
for index in range(len(state)):
result = _add(result, _mul(state[index], matrix[index]))
return result
def _normal_or_zero(value, tiny):
value = np.asarray(value)
return bool(np.all((value == 0) | (value >= tiny)))
def _new_metric():
return {'max_abs_error': 0.0, 'sum_abs_error': 0.0, 'elements': 0,
'max_relative_error_nonzero_reference': 0.0, 'zero_reference_nonzero_actual': 0,
'max_error_bound': 0.0, 'max_bound_utilization': 0.0, 'bound_violations': 0}
def _accumulate(metric, actual, reference, bound):
error = np.abs(np.asarray(actual, np.float64) - reference)
error_upper = np.where(error == 0, 0.0, _up(error))
nonzero = reference != 0
ratio = np.divide(error, np.abs(reference), out=np.zeros_like(error), where=nonzero)
usage = np.divide(error_upper, bound, out=np.zeros_like(error), where=bound > 0)
metric['max_abs_error'] = max(metric['max_abs_error'], float(error.max(initial=0)))
metric['sum_abs_error'] += float(error.sum(dtype=np.float64))
metric['elements'] += error.size
metric['max_relative_error_nonzero_reference'] = max(metric['max_relative_error_nonzero_reference'], float(ratio.max(initial=0)))
metric['zero_reference_nonzero_actual'] += int(np.count_nonzero((~nonzero) & (error != 0)))
metric['max_error_bound'] = max(metric['max_error_bound'], float(np.max(bound, initial=0)))
metric['max_bound_utilization'] = max(metric['max_bound_utilization'], float(usage.max(initial=0)))
metric['bound_violations'] += int(np.count_nonzero(error_upper > bound))
def validate(gpu_case_dir, bundle_dir, out_json):
"""Validate one completed fixture; write one exclusive pure-JSON audit."""
gpu_case_dir, bundle_dir, out_json = Path(gpu_case_dir), Path(bundle_dir), Path(out_json)
require(not out_json.exists(), 'Refusing to overwrite an existing component audit')
report = {'pass_all': False, 'scope': 'Frozen APL component extraction and recorded-spike replay only',
'independent_cpu_closed_loop_oracle': False, 'brain_or_learning_parameters_changed': False,
'candidate_function_called': False, 'gpu_case_dir': str(gpu_case_dir), 'bundle_dir': str(bundle_dir)}
try:
require(digest(SOURCE) == SOURCE_SHA256, 'Frozen source changed before component validation')
require(torch.cuda.is_available() and torch.cuda.device_count() == 1 and
'4090' in torch.cuda.get_device_name(), 'Require the one declared RTX4090')
environment = {'torch': str(torch.__version__), 'numpy': np.__version__,
'gpu': torch.cuda.get_device_name(), 'cuda': torch.version.cuda,
'cuda_matmul_allow_tf32': torch.backends.cuda.matmul.allow_tf32,
'float32_matmul_precision': torch.get_float32_matmul_precision(),
'deterministic_algorithms': torch.are_deterministic_algorithms_enabled(),
'precision_flags_changed': False}
report['environment'] = environment
canonical_hashes = tuple(sorted((name, digest(path)) for name, path in _canonical_files().items()))
view, reconstructed, provenance, code = reconstruct(canonical_hashes, 'cuda:0')
bundle = {}
matrix_checks = {}
for name, (dtype, shape) in BUNDLE_ARRAYS.items():
value = np.load(bundle_dir/(name+'.npy'), mmap_mode='r', allow_pickle=False)
require(value.dtype == dtype and value.ndim == len(shape or (0,)) and
(shape is None or value.shape == shape), 'Bundle schema mismatch: '+name)
bundle[name] = value
matrix_checks[name] = bit_equal(value, reconstructed[name])
scales = json.loads((bundle_dir/'scales.json').read_text())
for name in ('input_scale', 'output_scale'):
matrix_checks[name] = struct.pack('<d', float(scales[name])) == struct.pack('<d', float(getattr(view, name)))
report['matrix_checks'] = matrix_checks
report['extracted_source'] = provenance
report['canonical_sha256'] = dict(canonical_hashes)
report['bundle_sha256'] = {name+'.npy': digest(bundle_dir/(name+'.npy')) for name in BUNDLE_ARRAYS}
report['bundle_sha256']['scales.json'] = digest(bundle_dir/'scales.json')
report['reconstructed_array_sha256'] = {name: array_hash(value) for name, value in reconstructed.items()}
bundle_provenance = json.loads((bundle_dir/'provenance.json').read_text())
require(Path(bundle_provenance['canonical_root']).resolve() == CANONICAL.resolve(),
'Bundle provenance names another canonical dataset')
report['bundle_sha256']['provenance.json'] = digest(bundle_dir/'provenance.json')
require(all(matrix_checks.values()), 'Bundle differs from the actual frozen initializer prefix')
traces = {name: np.load(gpu_case_dir/('apl-'+name+'.float32.npy'), mmap_mode='r', allow_pickle=False)
for name in ('drive', 'state', 'inhibition')}
steps = len(traces['state'])
require(steps > 0, 'Empty APL trajectory cannot pass')
for name, width in (('drive', A), ('state', A), ('inhibition', K)):
require(traces[name].dtype == np.float32 and traces[name].shape == (steps, width) and
bool(np.isfinite(traces[name]).all()) and bool(np.all(traces[name] >= 0)), 'Invalid APL trace: '+name)
summary = json.loads((gpu_case_dir/'summary.json').read_text())
require(summary.get('complete') is True and summary.get('pass_all') is True and
summary.get('steps') == steps and summary.get('completed_ticks') == steps,
'GPU fixture did not complete its internal execution checks')
with np.load(gpu_case_dir/'state.npz', allow_pickle=False) as archive:
event_step, event_node = archive['step'].copy(), archive['neuron_idx'].copy()
require(event_step.dtype == event_node.dtype == np.int32 and event_step.ndim == 1 and
event_step.shape == event_node.shape, 'Invalid sparse actual spike event schema')
require(bool(np.all((event_step >= 0) & (event_step < steps))) and
bool(np.all((event_node >= 0) & (event_node < N))), 'Sparse event outside its clock/identity range')
require(np.array_equal(np.lexsort((event_node, event_step)), np.arange(len(event_step))), 'Actual events not sorted')
keys = event_step.astype(np.int64)*N + event_node
require(len(keys) < 2 or bool(np.all(np.diff(keys) > 0)), 'Duplicate actual spikes')
boundaries = np.searchsorted(event_step, np.arange(steps + 1))
proxy = TorchObservationProxy()
# Reconstructed original matrices are already on the original GPU/dtype.
replay_rt = types.SimpleNamespace(spike_u8=torch.zeros(N, dtype=torch.uint8, device=view.device))
shadow = types.SimpleNamespace(input_gpu=view.input_gpu, output_gpu=view.output_gpu, rt=replay_rt, dt=.1)
scope = {'self': shadow, 'np': np, 'math': math, 'torch': proxy,
'apl_state': torch.zeros(A, dtype=torch.float32, device=view.device)}
decay_code, update_code, gain_code = code
exec(decay_code, scope)
decay32 = np.float32(scope['apl_decay'])
gain32 = np.float32(eval(gain_code, {'np': np}))
require(0 < decay32 < 1 and gain32 > 0, 'Invalid extracted positive APL constants')
exact = {name: True for name in traces}
first_difference = None
I64 = np.asarray(bundle['input_matrix'], np.float64)
O64 = np.asarray(bundle['output_matrix'], np.float64)
require(bool(np.all(I64 >= 0)) and bool(np.all(O64 >= 0)), 'Positive-sum theory requires nonnegative matrices')
d, q = float(decay32), float(gain32)
u32, u64 = 2.0**-24, 2.0**-53
gd32, gd64 = _gamma(N-1, u32), _gamma(N-1, u64)
g232, g264 = _gamma(2, u32), _gamma(2, u64)
gh32, gh64 = _gamma(2*A+1, u32), _gamma(2*A+1, u64)
state64 = np.zeros(A, np.float64)
e32 = np.zeros(A, np.float64)
e64 = np.zeros(A, np.float64)
previous32 = np.zeros(A, np.float64)
statistics = {name: _new_metric() for name in traces}
normal_arithmetic = _normal_or_zero(I64, np.finfo(np.float32).tiny) and _normal_or_zero(O64, np.finfo(np.float32).tiny)
max_active_terms = 0
with torch.no_grad():
for tick in range(steps):
fired = event_node[boundaries[tick]:boundaries[tick+1]]
replay_rt.spike_u8.zero_()
if len(fired):
replay_rt.spike_u8[torch.as_tensor(fired.astype(np.int64), device=view.device)] = 1
before_calls = proxy.calls
exec(update_code, scope)
require(proxy.calls == before_calls + 1, 'Original update did not issue exactly one mv')
actual = {'drive': proxy.drive.detach().cpu().numpy(),
'state': scope['apl_state'].detach().cpu().numpy(),
'inhibition': scope['inhibition'].detach().cpu().numpy()}
for name in traces:
same = bit_equal(actual[name], traces[name][tick])
exact[name] &= same
if not same and first_difference is None:
first_difference = {'tick': tick, 'field': name,
'max_abs_error': float(np.max(np.abs(actual[name].astype(np.float64)-traces[name][tick])))}
# Float64 reference is measurement only and never feeds either brain.
selected = I64[:, fired]
drive64 = selected.sum(axis=1, dtype=np.float64)
max_active_terms = max(max_active_terms, int(np.count_nonzero(selected, axis=1).max(initial=0)))
Dupper = _up(drive64 / np.nextafter(1.0-gd64, -np.inf))
drive_bound = _add(_mul(gd32, Dupper), _mul(gd64, Dupper))
state32 = traces['state'][tick].astype(np.float64)
normal_arithmetic &= _normal_or_zero(d*previous32, np.finfo(np.float32).tiny)
normal_arithmetic &= _normal_or_zero(O64*state32[:, None], np.finfo(np.float32).tiny)
e32 = _add(_mul(d, e32), _add(_mul(g232, _add(_mul(d, previous32), Dupper)),
_mul(1.0+u32, _mul(gd32, Dupper))))
e64 = _add(_mul(d, e64), _add(_mul(g264, _add(_mul(d, state64), Dupper)),
_mul(1.0+u64, _mul(gd64, Dupper))))
state64 = d*state64 + drive64
inhibition64 = np.matmul(state64, O64)*q
h32bound = _add(_mul(q, _positive_dot_upper(e32, O64)),
_mul(gh32, _mul(q, _positive_dot_upper(state32, O64))))
h64bound = _add(_mul(q, _positive_dot_upper(e64, O64)),
_mul(gh64, _mul(q, _positive_dot_upper(state64, O64))))
normal_arithmetic &= _normal_or_zero(q*np.matmul(state32, O64), np.finfo(np.float32).tiny)
_accumulate(statistics['drive'], traces['drive'][tick], drive64, drive_bound)
_accumulate(statistics['state'], traces['state'][tick], state64, _add(e32, e64))
_accumulate(statistics['inhibition'], traces['inhibition'][tick], inhibition64, _add(h32bound, h64bound))
previous32 = state32
for metric in statistics.values():
metric['mean_abs_error'] = metric.pop('sum_abs_error') / metric['elements']
theory_applicable = bool(normal_arithmetic and not environment['cuda_matmul_allow_tf32'] and
environment['float32_matmul_precision'] == 'highest')
report.update(steps=steps, actual_spike_events=len(event_step),
ast_replay_bitwise_exact=exact, first_ast_difference=first_difference,
value_units={'drive': 'legacy normalized-contact spike drive',
'state': 'legacy normalized-drive accumulator', 'inhibition': 'legacy mV'},
decay_f32_bits=f'{int(decay32.view(np.uint32)):08x}', gain_f32_bits=f'{int(gain32.view(np.uint32)):08x}',
float64_measurement=statistics,
theoretical_bound={'applicable': theory_applicable, 'normal_or_zero_arithmetic': bool(normal_arithmetic),
'gamma_definition': 'gamma_n=(n*u)/(1-n*u), upward-rounded; u32=2^-24,u64=2^-53',
'drive_n': N-1, 'max_observed_nonzero_drive_terms': max_active_terms,
'gamma_drive_f32': float(gd32), 'gamma_drive_f64': float(gd64),
'state_recurrence': 'E_p[t] <= d*E_p[t-1] + gamma_2,p*(d*abs(s_p[t-1])+D_upper) + (1+u_p)*gamma_(N-1),p*D_upper',
'output_bound': 'q*sum(B*E_p) + gamma_(2*A+1),p*q*sum(B*abs(s_p)); compare with E32+E64',
'assumptions': 'nonnegative f32 matrices, spikes exactly 0/1, fixed stored f32 decay/gain, normal finite RN binary32/64 operations; no reduced-precision matmul',
'bound_arithmetic': 'Each positive bound operation is rounded toward +infinity via nextafter; denominator toward -infinity',
'tolerance_fitted_to_observed_error': False,
'f64_values_used_to_drive_brain': False,
'no_cpu_gpu_bitwise_expectation_for_f64_measurement': True},
input_sha256={name: digest(gpu_case_dir/name) for name in
('state.npz', 'summary.json', 'apl-drive.float32.npy', 'apl-state.float32.npy', 'apl-inhibition.float32.npy')})
report['pass_all'] = bool(all(matrix_checks.values()) and all(exact.values()) and theory_applicable and
all(value['bound_violations'] == 0 for value in statistics.values()))
report['limitations'] = [
'AST shadow and candidate use the same original Torch/CUDA primitives; this validates preserved component semantics, not an independent CPU whole-brain oracle.',
'Float64 is a non-feedback mathematical measurement with explicit gamma error bounds, not replacement APL dynamics.',
'Replay uses the recorded actual spike train; it does not establish equivalence for untested closed-loop inputs.',
'The N-1 positive-sum bound is deliberately conservative; passing it does not prove physiological validity or learning.']
save(out_json, report)
return report
except Exception as error:
report['error'] = {'type': type(error).__name__, 'message': str(error)}
if not out_json.exists():
save(out_json, report)
raise
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('gpu_case_dir', type=Path)
parser.add_argument('bundle_dir', type=Path)
parser.add_argument('out_json', type=Path)
args = parser.parse_args()
result = validate(args.gpu_case_dir, args.bundle_dir, args.out_json)
print(json.dumps({'pass_all': result['pass_all'], 'steps': result['steps']}), flush=True)
if not result['pass_all']:
raise SystemExit(1)
@@ -0,0 +1,35 @@
"""Run old reference unchanged, writing only new experiment output."""
import os
import sys
import time
import numpy as np
import pandas as pd
import yaml
from context import ROOT,EXP,CFG,save,check
def main():
check();assert not (EXP/'regression/frozen-five.json').exists()
rtpath=ROOT/'models/male-cns-lif/deterministic-runtime-v2';pc=yaml.safe_load((rtpath/'phase4p.yaml').read_text())
os.environ['CUDA_VISIBLE_DEVICES']=CFG['gpu_uuid'];os.environ['CUDA_HOME']='/usr/local/cuda'
os.environ['PATH']=str(ROOT/'models/male-cns-lif/.venv/bin')+':/usr/local/cuda/bin:'+os.environ['PATH']
os.environ['MAX_JOBS']='2';os.environ['TORCH_CUDA_ARCH_LIST']='8.9'
sys.path.insert(0,str(ROOT/'models/male-cns-lif/terminal-scope-diagnostic-v1'))
from diagnostic import queues
queues();sys.path.insert(0,str(ROOT/'models/male-cns-lif'));sys.path.insert(0,str(rtpath))
import torch,phase4p
assert torch.cuda.mem_get_info()[0]>2*1024**3
torch.cuda.reset_peak_memory_stats();t0=time.perf_counter();rt=phase4p.CanonicalRuntime(pc,rtpath,EXP);rows=[]
for spec in pc['reference_trials']:
queues();base=ROOT/'experiments/phase4p-deterministic-runtime/phase4c-v2/reference'/spec['name']
ev=pd.read_parquet(base/'spike-events.parquet')
ref=dict(step=ev.step.to_numpy(),neuron_idx=ev.neuron_idx.to_numpy(),counts=np.load(base/'per-neuron-spike-counts.int32.npy'),v=np.load(base/'final-voltage.float32.npy'),g=np.load(base/'final-g.float32.npy'))
result=rt.run(np.flatnonzero(rt.pops[spec['population']]),spec['rate_hz'],spec['seed'],spec['duration_ms'])
row=dict(trial=spec['name'],exact={k:bool(np.array_equal(v,result[k])) for k,v in ref.items()},wall_seconds=result['metrics']['wall_seconds'])
rows.append(row);print(row,flush=True)
save(EXP/'regression/frozen-five.json',dict(pass_all=all(all(r['exact'].values()) for r in rows),trials=rows,
wall_seconds=time.perf_counter()-t0,peak_allocated_vram=int(torch.cuda.max_memory_allocated()),oracle='old frozen deterministic-v2 only'))
assert all(all(r['exact'].values()) for r in rows)
if __name__=='__main__':main()
@@ -0,0 +1,84 @@
# Phase4AG: author LIF + frozen legacy graded APL
Execution revision r2: the first registered v1 attempt stopped before the first
Brian tick because resolving the science-venv Python symlink launched system
Python without NumPy. All v1 files and partial outputs are preserved separately.
This revision retains the declared venv invocation path. It does not change any
equation, arithmetic, mask, stimulus, gate, parameter or choice of trial.
The complete original protocol is rerun from fresh state; no failed trial is
overwritten or omitted, and the first version cannot be claimed numerical PASS.
Authorized independent hypothesis branch. All old source, raw connectome, signs,
W_syn, APL calibration, eligibility-v2 and 14,232-edge mask remain read-only.
No learning, gain/threshold changes, new edges, top-K, heldout activity, game or RL.
Author code provenance is the already archived MIT-licensed
https://github.com/philshiu/Drosophila_brain_model at
91bdd1e7dcf193f3e7ca5a8933497fcef63b7960; original model.py SHA-256
fc45837d7122c6ce2a7f3f2f23c515992e4b232aadb919efabb72337fac88e4e.
Associated paper: https://www.nature.com/articles/s41586-024-07763-9.
This new MaleCNS/APL combination is not a strict reproduction of that model.
The declared combination is author float64 LIF plus the exact old float32 graded
APL operator after synapses/resets at end. All 5,845 original APL fast out-edges
are zeroed only in the effective in-memory model, as in the legacy overlay.
Only KC receives graded replacement; known 1,212 non-KC edges remain unreplaced.
This existing scope limitation is not silently repaired in a compatibility test.
Use the original full normalized I[2,166700]/O[2,4064] float32 bytes and original
normalizers, even for induced real subgraphs. APL reads actual binary spikes,
never requests, and keeps independent float32 state. Preserve unfused operations:
state.mul_(float(f32(exp(-.1/20)))).add_(torch.mv(I, spikes_f32));
h32=torch.matmul(state,O)*f32(.01). Promote h32 to float64, multiply by float64
.001, then separately subtract from SI g. Do not alter TF32/default CuBLAS flags;
record them. No added APL delay, drive dt/tau scaling, truncation or clipping.
APL writes KC g unconditionally after author reset, including refractory KC.
Author g integration is frozen during refractory; therefore negative overlay g
may accumulate and differs from old dynamics. This is an explicit hypothesis,
not an assertion of original author or measured physiology. Guarded writes or
reset-before/after changes would be different hypotheses, not fixes to this one.
Eight fixed metadata/connectivity-selected fixtures cover zero/reset, real PN/KC
drive, current actual event feedback, duplicate natural/request event, 18-step
arrival vs22-step refractory boundary, full fast APL mask, non-KC scope and mixed
precision/high fan-in. No choice is made from runtime responses. Each GPU case
has3 independent fresh runs. A Brian2 author oracle starts from its own state,
computes its own actual spikes, and uses an isolated standard-I/O legacy-APL
worker with independent state. No candidate inhibition trace is fed into Brian.
All tick states, events, requests, queue order/guard, APL drive/state/h must agree
exactly. The APL component is shared, so this is NOT a fully independent CPU
oracle. Independently reconstruct old matrices using frozen initializer AST,
replay actual events through original update AST, require exact component bytes;
also quantify an independent float64 positive-sum arithmetic error bound. It is
not a replacement for exact legacy equivalence. No arithmetic bound is adjusted.
Only after all fixture gates pass, run two predeclared full-graph probes: first
old calibration odor, first original seed, both encoder modes. Compare each with
the independently running Brian + isolated APL worker. Save state hashes and sparse
events, not a time-by-all-neurons dense spike matrix. If a numerical gate fails,
stop CAL; keep diagnostic evidence and do not widen tolerance.
Then run the complete original6 CAL odors ×5 original seeds ×2 original modes,
100ms per run. Retain the ORIGINAL12-odor median for matched-energy encoding,
original pn_drive target/RNG column order, original evaluation seeds51101..51105.
Save Poisson requests before any trajectory. Only calibration dynamic cases are
used; formal A/B and heldout remain unrun. Repeat first seed for every odor/mode.
No per-odor pulse, amplitude, timing or threshold search. No learning.
Recompute the full original4L representation criteria on CAL only: mean KC active
fraction .03..09, min>0, max<.5, same-odor Jaccard>different, between Euclidean>
within, >=3 pairs whose mean between exceeds THAT PAIR's pooled within distances,
both modes. Add finiteness and exact repeat requirements. CAL PASS does not imply
heldout generalization, timing/credit specificity, memory or learning usability.
If CAL fails stop promotion and report it, not a least-bad candidate.
Before/after verify SHA-256 of all original230239 files and AA--AF seals; rerun original five
deterministic reference trials to new output. Archive code/env/source SHA,
matrices/norms/masks/identities, requests and all outputs. No published candidate.
Technical references (queried2026-09-30): Brian2 2.5.1 refractory documentation
https://brian2.readthedocs.io/en/2.5.1/user/refractoriness.html (actual generated code
remains authoritative); PyTorch numerical accuracy notes
https://docs.pytorch.org/docs/2.14/notes/numerical_accuracy.html (cross-backend
floating operations are not assumed bitwise equivalent).
@@ -0,0 +1,396 @@
"""Complete original Phase 4L representation metrics on fixed CAL inputs only.
No simulation, fitting, heldout trajectory access, or candidate generation is
performed here. The original 4L pair-specific within-odor baseline is retained;
the weaker Phase 4P r4 aggregate gate is deliberately not used.
"""
import csv
import hashlib
import itertools
import json
from pathlib import Path
import re
import numpy as np
STATE_DTYPES = {"step": np.int32, "neuron_idx": np.int32, "counts": np.int32,
"v": np.float64, "g": np.float64, "ref": np.int32}
REQUEST_FIELDS = ("tick", "neuron_idx", "attempted", "accepted", "rejected")
APL_FILES = {"apl-drive.float32.npy": 2, "apl-state.float32.npy": 2,
"apl-inhibition.float32.npy": 4064}
ORIGINAL_CAL_IDS = {
"OMSUIQOIVADKIM-RXMQYKEDSA-N", "LABTWGUMFABVFG-ARJAWSKDSA-N",
"QNVRIHYSUZMSGM-ZCFIWIBFSA-N", "VLSVVMPLPMNWBH-UHFFFAOYSA-N",
"XHIUFYZDQBSEMF-UHFFFAOYSA-N", "OMSUIQOIVADKIM-YFKPBYRVSA-N"}
ORIGINAL_MODES = ("physiological", "matched_energy")
ORIGINAL_SEEDS = (51101, 51102, 51103, 51104, 51105)
HEX_SHA = re.compile(r"[0-9a-f]{64}\Z")
_DEFAULT_OUTPUT = object()
def require(condition, message):
if not condition:
raise ValueError(message)
def read_json(path):
with Path(path).open(encoding="utf-8") as stream:
return json.load(stream)
def file_hash(path):
digest = hashlib.sha256()
with Path(path).open("rb") as stream:
for block in iter(lambda: stream.read(8 << 20), b""):
digest.update(block)
return digest.hexdigest()
def raw_hash(value):
return hashlib.sha256(np.ascontiguousarray(value).tobytes()).hexdigest()
def arrays_bitwise_equal(first, second):
"""Unlike array_equal, also reject different dtypes and signed-zero bits."""
return bool(first.dtype == second.dtype and first.shape == second.shape and
np.array_equal(np.ascontiguousarray(first).view(np.uint8),
np.ascontiguousarray(second).view(np.uint8)))
def pair_metrics(a, b):
"""Exact definitions copied from phase4i.pair_metrics/safe_corr/cosine."""
x, y = a.astype(np.float64), b.astype(np.float64)
aa, bb = a > 0, b > 0
union = int(np.count_nonzero(aa | bb))
intersection = int(np.count_nonzero(aa & bb))
denominator = float(np.linalg.norm(x) * np.linalg.norm(y))
cosine = 1.0 if denominator == 0 and np.array_equal(x, y) else (
0.0 if denominator == 0 else float(np.dot(x, y) / denominator))
correlation = (1.0 if np.array_equal(x, y) else 0.0) if np.std(x) == 0 or np.std(y) == 0 else float(np.corrcoef(x, y)[0, 1])
return {"active_intersection": intersection, "active_union": union,
"active_jaccard": 1.0 if union == 0 else float(intersection / union),
"cosine_similarity": cosine, "correlation": correlation,
"euclidean_distance": float(np.linalg.norm(x - y))}
def evaluate_gates(summary, gates):
"""Each conjunct in original phase4l.py:239, kept visible for audit."""
return {
"mean_sparsity_in_closed_interval": bool(float(gates["sparse_min_fraction"]) <=
summary["KC_active_fraction_mean"] <= float(gates["sparse_max_fraction"])),
"maximum_strictly_below_half": bool(summary["KC_active_fraction_max"] < 0.5),
"minimum_strictly_positive": bool(summary["KC_active_fraction_min"] > 0),
"same_jaccard_gt_different": bool(summary["same_odor_jaccard_mean"] > summary["different_odor_jaccard_mean"]),
"different_euclidean_gt_same": bool(summary["different_odor_euclidean_mean"] > summary["same_odor_euclidean_mean"]),
"at_least_original_pair_count": bool(summary["pairwise_separation_pass_count"] >= int(gates["minimum_separable_odor_pairs"]))}
def sample_cv(values):
"""Original pandas Series.std uses ddof=1. Undefined diagnostic -> null."""
values = np.asarray(values, dtype=np.float64)
mean = float(values.mean())
return None if mean == 0 else float(values.std(ddof=1) / mean)
def summarize_mode(mode, odor_ids, seeds, runs, gates):
within, within_j, between, between_j, between_cos, between_corr = [], [], [], [], [], []
pairs = []
for odor in odor_ids:
arrays = [runs[(mode, odor, seed)]["kc_counts"] for seed in seeds]
for first, second in itertools.combinations(arrays, 2):
metric = pair_metrics(first, second)
within.append(metric["euclidean_distance"])
within_j.append(metric["active_jaccard"])
for first_odor, second_odor in itertools.combinations(odor_ids, 2):
distances = []
for seed in seeds:
metric = pair_metrics(runs[(mode, first_odor, seed)]["kc_counts"],
runs[(mode, second_odor, seed)]["kc_counts"])
distances.append(metric["euclidean_distance"])
between.append(metric["euclidean_distance"])
between_j.append(metric["active_jaccard"])
between_cos.append(metric["cosine_similarity"])
between_corr.append(metric["correlation"])
pair_within = []
for odor in (first_odor, second_odor):
arrays = [runs[(mode, odor, seed)]["kc_counts"] for seed in seeds]
pair_within.extend(pair_metrics(first, second)["euclidean_distance"]
for first, second in itertools.combinations(arrays, 2))
cross_mean, within_mean = float(np.mean(distances)), float(np.mean(pair_within))
pairs.append({"odor_id_a": first_odor, "odor_id_b": second_odor,
"between_same_seed_mean": cross_mean, "within_this_pair_mean": within_mean,
"between_distance_count": len(distances), "within_distance_count": len(pair_within),
"gate": bool(cross_mean > within_mean)})
selected = [runs[(mode, odor, seed)] for odor in odor_ids for seed in seeds]
fractions = [int(np.count_nonzero(run["kc_counts"])) / len(run["kc_counts"]) for run in selected]
summary = {"KC_active_fraction_mean": float(np.mean(fractions)),
"KC_active_fraction_min": float(np.min(fractions)), "KC_active_fraction_max": float(np.max(fractions)),
"same_odor_jaccard_mean": float(np.mean(within_j)),
"different_odor_jaccard_mean": float(np.mean(between_j)),
"same_odor_euclidean_mean": float(np.mean(within)),
"different_odor_euclidean_mean": float(np.mean(between)),
"different_odor_cosine_mean": float(np.mean(between_cos)),
"different_odor_correlation_mean": float(np.mean(between_corr)),
"within_variance": float(np.var(within)), "between_distance_mean": float(np.mean(between)),
"pairwise_separation_pass_count": sum(row["gate"] for row in pairs), "pair_count": len(pairs),
"expected_event_count_cv": sample_cv([run["expected_external_events"] for run in selected]),
"actual_event_count_cv": sample_cv([run["external_events"] for run in selected]),
"within_distance_count": len(within), "between_distance_count": len(between),
"pairwise_baseline": "Each pair's two odors: 10+10 within-seed distances; never pooled across all odors",
"pairs": pairs}
summary["conditions"] = evaluate_gates(summary, gates)
summary["gate"] = bool(all(summary["conditions"].values()))
return summary
def validate_state(state, neurons, steps):
require(set(state) == set(STATE_DTYPES), "state.npz must have exactly the six declared arrays")
for name, dtype in STATE_DTYPES.items():
value = state[name]
require(value.dtype == dtype and value.ndim == 1, "Invalid state dtype/rank: " + name)
require(bool(np.isfinite(value).all()), "Nonfinite state: " + name)
if name not in ("step", "neuron_idx"):
require(value.shape == (neurons,), "Invalid state length: " + name)
ticks, nodes = state["step"], state["neuron_idx"]
require(ticks.shape == nodes.shape and bool(np.all((ticks >= 0) & (ticks < steps))) and
bool(np.all((nodes >= 0) & (nodes < neurons))), "Invalid sparse event indices")
keys = ticks.astype(np.int64) * neurons + nodes
require(bool(np.all(np.diff(keys) > 0)), "Sparse events not sorted unique by tick/global neuron")
require(np.array_equal(np.bincount(nodes, minlength=neurons), state["counts"]), "Counts disagree with sparse events")
require(bool(np.all((state["ref"] >= 0) & (state["ref"] <= 22))), "Final refractory outside frozen range")
return keys
def read_jsonl(path, steps, kind):
with Path(path).open(encoding="utf-8") as source:
rows = [json.loads(line) for line in source if line.strip()]
require(len(rows) == steps and [row.get("tick") for row in rows] == list(range(steps)),
"Missing/duplicate/reordered ticks in " + kind)
for row in rows:
names = ("v_sha256", "g_sha256", "ref_sha256") if kind == "state hashes" else (
"ordered_edge_sha256", "accepted_mask_sha256", "joint_sha256")
for name in names:
require(isinstance(row.get(name), str) and HEX_SHA.fullmatch(row[name]), "Invalid SHA256 in " + kind)
if kind == "queue":
require(type(row.get("count")) is int and type(row.get("accepted_count")) is int and
0 <= row["accepted_count"] <= row["count"], "Invalid queue counts")
return rows
def read_trial(output, case, spec, kc_globals, neurons, edges):
summary = read_json(output / "summary.json")
steps = spec["steps"]
require(summary.get("complete") is True and summary.get("pass_all") is True and
summary.get("all_finite") is True and summary.get("steps") == steps and
summary.get("completed_ticks") == steps and summary.get("nodes") == neurons and
summary.get("edges") == edges and summary.get("precision") == "float64" and
summary.get("apl_precision") == "float32" and summary.get("case") == spec["name"] and
summary.get("record_history") is False and summary.get("learning") is False,
"Incomplete/failed/wrong-scope GPU summary")
with np.load(output / "state.npz", allow_pickle=False) as source:
state = {name: source[name].copy() for name in source.files}
event_keys = validate_state(state, neurons, steps)
hashes = read_jsonl(output / "tick-state-hashes.jsonl", steps, "state hashes")
for name in ("v", "g", "ref"):
require(hashes[-1][name + "_sha256"] == raw_hash(state[name]), "Final state does not match last tick hash: " + name)
queues = read_jsonl(output / "queue.jsonl", steps, "queue")
apl = {}
for name, width in APL_FILES.items():
value = np.load(output / name, mmap_mode="r", allow_pickle=False)
require(value.dtype == np.float32 and value.shape == (steps, width) and
bool(np.isfinite(value).all()) and bool(np.all(value >= 0)), "Invalid full APL trace: " + name)
apl[name] = value
with (output / "requests.csv").open(encoding="utf-8", newline="") as source:
reader = csv.DictReader(source)
require(tuple(reader.fieldnames or ()) == REQUEST_FIELDS, "Request CSV schema mismatch")
request_rows = [{name: int(row[name]) for name in REQUEST_FIELDS} for row in reader]
with np.load(case / "requests.npz", allow_pickle=False) as source:
require(set(source.files) == {"tick", "neuron_idx"}, "Input request schema mismatch")
expected_ticks, expected_nodes = source["tick"], source["neuron_idx"]
require(expected_ticks.dtype == np.int32 and expected_nodes.dtype == np.int32 and
expected_ticks.ndim == 1 and expected_ticks.shape == expected_nodes.shape,
"Input request dtype/shape mismatch")
require(len(request_rows) == len(expected_ticks), "Requested event coverage mismatch")
require([row["tick"] for row in request_rows] == expected_ticks.tolist() and
[row["neuron_idx"] for row in request_rows] == expected_nodes.tolist(), "Requests differ from frozen input")
require(all(row["attempted"] == 1 and row["accepted"] in (0, 1) and
row["rejected"] == 1 - row["accepted"] for row in request_rows), "Invalid request acceptance bookkeeping")
requested_keys = expected_ticks.astype(np.int64) * neurons + expected_nodes
require(bool(np.all(np.diff(requested_keys) > 0)) and bool(np.all((expected_ticks >= 0) & (expected_ticks < steps))) and
bool(np.all((expected_nodes >= 0) & (expected_nodes < neurons))), "Input requests not sorted unique/in range")
actual_accepted = np.array([row["accepted"] for row in request_rows], dtype=np.uint8)
require(np.array_equal(np.isin(requested_keys, event_keys, assume_unique=True), actual_accepted.astype(bool)),
"Request accepted/rejected values disagree with actual spikes")
accepted = int(actual_accepted.sum())
require(summary.get("requested") == len(request_rows) and summary.get("accepted_requests") == accepted and
summary.get("rejected_requests") == len(request_rows) - accepted and
summary.get("total_spikes") == len(state["step"]), "Summary counts disagree with raw output")
component = read_json(output / "apl-component.json")
require(component.get("ok") is True and component.get("n_neurons") == neurons and
component.get("n_kc") == len(kc_globals) and component.get("n_apl") == 2 and
component.get("dt_ms") == .1 and summary.get("apl_component") == component,
"APL component provenance mismatch")
bundle = Path(spec["apl_bundle_dir"])
require(component.get("files_sha256") == {name: file_hash(bundle / name) for name in
("input_matrix.npy", "output_matrix.npy", "kc_globals.npy", "apl_globals.npy")}, "APL bundle hashes changed")
inputs = summary.get("input_sha256", {})
require(inputs.get("spec.json") == file_hash(case / "spec.json") and
inputs.get("requests.npz") == file_hash(case / "requests.npz"), "Case input provenance mismatch")
kc_counts = state["counts"][kc_globals].copy()
kc_event_mask = np.isin(state["neuron_idx"], kc_globals)
record = {"case": spec["name"], "mode": spec["mode"], "odor_id": spec["odor_id"],
"odor_name": spec["odor_name"], "seed": spec["seed"], "split": "calibration",
"KC_active": int(np.count_nonzero(kc_counts)), "KC_active_fraction": float(np.count_nonzero(kc_counts) / len(kc_globals)),
"KC_spikes": int(kc_counts.sum()), "KC_first_latency_ms":
float(state["step"][kc_event_mask][0] * .1) if bool(np.any(kc_event_mask)) else None,
"external_events": accepted, "expected_external_events": float(spec["expected_external_events"]),
"total_PN_rate_hz": float(spec["rate_sum_hz"]), "finite": True,
"total_spikes": len(state["step"]), "requested": len(request_rows)}
require(np.isfinite(record["expected_external_events"]) and record["expected_external_events"] > 0,
"CAL expected external events must be finite and positive")
return {"state": state, "hashes": hashes, "queues": queues, "apl": apl,
"requests": request_rows, "component": component, "kc_counts": kc_counts,
"expected_external_events": record["expected_external_events"], "external_events": accepted,
"record": record, "output": output}
def exact_repeat(first, repeat):
checks = {"state/" + name: arrays_bitwise_equal(first["state"][name], repeat["state"][name]) for name in STATE_DTYPES}
checks.update({name: arrays_bitwise_equal(first["apl"][name], repeat["apl"][name]) for name in APL_FILES})
checks.update(tick_state_hashes=first["hashes"] == repeat["hashes"],
queues=first["queues"] == repeat["queues"], requests=first["requests"] == repeat["requests"],
apl_component=first["component"] == repeat["component"])
return {"pass_all": bool(all(checks.values())), "checks": checks,
"scope": "All six state arrays, every tick all-neuron hashes, APL raw float32 traces, queues, requests and APL environment"}
def validate_inventory(records, cfg):
require(tuple(cfg["calibration"]["modes"]) == ORIGINAL_MODES and
tuple(cfg["calibration"]["seeds"]) == ORIGINAL_SEEDS and
cfg["calibration"]["duration_ms"] == 100.0 and cfg["calibration"]["odor_count"] == 6 and
cfg["calibration"]["split"] == "calibration" and
cfg["calibration"]["repeat_first_seed_each_odor"] is True, "Frozen CAL design changed")
gates = cfg["gates"]
require(gates["sparse_min_fraction"] == .03 and gates["sparse_max_fraction"] == .09 and
gates["minimum_separable_odor_pairs"] == 3 and gates["max_fraction_strict"] == .5 and
gates["min_fraction_strict"] == 0 and all(gates[key] is True for key in
("same_jaccard_gt_between", "between_euclidean_gt_within", "both_modes_required", "finite_required", "repeat_exact_required")),
"Original representation gates or additional integrity gates changed")
expected = {(mode, index, seed) for mode in ORIGINAL_MODES for index in range(6) for seed in ORIGINAL_SEEDS}
require(len(records) == 60 and {(row["mode"], row["odor_index"], row["seed"]) for row in records} == expected,
"CAL inventory must cover exactly 2 modes x 6 odors x 5 seeds")
odors = []
for index in range(6):
ids = {row["odor_id"] for row in records if row["odor_index"] == index}
require(len(ids) == 1, "Odor identity changes across seeds/modes")
odors.append(next(iter(ids)))
require(set(odors) == ORIGINAL_CAL_IDS, "CAL identities differ from the original frozen six")
for row in records:
require(row["name"] == f"cal-{row['mode']}-{row['odor_index']:02d}-s{row['seed']}", "Unexpected CAL case name")
return odors
def summarize(out_json=_DEFAULT_OUTPUT):
"""Recompute; default writes exclusively, out_json=None is strictly read-only."""
from context import EXP, ROOT, CFG, check
target = EXP / "calibration/summary.json" if out_json is _DEFAULT_OUTPUT else (
None if out_json is None else Path(out_json))
require(target is None or not target.exists(), "Refusing existing calibration summary")
failures, runs, run_records, repeats, provenance = [], {}, [], [], []
modes, odors = {}, []
prerequisites_ok = False
encoder = None
records = []
try:
check()
records = read_json(EXP / "protocol/calibration-cases.json")
odors = validate_inventory(records, CFG)
encoder = read_json(EXP / "protocol/encoder-audit.json")
require(encoder["panel_count"] == 12 and encoder["cal_count"] == 6 and
encoder["seeds"] == list(ORIGINAL_SEEDS) and encoder["requested_before_any_dynamics"] is True and
encoder["formal_AB_run"] is False and encoder["heldout_run"] is False, "Invalid frozen encoder scope")
# Only static original-panel metadata is read, never heldout trajectories.
import pandas as pd
original = pd.read_parquet(ROOT / "experiments/phase4l-olfactory-grounding/odor-encoder/frozen-odor-panel.parquet")
require(len(original) == 12 and set(original[original.split == "calibration"].odor_id) == ORIGINAL_CAL_IDS,
"Original static panel identity mismatch")
require(float(np.median(original.mapped_response_sum)) == encoder["median_mapped_response_sum"],
"Matched-energy reference is not the original frozen 12-panel median")
kc_globals = np.load(EXP / "apl-bundle/kc_globals.npy", allow_pickle=False)
require(kc_globals.dtype == np.int32 and kc_globals.shape == (4064,) and
bool(np.all(np.diff(kc_globals) > 0)) and bool(np.all((kc_globals >= 0) & (kc_globals < CFG["neurons"]))),
"Invalid frozen KC identities")
prerequisites_ok = True
except Exception as error:
failures.append({"stage": "prerequisites", "type": type(error).__name__, "message": str(error)})
if prerequisites_ok:
for row in records:
name = row["name"]
first = None
try:
case = EXP / "cases" / name
spec = read_json(case / "spec.json")
require(spec["name"] == name and spec["kind"] == "calibration" and spec["steps"] == 1000 and
spec["duration_ms"] == 100.0 and spec["dt_ms"] == .1 and spec["training"] is False and
all(spec[key] == row[key] for key in ("mode", "odor_id", "odor_index", "seed")),
"Case spec differs from fixed CAL inventory")
first = read_trial(EXP / "gpu" / (name + "-r0"), case, spec, kc_globals, CFG["neurons"], CFG["edges"])
require(first["record"]["requested"] == row["requests"], "Frozen inventory request count mismatch")
runs[(row["mode"], row["odor_id"], row["seed"])] = {key: first[key] for key in
("kc_counts", "expected_external_events", "external_events")}
run_records.append(first["record"])
provenance.append({"case": name, "repeat": 0, "state_npz_sha256": file_hash(first["output"] / "state.npz"),
"summary_sha256": file_hash(first["output"] / "summary.json")})
except Exception as error:
failures.append({"stage": "raw_trial", "case": name, "repeat": 0,
"type": type(error).__name__, "message": str(error)})
if row["seed"] == ORIGINAL_SEEDS[0]:
try:
require(first is not None, "Baseline unavailable for exact repeat")
repeat = read_trial(EXP / "gpu" / (name + "-r1"), case, spec, kc_globals, CFG["neurons"], CFG["edges"])
repeat_report = {"case": name, **exact_repeat(first, repeat)}
repeats.append(repeat_report)
provenance.append({"case": name, "repeat": 1, "state_npz_sha256": file_hash(repeat["output"] / "state.npz"),
"summary_sha256": file_hash(repeat["output"] / "summary.json")})
require(repeat_report["pass_all"], "Exact repeat differs: " + ", ".join(
key for key, value in repeat_report["checks"].items() if not value))
except Exception as error:
failures.append({"stage": "exact_repeat", "case": name, "repeat": 1,
"type": type(error).__name__, "message": str(error)})
if len(runs) == 60:
for mode in ORIGINAL_MODES:
try:
modes[mode] = summarize_mode(mode, odors, ORIGINAL_SEEDS, runs, CFG["gates"])
except Exception as error:
failures.append({"stage": "representation", "mode": mode,
"type": type(error).__name__, "message": str(error)})
integrity_pass = bool(prerequisites_ok and len(runs) == 60 and not any(row["stage"] in
("prerequisites", "raw_trial") for row in failures))
repeat_pass = bool(len(repeats) == 12 and all(row["pass_all"] for row in repeats) and
not any(row["stage"] == "exact_repeat" for row in failures))
representation_pass = bool(len(modes) == 2 and all(row["gate"] for row in modes.values()))
result = {"phase": "4AG", "scope": "Original fixed six CAL odors only; not heldout generalization or learning",
"pass_all": bool(integrity_pass and repeat_pass and representation_pass),
"numerical_integrity_pass": integrity_pass, "exact_repeat_pass": repeat_pass,
"original_representation_gate_pass": representation_pass,
"expected_base_trials": 60, "valid_base_trials": len(runs), "expected_repeats": 12,
"checked_repeats": len(repeats), "seeds": list(ORIGINAL_SEEDS), "duration_ms": 100.0,
"odor_ids": odors, "modes": modes, "runs": run_records, "repeats": repeats,
"failures": failures, "input_output_provenance": provenance, "encoder_audit": encoder,
"metric_source": "phase4l.representation (full original gate), phase4i.pair_metrics",
"finite_gate_note": "Added integrity prerequisite; original 4L recorded finite but omitted it from its gate",
"repeat_gate_note": "Additional exact repeat requirement; original metrics and numerical thresholds unchanged",
"shared_apl_component_oracle_limit": True, "independent_oracle_equivalence_claim": False,
"candidate_generated": False, "training": False, "heldout_dynamic_access": False}
if target is not None:
target.parent.mkdir(parents=True, exist_ok=True)
with target.open("x", encoding="utf-8") as output:
json.dump(result, output, ensure_ascii=False, indent=2, allow_nan=False)
output.write("\n")
return result
if __name__ == "__main__":
print(json.dumps({key: value for key, value in summarize().items() if key in
("pass_all", "numerical_integrity_pass", "exact_repeat_pass", "original_representation_gate_pass")}), flush=True)
@@ -0,0 +1,18 @@
49f53924f758317bfcbd2b53cab9b8b785121eb99f3234a8343c9b483c5701d8 PROTOCOL.md
edb9cb2d890471fd07afd88c959ef3540b0cd40af490fac3f26396b5e7f5bf9c calibration.py
6e1616b086f667fa4e4b5087f500f8080281977ca9922e7b055acfddd2003bd5 compare.py
a8bafb9deec49d918976f2836d977ef9f13c26a6fb7f70e015879e29cf986c9a config.json
274eb13ccf38dbbc5c7f14d9d642130eb0f69072d91a090f208c30c27f87dd2b context.py
b6e3c67e668a971b544df32d76435ab5e537061b9fc2e8d9dedb5d2a726f5782 finalize.py
69f5d893f47dafff4ef7c3186c3df0b9014666b32c8f4e943b57016bec92b18a gpu_apl.py
21ceec65fe42581dc55872010e0025d660e80358905f1cf4df1dadf341a3b291 legacy_apl_worker.py
357a7d3debb5abc34a8714c0233b456547a154d9d5855d28661b4f01019a80ea oracle_apl.py
e9328567753e144fc315491970f7e02af13725b93f35e4d4b97f7c4c48ce3338 prepare.py
afbe6d5a37c29bda66d38c470093584130d1852e67881c681662aec3c76b33c7 run_case.py
84c681030b0032119b5392d0c3f3c136a9c6b0d133eb548c40791a10bbbb8b63 run_suite.py
bab3136eecbc5bb09a985d715844ee845cb72b07930ce376bfb39be33bd1845a test_calibration.py
1a233f47943e01bbd845ac1dacdb1eec3f88c270c65a5f75bce1cf679b5de097 test_protocol.py
0ed665f686e3499f8543e48f1712ccb4523946971cb7a0e096cf4f6d10d3bcba test_python_entry.py
5cfc9a4505da6b8fb4e7d2617cdaedaa8475ed46a11ec9bdf0d4d25b1d22c2d3 validate_components.py
0d0e72b2f1348f6648124c8c34f75094f76fc5e1a281fbcca130a5fad2f35293 verify_frozen.py
208c00961b9d895d14ac050bc23fbc18db49d0df1fcf5c20d4c3eaa8e15ff7ff manifest.json
@@ -0,0 +1,508 @@
"""Fail-closed byte-exact audit of the shared-APL closed-loop fixtures.
Comparison is independent of either backend's stored PASS. No tolerance is
used, timing fields are never compared, and reports contain no wall timestamp.
"""
from __future__ import annotations
import csv
import hashlib
import json
import math
from pathlib import Path
import re
import struct
import numpy as np
N_GLOBAL = 166700
STATE_KEYS = ('step', 'neuron_idx', 'counts', 'v', 'g', 'ref')
REQUEST_FIELDS = ('tick', 'neuron_idx', 'attempted', 'accepted', 'rejected')
HASH_FIELDS = {'tick', 'v_sha256', 'g_sha256', 'ref_sha256'}
QUEUE_FIELDS = {'tick', 'count', 'accepted_count', 'ordered_edge_sha256',
'accepted_mask_sha256', 'joint_sha256'}
BUNDLE_FILES = ('input_matrix.npy', 'output_matrix.npy', 'kc_globals.npy', 'apl_globals.npy')
COEFFICIENTS = ('gd', 'c0', 'cg', 'cv', 'threshold', 'reset', 'seed_volt')
def require(condition, message):
if not condition:
raise ValueError(message)
def file_hash(path):
h = hashlib.sha256()
with Path(path).open('rb') as source:
for block in iter(lambda: source.read(8 << 20), b''):
h.update(block)
return h.hexdigest()
def raw_hash(array, dtype=None):
return hashlib.sha256(np.ascontiguousarray(array, dtype=dtype).tobytes()).hexdigest()
def save(path, report):
if path is None:
return
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
with path.open('x', encoding='utf-8') as target:
json.dump(report, target, indent=2, sort_keys=True, allow_nan=False)
target.write('\n')
def _read_json(path, used):
used.add(Path(path))
return json.loads(Path(path).read_text(encoding='utf-8'))
def _read_jsonl(path, used):
used.add(Path(path))
with Path(path).open(encoding='utf-8') as source:
return [json.loads(line) for line in source if line.strip()]
def _read_array(path, used):
used.add(Path(path))
return np.load(path, mmap_mode='r', allow_pickle=False)
def _check(checks, name, condition):
checks[name] = bool(condition)
def _bit_mask(a, b):
if a.dtype.kind == 'f':
unsigned = np.dtype('uint'+str(a.dtype.itemsize*8))
return np.ascontiguousarray(a).view(unsigned) != np.ascontiguousarray(b).view(unsigned)
return a != b
def _compare_array(name, a, b, checks, differences, dtype=None, shape=None):
a, b = np.asarray(a), np.asarray(b)
schema = a.shape == b.shape and a.dtype == b.dtype and \
(dtype is None or a.dtype == np.dtype(dtype)) and (shape is None or a.shape == shape)
_check(checks, name+'.schema', schema)
if not schema:
differences[name] = {'left_shape': list(a.shape), 'right_shape': list(b.shape),
'left_dtype': str(a.dtype), 'right_dtype': str(b.dtype), 'expected_shape': None if shape is None else list(shape),
'expected_dtype': None if dtype is None else str(np.dtype(dtype))}
_check(checks, name+'.bitwise_exact', False)
return False
finite = bool(np.isfinite(a).all() and np.isfinite(b).all())
_check(checks, name+'.finite', finite)
mask = _bit_mask(a, b)
exact = not bool(np.any(mask))
_check(checks, name+'.bitwise_exact', exact)
if not exact or not finite:
flat = np.flatnonzero(mask.ravel())
detail = {'mismatching_elements': int(len(flat)),
'first_positions': [list(map(int, np.unravel_index(int(index), a.shape))) for index in flat[:5]],
'left_nonfinite': int(np.count_nonzero(~np.isfinite(a))),
'right_nonfinite': int(np.count_nonzero(~np.isfinite(b)))}
if finite and a.size:
error = np.abs(a.astype(np.float64)-b.astype(np.float64))
detail.update(max_abs_error=float(error.max()), mean_abs_error=float(error.mean()))
if a.dtype.kind == 'f' and len(flat):
unsigned = np.dtype('uint'+str(a.dtype.itemsize*8))
av = np.ascontiguousarray(a).view(unsigned).ravel()
bv = np.ascontiguousarray(b).view(unsigned).ravel()
detail['first_bit_patterns'] = [{'left': hex(int(av[index])), 'right': hex(int(bv[index]))} for index in flat[:5]]
differences[name] = detail
return exact and finite
def _sha(value):
return isinstance(value, str) and re.fullmatch('[0-9a-f]{64}', value) is not None
def _read_requests(path, steps, used):
used.add(Path(path))
with Path(path).open(encoding='utf-8', newline='') as source:
reader = csv.DictReader(source)
require(tuple(reader.fieldnames or ()) == REQUEST_FIELDS, 'Request CSV schema mismatch: '+str(path))
rows = [{key: int(row[key]) for key in REQUEST_FIELDS} for row in reader]
previous = (-1, -1)
for row in rows:
key = row['tick'], row['neuron_idx']
require(previous < key and 0 <= key[0] < steps and 0 <= key[1] < N_GLOBAL,
'Request rows must be sorted, unique, and in range: '+str(path))
require(row['attempted'] == 1 and row['accepted'] in (0, 1) and row['rejected'] == 1-row['accepted'],
'Request accounting is incomplete: '+str(path))
previous = key
return rows
def _load_run(directory, role, n, edges, steps, record_history, name, used, checks):
directory = Path(directory)
summary = _read_json(directory/'summary.json', used)
_check(checks, role+'.summary_complete', summary.get('complete') is True and summary.get('pass_all') is True and
summary.get('steps') == steps and summary.get('completed_ticks') == steps and
summary.get('nodes') == n and summary.get('edges') == edges and summary.get('precision') == 'float64')
is_cpu = role == 'cpu'
_check(checks, role+'.case_name', summary.get('name' if is_cpu else 'case') == name)
_check(checks, role+'.history_mode', summary.get('history_recorded' if is_cpu else 'record_history') is record_history)
_check(checks, role+'.apl_precision', summary.get('APL_precision' if is_cpu else 'apl_precision') == 'float32')
_check(checks, role+'.no_error_marker', not (directory/'error.json').exists())
used.add(directory/'state.npz')
with np.load(directory/'state.npz', allow_pickle=False) as source:
require(set(source.files) == set(STATE_KEYS), 'State NPZ keys changed: '+str(directory))
state = {key: source[key].copy() for key in STATE_KEYS}
for key, dtype in (('v', 'float64'), ('g', 'float64'), ('ref', 'int32'), ('counts', 'int32')):
require(state[key].shape == (n,) and state[key].dtype == np.dtype(dtype), 'Invalid final '+key+': '+str(directory))
require(state['step'].dtype == state['neuron_idx'].dtype == np.int32 and state['step'].ndim == 1 and
state['step'].shape == state['neuron_idx'].shape, 'Invalid sparse event schema: '+str(directory))
require(bool(np.all((state['step'] >= 0) & (state['step'] < steps))) and
bool(np.all((state['neuron_idx'] >= 0) & (state['neuron_idx'] < N_GLOBAL))), 'Sparse event range error')
event_keys = state['step'].astype(np.int64)*N_GLOBAL+state['neuron_idx']
_check(checks, role+'.events_sorted_unique', len(event_keys) < 2 or np.all(np.diff(event_keys) > 0))
_check(checks, role+'.count_nonnegative_total', np.all(state['counts'] >= 0) and int(state['counts'].sum()) == len(event_keys))
_check(checks, role+'.ref_range', np.all((state['ref'] >= 0) & (state['ref'] <= 22)))
_check(checks, role+'.reported_events', summary.get('spikes' if is_cpu else 'total_spikes') == len(event_keys))
hashes = _read_jsonl(directory/'tick-state-hashes.jsonl', used)
require(len(hashes) == steps and [row.get('tick') for row in hashes] == list(range(steps)), 'Incomplete tick hash coverage')
require(all(set(row) == HASH_FIELDS and all(_sha(row[key]) for key in HASH_FIELDS-{'tick'}) for row in hashes),
'Invalid tick state hash schema')
queues = _read_jsonl(directory/'queue.jsonl', used)
require(len(queues) == steps and [row.get('tick') for row in queues] == list(range(steps)), 'Incomplete queue coverage')
require(all(set(row) == QUEUE_FIELDS and type(row['count']) is int and type(row['accepted_count']) is int and
0 <= row['accepted_count'] <= row['count'] <= edges and
all(_sha(row[key]) for key in QUEUE_FIELDS-{'tick', 'count', 'accepted_count'}) for row in queues),
'Invalid queue row schema/count/hash')
for key in ('v', 'g', 'ref'):
_check(checks, role+'.last_hash_'+key, hashes[-1][key+'_sha256'] == raw_hash(state[key], '<i4' if key == 'ref' else '<f8'))
requests = _read_requests(directory/'requests.csv', steps, used)
requested, accepted = len(requests), sum(row['accepted'] for row in requests)
_check(checks, role+'.request_summary', summary.get('requests' if is_cpu else 'requested') == requested and
summary.get('applicable_requests' if is_cpu else 'accepted_requests') == accepted and
summary.get('ref_rejected_requests' if is_cpu else 'rejected_requests') == requested-accepted)
apl = {field: _read_array(directory/('apl-'+field+'.float32.npy'), used) for field in ('drive', 'state', 'inhibition')}
for field, width in (('drive', 2), ('state', 2), ('inhibition', 4064)):
require(apl[field].dtype == np.float32 and apl[field].shape == (steps, width), 'Invalid APL '+field+' history schema')
_check(checks, role+'.apl_positive_'+field, np.all(apl[field] >= 0))
histories, pre = {}, {}
for field, dtype in (('v', 'float64'), ('g', 'float64'), ('ref', 'int32')):
files = (directory/(field+'-history.'+dtype+'.npy'), directory/('preAPL-'+field+'.'+dtype+'.npy'))
if record_history:
histories[field], pre[field] = (_read_array(path, used) for path in files)
require(all(array.dtype == np.dtype(dtype) and array.shape == (steps, n) for array in (histories[field], pre[field])),
'Small pre/post history schema mismatch')
_check(checks, role+'.history_hashes_'+field, all(row[field+'_sha256'] == raw_hash(histories[field][tick])
for tick, row in enumerate(hashes)))
_check(checks, role+'.history_final_'+field, not np.any(_bit_mask(histories[field][-1], state[field])))
else:
_check(checks, role+'.no_dense_'+field, not any(path.exists() for path in files))
if is_cpu:
component = _read_json(directory/'apl-worker-handshake.json', used)['handshake']
else:
component = _read_json(directory/'apl-component.json', used)
_check(checks, role+'.component_summary_consistent', summary.get('apl_component') == component)
return dict(directory=directory, summary=summary, state=state, hashes=hashes, queues=queues,
requests=requests, apl=apl, histories=histories, pre=pre, component=component)
def _pair_outputs(left, right, checks, differences, n, steps, record_history):
for field in STATE_KEYS:
shape = None if field in ('step', 'neuron_idx') else (n,)
dtype = 'float64' if field in ('v', 'g') else 'int32'
_compare_array('state.'+field, left['state'][field], right['state'][field], checks, differences, dtype, shape)
for field, width in (('drive', 2), ('state', 2), ('inhibition', 4064)):
_compare_array('apl.'+field, left['apl'][field], right['apl'][field], checks, differences, 'float32', (steps, width))
for field in ('hashes', 'queues', 'requests', 'component'):
same = left[field] == right[field]
_check(checks, field+'.parsed_exact', same)
if not same:
if isinstance(left[field], list):
first = next((i for i, (a, b) in enumerate(zip(left[field], right[field])) if a != b), None)
differences[field] = {'left_count': len(left[field]), 'right_count': len(right[field]),
'first_differing_row': first,
'left_row': None if first is None else left[field][first],
'right_row': None if first is None else right[field][first]}
else:
differences[field] = {'left': left[field], 'right': right[field]}
if record_history:
for stage in ('histories', 'pre'):
for field, dtype in (('v', 'float64'), ('g', 'float64'), ('ref', 'int32')):
_compare_array(stage+'.'+field, left[stage][field], right[stage][field], checks, differences, dtype, (steps, n))
def _queue_digest(tick, ids, accepted):
ids = np.ascontiguousarray(ids, dtype='<i8').tobytes()
mask = np.ascontiguousarray(accepted, dtype=np.uint8).tobytes()
return {'tick': tick, 'count': len(mask), 'accepted_count': int(np.count_nonzero(accepted)),
'ordered_edge_sha256': hashlib.sha256(ids).hexdigest(),
'accepted_mask_sha256': hashlib.sha256(mask).hexdigest(),
'joint_sha256': hashlib.sha256(b'phase4af-queue-v1\0'+struct.pack('<qq', tick, len(mask))+ids+mask).hexdigest()}
def _independent_event_accounting(run, role, graph, requested, steps, checks, differences):
nodes, ptr = graph['nodes'], graph['ptr']
n = len(nodes)
state = run['state']
local = np.searchsorted(nodes, state['neuron_idx'])
require(np.all(local < n) and np.array_equal(nodes[local], state['neuron_idx']), 'Actual spike outside graph identity')
_check(checks, role+'.events_per_neuron_counts', np.array_equal(np.bincount(local, minlength=n), state['counts']))
actual_request_pairs = [(row['tick'], row['neuron_idx']) for row in run['requests']]
_check(checks, role+'.requests_match_frozen_input', actual_request_pairs == requested)
require(actual_request_pairs == requested, 'Actual request population/time differs from frozen input')
bounds = np.searchsorted(state['step'], np.arange(steps+1))
request_ticks = np.asarray([row['tick'] for row in run['requests']], np.int32)
rbounds = np.searchsorted(request_ticks, np.arange(steps+1))
request_nodes = np.asarray([row['neuron_idx'] for row in run['requests']], np.int32)
request_local = np.searchsorted(nodes, request_nodes)
require(np.all(request_local < n) and np.array_equal(nodes[request_local], request_nodes), 'Request outside graph')
last = np.full(n, -1_000_000_000, np.int64)
degrees = np.diff(ptr)
expected_counts = np.zeros(steps, np.int64)
arrival_tick = state['step'].astype(np.int64)+18
valid = arrival_tick < steps
np.add.at(expected_counts, arrival_tick[valid], degrees[local[valid]])
_check(checks, role+'.delayed_all_edges_count', np.array_equal(expected_counts, [row['count'] for row in run['queues']]))
request_ok, delivered_ok, ref_ok, queue_ok, reset_ok = True, True, True, True, True
first = {}
for tick in range(steps):
fired = local[bounds[tick]:bounds[tick+1]]
lo, hi = rbounds[tick:tick+2]
targets = request_local[lo:hi]
accepted = (tick-last[targets]) >= 22
for index, ok in zip(range(lo, hi), accepted):
row = run['requests'][index]
if row['accepted'] != int(ok) or row['rejected'] != int(not ok):
request_ok = False
first.setdefault('request_ref_mismatch', {'tick': tick, 'neuron_idx': row['neuron_idx']})
if not np.isin(targets[accepted], fired).all() or np.isin(targets[~accepted], fired).any():
delivered_ok = False
first.setdefault('request_delivery_mismatch', tick)
last[fired] = tick
ref = np.maximum(22-(tick-last), 0).astype(np.int32)
if raw_hash(ref, '<i4') != run['hashes'][tick]['ref_sha256']:
ref_ok = False
first.setdefault('ref_hash_mismatch', tick)
if run['pre']:
if len(fired) and not np.array_equal(np.ascontiguousarray(run['pre']['g'][tick, fired]).view(np.uint64), np.zeros(len(fired), np.uint64)):
reset_ok = False
first.setdefault('pre_apl_spike_reset_mismatch', tick)
due = local[bounds[tick-18]:bounds[tick-17]] if tick >= 18 else np.empty(0, np.int64)
chunks = [np.arange(ptr[source], ptr[source+1], dtype=np.int64) for source in due]
indices = np.concatenate(chunks) if chunks else np.empty(0, np.int64)
expected_queue = _queue_digest(tick, graph['edge_id'][indices], (ref[graph['dst'][indices]] == 0).astype(np.uint8))
if expected_queue != run['queues'][tick]:
queue_ok = False
first.setdefault('queue_reconstruction_mismatch', tick)
_check(checks, role+'.request_refractory_gate', request_ok)
_check(checks, role+'.accepted_spikes_rejected_absent', delivered_ok)
_check(checks, role+'.all_ref_hashes_from_actual_events', ref_ok)
if run['pre']:
_check(checks, role+'.small_queue_independent_reconstruction', queue_ok)
_check(checks, role+'.spike_g_reset_before_apl', reset_ok)
if first:
differences[role+'.independent_accounting'] = first
def _check_apl_application(run, role, nodes, kc, checks, differences):
if not run['pre']:
return
common, local_kc, bundle_kc = np.intersect1d(nodes, kc, assume_unique=True, return_indices=True)
_compare_array(role+'.apl_keeps_voltage', run['pre']['v'], run['histories']['v'], checks, differences, 'float64')
_compare_array(role+'.apl_keeps_ref', run['pre']['ref'], run['histories']['ref'], checks, differences, 'int32')
expected = np.array(run['pre']['g'], copy=True)
delta = run['apl']['inhibition'][:, bundle_kc].astype(np.float64)*np.float64(.001)
expected[:, local_kc] = expected[:, local_kc]-delta
_compare_array(role+'.apl_unconditional_g_write', expected, run['histories']['g'], checks, differences, 'float64')
def _finish(report, checks, differences, used, out_json):
report['checks'] = {name: bool(value) for name, value in checks.items()}
report['differences'] = differences
report['pass_all'] = bool(checks) and all(checks.values()) and 'error' not in report
report['failed_checks'] = sorted(name for name, value in checks.items() if not value)
report['evidence_sha256'] = {str(path): file_hash(path) for path in sorted(used) if path.is_file()}
save(out_json, report)
return report
def compare(case_dir, gpu_dir, cpu_dir, out_json=None):
"""Strict independent closed-loop comparison; out_json=None is read-only."""
case_dir, gpu_dir, cpu_dir = Path(case_dir), Path(gpu_dir), Path(cpu_dir)
if out_json is not None:
require(not Path(out_json).exists(), 'Refusing existing comparison report')
checks, differences, used = {}, {}, set()
report = {'kind': 'shared-APL-component closed-loop byte-exact comparison', 'pass_all': False,
'case_dir': str(case_dir), 'gpu_dir': str(gpu_dir), 'cpu_dir': str(cpu_dir),
'tolerance': None, 'signed_zero_included': True, 'timing_fields_compared': False,
'independent_CPU_all_components_claim': False}
try:
spec = _read_json(case_dir/'spec.json', used)
steps, history = spec['steps'], spec['record_history']
require(type(steps) is int and steps > 0 and type(history) is bool and spec['dt_ms'] == .1,
'Invalid fixed case clock/history schema')
graph_dir, bundle_dir = Path(spec['graph_dir']), Path(spec['apl_bundle_dir'])
graph = {field: _read_array(graph_dir/(field+'.npy'), used) for field in
('nodes', 'edge_id', 'src', 'dst', 'ptr', 'signed_raw', 'weights')}
nodes = graph['nodes']
n, edges = len(nodes), len(graph['edge_id'])
require(n > 0 and edges > 0 and nodes.dtype == np.int32 and nodes.ndim == 1 and np.all((nodes >= 0) & (nodes < N_GLOBAL)) and
np.all(np.diff(nodes) > 0), 'Invalid canonical node identities')
require(graph['ptr'].dtype == np.int64 and graph['ptr'].shape == (n+1,) and graph['ptr'][0] == 0 and
graph['ptr'][-1] == edges and np.all(np.diff(graph['ptr']) >= 0), 'Invalid CSR')
for key, dtype in (('edge_id', 'int64'), ('src', 'int32'), ('dst', 'int32'), ('signed_raw', 'int64'), ('weights', 'float64')):
require(graph[key].dtype == np.dtype(dtype) and graph[key].shape == (edges,), 'Invalid graph '+key)
require(np.array_equal(graph['src'], np.repeat(np.arange(n, dtype=np.int32), np.diff(graph['ptr']))) and
np.all((graph['dst'] >= 0) & (graph['dst'] < n)), 'Invalid source/destination row mapping')
require(history == (n < 512) and (n < 512 or n == N_GLOBAL), 'Invalid small/full history declaration')
require(np.all(graph['edge_id'] >= 0) and np.all(np.diff(graph['edge_id']) > 0),
'Original canonical edge IDs must be unique and increasing')
if n == N_GLOBAL:
require(edges == 25582938 and np.array_equal(nodes, np.arange(n, dtype=np.int32)) and
np.array_equal(graph['edge_id'], np.arange(edges, dtype=np.int64)), 'Full canonical graph identity changed')
bundle = {name: _read_array(bundle_dir/name, used) for name in BUNDLE_FILES}
kc, apl_ids = bundle['kc_globals.npy'], bundle['apl_globals.npy']
require(kc.dtype == apl_ids.dtype == np.int32 and kc.shape == (4064,) and apl_ids.shape == (2,), 'Invalid APL/KC identities')
require(np.all((kc >= 0) & (kc < N_GLOBAL)) and np.all(np.diff(kc) > 0) and
np.all((apl_ids >= 0) & (apl_ids < N_GLOBAL)) and np.all(np.diff(apl_ids) > 0) and
not np.intersect1d(kc, apl_ids).size, 'APL/KC identities overlap or are invalid')
for key, shape in (('input_matrix.npy', (2, N_GLOBAL)), ('output_matrix.npy', (2, 4064))):
require(bundle[key].dtype == np.float32 and bundle[key].shape == shape and
np.isfinite(bundle[key]).all() and np.all(bundle[key] >= 0), 'Invalid normalized APL matrix')
gpu = _load_run(gpu_dir, 'gpu', n, edges, steps, history, spec['name'], used, checks)
cpu = _load_run(cpu_dir, 'cpu', n, edges, steps, history, spec['name'], used, checks)
_pair_outputs(gpu, cpu, checks, differences, n, steps, history)
used.add(case_dir/'requests.npz')
with np.load(case_dir/'requests.npz', allow_pickle=False) as source:
require(set(source.files) == {'tick', 'neuron_idx'} and source['tick'].dtype == source['neuron_idx'].dtype == np.int32,
'Fixed request NPZ schema changed')
require(source['tick'].shape == source['neuron_idx'].shape and source['tick'].ndim == 1, 'Invalid sparse request shape')
requested = list(zip(map(int, source['tick']), map(int, source['neuron_idx'])))
for role, run in (('gpu', gpu), ('cpu', cpu)):
_independent_event_accounting(run, role, graph, requested, steps, checks, differences)
_check_apl_application(run, role, nodes, kc, checks, differences)
# Independently derive the effective clone. Original graph weights stay read-only.
cpu_weights = _read_array(cpu_dir/'weights.npy', used)
require(cpu_weights.dtype == np.float64 and cpu_weights.shape == (edges,), 'CPU effective weight schema mismatch')
expected_hash, base_hash, mask_hash = hashlib.sha256(), hashlib.sha256(), hashlib.sha256()
weight_ok, mask_count = True, 0
for start in range(0, edges, 1 << 20):
stop = min(edges, start+(1 << 20))
original = np.asarray(graph['weights'][start:stop])
require(np.isfinite(original).all(), 'Nonfinite original weights')
raw_expected = graph['signed_raw'][start:stop]*(.275*.001)
require(not np.any(_bit_mask(original, raw_expected)), 'Original SI weights differ from unaltered signed contacts')
mask = np.isin(nodes[graph['src'][start:stop]], apl_ids)
expected = original.copy()
expected[mask] = np.float64(0)
mask_count += int(mask.sum())
expected_hash.update(np.ascontiguousarray(expected, dtype='<f8').tobytes())
base_hash.update(np.ascontiguousarray(original, dtype='<f8').tobytes())
mask_hash.update(np.ascontiguousarray(graph['edge_id'][start:stop][mask], dtype='<i8').tobytes())
weight_ok &= not np.any(_bit_mask(expected, cpu_weights[start:stop]))
expected_sha = expected_hash.hexdigest()
_check(checks, 'cpu.effective_weights_independent_bytes', weight_ok)
for role, run in (('gpu', gpu), ('cpu', cpu)):
_check(checks, role+'.effective_weights_raw_sha', run['summary'].get('effective_weights_raw_sha256') == expected_sha)
_check(checks, role+'.apl_fast_edge_count', run['summary'].get('apl_fast_edges_zeroed') == mask_count)
_check(checks, role+'.kc_target_count', run['summary'].get('kc_targets_present') == len(np.intersect1d(nodes, kc)))
mask_audit = _read_json(cpu_dir/'apl-mask-audit.json', used)
_check(checks, 'cpu.mask_provenance', mask_audit['count'] == mask_count and
mask_audit['ordered_original_edge_id_sha256'] == mask_hash.hexdigest() and
mask_audit['base_weight_raw_bytes_sha256'] == base_hash.hexdigest() and
mask_audit['effective_weights_raw_sha256'] == expected_sha and mask_audit['base_graph_files_modified'] is False)
case_hashes = {name: file_hash(case_dir/name) for name in ('spec.json', 'requests.npz')}
if (case_dir/'arrays.npz').exists():
case_hashes['arrays.npz'] = file_hash(case_dir/'arrays.npz')
used.add(case_dir/'arrays.npz')
baseline_coeff = _read_json(Path(spec['coefficients_path']), used)
actual_coeff = _read_json(cpu_dir/'coefficients.json', used)
_check(checks, 'cpu.actual_author_coefficients_exact', all(float(actual_coeff[key]).hex() == float(baseline_coeff[key]).hex()
for key in COEFFICIENTS))
audit = _read_json(cpu_dir/'input-audit.json', used)
expected_graph_hashes = {name: file_hash(graph_dir/name) for name in
tuple(field+'.npy' for field in graph)+('completeness.csv', 'connectivity.parquet')}
bundle_hashes = {name: file_hash(bundle_dir/name) for name in BUNDLE_FILES}
_check(checks, 'cpu.read_actual_case', audit['spec'] == spec and audit['case_hashes'] == case_hashes)
_check(checks, 'cpu.graph_hashes', audit['graph_hashes'] == expected_graph_hashes)
_check(checks, 'cpu.bundle_hashes', audit['bundle_hashes'] == bundle_hashes)
_check(checks, 'cpu.no_candidate_trace_input', audit.get('candidate_trace_used_as_input') is False and
cpu['summary'].get('candidate_trace_used_as_input') is False)
_check(checks, 'cpu.worker_source_hash', audit['legacy_apl_worker_sha256'] == file_hash(spec['legacy_apl_worker']))
_check(checks, 'cpu.coefficient_input_hash', audit['coefficients_sha256'] == file_hash(spec['coefficients_path']))
gpu_hashes = dict(case_hashes, **{'base_weights.npy': file_hash(graph_dir/'weights.npy'),
'coefficients.json': file_hash(spec['coefficients_path'])})
_check(checks, 'gpu.input_hashes', gpu['summary']['input_sha256'] == gpu_hashes)
for role, run in (('gpu', gpu), ('cpu', cpu)):
component = run['component']
_check(checks, role+'.actual_component_bundle_bytes', component['files_sha256'] == bundle_hashes and
component['array_sha256'] == {name: raw_hash(value) for name, value in bundle.items()})
_check(checks, role+'.component_dimensions_clock', component.get('ok') is True and
component['protocol'] == 'phase4ag-apl-v1' and component['n_neurons'] == N_GLOBAL and
component['n_apl'] == 2 and component['n_kc'] == 4064 and component['dt_ms'] == .1)
decay = np.float32(math.exp(-.1/20.0))
gain = np.float32(.01)
_check(checks, role+'.frozen_apl_constants', component['decay_f32_bits'] == f'{int(decay.view(np.uint32)):08x}' and
component['gain_f32_bits'] == f'{int(gain.view(np.uint32)):08x}')
env = component['environment']
_check(checks, role+'.component_precision_environment', env['cuda_matmul_allow_tf32'] is False and
env['float32_matmul_precision'] == 'highest' and env['precision_configuration_changed_by_component'] is False and
'4090' in env['device_name'])
environment = _read_json(cpu_dir/'environment.json', used)
_check(checks, 'cpu.pinned_environment', environment['packages']['brian2'] == '2.5.1' and
environment['packages']['numpy'] == '1.22.3' and environment['packages']['sympy'] == '1.12' and
environment['Torch_imported_into_Brian'] is False and environment['author_precision'] == 'float64')
queue_audit = _read_json(cpu_dir/'queue-audit.json', used)
_check(checks, 'cpu.queue_observer_coverage', queue_audit['peek_calls'] == queue_audit['advance_calls'] == steps and
queue_audit['same_peek_object_returned'] is True and queue_audit['zero_weight_and_refractory_rejected_edges_retained'] is True)
_check(checks, 'cpu.sidecar_complete', cpu['summary']['APL_worker_exit_status'] == 0 and cpu['summary']['APL_worker_ticks'] == steps)
report.update(case=spec['name'], steps=steps, nodes=n, edges=edges, record_history=history,
total_spikes=len(gpu['state']['step']), active_neurons=int(np.count_nonzero(gpu['state']['counts'])),
requested=len(requested), accepted_requests=sum(row['accepted'] for row in gpu['requests']),
rejected_requests=sum(row['rejected'] for row in gpu['requests']),
arriving_edges=sum(row['count'] for row in gpu['queues']),
accepted_arriving_edges=sum(row['accepted_count'] for row in gpu['queues']),
apl_fast_edges_zeroed=mask_count, effective_weights_raw_sha256=expected_sha,
component_environment=gpu['component']['environment'],
limits=['APL Torch primitives are shared; original AST component validation is a separate required gate.',
'Small cases preserve and independently hash all pre/post states; full cases compare all-tick instrumented state hashes without saving dense whole-brain histories.',
'For full cases intermediate finite checks are performed by the instrumented backends; this file independently inspects final states and all APL traces.',
'This is exact agreement for the declared trajectory, not physiological validity or learning.'])
except Exception as error:
report['error'] = {'type': type(error).__name__, 'message': str(error)}
return _finish(report, checks, differences, used, out_json)
def compare_gpu_repeats(first, second, out_json=None):
"""Repeat equality only; the first run's independent oracle gate is separate."""
first, second = Path(first), Path(second)
if out_json is not None:
require(not Path(out_json).exists(), 'Refusing existing repeat report')
checks, differences, used = {}, {}, set()
report = {'kind': 'fresh-GPU-run exact repeat comparison', 'first': str(first), 'second': str(second),
'pass_all': False, 'tolerance': None, 'signed_zero_included': True, 'timing_fields_compared': False,
'scope': 'Scientific outputs, recording integrity and input hashes; independent case/graph audit belongs to compare()'}
try:
summary = _read_json(first/'summary.json', used)
n, edges, steps, name, history = (summary[key] for key in ('nodes', 'edges', 'steps', 'case', 'record_history'))
require(type(n) is int and type(edges) is int and type(steps) is int and n > 0 and edges > 0 and steps > 0 and
type(history) is bool and history == (n < 512), 'Invalid repeat dimensions')
left = _load_run(first, 'first_gpu', n, edges, steps, history, name, used, checks)
right = _load_run(second, 'second_gpu', n, edges, steps, history, name, used, checks)
_pair_outputs(left, right, checks, differences, n, steps, history)
stable = ('case', 'complete', 'pass_all', 'steps', 'completed_ticks', 'nodes', 'edges', 'precision',
'apl_precision', 'state_units', 'total_spikes', 'requested', 'accepted_requests', 'rejected_requests',
'arriving_edges', 'accepted_arriving_edges', 'counts_match_sparse_events', 'all_finite', 'record_history',
'apl_fast_edges_zeroed', 'kc_targets_present', 'effective_weights_raw_sha256', 'apl_schedule',
'apl_si_conversion', 'build', 'sealed_ae_backend_sha256', 'learning', 'input_sha256')
for key in stable:
_check(checks, 'summary.'+key, key in left['summary'] and key in right['summary'] and
left['summary'][key] == right['summary'][key])
if not checks['summary.'+key]:
differences['summary.'+key] = {'first': left['summary'].get(key), 'second': right['summary'].get(key)}
report.update(case=name, steps=steps, nodes=n, edges=edges, record_history=history,
total_spikes=len(left['state']['step']),
explicit_exclusions=['wall_seconds', 'diagnostic_simulation_seconds', 'build_or_cache_seconds',
'peak_allocated_vram_bytes', 'peak_reserved_vram_bytes'])
except Exception as error:
report['error'] = {'type': type(error).__name__, 'message': str(error)}
return _finish(report, checks, differences, used, out_json)
@@ -0,0 +1,23 @@
{
"phase": "4AG-r2",
"name": "author-apl-lab-v2",
"execution_revision": "Preserve declared venv Python entry rather than resolving its symlink to system Python. No dynamics or inputs changed.",
"human_authorization": "允许独立新模型分支测试动力学假设",
"gpu_uuid": "GPU-79f3a85d-adce-7833-7003-6488140ca596",
"neurons": 166700,
"edges": 25582938,
"raw_weight_sum": 124177617,
"precision": "float64",
"apl_precision": "float32",
"apl": {"tau_ms": 20.0, "gain": 0.01, "normalization": 1.0},
"hypothesis": "Author LIF plus unchanged legacy graded APL operator at end, after reset, unconditional KC g write. Mixed precision: h32 promoted to float64, then multiplied by float64 .001 SI, then subtracted. Not original author's APL model.",
"fixtures": ["zero", "pn_pulse", "kc_ref_boundary", "two_sources", "arrival_collision", "natural_request", "apl_only", "high_fanin"],
"fixture_repeats": 3,
"calibration": {"split": "calibration", "odor_count": 6, "modes": ["physiological", "matched_energy"], "seeds": [51101,51102,51103,51104,51105], "duration_ms": 100.0, "median_scope": "original frozen 12-odor panel", "full_oracle_probes": ["cal-physiological-00-s51101", "cal-matched_energy-00-s51101"], "repeat_first_seed_each_odor": true},
"gates": {"sparse_min_fraction": 0.03, "sparse_max_fraction": 0.09, "max_fraction_strict": 0.5, "min_fraction_strict": 0.0, "minimum_separable_odor_pairs": 3, "same_jaccard_gt_between": true, "between_euclidean_gt_within": true, "both_modes_required": true, "finite_required": true, "repeat_exact_required": true},
"training": false,
"heldout_dynamic_access": false,
"candidate_generation": false,
"output_budget_bytes": 16106127360,
"scope": "Semantic compatibility and fixed old CAL only. Shared-APL-component closed-loop Brian oracle plus independent arithmetic audit; never claim all-component independent CPU equivalence or learning success. No parameter/input/site/window selection from results."
}
@@ -0,0 +1,50 @@
import hashlib
import importlib.util
import json
from pathlib import Path
ROOT=Path('/data/digital-drosophila')
MODEL=Path(__file__).resolve().parent
EXP=ROOT/'experiments/phase4ag-author-apl-r2'
AF_MODEL=ROOT/'models/male-cns-lif/author-fullgraph-lab-v1'
AF_EXP=ROOT/'experiments/phase4af-author-fullgraph'
AD_EXP=ROOT/'experiments/phase4ad-author-semantics'
CFG=json.loads((MODEL/'config.json').read_text(encoding='utf-8'))
def digest(path):
h=hashlib.sha256()
with Path(path).open('rb') as f:
for b in iter(lambda:f.read(8<<20),b''):h.update(b)
return h.hexdigest()
def save(path,value):
path=Path(path);path.parent.mkdir(parents=True,exist_ok=True)
with path.open('x',encoding='utf-8') as f:json.dump(value,f,indent=2,ensure_ascii=False,allow_nan=False);f.write('\n')
def sources():
return {p.name:digest(p) for p in sorted(MODEL.iterdir()) if p.is_file() and p.name not in ('manifest.json','checksums.sha256')}
def integrity():
spec=importlib.util.spec_from_file_location('frozen_af_context',AF_MODEL/'context.py')
mod=importlib.util.module_from_spec(spec);spec.loader.exec_module(mod)
result=mod.integrity()
import sys
sys.path.insert(0,str(ROOT/'models/male-cns-lif/terminal-scope-diagnostic-v1'))
from diagnostic import manifest_check
for p in (AF_MODEL,AF_EXP,ROOT/'models/male-cns-lif/author-apl-lab-v1',ROOT/'experiments/phase4ag-author-apl'):
result[str(p.relative_to(ROOT))]=manifest_check(p,digest)
assert all(r['pass'] for r in result.values())
return result
def check():
p=json.loads((EXP/'protocol/preregistered.json').read_text())
assert p['sources']==sources(),'Source changed after preregistration'
for row in p['inputs']:assert digest(ROOT/row['path'])==row['sha256'],row['path']
for row in json.loads((EXP/'protocol/prepared-hashes.json').read_text()):
assert digest(EXP/row['path'])==row['sha256'],row['path']
return p
def budget():
size=sum(p.stat().st_size for p in EXP.rglob('*') if p.is_file())
assert size<CFG['output_budget_bytes'],'New output resource budget exceeded'
return size
@@ -0,0 +1,90 @@
"""Seal a completed gate or preserved failure; never claim learning."""
import json
from context import ROOT,MODEL,EXP,CFG,check,save,digest,integrity,budget
def seal(root):
assert not (root/'manifest.json').exists() and not (root/'checksums.sha256').exists()
rows=[dict(path=str(p.relative_to(root)),bytes=p.stat().st_size,sha256=digest(p))
for p in sorted(root.rglob('*')) if p.is_file() and '__pycache__' not in p.parts]
save(root/'manifest.json',dict(root=str(root),files=rows))
with (root/'checksums.sha256').open('x') as f:
for row in rows:f.write(row['sha256']+' '+row['path']+'\n')
f.write(digest(root/'manifest.json')+' manifest.json\n')
def main():
from compare import compare,compare_gpu_repeats
check();budget();comparisons=[];repeats={};components={}
for p in sorted((EXP/'audit').glob('compare-*.json')):
name=p.stem[len('compare-'):]
actual=compare(EXP/'cases'/name,EXP/'gpu'/(name+'-r0'),EXP/'oracle'/name,None)
assert actual==json.loads(p.read_text()),'Changed raw closed-loop evidence: '+name
comparisons.append(dict(case=name,pass_all=actual['pass_all']))
for p in sorted((EXP/'audit').glob('repeat-*.json')):
name,repeat=p.stem[len('repeat-'):].rsplit('-r',1)
actual=compare_gpu_repeats(EXP/'gpu'/(name+'-r0'),EXP/'gpu'/f'{name}-r{repeat}',None)
assert actual==json.loads(p.read_text()),'Changed raw repeat evidence: '+name
repeats[f'{name}-r{repeat}']=actual['pass_all']
for p in (EXP/'component-audit').glob('*.json'):
result=json.loads(p.read_text())
components[p.stem]=result['pass_all']
for filename,sha in result.get('input_sha256',{}).items():
assert digest(EXP/'gpu'/(p.stem+'-r0')/filename)==sha
gates={}
for name in ('fixtures','probes','calibration'):
path=EXP/'audit'/(name+'-gate.json')
gates[name]=json.loads(path.read_text()) if path.exists() else None
calpath=EXP/'calibration/summary.json'
cal=json.loads(calpath.read_text()) if calpath.exists() else None
if cal is not None:
from calibration import summarize
assert summarize(out_json=None)==cal,'CAL raw evidence changed'
frozen=json.loads((EXP/'regression/frozen-five.json').read_text())
after=integrity();save(EXP/'regression/old-integrity-after.json',after)
stops=[dict(path=str(p.relative_to(EXP)),report=json.loads(p.read_text())) for p in sorted((EXP/'audit').glob('stopped-*.json'))]
expected_cases=CFG['fixtures']+CFG['calibration']['full_oracle_probes']
expected_repeats=[f'{name}-r{r}' for name in CFG['fixtures'] for r in range(1,CFG['fixture_repeats'])]
compared={x['case']:x['pass_all'] for x in comparisons}
missing=dict(comparisons=sorted(set(expected_cases)-set(compared)),
components=sorted(set(expected_cases)-set(components)),repeats=sorted(set(expected_repeats)-set(repeats)))
evidence_ok=(set(compared)==set(components)==set(expected_cases) and set(repeats)==set(expected_repeats) and
all(compared.values()) and all(components.values()) and all(repeats.values()))
numerical=evidence_ok and all(gates[x] is not None and gates[x]['pass_all'] for x in ('fixtures','probes'))
representation=bool(cal is not None and cal['pass_all'])
if numerical:status='PASS-FIXED-CAL-REPRESENTATION' if representation else 'FAIL-FIXED-CAL-REPRESENTATION' if cal is not None else 'INCOMPLETE-CAL-EXECUTION'
else:status='FAIL-NUMERICAL-OR-AUDIT-GATE' if any(not p for group in (compared,components,repeats) for p in group.values()) else 'INCOMPLETE-NUMERICAL-EXECUTION'
oldpass=bool(frozen['pass_all'] and all(r['pass'] for r in after.values()))
if not oldpass:status='FAIL-FROZEN-INTEGRITY-OR-REGRESSION'
measurements=[]
for p in sorted((EXP/'gpu').glob('*/summary.json')):
s=json.loads(p.read_text())
measurements.append({k:s[k] for k in ('case','total_spikes','accepted_requests','nodes','edges','diagnostic_simulation_seconds','peak_allocated_vram_bytes')})
result=dict(status=status,numerical_gate_pass=bool(numerical),fixed_CAL_representation_pass=representation,
gates=gates,closed_loop_comparisons=comparisons,component_results=components,repeat_results=repeats,
missing_numerical_evidence=missing,calibration=cal,stopped=stops,
old_frozen_integrity_and_five_reference_pass=oldpass,measurements=measurements,
unchanged_APL_parameters=CFG['apl'],author_LIF_precision='float64',legacy_APL_precision='float32',
explicit_hypothesis=CFG['hypothesis'],APL_nonKC_fast_edges_unreplaced=1212,
shared_APL_component_oracle_limitation=True,whole_brain_universal_equivalence_claim=False,
heldout_generalization_tested=False,formal_AB_tested=False,learning_achieved=False,candidate_generated=False,
payload_bytes_before_manifest=budget(),
next_gate='Independent seeds/novel-odor representation, then credit specificity; no learning promotion from CAL' if numerical and representation else
'Audit first failure in this explicitly declared hypothesis; no gain search, no heldout tuning, no conditioning')
save(EXP/'audit/final-status.json',result)
lines=['# Phase 4AG: author LIF + unchanged legacy graded APL','',f'Status: `{status}`.','',
f'Numerical closed-loop gate: {numerical}; original complete fixed six-CAL gate: {representation}.',
'The independent Brian LIF and candidate use independent state but share the APL arithmetic component. Original frozen APL AST replay and a float64 error audit are separately recorded.',
'Author LIF uses float64; APL retains float32, tau20ms/gain0.01/normalization1, full original matrices and order. No learning/parameter search.',
'The explicitly hypothesized unconditional end-APL write includes refractory KC. Original fast APL mask leaves1,212 non-KC edges unreplaced; this scope limitation was not silently fixed.',
f'Old checksums and five frozen reference trials: {oldpass}.',
f'Successfully compared cases: {comparisons}.',
'Detailed CAL, exact comparisons, component errors, event/request traces and execution exceptions are linked from audit/final-status.json.',
'Wall/VRAM here include per-tick CPU synchronization, IPC and hashes. They are diagnostic costs, not runtime-performance benchmarks.',
'No heldout dynamic outputs, formal A/B, learning, game, reward, decoder or new candidate.',
'Next gate: '+result['next_gate'],'']
with (EXP/'REPORT.md').open('x',encoding='utf-8') as f:f.write('\n'.join(lines))
check();seal(MODEL);seal(EXP);print(status,flush=True)
if __name__=='__main__':main()

Some files were not shown because too many files have changed in this diff Show More