Utopia  2
Framework for studying models of complex & adaptive systems.
env_param_func_collection.hh
Go to the documentation of this file.
1 #ifndef UTOPIA_MODELS_ENVIRONMENT_ENVPARAMFUNCCOLLECTION_HH
2 #define UTOPIA_MODELS_ENVIRONMENT_ENVPARAMFUNCCOLLECTION_HH
3 
4 #include <math.h>
5 
6 #include "tools.hh"
7 
9 namespace ParameterFunctionCollection {
10 
11 
14 
15 // -- Helper functions --------------------------------------------------------
16 
18 
21 template<typename EnvModel, class DistType,
22  class EnvParamFunc = typename EnvModel::EnvParamFunc>
23 EnvParamFunc
24  build_rng_env_param_func(const EnvModel& model,
25  DistType&& dist,
26  const std::string& param_name,
27  const ValMode& mode)
28 {
29  // NOTE It is VITAL to move-construct the perfectly-forwarded dist into
30  // the lambda; otherwise it has to be stored outside, which is a
31  // real pita. Also, the lambda has to be declared mutable such
32  // that the captured object are allowed to be changed; again, this
33  // is only relevant for the distribution's internal state ...
34  return
35  [&model, param_name, mode, dist{std::move(dist)}] () mutable {
36  double current_value = 0.;
37  if (mode == ValMode::Add) {
38  current_value = model.get_parameter(param_name);
39  }
40  const double rn = dist(*model.get_rng());
41 
42  return current_value + rn;
43  };
44 }
45 
51 // -- Environment parameter modification functions ----------------------------
52 // .. Keep these in alphabetical order and prefix with _epf_ ! .............
53 // NOTE The methods below do _not_ change any state, they just generate
54 // a function object that does so at the desired point in time.
55 
57 
71 template<typename EnvModel,
72  class EnvParamFunc = typename EnvModel::EnvParamFunc>
73 EnvParamFunc epf_increment(const EnvModel& model, const std::string param_name,
74  const Config& cfg)
75 {
76  const auto value = get_as<double>("value", cfg);
77  EnvParamFunc epf = [&model, param_name, value] () mutable
78  {
79  return model.get_parameter(param_name) + value;
80  };
81 
82  return epf;
83 }
84 
86 
104 template<typename EnvModel,
105  class EnvParamFunc = typename EnvModel::EnvParamFunc>
106 EnvParamFunc epf_random(const EnvModel& model, const std::string& param_name,
107  const Config& cfg)
108 {
109  const auto mode = extract_val_mode(cfg, "random");
110  const auto distribution = get_as<std::string>("distribution", cfg);
111 
112  // Depending on chosen distribution, construct it and build a rule
113  // function using a reference to the newly created one...
114  if (distribution == "normal") {
115  const auto mean = get_as<double>("mean", cfg);
116  const auto stddev = get_as<double>("stddev", cfg);
117  std::normal_distribution<> dist(mean, stddev);
118 
119  return build_rng_env_param_func(model, std::move(dist), param_name,
120  mode);
121  }
122  else if (distribution == "poisson") {
123  const auto mean = get_as<double>("mean", cfg);
124  std::poisson_distribution<> dist(mean);
125 
126  return build_rng_env_param_func(model, std::move(dist), param_name,
127  mode);
128  }
129  else if (distribution == "exponential") {
130  const auto lambda = get_as<double>("lambda", cfg);
131  std::exponential_distribution<> dist(lambda);
132 
133  return build_rng_env_param_func(model, std::move(dist), param_name,
134  mode);
135  }
136  else if (distribution == "uniform_int") {
137  auto interval = get_as<std::array<int, 2>>("interval", cfg);
138  std::uniform_int_distribution<> dist(interval[0], interval[1]);
139 
140  return build_rng_env_param_func(model, std::move(dist), param_name,
141  mode);
142  }
143  else if (distribution == "uniform_real" or distribution == "uniform") {
144  auto interval = get_as<std::array<double, 2>>("interval", cfg);
145  std::uniform_real_distribution<> dist(interval[0], interval[1]);
146 
147  return build_rng_env_param_func(model, std::move(dist), param_name,
148  mode);
149  }
150  else {
151  throw std::invalid_argument("No method implemented to resolve "
152  "noise distribution '" + distribution + "'! Valid options: "
153  "normal, poisson, uniform_int, uniform_real.");
154  }
155 };
156 
158 
179 template<typename EnvModel,
180  class EnvParamFunc = typename EnvModel::EnvParamFunc>
181 EnvParamFunc epf_rectangular(const EnvModel& model, const Config& cfg)
182 {
183  using Time = typename EnvModel::Time;
184 
185  double min_value = get_as<double>("offset", cfg, 0.);
186  double max_value = get_as<double>("amplitude", cfg) + min_value;
187  Time period = get_as<Time>("period", cfg);
188  Time time_in_max = get_as<Time>("time_in_max", cfg, period / 2.);
189  double phase = get_as<double>("phase", cfg, 0) * period;
190 
191  // Check parameter
192  if (time_in_max > period) {
193  throw std::invalid_argument("The `time_in_max` argument cannot be "
194  "larger than the `period` argument in rectangular "
195  "environment parameter function!");
196  }
197  if (phase < 0 or phase > period) {
198  throw std::invalid_argument("The `phase` argument was not in interval "
199  "[0., 1.]!");
200  }
201 
202  // get starting time
203  Time time_start = extract_time_start<Time>(cfg);
204 
205  // Build function
206  EnvParamFunc epf = [&model, max_value, min_value,
207  period, time_in_max, phase, time_start] () mutable
208  {
209  auto time = (model.get_time()+1 - time_start) % period;
210  if (time >= phase and time < time_in_max + phase) {
211  return max_value;
212  }
213  return min_value;
214  };
215 
216  return epf;
217 }
218 
220 
234 template<typename EnvModel,
235  class EnvParamFunc = typename EnvModel::EnvParamFunc>
236 EnvParamFunc epf_set(const EnvModel&, const Config& cfg)
237 {
238  const auto value = get_as<double>("value", cfg);
239  EnvParamFunc epf = [value] () mutable
240  {
241  return value;
242  };
243 
244  return epf;
245 }
246 
248 
268 template<typename EnvModel,
269  class EnvParamFunc = typename EnvModel::EnvParamFunc>
270 EnvParamFunc epf_sinusoidal(const EnvModel& model, const Config& cfg)
271 {
272  using Time = typename EnvModel::Time;
273 
274  const auto period = get_as<double>("period", cfg);
275  const auto amplitude = get_as<double>("amplitude", cfg);
276  double phase = 0;
277  if (cfg["phase"]) {
278  phase = get_as<double>("phase", cfg);
279  }
280  double offset = 0.;
281  if (cfg["offset"]) {
282  offset = get_as<double>("offset", cfg);
283  }
284 
285  // get starting time
286  Time time_start = extract_time_start<Time>(cfg);
287 
288  EnvParamFunc epf = [&model, period, amplitude,
289  phase, offset, time_start] () mutable
290  {
291  double x = (model.get_time() + 1 - time_start)/period * 2*M_PI;
292  return offset + amplitude * sin(x + phase * M_PI);
293  };
294 
295  return epf;
296 }
297 
298 // end group Environment
303 } // namespace ParameterFunctionCollection
304 } // namespace Utopia::Models::Environment
305 
306 #endif
YAML::Node Config
Type of a variadic dictionary-like data structure used throughout Utopia.
Definition: types.hh:71
EnvParamFunc epf_sinusoidal(const EnvModel &model, const Config &cfg)
Creates a rule function for sinusoidal parameter values.
Definition: env_param_func_collection.hh:270
EnvParamFunc epf_random(const EnvModel &model, const std::string &param_name, const Config &cfg)
Creates a rule function for random parameter values.
Definition: env_param_func_collection.hh:106
EnvParamFunc epf_increment(const EnvModel &model, const std::string param_name, const Config &cfg)
Creates a rule function for incrementing parameter values.
Definition: env_param_func_collection.hh:73
ValMode extract_val_mode(const DataIO::Config &cfg, const std::string &context)
Given a configuration node, extract the value mode.
Definition: tools.hh:19
EnvParamFunc epf_rectangular(const EnvModel &model, const Config &cfg)
Creates a rule function for rectangular function like parameter values.
Definition: env_param_func_collection.hh:181
EnvParamFunc epf_set(const EnvModel &, const Config &cfg)
Creates a rule function for setting a parameter value.
Definition: env_param_func_collection.hh:236
ValMode
Value calculation mode.
Definition: tools.hh:10
@ Add
Add the new value to the existing value.
EnvParamFunc build_rng_env_param_func(const EnvModel &model, DistType &&dist, const std::string &param_name, const ValMode &mode)
Create a rule function that uses a random number distribution.
Definition: env_param_func_collection.hh:24
DataIO::Config Config
Configuration node type alias.
Definition: env_param_func_collection.hh:13
Definition: env_param_func_collection.hh:8
unsigned int DistType
Type for distancens, i.e. intermediately long unsigned integers.
Definition: types.hh:37