Files
digital-drosophila/models/male-cns-lif/author-runtime-lab-v1/prepare.py
T
2026-09-30 07:50:57 +08:00

104 lines
8.6 KiB
Python

"""Read-only selection and deterministic fixtures, before observing any dynamics."""
from datetime import datetime,timezone
import json
import subprocess
import numpy as np
import pandas as pd
import yaml
from context import MODEL,ROOT,EXP,AD,CFG,digest,save,sources,integrity
M=json.loads((AD/'protocol/preregistered.json').read_text())['config']['model']
def put(name,nodes,src,dst,raw,steps,description,edge_id=None,requests=None,external=None,v=None,g=None,metadata=None):
n=len(nodes);src=np.asarray(src,np.int32);dst=np.asarray(dst,np.int32);raw=np.asarray(raw,np.int64)
eid=np.arange(len(src),dtype=np.int64) if edge_id is None else np.asarray(edge_id,np.int64)
order=np.lexsort((eid,src));src,dst,raw,eid=src[order],dst[order],raw[order],eid[order]
assert len(src) and len(src)==len(dst)==len(raw) and np.all((src>=0)&(src<n)) and np.all((dst>=0)&(dst<n))
arrays=dict(nodes=np.asarray(nodes,np.int32),src=src,dst=dst,signed_raw=raw,edge_id=eid,
requests=np.zeros((steps,n),np.uint8) if requests is None else requests,
external_mv=np.zeros((steps,n),np.float64) if external is None else external,
initial_v_mv=np.full(n,M['resting_potential_mv'],np.float64) if v is None else v,
initial_g_mv=np.zeros(n,np.float64) if g is None else g)
folder=EXP/'cases'/name;folder.mkdir()
np.savez_compressed(folder/'arrays.npz',**arrays)
save(folder/'spec.json',dict(name=name,dt_ms=M['dt_ms'],steps=steps,duration_ms=steps*M['dt_ms'],model=M,
description=description,trace_queue=True,validate_queue_proxy=True,selection=metadata))
def synthetic():
n=33;t=160;raw=np.array([16777216,1,-16777216,1]+[(-1 if i%2 else 1)*(i+1) for i in range(28)],np.int64)
req=np.zeros((t,n),np.uint8);req[0,:32]=1;g=np.zeros(n);g[-1]=.123
put('ordered_cancellation',np.arange(-n,0),np.arange(32),np.full(32,32),raw,t,
'Pure synthetic numerical cancellation; huge counts are nonphysiological; nonzero initial g.',requests=req,g=g)
n=257;t=600;src=np.r_[np.arange(256),0,256];dst=np.full(258,256);raw=np.r_[np.where(np.arange(256)%2,-1,1)*(np.arange(256)%17+1)*13,19,11]
req=np.zeros((t,n),np.uint8)
for step in (0,21,22,40,62,101,150,300):req[step,:256]=1
req[0,256]=1;ext=np.zeros((t,n));ext[[0,21,22,23,300],256]=[1,1,1,-1,.5]
put('fanin_bursts',np.arange(-n,0),src,dst,raw,t,'256-source signed fan-in, labelled duplicate/loop; refractory requests and external writes.',requests=req,external=ext)
n=4;t=160;req=np.zeros((t,n),np.uint8);req[0,[0,1,2]]=1;req[22,2]=1;req[44,[0,1]]=1
ext=np.zeros((t,n));ext[[0,21,22,23,43,44,45],2]=[2,2,2,2,-1,1,1]
put('release_selfloop',np.arange(-n,0),[0,1,2,2,3],[2,2,2,3,2],[1,400,10,100,-1],t,'Release at22 with same-tick force/arrival, loops and ring wraps.',requests=req,external=ext)
dt=.0001;tm=.020;ts=.005;rest=-.052;th=-.045;cv=np.exp(-dt/tm);c0=rest-rest*cv
center=(th-c0)/cv;vals=[np.nextafter(center,-np.inf),center,np.nextafter(center,np.inf)]
center32=np.float32((np.float32(th)-np.float32(c0))/np.float32(cv));x=center32
for _ in range(3):x=np.nextafter(x,np.float32(-np.inf))
for _ in range(7):vals.append(float(x));x=np.nextafter(x,np.float32(np.inf))
n=len(vals);put('threshold_rounding',np.arange(-n,0),[0],[0],[0],100,
'Preintegration voltages bracket strict-threshold landing in both precisions; inert zero fixture edge.',v=np.asarray(vals)*1000)
rng=np.random.default_rng(CFG['seed']);n=128;t=400;src=np.repeat(np.arange(n),8);dst=rng.integers(0,n,len(src),dtype=np.int32)
raw=rng.integers(1,601,len(src),dtype=np.int64)*np.where(src%3==0,-1,1)
req=(rng.random((t,n))<.001).astype(np.uint8);req[200:]=0
g=rng.uniform(-1,1,n);ext=np.zeros((t,n));ext[::37]=rng.uniform(-.5,.5,(len(ext[::37]),n))
put('signed_random',np.arange(-n,0),src,dst,raw,t,'Fixed seed128-cell signed random fixture; forcing stops at20ms; signs assigned per synthetic source.',requests=req,external=ext,g=g)
def real():
can=ROOT/'datasets/male-cns-v1.0/processed/neuron-only';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')
meta=pd.read_parquet(can/'neuron-index/unified-metadata.parquet').sort_values('neuron_idx').reset_index(drop=True)
assert np.array_equal(meta.neuron_idx,np.arange(166700)) and len(dst)==25582938 and int(raw.sum())==124177617
pol=yaml.safe_load((ROOT/'models/male-cns-lif/runtime-v1/phase4c.yaml').read_text())['sign_policy']
signs=[]
for nt in meta.neurotransmitter:
s='' if pd.isna(nt) else str(nt).strip().lower()
signs.append(pol['unknown_sign'] if not s else pol['unclear_sign'] if s=='unclear' else pol['neurotransmitter_sign'][s])
signs=np.asarray(signs,np.int8);src=np.repeat(np.arange(166700,dtype=np.int32),np.diff(ptr))
degree=np.bincount(dst,minlength=166700);pos=np.bincount(dst[signs[src]>0],minlength=166700);neg=np.bincount(dst[signs[src]<0],minlength=166700)
ranked=np.lexsort((np.arange(166700),-degree));targets=[int(ranked[0]),int(next(i for i in ranked if pos[i]>=64 and neg[i]>=63))]
for name,target in zip(CFG['real_cases'],targets):
incoming=np.flatnonzero((dst==target)&(src!=target));incoming=incoming[np.lexsort((src[incoming],-raw[incoming]))]
if name=='highest_indegree':chosen=incoming[:127]
else:
pp=incoming[signs[src[incoming]]>0][:64];nn=incoming[signs[src[incoming]]<0][:63]
assert len(pp)==64 and len(nn)==63,'Insufficient mixed partners for predeclared graph'
chosen=np.r_[pp,nn]
nodes=np.sort(np.unique(np.r_[src[chosen],target])).astype(np.int32);assert len(nodes)==128
lookup=np.full(166700,-1,np.int32);lookup[nodes]=np.arange(len(nodes),dtype=np.int32)
ids=np.concatenate([np.arange(ptr[s],ptr[s+1],dtype=np.int64) for s in nodes]);ids=ids[lookup[dst[ids]]>=0]
local_src=lookup[src[ids]];local_dst=lookup[dst[ids]];signed=raw[ids]*signs[src[ids]]
req=np.zeros((500,len(nodes)),np.uint8);stim=np.sort(src[chosen[:16]])
for tick in (0,25,50,100,150,200):req[tick,lookup[stim]]=1
put(name,nodes,local_src,local_dst,signed,500,'Deterministically selected real induced graph; canonical edge IDs/counts and frozen signs.',edge_id=ids,requests=req,
metadata=dict(target_neuron_idx=target,target_body_id=int(meta.body_id.iloc[target]),global_in_degree=int(degree[target]),positive_in_edges=int(pos[target]),negative_in_edges=int(neg[target]),stimulated_neuron_idx=stim.tolist()))
meta.iloc[nodes][['neuron_idx','body_id','annotation_type','neurotransmitter']].to_csv(EXP/'cases'/name/'identities.csv',index=False)
pd.DataFrame(dict(edge_id=ids,source_neuron_idx=src[ids],target_neuron_idx=dst[ids],raw_count=raw[ids],source_sign=signs[src[ids]],signed_raw=signed)).to_csv(EXP/'cases'/name/'anatomical-edges.csv',index=False)
ac=ROOT/'experiments/phase4ac-lif-semantics'
for name in CFG['prior_motifs']:
e=pd.read_csv(ac/'motifs'/f'{name}-edges.csv');nodes=np.load(ac/'motifs'/f'{name}-state.npz')['nodes'];look={int(v):i for i,v in enumerate(nodes)}
req=np.zeros((1000,len(nodes)),np.uint8)
if name!='no_input':req[0,look[1381]]=1
put('motif_'+name,nodes,[look[int(x)] for x in e.source_neuron_idx],[look[int(x)] for x in e.target_neuron_idx],e.raw_count.to_numpy()*signs[e.source_neuron_idx],1000,
'Same selected4AC/4AD motif,100ms prefix; no new edge or weight.',edge_id=e.edge_id.to_numpy(),requests=req)
def main():
assert not (EXP/'protocol').exists()
for d in ('protocol','cases','oracle','gpu','regression','audit','performance'):(EXP/d).mkdir()
can=ROOT/'datasets/male-cns-v1.0/processed/neuron-only'
inputs=[can/'gpu/csr-indptr.int64.npy',can/'gpu/csr-indices.int32.npy',can/'gpu/csr-weights.int64.npy',can/'neuron-index/unified-metadata.parquet',ROOT/'models/male-cns-lif/runtime-v1/phase4c.yaml',AD/'external-resources/model.py',AD/'manifest.json']
save(EXP/'protocol/preregistered.json',dict(timestamp_utc=datetime.now(timezone.utc).isoformat(),config=CFG,sources=sources(),
inputs=[dict(path=str(p.relative_to(ROOT)),sha256=digest(p)) for p in inputs],before_model_execution=True,
parent_commit=subprocess.check_output(['git','-C',str(ROOT),'rev-parse','HEAD'],text=True).strip()))
save(EXP/'regression/old-integrity-before.json',integrity())
synthetic();real()
save(EXP/'protocol/case-hashes.json',[dict(path=str(p.relative_to(EXP)),sha256=digest(p)) for p in sorted((EXP/'cases').rglob('*')) if p.is_file()])
print('PREPARED',len(list((EXP/'cases').iterdir())),'fixed cases; old integrity PASS',flush=True)
if __name__=='__main__':main()