#include "network.h"
double E_revValues[] = {E_L, E_g_E, E_g_I, 0.0, E_K, E_Na, E_K};
extern double eeAMPAscale, eiAMPAscale, inscale, iniscale, eeNMDAscale, eiNMDAscale;
extern double GABAAscale, GABABscale;
extern double ffAMPAscale, ffNMDAscale;
extern bool EIF, HH;
extern int funcout;
extern ofstream funcoutfile1,funcoutfile2;
double constitutive=0.05;
Neuron::Neuron() {
this->initialize("not", 'n', 'n');
}
Neuron::Neuron(const char ty[], const char inputset, const char inhibitionset) {
this->initialize(ty, inputset, inhibitionset);
}
void Neuron::initialize(const char ty[], const char inputset, const char inhibitionset) {
strncpy(celltype, ty, 4);
V_s = V_init + doubrand(-10, 10);
V_d = V_init + doubrand(-10, 10);
g_refr = 0;
AMPA = s_init;
NMDA = s_init;
GABAA = s_init;
GABAB = s_init;
T = 0; R = 0; D = 0; G = 0; B = 0;
inact = 0;
spike = 0;
for (int i=0; i<4; i++) {
gating[i] = 0;
}
input = inputset;
inhibition = inhibitionset;
}
void Neuron::fillwstats(double arr[7]) {
arr[0] = V_s; arr[1] = V_d; arr[2] = spike;
arr[3] = AMPA; arr[4] = NMDA; arr[5] = GABAA; arr[6] = GABAB;
}
void Neuron::step(double g_AMPA, double g_NMDA, double g_GABAA, double g_GABAB,
double g_in, double I_ext, double g_PING) {
if (EIF)
EIFstep(g_AMPA, g_NMDA, g_GABAA, g_GABAB, g_in, I_ext, g_PING);
else if (HH)
HHstep(g_AMPA, g_NMDA, g_GABAA, g_GABAB, g_in, I_ext, g_PING);
}
void Neuron::EIFstep(double g_AMPA, double g_NMDA, double g_GABAA, double g_GABAB,
double g_in, double I_ext, double g_PING) {
valarray<double> E_revs(E_revValues,5), g(E_revs), I(g); g=0; I=0;
double g_E, g_I, V_d0=V_d, V_s0=V_s, refrfact;
AMPA *= exp(-dt/tau_AMPA);
NMDA *= exp(-dt/tau_NMDA);
GABAA *= exp(-dt/tau_GABAA);
GABAB *= exp(-dt/tau_GABAB);
if (strcmp(celltype, "exc") == 0) {refrfact = exp(-dt/tau_refrE);}
else if (strcmp(celltype, "inh") == 0) {refrfact = exp(-dt/tau_refrI);}
else {cerr << celltype << " "; refrfact=1;}
g_refr *= refrfact;
g_E = g_AMPA + vdepend(g_NMDA,'N') + w_noise*doubrand(-1, 1)/sqrt(dt);
g_I = g_GABAA + vdepend(g_GABAB,'G') + w_noise*doubrand(-1, 1)/sqrt(dt);
g[0]=g_L; g[1]=g_E; g[2]=g_I; g[3]=g_c; g[4] = g_refr;
V_s = compartmentstep('s', V_s0, g, g_in, V_d0, I_ext, g_PING);
if (V_s > peak){
Neuron::spiking();
}
else if (V_s<thresh && V_s0>thresh) {
inact = false;
}
else {
spike = 0;
}
if (strcmp(celltype, "exc") == 0) {
V_d = compartmentstep('d', V_d0, g, g_in, V_s0, 0, g_PING);
}
else {V_d = V_s;}
V_s = abs(V_s)/V_s * min(100.0,abs(V_s));
V_d = abs(V_d)/V_d * min(100.0,abs(V_d));
}
void Neuron::HHstep(double g_AMPA, double g_NMDA, double g_GABAA, double g_GABAB,
double g_in, double I_ext, double g_PING) {
double alpha_m, beta_m, alpha_h, beta_h, alpha_n, beta_n;
double m=gating[0], h=gating[1], n=gating[2], x=gating[3];
valarray<double> E_revs(E_revValues,7), g(E_revs); g=0;
double g_E, g_I, V_d0=V_d, V_s0=V_s;
g_E = g_AMPA + vdepend(g_NMDA,'N');
g_I = g_GABAA;
g[0]=g_L; g[1]=g_E; g[2]=g_I; g[3]=g_c;
if (strcmp(celltype, "exc") == 0) {
g[6] = vdepend(g_GABAB,'G');
}
if (funcout) {
funcoutfile1 << g_in*(E_g_E-V_d) << " " << vdepend(g_NMDA,'N')*(E_g_E-V_d) << " ";
funcoutfile1 << g_GABAA*(E_g_I-V_d) << " " << vdepend(g_GABAB,'G')*(E_K-V_d) << " ";
if (funcout == 2)
funcoutfile2 << g_AMPA << " " << g_NMDA << " " << g_GABAA << " " << g_GABAB << " ";
}
if (strcmp(celltype, "exc") == 0) {
alpha_m = -0.1 * (V_s + 32)/(exp(-0.1*(V_s + 32)) - 1);
beta_m = 4 * exp(-(V_s + 57)/18);
alpha_h = 0.07 * exp(-(V_s + 48)/20);
beta_h = 1 / (exp(-0.1*(V_s + 18)) + 1);
m += (Phi_m * (alpha_m*(1 - m) - beta_m*m)) * dt;
h += (Phi_h * (alpha_h*(1 - h) - beta_h*h)) * dt;
g[5] = g_Na*pow(m,3)*h;
alpha_n = -0.01 * (V_s + 34)/(exp(-0.1*(V_s + 34))-1);
beta_n = 0.125 * exp(-(V_s + 44)/80);
n += (Phi_n * (alpha_n*(1 - n) - beta_n*n)) * dt;
g[4] = g_K*pow(n,4);
}
else if (strcmp(celltype, "inh") == 0) {
alpha_m = -0.1 * (V_s + 35)/(exp(-0.1*(V_s + 35)) - 1);
beta_m = 4 * exp(-(V_s + 60)/18);
alpha_h = 0.07 * exp(-(V_s + 58)/20);
beta_h = 1 / (exp(-0.1*(V_s + 28)) + 1);
m = alpha_m/(alpha_m + beta_m);
h += (Phi_n * (alpha_h*(1 - h) - beta_h*h)) * dt;
g[5] = g_Na*pow(m,3)*h;
alpha_n = -0.01 * (V_s + 34)/(exp(-0.1*(V_s + 34))-1);
beta_n = 0.125 * exp(-(V_s + 44)/80);
n += (Phi_n * (alpha_n*(1 - n) - beta_n*n)) * dt;
g[4] = g_K*pow(n,4);
}
else {
cerr << celltype << " ";
}
V_s = compartmentstep('s', V_s0, g, g_in, V_d0, I_ext, g_PING);
if (strcmp(celltype, "exc") == 0) {
V_d = compartmentstep('d', V_d0, g, g_in, V_s0, 0, g_PING);
}
else {V_d = V_s;}
V_s = abs(V_s)/V_s * min(100.0,abs(V_s));
V_d = abs(V_d)/V_d * min(100.0,abs(V_d));
if (spike == 0 && V_s > 0 && V_s > V_s0) {spike = -1;}
else if (spike == -1 && V_s > 20 && V_s < V_s0) {spike = 1;}
else if (spike == 1) {spike = 2;}
else if (spike == 2 && V_s < 0) {spike = 0;}
if (strcmp(celltype, "exc") == 0) {
AMPA += (kf * 1/(1 + exp(-V_s/2.0)) * (1 - AMPA) - kr * AMPA) * dt;
double alpha_x = 10, beta_x = 0.5, alpha_s = 0.5, beta_s = 0.01;
x += (alpha_x*1/(1 + exp(-V_s/2.0)) * (1 - x) - beta_x*x) * dt;
NMDA += (alpha_s*x*(1 - NMDA) - beta_s*NMDA) * dt;
}
else if (strcmp(celltype, "inh") == 0) {
GABAA += (kf * 1/(1 + exp(-V_s/2.0)) * (1 - GABAA) - beta * GABAA) * dt;
bool Destexhe1995=0, Destexhe1999=!Destexhe1995;
if (Destexhe1995) {
double dT, dR, dD, dG, Kd=100, K1=6.6*100, K2=0.02, K3=0.0053, K4=0.017, K5=0.083, K6=0.0079;
double Vmax=0.0001, Km=0.000004;
dT = - Vmax * T/(T+Km); dR = K1*T*(1-R-D) - K2*R + K3*D; dD = K4*R - K3*D; dG = K5*R - K6*G;
T += dT*dt; R += dR*dt; D += dD*dt; G += dG*dt;
if (spike==1) T += 0.007;
GABAB = pow(G,4)/(pow(G,4) + Kd);
}
else if (Destexhe1999) {
double dT, dB, dR, dG, kD=0.1, k1=30, kminus1=0.1, k2=0.02, Bm=1, K1=0.18, K2=0.0096, K3=0.19, K4=0.06, Kd=17.83;
dT = -k1*T*(Bm-B) + kminus1*B - kD*T; dB = k1*T*(Bm-B) - (kminus1+k2)*B;
dR = K1*T*(1-R) - K2*R; dG = K3*R - K4*G;
T += dT*dt; R += dR*dt; B += dB*dt; G += dG*dt;
if (spike==1) T += 1;
GABAB = pow(G,4)/(pow(G,4) + Kd);
}
}
gating[0]=m; gating[1]=h; gating[2]=n, gating[3]=x;
}
double Neuron::compartmentstep(char compartment, double V, valarray<double> g,
double g_in, double V_c, double I_ext, double g_PING) {
valarray<double> E_revs(E_revValues, g.size()), I(g);
double Psi=0, dV;
bool onecomp = false;
if (strcmp(celltype, "inh") == 0) {
onecomp = true;
E_revs[4] = -90;
}
E_revs[3] = V_c;
bool TTX=1;
if (compartment == 'd' || (I_ext!=0 && TTX)) {
g[4] = 0;
if (HH) {g[5] = 0;}
}
if (compartment == 's' && !onecomp) {
g[1] = 0;
g[2] += g_PING;
g[6] = 0;
}
if (EIF && (onecomp || compartment == 's') ) {
Psi = g_L * Delta * exp((V - thresh)/Delta);
}
if (compartment != inhibition && !onecomp) {
g[2] = 0;
}
if (compartment == input || onecomp) {
g[1] += g_in;
}
g[1] += w_noise*doubrand(-1, 1)/sqrt(dt);
g[2] += w_noise*doubrand(-1, 1)/sqrt(dt);
I = g*(E_revs - V);
dV = (I.sum() + I_ext + Psi*!inact)*dt/Cm;
V = V + dV;
return V;
}
double Neuron::vdepend(double g, char type) {
valarray<double> E_revs(E_revValues,7);
double g_new, g_max=1;
bool weak=0;
if (type == 'N') {
g_max = 1/(1 + 0.3*Mg*exp(0.08*(0)));
g_new = g/(1 + 0.3*Mg*exp(0.08*(E_revs[1]-V_d)));
}
else if (type == 'G') {
if (weak==1) {
g_max = 1/(1 + exp(-0.05*(0)));
g_new = g/(1 + exp(-0.07*(E_revs[6]-V_d)));
}
else {
g_max = 1/(1 + exp(-0.1*(-10)));
g_new = g/(1 + exp(-0.1*(E_revs[6]-V_d-10)));
}
}
else {
cerr << "Did not specify valid type for rectification." << endl;
}
return g_new;
}
void Neuron::spiking() {
V_s = peak;
if (strcmp(celltype,"exc") == 0) {
AMPA += alpha * (1 - AMPA);
NMDA += alpha * (1 - NMDA);
}
else if (strcmp(celltype, "inh") == 0) {
GABAA += alpha * (1 - GABAA);
GABAB += alpha_GABAB * (1 - GABAB);
}
g_refr = g_refr_max;
spike = 1;
inact = true;
}
Network::Network() {
N = 400;
N_E = (ratio*N/(ratio+1));
N_I = (N - N_E);
N_in = 100;
allneurons = new Neuron[N];
w_AMPA.resize(N_E*N,0.0); w_NMDA.resize(N_E*N,0.0);
w_GABAA.resize(N_I*N,0.0); w_GABAB.resize(N_I*N,0.0);
w_in.resize(N_in*N,0.0);
}
Network::Network(const size_t N_A, const valarray<double>& w_input, const double connectivity,
const char inputset, const char inhibitionset) {
this->initialize(N_A, w_input, connectivity, inputset, inhibitionset);
}
Network::Network(const size_t N_A, const size_t N_input, const double connectivity,
const char inputset, const char inhibitionset) {
this->initialize(N_A, N_input, connectivity, inputset, inhibitionset);
}
void Network::initialize(const size_t N_A, const size_t N_input, const double connectivity,
const char inputset, const char inhibitionset) {
slice s;
valarray<double> temp1, w_input;
N = N_A;
N_E = (ratio*N/(ratio+1));
N_I = (N - N_E);
N_in = N_input;
w_input.resize(N_in*N,0.0);
s = slice(0, N_E-1, N_in+1);
w_input[s] = inscale;
s = slice(N_in*N_E, N_in*N_I, 1);
temp1.resize(N_in*N_I, 0.0);
w_input[s] = connect(temp1, 1.0)*iniscale;
this->initialize(N_A, w_input, connectivity, inputset, inhibitionset);
}
void Network::initialize(const size_t N_A, const valarray<double>& w_input, const double connectivity,
const char inputset, const char inhibitionset) {
size_t i;
slice s, EEslice, EIslice, IEslice, IIslice;
valarray<double> temp1, temp2;
N = N_A;
N_E = (ratio*N/(ratio+1));
N_I = (N - N_E);
N_in = w_input.size()/N;
allneurons = new Neuron[N];
for (i=0; i<N_E; i++) {
allneurons[i].initialize("exc", inputset, inhibitionset);
}
for (i=N_E; i<N; i++) {
allneurons[i].initialize("inh", inputset, inhibitionset);
}
w_AMPA.resize(N_E*N,0.0); w_NMDA.resize(N_E*N,0.0);
w_GABAA.resize(N_I*N,0.0); w_GABAB.resize(N_I*N,0.0);
w_in.resize(N_in*N,0.0);
w_ffAMPA.resize(N_E*N,0.0); w_ffNMDA.resize(N_E*N,0.0);
temp1.resize(N_E*N_E, 0.0);
EEslice = slice(0,N_E*N_E,1); EIslice = slice(N_E*N_E,N_E*N_I,1);
IEslice = slice(0,N_I*N_E,1), IIslice = slice(N_I*N_E,N_I*N_I,1);
w_AMPA[EEslice] = connect(temp1, connectivity) * eeAMPAscale;
temp2.resize(N_E*N_I,0.0);
w_AMPA[EIslice] = connect(temp2, connectivity) * eiAMPAscale;
w_NMDA[EEslice] = temp1 * eeNMDAscale;
w_NMDA[EIslice] = temp2 * eiNMDAscale;
temp1.resize(N_E*N_I, 0.0);
w_GABAA[IEslice] = connect(temp1, connectivity) * GABAAscale;
temp2.resize(N_I*N_I, 0.0);
w_GABAB[IEslice] = connect(temp1, connectivity) * GABABscale;
w_in = w_input;
w_ffAMPA = w_AMPA/eeAMPAscale*ffAMPAscale;
w_ffNMDA = w_NMDA/eeNMDAscale*ffNMDAscale;
s = slice(0, N_E-1, N+1);
w_AMPA[s] = 0;
w_NMDA[s] = 0;
}
void Network::fillwsize(size_t arr[]) {
arr[0] = N; arr[1] = N_E; arr[2] = N_I; arr[3] = N_in;
}
double nullarray1[1]={0.0};
void Network::step(const valarray<double> syn_in, const double I_exts[]=nullarray1) {
int i;
double g_AMPA, g_NMDA, g_GABAA, g_GABAB, g_in=0, I_ext=0;
double stats[7];
valarray<double> syn_AMPA(N_E), syn_NMDA(N_E), syn_GABAA(N_I), syn_GABAB(N_I);
valarray<double> syns_AMPA(N_E), syns_NMDA(N_E), syns_GABAA(N_I), syns_GABAB(N_I), syns_in(N_in);
valarray<double> w_AMPAi(N_E), w_NMDAi(N_E), w_GABAAi(N_I), w_GABABi(N_I), w_ini(N_in);
slice iEslice, iIslice, iinslice;
for (i=0; i<N_E; i++) {
allneurons[i].fillwstats(stats);
syn_AMPA[i] = stats[3];
syn_NMDA[i] = stats[4];
}
for (i=0; i<N_I; i++) {
allneurons[N_E+i].fillwstats(stats);
syn_GABAA[i] = stats[5];
syn_GABAB[i] = stats[6]*(1-constitutive) + constitutive;
}
for (i=0; i<N; i++) {
iEslice = slice(i*N_E, N_E, 1);
iIslice = slice(i*N_I, N_I, 1);
iinslice = slice(i*N_in, N_in, 1);
w_AMPAi = w_AMPA[iEslice];
w_NMDAi = w_NMDA[iEslice];
w_ini = w_in[iinslice];
w_GABAAi = w_GABAA[iIslice];
w_GABABi = w_GABAB[iIslice];
syns_AMPA = syn_AMPA * w_AMPAi;
syns_NMDA = syn_NMDA * w_NMDAi;
syns_GABAA = syn_GABAA * w_GABAAi;
syns_GABAB = syn_GABAB * w_GABABi;
syns_in = syn_in * w_ini;
g_AMPA = syns_AMPA.sum();
g_NMDA = syns_NMDA.sum();
g_GABAA = syns_GABAA.sum();
g_GABAB = syns_GABAB.sum();
g_in = syns_in.sum();
if (I_exts[0]!=0) {I_ext=I_exts[i];}
allneurons[i].step(g_AMPA, g_NMDA, g_GABAA, g_GABAB, g_in, I_ext);
}
}
void Network::step(const valarray<double>& syn_in, const valarray<double>& syn_ff,
const double I_exts[]=nullarray1, const double g_PING) {
size_t i;
double g_AMPA, g_NMDA, g_GABAA, g_GABAB, g_in=0, I_ext=0;
double stats[7];
valarray<double> syn_AMPA(N_E), syn_NMDA(N_E), syn_GABAA(N_I), syn_GABAB(N_I);
valarray<double> syns_AMPA(N_E), syns_NMDA(N_E), syns_GABAA(N_I), syns_GABAB(N_I);
valarray<double> syns_in(N_in), syns_ffAMPA(N_E), syns_ffNMDA(N_E);
valarray<double> w_AMPAi(N_E), w_NMDAi(N_E), w_GABAAi(N_I), w_GABABi(N_I);
valarray<double> w_ini(N_in), w_ffAMPAi(N_E), w_ffNMDAi(N_E);
slice iEslice, iIslice, iinslice, ffAMPAslice(0,N_E,1), ffNMDAslice(N_E,N_E,1);
for (i=0; i<N_E; i++) {
allneurons[i].fillwstats(stats);
syn_AMPA[i] = stats[3];
syn_NMDA[i] = stats[4];
}
for (i=0; i<N_I; i++) {
allneurons[N_E+i].fillwstats(stats);
syn_GABAA[i] = stats[5];
syn_GABAB[i] = stats[6]*(1-constitutive) + constitutive;
}
for (i=0; i<N; i++) {
iEslice = slice(i*N_E, N_E, 1);
iIslice = slice(i*N_I, N_I, 1);
iinslice = slice(i*N_in, N_in, 1);
w_AMPAi = w_AMPA[iEslice];
w_NMDAi = w_NMDA[iEslice];
w_ini = w_in[iinslice];
w_ffAMPAi = w_ffAMPA[iEslice];
w_ffNMDAi = w_ffNMDA[iEslice];
w_GABAAi = w_GABAA[iIslice];
w_GABABi = w_GABAB[iIslice];
syns_AMPA = syn_AMPA * w_AMPAi;
syns_NMDA = syn_NMDA * w_NMDAi;
syns_GABAA = syn_GABAA * w_GABAAi;
syns_GABAB = syn_GABAB * w_GABABi;
syns_in = syn_in * w_ini;
syns_ffAMPA = syn_ff[ffAMPAslice] * w_ffAMPAi;
syns_ffNMDA = syn_ff[ffNMDAslice] * w_ffNMDAi;
g_AMPA = syns_AMPA.sum() + syns_ffAMPA.sum();
g_NMDA = syns_NMDA.sum() + syns_ffNMDA.sum();
g_GABAA = syns_GABAA.sum();
g_GABAB = syns_GABAB.sum();
g_in = syns_in.sum();
if (I_exts[0]!=0) {I_ext=I_exts[i];}
allneurons[i].step(g_AMPA, g_NMDA, g_GABAA, g_GABAB, g_in, I_ext, g_PING);
}
}
map<string,bool> arrayfileappend;
void outputvalarray(valarray<int> arr, size_t Nrows, size_t Ncols, string filename) {
valarray<double> arr_doub(arr.size());
for (size_t i=0; i<arr.size(); i++) {
arr_doub[i] = double(arr[i]);
}
outputvalarray(arr_doub, Nrows, Ncols, filename);
}
void outputvalarray(valarray<bool> arr, size_t Nrows, size_t Ncols, string filename) {
valarray<double> arr_doub(arr.size());
for (size_t i=0; i<arr.size(); i++) {
arr_doub[i] = double(arr[i]);
}
outputvalarray(arr_doub, Nrows, Ncols, filename);
}
void outputvalarray(valarray<double> arr, size_t Nrows, size_t Ncols, string filename) {
#ifdef __APPLE__
if (arr.size()!=Nrows*Ncols) {
cerr << "Nrows*Ncols = " << Nrows*Ncols << ", but arr.size() = " << arr.size() << endl;
assert(arr.size()==Nrows*Ncols);
}
ofstream arrayfile;
size_t i,j;
if (arrayfileappend.count(filename)==0)
arrayfile.open(filename.c_str());
else
arrayfile.open(filename.c_str(),ios_base::app);
for (i = 0; i<Nrows; i++) {
for (j = 0; j<Ncols; j++) {
arrayfile << arr[i + j*Nrows] << " ";
}
arrayfile << endl;
}
arrayfile.close();
arrayfileappend[filename]=true;
#endif
}
valarray<double> loadvalarray(string filename, const size_t Nrows, const size_t Ncols) {
ifstream infile(filename.c_str());
istringstream *lines = new istringstream[Nrows];
string line;
valarray<double> arr(Nrows*Ncols);
size_t count=0;
bool err1=0,err2=0,err3=0,err4=0;
if (infile.is_open()) {
while (getline(infile, line)) {
if (count == Nrows && !err1) {
cerr << "Valarray file has more rows than expected." << endl;
err1 = 1;
}
lines[count].str(line);
count++;
}
if (count < Nrows && !err2) {
cerr << "Valarray file has fewer rows than expected." << endl;
err2 = 1;
}
infile.close();
for (size_t col=0; col<Ncols; col++) {
for (size_t row=0; row<Nrows; row++) {
if (lines[row].good())
lines[row] >> arr[Nrows*col + row];
else if (!err3) {
cerr << "Valarray file has fewer columns than expected." << endl;
err3 = 1;
}
if (!err4 && col == Ncols-1 && !lines[row].eof()) {
double entry;
lines[row] >> entry;
if (abs(entry)>eps || !lines[row].eof()) {
cerr << "Valarray file has more columns than expected. ";
cerr << "Row " <<row << " has leftover " << entry << endl;
err4=1;
}
}
}
}
}
else cerr << "Unable to open valarray input file." << endl;
return arr;
}
valarray<double> valarraysort(valarray<double> &arr) {
size_t N=arr.size();
if (N<=1)
return arr;
vector<double> vec(N);
for (size_t i=0; i<N; i++) {
vec[i] = arr[i];
}
sort(vec.begin(),vec.end());
for (size_t i=0; i<N; i++) {
arr[i] = vec[i];
}
return arr;
}
valarray<double> connect(valarray<double>& w,
double connection)
{
for (size_t i=0; i<w.size(); i++) {
w[i] = doubrand();
w[i] = rectify(w[i] - 1 + connection)/connection;
if (w[i]>0) {w[i] = 1.0;}
}
return w;
}
double doubrand(double minimum, double maximum) {
double a;
a = minimum + double(rand())/RAND_MAX * (maximum - minimum);
return a;
}
double normrand(double mean, double std) {
double U=doubrand(), V=doubrand(),X;
X = sqrt(-2*log(U))*cos(2*pi*V);
return mean + X*std;
}
double rectify(double x) {
x = (x + abs(x))/2;
return x;
}