Skip to content

Commit

Permalink
Merge pull request #218 from sanjayankur31/symmetric_stdp_synapse
Browse files Browse the repository at this point in the history
Add symmetric stdp synapse to NEST
  • Loading branch information
heplesser authored Jul 5, 2016
2 parents 1abb181 + 2389d55 commit 62c019b
Show file tree
Hide file tree
Showing 4 changed files with 566 additions and 0 deletions.
1 change: 1 addition & 0 deletions models/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ set( models_sources
tsodyks_connection.h
tsodyks_connection_hom.h tsodyks_connection_hom.cpp
volume_transmitter.h volume_transmitter.cpp
vogels_sprekeler_connection.h
spike_dilutor.h spike_dilutor.cpp
)

Expand Down
16 changes: 16 additions & 0 deletions models/modelsmodule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
#include "tsodyks2_connection.h"
#include "tsodyks_connection.h"
#include "tsodyks_connection_hom.h"
#include "vogels_sprekeler_connection.h"

// Includes from nestkernel:
#include "common_synapse_properties.h"
Expand Down Expand Up @@ -571,6 +572,21 @@ ModelsModule::init( SLIInterpreter* )
.model_manager
.register_connection_model< STDPDopaConnection< TargetIdentifierIndex > >(
"stdp_dopamine_synapse_hpc" );

/* BeginDocumentation
Name: vogels_sprekeler_synapse_hpc - Variant of vogels_sprekeler_synapse
with low memory
consumption.
SeeAlso: synapsedict, vogels_sprekeler_synapse
*/
kernel()
.model_manager
.register_connection_model< VogelsSprekelerConnection< TargetIdentifierPtrRport > >(
"vogels_sprekeler_synapse" );
kernel()
.model_manager
.register_connection_model< VogelsSprekelerConnection< TargetIdentifierIndex > >(
"vogels_sprekeler_synapse_hpc" );
}

} // namespace nest
313 changes: 313 additions & 0 deletions models/vogels_sprekeler_connection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
/*
* vogels_sprekeler_connection.h
*
* This file is part of NEST.
*
* Copyright (C) 2004 The NEST Initiative
*
* NEST 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 2 of the License, or
* (at your option) any later version.
*
* NEST 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 NEST. If not, see <http://www.gnu.org/licenses/>.
*
*/

#ifndef VOGELS_SPREKELER_CONNECTION_H
#define VOGELS_SPREKELER_CONNECTION_H

/* BeginDocumentation
Name: vogels_sprekeler_synapse - Synapse type for symmetric spike-timing
dependent
plasticity with constant depression.
Description:
vogels_sprekeler_synapse is a connector to create synapses with symmetric
spike time dependent plasticity and constant depression (as defined in [1]).
The learning rule is symmetric, i.e., the synapse is strengthened
irrespective of the order of the pre and post-synaptic spikes. Each
pre-synaptic spike also causes a constant depression of the synaptic weight
which differentiates this rule from other classical stdp rules.
Parameters:
tau double - Time constant of STDP window, potentiation in ms
Wmax double - Maximum allowed weight
eta double - learning rate
alpha double - constant depression (= 2 * tau * target firing rate in
[1])
Transmits: SpikeEvent
References:
[1] Vogels et al. (2011) Inhibitory Plasticity Balances Excitation and
Inhibition in Sensory Pathways and Memory Networks.
Science Vol. 334, Issue 6062, pp. 1569-1573
DOI: 10.1126/science.1211095
FirstVersion: January 2016
Author: Ankur Sinha
SeeAlso: synapsedict
*/

// C-header for math.h since copysign() is in C99 but not C++98
#include <math.h>
#include "connection.h"

namespace nest
{

// connections are templates of target identifier type (used for pointer /
// target index addressing)
// derived from generic connection template
template < typename targetidentifierT >
class VogelsSprekelerConnection : public Connection< targetidentifierT >
{

public:
typedef CommonSynapseProperties CommonPropertiesType;
typedef Connection< targetidentifierT > ConnectionBase;

/**
* Default Constructor.
* Sets default values for all parameters. Needed by GenericConnectorModel.
*/
VogelsSprekelerConnection();


/**
* Copy constructor.
* Needs to be defined properly in order for GenericConnector to work.
*/
VogelsSprekelerConnection( const VogelsSprekelerConnection& );

// Explicitly declare all methods inherited from the dependent base
// ConnectionBase.
// This avoids explicit name prefixes in all places these functions are used.
// Since ConnectionBase depends on the template parameter, they are not
// automatically
// found in the base class.
using ConnectionBase::get_delay_steps;
using ConnectionBase::get_delay;
using ConnectionBase::get_rport;
using ConnectionBase::get_target;

/**
* Get all properties of this connection and put them into a dictionary.
*/
void get_status( DictionaryDatum& d ) const;

/**
* Set properties of this connection from the values given in dictionary.
*/
void set_status( const DictionaryDatum& d, ConnectorModel& cm );

/**
* Send an event to the receiver of this connection.
* \param e The event to send
* \param t_lastspike Point in time of last spike sent.
* \param cp common properties of all synapses (empty).
*/
void send( Event& e,
thread t,
double_t t_lastspike,
const CommonSynapseProperties& cp );


class ConnTestDummyNode : public ConnTestDummyNodeBase
{
public:
// Ensure proper overriding of overloaded virtual functions.
// Return values from functions are ignored.
using ConnTestDummyNodeBase::handles_test_event;
port
handles_test_event( SpikeEvent&, rport )
{
return invalid_port_;
}
};

void
check_connection( Node& s,
Node& t,
rport receptor_type,
double_t t_lastspike,
const CommonPropertiesType& )
{
ConnTestDummyNode dummy_target;

ConnectionBase::check_connection_( dummy_target, s, t, receptor_type );

t.register_stdp_connection( t_lastspike - get_delay() );
}

void
set_weight( double_t w )
{
weight_ = w;
}

private:
double_t
facilitate_( double_t w, double_t kplus )
{
double_t new_w = std::abs( w ) + ( eta_ * kplus );
return copysign( new_w < std::abs( Wmax_ ) ? new_w : Wmax_, Wmax_ );
}

double_t
depress_( double_t w )
{
double_t new_w = std::abs( w ) - ( alpha_ * eta_ );
return copysign( new_w > 0.0 ? new_w : 0.0, Wmax_ );
}

// data members of each connection
double_t weight_;
double_t tau_;
double_t alpha_;
double_t eta_;
double_t Wmax_;
double_t Kplus_;
};


/**
* Send an event to the receiver of this connection.
* \param e The event to send
* \param t The thread on which this connection is stored.
* \param t_lastspike Time point of last spike emitted
* \param cp Common properties object, containing the stdp parameters.
*/
template < typename targetidentifierT >
inline void
VogelsSprekelerConnection< targetidentifierT >::send( Event& e,
thread t,
double_t t_lastspike,
const CommonSynapseProperties& )
{
// synapse STDP depressing/facilitation dynamics
double_t t_spike = e.get_stamp().get_ms();
// t_lastspike_ = 0 initially

// use accessor functions (inherited from Connection< >) to obtain delay and
// target
Node* target = get_target( t );
double_t dendritic_delay = get_delay();

// get spike history in relevant range (t1, t2] from post-synaptic neuron
std::deque< histentry >::iterator start;
std::deque< histentry >::iterator finish;
target->get_history(
t_lastspike - dendritic_delay, t_spike - dendritic_delay, &start, &finish );

// presynaptic neuron j, post synaptic neuron i
// Facilitation for each post synaptic spike
// Wij = Wij + eta*xj
double_t minus_dt;
while ( start != finish )
{
minus_dt = t_lastspike - ( start->t_ + dendritic_delay );
++start;
if ( minus_dt == 0 )
continue;
weight_ = facilitate_( weight_, Kplus_ * std::exp( minus_dt / tau_ ) );
}

// For pre-synaptic spikes
// Wij = Wij + eta(xi - alpha)
// Facilitation and constant depression
// Getting kvalue at required time already for deferred processing, so no
// need to transform it to the current time, and so, no exponential required
weight_ =
facilitate_( weight_, target->get_K_value( t_spike - dendritic_delay ) );
weight_ = depress_( weight_ );

e.set_receiver( *target );
e.set_weight( weight_ );
// use accessor functions (inherited from Connection< >) to obtain delay in
// steps and rport
e.set_delay( get_delay_steps() );
e.set_rport( get_rport() );
e();

// exponential part for the decay, addition of one for each spike
Kplus_ = Kplus_ * std::exp( ( t_lastspike - t_spike ) / tau_ ) + 1.0;
}


template < typename targetidentifierT >
VogelsSprekelerConnection< targetidentifierT >::VogelsSprekelerConnection()
: ConnectionBase()
, weight_( 0.5 )
, tau_( 20.0 )
, alpha_( 0.12 )
, eta_( 0.001 )
, Wmax_( 1.0 )
, Kplus_( 0.0 )
{
}

template < typename targetidentifierT >
VogelsSprekelerConnection< targetidentifierT >::VogelsSprekelerConnection(
const VogelsSprekelerConnection< targetidentifierT >& rhs )
: ConnectionBase( rhs )
, weight_( rhs.weight_ )
, tau_( rhs.tau_ )
, alpha_( rhs.alpha_ )
, eta_( rhs.eta_ )
, Wmax_( rhs.Wmax_ )
, Kplus_( rhs.Kplus_ )
{
}

template < typename targetidentifierT >
void
VogelsSprekelerConnection< targetidentifierT >::get_status(
DictionaryDatum& d ) const
{
ConnectionBase::get_status( d );
def< double_t >( d, names::weight, weight_ );
def< double_t >( d, "tau", tau_ );
def< double_t >( d, "alpha", alpha_ );
def< double_t >( d, "eta", eta_ );
def< double_t >( d, "Wmax", Wmax_ );
def< double_t >( d, "Kplus", Kplus_ );
def< long_t >( d, names::size_of, sizeof( *this ) );
}

template < typename targetidentifierT >
void
VogelsSprekelerConnection< targetidentifierT >::set_status(
const DictionaryDatum& d,
ConnectorModel& cm )
{
ConnectionBase::set_status( d, cm );
updateValue< double_t >( d, names::weight, weight_ );
updateValue< double_t >( d, "tau", tau_ );
updateValue< double_t >( d, "alpha", alpha_ );
updateValue< double_t >( d, "eta", eta_ );
updateValue< double_t >( d, "Wmax", Wmax_ );
updateValue< double_t >( d, "Kplus", Kplus_ );

// check if weight_ and Wmax_ has the same sign
if ( not( ( ( weight_ >= 0 ) - ( weight_ < 0 ) )
== ( ( Wmax_ >= 0 ) - ( Wmax_ < 0 ) ) ) )
{
throw BadProperty( "Weight and Wmax must have same sign." );
}

if ( not( Kplus_ >= 0 ) )
{
throw BadProperty( "State Kplus must be positive." );
}
}
} // of namespace nest

#endif // of #ifndef VOGELS_SPREKELER_CONNECTION_H
Loading

0 comments on commit 62c019b

Please sign in to comment.