71 lines
4.4 KiB
Python
71 lines
4.4 KiB
Python
"""Independent event-scheduled author equation and preserved frozen component arms."""
|
|
import sys
|
|
from pathlib import Path
|
|
import numpy as np
|
|
|
|
sys.path.insert(0,'/data/digital-drosophila/models/male-cns-lif/lif-semantics-audit-v1')
|
|
from math_reference import params, state
|
|
|
|
|
|
def component(nodes,edges,weights,config,policy,seed_node):
|
|
p=params(config['model']);n=len(nodes);steps=round(config['duration_ms']/config['dt_ms'])
|
|
ix={int(x):i for i,x in enumerate(nodes)}
|
|
src=np.array([ix[int(x)] for x in edges.source_neuron_idx],np.int32)
|
|
dst=np.array([ix[int(x)] for x in edges.target_neuron_idx],np.int32)
|
|
v=np.full(n,p['rest'],np.float32);g=np.zeros(n,np.float32);ref=np.zeros(n,np.int32)
|
|
qlen=p['delay_steps']+1;q=np.zeros((qlen,n),np.float32)
|
|
history=np.empty((steps,3,n),np.float32);counts=np.zeros(n,np.int32);ts=[];ns=[]
|
|
for t in range(steps):
|
|
v,g,ref,fire=state(v,g,ref,q[t%qlen],p,policy);q[t%qlen]=0
|
|
if t==0 and seed_node is not None:
|
|
k=ix[seed_node];assert not fire[k] and ref[k]==0
|
|
fire[k]=True;v[k]=p['reset'];ref[k]=p['ref_steps']
|
|
if policy in ('reset_g_only','reset_and_refractory'):g[k]=np.float32(0)
|
|
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]):
|
|
acc=np.float32(0)
|
|
for e in selected[dst[selected]==target]:acc=np.float32(acc+weights[e])
|
|
slot=(t+p['delay_steps'])%qlen;q[slot,target]=np.float32(q[slot,target]+acc)
|
|
history[t]=v,g,ref
|
|
return dict(step=np.array(ts,np.int32),neuron_idx=np.array(ns,np.int32),counts=counts,v=v,g=g,ref=ref,history=history,queue=q)
|
|
|
|
|
|
def author_numpy(nodes,edges,config,precision,seed_node,external_arrivals=None):
|
|
"""Analytic integration in SI volts; sequential arrival writes follow spike detection."""
|
|
f=np.dtype(precision).type;m=config['model'];n=len(nodes);dt=config['dt_ms']
|
|
steps=round(config['duration_ms']/dt);rs=round(m['refractory_ms']/dt);ds=round(m['synaptic_delay_ms']/dt)
|
|
ix={int(x):i for i,x in enumerate(nodes)}
|
|
src=np.array([ix[int(x)] for x in edges.source_neuron_idx],np.int32)
|
|
dst=np.array([ix[int(x)] for x in edges.target_neuron_idx],np.int32)
|
|
weights=np.asarray(edges.raw_count.to_numpy(np.float64)*(m['w_syn_mv_per_anatomical_synapse']*.001),dtype=precision)
|
|
rest=m['resting_potential_mv']*.001;reset=m['reset_potential_mv']*.001;threshold=m['threshold_mv']*.001
|
|
v=np.full(n,rest,dtype=precision);g=np.zeros(n,dtype=precision)
|
|
last=np.full(n,-1000000,np.int64);counts=np.zeros(n,np.int32)
|
|
em=np.exp(-dt/m['membrane_tau_ms']);es=np.exp(-dt/m['synaptic_tau_ms'])
|
|
drive=m['synaptic_tau_ms']/(m['membrane_tau_ms']-m['synaptic_tau_ms'])*(em-es)
|
|
history=np.empty((steps,3,n),np.float64);queue=[[] for _ in range(ds+1)];ts=[];ns=[]
|
|
external=np.zeros((steps,n),dtype=precision) if external_arrivals is None else np.asarray(np.asarray(external_arrivals,np.float64)*.001,dtype=precision)
|
|
assert external.shape==(steps,n)
|
|
for t in range(steps):
|
|
available=(t-last)>=rs
|
|
# Use previous g for the coupled exact differential update, then cast to variable dtype.
|
|
oldg=g.copy()
|
|
v[available]=np.asarray(rest+em*(v[available]-rest)+drive*oldg[available],dtype=precision)
|
|
g[available]=np.asarray(es*oldg[available],dtype=precision)
|
|
if t==0 and seed_node is not None:v[ix[seed_node]]=f(threshold+config['seed_margin_mv']*.001)
|
|
fire=available&(v>threshold);last[fire]=t;counts+=fire
|
|
active=np.flatnonzero(fire);ts.extend([t]*len(active));ns.extend(nodes[active].tolist())
|
|
accept=available&~fire
|
|
due=queue[t%(ds+1)];queue[t%(ds+1)]=[]
|
|
for e in due:
|
|
if accept[dst[e]]:g[dst[e]]=f(g[dst[e]]+weights[e])
|
|
for j in np.flatnonzero(external[t]):
|
|
if accept[j]:g[j]=f(g[j]+external[t,j])
|
|
queue[(t+ds)%(ds+1)].extend(np.flatnonzero(fire[src]).tolist())
|
|
v[fire]=f(reset);g[fire]=f(0)
|
|
ref=np.maximum(rs-(t-last),0).astype(np.int32)
|
|
history[t]=np.asarray(v,np.float64)*1000,np.asarray(g,np.float64)*1000,ref
|
|
return dict(step=np.array(ts,np.int32),neuron_idx=np.array(ns,np.int32),counts=counts,
|
|
v=np.asarray(v,np.float64)*1000,g=np.asarray(g,np.float64)*1000,ref=ref,history=history,weights=np.asarray(weights,np.float64)*1000)
|