MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
STDPSynHandler.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 ** This program is part of 'MOOSE', the
3 ** Messaging Object Oriented Simulation Environment.
4 ** Copyright (C) 2011 Upinder S. Bhalla. and NCBS
5 ** It is made available under the terms of the
6 ** GNU Lesser General Public License version 2.1
7 ** See the file COPYING.LIB for the full notice.
8 **********************************************************************/
9 
10 #include <queue>
11 #include "header.h"
12 #include "Synapse.h"
13 #include "SynEvent.h" // only using the SynEvent class from this
14 #include "SynHandlerBase.h"
15 #include "STDPSynapse.h"
16 #include "STDPSynHandler.h"
17 
19 {
20  static string doc[] =
21  {
22  "Name", "STDPSynHandler",
23  "Author", "Aditya Gilra",
24  "Description",
25  "The STDPSynHandler handles synapses with spike timing dependent plasticity (STDP). "
26  "It uses two priority queues to manage pre and post spikes."
27  };
28 
30  "aMinus",
31  "aMinus is a post-synaptic variable that keeps a decaying 'history' of previous post-spike(s)"
32  "and is used to update the synaptic weight when a pre-synaptic spike appears."
33  "It determines the t_pre > t_post (pre after post) part of the STDP window.",
36  );
37 
39  "aMinus0",
40  "aMinus0 is added to aMinus on every pre-spike",
43  );
44 
46  "tauMinus",
47  "aMinus decays with tauMinus time constant",
50  );
51 
53  "aPlus0",
54  "aPlus0 is added to aPlus on every pre-spike",
57  );
58 
60  "tauPlus",
61  "aPlus decays with tauPlus time constant",
64  );
65 
66  static ValueFinfo< STDPSynHandler, double > weightMax(
67  "weightMax",
68  "an upper bound on the weight",
71  );
72 
73  static ValueFinfo< STDPSynHandler, double > weightMin(
74  "weightMin",
75  "a lower bound on the weight",
78  );
79 
80  static DestFinfo addPostSpike( "addPostSpike",
81  "Handles arriving spike messages from post-synaptic neuron, inserts into postEvent queue.",
83 
85  "synapse",
86  "Sets up field Elements for synapse",
88  /*
89  below SynHandlerBase::getSynapse is a function that returns Synapse*,
90  but I need to cast the returned pointer to an STDPSynapse*.
91  Since I take the address (&) of SynHandlerBase::getSynapse
92  which is: Synapse* (SynHandlerBase::*)(unsigned int),
93  I need to cast the address of the function to:
94  STDPSynapse* (SynHandlerBase::*)(unsigned int).
95 
96  This is required to put STDPSynapse in above FieldElementFinfo definition,
97  see FieldElementFinfo template class in basecode/FieldElementFinfo.h
98  */
102  );
103 
104  static Finfo* STDPSynHandlerFinfos[] = {
105  &synFinfo, // FieldElement
106  &addPostSpike, // DestFinfo
107  &aMinus0, // Field
108  &aMinus, // Field
109  &tauMinus, // Field
110  &aPlus0, // Field
111  &tauPlus, // Field
112  &weightMax, // Field
113  &weightMin // Field
114  };
115 
116  static Dinfo< STDPSynHandler > dinfo;
117  static Cinfo synHandlerCinfo (
118  "STDPSynHandler",
120  STDPSynHandlerFinfos,
121  sizeof( STDPSynHandlerFinfos ) / sizeof ( Finfo* ),
122  &dinfo,
123  doc,
124  sizeof( doc ) / sizeof( string )
125  );
126 
127  return &synHandlerCinfo;
128 }
129 
131 
133 {
134  aMinus_ = 0.0;
135  tauMinus_ = 1.0;
136  aMinus0_ = 0.0;
137  tauPlus_ = 1.0;
138  aPlus0_ = 0.0;
139  weightMin_ = 0.0;
140  weightMax_ = 0.0;
141 }
142 
144 { ; }
145 
147 {
148  synapses_ = ssh.synapses_;
149  for ( vector< STDPSynapse >::iterator
150  i = synapses_.begin(); i != synapses_.end(); ++i )
151  i->setHandler( this );
152 
153  // For no apparent reason, priority queues don't have a clear operation.
154  while( !events_.empty() )
155  events_.pop();
156 
157  while( !postEvents_.empty() )
158  postEvents_.pop();
159 
160  return *this;
161 }
162 
163 void STDPSynHandler::vSetNumSynapses( const unsigned int v )
164 {
165  unsigned int prevSize = synapses_.size();
166  synapses_.resize( v );
167  for ( unsigned int i = prevSize; i < v; ++i )
168  synapses_[i].setHandler( this );
169 }
170 
172 {
173  return synapses_.size();
174 }
175 
177 {
178  static STDPSynapse dummy;
179  if ( i < synapses_.size() )
180  return &synapses_[i];
181  cout << "Warning: STDPSynHandler::getSynapse: index: " << i <<
182  " is out of range: " << synapses_.size() << endl;
183  return &dummy;
184 }
185 
187  unsigned int index, double time, double weight )
188 {
189  assert( index < synapses_.size() );
190  events_.push( PreSynEvent( index, time, weight ) );
191 }
192 
193 double STDPSynHandler::getTopSpike( unsigned int index ) const
194 {
195  if ( events_.empty() )
196  return 0.0;
197  return events_.top().time;
198 }
199 
200 void STDPSynHandler::addPostSpike( const Eref& e, double time )
201 {
202  postEvents_.push( PostSynEvent( time ) );
203 }
204 
206 {
207  double activation = 0.0;
208 
209  // process pre-synaptic spike events for activation and STDP
210  while( !events_.empty() && events_.top().time <= p->currTime ) {
211  PreSynEvent currEvent = events_.top();
212 
213  unsigned int synIndex = currEvent.synIndex;
214  // Warning, coder! 'STDPSynapse currSyn = synapses_[synIndex];' is wrong,
215  // it creates a new, shallow-copied object.
216  // We want only to point to the same object.
217  STDPSynapse* currSynPtr = &synapses_[synIndex];
218 
219  // activate the synapse for every pre-spike
220  // If the synapse has a delay, the weight could be updated during the delay!
221  // currEvent.weight is the weight before the delay!
222  // Might be better to use currSynPtr->getWeight()
223  // or even the latest updated weight below?!
224  // Using currSynPtr->getWeight().
225  // However, the weight update is done
226  // after sending the current weight to activation
227 
228  // See: http://www.genesis-sim.org/GENESIS/Hyperdoc/Manual-26.html#synchan
229  // Send out weight / dt for every spike
230  // Since it is an impulse active only for one dt,
231  // need to send it divided by dt.
232  // Can connect activation to SynChan (double exp)
233  // or to LIF as an impulse to voltage.
234  //activation += currEvent.weight / p->dt;
235  activation += currSynPtr->getWeight() / p->dt;
236 
237  // Maintain 'history' of pre-spikes in Aplus
238  // Add aPlus0 to the aPlus for this synapse due to pre-spike
239  currSynPtr->setAPlus( currSynPtr->getAPlus() + aPlus0_ );
240 
241  // Change weight by aMinus_ at each pre-spike
242  // clip weight within [weightMin,weightMax]
243  double newWeight = currEvent.weight + aMinus_;
244  newWeight = std::max(weightMin_, std::min(newWeight, weightMax_));
245  currSynPtr->setWeight( newWeight );
246 
247  events_.pop();
248  }
249  if ( activation != 0.0 )
250  SynHandlerBase::activationOut()->send( e, activation );
251 
252  // process post-synaptic spike events for STDP
253  while( !postEvents_.empty() && postEvents_.top().time <= p->currTime ) {
254  // Add aMinus0 to the aMinus for this synapse
255  aMinus_ += aMinus0_;
256 
257  // Change weight of all synapses by aPlus_ at each post-spike
258  for (unsigned int i=0; i<synapses_.size(); i++) {
259  // since aPlus_, tauPlus_ are private inside STDPSynapse,
260  // we use the set, get functions
261  // Warning, coder! 'STDPSynapse currSyn = synapses_[i];' is wrong,
262  // it creates a new, shallow-copied object.
263  // We want only to point to the same object.
264  STDPSynapse* currSynPtr = &synapses_[i];
265  // clip weight within [weightMin,weightMax]
266  double newWeight = currSynPtr->getWeight() + currSynPtr->getAPlus();
267  newWeight = std::max(weightMin_, std::min(newWeight, weightMax_));
268  currSynPtr->setWeight( newWeight );
269  }
270 
271  postEvents_.pop();
272  }
273 
274  // modify aPlus and aMinus at every time step
275  // Future: I could make this event-driven. Would be faster.
276  // Or have a field to set it to event-driven or continuous.
277  double dt_ = p->dt;
278  // decay aPlus for all pre-synaptic inputs
279  for (unsigned int i=0; i<synapses_.size(); i++) {
280  // forward Euler
281  // since aPlus_, tauPlus_ are private inside STDPSynapse,
282  // we use the set, get functions
283  // Warning, coder! 'STDPSynapse currSyn = synapses_[i];' is wrong,
284  // it creates a new, shallow-copied object.
285  // We want only to point to the same object.
286  STDPSynapse* currSynPtr = &synapses_[i];
287  currSynPtr->setAPlus( currSynPtr->getAPlus() * (1.0 - dt_/tauPlus_) );
288  }
289  // decay aMinus for this STDPSynHandler which sits on the post-synaptic compartment
290  // forward Euler
291  aMinus_ -= aMinus_/tauMinus_*dt_;
292 
293 }
294 
296 {
297  // For no apparent reason, priority queues don't have a clear operation.
298  while( !events_.empty() )
299  events_.pop();
300  while( !postEvents_.empty() )
301  postEvents_.pop();
302 }
303 
305 {
306  unsigned int newSynIndex = synapses_.size();
307  synapses_.resize( newSynIndex + 1 );
308  synapses_[newSynIndex].setHandler( this );
309  return newSynIndex;
310 }
311 
312 
313 void STDPSynHandler::dropSynapse( unsigned int msgLookup )
314 {
315  assert( msgLookup < synapses_.size() );
316  synapses_[msgLookup].setWeight( -1.0 );
317 }
318 
319 void STDPSynHandler::setAMinus0( const double v )
320 {
321  aMinus0_ = v;
322 }
323 
325 {
326  return aMinus0_;
327 }
328 
329 void STDPSynHandler::setAMinus( const double v )
330 {
331  aMinus_ = v;
332 }
333 
335 {
336  return aMinus_;
337 }
338 
339 void STDPSynHandler::setTauMinus( const double v )
340 {
341  if ( rangeWarning( "tauMinus", v ) ) return;
342  tauMinus_ = v;
343 }
344 
346 {
347  return tauMinus_;
348 }
349 
350 void STDPSynHandler::setAPlus0( const double v )
351 {
352  aPlus0_ = v;
353 }
354 
356 {
357  return aPlus0_;
358 }
359 
360 void STDPSynHandler::setTauPlus( const double v )
361 {
362  if ( rangeWarning( "tauPlus", v ) ) return;
363  tauPlus_ = v;
364 }
365 
367 {
368  return tauPlus_;
369 }
370 
371 void STDPSynHandler::setWeightMax( const double v )
372 {
373  weightMax_ = v;
374 }
375 
377 {
378  return weightMax_;
379 }
380 
381 void STDPSynHandler::setWeightMin( const double v )
382 {
383  weightMin_ = v;
384 }
385 
387 {
388  return weightMin_;
389 }
unsigned int vGetNumSynapses() const
STDPSynapse * vGetSynapse(unsigned int i)
priority_queue< PostSynEvent, vector< PostSynEvent >, ComparePostSynEvent > postEvents_
void setNumSynapses(unsigned int num)
void vReinit(const Eref &e, ProcPtr p)
void setWeightMin(double v)
double currTime
Definition: ProcInfo.h:19
void setWeight(double v)
Definition: Synapse.cpp:78
Definition: Dinfo.h:60
double getWeightMin() const
double getTauPlus() const
void setTauMinus(double v)
Definition: EpFunc.h:64
static DestFinfo dummy("dummy","This Finfo is a dummy. If you are reading this you have used an invalid index", 0)
double getWeight() const
Definition: Synapse.cpp:88
unsigned int getNumSynapses() const
void vProcess(const Eref &e, ProcPtr p)
double getTopSpike(unsigned int index) const
double weight
Definition: SynEvent.h:25
void addSpike(unsigned int index, double time, double weight)
static const Cinfo * initCinfo()
Synapse * getSynapse(unsigned int i)
void dropSynapse(unsigned int droppedSynNumber)
void setTauPlus(double v)
vector< STDPSynapse > synapses_
void setAPlus0(double v)
static const Cinfo * initCinfo()
Definition: STDPSynapse.cpp:15
void setAMinus0(double v)
void setWeightMax(double v)
double getTauMinus() const
priority_queue< PreSynEvent, vector< PreSynEvent >, CompareSynEvent > events_
double dt
Definition: ProcInfo.h:18
Definition: Eref.h:26
double getAPlus() const
Definition: STDPSynapse.cpp:71
void vSetNumSynapses(unsigned int num)
bool rangeWarning(const string &field, double value)
void setAMinus(double v)
double getAMinus0() const
static SrcFinfo1< double > * activationOut()
unsigned int synIndex
Definition: SynEvent.h:52
double getAPlus0() const
unsigned int addSynapse()
Adds a new synapse, returns its index.
double getAMinus() const
static const Cinfo * initCinfo()
void setAPlus(double v)
Definition: STDPSynapse.cpp:66
static const Cinfo * synHandlerCinfo
static const Cinfo * STDPSynHandlerCinfo
STDPSynHandler & operator=(const STDPSynHandler &other)
double getWeightMax() const
Definition: Cinfo.h:18
void addPostSpike(const Eref &e, double time)
Definition: Finfo.h:12