1 /*
2  *  conn_parameter.h
3  *
4  *  This file is part of NEST.
5  *
6  *  Copyright (C) 2004 The NEST Initiative
7  *
8  *  NEST is free software: you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation, either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  NEST is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with NEST.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #ifndef CONN_PARAMETER_H
24 #define CONN_PARAMETER_H
25 
26 // C++ includes:
27 #include <limits>
28 #include <vector>
29 
30 // Includes from nestkernel:
31 #include "exceptions.h"
32 #include "parameter.h"
33 #include "nest_datums.h"
34 
35 // Includes from sli:
36 #include "token.h"
37 
38 /**
39  * Base class for parameters provided to connection routines.
40  *
41  * Principles for these parameters are
42  * - Each parameter is a single scalar value.
43  * - The parameter will be returned as type double.
44  * - The parameter values can be given either as
45  *   - a single scalar: the same value is returned for each call
46  *   - a random deviate generator: a new random values is returned for each call
47  *   - an array of scalars: values are returned in order
48  */
49 
50 namespace nest
51 {
52 
53 class ConnParameter
54 {
55 
56 public:
ConnParameter()57   ConnParameter()
58   {
59   }
60 
~ConnParameter()61   virtual ~ConnParameter()
62   {
63   }
64 
65   /**
66    * Return parameter value.
67    *
68    * The parameter value may depend on target threads
69    * and random numbers. Both must be supplied, even if
70    * a concrete parameter type does not use them.
71    *
72    * @param target_thread  will be ignored except for array parameters.
73    * @param rng   random number generator pointer
74    * will be ignored except for random parameters.
75    */
76   virtual double value_double( thread, RngPtr, index, Node* ) const = 0;
77   virtual long value_int( thread, RngPtr, index, Node* ) const = 0;
skip(thread,size_t)78   virtual void skip( thread, size_t ) const
79   {
80   }
81   virtual bool is_array() const = 0;
82 
83   virtual bool
is_scalar()84   is_scalar() const
85   {
86     return false;
87   }
88 
89   virtual bool
provides_long()90   provides_long() const
91   {
92     return false;
93   }
94 
95   virtual void
reset()96   reset() const
97   {
98     throw NotImplemented( "Symmetric connections require parameters that can be reset." );
99   }
100 
101   /**
102    * Returns number of values available.
103    *
104    * 0 indicates scalar/unlimited supply.
105    */
106   virtual size_t
number_of_values()107   number_of_values() const
108   {
109     return 0;
110   }
111 
112   /**
113   * @param t parameter
114   * type is established by casts to all acceptedpossibilities
115   * @param nthread number of threads
116   * required to fix number pointers to the iterator (one for each thread)
117   */
118   static ConnParameter* create( const Token&, const size_t );
119 };
120 
121 
122 /**
123  * Single double value.
124  *
125  * On each request, it returns the same value.
126  */
127 class ScalarDoubleParameter : public ConnParameter
128 {
129 public:
ScalarDoubleParameter(double value,const size_t)130   ScalarDoubleParameter( double value, const size_t )
131     : value_( value )
132   {
133   }
134 
135   double
value_double(thread,RngPtr,index,Node *)136   value_double( thread, RngPtr, index, Node* ) const
137   {
138     return value_;
139   }
140 
141   long
value_int(thread,RngPtr,index,Node *)142   value_int( thread, RngPtr, index, Node* ) const
143   {
144     throw KernelException( "ConnParameter calls value function with false return type." );
145   }
146 
147   inline bool
is_array()148   is_array() const
149   {
150     return false;
151   }
152 
153   void
reset()154   reset() const
155   {
156   }
157 
158   bool
is_scalar()159   is_scalar() const
160   {
161     return true;
162   }
163 
164 private:
165   double value_;
166 };
167 
168 /**
169  * Single integer value.
170  *
171  * On each request, it returns the same value.
172  */
173 class ScalarIntegerParameter : public ConnParameter
174 {
175 public:
ScalarIntegerParameter(long value,const size_t)176   ScalarIntegerParameter( long value, const size_t )
177     : value_( value )
178   {
179   }
180 
181   double
value_double(thread,RngPtr,index,Node *)182   value_double( thread, RngPtr, index, Node* ) const
183   {
184     return static_cast< double >( value_ );
185   }
186 
187   long
value_int(thread,RngPtr,index,Node *)188   value_int( thread, RngPtr, index, Node* ) const
189   {
190     return value_;
191   }
192 
193   inline bool
is_array()194   is_array() const
195   {
196     return false;
197   }
198 
199   void
reset()200   reset() const
201   {
202   }
203 
204   bool
is_scalar()205   is_scalar() const
206   {
207     return true;
208   }
209 
210   bool
provides_long()211   provides_long() const
212   {
213     return true;
214   }
215 
216 private:
217   long value_;
218 };
219 
220 
221 /**
222  * Array parameter classes, returning double values in order.
223  *
224  * - The array of values must not be empty
225  *   (so return 0 for number_of_values can signal non-array parameter)
226  * - Throws exception if more values requested than available.
227  * - The class contains nthread number of pointers (one for each thread)
228  *   to an iterator, which runs over the parameters initialised in an array.
229  *   Each pointer is moved along the parameter array by the function
230  *   value_double(), which returns the current parameter value and moves the
231  *   pointer to the subsequent position.
232  * - All parameters are  doubles, thus calling the function value_int()
233  *   throws an error.
234  */
235 
236 class ArrayDoubleParameter : public ConnParameter
237 {
238 public:
ArrayDoubleParameter(const std::vector<double> & values,const size_t nthreads)239   ArrayDoubleParameter( const std::vector< double >& values, const size_t nthreads )
240     : values_( &values )
241     , next_( nthreads, values_->begin() )
242   {
243   }
244 
245   void
skip(thread tid,size_t n_skip)246   skip( thread tid, size_t n_skip ) const
247   {
248     if ( next_[ tid ] < values_->end() )
249     {
250       next_[ tid ] += n_skip;
251     }
252     else
253     {
254       throw KernelException( "Parameter values exhausted." );
255     }
256   }
257 
258   size_t
number_of_values()259   number_of_values() const
260   {
261     return values_->size();
262   }
263 
264   double
value_double(thread tid,RngPtr,index,Node *)265   value_double( thread tid, RngPtr, index, Node* ) const
266   {
267     if ( next_[ tid ] != values_->end() )
268     {
269       return *next_[ tid ]++;
270     }
271     else
272     {
273       throw KernelException( "Parameter values exhausted." );
274     }
275   }
276 
277   long
value_int(thread,RngPtr,index,Node *)278   value_int( thread, RngPtr, index, Node* ) const
279   {
280     throw KernelException( "ConnParameter calls value function with false return type." );
281   }
282 
283   inline bool
is_array()284   is_array() const
285   {
286     return true;
287   }
288 
289   void
reset()290   reset() const
291   {
292     for ( std::vector< std::vector< double >::const_iterator >::iterator it = next_.begin(); it != next_.end(); ++it )
293     {
294       *it = values_->begin();
295     }
296   }
297 
298 private:
299   const std::vector< double >* values_;
300   mutable std::vector< std::vector< double >::const_iterator > next_;
301 };
302 
303 /**
304  * Array parameter classes, returning integer values in order.
305  *
306  * - The array of values must not be empty
307  *   (so return 0 for number_of_values can signal non-array parameter)
308  * - Throws exception if more values requested than available.
309  * - The class contains nthread number of pointers (one for each thread)
310  *   to an iterator, which runs over the parameters initialised in an array.
311  *   Each pointer is moved along the parameter array by the function
312  *   value_int(), which returns the current parameter value and moves the
313  *   pointer to the subsequent position.
314  * - All parameters are integer, thus calling the function value_double()
315  *   throws an error.
316  */
317 
318 class ArrayIntegerParameter : public ConnParameter
319 {
320 public:
ArrayIntegerParameter(const std::vector<long> & values,const size_t nthreads)321   ArrayIntegerParameter( const std::vector< long >& values, const size_t nthreads )
322     : values_( &values )
323     , next_( nthreads, values_->begin() )
324   {
325   }
326 
327   void
skip(thread tid,size_t n_skip)328   skip( thread tid, size_t n_skip ) const
329   {
330     if ( next_[ tid ] < values_->end() )
331     {
332       next_[ tid ] += n_skip;
333     }
334     else
335     {
336       throw KernelException( "Parameter values exhausted." );
337     }
338   }
339 
340   size_t
number_of_values()341   number_of_values() const
342   {
343     return values_->size();
344   }
345 
346   long
value_int(thread tid,RngPtr,index,Node *)347   value_int( thread tid, RngPtr, index, Node* ) const
348   {
349     if ( next_[ tid ] != values_->end() )
350     {
351       return *next_[ tid ]++;
352     }
353     else
354     {
355       throw KernelException( "Parameter values exhausted." );
356     }
357   }
358 
359   double
value_double(thread tid,RngPtr,index,Node *)360   value_double( thread tid, RngPtr, index, Node* ) const
361   {
362     if ( next_[ tid ] != values_->end() )
363     {
364       return static_cast< double >( *next_[ tid ]++ );
365     }
366     else
367     {
368       throw KernelException( "Parameter values exhausted." );
369     }
370   }
371 
372   inline bool
is_array()373   is_array() const
374   {
375     return true;
376   }
377 
378   bool
provides_long()379   provides_long() const
380   {
381     return true;
382   }
383 
384   void
reset()385   reset() const
386   {
387     for ( std::vector< std::vector< long >::const_iterator >::iterator it = next_.begin(); it != next_.end(); ++it )
388     {
389       *it = values_->begin();
390     }
391   }
392 
393 private:
394   const std::vector< long >* values_;
395   mutable std::vector< std::vector< long >::const_iterator > next_;
396 };
397 
398 class ParameterConnParameterWrapper : public ConnParameter
399 {
400 public:
401   ParameterConnParameterWrapper( const ParameterDatum&, const size_t );
402 
403   double value_double( thread target_thread, RngPtr rng, index snode_id, Node* target ) const;
404 
405   long
value_int(thread target_thread,RngPtr rng,index snode_id,Node * target)406   value_int( thread target_thread, RngPtr rng, index snode_id, Node* target ) const
407   {
408     return value_double( target_thread, rng, snode_id, target );
409   }
410 
411   inline bool
is_array()412   is_array() const
413   {
414     return false;
415   }
416 
417   bool
provides_long()418   provides_long() const
419   {
420     return parameter_->returns_int_only();
421   }
422 
423 private:
424   Parameter* parameter_;
425 };
426 
427 } // namespace nest
428 
429 #endif
430