function* lif_system_a(nSteps, g, v_ext_v_thr) {
const N = 1000;
const N_E = 0.8 * N;
const N_I = 0.2 * N;
const tau_E = 20;
const theta = 20;
const V_r = 10;
const D = 2;
const rp = 3;
const C_ext = 1;
const J = 0.1;
const eps = 0.1;
let v_thr = theta / (J * tau_E);
let v_ext = v_ext_v_thr * v_thr;
console.log(v_thr);
console.log(v_ext);
console.log(v_ext_v_thr);
let spikeTimes = range(N).map((x) => new Array());
let totalSpikes = (new Array(Math.max(D, rp))).fill(0);
// Here we encounter some of JS' limitations: there's no first class matrix object.
// Conceptually, we just want to take slices rasters[:, t-D], but we have to think
// about memory layout for this to be straightforward.
let rasters = range(nSteps).map(x => new Uint8Array(N));
let vs = new Uint8Array(N);
// Let's generate random connections.
let connE = [];
let connI = [];
for(var i = 0; i < N; i++) {
connE.push(randomSelection(0, N_E, eps * N_E));
connI.push(randomSelection(N_E, N, eps * N_I));
}
let exc, inh = 0.0;
for(let i = Math.max(D, rp); i < nSteps; i++) {
let newSpikeTimes = range(N).map((x) => new Array());
let sumSpikes = 0;
for(let j = 0; j < N; j++) {
// Random external drive. This looks a bit strange, but it means
// that v_thr = theta / (J C_ext tau)
let driveExt = stdlib.base.random.poisson(v_ext);
//let driveExt = v_ext * C_ext;
// Sum up contributions from all the synaptic currents, delayed.
// Note that the inhibitory inputs are scaled by a factor g.
// Note that we use a reduce function to implement the sum.
let drive = connE[j].map(x => rasters[i - D][x]).reduce((a, b) => a + b, 0) +
-g * connI[j].map(x => rasters[i - D][x]).reduce((a, b) => a + b, 0);
let RI = J * (
drive +
driveExt);
// equation 1.
let dv = - vs[j] / tau_E + RI;
vs[j] += dv;
// If there was a recent spike, override.
if(rasters[i - 1][j] == 1) {
if(rasters[i - D][j] == 0) {
vs[j] = V_r;
rasters[i][j] = 1;
}
}
if(vs[j] > theta) {
// A spike has been generated
spikeTimes[j].push(i);
newSpikeTimes[j].push(i);
rasters[i][j] = 1;
vs[j] = V_r;
sumSpikes += 1;
}
}
totalSpikes.push(sumSpikes / N);
yield [newSpikeTimes, totalSpikes];
}
}