NEURON
ivocrand.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 
3 // definition of random number generation from the g++ library
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include "Rand.hpp"
8 
9 #include <InterViews/resource.h>
10 #include "classreg.h"
11 #include "oc2iv.h"
12 #include "utils/enumerate.h"
13 
14 #include <vector>
15 #include <ocnotify.h>
16 #include "ocobserv.h"
17 #include <nrnran123.h>
18 
19 #include <Random.h>
20 #include <Poisson.h>
21 #include <Normal.h>
22 #include <Uniform.h>
23 #include <Binomial.h>
24 #include <DiscUnif.h>
25 #include <Erlang.h>
26 #include <Geom.h>
27 #include <LogNorm.h>
28 #include <NegExp.h>
29 #include <HypGeom.h>
30 #include <Weibull.h>
31 #include <NrnRandom123RNG.hpp>
32 #include <MCellRan4RNG.hpp>
33 
34 #if HAVE_IV
35 #include "ivoc.h"
36 #endif
37 
38 #undef dmaxuint
39 #define dmaxuint 4294967295.
40 
41 extern "C" void nrn_random_play();
42 
43 class RandomPlay: public Observer, public Resource {
44  public:
46  virtual ~RandomPlay() {}
47  void play();
48  void list_remove();
49  virtual void update(Observable*);
50 
51  private:
52  Rand* r_;
54 };
55 
56 using RandomPlayList = std::vector<RandomPlay*>;
58 
60  : r_{r}
61  , px_{std::move(px)} {
62  random_play_list_->push_back(this);
63  ref();
66 }
68  // printf("RandomPlay::play\n");
69  *px_ = (*(r_->rand))();
70 }
72  if (auto it = std::find(random_play_list_->begin(), random_play_list_->end(), this);
73  it != random_play_list_->end()) {
74  // printf("RandomPlay %p removed from list cnt=%d i=%d %p\n", this, cnt, i);
75  random_play_list_->erase(it);
77  }
78 }
80  // printf("RandomPlay::update\n");
82  list_remove();
83 }
84 
85 static void* r_cons(Object* obj) {
86  unsigned long seed = 0;
87  int size = 55;
88 
89  if (ifarg(1))
90  seed = long(*getarg(1));
91  if (ifarg(2))
92  size = int(chkarg(2, 7, 98));
93 
94  Rand* r = new Rand(seed, size, obj);
95  return (void*) r;
96 }
97 
98 // destructor -- called when no longer referenced
99 
100 static void r_destruct(void* r) {
101  delete (Rand*) r;
102 }
103 
104 static double r_MCellRan4(void* r) {
105  Rand* x = (Rand*) r;
106 
107  uint32_t seed1 = 0;
108  uint32_t ilow = 0;
109 
110  if (ifarg(1))
111  seed1 = (uint32_t) (chkarg(1, 0., dmaxuint));
112  if (ifarg(2))
113  ilow = (uint32_t) (chkarg(2, 0., dmaxuint));
114  MCellRan4* mcr = new MCellRan4(seed1, ilow);
115  x->rand->generator(mcr);
116  delete x->gen;
117  x->gen = x->rand->generator();
118  x->type_ = 2;
119  return (double) mcr->orig_;
120 }
121 
123  assert(r->type_ == 2);
124  MCellRan4* mcr = (MCellRan4*) r->gen;
125  return mcr->ihigh_;
126 }
127 
128 void nrn_set_random_sequence(Rand* r, long seq) {
129  assert(r->type_ == 2);
130  MCellRan4* mcr = (MCellRan4*) r->gen;
131  mcr->ihigh_ = seq;
132 }
133 
134 int nrn_random_isran123(Rand* r, uint32_t* id1, uint32_t* id2, uint32_t* id3) {
135  if (r->type_ == 4) {
136  NrnRandom123* nr = (NrnRandom123*) r->gen;
137  nrnran123_getids3(nr->s_, id1, id2, id3);
138  return 1;
139  }
140  return 0;
141 }
142 
143 static double r_nrnran123(void* r) {
144  Rand* x = (Rand*) r;
145  uint32_t id1 = 0;
146  uint32_t id2 = 0;
147  uint32_t id3 = 0;
148  if (ifarg(1))
149  id1 = (uint32_t) (chkarg(1, 0., dmaxuint));
150  if (ifarg(2))
151  id2 = (uint32_t) (chkarg(2, 0., dmaxuint));
152  if (ifarg(3))
153  id3 = (uint32_t) (chkarg(3, 0., dmaxuint));
154  try {
155  NrnRandom123* r123 = new NrnRandom123(id1, id2, id3);
156  x->rand->generator(r123);
157  } catch (const std::bad_alloc& e) {
158  hoc_execerror("Bad allocation for 'NrnRandom123'", e.what());
159  }
160  delete x->gen;
161  x->gen = x->rand->generator();
162  x->type_ = 4;
163  return 0.;
164 }
165 
166 static double r_ran123_globalindex(void* r) {
167  if (ifarg(1)) {
168  uint32_t gix = (uint32_t) chkarg(1, 0., 4294967295.); /* 2^32 - 1 */
170  }
171  return (double) nrnran123_get_globalindex();
172 }
173 
174 static double r_sequence(void* r) {
175  Rand* x = (Rand*) r;
176  if (x->type_ == 4) {
177  uint32_t seq;
178  char which;
179  if (ifarg(1)) {
180  double s = chkarg(1, 0., 17179869183.); /* 2^34 - 1 */
181  seq = (uint32_t) (s / 4.);
182  which = char(s - seq * 4.);
183  NrnRandom123* nr = (NrnRandom123*) x->gen;
184  nrnran123_setseq(nr->s_, seq, which);
185  }
186  nrnran123_getseq(((NrnRandom123*) x->gen)->s_, &seq, &which);
187  return double(seq) * 4. + double(which);
188  }
189 
190  MCellRan4* mcr = (MCellRan4*) x->gen;
191  if (ifarg(1)) {
192  mcr->ihigh_ = (long) (*getarg(1));
193  }
194  return (double) mcr->ihigh_;
195 }
196 
197 int nrn_random123_setseq(Rand* r, uint32_t seq, char which) {
198  if (r->type_ != 4) {
199  return 0;
200  }
201  nrnran123_setseq(((NrnRandom123*) r->gen)->s_, seq, which);
202  return 1;
203 }
204 
205 int nrn_random123_getseq(Rand* r, uint32_t* seq, char* which) {
206  if (r->type_ != 4) {
207  return 0;
208  }
209  nrnran123_getseq(((NrnRandom123*) r->gen)->s_, seq, which);
210  return 1;
211 }
212 
213 // Pick again from the distribution last used
214 // syntax:
215 // r.repick()
216 static double r_repick(void* r) {
217  Rand* x = (Rand*) r;
218  return (*(x->rand))();
219 }
220 
221 double nrn_random_pick(Rand* r) {
222  if (r) {
223  return (*(r->rand))();
224  } else {
225  return .5;
226  }
227 }
228 
230  if (r) {
231  r->gen->reset();
232  }
233 }
234 
236  Object* ob = *hoc_objgetarg(i);
237  check_obj_type(ob, "Random");
238  Rand* r = (Rand*) (ob->u.this_pointer);
239  return r;
240 }
241 
242 // uniform random variable over the open interval [low...high)
243 // syntax:
244 // r.uniform(low,high)
245 
246 static double r_uniform(void* r) {
247  Rand* x = (Rand*) r;
248  double a1 = *getarg(1);
249  double a2 = *getarg(2);
250  delete x->rand;
251  x->rand = new Uniform(a1, a2, x->gen);
252  return (*(x->rand))();
253 }
254 
255 // uniform random variable over the closed interval [low...high]
256 // syntax:
257 // r.discunif(low,high)
258 
259 static double r_discunif(void* r) {
260  Rand* x = (Rand*) r;
261  long a1 = long(*getarg(1));
262  long a2 = long(*getarg(2));
263  delete x->rand;
264  x->rand = new DiscreteUniform(a1, a2, x->gen);
265  return (*(x->rand))();
266 }
267 
268 
269 // normal (gaussian) distribution
270 // syntax:
271 // r.normal(mean,variance)
272 
273 static double r_normal(void* r) {
274  Rand* x = (Rand*) r;
275  double a1 = *getarg(1);
276  double a2 = *getarg(2);
277  delete x->rand;
278  x->rand = new Normal(a1, a2, x->gen);
279  return (*(x->rand))();
280 }
281 
282 
283 // logarithmic normal distribution
284 // syntax:
285 // r.lognormal(mean)
286 
287 static double r_lognormal(void* r) {
288  Rand* x = (Rand*) r;
289  double a1 = *getarg(1);
290  double a2 = *getarg(2);
291  delete x->rand;
292  x->rand = new LogNormal(a1, a2, x->gen);
293  return (*(x->rand))();
294 }
295 
296 
297 // poisson distribution
298 // syntax:
299 // r.poisson(mean)
300 
301 static double r_poisson(void* r) {
302  Rand* x = (Rand*) r;
303  double a1 = *getarg(1);
304  delete x->rand;
305  x->rand = new Poisson(a1, x->gen);
306  return (*(x->rand))();
307 }
308 
309 
310 // binomial distribution, which models successfully drawing items from a pool
311 // n is the number items in the pool and p is the probablity of each item
312 // being successfully drawn (n>0, 0<=p<=1)
313 // syntax:
314 // r.binomial(n,p)
315 
316 static double r_binomial(void* r) {
317  Rand* x = (Rand*) r;
318  int a1 = int(chkarg(1, 0, 1e99));
319  double a2 = chkarg(2, 0, 1);
320  delete x->rand;
321  x->rand = new Binomial(a1, a2, x->gen);
322  return (*(x->rand))();
323 }
324 
325 
326 // discrete geometric distribution
327 // Given 0<=mean<=1, returns the number of uniform random samples
328 // that were drawn before the sample was larger than mean (always
329 // greater than 0.
330 // syntax:
331 // r.geometric(mean)
332 
333 static double r_geometric(void* r) {
334  Rand* x = (Rand*) r;
335  double a1 = chkarg(1, 0, 1);
336  delete x->rand;
337  x->rand = new Geometric(a1, x->gen);
338  return (*(x->rand))();
339 }
340 
341 
342 // hypergeometric distribution
343 // syntax:
344 // r.hypergeo(mean,variance)
345 
346 static double r_hypergeo(void* r) {
347  Rand* x = (Rand*) r;
348  double a1 = *getarg(1);
349  double a2 = *getarg(2);
350  delete x->rand;
351  x->rand = new HyperGeometric(a1, a2, x->gen);
352  return (*(x->rand))();
353 }
354 
355 
356 // negative exponential distribution
357 // syntax:
358 // r.negexp(mean)
359 
360 static double r_negexp(void* r) {
361  Rand* x = (Rand*) r;
362  double a1 = *getarg(1);
363  delete x->rand;
364  x->rand = new NegativeExpntl(a1, x->gen);
365  return (*(x->rand))();
366 }
367 
368 
369 // Erlang distribution
370 // syntax:
371 // r.erlang(mean,variance)
372 
373 static double r_erlang(void* r) {
374  Rand* x = (Rand*) r;
375  double a1 = *getarg(1);
376  double a2 = *getarg(2);
377  delete x->rand;
378  x->rand = new Erlang(a1, a2, x->gen);
379  return (*(x->rand))();
380 }
381 
382 
383 // Weibull distribution
384 // syntax:
385 // r.weibull(alpha,beta)
386 
387 static double r_weibull(void* r) {
388  Rand* x = (Rand*) r;
389  double a1 = *getarg(1);
390  double a2 = *getarg(2);
391  delete x->rand;
392  x->rand = new Weibull(a1, a2, x->gen);
393  return (*(x->rand))();
394 }
395 
396 static double r_play(void* r) {
397  new RandomPlay(static_cast<Rand*>(r), hoc_hgetarg<double>(1));
398  return 0.;
399 }
400 
401 extern "C" void nrn_random_play() {
402  for (const auto& rp: *random_play_list_) {
403  rp->play();
404  }
405 }
406 
407 
408 static Member_func r_members[] = {{"MCellRan4", r_MCellRan4},
409  {"Random123", r_nrnran123},
410  {"Random123_globalindex", r_ran123_globalindex},
411  {"seq", r_sequence},
412  {"repick", r_repick},
413  {"uniform", r_uniform},
414  {"discunif", r_discunif},
415  {"normal", r_normal},
416  {"lognormal", r_lognormal},
417  {"binomial", r_binomial},
418  {"poisson", r_poisson},
419  {"geometric", r_geometric},
420  {"hypergeo", r_hypergeo},
421  {"negexp", r_negexp},
422  {"erlang", r_erlang},
423  {"weibull", r_weibull},
424  {"play", r_play},
425  {nullptr, nullptr}};
426 
427 void Random_reg() {
428  class2oc("Random", r_cons, r_destruct, r_members, nullptr, nullptr);
430 }
431 
432 // Deprecated backwards-compatibility definitions
433 long nrn_get_random_sequence(void* r) {
434  return nrn_get_random_sequence(static_cast<Rand*>(r));
435 }
436 int nrn_random_isran123(void* r, uint32_t* id1, uint32_t* id2, uint32_t* id3) {
437  return nrn_random_isran123(static_cast<Rand*>(r), id1, id2, id3);
438 }
439 double nrn_random_pick(void* r) {
440  return nrn_random_pick(static_cast<Rand*>(r));
441 }
442 void nrn_random_reset(void* r) {
443  nrn_random_reset(static_cast<Rand*>(r));
444 }
445 int nrn_random123_getseq(void* r, uint32_t* seq, char* which) {
446  return nrn_random123_getseq(static_cast<Rand*>(r), seq, which);
447 }
448 int nrn_random123_setseq(void* r, uint32_t seq, char which) {
449  return nrn_random123_setseq(static_cast<Rand*>(r), seq, which);
450 }
451 void nrn_set_random_sequence(void* r, int seq) {
452  nrn_set_random_sequence(static_cast<Rand*>(r), static_cast<long>(seq));
453 }
Definition: Erlang.h:22
Definition: Geom.h:21
std::uint32_t orig_
std::uint32_t ihigh_
Definition: Normal.h:21
nrnran123_State * s_
virtual void reset()=0
Definition: Rand.hpp:15
Random * rand
Definition: Rand.hpp:20
int type_
Definition: Rand.hpp:21
Object * obj_
Definition: Rand.hpp:23
RNG * gen
Definition: Rand.hpp:19
RNG * generator()
Definition: Random.h:42
void play()
Definition: ivocrand.cpp:67
RandomPlay(Rand *, neuron::container::data_handle< double > px)
Definition: ivocrand.cpp:59
neuron::container::data_handle< double > px_
Definition: ivocrand.cpp:53
virtual ~RandomPlay()
Definition: ivocrand.cpp:46
void list_remove()
Definition: ivocrand.cpp:71
virtual void update(Observable *)
Definition: ivocrand.cpp:79
Rand * r_
Definition: ivocrand.cpp:52
virtual void ref() const
Definition: resource.cpp:42
virtual void unref_deferred() const
Definition: resource.cpp:58
void class2oc(const char *, ctor_f *cons, dtor_f *destruct, Member_func *, Member_ret_obj_func *, Member_ret_str_func *)
Definition: hoc_oop.cpp:1631
#define i
Definition: md1redef.h:19
double chkarg(int, double low, double high)
Definition: code2.cpp:626
void nrnran123_getids3(nrnran123_State *s, std::uint32_t *id1, std::uint32_t *id2, std::uint32_t *id3)
Definition: nrnran123.cpp:97
void nrnran123_setseq(nrnran123_State *s, std::uint32_t seq, char which)
Set a Random123 sequence for a sequnece ID and which selector.
Definition: nrnran123.cpp:55
void nrnran123_getseq(nrnran123_State *s, std::uint32_t *seq, char *which)
Get sequence number and selector from an nrnran123_State object.
Definition: nrnran123.cpp:50
void check_obj_type(Object *obj, const char *type_name)
Definition: hoc_oop.cpp:2098
#define assert(ex)
Definition: hocassrt.h:24
#define getarg
Definition: hocdec.h:17
Object ** hoc_objgetarg(int)
Definition: code.cpp:1614
void nrn_notify_when_void_freed(void *p, Observer *ob)
Definition: ivoc.cpp:52
void nrn_notify_pointer_disconnect(Observer *ob)
Definition: ivoc.cpp:70
#define dmaxuint
Definition: ivocrand.cpp:39
static double r_negexp(void *r)
Definition: ivocrand.cpp:360
void nrn_random_reset(Rand *r)
Definition: ivocrand.cpp:229
int nrn_random123_setseq(Rand *r, uint32_t seq, char which)
Definition: ivocrand.cpp:197
static void * r_cons(Object *obj)
Definition: ivocrand.cpp:85
static double r_poisson(void *r)
Definition: ivocrand.cpp:301
static double r_sequence(void *r)
Definition: ivocrand.cpp:174
static double r_repick(void *r)
Definition: ivocrand.cpp:216
static double r_uniform(void *r)
Definition: ivocrand.cpp:246
static void r_destruct(void *r)
Definition: ivocrand.cpp:100
double nrn_random_pick(Rand *r)
Definition: ivocrand.cpp:221
static double r_ran123_globalindex(void *r)
Definition: ivocrand.cpp:166
static double r_discunif(void *r)
Definition: ivocrand.cpp:259
static double r_MCellRan4(void *r)
Definition: ivocrand.cpp:104
static Member_func r_members[]
Definition: ivocrand.cpp:408
int nrn_random123_getseq(Rand *r, uint32_t *seq, char *which)
Definition: ivocrand.cpp:205
static double r_normal(void *r)
Definition: ivocrand.cpp:273
void nrn_random_play()
Definition: ivocrand.cpp:401
static double r_hypergeo(void *r)
Definition: ivocrand.cpp:346
int nrn_random_isran123(Rand *r, uint32_t *id1, uint32_t *id2, uint32_t *id3)
Definition: ivocrand.cpp:134
static double r_weibull(void *r)
Definition: ivocrand.cpp:387
static RandomPlayList * random_play_list_
Definition: ivocrand.cpp:57
static double r_lognormal(void *r)
Definition: ivocrand.cpp:287
void nrn_set_random_sequence(Rand *r, long seq)
Definition: ivocrand.cpp:128
static double r_play(void *r)
Definition: ivocrand.cpp:396
static double r_erlang(void *r)
Definition: ivocrand.cpp:373
std::vector< RandomPlay * > RandomPlayList
Definition: ivocrand.cpp:56
void Random_reg()
Definition: ivocrand.cpp:427
static double r_nrnran123(void *r)
Definition: ivocrand.cpp:143
long nrn_get_random_sequence(Rand *r)
Definition: ivocrand.cpp:122
Rand * nrn_random_arg(int i)
Definition: ivocrand.cpp:235
static double r_binomial(void *r)
Definition: ivocrand.cpp:316
static double r_geometric(void *r)
Definition: ivocrand.cpp:333
void move(Item *q1, Item *q2, Item *q3)
Definition: list.cpp:200
void nrnran123_set_globalindex(uint32_t gix)
Definition: nrnran123.cpp:117
void hoc_execerror(const char *s1, const char *s2)
Definition: nrnoc_aux.cpp:39
uint32_t nrnran123_get_globalindex()
Definition: nrnran123.cpp:112
void notify_when_handle_dies(data_handle< double > dh, Observer *obs)
Register that obs should be notified when dh dies.
Definition: ivoc.cpp:91
if(ncell==0)
Definition: cellorder.cpp:785
s
Definition: multisend.cpp:521
int ifarg(int)
Definition: code.cpp:1607
int find(const int, const int, const int, const int, const int)
Definition: hocdec.h:173
void * this_pointer
Definition: hocdec.h:178
union Object::@47 u