1 /*
2  *  :copyright: Copyright 2006-2021 by the PyNN team, see AUTHORS.
3  *  :license: CeCILL, see LICENSE for details.
4  *
5  */
6 
7 #ifndef SIMPLE_STOCHASTIC_SYNAPSE_H
8 #define SIMPLE_STOCHASTIC_SYNAPSE_H
9 
10 // Includes from nestkernel:
11 #include "connection.h"
12 
13 
14 /* BeginUserDocs: synapse, short-term plasticity
15 
16 Short description
17 +++++++++++++++++
18 
19 Synapse dropping spikes stochastically.
20 
21 Description
22 +++++++++++
23 
24 This synapse will deliver spikes with probability p.
25 
26 Parameters
27 ++++++++++
28 
29 = ==== =========================================================================================
30 p real probability that a spike is transmitted, default = 1.0 (i.e. spike is always transmitted)
31 = ==== =========================================================================================
32 
33 Transmits
34 +++++++++
35 
36 SpikeEvent
37 
38 SeeAlso
39 +++++++
40 
41 static_synapse, synapsedict
42 EndUserDocs */
43 
44 namespace pynn
45 {
46 
47 template < typename targetidentifierT >
48 class simple_stochastic_synapse : public nest::Connection< targetidentifierT >
49 {
50 private:
51   double weight_; //!< Synaptic weight
52   double p_;      //!< Probability of spike transmission
53 
54 public:
55   //! Type to use for representing common synapse properties
56   typedef nest::CommonSynapseProperties CommonPropertiesType;
57 
58   //! Shortcut for base class
59   typedef nest::Connection< targetidentifierT > ConnectionBase;
60 
61   /**
62    * Default Constructor.
63    * Sets default values for all parameters. Needed by GenericConnectorModel.
64    */
simple_stochastic_synapse()65   simple_stochastic_synapse()
66     : ConnectionBase()
67     , weight_( 1.0 )
68     , p_( 1.0 )
69   {
70   }
71 
72   //! Default Destructor.
~simple_stochastic_synapse()73   ~simple_stochastic_synapse()
74   {
75   }
76 
77   /**
78    * Helper class defining which types of events can be transmitted.
79    *
80    * These methods are only used to test whether a certain type of connection
81    * can be created.
82    *
83    * `handles_test_event()` should be added for all event types that the
84    * synapse can transmit. The methods shall return `invalid_port_`; the
85    * return value will be ignored.
86    *
87    * Since this is a synapse model dropping spikes, it is only for spikes,
88    * therefore we only implement `handles_test_event()` only for spike
89    * events.
90    *
91    * See Kunkel et al (2014), Sec 3.3.1, for background information.
92    */
93   class ConnTestDummyNode : public nest::ConnTestDummyNodeBase
94   {
95   public:
96     using nest::ConnTestDummyNodeBase::handles_test_event;
97     nest::port
handles_test_event(nest::SpikeEvent &,nest::rport)98     handles_test_event( nest::SpikeEvent&, nest::rport )
99     {
100       return nest::invalid_port_;
101     }
102 
103     nest::port
handles_test_event(nest::DSSpikeEvent &,nest::rport)104     handles_test_event( nest::DSSpikeEvent&, nest::rport )
105     {
106       return nest::invalid_port_;
107     }
108   };
109 
110   /**
111    * Check that requested connection can be created.
112    *
113    * This function is a boilerplate function that should be included unchanged
114    * in all synapse models. It is called before a connection is added to check
115    * that the connection is legal. It is a wrapper that allows us to call
116    * the "real" `check_connection_()` method with the `ConnTestDummyNode
117    * dummy_target;` class for this connection type. This avoids a virtual
118    * function call for better performance.
119    *
120    * @param s  Source node for connection
121    * @param t  Target node for connection
122    * @param receptor_type  Receptor type for connection
123    * @param lastspike Time of most recent spike of presynaptic (sender) neuron,
124    *                  not used here
125    */
126   void
check_connection(nest::Node & s,nest::Node & t,nest::rport receptor_type,const CommonPropertiesType &)127   check_connection( nest::Node& s,
128     nest::Node& t,
129     nest::rport receptor_type,
130     const CommonPropertiesType& )
131   {
132     ConnTestDummyNode dummy_target;
133     ConnectionBase::check_connection_( dummy_target, s, t, receptor_type );
134   }
135 
136   /**
137    * Send an event to the receiver of this connection.
138    * @param e The event to send
139    * @param t Thread
140    * @param cp Common properties to all synapses.
141    */
142   void send( nest::Event& e, nest::thread t, const CommonPropertiesType& cp );
143 
144   // The following methods contain mostly fixed code to forward the
145   // corresponding tasks to corresponding methods in the base class and the w_
146   // data member holding the weight.
147 
148   //! Store connection status information in dictionary
149   void get_status( DictionaryDatum& d ) const;
150 
151   /**
152    * Set connection status.
153    *
154    * @param d Dictionary with new parameter values
155    * @param cm ConnectorModel is passed along to validate new delay values
156    */
157   void set_status( const DictionaryDatum& d, nest::ConnectorModel& cm );
158 
159   //! Allows efficient initialization on construction
160   void
set_weight(double w)161   set_weight( double w )
162   {
163     weight_ = w;
164   }
165 };
166 
167 
168 template < typename targetidentifierT >
169 inline void
send(nest::Event & e,nest::thread t,const CommonPropertiesType & props)170 simple_stochastic_synapse< targetidentifierT >::send( nest::Event& e,
171   nest::thread t,
172   const CommonPropertiesType& props )
173 {
174   if ( nest::get_vp_specific_rng( t )->drand() < (1 - p_) )  // drop spike
175     return;
176 
177   // Even time stamp, we send the spike using the normal sending mechanism
178   // send the spike to the target
179   e.set_weight( weight_ );
180   e.set_delay_steps( ConnectionBase::get_delay_steps() );
181   e.set_receiver( *ConnectionBase::get_target( t ) );
182   e.set_rport( ConnectionBase::get_rport() );
183   e(); // this sends the event
184 }
185 
186 template < typename targetidentifierT >
187 void
get_status(DictionaryDatum & d)188 simple_stochastic_synapse< targetidentifierT >::get_status(
189   DictionaryDatum& d ) const
190 {
191   ConnectionBase::get_status( d );
192   def< double >( d, nest::names::weight, weight_ );
193   def< double >( d, nest::names::p, p_ );
194   def< long >( d, nest::names::size_of, sizeof( *this ) );
195 }
196 
197 template < typename targetidentifierT >
198 void
set_status(const DictionaryDatum & d,nest::ConnectorModel & cm)199 simple_stochastic_synapse< targetidentifierT >::set_status(
200   const DictionaryDatum& d,
201   nest::ConnectorModel& cm )
202 {
203   ConnectionBase::set_status( d, cm );
204   updateValue< double >( d, nest::names::weight, weight_ );
205   updateValue< double >( d, nest::names::p, p_ );
206 }
207 
208 } // namespace
209 
210 #endif // simple_stochastic_synapse.h
211