1 /*
2  *  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 PARAMETER_H_
24 #define PARAMETER_H_
25 
26 // C++ includes:
27 #include <limits>
28 #include <cmath>
29 
30 // Includes from nestkernel:
31 #include "nest_names.h"
32 #include "nest_types.h"
33 #include "nestmodule.h"
34 #include "node_collection.h"
35 #include "random_generators.h"
36 
37 // Includes from libnestutil:
38 #include "dictutils.h"
39 
40 namespace nest
41 {
42 
43 class AbstractLayer;
44 
45 /**
46  * Abstract base class for parameters.
47  */
48 class Parameter
49 {
50 public:
51   /**
52    * Creates a Parameter, with optionally specified attributes.
53    * @param is_spatial true if the Parameter contains spatial elements
54    * @param returns_int_only true if the value of the parameter can only be an integer
55    */
56   Parameter( bool is_spatial = false, bool returns_int_only = false )
is_spatial_(is_spatial)57     : is_spatial_( is_spatial )
58     , returns_int_only_( returns_int_only )
59   {
60   }
61 
62   /**
63    * Copy constructor
64    */
65   Parameter( const Parameter& p ) = default;
66 
67   /**
68    * Virtual destructor
69    */
70   virtual ~Parameter() = default;
71 
72   /**
73    * Generates a value based on parameter specifications and arguments.
74    * Used when getting a parameter value based on random values or node attributes,
75    * like position. Note that not all parameters support all overloaded versions.
76    * @param rng pointer to the random number generator
77    * @param node pointer to the node, used when the node position is relevant
78    * @returns the value of the parameter.
79    */
80   virtual double value( RngPtr rng, Node* node ) = 0;
81 
82   /**
83    * Generates a value based on parameter specifications and arguments.
84    * Used when connecting spatial nodes. Note that not all parameters
85    * support all overloaded versions.
86    * @param rng pointer to the random number generator
87    * @param source_pos position of the source node
88    * @param target_pos position of the target node
89    * @param layer spatial layer
90    * @param node target node, required for normal and lognormal parameters
91    * @returns the value of the parameter.
92    */
93   virtual double value( RngPtr rng,
94     const std::vector< double >& source_pos,
95     const std::vector< double >& target_pos,
96     const AbstractLayer& layer,
97     Node* node );
98 
99   /**
100    * Applies a parameter on a single-node ID NodeCollection and given array of positions.
101    * @returns array of result values, one per position in the TokenArray.
102    */
103   std::vector< double > apply( const NodeCollectionPTR&, const TokenArray& );
104 
105   /**
106    * Check if the Parameter is based on spatial properties.
107    * @returns true if the Parameter is based on spatial properties, false otherwise.
108    */
109   bool is_spatial() const;
110 
111   /**
112    * Check if the Parameter only returns integer values.
113    * @returns true if the Parameter only returns integers, false otherwise.
114    */
115   bool returns_int_only() const;
116 
117 protected:
118   bool is_spatial_{ false };
119   bool returns_int_only_{ false };
120 
121   bool value_is_integer_( const double value ) const;
122 };
123 
124 /**
125  * Parameter with constant value.
126  */
127 class ConstantParameter : public Parameter
128 {
129 public:
130   using Parameter::value;
131 
132   /**
133    * Creates a ConstantParameter with a specified value.
134    * @param value parameter value
135    */
ConstantParameter(double value)136   ConstantParameter( double value )
137     : value_( value )
138   {
139   }
140 
141   /**
142    * Creates a ConstantParameter with the value specified in a dictionary.
143    * @param d dictionary with the parameter value
144    *
145    * The dictionary must include the following entry:
146    * value - constant value of this parameter
147    */
ConstantParameter(const DictionaryDatum & d)148   ConstantParameter( const DictionaryDatum& d )
149   {
150     value_ = getValue< double >( d, "value" );
151     returns_int_only_ = value_is_integer_( value_ );
152   }
153 
154   ~ConstantParameter() override = default;
155 
156   /**
157    * @returns the constant value of this parameter.
158    */
159   double
value(RngPtr,Node *)160   value( RngPtr, Node* ) override
161   {
162     return value_;
163   }
164 
165 private:
166   double value_;
167 };
168 
169 
170 /**
171  * Random parameter with uniform distribution in [min,max).
172  */
173 class UniformParameter : public Parameter
174 {
175 public:
176   using Parameter::value;
177 
178   /**
179    * Creates a UniformParameter with specifications specified in a dictionary.
180    * @param d dictionary with parameter specifications
181    *
182    * The dictionary can include the following entries:
183    * min - minimum value
184    * max - maximum value
185    */
UniformParameter(const DictionaryDatum & d)186   UniformParameter( const DictionaryDatum& d )
187     : lower_( 0.0 )
188     , range_( 1.0 )
189   {
190     updateValue< double >( d, names::min, lower_ );
191     updateValue< double >( d, names::max, range_ );
192     if ( lower_ >= range_ )
193     {
194       throw BadProperty(
195         "nest::UniformParameter: "
196         "min < max required." );
197     }
198 
199     range_ -= lower_;
200   }
201 
202   double
value(RngPtr rng,Node *)203   value( RngPtr rng, Node* ) override
204   {
205     return lower_ + rng->drand() * range_;
206   }
207 
208 private:
209   double lower_, range_;
210 };
211 
212 /**
213  * Random parameter with uniform distribution in [0,max), yielding integer values.
214  */
215 class UniformIntParameter : public Parameter
216 {
217 public:
218   using Parameter::value;
219 
220   /**
221    * Creates a UniformIntParameter with specifications specified in a dictionary.
222    * @param d dictionary with parameter specifications
223    *
224    * The dictionary can include the following entries:
225    * max - maximum value
226    */
UniformIntParameter(const DictionaryDatum & d)227   UniformIntParameter( const DictionaryDatum& d )
228     : Parameter( false, true )
229     , max_( 1.0 )
230   {
231     updateValue< long >( d, names::max, max_ );
232     if ( max_ <= 0 )
233     {
234       throw BadProperty( "nest::UniformIntParameter: max > 0 required." );
235     }
236   }
237 
238   double
value(RngPtr rng,Node *)239   value( RngPtr rng, Node* ) override
240   {
241     return rng->ulrand( max_ );
242   }
243 
244 private:
245   double max_;
246 };
247 
248 
249 /**
250  * Random parameter with normal distribution.
251  */
252 class NormalParameter : public Parameter
253 {
254 public:
255   using Parameter::value;
256 
257   /**
258    * Creates a NormalParameter with specifications specified in a dictionary.
259    * @param d dictionary with parameter specifications
260    *
261    * The dictionary can include the following entries:
262    * mean - mean value
263    * std - standard deviation
264    */
265   NormalParameter( const DictionaryDatum& d );
266 
267   double value( RngPtr rng, Node* node ) override;
268 
269 private:
270   double mean_, std_;
271   std::vector< normal_distribution > normal_dists_;
272 };
273 
274 
275 /**
276  * Random parameter with lognormal distribution.
277  */
278 class LognormalParameter : public Parameter
279 {
280 public:
281   using Parameter::value;
282 
283   /**
284    * Creates a LognormalParameter with specifications specified in a dictionary.
285    * @param d dictionary with parameter specifications
286    *
287    * The dictionary can include the following entries:
288    * mean - mean value of logarithm
289    * sigma - standard distribution of logarithm
290    */
291   LognormalParameter( const DictionaryDatum& d );
292 
293   double value( RngPtr rng, Node* node ) override;
294 
295 private:
296   double mean_, std_;
297   std::vector< lognormal_distribution > lognormal_dists_;
298 };
299 
300 
301 /**
302  * Random parameter with exponential distribution.
303  */
304 class ExponentialParameter : public Parameter
305 {
306 public:
307   using Parameter::value;
308 
309   /**
310    * Creates a ExponentialParameter with specifications specified in a dictionary.
311    * @param d dictionary with parameter specifications
312    *
313    * The dictionary can include the following entries:
314    * beta - the scale parameter
315    */
ExponentialParameter(const DictionaryDatum & d)316   ExponentialParameter( const DictionaryDatum& d )
317     : beta_( 1.0 )
318   {
319     updateValue< double >( d, names::beta, beta_ );
320   }
321 
322   double
value(RngPtr rng,Node *)323   value( RngPtr rng, Node* ) override
324   {
325     return beta_ * ( -std::log( 1 - rng->drand() ) );
326   }
327 
328 private:
329   double beta_;
330 };
331 
332 
333 /**
334  * Node position parameter.
335  */
336 class NodePosParameter : public Parameter
337 {
338 public:
339   /**
340    * Creates a NodePosParameter with specifications specified in a dictionary.
341    * @param d dictionary with parameter specifications
342    *
343    * The dictionary can include the following entries:
344    * dimension - Dimension from which to get the position value of the node.
345    *             0: x, 1: y, 2: z.
346    * synaptic_endpoint - If specified, specifies if the position should be taken
347    *                     from the presynaptic or postsynaptic node in a connection.
348    *                     0: unspecified, 1: presynaptic, 2: postsynaptic.
349    */
NodePosParameter(const DictionaryDatum & d)350   NodePosParameter( const DictionaryDatum& d )
351     : Parameter( true )
352     , dimension_( 0 )
353     , synaptic_endpoint_( 0 )
354   {
355     bool dimension_specified = updateValue< long >( d, names::dimension, dimension_ );
356     if ( not dimension_specified )
357     {
358       throw BadParameterValue( "Dimension must be specified when creating a node position parameter." );
359     }
360     if ( dimension_ < 0 )
361     {
362       throw BadParameterValue( "Node position parameter dimension cannot be negative." );
363     }
364     updateValue< long >( d, names::synaptic_endpoint, synaptic_endpoint_ );
365     if ( synaptic_endpoint_ < 0 or 2 < synaptic_endpoint_ )
366     {
367       throw BadParameterValue( "Synaptic endpoint must either be unspecified (0), source (1) or target (2)." );
368     }
369   }
370 
371   double
value(RngPtr,Node * node)372   value( RngPtr, Node* node ) override
373   {
374     if ( synaptic_endpoint_ != 0 )
375     {
376       throw BadParameterValue( "Source or target position parameter can only be used when connecting." );
377     }
378     if ( node == nullptr )
379     {
380       throw KernelException( "Node position parameter can only be used when connecting spatially distributed nodes." );
381     }
382     return get_node_pos_( node );
383   }
384 
385   double
value(RngPtr,const std::vector<double> & source_pos,const std::vector<double> & target_pos,const AbstractLayer &,Node *)386   value( RngPtr,
387     const std::vector< double >& source_pos,
388     const std::vector< double >& target_pos,
389     const AbstractLayer&,
390     Node* ) override
391   {
392     switch ( synaptic_endpoint_ )
393     {
394     case 0:
395       throw BadParameterValue( "Node position parameter cannot be used when connecting." );
396     case 1:
397     {
398       return source_pos[ dimension_ ];
399     }
400     case 2:
401       return target_pos[ dimension_ ];
402     }
403     throw KernelException( "Wrong synaptic_endpoint_." );
404   }
405 
406 private:
407   int dimension_;
408   int synaptic_endpoint_;
409 
410   double get_node_pos_( Node* node ) const;
411 };
412 
413 
414 /**
415  * Parameter representing the spatial distance between two nodes, optionally in a specific dimension.
416  */
417 class SpatialDistanceParameter : public Parameter
418 {
419 public:
SpatialDistanceParameter(const DictionaryDatum & d)420   SpatialDistanceParameter( const DictionaryDatum& d )
421     : Parameter( true )
422     , dimension_( 0 )
423   {
424     updateValue< long >( d, names::dimension, dimension_ );
425     if ( dimension_ < 0 )
426     {
427       throw BadParameterValue( "Spatial distance parameter dimension cannot be negative." );
428     }
429   }
430 
431   double
value(RngPtr,Node *)432   value( RngPtr, Node* ) override
433   {
434     throw BadParameterValue( "Spatial distance parameter can only be used when connecting." );
435   }
436 
437   double value( RngPtr rng,
438     const std::vector< double >& source_pos,
439     const std::vector< double >& target_pos,
440     const AbstractLayer& layer,
441     Node* ) override;
442 
443 private:
444   int dimension_;
445 };
446 
447 
448 /**
449  * Parameter class representing the product of two parameters.
450  */
451 class ProductParameter : public Parameter
452 {
453 public:
454   /**
455    * Construct the product of the two given parameters. Copies are made
456    * of the supplied Parameter objects.
457    */
ProductParameter(const std::shared_ptr<Parameter> m1,const std::shared_ptr<Parameter> m2)458   ProductParameter( const std::shared_ptr< Parameter > m1, const std::shared_ptr< Parameter > m2 )
459     : Parameter( m1->is_spatial() or m2->is_spatial(), m1->returns_int_only() and m2->returns_int_only() )
460     , parameter1_( m1 )
461     , parameter2_( m2 )
462   {
463   }
464 
465   /**
466    * Copy constructor.
467    */
ProductParameter(const ProductParameter & p)468   ProductParameter( const ProductParameter& p )
469     : Parameter( p )
470     , parameter1_( p.parameter1_ )
471     , parameter2_( p.parameter2_ )
472   {
473   }
474 
475   /**
476    * @returns the value of the product.
477    */
478   double
value(RngPtr rng,Node * node)479   value( RngPtr rng, Node* node ) override
480   {
481     return parameter1_->value( rng, node ) * parameter2_->value( rng, node );
482   }
483 
484   double
value(RngPtr rng,const std::vector<double> & source_pos,const std::vector<double> & target_pos,const AbstractLayer & layer,Node * node)485   value( RngPtr rng,
486     const std::vector< double >& source_pos,
487     const std::vector< double >& target_pos,
488     const AbstractLayer& layer,
489     Node* node ) override
490   {
491     return parameter1_->value( rng, source_pos, target_pos, layer, node )
492       * parameter2_->value( rng, source_pos, target_pos, layer, node );
493   }
494 
495 protected:
496   std::shared_ptr< Parameter > const parameter1_;
497   std::shared_ptr< Parameter > const parameter2_;
498 };
499 
500 /**
501  * Parameter class representing the quotient of two parameters.
502  */
503 class QuotientParameter : public Parameter
504 {
505 public:
506   /**
507    * Construct the quotient of two given parameters. Copies are made
508    * of the supplied Parameter objects.
509    */
QuotientParameter(std::shared_ptr<Parameter> m1,std::shared_ptr<Parameter> m2)510   QuotientParameter( std::shared_ptr< Parameter > m1, std::shared_ptr< Parameter > m2 )
511     : Parameter( m1->is_spatial() or m2->is_spatial(), m1->returns_int_only() and m2->returns_int_only() )
512     , parameter1_( m1 )
513     , parameter2_( m2 )
514   {
515   }
516 
517   /**
518    * Copy constructor.
519    */
QuotientParameter(const QuotientParameter & p)520   QuotientParameter( const QuotientParameter& p )
521     : Parameter( p )
522     , parameter1_( p.parameter1_ )
523     , parameter2_( p.parameter2_ )
524   {
525   }
526 
527   /**
528    * @returns the value of the product.
529    */
530   double
value(RngPtr rng,Node * node)531   value( RngPtr rng, Node* node ) override
532   {
533     return parameter1_->value( rng, node ) / parameter2_->value( rng, node );
534   }
535 
536   double
value(RngPtr rng,const std::vector<double> & source_pos,const std::vector<double> & target_pos,const AbstractLayer & layer,Node * node)537   value( RngPtr rng,
538     const std::vector< double >& source_pos,
539     const std::vector< double >& target_pos,
540     const AbstractLayer& layer,
541     Node* node ) override
542   {
543     return parameter1_->value( rng, source_pos, target_pos, layer, node )
544       / parameter2_->value( rng, source_pos, target_pos, layer, node );
545   }
546 
547 protected:
548   std::shared_ptr< Parameter > const parameter1_;
549   std::shared_ptr< Parameter > const parameter2_;
550 };
551 
552 /**
553  * Parameter class representing the sum of two parameters
554  */
555 class SumParameter : public Parameter
556 {
557 public:
558   /**
559    * Construct the sum of two given parameters. Copies are made
560    * of the supplied Parameter objects.
561    */
SumParameter(std::shared_ptr<Parameter> m1,std::shared_ptr<Parameter> m2)562   SumParameter( std::shared_ptr< Parameter > m1, std::shared_ptr< Parameter > m2 )
563     : Parameter( m1->is_spatial() or m2->is_spatial(), m1->returns_int_only() and m2->returns_int_only() )
564     , parameter1_( m1 )
565     , parameter2_( m2 )
566   {
567   }
568 
569   /**
570    * Copy constructor.
571    */
SumParameter(const SumParameter & p)572   SumParameter( const SumParameter& p )
573     : Parameter( p )
574     , parameter1_( p.parameter1_ )
575     , parameter2_( p.parameter2_ )
576   {
577   }
578 
579   /**
580    * @returns the value of the sum.
581    */
582   double
value(RngPtr rng,Node * node)583   value( RngPtr rng, Node* node ) override
584   {
585     return parameter1_->value( rng, node ) + parameter2_->value( rng, node );
586   }
587 
588   double
value(RngPtr rng,const std::vector<double> & source_pos,const std::vector<double> & target_pos,const AbstractLayer & layer,Node * node)589   value( RngPtr rng,
590     const std::vector< double >& source_pos,
591     const std::vector< double >& target_pos,
592     const AbstractLayer& layer,
593     Node* node ) override
594   {
595     return parameter1_->value( rng, source_pos, target_pos, layer, node )
596       + parameter2_->value( rng, source_pos, target_pos, layer, node );
597   }
598 
599 protected:
600   std::shared_ptr< Parameter > const parameter1_;
601   std::shared_ptr< Parameter > const parameter2_;
602 };
603 
604 /**
605  * Parameter class representing the difference of two parameters
606  */
607 class DifferenceParameter : public Parameter
608 {
609 public:
610   /**
611    * Construct the difference of two given parameters. Copies are made
612    * of the supplied Parameter objects.
613    */
DifferenceParameter(std::shared_ptr<Parameter> m1,std::shared_ptr<Parameter> m2)614   DifferenceParameter( std::shared_ptr< Parameter > m1, std::shared_ptr< Parameter > m2 )
615     : Parameter( m1->is_spatial() or m2->is_spatial(), m1->returns_int_only() and m2->returns_int_only() )
616     , parameter1_( m1 )
617     , parameter2_( m2 )
618   {
619   }
620 
621   /**
622    * Copy constructor.
623    */
DifferenceParameter(const DifferenceParameter & p)624   DifferenceParameter( const DifferenceParameter& p )
625     : Parameter( p )
626     , parameter1_( p.parameter1_ )
627     , parameter2_( p.parameter2_ )
628   {
629   }
630 
631   /**
632    * @returns the value of the difference.
633    */
634   double
value(RngPtr rng,Node * node)635   value( RngPtr rng, Node* node ) override
636   {
637     return parameter1_->value( rng, node ) - parameter2_->value( rng, node );
638   }
639 
640   double
value(RngPtr rng,const std::vector<double> & source_pos,const std::vector<double> & target_pos,const AbstractLayer & layer,Node * node)641   value( RngPtr rng,
642     const std::vector< double >& source_pos,
643     const std::vector< double >& target_pos,
644     const AbstractLayer& layer,
645     Node* node ) override
646   {
647     return parameter1_->value( rng, source_pos, target_pos, layer, node )
648       - parameter2_->value( rng, source_pos, target_pos, layer, node );
649   }
650 
651 protected:
652   std::shared_ptr< Parameter > const parameter1_;
653   std::shared_ptr< Parameter > const parameter2_;
654 };
655 
656 /**
657  * Parameter class representing the comparison of two parameters.
658  */
659 class ComparingParameter : public Parameter
660 {
661 public:
662   /**
663    * Construct the comparison of the two given parameters. Copies are made
664    * of the supplied Parameter objects.
665    *
666    * comparator - Operator to use as a comparator.
667    *              0: <
668    *              2: <=
669    *              4: ==
670    *              5: !=
671    *              3: >=
672    *              1: >
673    *
674    */
ComparingParameter(std::shared_ptr<Parameter> m1,std::shared_ptr<Parameter> m2,const DictionaryDatum & d)675   ComparingParameter( std::shared_ptr< Parameter > m1, std::shared_ptr< Parameter > m2, const DictionaryDatum& d )
676     : Parameter( m1->is_spatial() or m2->is_spatial(), true )
677     , parameter1_( m1 )
678     , parameter2_( m2 )
679     , comparator_( -1 )
680   {
681     if ( not updateValue< long >( d, names::comparator, comparator_ ) )
682     {
683       throw BadParameter( "A comparator has to be specified." );
684     }
685     if ( comparator_ < 0 or 5 < comparator_ )
686     {
687       throw BadParameter( "Comparator specification has to be in the range 0-5." );
688     }
689   }
690 
691   /**
692    * Copy constructor.
693    */
ComparingParameter(const ComparingParameter & p)694   ComparingParameter( const ComparingParameter& p )
695     : Parameter( p )
696     , parameter1_( p.parameter1_ )
697     , parameter2_( p.parameter2_ )
698     , comparator_( p.comparator_ )
699   {
700   }
701 
702   /**
703    * @returns the result of the comparison, bool given as a double.
704    */
705   double
value(RngPtr rng,Node * node)706   value( RngPtr rng, Node* node ) override
707   {
708     return compare_( parameter1_->value( rng, node ), parameter2_->value( rng, node ) );
709   }
710 
711   double
value(RngPtr rng,const std::vector<double> & source_pos,const std::vector<double> & target_pos,const AbstractLayer & layer,Node * node)712   value( RngPtr rng,
713     const std::vector< double >& source_pos,
714     const std::vector< double >& target_pos,
715     const AbstractLayer& layer,
716     Node* node ) override
717   {
718     return compare_( parameter1_->value( rng, source_pos, target_pos, layer, node ),
719       parameter2_->value( rng, source_pos, target_pos, layer, node ) );
720   }
721 
722 protected:
723   std::shared_ptr< Parameter > const parameter1_;
724   std::shared_ptr< Parameter > const parameter2_;
725 
726 private:
727   bool
compare_(double value_a,double value_b)728   compare_( double value_a, double value_b ) const
729   {
730     switch ( comparator_ )
731     {
732     case 0:
733       return value_a < value_b;
734     case 1:
735       return value_a <= value_b;
736     case 2:
737       return value_a == value_b;
738     case 3:
739       return value_a != value_b;
740     case 4:
741       return value_a >= value_b;
742     case 5:
743       return value_a > value_b;
744     }
745     throw KernelException( "Wrong comparison operator." );
746   }
747 
748   int comparator_;
749 };
750 
751 
752 /**
753  * Parameter class choosing a value based on a comparing parameter.
754  */
755 class ConditionalParameter : public Parameter
756 {
757 public:
758   /**
759    * Construct the choice of two given parameters, based on a third.
760    * Copies are made of the supplied Parameter objects.
761    */
ConditionalParameter(std::shared_ptr<Parameter> condition,std::shared_ptr<Parameter> if_true,std::shared_ptr<Parameter> if_false)762   ConditionalParameter( std::shared_ptr< Parameter > condition,
763     std::shared_ptr< Parameter > if_true,
764     std::shared_ptr< Parameter > if_false )
765     : Parameter( condition->is_spatial() or if_true->is_spatial() or if_false->is_spatial(),
766         if_true->returns_int_only() and if_false->returns_int_only() )
767     , condition_( condition )
768     , if_true_( if_true )
769     , if_false_( if_false )
770   {
771   }
772 
773   /**
774    * Copy constructor.
775    */
ConditionalParameter(const ConditionalParameter & p)776   ConditionalParameter( const ConditionalParameter& p )
777     : Parameter( p )
778     , condition_( p.condition_ )
779     , if_true_( p.if_true_ )
780     , if_false_( p.if_false_ )
781   {
782   }
783 
784   /**
785    * @returns the value chosen by the comparison.
786    */
787   double
value(RngPtr rng,Node * node)788   value( RngPtr rng, Node* node ) override
789   {
790     if ( condition_->value( rng, node ) )
791     {
792       return if_true_->value( rng, node );
793     }
794     else
795     {
796       return if_false_->value( rng, node );
797     }
798   }
799 
800   double
value(RngPtr rng,const std::vector<double> & source_pos,const std::vector<double> & target_pos,const AbstractLayer & layer,Node * node)801   value( RngPtr rng,
802     const std::vector< double >& source_pos,
803     const std::vector< double >& target_pos,
804     const AbstractLayer& layer,
805     Node* node ) override
806   {
807     if ( condition_->value( rng, source_pos, target_pos, layer, node ) )
808     {
809       return if_true_->value( rng, source_pos, target_pos, layer, node );
810     }
811     else
812     {
813       return if_false_->value( rng, source_pos, target_pos, layer, node );
814     }
815   }
816 
817 protected:
818   std::shared_ptr< Parameter > const condition_;
819   std::shared_ptr< Parameter > const if_true_;
820   std::shared_ptr< Parameter > const if_false_;
821 };
822 
823 
824 /**
825  * Parameter class representing the minimum of a parameter's value and a given value.
826  */
827 class MinParameter : public Parameter
828 {
829 public:
830   /**
831    * Construct a min parameter. A copy is made of the supplied Parameter
832    * object.
833    */
MinParameter(std::shared_ptr<Parameter> p,const double other_value)834   MinParameter( std::shared_ptr< Parameter > p, const double other_value )
835     : Parameter( p->is_spatial(), p->returns_int_only() and value_is_integer_( other_value ) )
836     , p_( p )
837     , other_value_( other_value )
838   {
839     assert( is_spatial_ == p->is_spatial() );
840   }
841 
842   /**
843    * Copy constructor.
844    */
MinParameter(const MinParameter & p)845   MinParameter( const MinParameter& p )
846     : Parameter( p )
847     , p_( p.p_ )
848     , other_value_( p.other_value_ )
849   {
850   }
851 
852   /**
853    * @returns the value of the parameter.
854    */
855   double
value(RngPtr rng,Node * node)856   value( RngPtr rng, Node* node ) override
857   {
858     return std::min( p_->value( rng, node ), other_value_ );
859   }
860 
861   double
value(RngPtr rng,const std::vector<double> & source_pos,const std::vector<double> & target_pos,const AbstractLayer & layer,Node * node)862   value( RngPtr rng,
863     const std::vector< double >& source_pos,
864     const std::vector< double >& target_pos,
865     const AbstractLayer& layer,
866     Node* node ) override
867   {
868     return std::min( p_->value( rng, source_pos, target_pos, layer, node ), other_value_ );
869   }
870 
871 protected:
872   std::shared_ptr< Parameter > const p_;
873   double other_value_;
874 };
875 
876 
877 /**
878  * Parameter class representing the maximum of a parameter's value and a given value.
879  */
880 class MaxParameter : public Parameter
881 {
882 public:
883   /**
884    * Construct a max parameter. A copy is made of the supplied Parameter
885    * object.
886    */
MaxParameter(std::shared_ptr<Parameter> p,const double other_value)887   MaxParameter( std::shared_ptr< Parameter > p, const double other_value )
888     : Parameter( p->is_spatial(), p->returns_int_only() and value_is_integer_( other_value ) )
889     , p_( p )
890     , other_value_( other_value )
891   {
892   }
893 
894   /**
895    * Copy constructor.
896    */
MaxParameter(const MaxParameter & p)897   MaxParameter( const MaxParameter& p )
898     : Parameter( p )
899     , p_( p.p_ )
900     , other_value_( p.other_value_ )
901   {
902   }
903 
904   /**
905    * @returns the value of the parameter.
906    */
907   double
value(RngPtr rng,Node * node)908   value( RngPtr rng, Node* node ) override
909   {
910     return std::max( p_->value( rng, node ), other_value_ );
911   }
912 
913   double
value(RngPtr rng,const std::vector<double> & source_pos,const std::vector<double> & target_pos,const AbstractLayer & layer,Node * node)914   value( RngPtr rng,
915     const std::vector< double >& source_pos,
916     const std::vector< double >& target_pos,
917     const AbstractLayer& layer,
918     Node* node ) override
919   {
920     return std::max( p_->value( rng, source_pos, target_pos, layer, node ), other_value_ );
921   }
922 
923 protected:
924   std::shared_ptr< Parameter > const p_;
925   double other_value_;
926 };
927 
928 
929 /**
930  * Parameter class redrawing a parameter value if it is outside of specified limits.
931  */
932 class RedrawParameter : public Parameter
933 {
934 public:
935   /**
936    * Construct a redrawing parameter. A copy is made of the supplied Parameter
937    * object.
938    */
939   RedrawParameter( std::shared_ptr< Parameter > p, const double min, const double max );
940 
941   /**
942    * Copy constructor.
943    */
RedrawParameter(const RedrawParameter & p)944   RedrawParameter( const RedrawParameter& p )
945     : Parameter( p )
946     , p_( p.p_ )
947     , min_( p.min_ )
948     , max_( p.max_ )
949     , max_redraws_( p.max_redraws_ )
950   {
951   }
952 
953   /**
954    * @returns the value of the parameter.
955    */
956   double value( RngPtr rng, Node* node ) override;
957   double value( RngPtr rng,
958     const std::vector< double >& source_pos,
959     const std::vector< double >& target_pos,
960     const AbstractLayer& layer,
961     Node* node ) override;
962 
963 protected:
964   std::shared_ptr< Parameter > const p_;
965   double min_;
966   double max_;
967   const size_t max_redraws_;
968 };
969 
970 
971 /**
972  * Parameter class representing the exponential of a parameter.
973  */
974 class ExpParameter : public Parameter
975 {
976 public:
977   /**
978    * Construct the exponential of the given parameter. A copy is made of the
979    * supplied Parameter object.
980    */
ExpParameter(std::shared_ptr<Parameter> p)981   ExpParameter( std::shared_ptr< Parameter > p )
982     : Parameter( p->is_spatial() )
983     , p_( p )
984   {
985   }
986 
987   /**
988    * Copy constructor.
989    */
ExpParameter(const ExpParameter & p)990   ExpParameter( const ExpParameter& p )
991     : Parameter( p )
992     , p_( p.p_ )
993   {
994   }
995 
996   /**
997    * @returns the value of the parameter.
998    */
999   double
value(RngPtr rng,Node * node)1000   value( RngPtr rng, Node* node ) override
1001   {
1002     return std::exp( p_->value( rng, node ) );
1003   }
1004 
1005   double
value(RngPtr rng,const std::vector<double> & source_pos,const std::vector<double> & target_pos,const AbstractLayer & layer,Node * node)1006   value( RngPtr rng,
1007     const std::vector< double >& source_pos,
1008     const std::vector< double >& target_pos,
1009     const AbstractLayer& layer,
1010     Node* node ) override
1011   {
1012     return std::exp( p_->value( rng, source_pos, target_pos, layer, node ) );
1013   }
1014 
1015 protected:
1016   std::shared_ptr< Parameter > const p_;
1017 };
1018 
1019 
1020 /**
1021  * Parameter class representing the sine of a parameter.
1022  */
1023 class SinParameter : public Parameter
1024 {
1025 public:
1026   /**
1027    * Construct the sine of the given parameter. A copy is made of the
1028    * supplied Parameter object.
1029    */
SinParameter(std::shared_ptr<Parameter> p)1030   SinParameter( std::shared_ptr< Parameter > p )
1031     : Parameter( p->is_spatial() )
1032     , p_( p )
1033   {
1034   }
1035 
1036   /**
1037    * Copy constructor.
1038    */
SinParameter(const SinParameter & p)1039   SinParameter( const SinParameter& p )
1040     : Parameter( p )
1041     , p_( p.p_ )
1042   {
1043   }
1044 
1045   /**
1046    * @returns the value of the parameter.
1047    */
1048   double
value(RngPtr rng,Node * node)1049   value( RngPtr rng, Node* node ) override
1050   {
1051     return std::sin( p_->value( rng, node ) );
1052   }
1053 
1054   double
value(RngPtr rng,const std::vector<double> & source_pos,const std::vector<double> & target_pos,const AbstractLayer & layer,Node * node)1055   value( RngPtr rng,
1056     const std::vector< double >& source_pos,
1057     const std::vector< double >& target_pos,
1058     const AbstractLayer& layer,
1059     Node* node ) override
1060   {
1061     return std::sin( p_->value( rng, source_pos, target_pos, layer, node ) );
1062   }
1063 
1064 protected:
1065   std::shared_ptr< Parameter > const p_;
1066 };
1067 
1068 /**
1069  * Parameter class representing the cosine of a parameter.
1070  */
1071 class CosParameter : public Parameter
1072 {
1073 public:
1074   /**
1075    * Construct the exponential of the given parameter. A copy is made of the
1076    * supplied Parameter object.
1077    */
CosParameter(std::shared_ptr<Parameter> p)1078   CosParameter( std::shared_ptr< Parameter > p )
1079     : Parameter( p->is_spatial() )
1080     , p_( p )
1081   {
1082   }
1083 
1084   /**
1085    * Copy constructor.
1086    */
CosParameter(const CosParameter & p)1087   CosParameter( const CosParameter& p )
1088     : Parameter( p )
1089     , p_( p.p_ )
1090   {
1091   }
1092 
1093   /**
1094    * @returns the value of the parameter.
1095    */
1096   double
value(RngPtr rng,Node * node)1097   value( RngPtr rng, Node* node ) override
1098   {
1099     return std::cos( p_->value( rng, node ) );
1100   }
1101 
1102   double
value(RngPtr rng,const std::vector<double> & source_pos,const std::vector<double> & target_pos,const AbstractLayer & layer,Node * node)1103   value( RngPtr rng,
1104     const std::vector< double >& source_pos,
1105     const std::vector< double >& target_pos,
1106     const AbstractLayer& layer,
1107     Node* node ) override
1108   {
1109     return std::cos( p_->value( rng, source_pos, target_pos, layer, node ) );
1110   }
1111 
1112 protected:
1113   std::shared_ptr< Parameter > const p_;
1114 };
1115 
1116 
1117 /**
1118  * Parameter class representing the parameter raised to the power of an
1119  * exponent.
1120  */
1121 class PowParameter : public Parameter
1122 {
1123 public:
1124   /**
1125    * Construct the parameter. A copy is made of the supplied Parameter object.
1126    */
PowParameter(std::shared_ptr<Parameter> p,const double exponent)1127   PowParameter( std::shared_ptr< Parameter > p, const double exponent )
1128     : Parameter( p->is_spatial(), p->returns_int_only() )
1129     , p_( p )
1130     , exponent_( exponent )
1131   {
1132   }
1133 
1134   /**
1135    * Copy constructor.
1136    */
PowParameter(const PowParameter & p)1137   PowParameter( const PowParameter& p )
1138     : Parameter( p )
1139     , p_( p.p_ )
1140     , exponent_( p.exponent_ )
1141   {
1142   }
1143 
1144   /**
1145    * @returns the value of the parameter.
1146    */
1147   double
value(RngPtr rng,Node * node)1148   value( RngPtr rng, Node* node ) override
1149   {
1150     return std::pow( p_->value( rng, node ), exponent_ );
1151   }
1152 
1153   double
value(RngPtr rng,const std::vector<double> & source_pos,const std::vector<double> & target_pos,const AbstractLayer & layer,Node * node)1154   value( RngPtr rng,
1155     const std::vector< double >& source_pos,
1156     const std::vector< double >& target_pos,
1157     const AbstractLayer& layer,
1158     Node* node ) override
1159   {
1160     return std::pow( p_->value( rng, source_pos, target_pos, layer, node ), exponent_ );
1161   }
1162 
1163 protected:
1164   std::shared_ptr< Parameter > const p_;
1165   const double exponent_;
1166 };
1167 
1168 
1169 /**
1170  * Position-generating Parameter class. One Parameter per dimension is
1171  * stored. When getting a position vector, a value for each dimension is
1172  * generated from their respective Parameters.
1173  */
1174 class DimensionParameter : public Parameter
1175 {
1176 public:
1177   using Parameter::value;
1178 
1179   /**
1180    * Construct the Parameter with one given Parameter per dimension. A
1181    * copy is made of the supplied Parameter objects.
1182    */
DimensionParameter(std::shared_ptr<Parameter> px,std::shared_ptr<Parameter> py)1183   DimensionParameter( std::shared_ptr< Parameter > px, std::shared_ptr< Parameter > py )
1184     : Parameter( true )
1185     , num_dimensions_( 2 )
1186     , px_( px )
1187     , py_( py )
1188     , pz_( nullptr )
1189   {
1190   }
1191 
DimensionParameter(std::shared_ptr<Parameter> px,std::shared_ptr<Parameter> py,std::shared_ptr<Parameter> pz)1192   DimensionParameter( std::shared_ptr< Parameter > px,
1193     std::shared_ptr< Parameter > py,
1194     std::shared_ptr< Parameter > pz )
1195     : Parameter( true )
1196     , num_dimensions_( 3 )
1197     , px_( px )
1198     , py_( py )
1199     , pz_( pz )
1200   {
1201   }
1202 
1203   /**
1204    * Copy constructor.
1205    */
DimensionParameter(const DimensionParameter & p)1206   DimensionParameter( const DimensionParameter& p )
1207     : Parameter( p )
1208     , num_dimensions_( p.num_dimensions_ )
1209     , px_( p.px_ )
1210     , py_( p.py_ )
1211     , pz_( p.pz_ )
1212   {
1213   }
1214 
1215   /**
1216    * The DimensionParameter has no double value, so this method will always throw.
1217    */
1218   double
value(RngPtr,Node *)1219   value( RngPtr, Node* ) override
1220   {
1221     throw KernelException( "Cannot get value of DimensionParameter." );
1222   }
1223 
1224   /**
1225    * Generates a position with values for each dimension generated from their respective parameters.
1226    * @returns The position, given as an array.
1227    */
1228   std::vector< double >
get_values(RngPtr rng)1229   get_values( RngPtr rng )
1230   {
1231     switch ( num_dimensions_ )
1232     {
1233     case 2:
1234       return { px_->value( rng, nullptr ), py_->value( rng, nullptr ) };
1235     case 3:
1236       return { px_->value( rng, nullptr ), py_->value( rng, nullptr ), pz_->value( rng, nullptr ) };
1237     }
1238     throw KernelException( "Wrong number of dimensions in get_values!" );
1239   }
1240 
1241   int
get_num_dimensions()1242   get_num_dimensions() const
1243   {
1244     return num_dimensions_;
1245   }
1246 
1247 protected:
1248   int num_dimensions_;
1249   std::shared_ptr< Parameter > const px_;
1250   std::shared_ptr< Parameter > const py_;
1251   std::shared_ptr< Parameter > const pz_;
1252 };
1253 
1254 
1255 /**
1256  * Parameter class representing an exponential distribution applied on a parameter.
1257  * Can only be used when connecting spatially distributed nodes.
1258  */
1259 class ExpDistParameter : public Parameter
1260 {
1261 public:
1262   using Parameter::value;
1263 
1264   /**
1265    * Construct the parameter from a dictionary of arguments.
1266    */
1267   ExpDistParameter( const DictionaryDatum& d );
1268 
1269   /**
1270    * Copy constructor.
1271    */
ExpDistParameter(const ExpDistParameter & p)1272   ExpDistParameter( const ExpDistParameter& p )
1273     : Parameter( p )
1274     , p_( p.p_ )
1275     , inv_beta_( p.inv_beta_ )
1276   {
1277     assert( is_spatial_ == p.is_spatial() );
1278   }
1279 
1280   /**
1281    * @returns the value of the parameter.
1282    */
1283   double
value(RngPtr,Node *)1284   value( RngPtr, Node* ) override
1285   {
1286     throw BadParameterValue( "Exponential distribution parameter can only be used when connecting." );
1287   }
1288 
1289   double value( RngPtr rng,
1290     const std::vector< double >& source_pos,
1291     const std::vector< double >& target_pos,
1292     const AbstractLayer& layer,
1293     Node* node ) override;
1294 
1295 protected:
1296   std::shared_ptr< Parameter > const p_;
1297   const double inv_beta_;
1298 };
1299 
1300 
1301 /**
1302  * Parameter class representing a gaussian distribution applied on a parameter.
1303  * Can only be used when connecting spatially distributed nodes.
1304  */
1305 class GaussianParameter : public Parameter
1306 {
1307 public:
1308   using Parameter::value;
1309 
1310   /**
1311    * Construct the parameter from a dictionary of arguments.
1312    */
1313   GaussianParameter( const DictionaryDatum& d );
1314 
1315   /**
1316    * Copy constructor.
1317    */
GaussianParameter(const GaussianParameter & p)1318   GaussianParameter( const GaussianParameter& p )
1319     : Parameter( p )
1320     , p_( p.p_ )
1321     , mean_( p.mean_ )
1322     , inv_two_std2_( p.inv_two_std2_ )
1323   {
1324   }
1325 
1326   /**
1327    * @returns the value of the parameter.
1328    */
1329   double
value(RngPtr,Node *)1330   value( RngPtr, Node* ) override
1331   {
1332     throw BadParameterValue( "Gaussian distribution parameter can only be used when connecting." );
1333   }
1334 
1335   double value( RngPtr rng,
1336     const std::vector< double >& source_pos,
1337     const std::vector< double >& target_pos,
1338     const AbstractLayer& layer,
1339     Node* node ) override;
1340 
1341 protected:
1342   std::shared_ptr< Parameter > const p_;
1343   const double mean_;
1344   const double inv_two_std2_;
1345 };
1346 
1347 
1348 /**
1349  * Parameter class representing a gaussian distribution in two dimensions applied on a parameter.
1350  * Can only be used when connecting spatially distributed nodes.
1351  */
1352 class Gaussian2DParameter : public Parameter
1353 {
1354 public:
1355   using Parameter::value;
1356 
1357   /**
1358    * Construct the parameter from a dictionary of arguments.
1359    */
1360   Gaussian2DParameter( const DictionaryDatum& d );
1361 
1362   /**
1363    * Copy constructor.
1364    */
Gaussian2DParameter(const Gaussian2DParameter & p)1365   Gaussian2DParameter( const Gaussian2DParameter& p )
1366     : Parameter( p )
1367     , px_( p.px_ )
1368     , py_( p.py_ )
1369     , mean_x_( p.mean_x_ )
1370     , mean_y_( p.mean_y_ )
1371     , x_term_const_( p.x_term_const_ )
1372     , y_term_const_( p.y_term_const_ )
1373     , xy_term_const_( p.xy_term_const_ )
1374   {
1375   }
1376 
1377   /**
1378    * @returns the value of the parameter.
1379    */
1380   double
value(RngPtr,Node *)1381   value( RngPtr, Node* ) override
1382   {
1383     throw BadParameterValue( "Gaussian 2D parameter can only be used when connecting." );
1384   }
1385 
1386   double value( RngPtr rng,
1387     const std::vector< double >& source_pos,
1388     const std::vector< double >& target_pos,
1389     const AbstractLayer& layer,
1390     Node* node ) override;
1391 
1392 protected:
1393   std::shared_ptr< Parameter > const px_;
1394   std::shared_ptr< Parameter > const py_;
1395   const double mean_x_;
1396   const double mean_y_;
1397   const double x_term_const_;
1398   const double y_term_const_;
1399   const double xy_term_const_;
1400 };
1401 
1402 
1403 /**
1404  * Parameter class representing a gamma distribution applied on a parameter.
1405  * Can only be used when connecting spatially distributed nodes.
1406  */
1407 class GammaParameter : public Parameter
1408 {
1409 public:
1410   using Parameter::value;
1411 
1412   /**
1413    * Construct the parameter from a dictionary of arguments.
1414    */
1415   GammaParameter( const DictionaryDatum& d );
1416 
1417   /**
1418    * Copy constructor.
1419    */
GammaParameter(const GammaParameter & p)1420   GammaParameter( const GammaParameter& p )
1421     : Parameter( p )
1422     , p_( p.p_ )
1423     , kappa_( p.kappa_ )
1424     , inv_theta_( p.inv_theta_ )
1425     , delta_( p.delta_ )
1426   {
1427   }
1428 
1429   /**
1430    * @returns the value of the parameter.
1431    */
1432   double
value(RngPtr,Node *)1433   value( RngPtr, Node* ) override
1434   {
1435     throw BadParameterValue( "Gamma distribution parameter can only be used when connecting." );
1436   }
1437 
1438   double value( RngPtr rng,
1439     const std::vector< double >& source_pos,
1440     const std::vector< double >& target_pos,
1441     const AbstractLayer& layer,
1442     Node* node ) override;
1443 
1444 protected:
1445   std::shared_ptr< Parameter > const p_;
1446   const double kappa_;
1447   const double inv_theta_;
1448   const double delta_;
1449 };
1450 
1451 inline double
value(RngPtr rng,const std::vector<double> &,const std::vector<double> &,const AbstractLayer &,Node * node)1452 Parameter::value( RngPtr rng,
1453   const std::vector< double >&,
1454   const std::vector< double >&,
1455   const AbstractLayer&,
1456   Node* node )
1457 {
1458   return value( rng, node );
1459 }
1460 
1461 inline bool
is_spatial()1462 Parameter::is_spatial() const
1463 {
1464   return is_spatial_;
1465 }
1466 
1467 inline bool
returns_int_only()1468 Parameter::returns_int_only() const
1469 {
1470   return returns_int_only_;
1471 }
1472 
1473 inline bool
value_is_integer_(const double value)1474 Parameter::value_is_integer_( const double value ) const
1475 {
1476   // Here fmod calculates the remainder of the division operation x/y. By using y=1.0,
1477   // the remainder is the fractional part of the value. If the fractional part
1478   // is zero, the value is an integer.
1479   return std::fmod( value, static_cast< double >( 1.0 ) ) == 0.0;
1480 }
1481 
1482 
1483 /**
1484  * Create the product of one parameter with another.
1485  * @returns a new dynamically allocated parameter.
1486  */
1487 std::shared_ptr< Parameter > multiply_parameter( const std::shared_ptr< Parameter > first,
1488   const std::shared_ptr< Parameter > second );
1489 
1490 /**
1491  * Create the quotient of one parameter with another.
1492  * @returns a new dynamically allocated parameter.
1493  */
1494 std::shared_ptr< Parameter > divide_parameter( const std::shared_ptr< Parameter > first,
1495   const std::shared_ptr< Parameter > second );
1496 
1497 /**
1498  * Create the sum of one parameter with another.
1499  * @returns a new dynamically allocated parameter.
1500  */
1501 std::shared_ptr< Parameter > add_parameter( const std::shared_ptr< Parameter > first,
1502   const std::shared_ptr< Parameter > second );
1503 
1504 /**
1505  * Create the difference between one parameter and another.
1506  * @returns a new dynamically allocated parameter.
1507  */
1508 std::shared_ptr< Parameter > subtract_parameter( const std::shared_ptr< Parameter > first,
1509   const std::shared_ptr< Parameter > second );
1510 
1511 /**
1512  * Create comparison of one parameter with another.
1513  * @returns a new dynamically allocated parameter.
1514  */
1515 std::shared_ptr< Parameter > compare_parameter( const std::shared_ptr< Parameter > first,
1516   const std::shared_ptr< Parameter > second,
1517   const DictionaryDatum& d );
1518 
1519 /**
1520  * Create a parameter that chooses between two other parameters,
1521  * based on a given condition parameter. The resulting value of the condition parameter
1522  * is treated as a bool, meaning that a zero value evaluates as false, and all other values
1523  * evaluate as true.
1524  * @returns a new dynamically allocated parameter.
1525  */
1526 std::shared_ptr< Parameter > conditional_parameter( const std::shared_ptr< Parameter > condition,
1527   const std::shared_ptr< Parameter > if_true,
1528   const std::shared_ptr< Parameter > if_false );
1529 
1530 /**
1531  * Create parameter whose value is the minimum of a given parameter's value and the given value.
1532  * @returns a new dynamically allocated parameter.
1533  */
1534 std::shared_ptr< Parameter > min_parameter( const std::shared_ptr< Parameter > parameter, const double other );
1535 
1536 /**
1537  * Create parameter whose value is the maximum of a given parameter's value and the given value.
1538  * @returns a new dynamically allocated parameter.
1539  */
1540 std::shared_ptr< Parameter > max_parameter( const std::shared_ptr< Parameter > parameter, const double other );
1541 
1542 /**
1543  * Create parameter redrawing the value if the value of a parameter is outside the set limits.
1544  * @returns a new dynamically allocated parameter.
1545  */
1546 std::shared_ptr< Parameter >
1547 redraw_parameter( const std::shared_ptr< Parameter > parameter, const double min, const double max );
1548 
1549 /**
1550  * Create the exponential of a parameter.
1551  * @returns a new dynamically allocated parameter.
1552  */
1553 std::shared_ptr< Parameter > exp_parameter( const std::shared_ptr< Parameter > parameter );
1554 
1555 /**
1556  * Create the sine of a parameter.
1557  * @returns a new dynamically allocated parameter.
1558  */
1559 std::shared_ptr< Parameter > sin_parameter( const std::shared_ptr< Parameter > parameter );
1560 
1561 /**
1562  * Create the cosine of a parameter.
1563  * @returns a new dynamically allocated parameter.
1564  */
1565 std::shared_ptr< Parameter > cos_parameter( const std::shared_ptr< Parameter > parameter );
1566 
1567 /**
1568  * Create a parameter raised to the power of an exponent.
1569  * @returns a new dynamically allocated parameter.
1570  */
1571 std::shared_ptr< Parameter > pow_parameter( const std::shared_ptr< Parameter > parameter, const double exponent );
1572 
1573 /**
1574  * Create a parameter that can generate position vectors from a given set of parameters.
1575  * @returns a new dynamically allocated parameter.
1576  */
1577 std::shared_ptr< Parameter > dimension_parameter( const std::shared_ptr< Parameter > x_parameter,
1578   const std::shared_ptr< Parameter > y_parameter );
1579 
1580 std::shared_ptr< Parameter > dimension_parameter( const std::shared_ptr< Parameter > x_parameter,
1581   const std::shared_ptr< Parameter > y_parameter,
1582   const std::shared_ptr< Parameter > z_parameter );
1583 
1584 
1585 } // namespace nest
1586 
1587 #endif
1588