Archive MaleCNS research sources, provenance, bibliography and immutable data inventory
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"file_count": 10,
|
||||
"files": [
|
||||
{
|
||||
"bytes": 342,
|
||||
"path": "VERSION.json",
|
||||
"sha256": "036775cdd0e3851114d6439b9a8b7706c5f96e9ce4e49b4529484f0aa3e03252"
|
||||
},
|
||||
{
|
||||
"bytes": 11982,
|
||||
"path": "__pycache__/phase4o_a.cpython-310.pyc",
|
||||
"sha256": "61d9d7ea769df6546382b06081bd6dcf376c07deb9bc613aad6257c863190341"
|
||||
},
|
||||
{
|
||||
"bytes": 1253,
|
||||
"path": "phase4o.yaml",
|
||||
"sha256": "8b380f0597dd3f2d656e9e773a581855f75d940bcc0dad9e84abb6b02173aa16"
|
||||
},
|
||||
{
|
||||
"bytes": 11747,
|
||||
"path": "phase4o_a.py",
|
||||
"sha256": "1048a073de399052bd525faf010858fa83f075a7c747b3fe5dcf8e4fc9ce3b87"
|
||||
},
|
||||
{
|
||||
"bytes": 4736,
|
||||
"path": "phase4o_atomic.py",
|
||||
"sha256": "b481d91ac3a72d360c4dbb5378b975e430f0d1027fad94de5e2a041f9849c714"
|
||||
},
|
||||
{
|
||||
"bytes": 7748,
|
||||
"path": "phase4o_eligibility.py",
|
||||
"sha256": "4fb7c97c8832c3ef51fe7613083dd6eab627bcde419254696c19a07632deb878"
|
||||
},
|
||||
{
|
||||
"bytes": 7916,
|
||||
"path": "phase4o_event_replay.py",
|
||||
"sha256": "b169937bab495c77d8ee6c1013877e7500e7354140d9fcc90595d984238ba44e"
|
||||
},
|
||||
{
|
||||
"bytes": 11065,
|
||||
"path": "phase4o_finalize.py",
|
||||
"sha256": "db6318467fb1ecef4003077ec1db8eac299c0c56944f463f96418ab41135c08f"
|
||||
},
|
||||
{
|
||||
"bytes": 6133,
|
||||
"path": "phase4o_modes.py",
|
||||
"sha256": "8980ff1581c81d99752515349ee7be747a6f954a94ab56492b400a5324f1b6a2"
|
||||
},
|
||||
{
|
||||
"bytes": 4268,
|
||||
"path": "phase4o_targeted.py",
|
||||
"sha256": "cfd6cc4dd0f2c0d58b5eb2634fb4e6bd530eec5037c4c8462f6ef7a885301200"
|
||||
}
|
||||
],
|
||||
"generated_utc": "2026-09-21T15:31:34.397398+00:00",
|
||||
"root": "/data/digital-drosophila/models/male-cns-lif/runtime-credit-v1",
|
||||
"total_bytes": 67190
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"eligibility_v3_experimental_started": false,
|
||||
"frozen_runtime_v1_overwritten": false,
|
||||
"name": "MaleCNS-runtime-credit-v1-audit",
|
||||
"phase": "4O-A",
|
||||
"runtime_v2_deterministic_candidate_generated": false,
|
||||
"status": "FAIL-RUNTIME-DETERMINISM",
|
||||
"summary_sha256": "e7db20298cce2952d585f655cc866eb389946c2818ba4924ebd6f049bc228947"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
9a1d1bcb8da99194ba58a1db1aae288648eab72a94c55d3862fac478670c7e8e MANIFEST.json
|
||||
036775cdd0e3851114d6439b9a8b7706c5f96e9ce4e49b4529484f0aa3e03252 VERSION.json
|
||||
61d9d7ea769df6546382b06081bd6dcf376c07deb9bc613aad6257c863190341 __pycache__/phase4o_a.cpython-310.pyc
|
||||
8b380f0597dd3f2d656e9e773a581855f75d940bcc0dad9e84abb6b02173aa16 phase4o.yaml
|
||||
1048a073de399052bd525faf010858fa83f075a7c747b3fe5dcf8e4fc9ce3b87 phase4o_a.py
|
||||
b481d91ac3a72d360c4dbb5378b975e430f0d1027fad94de5e2a041f9849c714 phase4o_atomic.py
|
||||
4fb7c97c8832c3ef51fe7613083dd6eab627bcde419254696c19a07632deb878 phase4o_eligibility.py
|
||||
b169937bab495c77d8ee6c1013877e7500e7354140d9fcc90595d984238ba44e phase4o_event_replay.py
|
||||
db6318467fb1ecef4003077ec1db8eac299c0c56944f463f96418ab41135c08f phase4o_finalize.py
|
||||
8980ff1581c81d99752515349ee7be747a6f954a94ab56492b400a5324f1b6a2 phase4o_modes.py
|
||||
cfd6cc4dd0f2c0d58b5eb2634fb4e6bd530eec5037c4c8462f6ef7a885301200 phase4o_targeted.py
|
||||
@@ -0,0 +1,28 @@
|
||||
phase: 4O
|
||||
stage: A-runtime-determinism-recovery
|
||||
status_policy: fail-closed
|
||||
experiment_root: /data/digital-drosophila/experiments/phase4o-runtime-credit
|
||||
model_root: /data/digital-drosophila/models/male-cns-lif/runtime-credit-v1
|
||||
frozen_phase4c_config: /data/digital-drosophila/models/male-cns-lif/runtime-v1/phase4c.yaml
|
||||
frozen_phase4m_config: /data/digital-drosophila/models/male-cns-lif/kcmbon-efficacy-v1/phase4m.yaml
|
||||
frozen_phase4n_config: /data/digital-drosophila/models/male-cns-lif/credit-assignment-v1/phase4n.yaml
|
||||
required_gpu_uuid: GPU-79f3a85d-adce-7833-7003-6488140ca596
|
||||
phase4c_reference_trials: [auditory-10hz, auditory-100hz, olfactory-50hz, mechanosensory-50hz, gustatory-50hz]
|
||||
phase4c_repeats_per_trial: 10
|
||||
phase4m_training_trials: 500
|
||||
eligibility_complete_event_repeats: 5
|
||||
pass_requires:
|
||||
phase4c_spike_events_exact: true
|
||||
phase4c_per_neuron_counts_exact: true
|
||||
frozen_phase4m_eligibility_exact: true
|
||||
instrumentation_independent: true
|
||||
logging_independent: true
|
||||
backend_identity_fixed: true
|
||||
frozen_artifacts_unchanged: true
|
||||
part_b_gate: PASS-RUNTIME-DETERMINISM-RECOVERED
|
||||
prohibitions:
|
||||
modify_frozen_artifact: true
|
||||
modify_brain_dynamics: true
|
||||
modify_eligibility_v2: true
|
||||
train: true
|
||||
start_part_b_on_part_a_fail: true
|
||||
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Read-only Phase 4O-A runtime determinism audit; never writes frozen roots."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import random
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pyarrow.parquet as pq
|
||||
import torch
|
||||
import yaml
|
||||
|
||||
ROOT = Path("/data/digital-drosophila")
|
||||
EXP = ROOT / "experiments/phase4o-runtime-credit"
|
||||
MODEL = ROOT / "models/male-cns-lif/runtime-credit-v1"
|
||||
FROZEN = ROOT / "experiments/phase4c-runtime/regression/reference"
|
||||
GPU_UUID = "GPU-79f3a85d-adce-7833-7003-6488140ca596"
|
||||
|
||||
|
||||
def save(path: Path, value: object) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(value, ensure_ascii=False, indent=2, sort_keys=True, default=str) + "\n")
|
||||
|
||||
|
||||
def sha(path: Path) -> str:
|
||||
h = hashlib.sha256()
|
||||
with path.open("rb") as f:
|
||||
for block in iter(lambda: f.read(8 << 20), b""):
|
||||
h.update(block)
|
||||
return h.hexdigest()
|
||||
|
||||
|
||||
def digest(data: bytes) -> str:
|
||||
return hashlib.sha256(data).hexdigest()
|
||||
|
||||
|
||||
def cmd(args: list[str]) -> dict:
|
||||
exe = shutil.which(args[0])
|
||||
if exe is None:
|
||||
return {"available": False}
|
||||
p = subprocess.run(args, text=True, capture_output=True)
|
||||
return {"available": True, "exit_code": p.returncode, "stdout": p.stdout.strip()[:8000], "stderr": p.stderr.strip()[:2000]}
|
||||
|
||||
|
||||
def env_audit() -> None:
|
||||
if os.environ.get("CUDA_VISIBLE_DEVICES") != GPU_UUID:
|
||||
raise RuntimeError("CUDA_VISIBLE_DEVICES must select frozen RTX 4090 UUID")
|
||||
names = ["CUDA_VISIBLE_DEVICES", "CUBLAS_WORKSPACE_CONFIG", "PYTHONHASHSEED", "OMP_NUM_THREADS", "MKL_NUM_THREADS"]
|
||||
names += sorted(x for x in os.environ if x.startswith("TORCH_"))
|
||||
gpu = torch.cuda.get_device_properties(0)
|
||||
e = {"OS_release": platform.platform(), "kernel": platform.release(), "uname": platform.uname()._asdict(),
|
||||
"python": sys.version, "torch": torch.__version__, "cuda_runtime": torch.version.cuda,
|
||||
"cudnn": torch.backends.cudnn.version(), "gpu_name": gpu.name, "gpu_uuid": GPU_UUID,
|
||||
"gpu_total_memory_bytes": gpu.total_memory, "env_allowlist": {x: os.environ.get(x) for x in names},
|
||||
"nvcc": cmd(["nvcc", "--version"]), "nvidia_smi": cmd(["nvidia-smi", "--query-gpu=name,uuid,driver_version,memory.total", "--format=csv,noheader"]),
|
||||
"gcc": cmd(["gcc", "--version"]), "gxx": cmd(["g++", "--version"]), "ninja": cmd(["ninja", "--version"]),
|
||||
"git_model": cmd(["git", "-C", str(ROOT / "models/male-cns-lif"), "status", "--short", "--branch"]),
|
||||
"git_workspace": cmd(["git", "-C", str(ROOT), "rev-parse", "HEAD"]),
|
||||
"torch_flags": {"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,
|
||||
"matmul_precision": torch.get_float32_matmul_precision()}}
|
||||
save(EXP / "environment/runtime-environment.json", e)
|
||||
roots = [ROOT / "models/male-cns-lif/reference-v1", ROOT / "models/male-cns-lif/runtime-v1",
|
||||
FROZEN, ROOT / "models/male-cns-lif/kcmbon-efficacy-v1",
|
||||
ROOT / "experiments/phase4n-credit-assignment/compiler-reports/extension-build",
|
||||
ROOT / "experiments/phase4c-runtime/compiler-reports/extension-build"]
|
||||
files = []
|
||||
for root in roots:
|
||||
if root.exists():
|
||||
for p in sorted(root.rglob("*")):
|
||||
if p.is_file() and p.suffix not in (".pyc", ".o"):
|
||||
files.append({"path": str(p), "bytes": p.stat().st_size, "mtime_ns": p.stat().st_mtime_ns, "sha256": sha(p)})
|
||||
for p in [ROOT / "models/male-cns-lif/brain_runtime.py", ROOT / "models/male-cns-lif/phase4i.py",
|
||||
ROOT / "models/male-cns-lif/phase4m.py", ROOT / "models/male-cns-lif/phase4l.py",
|
||||
ROOT / "models/male-cns-lif/phase4n_events.py"]:
|
||||
if p.is_file():
|
||||
files.append({"path": str(p), "bytes": p.stat().st_size, "mtime_ns": p.stat().st_mtime_ns, "sha256": sha(p)})
|
||||
save(EXP / "binary-audit/execution-file-sha256.json", files)
|
||||
binary = [x for x in files if x["path"].endswith(".so")]
|
||||
save(EXP / "binary-audit/runtime-binary-diff-report.json", {
|
||||
"binary_files": binary, "bytewise_same": len({x["sha256"] for x in binary}) == 1 if len(binary) > 1 else None,
|
||||
"warning": "A binary hash difference is not itself proof of changed semantics; build paths and toolchain can alter ELF bytes.",
|
||||
"historical_phase4c_manifest": str(ROOT / "experiments/phase4c-runtime/manifests/manifest.json")})
|
||||
|
||||
|
||||
def rng_hashes(rt=None) -> dict:
|
||||
py = digest(repr(random.getstate()).encode())
|
||||
npy = digest(repr(np.random.get_state()).encode())
|
||||
out = {"python_random": py, "numpy_global": npy, "torch_cpu": digest(torch.get_rng_state().numpy().tobytes()),
|
||||
"torch_cuda": digest(torch.cuda.get_rng_state(0).cpu().numpy().tobytes())}
|
||||
if rt is not None and hasattr(rt, "generator"):
|
||||
out["input_generator"] = digest(rt.generator.get_state().cpu().numpy().tobytes())
|
||||
return out
|
||||
|
||||
|
||||
def first_event_diff(a_step, a_node, b_step, b_node):
|
||||
n = min(len(a_step), len(b_step))
|
||||
mismatched = np.flatnonzero((a_step[:n] != b_step[:n]) | (a_node[:n] != b_node[:n]))
|
||||
j = int(mismatched[0]) if len(mismatched) else (n if len(a_step) != len(b_step) else None)
|
||||
if j is None:
|
||||
return None
|
||||
ref = None if j >= len(a_step) else {"step": int(a_step[j]), "neuron_idx": int(a_node[j])}
|
||||
got = None if j >= len(b_step) else {"step": int(b_step[j]), "neuron_idx": int(b_node[j])}
|
||||
step = min(x["step"] for x in (ref, got) if x is not None)
|
||||
return {"event_position": j, "first_difference_step_upper_bound": step, "reference_event": ref, "observed_event": got,
|
||||
"note": "Event-list first difference is not necessarily first state divergence; state-level instrumentation is required."}
|
||||
|
||||
|
||||
def repeat_audit(repeats: int, trial_filter: str | None = None, tag: str = "baseline") -> None:
|
||||
from brain_runtime import BrainRuntime
|
||||
from phase4i import poisson_batch
|
||||
cfgpath = ROOT / "models/male-cns-lif/mb-mechanistic-v1/phase4i.yaml"
|
||||
rt = BrainRuntime(cfgpath, EXP / "compiler-reports/extension-build")
|
||||
backend_file = Path(rt.extension.__file__)
|
||||
identity = {"module": rt.extension.__name__, "binary_path": str(backend_file), "binary_sha256": sha(backend_file),
|
||||
"runtime_v1_python_sha256": sha(ROOT / "models/male-cns-lif/runtime-v1/phase4c.py"),
|
||||
"source": "BrainRuntime._hybrid_edges plus GPU scatter_add_", "config": str(cfgpath), "config_sha256": sha(cfgpath)}
|
||||
save(EXP / "binary-audit/loaded-backend.json", identity)
|
||||
specs = [(s["name"], s["population"], float(s["rate_hz"]), int(s["seed"])) for s in yaml.safe_load((ROOT / "models/male-cns-lif/runtime-v1/phase4c.yaml").read_text())["reference_trials"]]
|
||||
if trial_filter:
|
||||
specs = [x for x in specs if x[0] == trial_filter]
|
||||
if not specs: raise ValueError(f"unknown frozen trial {trial_filter}")
|
||||
rows = []
|
||||
output_dir = EXP / "phase4c-replay" / tag
|
||||
for name, pop, rate, seed in specs:
|
||||
refroot = FROZEN / name
|
||||
table = pq.read_table(refroot / "spike-events.parquet")
|
||||
rstep = table["step"].to_numpy().astype(np.int32); rnode = table["neuron_idx"].to_numpy().astype(np.int32)
|
||||
rcount = np.load(refroot / "per-neuron-spike-counts.int32.npy")
|
||||
rv = np.load(refroot / "final-voltage.float32.npy"); rg = np.load(refroot / "final-g.float32.npy")
|
||||
targets = np.flatnonzero(rt.population_masks[pop]).astype(np.int64)
|
||||
for repeat in range(repeats):
|
||||
before = rng_hashes(rt)
|
||||
rt.reset(seed)
|
||||
after_reset = rng_hashes(rt)
|
||||
before_first = rng_hashes(rt)
|
||||
t0 = time.perf_counter()
|
||||
error = None
|
||||
try:
|
||||
rt.step(poisson_batch(targets, rate, 1000.0, name), 1000.0)
|
||||
events = rt.read_spikes()
|
||||
step = events["step"].astype(np.int32); node = events["neuron_idx"].astype(np.int32)
|
||||
counts = rt.spike_counts.cpu().numpy().astype(np.int32)
|
||||
voltage = rt.v.cpu().numpy(); g = rt.g.cpu().numpy()
|
||||
match_events = bool(np.array_equal(step, rstep) and np.array_equal(node, rnode))
|
||||
match_counts = bool(np.array_equal(counts, rcount))
|
||||
row = {"trial": name, "repeat": repeat, "target_count": int(len(targets)),
|
||||
"spike_events_exact": match_events, "per_neuron_counts_exact": match_counts,
|
||||
"final_voltage_max_abs_error": float(np.max(np.abs(voltage-rv))),
|
||||
"final_g_max_abs_error": float(np.max(np.abs(g-rg))),
|
||||
"event_count": len(node), "event_sha256": digest(step.tobytes()+node.tobytes()),
|
||||
"counts_sha256": digest(counts.tobytes()), "first_event_difference": first_event_diff(rstep,rnode,step,node),
|
||||
"wall_seconds": time.perf_counter()-t0,
|
||||
"rng_before_reset": before, "rng_after_reset": after_reset,
|
||||
"rng_before_first_timestep": before_first, "rng_after_trial": rng_hashes(rt)}
|
||||
if not match_events:
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
pq.write_table(__import__('pyarrow').table({'step':step,'neuron_idx':node}),
|
||||
output_dir / f"divergent-{name}-repeat-{repeat}-events.parquet",compression='zstd')
|
||||
np.savez_compressed(output_dir / f"divergent-{name}-repeat-{repeat}-state.npz",
|
||||
final_voltage=voltage, final_g=g, counts=counts)
|
||||
except Exception as exc:
|
||||
error = repr(exc)
|
||||
row = {"trial": name, "repeat": repeat, "error": error, "wall_seconds": time.perf_counter()-t0,
|
||||
"rng_before_reset": before, "rng_after_reset": after_reset}
|
||||
rows.append(row)
|
||||
save(output_dir / "reproducibility-matrix.json", rows)
|
||||
print(json.dumps({"trial": name, "repeat": repeat, "event_exact": row.get("spike_events_exact"),
|
||||
"count_exact": row.get("per_neuron_counts_exact"), "first_diff": row.get("first_event_difference"), "error": error}), flush=True)
|
||||
save(output_dir / "summary.json", {"repeats_per_trial": repeats, "all_spike_events_exact": all(r.get("spike_events_exact",False) for r in rows),
|
||||
"all_counts_exact": all(r.get("per_neuron_counts_exact",False) for r in rows),
|
||||
"trial_summary": {name: {"event_exact": sum(r.get("spike_events_exact",False) for r in rows if r["trial"]==name),
|
||||
"count_exact": sum(r.get("per_neuron_counts_exact",False) for r in rows if r["trial"]==name)} for name,_,_,_ in specs},
|
||||
"backend": identity})
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("task", choices=["environment", "repeats"])
|
||||
ap.add_argument("--repeats", type=int, default=10)
|
||||
ap.add_argument("--trial")
|
||||
ap.add_argument("--tag", default="baseline")
|
||||
args = ap.parse_args()
|
||||
EXP.mkdir(parents=True, exist_ok=True); MODEL.mkdir(parents=True, exist_ok=True)
|
||||
if args.task == "environment": env_audit()
|
||||
else: repeat_audit(args.repeats, args.trial, args.tag)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Real Phase 4C event/CSR atomic-collision micro-reproduction (read-only inputs)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pyarrow.parquet as pq
|
||||
import torch
|
||||
import yaml
|
||||
|
||||
from phase4o_a import EXP,FROZEN,ROOT,save
|
||||
|
||||
|
||||
def main():
|
||||
trial='mechanosensory-50hz'
|
||||
step=6625
|
||||
delay=18
|
||||
focus=[3942,3954]
|
||||
ref=pq.read_table(FROZEN/trial/'spike-events.parquet',columns=['step','neuron_idx']).to_pandas()
|
||||
src=ref.loc[ref.step==step-delay,'neuron_idx'].to_numpy(np.int32)
|
||||
graph=ROOT/'datasets/male-cns-v1.0/processed/neuron-only/gpu'
|
||||
indptr=np.load(graph/'csr-indptr.int64.npy',mmap_mode='r')
|
||||
indices=np.load(graph/'csr-indices.int32.npy',mmap_mode='r')
|
||||
raw=np.load(graph/'csr-weights.int64.npy',mmap_mode='r')
|
||||
cfg=yaml.safe_load((ROOT/'models/male-cns-lif/runtime-v1/phase4c.yaml').read_text())
|
||||
meta=pq.read_table(ROOT/'datasets/male-cns-v1.0/processed/neuron-only/neuron-index/unified-metadata.parquet',columns=['neurotransmitter']).column('neurotransmitter').to_pylist()
|
||||
signs=[]
|
||||
policy=cfg['sign_policy'];mp=policy['neurotransmitter_sign']
|
||||
for n in src:
|
||||
val=meta[int(n)]
|
||||
key='' if val is None else str(val).strip().lower()
|
||||
signs.append(policy['unknown_sign'] if not key else policy['unclear_sign'] if key=='unclear' else mp[key])
|
||||
edge_ids=np.concatenate([np.arange(int(indptr[n]),int(indptr[n+1]),dtype=np.int64) for n in src]) if len(src) else np.empty(0,np.int64)
|
||||
edge_src=np.repeat(src,(indptr[src+1]-indptr[src]).astype(np.int64))
|
||||
sign_edge=np.repeat(np.asarray(signs,np.int8),(indptr[src+1]-indptr[src]).astype(np.int64))
|
||||
tgt=np.asarray(indices[edge_ids],np.int32)
|
||||
w=(np.asarray(raw[edge_ids],np.float32)*sign_edge.astype(np.float32)*np.float32(cfg['model']['w_syn_mv_per_anatomical_synapse'])).astype(np.float32)
|
||||
counts=np.bincount(tgt,minlength=166700)
|
||||
# Run the unchanged scatter_add_ ordering against the real active-event edge subset.
|
||||
target_gpu=torch.as_tensor(tgt,dtype=torch.int64,device='cuda:0')
|
||||
weight_gpu=torch.as_tensor(w,dtype=torch.float32,device='cuda:0')
|
||||
samples=[];all_samples=[]
|
||||
for _ in range(100):
|
||||
out=torch.zeros(166700,dtype=torch.float32,device='cuda:0')
|
||||
out.scatter_add_(0,target_gpu,weight_gpu)
|
||||
all_samples.append(out.cpu().numpy().copy())
|
||||
samples.append(all_samples[-1][focus].copy())
|
||||
sampled=np.asarray(samples,np.float32)
|
||||
full=np.asarray(all_samples,np.float32)
|
||||
spread=np.ptp(full,axis=0)
|
||||
variable=np.flatnonzero(spread>0)
|
||||
detail=[]
|
||||
for j,n in enumerate(focus):
|
||||
loc=np.flatnonzero(tgt==n)
|
||||
contrib=w[loc]
|
||||
# Deterministic reference keyed by original anatomical edge_id.
|
||||
order=np.argsort(edge_ids[loc],kind='stable')
|
||||
acc=np.float32(0)
|
||||
for value in contrib[order]: acc=np.float32(acc+value)
|
||||
detail.append({'target_neuron_idx':n,'same_target_writes':len(loc),'incoming_source_neuron_idx':edge_src[loc].tolist(),
|
||||
'incoming_edge_ids':edge_ids[loc].tolist(),'incoming_effective_weights_mv':contrib.tolist(),
|
||||
'cpu_edge_order_float32_sum_mv':float(acc),'cpu_float64_sum_mv':float(np.sum(contrib.astype(np.float64))),
|
||||
'gpu_atomic_min_mv':float(sampled[:,j].min()),'gpu_atomic_max_mv':float(sampled[:,j].max()),
|
||||
'gpu_atomic_unique_values':np.unique(sampled[:,j]).tolist()})
|
||||
report={'reference_divergence_event_step':step,'arrival_source_step':step-delay,
|
||||
'arrival_presynaptic_count':len(src),'fanout_edges':len(edge_ids),
|
||||
'targets_with_multiple_concurrent_writes':int(np.count_nonzero(counts>1)),
|
||||
'maximum_same_target_writes':int(counts.max()),
|
||||
'targets_with_nonidentical_atomic_sum_across_100_repeats':len(variable),
|
||||
'max_atomic_sum_range_mv':float(spread.max()),
|
||||
'variable_target_examples':variable[:30].tolist(),
|
||||
'focus':detail,'gpu_atomic_repetitions':len(samples),
|
||||
'interpretation':'Collisions and float-order sensitivity are necessary evidence, not by themselves proof of the first state divergence.'}
|
||||
save(EXP/'atomic/real-edge-subset.json',report)
|
||||
print(json.dumps({'source_step':step-delay,'fanout_edges':len(edge_ids),'collision_targets':report['targets_with_multiple_concurrent_writes'],
|
||||
'max_fanin':report['maximum_same_target_writes'],'focus':[{'neuron_idx':x['target_neuron_idx'],
|
||||
'writes':x['same_target_writes'],'gpu_unique':len(x['gpu_atomic_unique_values'])} for x in detail]}),flush=True)
|
||||
|
||||
|
||||
if __name__=='__main__':main()
|
||||
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Five read-only repeats of sealed Phase 4M's 500-trial eligibility trajectory."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import torch
|
||||
|
||||
from phase4n import load_config
|
||||
from phase4i import Validator
|
||||
from phase4j import apply_v2
|
||||
from phase4l import OdorSimulator, pn_drive
|
||||
from phase4m import load_odor_inputs
|
||||
|
||||
ROOT = Path("/data/digital-drosophila")
|
||||
EXP = ROOT / "experiments/phase4o-runtime-credit"
|
||||
|
||||
|
||||
def save(path: Path, x: object) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(json.dumps(x, indent=2, sort_keys=True, default=str) + "\n")
|
||||
|
||||
|
||||
def arrhash(x: np.ndarray) -> str:
|
||||
return hashlib.sha256(x.tobytes()).hexdigest()
|
||||
|
||||
|
||||
def first_diff(a: np.ndarray, b: np.ndarray):
|
||||
n = min(len(a), len(b))
|
||||
mismatched = np.flatnonzero(a[:n] != b[:n])
|
||||
j = int(mismatched[0]) if len(mismatched) else (n if len(a) != len(b) else None)
|
||||
if j is None:
|
||||
return None
|
||||
return {"event_position": j, "reference": None if j >= len(a) else int(a[j]), "observed": None if j >= len(b) else int(b[j])}
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--repeats", type=int, default=5)
|
||||
args = ap.parse_args()
|
||||
ncfg, mcfg, cfg, cfgpath = load_config(ROOT / "models/male-cns-lif/credit-assignment-v1/phase4n.yaml")
|
||||
history = pd.read_parquet(Path(mcfg["experiment_root"]) / "efficacy-overlay/update-history.parquet")
|
||||
frozen = {(int(s), int(p)): f for (s, p), f in history.groupby(["train_seed", "pairing"])}
|
||||
old = pd.read_parquet(ROOT / "experiments/phase4n-credit-assignment/local-eligibility/KC-spike-history.parquet")
|
||||
old_events = {(int(s), int(p)): f[["step", "neuron_idx"]].to_numpy(np.int32)
|
||||
for (s, p), f in old.groupby(["seed", "pairing"])}
|
||||
v = Validator(cfg, cfgpath, EXP)
|
||||
sim = OdorSimulator(v, cfg, EXP)
|
||||
panel, vectors, selection, mapping = load_odor_inputs(cfg)
|
||||
oid = selection["ODOR_A"]["odor_id"]
|
||||
pn = pn_drive(oid, vectors[oid], mapping, selection["glomeruli_order"], str(mcfg["protocol"]["input_mode"]),
|
||||
float(np.median(panel.mapped_response_sum)), cfg)[:2]
|
||||
target = str(mcfg["protocol"]["target_compartment_verbatim"])
|
||||
dan = v.dan_targets(str(mcfg["protocol"]["matched_dan_type"]), target)
|
||||
src = v.cand.source_neuron_idx.to_numpy(np.int32)
|
||||
lookup = np.full(v.n, -1, np.int32)
|
||||
lookup[v.kc] = np.arange(len(v.kc), dtype=np.int32)
|
||||
loc = lookup[src]
|
||||
comp = v.cand.target_compartment_verbatim.astype(str).to_numpy() == target
|
||||
ids = v.edge_ids.astype(np.int64)
|
||||
id_to_local = pd.Series(np.arange(len(ids), dtype=np.int32), index=ids)
|
||||
seen = {}
|
||||
rows = []
|
||||
first_failures = []
|
||||
for repeat in range(args.repeats):
|
||||
for seed in ncfg["train_seeds"]:
|
||||
delta = np.zeros(len(ids), np.float32)
|
||||
for pairing in range(1, 101):
|
||||
start = time.perf_counter()
|
||||
run = sim.run_rates(*pn, seed+pairing, float(mcfg["protocol"]["duration_ms"]),
|
||||
delta=delta, dan_targets=dan, dan_pulses=[float(mcfg["protocol"]["dan_time_ms"])],
|
||||
collect_kc_spikes=True)
|
||||
trace = run["kc_trace_at_dan"]
|
||||
events = run["kc_spikes"][["step", "neuron_idx"]].to_numpy(np.int32)
|
||||
old_ev = old_events.get((seed, pairing), np.empty((0, 2), np.int32))
|
||||
rec = frozen[(seed, pairing)]
|
||||
local = id_to_local.loc[rec.edge_id.to_numpy(np.int64)].to_numpy(np.int32)
|
||||
value = trace[loc[local]]
|
||||
recorded = rec.eligibility.to_numpy(np.float32)
|
||||
max_err = float(np.max(np.abs(value-recorded))) if len(value) else 0.0
|
||||
nonzero_now = np.flatnonzero(comp & (trace[loc] > 0))
|
||||
frozen_active = set(map(int, local))
|
||||
active_symmetric_diff = len(set(map(int, nonzero_now)) ^ frozen_active)
|
||||
key = (seed,pairing)
|
||||
h = arrhash(events)
|
||||
if key not in seen:
|
||||
seen[key] = h
|
||||
row = {"repeat": repeat, "seed": seed, "pairing": pairing,
|
||||
"KC_event_count": len(events), "KC_event_sha256": h,
|
||||
"KC_events_same_as_first_repeat": h == seen[key],
|
||||
"KC_events_same_as_phase4n_audit": bool(np.array_equal(events, old_ev)),
|
||||
"first_KC_event_difference_from_phase4n": first_diff(old_ev[:,0],events[:,0]) if not np.array_equal(events,old_ev) else None,
|
||||
"eligibility_max_abs_error_vs_frozen_phase4m": max_err,
|
||||
"eligibility_active_edge_symmetric_difference": active_symmetric_diff,
|
||||
"exact_eligibility": bool(max_err <= 2e-5 and active_symmetric_diff == 0),
|
||||
"trace_sha256": arrhash(trace), "runtime_wall_seconds": run["wall_seconds"],
|
||||
"audit_wall_seconds": time.perf_counter()-start}
|
||||
if not row["exact_eligibility"]:
|
||||
err = np.abs(value-recorded)
|
||||
j = int(np.argmax(err)) if len(err) else None
|
||||
row["first_edge_mismatch"] = None if j is None else {
|
||||
"edge_id": int(rec.edge_id.iloc[j]), "KC_neuron_idx": int(src[local[j]]),
|
||||
"DAN_pulse_ms": float(mcfg["protocol"]["dan_time_ms"]),
|
||||
"observed_trace": float(value[j]), "frozen_trace": float(recorded[j]),
|
||||
"delta_trace": float(value[j]-recorded[j])}
|
||||
if len(first_failures) < 20:
|
||||
first_failures.append(row)
|
||||
path = EXP / "eligibility-replay" / f"mismatch-repeat-{repeat}-seed-{seed}-pairing-{pairing}-KC-events.parquet"
|
||||
path.parent.mkdir(parents=True,exist_ok=True)
|
||||
run["kc_spikes"].to_parquet(path,index=False)
|
||||
rows.append(row)
|
||||
# Keep subsequent brain input equal to the sealed historical additive trajectory,
|
||||
# even when a diagnostic trial diverged; no frozen state is ever overwritten.
|
||||
sealed_trace = np.zeros(len(v.kc), np.float32)
|
||||
sealed_trace[loc[local]] = recorded
|
||||
delta, _ = apply_v2(v, sealed_trace, target, 1.0, delta, cfg)
|
||||
if pairing % 20 == 0:
|
||||
save(EXP / "eligibility-replay/reproducibility-matrix.json", rows)
|
||||
print(json.dumps({"repeat":repeat,"seed":seed,"pairing":pairing,
|
||||
"exact_in_block":sum(r["exact_eligibility"] for r in rows[-20:]),
|
||||
"event_repeat_exact_in_block":sum(r["KC_events_same_as_first_repeat"] for r in rows[-20:])}),flush=True)
|
||||
save(EXP / "eligibility-replay/reproducibility-matrix.json", rows)
|
||||
save(EXP / "eligibility-replay/summary.json", {"complete_repeats": args.repeats, "trials_per_repeat":500,
|
||||
"exact_frozen_eligibility_count":sum(r["exact_eligibility"] for r in rows),
|
||||
"exact_repeat_event_count":sum(r["KC_events_same_as_first_repeat"] for r in rows),
|
||||
"all_exact":all(r["exact_eligibility"] and r["KC_events_same_as_first_repeat"] for r in rows),
|
||||
"first_failures":first_failures,
|
||||
"historical_training_KC_event_sequence_available":False,
|
||||
"phase4n_event_sequence_used_as_comparator":True,
|
||||
"note":"Phase4M sealed only eligibility/update history, not all training KC events; Phase4N KC events are a later audit comparator."})
|
||||
|
||||
|
||||
if __name__ == "__main__": main()
|
||||
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Exact-order replay of all frozen Phase 4N KC events through Phase 4M eligibility."""
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import pyarrow.parquet as pq
|
||||
import yaml
|
||||
|
||||
ROOT=Path('/data/digital-drosophila')
|
||||
EXP=ROOT/'experiments/phase4o-runtime-credit'
|
||||
MODEL=ROOT/'models/male-cns-lif'
|
||||
|
||||
|
||||
def save(p,x):
|
||||
p.parent.mkdir(parents=True,exist_ok=True)
|
||||
p.write_text(json.dumps(x,indent=2,sort_keys=True,default=str)+'\n')
|
||||
|
||||
|
||||
def h(x): return hashlib.sha256(x.tobytes()).hexdigest()
|
||||
|
||||
|
||||
def main():
|
||||
ncfg=yaml.safe_load((MODEL/'credit-assignment-v1/phase4n.yaml').read_text())
|
||||
mcfg=yaml.safe_load((MODEL/'kcmbon-efficacy-v1/phase4m.yaml').read_text())
|
||||
lcfg=yaml.safe_load(Path(mcfg['frozen_phase4l_config']).read_text())
|
||||
cfg=lcfg
|
||||
identity=pd.read_parquet(ROOT/'experiments/phase4n-credit-assignment/edge-identity/frozen-edge-identity.parquet')
|
||||
historical=pd.read_parquet(Path(mcfg['experiment_root'])/'efficacy-overlay/update-history.parquet')
|
||||
kc_events=pd.read_parquet(ROOT/'experiments/phase4n-credit-assignment/local-eligibility/KC-spike-history.parquet')
|
||||
graph=Path(cfg['paths']['connectome_root'])
|
||||
meta=pq.read_table(graph/'neuron-index/unified-metadata.parquet',columns=['neuron_idx','annotation_class']).to_pandas()
|
||||
kc=meta.loc[meta.annotation_class=='Kenyon_Cell','neuron_idx'].to_numpy(np.int32)
|
||||
kc.sort()
|
||||
lookup=np.full(len(meta),-1,np.int32);lookup[kc]=np.arange(len(kc),dtype=np.int32)
|
||||
src=identity.source_neuron_idx.to_numpy(np.int32);local=lookup[src]
|
||||
if (local<0).any(): raise RuntimeError('non-KC edge source')
|
||||
comp=identity.compartment.astype(str).to_numpy()==str(ncfg['matched_compartment_verbatim'])
|
||||
edgeid=identity.edge_id.to_numpy(np.int64)
|
||||
id_to_local=pd.Series(np.arange(len(identity),dtype=np.int32),index=edgeid)
|
||||
events={(int(seed),int(pair)):group[['step','neuron_idx']].to_numpy(np.int32)
|
||||
for (seed,pair),group in kc_events.groupby(['seed','pairing'])}
|
||||
histories={(int(seed),int(pair)):group for (seed,pair),group in historical.groupby(['train_seed','pairing'])}
|
||||
dt=float(cfg['model']['dt_ms']);tau=float(cfg['eligibility_v2']['kc_trace_tau_ms'])
|
||||
decay=np.float32(math.exp(-dt/tau));step_gate=int(round(float(mcfg['protocol']['dan_time_ms'])/dt))
|
||||
k=np.float32(cfg['eligibility_v2']['eta_effective_mv']/cfg['model']['w_syn_mv_per_anatomical_synapse'])
|
||||
bound=np.float32(1.0-cfg['eligibility_v2']['max_fractional_depression'])
|
||||
results=[];first_signatures={};mismatch_examples=[]
|
||||
for repeat in range(5):
|
||||
for seed in ncfg['train_seeds']:
|
||||
E=np.ones(len(identity),np.float32)
|
||||
for pairing in range(1,101):
|
||||
arr=events.get((seed,pairing),np.empty((0,2),np.int32))
|
||||
# Phase4N emitted events in simulation-time, then neuron_idx order.
|
||||
if len(arr) and (np.any(arr[:,0]<0) or np.any(arr[:,0]>=int(round(mcfg['protocol']['duration_ms']/dt)))): raise RuntimeError('invalid event timestamp')
|
||||
if len(arr)>1 and (np.any(arr[1:,0]<arr[:-1,0]) or np.any((arr[1:,0]==arr[:-1,0])&(arr[1:,1]<=arr[:-1,1]))): raise RuntimeError('event tie/duplicate/order ambiguity')
|
||||
relevant=arr[arr[:,0]<=step_gate]
|
||||
if len(relevant) and (lookup[relevant[:,1]]<0).any(): raise RuntimeError('non-KC event')
|
||||
by_step={int(step):lookup[relevant[relevant[:,0]==step,1]] for step in np.unique(relevant[:,0])}
|
||||
trace=np.zeros(len(kc),np.float32)
|
||||
for step in range(step_gate+1):
|
||||
trace*=decay
|
||||
firing=by_step.get(step)
|
||||
if firing is not None: trace[firing]+=np.float32(1)
|
||||
np.minimum(trace,np.float32(1),out=trace)
|
||||
rec=histories[(seed,pairing)]
|
||||
rid=id_to_local.loc[rec.edge_id.to_numpy(np.int64)].to_numpy(np.int32)
|
||||
observed=trace[local[rid]]
|
||||
expected=rec.eligibility.to_numpy(np.float32)
|
||||
err=np.abs(observed-expected)
|
||||
actual=np.flatnonzero(comp&(trace[local]>0))
|
||||
missing=np.setdiff1d(rid,actual,assume_unique=True)
|
||||
extra=np.setdiff1d(actual,rid,assume_unique=True)
|
||||
predicted=np.maximum(bound,E[rid]*(np.float32(1)-k*observed))
|
||||
frozen_after=rec.E_bounded_after.to_numpy(np.float32)
|
||||
update_error=float(np.max(np.abs(predicted-frozen_after))) if len(predicted) else 0.0
|
||||
trace_error=float(err.max()) if len(err) else 0.0
|
||||
signature=h(np.concatenate((arr.flatten(),observed.view(np.int32),predicted.view(np.int32))))
|
||||
key=(seed,pairing)
|
||||
first_signatures.setdefault(key,signature)
|
||||
row={'repeat':repeat,'seed':seed,'pairing':pairing,'event_count':len(arr),'event_sha256':h(arr),
|
||||
'gate_step':step_gate,'eligibility_sha256':h(observed),'update_sha256':h(predicted),
|
||||
'repeat_exact':signature==first_signatures[key],
|
||||
'frozen_trace_max_abs_error':trace_error,'frozen_update_max_abs_error':update_error,
|
||||
'missing_frozen_active_edges':len(missing),'extra_active_edges':len(extra),
|
||||
'exact_to_phase4m':trace_error<=2e-5 and update_error<=2e-5 and len(missing)==0 and len(extra)==0}
|
||||
if not row['exact_to_phase4m'] and len(mismatch_examples)<30:
|
||||
j=int(np.argmax(err)) if len(err) else None
|
||||
row['example']={'edge_id':int(rec.edge_id.iloc[j]) if j is not None else None,
|
||||
'KC_neuron_idx':int(src[rid[j]]) if j is not None else None,
|
||||
'timestamp_ms':float(mcfg['protocol']['dan_time_ms']),
|
||||
'event_trace':float(observed[j]) if j is not None else None,
|
||||
'frozen_trace':float(expected[j]) if j is not None else None,
|
||||
'frozen_delta_E':float(frozen_after[j]-rec.E_bounded_before.iloc[j]) if j is not None else None,
|
||||
'missing_edge_ids':edgeid[missing[:20]].tolist(),'extra_edge_ids':edgeid[extra[:20]].tolist()}
|
||||
mismatch_examples.append(row.copy())
|
||||
results.append(row)
|
||||
# Each trial is run against the sealed Phase4M before/after trajectory.
|
||||
# A divergent diagnostic event trace never feeds the next trial.
|
||||
E[rid]=frozen_after
|
||||
print(json.dumps({'repeat':repeat,'seed':seed,'total_so_far':len(results),
|
||||
'exact_to_phase4m_so_far':sum(r['exact_to_phase4m'] for r in results)}),flush=True)
|
||||
save(EXP/'eligibility-replay/event-reproducibility-matrix.json',results)
|
||||
save(EXP/'eligibility-replay/event-reproducibility-matrix.json',results)
|
||||
save(EXP/'eligibility-replay/event-replay-summary.json',{'complete_repeats':5,'events_per_repeat':500,
|
||||
'same_event_and_update_sequence_5_of_5':all(r['repeat_exact'] for r in results),
|
||||
'all_exact_to_frozen_phase4m':all(r['exact_to_phase4m'] for r in results),
|
||||
'frozen_exact_count_by_repeat':{str(rep):sum(r['exact_to_phase4m'] for r in results if r['repeat']==rep) for rep in range(5)},
|
||||
'mismatch_examples':mismatch_examples,
|
||||
'event_order_contract_observed':'simulation_step ascending, neuron_idx ascending, no duplicate KC/step; trace updated after spike; external gate sampled after step 900 trace update',
|
||||
'limitation':'Phase4M did not seal its training KC event sequence. Phase4N sealed the later event replay; exact repeat of those events does not prove the original GPU trajectory.'})
|
||||
|
||||
|
||||
if __name__=='__main__':main()
|
||||
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fail-closed Phase 4O-A synthesis, frozen checks, and SHA-256 sealing."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
from phase4h_audit import verify_checksum
|
||||
from phase4k import dataset_checks,seal
|
||||
from phase4m import frozen_checks,frozen_hashes
|
||||
from phase4n import load_config
|
||||
from phase4o_a import EXP,MODEL,ROOT,save,sha
|
||||
|
||||
|
||||
def read(path): return json.loads(path.read_text())
|
||||
|
||||
|
||||
def frozen_integrity():
|
||||
ncfg,mcfg,cfg,_=load_config(ROOT/'models/male-cns-lif/credit-assignment-v1/phase4n.yaml')
|
||||
checks={}
|
||||
for label,root,rel in [
|
||||
('Phase4M experiment',Path(mcfg['experiment_root']),'manifests/checksums.sha256'),
|
||||
('Phase4M model',Path(mcfg['model_root']),'checksums.sha256'),
|
||||
('Phase4N experiment',Path(ncfg['experiment_root']),'manifests/checksums.sha256'),
|
||||
('Phase4N model',Path(ncfg['model_root']),'checksums.sha256')]:
|
||||
checks[label]=verify_checksum(root,root/rel)
|
||||
earlier=frozen_checks(cfg)
|
||||
datasets=dataset_checks(cfg)
|
||||
current=frozen_hashes(cfg)
|
||||
saved=read(Path(mcfg['experiment_root'])/'audit/final-summary.json')['integrity']['after']
|
||||
report={'Phase4C_to_4L':earlier,'Phase4M_4N':checks,'Phase1_to_3B':datasets,
|
||||
'frozen_input_hashes_unchanged':current==saved,
|
||||
'all_static_checks_passed':bool(earlier['all_passed'] and datasets['all_passed'] and
|
||||
all(x['passed'] for x in checks.values()) and current==saved)}
|
||||
save(EXP/'audit/frozen-integrity-final.json',report)
|
||||
return report
|
||||
|
||||
|
||||
def main():
|
||||
matrix=read(EXP/'phase4c-replay/summary.json')
|
||||
replay=read(EXP/'eligibility-replay/event-replay-summary.json')
|
||||
targeted=read(EXP/'eligibility-replay/targeted-summary.json')
|
||||
atomic=read(EXP/'atomic/real-edge-subset.json')
|
||||
backend=read(EXP/'binary-audit/loaded-backend.json')
|
||||
environment=read(EXP/'environment/runtime-environment.json')
|
||||
modes={p.stem:read(p) for p in sorted((EXP/'divergence').glob('mode-*.json'))}
|
||||
matched=next(x for x in modes.values() if x['mode']=='instrumentation-on' and x['repeat']==1)
|
||||
divergent=next(x for x in modes.values() if x['mode']=='instrumentation-on' and x['repeat']==0)
|
||||
def state(run,step,when):
|
||||
return next(x for x in run['state_window'] if x['step']==step and x['when']==when)
|
||||
state_report={'first_observed_spike_event_divergence_step':6625,
|
||||
'first_observed_divergent_neuron_idx':3942,
|
||||
'biological_time_ms':662.5,
|
||||
'pre_step_6625_matched':{k:state(matched,6625,'before')[k] for k in ('voltage','g','arrival_buffer','refractory')},
|
||||
'pre_step_6625_divergent':{k:state(divergent,6625,'before')[k] for k in ('voltage','g','arrival_buffer','refractory')},
|
||||
'matched_after_step_6625_voltage':state(matched,6625,'after')['voltage'],
|
||||
'divergent_after_step_6625_voltage':state(divergent,6625,'after')['voltage'],
|
||||
'matched_spiked_step_6625':bool(state(matched,6625,'after')['focus_spiked']),
|
||||
'divergent_spiked_step_6625':bool(state(divergent,6625,'after')['focus_spiked']),
|
||||
'matched_spiked_step_6626':bool(state(matched,6626,'after')['focus_spiked']),
|
||||
'tracked_neuron_state_already_differs_by_step':6619,
|
||||
'first_global_floating_state_divergence_exactly_located':False,
|
||||
'classification':'FLOAT-ORDER-THRESHOLD-BIFURCATION'}
|
||||
save(EXP/'divergence/first-divergence-forensic.json',state_report)
|
||||
source=ROOT/'models/male-cns-lif/runtime-v1'
|
||||
old_build=ROOT/'experiments/phase4c-runtime/compiler-reports/extension-build'
|
||||
new_build=EXP/'compiler-reports/extension-build'
|
||||
binary={'frozen_runtime_source_sha256':{x:sha(source/x) for x in ('phase4c.py','phase4c_ext.cpp','phase4c_ext.cu','phase4c.yaml')},
|
||||
'historical_extension_sha256':sha(old_build/'male_cns_lif_runtime_v1_ext.so'),
|
||||
'current_loaded_extension_sha256':backend['binary_sha256'],
|
||||
'binary_bytewise_same':sha(old_build/'male_cns_lif_runtime_v1_ext.so')==backend['binary_sha256'],
|
||||
'historical_build_ninja_sha256':sha(old_build/'build.ninja'),
|
||||
'current_build_ninja_sha256':sha(new_build/'build.ninja'),
|
||||
'toolkit_path_historical':'/usr/local/cuda-12.6',
|
||||
'toolkit_path_current':'/usr/local/cuda',
|
||||
'toolkit_realpath_current':'/usr/local/cuda-12.6',
|
||||
'source_and_arch_flags_unchanged_except_absolute_build_paths':True,
|
||||
'interpretation':'ELF hashes differ; build manifests differ in absolute source/toolkit paths while /usr/local/cuda resolves to CUDA 12.6. No proof that binary difference caused the stochastic bifurcation.'}
|
||||
save(EXP/'binary-audit/runtime-binary-diff-report.json',binary)
|
||||
rows=read(EXP/'phase4c-replay/reproducibility-matrix.json')
|
||||
rng={'input_generator_before_first_unique_hashes_by_trial':{},'input_generator_after_trial_unique_hashes_by_trial':{}}
|
||||
for trial in matrix['trial_summary']:
|
||||
subset=[x for x in rows if x['trial']==trial]
|
||||
rng['input_generator_before_first_unique_hashes_by_trial'][trial]=len({x['rng_before_first_timestep']['input_generator'] for x in subset})
|
||||
rng['input_generator_after_trial_unique_hashes_by_trial'][trial]=len({x['rng_after_trial']['input_generator'] for x in subset})
|
||||
rng['mechanosensory_input_generator_states_identical_in_all_10_repeats']=rng['input_generator_before_first_unique_hashes_by_trial']['mechanosensory-50hz']==1 and rng['input_generator_after_trial_unique_hashes_by_trial']['mechanosensory-50hz']==1
|
||||
save(EXP/'rng/summary.json',rng)
|
||||
integrity=frozen_integrity()
|
||||
# Frozen Phase4C spike 49/50 and frozen Phase4M eligibility 498/500 each
|
||||
# independently fail the conjunctive Part A gate. No Part B is executed.
|
||||
gate={'five_phase4c_trials_10_of_10_spike_events_exact':matrix['all_spike_events_exact'],
|
||||
'five_phase4c_trials_10_of_10_per_neuron_counts_exact':matrix['all_counts_exact'],
|
||||
'mechanosensory_divergence_absent':matrix['trial_summary']['mechanosensory-50hz']['event_exact']==10,
|
||||
'phase4m_500_eligibility_5_complete_repeats_exact_to_frozen':replay['all_exact_to_frozen_phase4m'],
|
||||
'event_sequence_repeated_exactly_5_of_5':replay['same_event_and_update_sequence_5_of_5'],
|
||||
'instrumentation_independence':False,
|
||||
'logging_independence_proven':False,
|
||||
'backend_identity_fixed':True,
|
||||
'frozen_static_integrity':integrity['all_static_checks_passed']}
|
||||
passed=all(gate[k] for k in ('five_phase4c_trials_10_of_10_spike_events_exact','five_phase4c_trials_10_of_10_per_neuron_counts_exact',
|
||||
'mechanosensory_divergence_absent','phase4m_500_eligibility_5_complete_repeats_exact_to_frozen',
|
||||
'instrumentation_independence','logging_independence_proven','backend_identity_fixed','frozen_static_integrity'))
|
||||
result={'phase':'4O-A','status':'PASS-RUNTIME-DETERMINISM-RECOVERED' if passed else 'FAIL-RUNTIME-DETERMINISM',
|
||||
'phase4o_b_executed':False,'deterministic_runtime_candidate_generated':False,
|
||||
'phase4c_repeat_matrix':matrix['trial_summary'],
|
||||
'first_divergence':state_report,
|
||||
'root_cause':'Concurrent GPU scatter_add_ floating reduction order varies on real CSR fan-out; a few-ULP g/V difference at neuron 3942 crosses the -45 mV threshold one timestep earlier. Exact first floating-state operation before step 6619 is not located.',
|
||||
'atomic_real_event_subset':{k:atomic[k] for k in ('fanout_edges','targets_with_multiple_concurrent_writes','maximum_same_target_writes','targets_with_nonidentical_atomic_sum_across_100_repeats','max_atomic_sum_range_mv')},
|
||||
'eligibility_replay':{'same_sequence_5_of_5':replay['same_event_and_update_sequence_5_of_5'],
|
||||
'frozen_exact_count_by_repeat':replay['frozen_exact_count_by_repeat'],
|
||||
'mismatch_seed_pairing':[[51202,40],[51203,39]],
|
||||
'mismatch_KC_neuron_idx':78836,
|
||||
'mismatch_trace_absolute_error':0.12266039848327637,
|
||||
'targeted_GPU':targeted,
|
||||
'cause':'KC spike at step 899 versus step 904 around the step-900 external US. Offline event ordering and trace update are repeat-exact; upstream LIF trajectory bifurcates.'},
|
||||
'RNG':rng,'backend':backend,'binary_audit':binary,'environment':{'torch':environment['torch'],'cuda_runtime':environment['cuda_runtime'],
|
||||
'nvcc':environment['nvcc']['stdout'],'driver_gpu':environment['nvidia_smi']['stdout']},
|
||||
'mode_matrix':{k:{x:v for x,v in m.items() if x not in ('state_window','backend')} for k,m in modes.items()},
|
||||
'part_a_gate':gate,'frozen_static_integrity':integrity['all_static_checks_passed'],
|
||||
'limitations':['A single exact first global floating-state divergence operation was not localized; tracked neuron 3942 already differs at step 6619.',
|
||||
'Historical Phase4M training KC events were not sealed, so the two historical event timelines cannot be directly replayed byte-for-byte.',
|
||||
'Logging OFF has final-state/count comparison only; no event sequence was recorded by design.'],
|
||||
'part_b_not_started_reason':'Part A conjunctive PASS gate failed; eligibility-v3 calibration, learning controls and candidates are prohibited.'}
|
||||
save(EXP/'audit/final-summary.json',result)
|
||||
if Path(__file__).resolve() != (MODEL/'phase4o_finalize.py').resolve():
|
||||
shutil.copy2(Path(__file__),MODEL/'phase4o_finalize.py')
|
||||
if Path(__file__).with_name('phase4o.yaml').resolve() != (MODEL/'phase4o.yaml').resolve():
|
||||
shutil.copy2(Path(__file__).with_name('phase4o.yaml'),MODEL/'phase4o.yaml')
|
||||
save(MODEL/'VERSION.json',{'name':'MaleCNS-runtime-credit-v1-audit','phase':'4O-A','status':result['status'],
|
||||
'runtime_v2_deterministic_candidate_generated':False,'eligibility_v3_experimental_started':False,
|
||||
'frozen_runtime_v1_overwritten':False,'summary_sha256':sha(EXP/'audit/final-summary.json')})
|
||||
seal(MODEL,MODEL/'MANIFEST.json',MODEL/'checksums.sha256')
|
||||
seal(EXP,EXP/'manifests/manifest.json',EXP/'manifests/checksums.sha256')
|
||||
own={'model':verify_checksum(MODEL,MODEL/'checksums.sha256')['passed'],
|
||||
'experiment':verify_checksum(EXP,EXP/'manifests/checksums.sha256')['passed']}
|
||||
print(json.dumps({'status':result['status'],'part_B_executed':False,'phase4c':matrix['trial_summary'],
|
||||
'eligibility_5_repeats':replay['frozen_exact_count_by_repeat'],
|
||||
'static_integrity':integrity['all_static_checks_passed'],'own_sha256':own},indent=2),flush=True)
|
||||
|
||||
|
||||
if __name__=='__main__':main()
|
||||
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Mechanosensory runtime mode matrix and optional state-window forensics."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pyarrow.parquet as pq
|
||||
import torch
|
||||
import yaml
|
||||
|
||||
from phase4o_a import EXP,FROZEN,ROOT,sha,first_event_diff,save
|
||||
|
||||
NAME='mechanosensory-50hz'
|
||||
SEED=42003
|
||||
|
||||
|
||||
def run(mode: str, focus_step: int, focus_neuron: int):
|
||||
from brain_runtime import BrainRuntime
|
||||
from phase4i import poisson_batch
|
||||
cfgpath=ROOT/'models/male-cns-lif/mb-mechanistic-v1/phase4i.yaml'
|
||||
if mode=='deterministic-flags':
|
||||
torch.use_deterministic_algorithms(True)
|
||||
torch.backends.cudnn.deterministic=True
|
||||
torch.backends.cudnn.benchmark=False
|
||||
torch.backends.cudnn.allow_tf32=False
|
||||
torch.backends.cuda.matmul.allow_tf32=False
|
||||
torch.set_float32_matmul_precision('highest')
|
||||
rt=BrainRuntime(cfgpath,EXP/'compiler-reports/extension-build')
|
||||
target=np.flatnonzero(rt.population_masks['mechanosensory']).astype(np.int64)
|
||||
refroot=FROZEN/NAME
|
||||
ref=pq.read_table(refroot/'spike-events.parquet')
|
||||
rstep=ref['step'].to_numpy().astype(np.int32);rnode=ref['neuron_idx'].to_numpy().astype(np.int32)
|
||||
rcount=np.load(refroot/'per-neuron-spike-counts.int32.npy')
|
||||
rv=np.load(refroot/'final-voltage.float32.npy');rg=np.load(refroot/'final-g.float32.npy')
|
||||
rt.reset(SEED)
|
||||
batch=poisson_batch(target,50.,1000.,NAME)
|
||||
backend={'python_module':str(Path(rt.runtime_module.__file__)), 'python_sha256':sha(Path(rt.runtime_module.__file__)),
|
||||
'extension':str(Path(rt.extension.__file__)), 'extension_sha256':sha(Path(rt.extension.__file__))}
|
||||
window=[]
|
||||
if mode in ('logging-off','logging-on'):
|
||||
p4cfg=yaml.safe_load((ROOT/'models/male-cns-lif/runtime-v1/phase4c.yaml').read_text())
|
||||
direct=rt.runtime_module.Runtime(p4cfg,rt.table,rt.indptr_np,rt.indices_np,rt.raw_np,rt.device,rt.extension)
|
||||
out=direct.run('hybrid-exact',target,50.,SEED,1000.,capture_events=(mode=='logging-on'))
|
||||
step=out['event_steps'];node=out['event_nodes'];counts=out['counts'];v=out['v'];g=out['g']
|
||||
elif mode in ('instrumentation-on','single-stream-sync'):
|
||||
for t in range(10000):
|
||||
oldlen=len(rt.spike_steps)
|
||||
if mode=='instrumentation-on' and focus_step-6<=t<=focus_step+5 and focus_neuron>=0:
|
||||
slot=t%rt.queue_len
|
||||
window.append({'step':t,'when':'before','neuron_idx':focus_neuron,
|
||||
'voltage':float(rt.v[focus_neuron].item()),'g':float(rt.g[focus_neuron].item()),
|
||||
'refractory':int(rt.refractory[focus_neuron].item()),
|
||||
'arrival_buffer':float(rt.delay_queue[slot,focus_neuron].item()),
|
||||
'ring_buffer_sha256':hashlib.sha256(rt.delay_queue.cpu().numpy().tobytes()).hexdigest()})
|
||||
rt.step(batch,0.1)
|
||||
torch.cuda.synchronize()
|
||||
if mode=='instrumentation-on' and focus_step-6<=t<=focus_step+5 and focus_neuron>=0:
|
||||
new_nodes=np.concatenate(rt.spike_nodes[oldlen:]) if len(rt.spike_nodes)>oldlen else np.empty(0,np.int32)
|
||||
window.append({'step':t,'when':'after','neuron_idx':focus_neuron,
|
||||
'voltage':float(rt.v[focus_neuron].item()),'g':float(rt.g[focus_neuron].item()),
|
||||
'refractory':int(rt.refractory[focus_neuron].item()),'focus_spiked':int(focus_neuron in new_nodes),
|
||||
'active_presynaptic_count':len(new_nodes),
|
||||
'fanout_edge_count':int(np.sum(rt.indptr_np[new_nodes+1]-rt.indptr_np[new_nodes])) if len(new_nodes) else 0,
|
||||
'active_presynaptic_neuron_idx':new_nodes.tolist()[:500]})
|
||||
events=rt.read_spikes();step=events['step'].astype(np.int32);node=events['neuron_idx'].astype(np.int32)
|
||||
counts=rt.spike_counts.cpu().numpy().astype(np.int32);v=rt.v.cpu().numpy();g=rt.g.cpu().numpy()
|
||||
else:
|
||||
rt.step(batch,1000.)
|
||||
events=rt.read_spikes();step=events['step'].astype(np.int32);node=events['neuron_idx'].astype(np.int32)
|
||||
counts=rt.spike_counts.cpu().numpy().astype(np.int32);v=rt.v.cpu().numpy();g=rt.g.cpu().numpy()
|
||||
event_known=mode!='logging-off'
|
||||
result={'mode':mode,'backend':backend,'logging_events_captured':event_known,
|
||||
'spike_events_exact':bool(np.array_equal(step,rstep) and np.array_equal(node,rnode)) if event_known else None,
|
||||
'per_neuron_counts_exact':bool(np.array_equal(counts,rcount)),
|
||||
'final_voltage_max_abs_error':float(np.max(np.abs(v-rv))),
|
||||
'final_g_max_abs_error':float(np.max(np.abs(g-rg))),
|
||||
'first_event_difference':first_event_diff(rstep,rnode,step,node) if event_known else None,
|
||||
'event_sha256':hashlib.sha256(step.tobytes()+node.tobytes()).hexdigest() if event_known else None,
|
||||
'count_sha256':hashlib.sha256(counts.tobytes()).hexdigest(),
|
||||
'torch_deterministic_algorithms':torch.are_deterministic_algorithms_enabled(),
|
||||
'CUBLAS_WORKSPACE_CONFIG':os.getenv('CUBLAS_WORKSPACE_CONFIG'),
|
||||
'state_window':window}
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
ap=argparse.ArgumentParser();ap.add_argument('mode',choices=['default','logging-off','logging-on','instrumentation-off','instrumentation-on','single-stream-sync','deterministic-flags'])
|
||||
ap.add_argument('--focus-step',type=int,default=-1000);ap.add_argument('--focus-neuron',type=int,default=-1)
|
||||
ap.add_argument('--repeat',type=int,default=0);a=ap.parse_args()
|
||||
try: result=run(a.mode,a.focus_step,a.focus_neuron)
|
||||
except Exception as exc: result={'mode':a.mode,'error':repr(exc),'unsupported_or_failed':True}
|
||||
result['repeat']=a.repeat
|
||||
save(EXP/'divergence'/f'mode-{a.mode}-repeat-{a.repeat}.json',result)
|
||||
print(json.dumps({k:result.get(k) for k in ('mode','repeat','spike_events_exact','per_neuron_counts_exact','first_event_difference','error')}),flush=True)
|
||||
|
||||
|
||||
if __name__=='__main__':main()
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Targeted GPU replays of the two Phase 4N/4M eligibility discrepancies."""
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import torch
|
||||
|
||||
from phase4n import load_config
|
||||
from phase4i import Validator
|
||||
from phase4j import apply_v2
|
||||
from phase4l import OdorSimulator,pn_drive
|
||||
from phase4m import load_odor_inputs
|
||||
from phase4o_a import EXP,ROOT,save
|
||||
|
||||
|
||||
def main():
|
||||
ncfg,mcfg,cfg,cfgpath=load_config(ROOT/'models/male-cns-lif/credit-assignment-v1/phase4n.yaml')
|
||||
history=pd.read_parquet(Path(mcfg['experiment_root'])/'efficacy-overlay/update-history.parquet')
|
||||
by={(int(s),int(p)):g for (s,p),g in history.groupby(['train_seed','pairing'])}
|
||||
v=Validator(cfg,cfgpath,EXP);sim=OdorSimulator(v,cfg,EXP)
|
||||
panel,vectors,selection,mapping=load_odor_inputs(cfg)
|
||||
oid=selection['ODOR_A']['odor_id']
|
||||
pn=pn_drive(oid,vectors[oid],mapping,selection['glomeruli_order'],str(mcfg['protocol']['input_mode']),float(np.median(panel.mapped_response_sum)),cfg)[:2]
|
||||
target=str(mcfg['protocol']['target_compartment_verbatim'])
|
||||
dan=v.dan_targets(str(mcfg['protocol']['matched_dan_type']),target)
|
||||
lookup=np.full(v.n,-1,np.int32);lookup[v.kc]=np.arange(len(v.kc),dtype=np.int32)
|
||||
loc=lookup[v.cand.source_neuron_idx.to_numpy(np.int32)]
|
||||
eid_to_local=pd.Series(np.arange(len(v.edge_ids),dtype=np.int32),index=v.edge_ids.astype(np.int64))
|
||||
rows=[]
|
||||
for seed,pairing in [(51202,40),(51203,39)]:
|
||||
delta=np.zeros(len(v.edge_ids),np.float32)
|
||||
for p in range(1,pairing):
|
||||
rec=by[(seed,p)]
|
||||
local=eid_to_local.loc[rec.edge_id.to_numpy(np.int64)].to_numpy(np.int32)
|
||||
frozen_trace=np.zeros(len(v.kc),np.float32)
|
||||
frozen_trace[loc[local]]=rec.eligibility.to_numpy(np.float32)
|
||||
delta,_=apply_v2(v,frozen_trace,target,1.,delta,cfg)
|
||||
rec=by[(seed,pairing)]
|
||||
local=eid_to_local.loc[rec.edge_id.to_numpy(np.int64)].to_numpy(np.int32)
|
||||
old_trace=rec.eligibility.to_numpy(np.float32)
|
||||
for repeat in range(15):
|
||||
run=sim.run_rates(*pn,seed+pairing,float(mcfg['protocol']['duration_ms']),delta=delta,dan_targets=dan,
|
||||
dan_pulses=[float(mcfg['protocol']['dan_time_ms'])],collect_kc_spikes=True)
|
||||
observed=run['kc_trace_at_dan'][loc[local]]
|
||||
diff=np.abs(observed-old_trace)
|
||||
j=int(np.argmax(diff)) if len(diff) else None
|
||||
events=run['kc_spikes'][['step','neuron_idx']].to_numpy(np.int32)
|
||||
row={'seed':seed,'pairing':pairing,'repeat':repeat,'event_count':len(events),
|
||||
'event_sha256':hashlib.sha256(events.tobytes()).hexdigest(),
|
||||
'trace_sha256':hashlib.sha256(observed.tobytes()).hexdigest(),
|
||||
'max_abs_error_vs_frozen':float(diff.max()) if len(diff) else 0.,
|
||||
'exact_to_frozen':bool(len(diff)==0 or float(diff.max())<=2e-5),
|
||||
'first_largest_error_edge_id':int(rec.edge_id.iloc[j]) if j is not None else None,
|
||||
'first_largest_error_KC_neuron_idx':int(v.cand.source_neuron_idx.iloc[local[j]]) if j is not None else None,
|
||||
'observed_eligibility':float(observed[j]) if j is not None else None,
|
||||
'frozen_eligibility':float(old_trace[j]) if j is not None else None,
|
||||
'wall_seconds':run['wall_seconds']}
|
||||
rows.append(row)
|
||||
print(json.dumps({'seed':seed,'pairing':pairing,'repeat':repeat,'exact':row['exact_to_frozen'],
|
||||
'event_sha256':row['event_sha256'][:12]}),flush=True)
|
||||
save(EXP/'eligibility-replay/targeted-gpu-repeats.json',rows)
|
||||
save(EXP/'eligibility-replay/targeted-summary.json',{'rows':len(rows),
|
||||
'exact_count':sum(r['exact_to_frozen'] for r in rows),
|
||||
'distinct_event_hashes_by_trial':{f'{s}/{p}':len({r['event_sha256'] for r in rows if r['seed']==s and r['pairing']==p}) for s,p in [(51202,40),(51203,39)]},
|
||||
'same_seed_config_and_sealed_additive_prefix':True,
|
||||
'note':'This is an isolated 15-repeat targeted diagnostic of the two formerly discrepant trials, not a 5x500 complete brain rerun.'})
|
||||
|
||||
|
||||
if __name__=='__main__':main()
|
||||
Reference in New Issue
Block a user