Audit frozen LIF semantics and real recurrent motifs without learning changes

This commit is contained in:
Digital Drosophila Archive
2026-09-30 01:00:16 +08:00
parent 3213aada79
commit 6fc326ccd1
55 changed files with 2809 additions and 26 deletions
@@ -0,0 +1,61 @@
# Phase 4AC — upstream LIF semantics audit
Goal context: usable stimulus-specific associative learning remains unachieved.
This stage is a prerequisite diagnosis, never a substitute for that goal.
All raw, base CSR, old models/experiments and signs remain read-only. No eta,
threshold, gain, mask or APL calibration is changed. No conditioning, games,
decoder, visual stimulation, or new formal runtime is produced.
## New evidence and hypotheses
The official Shiu paper links philshiu/Drosophila_brain_model. Commit
91bdd1e7dcf193f3e7ca5a8933497fcef63b7960 (2024-09-14) model.py explicitly resets g
on a spike, declares both v and g `(unless refractory)`, uses linear integration
and strict `v > v_th`, and removes refractory time on Poisson-target neurons.
Current frozen Phase 4B/P instead retains g, decays/accepts arrivals during
refractory, uses explicit Euler, `>=`, and force requests respecting refractory.
The Phase 4B config documents its refractory-g policy, so this is a documented
adaptation difference, NOT evidence that deterministic CUDA regressed its oracle.
Neither implementation is automatically a more accurate MaleCNS physiology model.
## Scope of work allowed without replacing frozen brain dynamics
1. Preserve official code/license at a pinned commit, with hashes; do not execute
downloaded code. Extract exact source statements into an evidence table.
2. Synthetic one-cell mathematical fixtures compare the frozen g policy with
reset-only, refractory-only, and combined component ablations. Other arithmetic
stays frozen. These are NOT a Brian2 reproduction (integration and scheduling
also differ), and are not deployed to the MaleCNS brain.
3. Simulate only the UNCHANGED frozen dynamics on actual induced 2/3/5-neuron
circuits selected from the already observed Phase 4Z path. One force request at
t=0, then no input, for 1,000 ms. Include no-input and real-edge feedforward
controls. Missing external network inhibition/feedback is explicitly excluded;
a sustained isolated response is not proof of whole-brain necessity.
4. Validate every frozen CPU small-circuit event/state against the unchanged CUDA
kernel, using exact float32 ordered accumulation and delay=18 steps.
5. Recheck the five archived deterministic reference trials and all old hashes.
All single-cell amplitudes derive from the complete unique contact-count set in
the selected real subgraph, plus a one-contact unit fixture. Do not choose a
successful amplitude after observing outcomes. Add a refractory-arrival fixture
at t=0/1/2/2.2/2.3 ms and a sustained-input-then-off fixture (100 ms then100 ms).
These describe operator consequences, not measured cell physiology or tuning.
The full learning gate still requires >=5 training seeds, independent evaluation,
A-vs-neutral-B specificity in MBON/downstream, appropriate controls, acquisition,
reversal, retention and delayed-reward tests. Existing transfer PASS is not that.
## Next-stage authorization boundary
Testing alternative semantics or measured local physiology on the full MaleCNS
network would be a NEW model experiment, not an exact runtime optimization.
User confirmation is requested separately. This stage does not silently execute
or promote that experiment, even if synthetic ablations reduce firing.
## Caveats to record
W_syn=0.275 is the original paper's free parameter selected on its feeding circuit,
not a universal measured MaleCNS contact efficacy. g reset by itself does not make
the model equivalent to the author's Brian2 implementation. Old reference PASS
means consistency with our old oracle, not matching the original author software.
@@ -0,0 +1,256 @@
"""Evidence-only audit and unchanged-dynamics real motif tests; no learning."""
import argparse
import ast
from datetime import datetime, timezone
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import time
import unittest
import urllib.request
import numpy as np
import pandas as pd
import yaml
from math_reference import params, single, state, cpu_motif
CFG = yaml.safe_load(Path(__file__).with_name('config.yaml').read_text())
ROOT = Path(CFG['root']); MODEL = ROOT/CFG['model']; EXP = ROOT/CFG['experiment']
sys.path.insert(0, str(ROOT/'models/male-cns-lif/apl-pn-scope-audit-v1'))
from audit import save, digest, immutable_check, seal
sys.path.insert(0, str(ROOT/'models/male-cns-lif/terminal-scope-diagnostic-v1'))
from diagnostic import manifest_check, queues
def integrity():
result = {'original': immutable_check(ROOT, ROOT/CFG['old_snapshot'], 4)}
for name in CFG['additional_frozen']: result[name] = manifest_check(ROOT/name, digest)
assert all(x['pass'] for x in result.values()), result
return result
def prepare():
if EXP.exists() and any(EXP.iterdir()): raise RuntimeError('Refusing nonempty output')
EXP.mkdir(exist_ok=True)
for d in ['protocol', 'external-resources', 'audit', 'synthetic', 'motifs', 'regression', 'performance']:
(EXP/d).mkdir()
save(EXP/'protocol/preregistered.json', {'config': CFG, 'before_analysis': True,
'timestamp_utc': datetime.now(timezone.utc).isoformat(),
'parent_commit': subprocess.check_output(['git', '-C', str(ROOT), 'rev-parse', 'HEAD'], text=True).strip(),
'sources': {p.name: digest(p) for p in sorted(MODEL.iterdir()) if p.is_file()}})
save(EXP/'regression/preflight.json', integrity())
external = EXP/'external-resources'; commit = CFG['author']['commit']; records = []
for filename in ['model.py', 'LICENSE', 'environment_full.yml']:
url = f'https://raw.githubusercontent.com/philshiu/Drosophila_brain_model/{commit}/{filename}'
with urllib.request.urlopen(url, timeout=60) as response: data = response.read()
target = external/filename
with target.open('xb') as out: out.write(data)
records.append({'path': filename, 'url': url, 'bytes': len(data), 'sha256': digest(target), 'license': 'MIT'})
assert digest(external/'model.py') == CFG['author']['model_sha256']
assert 'MIT License' in (external/'LICENSE').read_text()
text = (external/'model.py').read_text(); ast.parse(text)
clauses = ['dg/dt = -g / tau', '(unless refractory)', 'v = v_rst; w = 0; g = 0 * mV',
"method='linear'", "'v > v_th'", 'neu[i].rfc = 0 * ms']
assert all(clause in text for clause in clauses)
lines = text.splitlines()
save(EXP/'audit/author-source-clauses.json', [{'clause': clause, 'line_numbers_1based': [i+1 for i, line in enumerate(lines) if clause in line]} for clause in clauses])
save(external/'provenance.json', {'files': records, 'commit': commit, 'paper': CFG['author']['paper'],
'downloaded_code_executed': False, 'new_dependencies_installed': False})
can = ROOT/CFG['canonical']; metadata = pd.read_parquet(can/'neuron-index/unified-metadata.parquet').sort_values('neuron_idx').reset_index(drop=True)
ptr = np.load(can/'gpu/csr-indptr.int64.npy', mmap_mode='r'); dst = np.load(can/'gpu/csr-indices.int32.npy', mmap_mode='r'); raw = np.load(can/'gpu/csr-weights.int64.npy', mmap_mode='r')
assert len(metadata) == 166700 and len(dst) == 25582938 and int(raw.sum()) == 124177617
nodes = np.array(CFG['selected_nodes'], np.int32)
meta = metadata.iloc[nodes].copy(); assert np.array_equal(meta.neuron_idx, nodes)
assert meta.neurotransmitter.eq('acetylcholine').all(), 'No sign inference or reassignment'
alln = meta[meta.annotation_class.eq('ALLN')]; assert alln.annotation_type.eq('lLN1_bc').all() and alln.nt_ground_truth.eq('acetylcholine').all()
ids = np.concatenate([np.arange(ptr[n], ptr[n+1], dtype=np.int64) for n in nodes])
src = np.concatenate([np.full(ptr[n+1]-ptr[n], n, np.int32) for n in nodes])
keep = np.isin(dst[ids], nodes); ids = ids[keep]; src = src[keep]
edges = pd.DataFrame({'edge_id': ids, 'source_neuron_idx': src, 'target_neuron_idx': dst[ids], 'raw_count': raw[ids]})
edges['source_body_id'] = metadata.body_id.to_numpy()[src]; edges['target_body_id'] = metadata.body_id.to_numpy()[dst[ids]]
assert len(edges) == 13
meta.to_parquet(EXP/'audit/selected-metadata.parquet', index=False); edges.to_csv(EXP/'audit/selected-real-edges.csv', index=False)
# Explicit metadata mapping only, not physiological parameter assignment.
graded = metadata[metadata.annotation_type.isin(['lLN2P_a', 'lLN2P_b', 'lLN2P_c', 'lLN2F_b'])].copy()
cols = ['neuron_idx','body_id','annotation_type','annotation_hemibrainType','annotation_flywireType','annotation_matchingNotes','neurotransmitter','nt_ground_truth']
graded[cols].to_csv(EXP/'audit/local-inhibition-crosswalk.csv', index=False)
frozen_yaml = ROOT/CFG['runtime']/'phase4p.yaml'; pc = yaml.safe_load(frozen_yaml.read_text())
save(EXP/'protocol/frozen-input-hashes.json', {'runtime_config': digest(frozen_yaml),
'runtime_cpp': digest(ROOT/CFG['runtime']/'phase4p_ext.cpp'), 'runtime_cuda': digest(ROOT/CFG['runtime']/'phase4p_ext.cu'),
'baseline_phase4b': digest(ROOT/'models/male-cns-lif/phase4b.py'),
'metadata': digest(can/'neuron-index/unified-metadata.parquet')})
save(EXP/'protocol/dynamics.json', pc['model'])
evidence = [
['spike reset g', 'reset to zero', 'retain g'],
['g during refractory', 'ODE paused; synaptic writes blocked', 'decay and accept arrivals'],
['integration', 'linear exact state updater', 'forward Euler with decayed g'],
['threshold', 'strict >', '>='],
['within-step arrivals', 'after integration, before reset', 'before integration'],
['stimulated neurons', 'voltage Poisson input; refractory=0', 'forced spikes subject to 22-step refractory'],
['W_syn', 'free parameter calibrated on FlyWire feeding response', 'same value transferred to MaleCNS; not independently measured']]
pd.DataFrame(evidence, columns=['item', 'author', 'frozen_adapted']).to_csv(EXP/'audit/semantics-differences.csv', index=False)
prepared = ['protocol/dynamics.json','audit/selected-real-edges.csv','audit/selected-metadata.parquet',
'protocol/frozen-input-hashes.json','audit/local-inhibition-crosswalk.csv']
save(EXP/'protocol/prepared-input-hashes.json', {name:digest(EXP/name) for name in prepared})
print('PREPARED: pinned author source, 13 actual motif edges, frozen integrity PASS', flush=True)
def synthetic():
m = json.loads((EXP/'protocol/dynamics.json').read_text()); p = params(m)
edges = pd.read_csv(EXP/'audit/selected-real-edges.csv'); counts = np.unique(np.r_[1, edges.raw_count.to_numpy(np.int64)])
results, traces = [], {}
cases = {}
for count in counts:
a = np.zeros(round(100/m['dt_ms']), np.float32); a[0] = np.float32(count)*np.float32(m['w_syn_mv_per_anatomical_synapse'])
cases[f'one_impulse_contacts_{count}'] = a
# The separate refractory boundary fixture is a synthetic unit test, not a biological stimulation.
a = np.zeros(round(20/m['dt_ms']), np.float32)
a[0] = np.float32(2000) # enough for a spike at t=0 in every component policy
a[[1,10,20,22,23]] += np.float32(10)
cases['refractory_boundary'] = a
a = np.zeros(round(200/m['dt_ms']), np.float32); a[:round(100/m['dt_ms'])] = np.float32(10)
cases['sustained_then_off'] = a
cases['zero_input'] = np.zeros(round(100/m['dt_ms']), np.float32)
for name, a in cases.items():
for policy in CFG['synthetic_policies']:
events, history = single(a, p, policy)
repeat = single(a, p, policy)
assert np.array_equal(events, repeat[0]) and np.array_equal(history, repeat[1])
if policy in ('reset_g_only', 'reset_and_refractory'): assert np.all(history[events,1] == 0)
if name.startswith('one_impulse') and policy in ('reset_g_only', 'reset_and_refractory'): assert len(events) <= 1
if name == 'zero_input': assert not len(events)
if name == 'refractory_boundary' and policy == 'reset_and_refractory':
assert np.all(history[:22,1] == 0) and history[22,1] > 0
results.append({'case': name, 'policy': policy, 'spikes': len(events),
'spike_times_ms': json.dumps((events.astype(float)*m['dt_ms']).tolist()),
'post_input_spikes': int((events >= 1000).sum()) if name == 'sustained_then_off' else None,
'final_g': float(history[-1,1]), 'finite': bool(np.isfinite(history).all()), 'exact_repeat': True,
'not_full_Brian2_replication': True})
traces[name+'__'+policy] = history
traces[name+'__input'] = a
pd.DataFrame(results).to_csv(EXP/'synthetic/results.csv', index=False)
np.savez_compressed(EXP/'synthetic/traces.npz', **traces)
save(EXP/'regression/synthetic.json', {'pass': True, 'cases': len(cases), 'policies': 4,
'proves_only_operator_difference': True, 'brain_model_modified': False, 'Brian2_executed': False})
def gpu_motif(rt, nodes, edges, weights, p, steps, seed):
import torch
n = len(nodes); lookup = {int(node): i for i, node in enumerate(nodes)}
src = np.array([lookup[int(x)] for x in edges.source_neuron_idx], np.int32)
dst = np.array([lookup[int(x)] for x in edges.target_neuron_idx], np.int32)
d = rt.device; qlen = p['delay_steps']+1
v = torch.full((n,), float(p['rest']), dtype=torch.float32, device=d); g = torch.zeros_like(v)
ref = torch.zeros(n, dtype=torch.int32, device=d); spike = torch.zeros(n, dtype=torch.uint8, device=d); counts = torch.zeros_like(ref)
queue = torch.zeros((qlen,n), dtype=torch.float32, device=d); wg = torch.as_tensor(weights, device=d)
history = np.empty((steps,3,n), np.float32); ts, ns = [], []
for t in range(steps):
rt.ext.state_step(v,g,ref,queue[t%qlen],spike,counts,float(p['gd']),float(p['alpha']),float(p['rest']),float(p['reset']),float(p['threshold']),p['ref_steps'])
if t == 0 and seed is not None:
targets = torch.tensor([lookup[seed]], dtype=torch.int64, device=d); force = torch.ones(1,dtype=torch.uint8,device=d)
rt.ext.force_step(v,ref,spike,counts,targets,force,float(p['reset']),p['ref_steps'])
active = spike.cpu().numpy().astype(bool)
indices = np.flatnonzero(active); ts.extend([t]*len(indices)); ns.extend(nodes[indices].tolist())
selected = np.flatnonzero(active[src]); selected = selected[np.argsort(dst[selected],kind='stable')]
if len(selected):
st = dst[selected]; starts = np.flatnonzero(np.r_[True,st[1:] != st[:-1]])
rt.ext.segmented_sum(torch.as_tensor(selected,dtype=torch.int64,device=d),
torch.as_tensor(starts,dtype=torch.int64,device=d), torch.as_tensor(st[starts],dtype=torch.int32,device=d),
wg,queue[(t+p['delay_steps'])%qlen])
history[t] = torch.stack([v,g,ref.float()]).cpu().numpy()
return {'step': np.asarray(ts,np.int32),'neuron_idx':np.asarray(ns,np.int32),'counts':counts.cpu().numpy(),
'v':v.cpu().numpy(),'g':g.cpu().numpy(),'ref':ref.cpu().numpy(),'history':history,'queue':queue.cpu().numpy()}
def run():
pre = json.loads((EXP/'protocol/preregistered.json').read_text())
assert all(digest(MODEL/name) == h for name,h in pre['sources'].items())
assert not (EXP/'regression/run-start.json').exists(), 'Refusing overwrite'
prepared = json.loads((EXP/'protocol/prepared-input-hashes.json').read_text())
assert all(digest(EXP/name) == h for name,h in prepared.items()), 'Prepared-input drift'
runtime = ROOT/CFG['runtime']; pc = yaml.safe_load((runtime/'phase4p.yaml').read_text())
assert pc['model'] == json.loads((EXP/'protocol/dynamics.json').read_text())
suite = unittest.defaultTestLoader.discover(str(MODEL), pattern='test_math.py')
test_result = unittest.TextTestRunner(verbosity=2).run(suite)
assert test_result.wasSuccessful() and test_result.testsRun == 7
save(EXP/'regression/unit-tests.json', {'pass': True, 'tests': test_result.testsRun})
queues(); os.environ['CUDA_VISIBLE_DEVICES'] = pc['device']['visible_gpu_uuid']
os.environ['CUDA_HOME'] = '/usr/local/cuda'; os.environ['MAX_JOBS'] = '2'; os.environ['TORCH_CUDA_ARCH_LIST'] = '8.9'
os.environ['PATH'] = str(ROOT/'models/male-cns-lif/.venv/bin')+':/usr/local/cuda/bin:'+os.environ['PATH']
sys.path.insert(0,str(ROOT/'models/male-cns-lif')); sys.path.insert(0,str(runtime))
import torch, phase4p
free,total = torch.cuda.mem_get_info(); assert free > 2*1024**3
save(EXP/'regression/run-start.json', {'free_VRAM': free,'device':torch.cuda.get_device_name(),
'whole_brain_uses_only_frozen_reference':True,'alternative_policies_only_synthetic_single_cell':True})
start = time.perf_counter(); torch.cuda.reset_peak_memory_stats()
rt = phase4p.CanonicalRuntime(pc,runtime,EXP); p = params(pc['model'])
synthetic()
edges = pd.read_csv(EXP/'audit/selected-real-edges.csv').sort_values('edge_id')
eid=edges.edge_id.to_numpy(np.int64); src=edges.source_neuron_idx.to_numpy(np.int32)
assert np.all(eid >= rt.indptr_np[src]) and np.all(eid < rt.indptr_np[src+1])
assert np.array_equal(rt.indices_np[eid],edges.target_neuron_idx)
assert np.array_equal(rt.raw_np[eid],edges.raw_count)
save(EXP/'regression/anatomical-edge-validation.json', {'pass':True,'edges':len(edges),
'checks':['canonical edge_id in source CSR row','exact target','exact raw int64 count','exact effective float32 weight']})
effective = rt.weights.cpu().numpy(); rows, regress = [], []
assert np.array_equal(effective[edges.edge_id], edges.raw_count.to_numpy(np.float32)*np.float32(pc['model']['w_syn_mv_per_anatomical_synapse']))
for spec in CFG['motifs']:
queues(); nodes = np.sort(np.array(spec['nodes'],np.int32)); subset = edges[edges.source_neuron_idx.isin(nodes)&edges.target_neuron_idx.isin(nodes)].copy()
if 'pairs' in spec:
pairs = {tuple(x) for x in spec['pairs']}
subset = subset[[tuple(x) in pairs for x in subset[['source_neuron_idx','target_neuron_idx']].to_numpy()]]
assert len(subset) == len(pairs)
w = effective[subset.edge_id]; seed = CFG['seed_node'] if spec.get('force',True) else None
steps = round(CFG['duration_ms']/pc['model']['dt_ms']); t0 = time.perf_counter()
cpu = cpu_motif(nodes,subset,w,p,steps,seed); gpu = gpu_motif(rt,nodes,subset,w,p,steps,seed)
eq = {key:bool(np.array_equal(value,gpu[key])) for key,value in cpu.items()}
save(EXP/'regression'/(spec['name']+'.json'), {'exact':eq,'pass':all(eq.values())}); assert all(eq.values()),eq
if seed is None: assert len(cpu['step']) == 0
subset.to_csv(EXP/'motifs'/(spec['name']+'-edges.csv'),index=False)
pd.DataFrame({'step':cpu['step'],'neuron_idx':cpu['neuron_idx']}).to_parquet(EXP/'motifs'/(spec['name']+'-events.parquet'),index=False)
np.savez_compressed(EXP/'motifs'/(spec['name']+'-state.npz'), nodes=nodes, **{k:v for k,v in cpu.items() if k not in ('step','neuron_idx')})
late = cpu['step'] >= round(CFG['late_start_ms']/pc['model']['dt_ms'])
for node in nodes:
chosen = cpu['neuron_idx'] == node
rows.append({'motif':spec['name'],'neuron_idx':int(node),'spikes':int(chosen.sum()),
'late_spikes':int((chosen&late).sum()),'first_ms':float(cpu['step'][chosen][0]*pc['model']['dt_ms']) if chosen.any() else None,
'last_ms':float(cpu['step'][chosen][-1]*pc['model']['dt_ms']) if chosen.any() else None,
'external_force_requests':int(seed == node),'frozen_math_unchanged':True,'whole_brain_necessity_proven':False})
regress.append({'motif':spec['name'],'CPU_GPU_exact':True,'wall_seconds':time.perf_counter()-t0})
print(json.dumps({'motif':spec['name'],'events':len(cpu['step']),'late_events':int(late.sum()),'exact':True}),flush=True)
pd.DataFrame(rows).to_csv(EXP/'motifs/summary.csv',index=False)
save(EXP/'regression/motifs.json',regress)
refs=[]
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')
expected={'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')}
r=rt.run(np.flatnonzero(rt.pops[spec['population']]),spec['rate_hz'],spec['seed'],spec['duration_ms'])
eq={k:bool(np.array_equal(r[k],v)) for k,v in expected.items()};assert all(eq.values()),eq
refs.append({'trial':spec['name'],'exact':eq,'wall_seconds':r['metrics']['wall_seconds']})
print(json.dumps({'frozen_trial':spec['name'],'exact':True}),flush=True)
save(EXP/'regression/frozen-five.json',{'pass':True,'trials':refs,'oracle':'frozen deterministic-v2, not Brian2'})
save(EXP/'performance/summary.json',{'wall_seconds':time.perf_counter()-start,'peak_allocated_VRAM':int(torch.cuda.max_memory_allocated()),
'not_runtime_benchmark':True,'ComfyUI_unloaded':False})
save(EXP/'audit/run-complete.json',{'synthetic_policies':4,'real_motifs_frozen_only':5,'all_CPU_GPU_exact':True,'learning_achieved':False,
'alternative_MaleCNS_dynamics_run':False,'original_author_code_executed':False})
def finalize():
assert (EXP/'audit/run-complete.json').exists()
post=integrity();assert post==json.loads((EXP/'regression/preflight.json').read_text())
save(EXP/'regression/final-integrity.json',post)
pre=json.loads((EXP/'protocol/preregistered.json').read_text());assert all(digest(MODEL/n)==h for n,h in pre['sources'].items())
from report import write_report
write_report(EXP)
save(EXP/'audit/final-status.json',{'status':'COMPLETE-SEMANTICS-AUDIT / LEARNING-NOT-ACHIEVED','frozen_integrity_pass':True,
'documented_adaptation_not_GPU_regression':True,'new_model_authorization_separate':True,'goal_remains_active':True})
for folder in (MODEL,EXP):
print('SEALED',folder,seal(folder),flush=True);assert manifest_check(folder,digest)['pass']
if __name__=='__main__':
parser=argparse.ArgumentParser();parser.add_argument('task',choices=['prepare','run','finalize']);a=parser.parse_args();globals()[a.task]()
@@ -0,0 +1,32 @@
{
"version": "Brian2 2.5.1",
"source_commit": "577bb35ec677947d6f3d4af367a8a4b3b88815ee",
"method": "Read official source and tests; no executable oracle run",
"claims": [
{
"claim": "Every differential variable flagged unless refractory has writes guarded by not_refractory; this includes g. Reset explicitly bypasses the guard.",
"source": "https://github.com/brian-team/brian2/blob/577bb35ec677947d6f3d4af367a8a4b3b88815ee/brian2/groups/neurongroup.py",
"lines_1based": [[794,802],[334,351]]
},
{
"claim": "Default non-legacy refractory release compares integer elapsed steps >= refractory steps; with 2.2 ms and dt 0.1 ms release is n+22.",
"source": "https://github.com/brian-team/brian2/blob/577bb35ec677947d6f3d4af367a8a4b3b88815ee/brian2/groups/neurongroup.py",
"lines_1based": [[178,198],[215,239]]
},
{
"claim": "Default schedule places groups before thresholds, then synapses, then resets. Newly accepted g at n+22 is integrated in the next groups slot; this is not a 23-step refractory duration.",
"source": "https://github.com/brian-team/brian2/blob/577bb35ec677947d6f3d4af367a8a4b3b88815ee/brian2/core/network.py",
"lines_1based": [[34,42]]
},
{
"claim": "Official tests assert ten-dt refractory gives ten-dt spike spacing and reject same-tick writes on spiking refractory targets.",
"source": "https://github.com/brian-team/brian2/blob/577bb35ec677947d6f3d4af367a8a4b3b88815ee/brian2/tests/test_refractory.py",
"lines_1based": [[120,127],[232,248]]
}
],
"caveats": [
"Assumes default schedule/clocks and legacy.refractory_timing=False.",
"The version 2.5.1 prose refractory documentation uses an inconsistent <= example; use pinned implementation and tests for the release boundary.",
"Synthetic reset/refractory ablations in this audit retain frozen Euler and arrival timing; they are not a Brian2 reproduction."
]
}
@@ -0,0 +1,7 @@
484296e132a836900efaa336d387b6974aa39c6af2dee211b7ba668cf71be257 PROTOCOL.md
f20724387ca7ed63b9e35fb9ce3d2964da44f85318856b7403b5536a442422b8 audit_semantics.py
bebd4dfa2dda1aca601a52b24e3eabdd887ce261c3548e377198ab154d81f16e brian2-evidence.json
433151183a4755f5fdfec33f6a9404aa5fb186ec45866ebb58be4ba3e4ebb568 config.yaml
5166366251f99359b1301f514f5d9ae5f0f041fd3a3f98902386192117f01aea math_reference.py
76a21eca32ff8caba88ab84616e226e687dd0d2df5da62816c81b5ba08297394 report.py
9ee96ed78bfa692b12f0db6862087a19dc351c4afd9bb94cf02733ec6a002f01 test_math.py
@@ -0,0 +1,33 @@
phase: 4AC
root: /data/digital-drosophila
model: models/male-cns-lif/lif-semantics-audit-v1
experiment: experiments/phase4ac-lif-semantics
runtime: models/male-cns-lif/deterministic-runtime-v2
canonical: datasets/male-cns-v1.0/processed/neuron-only
old_snapshot: registry/snapshots/bootstrap-20260929
additional_frozen:
- models/male-cns-lif/apl-pn-scope-audit-v1
- experiments/phase4aa-apl-pn-scope
- models/male-cns-lif/terminal-scope-diagnostic-v1
- experiments/phase4ab-terminal-scope
author:
repository: https://github.com/philshiu/Drosophila_brain_model
commit: 91bdd1e7dcf193f3e7ca5a8933497fcef63b7960
model_sha256: fc45837d7122c6ce2a7f3f2f23c515992e4b232aadb919efabb72337fac88e4e
paper: https://www.nature.com/articles/s41586-024-07763-9
selected_nodes: [1197, 1381, 1511, 82312, 133666]
seed_node: 1381
duration_ms: 1000
late_start_ms: 500
motifs:
- {name: pair, nodes: [1381, 1511]}
- {name: trio, nodes: [1197, 1381, 1511]}
- {name: five, nodes: [1197, 1381, 1511, 82312, 133666]}
- {name: feedforward, nodes: [1197, 1381, 1511, 82312, 133666], pairs: [[1381,1511],[1511,1197],[1197,133666],[133666,82312]]}
- {name: no_input, nodes: [1197, 1381, 1511, 82312, 133666], force: false}
synthetic_policies: [frozen, reset_g_only, refractory_gate_only, reset_and_refractory]
scope:
full_brain_alternative_dynamics: false
conditioning: false
learned_candidate: false
requires_separate_authorization_for_new_brain_model: true
@@ -0,0 +1,40 @@
{
"created_utc": "2026-09-29T16:58:20.616795+00:00",
"files": [
{
"bytes": 3661,
"path": "PROTOCOL.md",
"sha256": "484296e132a836900efaa336d387b6974aa39c6af2dee211b7ba668cf71be257"
},
{
"bytes": 18769,
"path": "audit_semantics.py",
"sha256": "f20724387ca7ed63b9e35fb9ce3d2964da44f85318856b7403b5536a442422b8"
},
{
"bytes": 1963,
"path": "brian2-evidence.json",
"sha256": "bebd4dfa2dda1aca601a52b24e3eabdd887ce261c3548e377198ab154d81f16e"
},
{
"bytes": 1464,
"path": "config.yaml",
"sha256": "433151183a4755f5fdfec33f6a9404aa5fb186ec45866ebb58be4ba3e4ebb568"
},
{
"bytes": 3768,
"path": "math_reference.py",
"sha256": "5166366251f99359b1301f514f5d9ae5f0f041fd3a3f98902386192117f01aea"
},
{
"bytes": 5237,
"path": "report.py",
"sha256": "76a21eca32ff8caba88ab84616e226e687dd0d2df5da62816c81b5ba08297394"
},
{
"bytes": 2902,
"path": "test_math.py",
"sha256": "9ee96ed78bfa692b12f0db6862087a19dc351c4afd9bb94cf02733ec6a002f01"
}
]
}
@@ -0,0 +1,70 @@
"""Exact float32 frozen state arithmetic plus explicitly labelled synthetic ablations."""
import numpy as np
def params(model):
f = np.float32
return {'gd': f(1-model['dt_ms']/model['synaptic_tau_ms']),
'alpha': f(model['dt_ms']/model['membrane_tau_ms']),
'rest': f(model['resting_potential_mv']), 'reset': f(model['reset_potential_mv']),
'threshold': f(model['threshold_mv']),
'ref_steps': round(model['refractory_ms']/model['dt_ms']),
'delay_steps': round(model['synaptic_delay_ms']/model['dt_ms'])}
def state(v, g, ref, arrival, p, policy='frozen'):
if policy not in ('frozen', 'reset_g_only', 'refractory_gate_only', 'reset_and_refractory'):
raise ValueError('Unknown synthetic policy: '+policy)
r = np.maximum(ref-1, 0).astype(np.int32)
available = r == 0
gi = np.add(np.multiply(g, p['gd'], dtype=np.float32), arrival, dtype=np.float32)
if policy in ('refractory_gate_only', 'reset_and_refractory'):
gi = np.where(available, gi, g).astype(np.float32)
leak = np.subtract(v, p['rest'], dtype=np.float32)
dv = np.multiply(p['alpha'], np.subtract(gi, leak, dtype=np.float32), dtype=np.float32)
vi = np.where(available, np.add(v, dv, dtype=np.float32), p['reset']).astype(np.float32)
fire = available & (vi >= p['threshold'])
vi[fire] = p['reset']; r[fire] = p['ref_steps']
if policy in ('reset_g_only', 'reset_and_refractory'): gi[fire] = np.float32(0)
return vi, gi, r, fire
def single(arrivals, p, policy='frozen'):
v = np.array([p['rest']], np.float32); g = np.zeros(1, np.float32); r = np.zeros(1, np.int32)
history = np.empty((len(arrivals), 3), np.float32); events = []
for t, a in enumerate(arrivals):
v, g, r, fire = state(v, g, r, np.array([a], np.float32), p, policy)
if fire[0]: events.append(t)
history[t] = v[0], g[0], r[0]
return np.asarray(events, np.int32), history
def cpu_motif(nodes, edges, weights, p, steps, seed):
assert np.all(np.diff(nodes) > 0), 'Canonical nodes must be sorted and unique'
assert np.all(np.diff(edges.edge_id.to_numpy()) > 0), 'Canonical edge order required'
n = len(nodes); lookup = {int(node): i for i, node in enumerate(nodes)}
src = np.array([lookup[int(x)] for x in edges.source_neuron_idx], np.int32)
dst = np.array([lookup[int(x)] for x in edges.target_neuron_idx], np.int32)
qlen = p['delay_steps']+1; queue = np.zeros((qlen, n), np.float32)
v = np.full(n, p['rest'], np.float32); g = np.zeros(n, np.float32); ref = np.zeros(n, np.int32)
counts = np.zeros(n, np.int32); history = np.empty((steps, 3, n), np.float32)
ts, ns = [], []
for t in range(steps):
slot = t % qlen
v, g, ref, fire = state(v, g, ref, queue[slot], p); queue[slot] = 0
if t == 0 and seed is not None:
i = lookup[seed]
assert not fire[i] and ref[i] == 0
fire[i] = True; v[i] = p['reset']; ref[i] = p['ref_steps']
counts += fire
active = np.flatnonzero(fire)
ts.extend([t]*len(active)); ns.extend(nodes[active].tolist())
selected = np.flatnonzero(fire[src]); selected = selected[np.argsort(dst[selected], kind='stable')]
for target in np.unique(dst[selected]):
ix = selected[dst[selected] == target]; acc = np.float32(0)
for e in ix: acc = np.float32(acc+weights[e])
outslot = (t+p['delay_steps']) % qlen
queue[outslot, target] = np.float32(queue[outslot, target]+acc)
history[t] = v, g, ref
return {'step': np.asarray(ts, np.int32), 'neuron_idx': np.asarray(ns, np.int32), 'counts': counts,
'v': v, 'g': g, 'ref': ref, 'history': history, 'queue': queue}
@@ -0,0 +1,49 @@
"""Derive a descriptive report, never pick a model winner from activity reduction."""
import json
import pandas as pd
def write_report(exp):
synthetic = pd.read_csv(exp/'synthetic/results.csv')
motifs = pd.read_csv(exp/'motifs/summary.csv')
one = synthetic[synthetic['case'].str.startswith('one_impulse')]
combined = one.pivot(index='case',columns='policy',values='spikes')
lines = [
'# 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 |',
'|---|---:|---:|---:|---:|']
for name,row in combined.iterrows():
lines.append(f"| {name} | {int(row.frozen)} | {int(row.reset_g_only)} | {int(row.refractory_gate_only)} | {int(row.reset_and_refractory)} |")
lines += ['', '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 |', '|---|---:|---:|---:|---:|']
for r in motifs.itertuples():
lines.append(f'| {r.motif} | {r.neuron_idx} | {r.spikes} | {r.late_spikes} | {r.last_ms if pd.notna(r.last_ms) else "none"} |')
perf=json.loads((exp/'performance/summary.json').read_text())
lines += ['', '## 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.',
f"Diagnostic wall time including compilation and observation: {perf['wall_seconds']:.3f} s. Peak allocated process VRAM: {perf['peak_allocated_VRAM']} 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.', '']
with (exp/'REPORT.md').open('x',encoding='utf-8') as f: f.write('\n'.join(lines))
@@ -0,0 +1,59 @@
"""Independent fixtures; no access to the MaleCNS raw data or experiment outputs."""
import unittest
import numpy as np
import pandas as pd
from math_reference import params, state, single, cpu_motif
class Operators(unittest.TestCase):
def setUp(self):
self.p = params(dict(dt_ms=.1, synaptic_tau_ms=5., membrane_tau_ms=20.,
resting_potential_mv=-52., reset_potential_mv=-52., threshold_mv=-45.,
refractory_ms=2.2, synaptic_delay_ms=1.8))
def test_zero_input_and_exact_repeat(self):
for policy in ('frozen','reset_g_only','refractory_gate_only','reset_and_refractory'):
a, h = single(np.zeros(1000,np.float32),self.p,policy)
self.assertEqual(len(a),0)
np.testing.assert_array_equal(h[:,0],np.full(1000,-52,np.float32))
self.assertTrue(np.isfinite(h).all())
np.testing.assert_array_equal(h,single(np.zeros(1000,np.float32),self.p,policy)[1])
def test_single_spike_reset(self):
a = np.zeros(1000,np.float32); a[0] = 2000
for policy in ('reset_g_only','reset_and_refractory'):
ev, h = single(a,self.p,policy)
np.testing.assert_array_equal(ev,[0]); self.assertEqual(h[0,1],0)
def test_refractory_release_at_22(self):
a = np.zeros(30,np.float32); a[0] = 2000; a[1:23] = 10
ev, h = single(a,self.p,'reset_and_refractory')
self.assertEqual(ev[0],0)
np.testing.assert_array_equal(h[:22,1],np.zeros(22))
self.assertEqual(h[21,2],1); self.assertEqual(h[22,2],0)
self.assertEqual(h[22,1],10)
def test_inhibitory_arrival_sign_preserved(self):
v,g,r,f = state(np.array([-52],np.float32),np.zeros(1,np.float32),
np.zeros(1,np.int32),np.array([-10],np.float32),self.p)
self.assertLess(v[0],-52); self.assertEqual(g[0],-10); self.assertFalse(f[0])
def test_exact_delay_and_no_duplicate_count(self):
edges = pd.DataFrame(dict(edge_id=[17],source_neuron_idx=[100],target_neuron_idx=[200]))
r = cpu_motif(np.array([100,200],np.int32),edges,np.array([1],np.float32),self.p,40,100)
np.testing.assert_array_equal(r['step'],[0]); np.testing.assert_array_equal(r['counts'],[1,0])
self.assertTrue((r['history'][:18,1,1] == 0).all())
self.assertEqual(r['history'][18,1,1],1)
np.testing.assert_array_equal(r['queue'],np.zeros((19,2),np.float32))
def test_ref_gate_is_not_identical_to_reset(self):
a = np.zeros(60,np.float32); a[0] = 2000
_, frozen = single(a,self.p,'frozen')
_, gate = single(a,self.p,'refractory_gate_only')
self.assertLess(frozen[1,1],frozen[0,1]); self.assertEqual(gate[1,1],gate[0,1])
def test_unknown_policy_rejected(self):
with self.assertRaises(ValueError): single(np.zeros(1,np.float32),self.p,'guess')
if __name__ == '__main__': unittest.main(verbosity=2)