104 lines
8.6 KiB
Python
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()
|