/*
Version: $Id: constructs.cpp 172 2014-02-12 10:06:07Z gk $
LAModel main imlementation file
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "constructs.h"
//#include "wxglmodel.h"
#include <iterator>
#include <assert.h>
const int DEBUG_NID = 91;
const int DEBUG_BID = 2270;
const int DEBUG_SID = 3024;
const int CUTOFF = 10.0;
int LANetwork::RSEED = 1980;
static void updminmax(float& cmin, float& cmax, float val)
{
if (val < cmin )
cmin = val;
if (val > cmax )
cmax = val;
}
#define VEC_REMOVE(vec, t) (vec).erase(std::remove((vec).begin(), (vec).end(), t), (vec).end())
inline float sigmoid(float x, float x0, float broad)
{
return (1.0 / (1.0 + exp(-x - x0)/broad));
}
inline double nuclearproteinalpha(float x)
{
return (x>20.)*((x-20.*60.)/(30.*60)) * exp(1. - (x-20.*60. )/(30.*60.));
//double d = (x-60.*60)/(40.0*60.);
//return (exp(-d*d));
//double d = ((x-3.*60)/(23.*60)) * exp(1. - (x-(3.*60.) )/(23.*60.)); // 4. or 6.
//if (d >0.) return d;
//else return 0.;
}
inline double branchproteinalpha(float x)
{
return ((x)/(15.*60)) * exp(1. - (x )/(15.*60.));
}
inline void adjust_with_bounds(float& val, float direction, float max, float min)
{
if (direction>=0.0) val += direction*(max-val);
else val += direction*(val - min);
}
inline float step_with_bounds(float cur_val, float dir, float max, float min)
{
if (dir >0) return dir*(max - cur_val);
else return dir*(cur_val - min);
}
inline float caDP(float x)
{
//return x >0.2 ? 1.0 : 0.0;
//float f = (2.0/(1.+exp(-(x*10.-3.5)*10.))) - (1.0/(1.+exp(-(x*10.0-0.5)*19.)));
float f = (1.3/(1.+exp(-(x*10.-3.5)*10.))) - (0.3/(1.+exp(-(x*10.0-2.0)*19.)));
return f;
//return f;//(2.0/(1.+exp(-(x*10.-0.7)*10.))) - (1.0/(1.+exp(-(x*10.0-0.2)*19.)));
//return (2.0/(1.+exp(-(x*10.-3.1)*8.))) - (1.0/(1.+exp(-(x*10.0-2.1)*6.)));
}
inline void program_input(nrn_list lst, int tstart, int duration, float freq, float randomness, int limitActive = -1)
{
int skip = 0;
if (limitActive == -999)
skip = 3;
for (nrn_iter n = lst.begin(); n != lst.end(); ++n)
{
if (skip>0)
{
skip--;
continue;
}
LAInput* in = (LAInput*)(*n);
in->Program(tstart, duration, freq, randomness);
//if (limitActive >0 && ++tot >= limitActive) return;
}
}
void LANetwork::CreateNeurons(int number, int n_branches_per_neuron, char type, vector<LANeuron*>* appendTo = 0, int inputId =-1, int nBranchesTurnover = 0)
{
for (int i =0 ;i < number; i++)
{
LANeuron* n ;
if (type == 'S')
{
n = new LAInput();
n->network = this;
n->input_id = inputId;
((LAInput*)n)->groupIdx = i;
}
else
{
n = new LANeuron();
n->network = this;
for (int tt =0; tt < n_branches_per_neuron; tt++)
{
LABranch* bb = new LABranch;
bb->bid = this->branches.size();
bb->neuron = n;
if (tt < nBranchesTurnover)
{
if (this->turnoverHotspots ==2)
bb->turnoverRate = 0.5 + rgen()*0.5;
else
bb->turnoverRate = 1.0;
}
else
bb->turnoverRate = 0.0;
this->branches.push_back(bb);
n->branches.push_back(bb);
}
}
n->type = type;
n->V = param_V_rest +1.0;
n->nid = this->neurons.size();
n->glx = 1.9*(n->nid%50)/50. - 0.9;
n->gly = 1.9*(n->nid/50)/50. - 0.9;
this->neurons.push_back(n);
if (appendTo)
appendTo->push_back(n);
}
}
void LANetwork::CalculateDistances()
{
for (nrn_iter na = neurons.begin(); na != neurons.end(); ++na)
for (nrn_iter nb = neurons.begin(); nb != neurons.end(); ++nb)
if (nb != na)
{
LANeuron* a = *na, *b=*nb;
float dx = b->pos_x - a->pos_x;
float dy = b->pos_y - a->pos_y;
float dz = b->pos_z - a->pos_z;
distances[pair<int,int>(a->nid,b->nid)] = (double)sqrt(dx*dx + dy*dy + dz*dz);
}
}
/*
int LANetwork::ConnectToRandomBranches(vector<LANeuron*> fromList, vector<LANeuron*> toList, int nSynapses, float weight)
{
LANeuron* from = fromList.at(int(rgen()*(float)toList.size()));
LANeuron* to = toList.at(int(rgen()*(float)toList.size()));
LASynapse* syn = new LASynapse();
syn->sid = this->synapsesCounter++;
syn->target_branch = b;
syn->source_nrn = from;
syn->target_nrn = to;
syn->isPlastic = isPlastic;
syn->weight = weight;
syn->target_branch = syn->target_nrn->branches[(int)rval];
syn->source_nrn->outgoing.push_back(syn);
syn->target_nrn->incoming.push_back(syn);
syn->target_branch->synapses.push_back(syn);
syn->pos = rgen();
this->synapses.push_back(syn);
}
*/
void LANetwork::AddSynapse(LANeuron* a, LABranch* br, float weight, bool isPlastic)
{
LASynapse* syn = new LASynapse();
syn->sid = this->synapsesCounter++;
syn->source_nrn = a;
syn->target_nrn = br->neuron;
syn->isPlastic = isPlastic;
syn->weight = weight;
syn->target_branch = br;
syn->source_nrn->outgoing.push_back(syn);
syn->target_nrn->incoming.push_back(syn);
syn->target_branch->synapses.push_back(syn);
syn->pos = rgen();
this->synapses.push_back(syn);
}
int LANetwork::ConnectByDistance(vector<LANeuron*> fromList, vector<LANeuron*> toList, float fromDistance, float toDistance, int nNeuronPairs, int nSynapsesPerNeuron, float weight, bool isPlastic= false, bool randomizeweight = false, float overlap =-1.0)
{
int tpairs =0;
while(true)
{
LANeuron* a = fromList.at(int(rgen()*(float)fromList.size()));
LANeuron* b = toList.at(int(rgen()*(float)toList.size()));
for (int i =0; i < nSynapsesPerNeuron; i++)
{
float rval;
rval = rgen()*float(b->branches.size());
LABranch* br = b->branches[(int)rval];
this->AddSynapse(a, br, weight, isPlastic);
}
if (++tpairs >= nNeuronPairs) break;
}
return tpairs;
}
inline int randomindex(int max)
{
return (int)(rgen()*float(max));
}
int LANetwork::PurgeInputSynapses(int totalToRemove,float weightLimit)
{
int totalFound =0;
int totalTries = totalToRemove*3;
while (totalFound < totalToRemove && totalTries-->0)
{
nrn_list lst = this->inputs_cs.at(randomindex(this->inputs_cs.size()));
LANeuron* n = lst.at(randomindex(lst.size()));
if (n->outgoing.size())
{
LASynapse* s = n->outgoing.at(randomindex(n->outgoing.size()));
if (s->target_nrn->type == 'P' && s->weight <= weightLimit)
{
//candidate for deletion
//pthread_mutex_lock(&this->synapses_mutex);
VEC_REMOVE(s->source_nrn->outgoing, s);
VEC_REMOVE(s->target_nrn->incoming, s);
VEC_REMOVE(s->target_branch->synapses, s);
VEC_REMOVE(this->synapses, s);
//cout << " Removing " << s->sid << endl;
delete s;
//pthread_mutex_unlock(&this->synapses_mutex);
totalFound++;
}
}
}
if (totalFound < totalToRemove)
{
cout << " Warning: not enougn synapses to remove: " << totalToRemove << endl;
}
return totalFound;
}
int LANetwork::CreateInputSynapses( int totalToAdd)
{
int totalFound = 0;
while (totalFound < totalToAdd)
{
this->ConnectByDistance(this->inputs_cs[randomindex(this->inputs_cs.size())], this->pyr_list, 0.0, 10.0, 1, 1, initWeight, true);
totalFound++;
}
return totalFound;
}
void LANetwork::CreateFearNet(int nneurons, int nbranches, int ninputs, int nneuronsperinput)
{
this->n_neurons = nneurons;
this->n_inputs = ninputs;
this->n_neurons_per_input = nneuronsperinput;
this->n_branches_per_neuron = nbranches;
this->CreateNeurons(this->n_neurons*0.8, this->n_branches_per_neuron, 'P', &this->pyr_list, -1, this->nBranchesTurnover);
this->CreateNeurons(this->n_neurons*0.2, 1 , 'I', &this->in_list);
for (int i=0;i < n_inputs;i++)
{
vector<LANeuron*> nrnsCS;
CreateNeurons(this->n_neurons_per_input, 0, 'S', &nrnsCS, i, true);
this->inputs_cs.push_back(nrnsCS);
}
CreateNeurons(10, 0, 'S', &this->bg_list, -1, true);
this->CalculateDistances();
if (1)
{
/*
int nconn = 1.0*float(this->pyr_list.size()*this->in_list.size());
nrn_list pl, nl;
for (int i=0; i < nconn; i++)
{
pl.clear();
nl.clear();
pl.append(this->pyr_list.at(randomindex(this->pyr_list.size())));
nl.append(this->in_list.at(randomindex(this->pyr_list.size())));
}
*/
ConnectByDistance(this->pyr_list, this->in_list, 0., 10., this->inhibitionParam*2.*.4*20.*float(this->pyr_list.size()), 1, 2.0, false);
ConnectByDistance(this->in_list, this->pyr_list, 0.0, 10.,this->inhibitionParam*2.*.6*20.*float(this->pyr_list.size()), 1, 2.0, false);
}
// CS inputs projections
for (int i =0; i < this->n_inputs ; i++)
{
this->ConnectByDistance(this->inputs_cs[i], this->pyr_list, 0.0, 10.0, this->connectivityParam*float(this->pyr_list.size()*2), 1, initWeight, true, false, this->branchOverlap);
/*
Quote:
-Synaptic inputs are not clustered in fast-spiking parvalbumin-positive interneurons
-Inhibitory interneurons exhibited highly localized alcium activity in their aspiny dendrites,
as reported previously (S10, 11). Because they are highly excitable and can fire in response to a
single excitatory input (S12), they may not require dendritic integration via synaptic clustering.
For another type of interneuron, see ref. S10.
Takahashi et al. Science 2012 (supplement figure S6)
*/
}
ConnectByDistance(this->bg_list, this->pyr_list, 0.0, 10., 20*float(this->pyr_list.size()), 1, 0.6, false);
//this->spikesFile = fopen("./data/0/spikes.dat", "w");
/*&
for (int i=0; i < 0.20*this->pyr_list.size(); i++)
{
//LANeuron* a = this->pyr_list.at(int(rgen()*(float)this->pyr_list.size()));
LANeuron* a = this->pyr_list.at(i);
if (!this->disableCreb)
{
//a->crebLevel = 1.0;
}
//a->prpTransients.push_back( pair<float,float>(0, 1.) );
}
*/
this->RecordInitialWeightSums();
}
void LANetwork::RunPattern(vector<int>& pattern, float hifreq, float lowfreq, int duration, int limitActive )
{
int pad = (4000 - duration)/2;
//printf("Running pattern: [ ");
for (size_t j=0; j < pattern.size(); j++)
{
if (pattern[j]>0)
{
/*
double ts =0;
for (syn_iter si= this->synapses.begin() ;
si != this->synapses.end() ;
si++)
{
LASynapse* s = *si;
if (s->source_nrn->input_id == (int)j)
{
ts+= s->weight;
}
}
//printf("Total synaptic drive: %f\n", ts);
//*/
program_input(this->inputs_cs[j], pad, duration, hifreq, 0.5, limitActive);
}
else
program_input(this->inputs_cs[j], pad, duration, lowfreq, 0.5, limitActive);
//printf(" %d", pattern[j] ? 1 : 0);
}
program_input(this->bg_list, pad, duration, .5, 0.5, -1);
//printf("] @%f Hz dur=%d \n", hifreq, duration);
this->ResetSpikeCounters();
this->StimDynamics(duration+pad+pad);
int tActive =0;
int tSpikes =0;
for (nrn_iter ni = this->pyr_list.begin(); ni != this->pyr_list.end(); ni++)
{
LANeuron* n = *ni;
if (float(n->total_spikes) /4000.> CUTOFF )
tActive++;
tSpikes += n->total_spikes;
}
printf("Active: %d (%.2f%%), avgF: %.2f\n", tActive, 100.0*float(tActive)/float(this->pyr_list.size()), tSpikes/(float(this->pyr_list.size())*2));
}
void LANetwork::RunStoreTest(int n_patterns, int activePerPattern, int delayMinutes, int testMode, int patternsOverlapping)
{
vector<int> pattern;
int inpfrequency=60;
int lowfreq = 0;
int multiruns = 1;
int n_ones = activePerPattern;
printf("Running net with %d pyr. neurons, %d branches, %d synapses [%s,%s] [%d per pattern]\n", (int)this->pyr_list.size(), (int)branches.size(), (int)synapses.size(), localProteins ? "Local" : "Global", disableCreb ? "-CREB" : "+CREB", n_ones);
//this->mfile.open("./data/bdata.dat");
//this->vfile.open("./data/bvoltage.dat");
//fill(pattern.begin(), pattern.end(), 0);
for (int i =0; i < this->n_inputs; i++) pattern.push_back( (i < n_ones) ? 1 : 0);
//std::random_shuffle(pattern.begin(), pattern.end());
int cp=0;
int np=0;
for (int i =0; i < n_patterns; i++)
{
//fill( pattern.begin(), pattern.end(), 0);
if (this->repeatedLearning)
{
this->patterns.push_back( pattern );
}
else
{
fill( pattern.begin(), pattern.end(), 0);
//cp=0;
for (np = 0; np < n_ones; np++)
if (cp < n_inputs)
pattern[cp++] = 1;
//std::random_shuffle(pattern.begin(), pattern.end());
this->patterns.push_back( pattern );
}
cout<< "Pattern " << i<< " : [";
copy(pattern.begin(), pattern.end(), ostream_iterator<int>(cout, ""));
cout << "]" << endl;
}
np =0;
this->Interstim(1*60);
PrintSynapsesSnapshot( datadir + "/syn-pre.txt");
this->ReportSumWeights();
if (this->pretraining)
{
this->runningMode = RUN_PRE;
this->enablePlasticity = false;
for (int nr=0; nr < multiruns; nr++)
{
np =0;
for (vector<vector<int> >::iterator it = this->patterns.begin(); it != this->patterns.end(); it++)
{
pattern = *it;
cout<< "Pretraining" << np<< endl;
this->runningPatternNo = np;
RunPattern(pattern, inpfrequency, lowfreq, stimDurationParam*3800., n_ones/2);
cout << "Tiny interstim ..." << endl;
this->Interstim(5*60);
cout << "done" << endl;
np++;
}
}
}
cout << "Training .. " << endl;
this->enablePlasticity = true;
np =0;
this->runningMode = RUN_TRAINING;
for (vector<vector<int> >::iterator it = this->patterns.begin(); it != this->patterns.end(); it++)
{
pattern = *it;
cout<< "Training" << np<< endl;
this->runningPatternNo = np;
if (std::find(isWeakMem.begin(), isWeakMem.end(), np) != isWeakMem.end())
{
printf("Weak: %d\n", np);
RunPattern(pattern, inpfrequency, lowfreq, 2700, -1);
}
else
RunPattern(pattern, inpfrequency, lowfreq, 3800, -1);
cout << "Interstim " << delayMinutes << " mins ..." << endl;
//this->SaveCalcs();
this->Interstim(delayMinutes*60);
cout << "done" << endl;
np++;
this->ReportSumWeights();
}
this->runningMode = RUN_TEST;
cout << "Large interstim ..." << endl;
this->enablePlasticity = false;
for (nrn_iter na = neurons.begin(); na != neurons.end(); ++na)
{
LANeuron* nrn = *na;
nrn->crebLevel = 0.0;
}
this->Interstim((int)(this->homeostasisTime*3600.));
cout << " done" << endl;
this->ReportSumWeights();
this->isRecall = true;
cout << "Recall .. " << endl;
np =0;
this->enablePlasticity = false;
int n =0;
PrintSynapsesSnapshot(datadir + "/syn-post.txt");
this->spikesPerPattern.resize(n_patterns);
for (int i=0; i < n_patterns; i++)
this->spikesPerPattern[i].resize(this->neurons.size());
this->enablePlasticity = false;
for ( vector<vector<int> >::iterator it = patterns.begin(); it != patterns.end(); it++ )
{
pattern = *it;
n++ ;
for (nrn_iter na = neurons.begin(); na != neurons.end(); ++na)
{
LANeuron* nrn = *na;
nrn->crebLevel = 0.0;
}
cout<< endl<< "Testing " << np<< endl;
this->runningPatternNo = np;
RunPattern(pattern, inpfrequency, lowfreq, 3800, n_ones/2);
this->Interstim(60);
for (nrn_iter na = neurons.begin(); na != neurons.end(); ++na)
{
LANeuron* nrn = *na;
this->spikesPerPattern[np][nrn->nid] = nrn->total_spikes;
}
np++;
}
/*
np =0;
n=0;
for ( vector<vector<int> >::iterator it = patterns.begin(); it != patterns.end(); it++ )
{
pattern = *it;
n++ ;
for (nrn_iter na = neurons.begin(); na != neurons.end(); ++na)
{
LANeuron* nrn = *na;
nrn->crebLevel = 0.0;
}
cout<< endl<< "Testing US " << np<< endl;
this->runningPatternNo = np;
RunPattern(pattern, inpfrequency, lowfreq, 3800, -999);
this->Interstim(60);
for (nrn_iter na = neurons.begin(); na != neurons.end(); ++na)
{
LANeuron* nrn = *na;
this->spikesPerPattern[np][nrn->nid] = nrn->total_spikes;
}
np++;
}
*/
//this->mfile.close();
}
template <typename T> static void PrintVector( vector<T>& ar, ostream& outfile)
{
for (typename vector<T>::iterator it = ar.begin(); it != ar.end(); it++)
{
outfile << *it << ' ';
}
outfile << std::endl;
}
void LANetwork::StoreDataFiles( bool extras = false )
{
vector<int> pattern;
string dirname = this->datadir;
ofstream paramsdat((dirname + "/parameters.txt").c_str());
paramsdat <<"total_neurons="<< this->neurons.size() << endl;
paramsdat <<"total_pyramidals="<< this->pyr_list.size() << endl;
paramsdat <<"branches_per_neuron="<< this->n_branches_per_neuron << endl;
paramsdat <<"number_inputs="<< this->inputs_cs.size() << endl;
paramsdat <<"neurons_per_input="<< this->n_neurons_per_input << endl;
paramsdat <<"rseed="<< RSEED << endl;
ofstream patternsdat((dirname + "/patterns.txt").c_str());
for (vector<vector<int> >::iterator it = this->patterns.begin(); it != this->patterns.end(); it++)
{
pattern = *it;
copy(pattern.begin(), pattern.end(), ostream_iterator<int>(patternsdat, " "));
patternsdat << endl;
}
ofstream synstatedat((dirname + "/synstate.dat").c_str());
ofstream spikesdat((dirname + "/spikes.dat").c_str());
ofstream crebdat((dirname + "/creb.dat").c_str());
ofstream voltagedat((dirname + "/voltages.dat").c_str());
ofstream branchspikesdat((dirname +"/branchspikes.dat").c_str());
ofstream branchcalcium((dirname + "/branchcalcium.dat").c_str());
ofstream weightsdat((dirname + "/weights.dat").c_str());
ofstream branchproteins((dirname + "/branchproteins.dat").c_str());
ofstream branchstrengths((dirname + "/branchstrengths.dat").c_str());
ofstream tagsdat((dirname + "/tags.dat").c_str());
ofstream nrnproteindat((dirname + "/nrnprotein.dat").c_str());
ofstream weighthistorydat((dirname + "/weighthistory.dat").c_str());
ofstream dbgneuron((dirname + "/dbgneuron.dat").c_str());
PrintVector<float>( dbgNeuron, dbgneuron);
for (nrn_iter na = neurons.begin(); na != neurons.end(); ++na)
{
LANeuron* nrn = *na;
PrintVector<int>( nrn->spikeTimings, spikesdat);
//PrintVector<float>( nrn->crebHistory, crebdat);
PrintVector<float>( nrn->proteinHistory, nrnproteindat);
for (branch_iter bi = nrn->branches.begin(); bi != nrn->branches.end(); ++bi)
{
LABranch* b = *bi;
PrintVector<float>(b->branchSpikesHistory, branchspikesdat);
for (syn_iter si = b->synapses.begin(); si != b->synapses.end(); ++si)
{
LASynapse* s = *si;
//PrintVector<float>(s->weightHistory, weightsdat);
synstatedat << s->sid<<" "
<< b->bid<<" "
<< nrn->nid << " "
<< s->source_nrn->nid <<" "
<< s->source_nrn->input_id<< " "
<< b->strength << " "
<< s->weight << " "
<<endl;
if (s->tagHistory.size())
{
tagsdat << s->source_nrn->input_id<< " ";
PrintVector<float>(s->tagHistory, tagsdat);
}
if (s->weightHistory.size())
{
weighthistorydat << s->source_nrn->input_id<< " ";
PrintVector<float>(s->weightHistory, weighthistorydat);
}
}
}
}
ofstream sppdat((dirname + "/spikesperpattern.dat").c_str());
for (uint i =0; i < this->spikesPerPattern.size(); i++)
{
for (uint j =0; j < this->spikesPerPattern[i].size(); j++) sppdat << this->spikesPerPattern[i][j] << " ";
sppdat << endl;
}
}
void LANetwork::StimDynamics(int duration) // stimulation dynamics, with dt=1msec
{
int t = 0;
bool spikeState[this->neurons.size()+1];
int lastSpikeT[this->neurons.size()+1];
fill_n(spikeState, this->neurons.size()+1, 0);
fill_n(lastSpikeT, this->neurons.size()+1, 0);
//FILE* outfile = fopen("./data/0/wdata.dat", "w");
for (syn_iter si = this->synapses.begin(); si != this->synapses.end(); ++si)
{
(*si)->calcium = 0.0;
}
for (nrn_iter ni = this->neurons.begin(); ni != this->neurons.end(); ++ni)
{
LANeuron* n = *ni;
n->wadapt = 0.0;
n->vspike =0.;
n->vreset =0.;
n->V =0.;
}
for (branch_iter bi=this->branches.begin(); bi != this->branches.end(); ++bi)
{
(*bi)->totcalc = 0.0;
(*bi)->depol = 0.0;
(*bi)->dspike = 0.0;
(*bi)->dspikeT = -1;
}
for (t=0; t < duration; t++)
{
for (nrn_iter ni = this->neurons.begin(); ni != this->neurons.end(); ++ni)
{
LANeuron* n = *ni;
double s_inh = 0.0;
double sv =0.0 ; //, ss =0;
for (branch_iter bi=n->branches.begin(); bi != n->branches.end(); ++bi)
{
LABranch* b = *bi;
float sumepsp =0.;
float sumipsp =0.;
//if (this->debugMode && b->bid==DEBUG_BID) vfile<< b->depol << " " << n->V << endl;
for (syn_iter si=b->synapses.begin(); si != b->synapses.end(); ++si)
{
LASynapse* s = *si;
if (spikeState[s->source_nrn->nid])
{
if (s->source_nrn->type == 'I') sumipsp += ( s->weight);
else sumepsp += ( s->weight);
}
}
b->depol += (4.0*sumepsp) - b->depol/20.0;
s_inh += sumipsp;
//if (b->bid == 40) printf("BID %d f=%f epsp=%f\n", b->bid, b->depol, sumepsp);
// http://www.cell.com/neuron/abstract/S0896-6273(12)00761-1: Inhibition blocks only weak dendritic spikes
/*
if ( b->dspikeT > 0)
{
float tds = t - b->dspikeT;
if (tds < 40)
b->depol = 40.;
else if (tds < 60)
{
}
else
{
b->dspikeT = -1; // Allow next dend spike
b->depol =0.;// Reset dspike
}
}
*/
if (n->type == 'P' && b->dspikeT < t-100 && (n->vspike + b->depol) > 30.*dendSpikeThresh) // Generate a dendritic branch spike
{
//b->depol = 60.0;
b->depol = 50;
b->dspikeT =t;
b->branch_spikes++;
n->dend_spikes++;
if (this->enablePlasticity && b->strengthTag < 1.0) b->strengthTag += (1.0 - b->strengthTag)*0.20;
}
// if (b->dspikeT >0 && t-b->dspikeT < 20) b->depol = 50.;
for (syn_iter si=b->synapses.begin(); si != b->synapses.end(); ++si)
{
LASynapse* s = *si;
if (spikeState[s->source_nrn->nid])
{
if (this->enablePlasticity && s->isPlastic) // && t > 50b)
{
float depol = b->depol + n->vspike;
//float depol = n->vspike;
//NMDA dynamics: Jahr_1993
//if (depol > 10.0)
if (depol > 1.0) //n->vspike > 10)
{
//float ff = exp(-dt/70.0 ) * (1.0/(1.+exp( (-(depol-30.0)/7.0))));
float ff = (1.0/(1.+exp( (-(depol-30.0)/5.0))));
//s->calcium += ( 0.5*ff)*(1.0 - s->calcium) ;
//s->calcium += 2.0*(ff);
//cout << " Calc " << s->calcium<< endl;
s->calcium += ff/10.;
}
}
}
}
sv += (b->depol)*b->strength ;
//if (b->dspike > 0.0) b->dspike -= (b->dspike*b->dspike)/40.0; // see Losoczy 2008 for epsp durations
//b->branchVoltageHistory.push_back(b->depol1 + n->vspike + b->dspike);
//b->branchCalciumHistory.push_back(bcalc);
}
n->inh_cur += 0.18*s_inh;
if (n->type == 'S') // Source neuron
{
LAInput* in = (LAInput*)n;
//if (t ==0) printf ("nid=%d , T=%d, next=%d\n", in->nid, t, in->nextSpikeT);
if (in->spikeTimes && t >= in->nextSpikeT && in->nextSpikeT >0)
{
//printf("ID %d spike! t=%d\n", in->nid, t );
if (in->curSpike < in->totalSpikes)
in->nextSpikeT = in->spikeTimes[in->curSpike++];
else
in->nextSpikeT = -1;
spikeState[in->nid] = 1;
n->isSpiking = true;
lastSpikeT[in->nid] = t;
in->total_spikes++;
in->V = 20.0; // threshold
}
else
{
spikeState[in->nid] = 0;
n->isSpiking = false;
in->V = param_E_L;
}
}
else /// PYR OR IN NEURON
{
if (spikeState[n->nid])
{
//spikeState[n->nid] =0;
n->V = 0.0;
n->wadapt += 0.18;
}
n->exc_cur = sv*0.12;
if (n->type == 'I') // Interneuron
{
n->V += (n->exc_cur - n->inh_cur) - (n->V)/20. - n->wadapt*(n->V+10.0);
n->wadapt -= n->wadapt/70.;
}
else
{
n->V += n->exc_cur - 3.0*s_inh - (n->V)/30. - n->wadapt*(n->V+10.0) ;
if (this->disableCreb)
n->wadapt -= n->wadapt/180.;
else
n->wadapt -= n->wadapt/((180. - 70.0*(n->crebLevel>0.2 ? 1. : 0.)));
}
if ( lastSpikeT[n->nid] < t-2 && n->V > (20.0 - (n->crebLevel>100.2 ? 2.0 : 0.) ))
{
spikeState[n->nid] = 1;
lastSpikeT[n->nid] = t;
n->total_spikes++;
n->isSpiking = true;
n->vspike = 30.0;
n->V = 70.;
}
else
{
spikeState[n->nid] = 0;
n->isSpiking = false;
}
if (n->vspike > 0) n->vspike -= n->vspike / 17.0;
// Legenstein&maas eta_reset = 20msec
if (n->wadapt <-0.) n->wadapt =0.;
//if (n->wadapt < 0.) n->wadapt =0.;
}
if (spikeState[n->nid])
{
n->spikeTimings.push_back(t+ this->Tstimulation);
}
}
#ifdef WXGLMODEL_H
if (this->wx_window && t%10==0)
{
this->wx_window->UpdatePanel();
}
#endif
//usleep(10000);
}
for (branch_iter bi=this->branches.begin(); bi != this->branches.end(); ++bi)
{
LABranch* b = *bi;
b->branchSpikesHistory.push_back(b->branch_spikes);
}
//fflush(stdout);
//fflush(spikesFile);
this->Tstimulation += duration;
}
void LANetwork::SaveSnapshot(char* filename)
{
ofstream of(filename);
for (nrn_iter ni = this->pyr_list.begin(); ni != this->pyr_list.end(); ni++)
{
LANeuron* nrn = *ni;
if (nrn->type == 'P')
{
float totTag =0;
float totProtein =0;
for (branch_iter bi = nrn->branches.begin(); bi != nrn->branches.end(); ++bi)
{
LABranch* b = *bi;
for (syn_iter si = b->synapses.begin(); si != b->synapses.end(); ++si)
{
LASynapse* s = *si;
if (s->isPlastic)
{
totTag += s->stag;
//of<<s->sid << " "<< s->source_nrn->input_id << " "<< b->bid << ' ' << nrn->nid <<' '<< b->protein <<' '<< s->stag <<' '<< endl;
}
}
totProtein += b->protein;
}
of << nrn->nid << ' ' << totProtein << ' '<< totTag << endl;
}
}
}
void LANetwork::Interstim(int durationSecs)
{
int tstop = T + durationSecs;
this->isInterstim = true;
printf("Interstim %d seconds (T=%d) plast=%d G=%d, L=%d ... \n", durationSecs, T, this->enablePlasticity, this->globalProteins, this->localProteins);
float tstep = 60.0;
int totalWeak =0;
float weightLimit = initWeight + 0.0;
// Count the total weak afferent synapses
for (input_iter ii = this->inputs_cs.begin(); ii != this->inputs_cs.end(); ++ii)
{
nrn_list lst = *ii;
for (nrn_iter n = lst.begin(); n != lst.end(); ++n)
for (syn_iter si=(*n)->outgoing.begin(); si != (*n)->outgoing.end(); ++si)
if ((*si)->weight <= weightLimit)
totalWeak++;
}
int trec =0, tactrec=0;
int totTagged=0, totTaggedMinus=0, totBProd =0;
float totLTP=0., totLTD=0.;
int totact =0, totSact =0;
int totbspikes =0, totSpikes=0;
float maxSpk =0;
float actmin=9999, actmax=0;
float nactmin=9999, nactmax=0;
for (nrn_iter ni = this->pyr_list.begin(); ni != this->pyr_list.end(); ni++)
{
LANeuron* nrn = *ni;
float nrnCalc =0.0;
if (nrn->total_spikes > 4)
totSact++;
for (branch_iter bi = nrn->branches.begin(); bi != nrn->branches.end(); ++bi)
{
LABranch* b = *bi;
totbspikes += b->branch_spikes;
if (!this->enablePlasticity)
continue;
for (syn_iter si = b->synapses.begin(); si != b->synapses.end(); ++si)
{
LASynapse* s =*si;
float ctag = caDP(s->calcium);
if (fabs(s->stag) < 0.1) /// Avoid erasing existing tags
{
s->stag = ctag;
if (s->stag > 0.1)
{
totTagged++;
totLTP += s->stag;
//if (s->stag > 0.5 && b->prpTransients.size()>0) cout <<"Candidate is "<<s->sid<< " " << b->bid << " "<< nrn->nid<<endl;
}
if (s->stag < -0.1)
{
totTaggedMinus++;
totLTD += s->stag;
}
}
/* */
//printf("SID=%d Calc=%f tag=%f %f\n", s->sid, s->calcium, ctag, s->stag);
//s->stag = ctag ;
//* (1.0 - s->stag) ; // * ((1.- 1. / (1.+ exp(-(totw-2.5)*1.5))));
//else if (ctag < -0.05) s->stag = ctag ; // * (s->stag - (-1.0)) ; // * ((1.- 1. / (1.+ exp(-(totw-2.5)*1.5))));
//
//if (s->stag > 1.5 && nrn->prpTransients.size()==1) printf("SID=%d tag=%f PR=%f\n", s->sid, s->stag, nrn->proteinRate);
//if (nrn->nid == 65) printf("ST=%f %d, pr=%f\n", s->stag, s->sid, b->proteinRate);
//if (s->stag > 0.2) printf("ID=%d %f\n", s->sid, s->stag);
//s->eltp = caDP(s->calcium);
//if (s->calcium >0.0) printf("NID=%d sid=%d calc=%f tag=%f\n", nrn->nid, s->sid, s->calcium, s->stag);
b->totcalc += s->calcium;
s->calcium = 0.;
}
if ( b->totcalc > this->localPRPThresh*BPROD_CUTOFF) // This branch should produce PRPs now BPROD
{
b->prpTransients.push_back( pair<float,float>(T, b->totcalc));
//printf ("BID %d NID %d BCALC=%f NCALC=%f S=%d\n", b->bid, nrn->nid, b->totcalc, nrnCalc, (int)b->prpTransients.size());
totBProd++;
}
nrnCalc += b->totcalc;
}
if (nrn->total_spikes > CUTOFF*4.0)
{
totSpikes += nrn->total_spikes;
totact++;
//printf("ACT %d\t %.2f\t%d\t%.2f\n", nrn->nid , nrn->crebLevel , (nrn->total_spikes) , nrnCalc);
updminmax(actmin, actmax, nrnCalc);
}
else
updminmax(nactmin, nactmax, nrnCalc);
if (maxSpk < nrn->total_spikes)
maxSpk = nrn->total_spikes;
if (this->enablePlasticity)
{
if (nrnCalc > this->globalPRPThresh*GPROD_CUTOFF) /// GPROD
{
nrn->prpTransients.push_back( pair<float,float>(T, nrnCalc) );
if (!this->disableCreb )
nrn->crebLevel=1.0;
if (nrn->total_spikes > CUTOFF*4)
tactrec ++;
trec ++;
//printf("id %d nrnCalc=%f spk=%d, dspk=%d CREB=%f trans=%d\n", nrn->nid, nrnCalc, nrn->total_spikes, nrn->dend_spikes, nrn->crebLevel,(int)nrn->prpTransients.size());
}
}
nrn->totcalc = nrnCalc;
}
printf("\n\nAct=[%f,%f] nonact=[%f,%f] \n", actmin, actmax, nactmin, nactmax);
if (this->runningMode == RUN_TRAINING)
{
char buf[256];
sprintf(buf, "./data/r%d.dat", this->runningPatternNo);
//this->SaveSnapshot(buf);
}
printf("TAGGED: %d/%d +%.1f/%.1f GPROD:%d (%.1f%%) BPROD:%d, ACT:%d (%.1f%% ), act+gprod:%d FREQ:%.1f max %.1f DSPK:%d sact:%d\n", totTagged, totTaggedMinus, totLTP, totLTD, trec, 100.*(float)trec/(float(this->pyr_list.size())), totBProd, totact, 100.*(float)totact/(float(this->pyr_list.size())), tactrec, (float)totSpikes/((float)this->pyr_list.size()*4.0), float(maxSpk)/4.0, totbspikes, totSact);
for (; T < tstop; T+= tstep)
{
for (nrn_iter ni = this->pyr_list.begin(); ni != this->pyr_list.end(); ni++)
{
LANeuron* nrn = *ni;
float totalSynapseWeight =0.0;
float totalBranchStrength =0.0;
int totalSynapses =0;
nrn->protein =0.0;
// "Whole-neuron" distribution of proteins
nrn->proteinRate =0;
for (pair_iter ii = nrn->prpTransients.begin(); ii != nrn->prpTransients.end(); ++ii)
{
pair<float, float> p = *ii;
int td= (T - p.first);
float al = (nuclearproteinalpha(td));
if (nrn->proteinRate < al)
nrn->proteinRate = al;
}
for (branch_iter bi = nrn->branches.begin(); bi != nrn->branches.end(); ++bi)
{
LABranch* b = *bi;
b->proteinRate =0.;
for (pair_iter ii = b->prpTransients.begin();ii != b->prpTransients.end(); ++ii)
{
pair<float, float> p = *ii;
float td = float(T - p.first);
float al = (branchproteinalpha(td));
if (b->proteinRate < al)
b->proteinRate = al;
}
float f =0.;
if (this->localProteins)
f = 1.0*b->proteinRate;
else if (this->globalProteins)
f = 1.0* nrn->proteinRate;
else
{
f = 1.0*b->proteinRate + 1.0* nrn->proteinRate;
if (f>1.0) f = 1.0;
}
b->protein = f; // += tstep*(f/2000. - b->protein/3600.);
vector<LASynapse*> candidates;
for (syn_iter si = b->synapses.begin(); si != b->synapses.end(); ++si)
{
LASynapse* s =*si;
if (s->stag != 0.0)
{
s->stag -= (tstep/3600.)* s->stag;
//s->stag -= (s->stag>0. ? +1. : -1.)*tstep / (3.4*3600);
//if (s->sid == 3024) printf("STAG=%f\n", s->stag);
if (b->protein > 0.1 && (s->stag >0.1 || s->stag < 0.1))
{
//candidates.push_back(s);
float fw = s->stag* b->protein;
//if (s->stag >0.)
s->weight += tstep * fw/400.;
}
}
if(1)
{
if (s->weight > maxWeight)
{
s->weight = maxWeight;
//s->stag =0.;
}
else if (s->weight < 0.)
{
s->weight = 0.;
//s->stag =0.;
}
}
totalSynapseWeight += s->weight;
totalSynapses++;
//Homeostasis
//if (1) //this->runningMode != RUN_TRAINING)
//if (this->runningMode == RUN_TEST)
if (1)
{
s->weight += s->weight * (1.0 - nrn->synScaling )*tstep/(7.*24.0* 3600.*homeostasisTimeParam); // Synaptic scaling (Ref: http://www.sciencedirect.com/science/article/pii/S0896627308002134)
}
//if (s->weight > 1.2) printf("SID = %d %f\n", s->sid, s->weight);
if (this->debugMode && b->bid == DEBUG_BID)
{
//cout << b->proteinRate << " " << nrn->proteinRate << " " << b->protein << " " << s->stag << " " << s->weight << " " << endl;
//this->mfile << " " << s->stag << " " << s->weight ;
}
}
/*
if (candidates.size()>0 && b->protein >0.1)
{
LASynapse* s = candidates.at(int(rgen()*(float)candidates.size()));
// Consolidation
float q = b->protein* (s->stag>0 ? 1.0 : -1.0) *tstep/600.0;
float dw;
if (q>=0)
dw = q; //(MAXSTRENGTH - s->weight);
else
dw = q; // *(s->weight - 0.0);
s->weight += dw;
s->stag -= q*1.0;
totCons += dw;
if (s->weight > MAXSTRENGTH)
{
s->weight = MAXSTRENGTH;
//s->stag =0.;
}
else if (s->weight < 0.)
{
s->weight = 0.;
//s->stag =0.;
}
}
*/
//if (this->debugMode && b->bid == DEBUG_BID) this->mfile << endl;
if (0) // Branch strength potentiation
{
if (b->strengthTag>0.01)
{
b->strength += tstep*b->strengthTag*(1.5- b->strength) / (2.0*60.*60.*BSPTimeParam); // Max branch strength=2, time to get there: 40 minutes losonczy 2008 figure 3 http://www.nature.com/nature/journal/v452/n7186/abs/nature06725.html
b->strengthTag -= tstep*b->strengthTag / (10.*60.);
}
totalBranchStrength += b->strength;
b->strength += tstep*b->strength*(1.0 - nrn->branch_scaling) / (3.0*3600.); // Branch homeostatic scaling
}
if (T%800 ==0)
{
b->branchProteinHistory.push_back(b->protein);
//b->branchStrengthHistory .push_back(b->strength);
}
}
//if (T%500==0) nrn->proteinHistory.push_back(nrn->proteinRate);
// Synaptic homeostasis / synaptic scaling
//if (nrn->synapticWeightsInitialSum != 0.0 )
if (totalSynapses>0)
nrn->synScaling = totalSynapseWeight / (initWeight*float(totalSynapses));
else
nrn->synScaling = 1.0;
// Branch plasticity homeostasis
nrn->branch_scaling = totalBranchStrength/((float(1.0) * float(nrn->branches.size())));
//creb Drop
if (nrn->crebLevel >0.0)
{
nrn->crebLevel -= tstep/(3600.*8.*CREBTimeParam );
//if (nrn->nid == DEBUG_NID) printf("CREBlev=%f\n", nrn->crebLevel);
//nrn->crebLevel -= nrn->crebLevel * tstep / (3600.0*4.);
}
}
#ifdef WXGLMODEL_H
if (this->wx_window && T%20 ==0)
{
this->wx_window->UpdatePanel();
}
#endif
}
//printf("CONSOLIDATED: %f\n", totCons);
// zuo et al. 2005
// We assume 100% of filopodia turn over over 24 hours.
// We assume that weak synapses (W < 0.3) are filopodia
/*
if (this->enablePlasticity)
{
this->isPruningSynapses = true;
int synapsesToPrune = 0.005*float(totalWeak) * float(durationSecs)/3600.0;
cout << "removing "<< synapsesToPrune << "synapses" << endl;
int found = this->PurgeInputSynapses(synapsesToPrune, weightLimit);
if (found > 0)
this->CreateInputSynapses(found);
cout << "Renewed " << found <<" synapses" << endl;
this->isPruningSynapses = false;
}
*/
if (this->enablePlasticity)
this->DoTurnover(durationSecs);
this->isInterstim = false;
}
void LANetwork::DoTurnover(float durationSecs )
{
float pTurnOver = 4.*durationSecs/86400.; // per day
int synsAdded=0;
for (branch_iter bi = this->branches.begin(); bi != this->branches.end(); bi++)
{
LABranch* b = *bi;
if (b->turnoverRate>0.0)
{
vector<LASynapse*> v;
for (syn_iter si = b->synapses.begin(); si != b->synapses.end(); si++)
{
LASynapse* s = *si;
if (s->isPlastic && s->weight <= this->initWeight)
{
float p;
if (this->turnoverHotspots==0 || this->turnoverHotspots == 2)
p = b->turnoverRate*0.1981; // uniform
else
{
float dist = s->pos - b->turnoverPoint;
p = exp(-(dist*dist)/.1)*b->turnoverRate;
}
if (rgen() < p*pTurnOver)
{
VEC_REMOVE(s->source_nrn->outgoing, s);
VEC_REMOVE(s->target_nrn->incoming, s);
VEC_REMOVE(this->synapses, s);
//cout << " Removing syn " << s->sid << endl;
si = b->synapses.erase(si); //VEC_REMOVE(s->target_branch->synapses, s);
delete s;
/* Connect a random input back here */
nrn_list lst = this->inputs_cs.at(randomindex(this->inputs_cs.size()));
LANeuron* n = lst.at(randomindex(lst.size()));
this->AddSynapse(n, b, initWeight, true);
synsAdded++;
continue;
}
}
}
}
}
printf("Added/removed %d synapses\n", synsAdded);
}
void LANetwork::Begin()
{
}