Files
digital-drosophila/models/male-cns-lif/author-semantics-lab-v1/run_lab.py
T
2026-09-30 07:23:09 +08:00

159 lines
10 KiB
Python

"""Run fixed component arms and independent author oracle, preserving divergences."""
import importlib.metadata
import json
from pathlib import Path
import platform
import sys
import subprocess
import time
import numpy as np
import pandas as pd
from context import CFG,ROOT,EXP,MODEL,AC,digest,save,check_prereg
from math_lab import component,author_numpy
from oracle_runner import run_brian,PACKAGE_PINS
def save_result(where,result,nodes):
where.mkdir(parents=True,exist_ok=False)
pd.DataFrame(dict(step=result['step'],neuron_idx=result['neuron_idx'])).to_csv(where/'events.csv',index=False)
np.savez_compressed(where/'state.npz',nodes=nodes,**{k:v for k,v in result.items() if k not in ('step','neuron_idx')})
def compare(actual,expected,precision):
event=bool(np.array_equal(actual['step'],expected['step']) and np.array_equal(actual['neuron_idx'],expected['neuron_idx']))
a=np.asarray(actual['history'],np.float64);b=np.asarray(expected['history'],np.float64)
assert a.shape==b.shape
errs=np.abs(a[:,:2]-b[:,:2])
# Describe numerical prefix separately from post-event-divergence trajectories.
first=None
for t in range(len(a)):
aa=actual['neuron_idx'][actual['step']==t];bb=expected['neuron_idx'][expected['step']==t]
if not np.array_equal(aa,bb):first=t;break
prefix=errs[:first] if first is not None else errs
tol=CFG['comparison'][precision+'_state_max_abs_tolerance_mv']
return dict(exact_events=event,exact_counts=bool(np.array_equal(actual['counts'],expected['counts'])),
ref_exact=bool(np.array_equal(a[:,2],b[:,2])),max_abs_mv=float(errs.max()),mean_abs_mv=float(errs.mean()),
same_event_prefix_max_abs_mv=float(prefix.max()) if prefix.size else None,
first_event_divergence_step=first,tolerance_mv=tol,
pass_oracle=bool(event and errs.max()<=tol and np.array_equal(a[:,2],b[:,2])))
def oracle_trial(name,nodes,edges,cfg,precision,seed,external=None):
io=EXP/'oracle'/(name+'-'+precision)
result=run_brian(EXP/'external-resources/model.py',io,nodes,edges,cfg,precision,seed,external)
independent=author_numpy(nodes,edges,cfg,precision,seed,external)
comparison=compare(result,independent,precision)
save(io/'comparison.json',comparison)
save_result(io/'brian-output',result,nodes);save_result(io/'independent-output',independent,nodes)
assert np.isfinite(result['history']).all() and np.isfinite(independent['history']).all()
return result,comparison
def unit_fixtures():
rows=[];nodes=np.array([-1],np.int32)
# Brian2 2.5.1 calls max/min on connect arrays and rejects zero-length arrays.
# An explicitly synthetic zero-weight self-edge is inert, not an anatomical edge.
inert=pd.DataFrame(dict(edge_id=[-1],source_neuron_idx=[-1],target_neuron_idx=[-1],raw_count=[0]),dtype='int64')
for precision in CFG['author_precisions']:
# Synthetic fixture indices are negative and are not MaleCNS body IDs.
c=dict(CFG,duration_ms=20.0)
cases={}
a=np.zeros((200,1));cases['zero']=(a,None,1.0)
a=np.zeros((200,1));a[0,0]=1.;cases['weak_excitation']=(a,None,1.0)
a=np.zeros((200,1));a[0,0]=-1.;cases['inhibition']=(a,None,1.0)
a=np.zeros((200,1));a[[0,21,22,23],0]=.1;cases['refractory_boundary']=(a,-1,1.0)
a=np.zeros((200,1));cases['equal_threshold']=(a,-1,0.0)
a=np.zeros((200,1));cases['above_threshold']=(a,-1,1.0)
a=np.zeros((200,1));a[0,0]=2000.;cases['nonzero_g_reset']=(a,None,1.0)
for name,(arr,seed,margin) in cases.items():
cfg=dict(c,seed_margin_mv=margin)
r,cmp=oracle_trial('unit-'+name,nodes,inert,cfg,precision,seed,arr)
h=r['history'];events=r['step'];checks={}
if name=='zero':checks={'no_events':len(events)==0,'g_zero':bool(np.all(h[:,1]==0)),
'rest_stationary':bool(np.max(np.abs(h[:,0]-CFG['model']['resting_potential_mv']))<1e-3)}
elif name in ('weak_excitation','inhibition'):
checks={'no_events':len(events)==0,'arrival_at_zero':bool(h[0,1,0]>0 if name=='weak_excitation' else h[0,1,0]<0),
'integration_next_step':bool(h[1,0,0]>h[0,0,0] if name=='weak_excitation' else h[1,0,0]<h[0,0,0])}
elif name=='refractory_boundary':checks={'one_seed':np.array_equal(events,[0]),'reject_through_21':bool(np.all(h[:22,1]==0)),
'accept_at_22':bool(h[22,1,0]>0),'release_at_22':bool(h[21,2,0]==1 and h[22,2,0]==0),'reset_g_at_zero':h[0,1,0]==0}
elif name=='equal_threshold':checks={'strict_threshold_no_event':len(events)==0}
elif name=='nonzero_g_reset':checks={'natural_spike_at_1':np.array_equal(events,[1]),
'nonzero_g_before_spike':bool(h[0,1,0]>1999),'zero_g_after_spike':bool(np.all(h[1:,1,0]==0))}
else:checks={'single_seed':np.array_equal(events,[0]),'reset_g':bool(h[0,1,0]==0)}
row=dict(fixture=name,precision=precision,checks={k:bool(v) for k,v in checks.items()},comparison=cmp)
rows.append(row);save(EXP/'regression'/('unit-'+name+'-'+precision+'.json'),row)
print(json.dumps(dict(unit=name,precision=precision,checks=all(checks.values()),oracle=cmp)),flush=True)
delay_nodes=np.array([-2,-1],np.int32)
weak_edge=pd.DataFrame(dict(edge_id=[-1],source_neuron_idx=[-2],target_neuron_idx=[-1],raw_count=[1]),dtype='int64')
r,cmp=oracle_trial('unit-delay_18',delay_nodes,weak_edge,c,precision,-2)
h=r['history'];checks=dict(one_seed=np.array_equal(r['step'],[0]),
zero_before_arrival=bool(np.all(h[:18,1,1]==0)),arrival_at_18=bool(h[18,1,1]>0),
first_voltage_effect_at_19=bool(h[19,0,1]>h[18,0,1]))
row=dict(fixture='delay_18',precision=precision,checks=checks,comparison=cmp)
rows.append(row);save(EXP/'regression'/('unit-delay_18-'+precision+'.json'),row)
save(EXP/'regression/unit-fixtures.json',rows)
# Unit oracle failures prevent real author-motif execution; preserve all failed traces.
assert all(all(r['checks'].values()) and r['comparison']['pass_oracle'] for r in rows),'Author operator unit gate failed'
def main():
check_prereg();assert not (EXP/'audit/run-start.json').exists(),'Refusing overwritten run'
assert all(importlib.metadata.version(n)==v for n,v in PACKAGE_PINS.items()),'Dependency-pin mismatch'
save(EXP/'environment/installed-packages.json',json.loads(subprocess.check_output([sys.executable,'-m','pip','list','--format=json'],text=True)))
save(EXP/'audit/run-start.json',dict(python=sys.version,platform=platform.platform(),
packages={n:importlib.metadata.version(n) for n in ('brian2','numpy','pandas','scipy','pyarrow','sympy','cython')},
codegen='numpy',learning=False,user_authorized_new_model_hypotheses=True))
t0=time.perf_counter();rows=[];validations=[]
for name in CFG['motifs']:
edges=pd.read_csv(AC/'motifs'/f'{name}-edges.csv').sort_values('edge_id')
old=np.load(AC/'motifs'/f'{name}-state.npz');nodes=old['nodes'];seed=None if name=='no_input' else CFG['seed_node']
weights=edges.raw_count.to_numpy(np.float32)*np.float32(CFG['model']['w_syn_mv_per_anatomical_synapse'])
for policy in CFG['component_policies']:
r=component(nodes,edges,weights,CFG,policy,seed)
assert np.isfinite(r['history']).all()
if policy=='frozen':
ev=pd.read_parquet(AC/'motifs'/f'{name}-events.parquet')
eq={k:bool(np.array_equal(old[k],r[k])) for k in old.files if k!='nodes'}
eq['events']=bool(np.array_equal(ev.step,r['step']) and np.array_equal(ev.neuron_idx,r['neuron_idx']))
assert all(eq.values()),eq
validations.append(dict(motif=name,frozen_vs_4AC_exact=eq))
save_result(EXP/'components'/(name+'-'+policy),r,nodes)
late=r['step']>=round(CFG['late_start_ms']/CFG['dt_ms'])
for node in nodes:
select=r['neuron_idx']==node
rows.append(dict(motif=name,policy=policy,precision='float32',neuron_idx=int(node),spikes=int(select.sum()),
late_spikes=int((select&late).sum()),last_ms=float(r['step'][select][-1]*CFG['dt_ms']) if select.any() else None))
pd.DataFrame(rows).to_csv(EXP/'components/summary.csv',index=False)
save(EXP/'regression/frozen-components.json',validations)
unit_fixtures()
from interface_audit import audit_author_poi
audit_author_poi()
ors=[]
for name in CFG['motifs']:
edges=pd.read_csv(AC/'motifs'/f'{name}-edges.csv').sort_values('edge_id')
nodes=np.load(AC/'motifs'/f'{name}-state.npz')['nodes'];seed=None if name=='no_input' else CFG['seed_node'];by_precision={}
for precision in CFG['author_precisions']:
r,cmp=oracle_trial(name,nodes,edges,CFG,precision,seed);by_precision[precision]=r
repeat=run_brian(EXP/'external-resources/model.py',EXP/'oracle'/(name+'-'+precision+'-repeat'),nodes,edges,CFG,precision,seed)
exact_repeat={k:bool(np.array_equal(r[k],repeat[k])) for k in r}
save_result(EXP/'oracle'/(name+'-'+precision+'-repeat')/'brian-output',repeat,nodes)
save(EXP/'regression'/(name+'-'+precision+'-repeat.json'),exact_repeat)
assert all(exact_repeat.values()),exact_repeat
late=r['step']>=round(CFG['late_start_ms']/CFG['dt_ms'])
for node in nodes:
chosen=r['neuron_idx']==node
rows.append(dict(motif=name,policy='author_complete',precision=precision,neuron_idx=int(node),
spikes=int(chosen.sum()),late_spikes=int((chosen&late).sum()),last_ms=float(r['step'][chosen][-1]*CFG['dt_ms']) if chosen.any() else None))
ors.append(dict(motif=name,precision=precision,comparison=cmp))
print(json.dumps(dict(motif=name,precision=precision,events=len(r['step']),late=int(late.sum()),oracle=cmp)),flush=True)
save(EXP/'regression'/(name+'-precision-cross-comparison.json'),compare(by_precision['float32'],by_precision['float64'],'float32'))
pd.DataFrame(rows).to_csv(EXP/'audit/all-motif-results.csv',index=False)
save(EXP/'regression/author-motifs.json',ors)
save(EXP/'performance/summary.json',dict(wall_seconds=time.perf_counter()-t0,backend='CPU NumPy + Brian2',not_runtime_benchmark=True))
save(EXP/'audit/run-complete.json',dict(all_author_oracle_comparisons_pass=all(x['comparison']['pass_oracle'] for x in ors),
all_frozen_components_match_archive=True,learning_achieved=False,whole_brain_alternative_run=False,
author_original_source_sha256=digest(EXP/'external-resources/model.py')))
if __name__=='__main__':main()