Hi,
I am trying to implement a fast event-based numerically exact
simulation of a sparse large spiking neural network using a priority
queue. It is fast, but not fast enough.
Profiling indicates that the bottleneck seem to be the dictionary
operations keyindex and setindex! when changing priority of an existing key
(3rd line of
function ptc! in code below). Is there a way to avoid this? Is is
possible to set up a priority queue with integer keys instead?
More generally, is there a smarter data structure than priority queue,
if I want to find the smallest element of an large array and change a small
fraction array entries (say 10^2 out of 10^8) each iteration?

Best regards
Rainer

## For those interested into the implementation: We map the membrane
potential to a phase variable phi \in [-1, inf) and solve the network
evolution of an purely inhibitory homogeneous pulse-coupled leaky integrate
and fire
network analytically between network spikes. This is just a toy example,
some important steps are missing.

##### code ###

function ptc!(phi, postid, phishift, w, c) #phase transition curve
        @inbounds for i = postid
        phi[i] = w*log(exp((phi[i]-phishift)/w)+c) + phishift
    end
end

function lifnet(n,nstep,k,j0,ratewnt,tau,seedic,seedtopo)
    iext = tau*sqrt(k)*j0*ratewnt # iext given by balance equation
    w = 1/log(1. + 1/iext) # phase velocity LIF
    c = j0/sqrt(k)/(1. + iext) # effective coupling in PTC for LIF
    phith, phireset = 1., 0. # reset and threshold for LIF

    srand(seedic) # initialize random number generator (Mersenne Twister)
    phi = Collections.PriorityQueue(UInt32,Float64)
    @inbounds for i = 1:n #set initial phases for all neurons
        phi[i] = -rand()
    end

    spikeidx, spiketimes = Int64[], Float64[] # initialize time & spike
raster
    postidx = Array{UInt32,1}(k) # idices of postsynaptic neurons
    t = phishift = 0. # initial time and initial global phase shift
    for s = 1 : nstep #
        j, phimax = Collections.peek(phi) # next spiking neuron
        dphi = phith+phimax-phishift   # calculate next spike time
        phishift += dphi # global backshift instead of shifting all phases
        t += dphi  # update time
        state = UInt(j+seedtopo)  # spiking neuron index is seed of rng
        @inbounds for i = 1:k     # idea by R.Rosenbaum to reduce memory
            postidx[i], state = randfast(n,state) # get postsyn. neurons
        end

        ptc!(phi,postidx,phishift,w,c) # evaluate PTC
        phi[j] = phireset + phishift    # reset spiking neuron to 0
        push!(spiketimes,t) # store spiketimes
        push!(spikeidx,j) # store spiking neuron
    end
    nstep/t/n/tau*w, spikeidx, spiketimes*tau/w
end

function randfast(m, state::UInt) # linear congruential generator
    state = lcg(state)               # faster then Mersenne-Twister
    1 + rem(state, m) % Int, state   # but can be problematic
end

function lcg(oldstate) # tinyurl.com/fastrand by M. Schauer
    a = unsigned(2862933555777941757)
    b = unsigned(3037000493)
    a*oldstate + b
end

#n: # of neurons, k: synapses/neuron, j0: syn. strength, tau: membr. time
const.
n,nstep,k,j0,ratewnt,tau,seedic,seedtopo = 10^6,10^4,10^2,1,1,.01,1,1
@time lifnet(100, 1, 10, j0, ratewnt, tau, seedic, seedtopo); #warmup
gc()
@time rate,spidx,sptimes = lifnet(n,nstep,k,j0,ratewnt,tau,seedic,seedtopo);
#using PyPlot;plot(sptimes,spidx,".k");ylabel("Neuron Index");xlabel("Time
(s)")

Reply via email to