Lumiera  0.pre.03
»edit your freedom«
random-draw-test.cpp
Go to the documentation of this file.
1 /*
2  RandomDraw(Test) - verify the component builder for random selected values
3 
4  Copyright (C) Lumiera.org
5  2023, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
29 #include "lib/test/run.hpp"
30 #include "lib/random-draw.hpp"
31 #include "lib/format-string.hpp"
32 #include "lib/test/test-helper.hpp"
33 
34 #include <array>
35 
36 
37 
38 namespace lib {
39 namespace test{
40 
41  using util::_Fmt;
42  using lib::meta::_FunRet;
43  using err::LUMIERA_ERROR_LIFECYCLE;
44 
45 
46 
47  namespace { // policy and configuration for test...
48 
49  double ctxParameter = 1.0;
50 
59  : function<Limited<int, 2,-2, 0>(size_t)>
60  {
62  static size_t defaultSrc (size_t hash) { return hash; }
63 
65  template<class SIG>
66  struct Adaptor
67  {
68  static_assert (not sizeof(SIG), "Unable to adapt given functor.");
69  };
70 
72  template<typename RES>
73  struct Adaptor<RES(uint,uint)>
74  {
75  template<typename FUN>
76  static auto
77  build (FUN&& fun)
78  {
79  return [functor=std::forward<FUN>(fun)]
80  (size_t hash) -> _FunRet<FUN>
81  {
82  return functor(uint(hash/64), uint(hash%64));
83  };
84  }
85  };
86 
88  template<typename RES>
89  struct Adaptor<RES(size_t, double)>
90  {
91  template<typename FUN>
92  static auto
93  build (FUN&& fun)
94  {
95  return [functor=std::forward<FUN>(fun)]
96  (size_t hash) -> _FunRet<FUN>
97  {
98  return functor(hash, ctxParameter);
99  };
100  }
101  };
102  };
103  //
104  }//(End) Test config
105 
106 
108 
109 
110 
111  /***********************************************************************************/
123  : public Test
124  {
125 
126  void
127  run (Arg)
128  {
129  simpleUse();
130 
131  verify_policy();
132  verify_numerics();
133  verify_adaptMapping();
134  verify_dynamicChange();
135  }
136 
137 
138 
141  void
143  {
144  auto draw = Draw().probability(0.5);
145  CHECK (draw( 0) == 0);
146  CHECK (draw( 16) == 0);
147  CHECK (draw( 32) == 1);
148  CHECK (draw( 40) == 2);
149  CHECK (draw( 48) == -2);
150  CHECK (draw( 56) == -1);
151  CHECK (draw( 64) == 0); // values repeat after 64 steps
152  CHECK (draw( 95) == 0); // ~ half of each cycle yields the »neutral value«
153  CHECK (draw( 96) == 1);
154  CHECK (draw(127) == -1);
155  CHECK (draw(128) == 0);
156  CHECK (draw(168) == 2);
157  CHECK (draw(256) == 0);
158  }
159 
160 
161 
173  void
175  {
176  auto d1 = RandomDraw<random_draw::LimitedRandomGenerate<5>>().probability(1.0);
177  uint v1 = d1();
178  CHECK (0 < v1 and v1 <=5);
179 
180  struct SpecialPolicy
181  : function<Limited<char, 'Z','A'>(char,uint)>
182  {
183  static double defaultSrc (char b, uint off) { return fmod ((b-'A'+off)/double('Z'-'A'), 1.0); }
184  };
185 
186  auto d2 = RandomDraw<SpecialPolicy>().probability(1.0);
187  CHECK (d2('A', 2) == 'D');
188  CHECK (d2('M',10) == 'X');
189  CHECK (d2('Y', 0) == 'Z');
190  CHECK (d2('Y',15) == 'P');
191  }
192 
193 
194 
205  void
207  {
208  auto distribution = [](Draw const& draw)
209  { // investigate value distribution
210  using Arr = std::array<int,5>;
211  Arr step{-1,-1,-1,-1,-1};
212  Arr freq{0};
213  for (uint i=0; i<128; ++i)
214  {
215  int res = draw(i);
216  CHECK (-2 <= res and res <= +2);
217  int idx = res+2;
218  freq[idx] += 1;
219  if (step[idx] < 0)
220  step[idx] = i;
221  }
222  _Fmt line{"val:%+d (%02d|%5.2f%%)\n"};
223  string report;
224  for (int idx=0; idx<5; ++idx)
225  {
226  report += line % (idx-2) % step[idx] % (100.0*freq[idx]/128);
227  }
228  return report;
229  };
230 
231  auto draw = Draw();
232  string report{"+++| --empty-- \n"};
233 
234  CHECK (draw( 0) == 0);
235  CHECK (draw( 32) == 0);
236  CHECK (draw( 96) == 0);
237 
238  report += distribution(draw);
239  CHECK (report ==
240  "+++| --empty-- \n"
241  "val:-2 (-1| 0.00%)\n"
242  "val:-1 (-1| 0.00%)\n"
243  "val:+0 (00|100.00%)\n"
244  "val:+1 (-1| 0.00%)\n"
245  "val:+2 (-1| 0.00%)\n"_expect);
246 
247 
248  draw.probability(1.0);
249  CHECK (draw( 0) == +1);
250  CHECK (draw( 15) == +1);
251  CHECK (draw( 16) == +2);
252  CHECK (draw( 31) == +2);
253  CHECK (draw( 32) == -2);
254  CHECK (draw( 47) == -2);
255  CHECK (draw( 48) == -1);
256  CHECK (draw( 63) == -1);
257  CHECK (draw( 64) == +1);
258  CHECK (draw( 96) == -2);
259 
260  report = "+++| p ≔ 1.0 \n";
261  report += distribution(draw);
262  CHECK (report ==
263  "+++| p ≔ 1.0 \n"
264  "val:-2 (32|25.00%)\n"
265  "val:-1 (48|25.00%)\n"
266  "val:+0 (-1| 0.00%)\n"
267  "val:+1 (00|25.00%)\n"
268  "val:+2 (16|25.00%)\n"_expect);
269 
270 
271  draw.probability(0.99);
272  CHECK (draw( 0) == 0);
273  CHECK (draw( 1) == +1);
274  CHECK (draw( 16) == +1);
275  CHECK (draw( 17) == +2);
276  CHECK (draw( 32) == +2);
277  CHECK (draw( 33) == -2);
278  CHECK (draw( 48) == -2);
279  CHECK (draw( 49) == -1);
280  CHECK (draw( 63) == -1);
281  CHECK (draw( 64) == 0);
282  CHECK (draw( 65) == +1);
283  CHECK (draw( 80) == +1); // 64+16
284  CHECK (draw( 82) == +2); // 64+17
285  CHECK (draw( 97) == -2); // 64+33
286  CHECK (draw(352) == +2); // 64+32+256
287  CHECK (draw(353) == -2); // 64+33+256
288 
289  report = "+++| p ≔ 0.99 \n";
290  report += distribution(draw);
291  CHECK (report ==
292  "+++| p ≔ 0.99 \n"
293  "val:-2 (33|25.00%)\n"
294  "val:-1 (49|23.44%)\n"
295  "val:+0 (00| 1.56%)\n"
296  "val:+1 (01|25.00%)\n"
297  "val:+2 (17|25.00%)\n"_expect);
298 
299 
300  draw.probability(0.98);
301  CHECK (draw( 0) == 0);
302  CHECK (draw( 1) == 0);
303  CHECK (draw( 2) == +1);
304  CHECK (draw( 63) == -1);
305  CHECK (draw( 64) == 0);
306  CHECK (draw( 65) == 0);
307  CHECK (draw( 66) == +1);
308 
309  report = "+++| p ≔ 0.98 \n";
310  report += distribution(draw);
311  CHECK (report ==
312  "+++| p ≔ 0.98 \n"
313  "val:-2 (33|25.00%)\n"
314  "val:-1 (49|23.44%)\n"
315  "val:+0 (00| 3.12%)\n"
316  "val:+1 (02|23.44%)\n"
317  "val:+2 (17|25.00%)\n"_expect);
318 
319 
320  draw.probability(0.97);
321  report = "+++| p ≔ 0.97 \n";
322  report += distribution(draw);
323  CHECK (report ==
324  "+++| p ≔ 0.97 \n"
325  "val:-2 (33|25.00%)\n"
326  "val:-1 (49|23.44%)\n"
327  "val:+0 (00| 3.12%)\n"
328  "val:+1 (02|25.00%)\n"
329  "val:+2 (18|23.44%)\n"_expect);
330 
331 
332  draw.probability(0.75);
333  report = "+++| p ≔ 0.75 \n";
334  report += distribution(draw);
335  CHECK (report ==
336  "+++| p ≔ 0.75 \n"
337  "val:-2 (40|18.75%)\n"
338  "val:-1 (52|18.75%)\n"
339  "val:+0 (00|25.00%)\n"
340  "val:+1 (16|18.75%)\n"
341  "val:+2 (28|18.75%)\n"_expect);
342 
343 
344  draw.probability(0.5);
345  report = "+++| p ≔ 0.50 \n";
346  report += distribution(draw);
347  CHECK (report ==
348  "+++| p ≔ 0.50 \n"
349  "val:-2 (48|12.50%)\n"
350  "val:-1 (56|12.50%)\n"
351  "val:+0 (00|50.00%)\n"
352  "val:+1 (32|12.50%)\n"
353  "val:+2 (40|12.50%)\n"_expect);
354 
355 
356  draw.probability(0.2);
357  report = "+++| p ≔ 0.20 \n";
358  report += distribution(draw);
359  CHECK (report ==
360  "+++| p ≔ 0.20 \n"
361  "val:-2 (58| 4.69%)\n"
362  "val:-1 (61| 4.69%)\n"
363  "val:+0 (00|81.25%)\n"
364  "val:+1 (52| 4.69%)\n"
365  "val:+2 (55| 4.69%)\n"_expect);
366 
367 
368  draw.probability(0.1);
369  report = "+++| p ≔ 0.10 \n";
370  report += distribution(draw);
371  CHECK (report ==
372  "+++| p ≔ 0.10 \n"
373  "val:-2 (61| 3.12%)\n"
374  "val:-1 (63| 1.56%)\n"
375  "val:+0 (00|90.62%)\n"
376  "val:+1 (58| 3.12%)\n"
377  "val:+2 (60| 1.56%)\n"_expect);
378 
379 
380  // ══════════
381  draw.probability(1.0).shuffle(1);
382  CHECK (draw( 6) == +1); // 6*1
383  CHECK (draw( 6) == +1); // 6*2
384  CHECK (draw( 6) == +2); // 6*3
385  CHECK (draw( 6) == +2); // 6*4
386  CHECK (draw( 6) == +2); // 6*5
387  CHECK (draw( 6) == -2); // 6*6
388  CHECK (draw(16) == -1); // 16*7 %64 = 48
389  CHECK (draw(16) == +1); // 16*8 %64 = 0
390 
391  report = "+++| p ≔ 1.0 +shuffle \n";
392  report += distribution(draw);
393  CHECK (report ==
394  "+++| p ≔ 1.0 +shuffle \n"
395  "val:-2 (03|25.00%)\n"
396  "val:-1 (04|25.00%)\n"
397  "val:+0 (-1| 0.00%)\n"
398  "val:+1 (00|25.00%)\n"
399  "val:+2 (02|25.00%)\n"_expect);
400  draw.shuffle(0);
401  CHECK (draw(16) == +2); // shuffling disabled
402  CHECK (draw(16) == +2); // values reproducible
403  CHECK (draw(32) == -2);
404  CHECK (draw(32) == -2);
405  CHECK (draw(16) == +2);
406  CHECK (draw(16) == +2);
407 
408 
409 
410  // ═════════
411  draw.probability(0.5).maxVal(1);
412  CHECK (draw( 0) == 0);
413  CHECK (draw( 16) == 0);
414  CHECK (draw( 31) == 0);
415  CHECK (draw( 32) == +1);
416  CHECK (draw( 42) == +1);
417  CHECK (draw( 43) == -2);
418  CHECK (draw( 53) == -2);
419  CHECK (draw( 54) == -1);
420  CHECK (draw( 63) == -1);
421  CHECK (draw( 64) == 0);
422  CHECK (draw( 95) == 0);
423  CHECK (draw( 96) == +1);
424 
425  report = "+++| p ≔ 0.50 max ≔ 1 \n";
426  report += distribution(draw);
427  CHECK (report ==
428  "+++| p ≔ 0.50 max ≔ 1 \n"
429  "val:-2 (43|17.19%)\n"
430  "val:-1 (54|15.62%)\n"
431  "val:+0 (00|50.00%)\n"
432  "val:+1 (32|17.19%)\n"
433  "val:+2 (-1| 0.00%)\n"_expect);
434 
435 
436  draw.probability(1.0).maxVal(1);
437  CHECK (draw( 0) == +1);
438  CHECK (draw( 16) == +1);
439  CHECK (draw( 21) == +1);
440  CHECK (draw( 22) == -2);
441  CHECK (draw( 42) == -2);
442  CHECK (draw( 43) == -1);
443  CHECK (draw( 63) == -1);
444  CHECK (draw( 64) == +1);
445  CHECK (draw( 85) == +1);
446  CHECK (draw( 86) == -2);
447  CHECK (draw( 96) == -2);
448 
449  report = "+++| p ≔ 1.0 max ≔ 1 \n";
450  report += distribution(draw);
451  CHECK (report ==
452  "+++| p ≔ 1.0 max ≔ 1 \n"
453  "val:-2 (22|32.81%)\n"
454  "val:-1 (43|32.81%)\n"
455  "val:+0 (-1| 0.00%)\n"
456  "val:+1 (00|34.38%)\n"
457  "val:+2 (-1| 0.00%)\n"_expect);
458 
459 
460  // ═════════
461  draw.probability(0.5).maxVal(0);
462  CHECK (draw( 0) == 0);
463  CHECK (draw( 31) == 0);
464  CHECK (draw( 32) == -2);
465  CHECK (draw( 47) == -2);
466  CHECK (draw( 48) == -1);
467  CHECK (draw( 63) == -1);
468  CHECK (draw( 64) == 0);
469  CHECK (draw( 95) == 0);
470  CHECK (draw( 96) == -2);
471 
472  report = "+++| p ≔ 0.50 max ≔ 0 \n";
473  report += distribution(draw);
474  CHECK (report ==
475  "+++| p ≔ 0.50 max ≔ 0 \n"
476  "val:-2 (32|25.00%)\n"
477  "val:-1 (48|25.00%)\n"
478  "val:+0 (00|50.00%)\n"
479  "val:+1 (-1| 0.00%)\n"
480  "val:+2 (-1| 0.00%)\n"_expect);
481 
482 
483  draw.probability(1.0).maxVal(0);
484  CHECK (draw( 0) == -2);
485  CHECK (draw( 31) == -2);
486  CHECK (draw( 32) == -1);
487  CHECK (draw( 63) == -1);
488  CHECK (draw( 64) == -2);
489  CHECK (draw( 96) == -1);
490 
491  report = "+++| p ≔ 1.0 max ≔ 0 \n";
492  report += distribution(draw);
493  CHECK (report ==
494  "+++| p ≔ 1.0 max ≔ 0 \n"
495  "val:-2 (00|50.00%)\n"
496  "val:-1 (32|50.00%)\n"
497  "val:+0 (-1| 0.00%)\n"
498  "val:+1 (-1| 0.00%)\n"
499  "val:+2 (-1| 0.00%)\n"_expect);
500 
501 
502  // ═════════
503  draw.probability(0.5).maxVal(-1);
504  CHECK (draw( 32) == -2);
505  CHECK (draw( 47) == -2);
506  CHECK (draw( 48) == -1);
507  CHECK (draw( 63) == -1);
508  CHECK (draw( 64) == 0);
509  CHECK (draw( 95) == 0);
510  CHECK (draw( 96) == -2);
511 
512  report = "+++| p ≔ 0.50 max ≔ -1 \n";
513  report += distribution(draw);
514  CHECK (report ==
515  "+++| p ≔ 0.50 max ≔ -1 \n"
516  "val:-2 (32|25.00%)\n"
517  "val:-1 (48|25.00%)\n"
518  "val:+0 (00|50.00%)\n"
519  "val:+1 (-1| 0.00%)\n"
520  "val:+2 (-1| 0.00%)\n"_expect);
521 
522 
523  draw.probability(1.0).maxVal(-1);
524  CHECK (draw( 0) == -2);
525  CHECK (draw( 31) == -2);
526  CHECK (draw( 32) == -1);
527  CHECK (draw( 63) == -1);
528  CHECK (draw( 64) == -2);
529 
530  report = "+++| p ≔ 1.0 max ≔ -1 \n";
531  report += distribution(draw);
532  CHECK (report ==
533  "+++| p ≔ 1.0 max ≔ -1 \n"
534  "val:-2 (00|50.00%)\n"
535  "val:-1 (32|50.00%)\n"
536  "val:+0 (-1| 0.00%)\n"
537  "val:+1 (-1| 0.00%)\n"
538  "val:+2 (-1| 0.00%)\n"_expect);
539 
540 
541  // ═════════
542  draw.probability(0.5).maxVal(2).minVal(1);
543  CHECK (draw( 32) == +1);
544  CHECK (draw( 48) == +2);
545  CHECK (draw( 63) == +2);
546  CHECK (draw( 64) == 0);
547 
548  report = "+++| p ≔ 0.50 min ≔ 1 max ≔ 2 \n";
549  report += distribution(draw);
550  CHECK (report ==
551  "+++| p ≔ 0.50 min ≔ 1 max ≔ 2 \n"
552  "val:-2 (-1| 0.00%)\n"
553  "val:-1 (-1| 0.00%)\n"
554  "val:+0 (00|50.00%)\n"
555  "val:+1 (32|25.00%)\n"
556  "val:+2 (48|25.00%)\n"_expect);
557 
558 
559  draw.probability(1.0).maxVal(2).minVal(1);
560  CHECK (draw( 0) == +1);
561  CHECK (draw( 32) == +2);
562  CHECK (draw( 63) == +2);
563  CHECK (draw( 64) == +1);
564 
565  report = "+++| p ≔ 1.0 min ≔ 1 max ≔ 2 \n";
566  report += distribution(draw);
567  CHECK (report ==
568  "+++| p ≔ 1.0 min ≔ 1 max ≔ 2 \n"
569  "val:-2 (-1| 0.00%)\n"
570  "val:-1 (-1| 0.00%)\n"
571  "val:+0 (-1| 0.00%)\n"
572  "val:+1 (00|50.00%)\n"
573  "val:+2 (32|50.00%)\n"_expect);
574 
575 
576  // ═════════
577  draw.probability(0.5).maxVal(0);
578  CHECK (draw( 32) == -1);
579  CHECK (draw( 63) == -1);
580  CHECK (draw( 64) == 0);
581 
582  report = "+++| p ≔ 0.50 max ≔ 0 (-> min ≔ -1) \n";
583  report += distribution(draw);
584  CHECK (report ==
585  "+++| p ≔ 0.50 max ≔ 0 (-> min ≔ -1) \n"
586  "val:-2 (-1| 0.00%)\n"
587  "val:-1 (32|50.00%)\n"
588  "val:+0 (00|50.00%)\n"
589  "val:+1 (-1| 0.00%)\n"
590  "val:+2 (-1| 0.00%)\n"_expect);
591 
592 
593  // ═════════
594  draw.fixedVal(1);
595  report = "+++| fixedVal(1) \n";
596  report += distribution(draw);
597  CHECK (report ==
598  "+++| fixedVal(1) \n"
599  "val:-2 (-1| 0.00%)\n"
600  "val:-1 (-1| 0.00%)\n"
601  "val:+0 (-1| 0.00%)\n"
602  "val:+1 (00|100.00%)\n"
603  "val:+2 (-1| 0.00%)\n"_expect);
604  }
605 
606 
607 
617  void
619  {
620  // Note: no special Adapter required for the following function,
621  // since it takes the same arguments as our RandomDraw (size_t);
622  // moreover, since the function yields a double, the adapter scheme
623  // concludes that this function wants to feed directly into the
624  // primary mapping function RandomDraw::limited(double)
625  auto d1 = Draw([](size_t hash) -> double { return hash / 10.0; });
626  CHECK (d1( 0) == +1);
627  CHECK (d1( 1) == +1);
628  CHECK (d1( 2) == +1);
629  CHECK (d1( 3) == +2);
630  CHECK (d1( 4) == +2);
631  CHECK (d1( 5) == -2);
632  CHECK (d1( 6) == -2);
633  CHECK (d1( 7) == -2);
634  CHECK (d1( 8) == -1);
635  CHECK (d1( 9) == -1);
636  CHECK (d1(10) == 0);
637  CHECK (d1(11) == 0);
638  CHECK (d1(12) == 0);
639  CHECK (d1(13) == 0);
640 
641  d1.probability(0.4);
642  CHECK (d1( 0) == 0);
643  CHECK (d1( 1) == 0);
644  CHECK (d1( 2) == 0);
645  CHECK (d1( 3) == 0);
646  CHECK (d1( 4) == 0);
647  CHECK (d1( 5) == 0);
648  CHECK (d1( 6) == +1); // probability 0.4
649  CHECK (d1( 7) == +2);
650  CHECK (d1( 8) == -2);
651  CHECK (d1( 9) == -1);
652  CHECK (d1(10) == 0);
653 
654  d1.minVal(-1).probability(0.7);
655  CHECK (d1( 0) == 0);
656  CHECK (d1( 1) == 0);
657  CHECK (d1( 2) == 0);
658  CHECK (d1( 3) == 0);
659  CHECK (d1( 4) == +1); // probability 0.7
660  CHECK (d1( 5) == +1);
661  CHECK (d1( 6) == +2);
662  CHECK (d1( 7) == +2);
663  CHECK (d1( 8) == -1);
664  CHECK (d1( 9) == -1);
665  CHECK (d1(10) == 0);
666 
667  // The next example demonstrates accepting special input arguments;
668  // as defined in the policy, this function will get the `(div, mod)`
669  // of the hash with modulus 64
670  auto d2 = Draw([](uint cycle, uint rem){ return double(rem) / ((cycle+1)*5); });
671  CHECK (d2( 0) == +1);
672  CHECK (d2( 1) == +1);
673  CHECK (d2( 2) == +2);
674  CHECK (d2( 3) == -2);
675  CHECK (d2( 4) == -1); // the first cycle is only 5 steps long (0+1)*5
676  CHECK (d2( 5) == 0);
677  CHECK (d2( 6) == 0);
678  CHECK (d2( 7) == 0);
679  CHECK (d2( 8) == 0);
680  CHECK (d2( 9) == 0);
681  CHECK (d2(10) == 0);
682  CHECK (d2(63) == 0);
683  CHECK (d2(64) == +1); // the second cycle starts here...
684  CHECK (d2(65) == +1);
685  CHECK (d2(66) == +1);
686  CHECK (d2(67) == +2);
687  CHECK (d2(68) == +2);
688  CHECK (d2(69) == -2);
689  CHECK (d2(70) == -2);
690  CHECK (d2(71) == -2);
691  CHECK (d2(72) == -1);
692  CHECK (d2(73) == -1);
693  CHECK (d2(74) == 0); // and is 10 steps long (same pattern as in the first example above)
694  CHECK (d2(75) == 0);
695 
696  // The next example uses the other Adapter variant, which „sneaks in“ a context value
697  // Moreover, we can change the mapping function of an existing RandomDraw, as demonstrated here
698  d2.mapping([](size_t hash, double ctx){ return hash / ctx; });
699 
700  ctxParameter = 4.0;
701  CHECK (d2( 0) == +1);
702  CHECK (d2( 1) == +2);
703  CHECK (d2( 2) == -2);
704  CHECK (d2( 3) == -1); // cycle-length: 4
705  CHECK (d2( 4) == 0);
706  CHECK (d2( 5) == 0);
707  CHECK (d2( 6) == 0);
708  CHECK (d2( 7) == 0);
709  CHECK (d2( 8) == 0);
710  CHECK (d2( 9) == 0);
711  CHECK (d2(10) == 0);
712 
713  ctxParameter = 8.0;
714  CHECK (d2( 0) == +1);
715  CHECK (d2( 1) == +1);
716  CHECK (d2( 2) == +2);
717  CHECK (d2( 3) == +2);
718  CHECK (d2( 4) == -2);
719  CHECK (d2( 5) == -2);
720  CHECK (d2( 6) == -1);
721  CHECK (d2( 7) == -1); // cycle-length: 8
722  CHECK (d2( 8) == 0);
723  CHECK (d2( 9) == 0);
724  CHECK (d2(10) == 0);
725 
726  // and can of course dynamically tweak the mapping profile...
727  d2.maxVal(0).probability(0.5);
728  CHECK (d2( 0) == 0);
729  CHECK (d2( 1) == 0);
730  CHECK (d2( 2) == 0);
731  CHECK (d2( 3) == 0);
732  CHECK (d2( 4) == -2); // start here due to probability 0.5
733  CHECK (d2( 5) == -2);
734  CHECK (d2( 6) == -1);
735  CHECK (d2( 7) == -1); // cycle-length: 8
736  CHECK (d2( 8) == 0);
737  CHECK (d2( 9) == 0);
738  CHECK (d2(10) == 0);
739 
740  // NOTE: once a custom mapping function has been installed,
741  // the object can no longer be moved, due to reference binding.
742  VERIFY_ERROR (LIFECYCLE, Draw dx{move(d2)} );
743  }
744 
745 
746 
747 
751  void
753  {
754  auto d1 = Draw([](uint cycle, uint)
755  { // dynamically control probability
756  return Draw().probability((cycle+1)*0.25);
757  });
758 
759  CHECK (d1( 0) == 0);
760  CHECK (d1( 8) == 0);
761  CHECK (d1( 16) == 0);
762  CHECK (d1( 24) == 0);
763  CHECK (d1( 32) == 0);
764  CHECK (d1( 40) == 0);
765  CHECK (d1( 48) == 1); // 1st cycle: 25% probability
766  CHECK (d1( 56) == -2);
767  CHECK (d1( 63) == -1);
768  CHECK (d1( 64 +0) == 0);
769  CHECK (d1( 64 +8) == 0);
770  CHECK (d1( 64+16) == 0);
771  CHECK (d1( 64+24) == 0);
772  CHECK (d1( 64+32) == 1); // 2nd cycle: 50% probability
773  CHECK (d1( 64+40) == 2);
774  CHECK (d1( 64+48) == -2);
775  CHECK (d1( 64+56) == -1);
776  CHECK (d1( 64+63) == -1);
777  CHECK (d1(128 +0) == 0);
778  CHECK (d1(128 +8) == 0);
779  CHECK (d1(128 +16) == 1); // 3rd cycle: 75% probability
780  CHECK (d1(128 +24) == 1);
781  CHECK (d1(128 +32) == 2);
782  CHECK (d1(128 +40) == -2);
783  CHECK (d1(128 +48) == -2);
784  CHECK (d1(128 +56) == -1);
785  CHECK (d1(128 +63) == -1);
786  CHECK (d1(128+64 +0) == 1); // 4rth cycle: 100% probability
787  CHECK (d1(128+64 +8) == 1);
788  CHECK (d1(128+64+16) == 2);
789  CHECK (d1(128+64+24) == 2);
790  CHECK (d1(128+64+32) == -2);
791  CHECK (d1(128+64+40) == -2);
792  CHECK (d1(128+64+48) == -1);
793  CHECK (d1(128+64+56) == -1);
794  CHECK (d1(128+64+63) == -1);
795  CHECK (d1(128+64+64) == 1);
796  }
797  };
798 
799 
801  LAUNCHER (RandomDraw_test, "unit common");
802 
803 
804 }} // namespace lib::test
Definition: run.hpp:49
static size_t defaultSrc(size_t hash)
by default use the hash directly as source of randomness
Front-end for printf-style string template interpolation.
#define VERIFY_ERROR(ERROR_ID, ERRONEOUS_STATEMENT)
Macro to verify that a statement indeed raises an exception.
A front-end for using printf-style formatting.
Implementation namespace for support and library code.
A component and builder to draw limited parameter values based on some source of randomness (or hash ...
Simple test class runner.
A collection of frequently used helper functions to support unit testing.
Build a component to select limited values randomly.
typename _Fun< FUN >::Ret _FunRet
abbreviation for referring to a function&#39;s return type
Definition: function.hpp:196