Simulation principles --------------------- The following paper outlines the principles of Brian simulation: Goodman, D and Brette R (2008), `Brian: a simulator for spiking neural networks in Python `__, Front. Neuroinform. doi:10.3389/neuro.11.005.2008. This one describes the simulation algorithms, which are based on vectorisation: Brette R and Goodman, DF, `Vectorised algorithms for spiking neural network simulation `__, Neural Computation (in press). Sample script ~~~~~~~~~~~~~ Below we present a Brian script, and a translation into pure Python to illustrate the basic principles of Brian simulations. Original Brian script ..................... A script in Brian:: ''' Very short example program. ''' from brian import * from time import time N=10000 # number of neurons Ne=int(N*0.8) # excitatory neurons Ni=N-Ne # inhibitory neurons p=80./N duration=1000*ms eqs=''' dv/dt = (ge+gi-(v+49*mV))/(20*ms) : volt dge/dt = -ge/(5*ms) : volt dgi/dt = -gi/(10*ms) : volt ''' P=NeuronGroup(N,model=eqs, threshold=-50*mV,reset=-60*mV) P.v=-60*mV+10*mV*rand(len(P)) Pe=P.subgroup(Ne) Pi=P.subgroup(Ni) Ce=Connection(Pe,P,'ge',weight=1.62*mV,sparseness=p) Ci=Connection(Pi,P,'gi',weight=-9*mV,sparseness=p) M=SpikeMonitor(P) trace=StateMonitor(P,'v',record=0) t1=time() run(1*second) t2=time() print "Simulated in",t2-t1,"s" print len(M.spikes),"spikes" subplot(211) raster_plot(M) subplot(212) plot(trace.times/ms,trace[0]/mV) show() Equivalent in pure Python ......................... The script above translated into pure Python (no Brian):: ''' A pure Python version of the CUBA example, that reproduces basic Brian principles. ''' from pylab import * from time import time from random import sample from scipy import random as scirandom """ Parameters """ N=10000 # number of neurons Ne=int(N*0.8) # excitatory neurons Ni=N-Ne # inhibitory neurons mV=ms=1e-3 # units dt=0.1*ms # timestep taum=20*ms # membrane time constant taue=5*ms taui=10*ms p=80.0/N # connection probability (80 synapses per neuron) Vt=-1*mV # threshold = -50+49 Vr=-11*mV # reset = -60+49 we=60*0.27/10 # excitatory weight wi=-20*4.5/10 # inhibitory weight duration=1000*ms """ Equations --------- eqs=''' dv/dt = (ge+gi-(v+49*mV))/(20*ms) : volt dge/dt = -ge/(5*ms) : volt dgi/dt = -gi/(10*ms) : volt ''' This is a linear system, so each update corresponds to multiplying the state matrix by a (3,3) 'update matrix' """ # Update matrix A=array([[exp(-dt/taum),0,0], [taue/(taum-taue)*(exp(-dt/taum)-exp(-dt/taue)),exp(-dt/taue),0], [taui/(taum-taui)*(exp(-dt/taum)-exp(-dt/taui)),0,exp(-dt/taui)]]).T """ State variables --------------- P=NeuronGroup(4000,model=eqs, threshold=-50*mV,reset=-60*mV) """ S=zeros((3,N)) """ Initialisation -------------- P.v=-60*mV+10*mV*rand(len(P)) """ S[0,:]=rand(N)*(Vt-Vr)+Vr # Potential: uniform between reset and threshold """ Connectivity matrices --------------------- Pe=P.subgroup(3200) # excitatory group Pi=P.subgroup(800) # inhibitory group Ce=Connection(Pe,P,'ge',weight=1.62*mV,sparseness=p) Ci=Connection(Pi,P,'gi',weight=-9*mV,sparseness=p) """ We_target=[] We_weight=[] for _ in range(Ne): k=scirandom.binomial(N,p,1)[0] target=sample(xrange(N),k) target.sort() We_target.append(target) We_weight.append([1.62*mV]*k) Wi_target=[] Wi_weight=[] for _ in range(Ni): k=scirandom.binomial(N,p,1)[0] target=sample(xrange(N),k) target.sort() Wi_target.append(target) Wi_weight.append([-9*mV]*k) """ Spike monitor ------------- M=SpikeMonitor(P) will contain a list of (i,t), where neuron i spiked at time t. """ spike_monitor=[] # Empty list of spikes """ State monitor ------------- trace=StateMonitor(P,'v',record=0) # record only neuron 0 """ trace=[] # Will contain v(t) for each t (for neuron 0) """ Simulation ---------- run(duration) """ t1=time() t=0*ms while tVt).nonzero()[0] # List of neurons that meet threshold condition # PROPAGATION OF SPIKES # Excitatory neurons spikes=(S[0,:Ne]>Vt).nonzero()[0] # In Brian we actually use bisection to speed it up for i in spikes: S[1,We_target[i]]+=We_weight[i] # Inhibitory neurons spikes=(S[0,Ne:N]>Vt).nonzero()[0] for i in spikes: S[2,Wi_target[i]]+=Wi_weight[i] # Reset neurons after spiking S[0,all_spikes]=Vr # Reset membrane potential # Spike monitor spike_monitor+=[(i,t) for i in all_spikes] # State monitor trace.append(S[0,0]) t+=dt t2=time() print "Simulated in",t2-t1,"s" print len(spike_monitor),"spikes" """ Plot ---- subplot(211) raster_plot(M) subplot(212) plot(trace.times/ms,trace[0]/mV) show() Here we cheat a little. """ from brian import raster_plot class M: pass M.spikes=spike_monitor subplot(211) raster_plot(M) subplot(212) plot(arange(len(trace))*dt/ms,array(trace)/mV) show()