2023-11-20 16:38:55 +01:00
|
|
|
|
/*
|
|
|
|
|
|
RandomDraw(Test) - verify the component builder for random selected values
|
|
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
Copyright (C)
|
|
|
|
|
|
2023, Hermann Vosseler <Ichthyostega@web.de>
|
2023-11-20 16:38:55 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
**Lumiera** is free software; you can redistribute it and/or modify it
|
|
|
|
|
|
under the terms of the GNU General Public License as published by the
|
|
|
|
|
|
Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
|
|
option) any later version. See the file COPYING for further details.
|
2023-11-20 16:38:55 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
* *****************************************************************/
|
2023-11-20 16:38:55 +01:00
|
|
|
|
|
|
|
|
|
|
/** @file random-draw-test.cpp
|
|
|
|
|
|
** unit test \ref RandomDraw_test
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/test/run.hpp"
|
|
|
|
|
|
#include "lib/random-draw.hpp"
|
2023-11-21 22:07:51 +01:00
|
|
|
|
#include "lib/format-string.hpp"
|
2023-11-23 02:42:02 +01:00
|
|
|
|
#include "lib/test/test-helper.hpp"
|
2023-11-20 16:38:55 +01:00
|
|
|
|
|
2023-11-21 22:07:51 +01:00
|
|
|
|
#include <array>
|
2023-11-20 16:38:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
|
namespace test{
|
|
|
|
|
|
|
2023-11-21 22:07:51 +01:00
|
|
|
|
using util::_Fmt;
|
2023-11-22 22:11:59 +01:00
|
|
|
|
using lib::meta::_FunRet;
|
2023-11-23 02:42:02 +01:00
|
|
|
|
using err::LUMIERA_ERROR_LIFECYCLE;
|
2023-11-20 16:38:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-11-22 02:36:34 +01:00
|
|
|
|
namespace { // policy and configuration for test...
|
2023-11-22 04:26:22 +01:00
|
|
|
|
|
|
|
|
|
|
double ctxParameter = 1.0;
|
|
|
|
|
|
|
2023-11-22 02:36:34 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* @note the test uses a rather elaborate result value setting
|
|
|
|
|
|
* - produces five distinct values
|
|
|
|
|
|
* - value range is symmetrical to origin
|
|
|
|
|
|
* - zero is defined as the _neutral value_
|
|
|
|
|
|
* - accepts a `size_t` hash value as basic input
|
|
|
|
|
|
*/
|
2023-11-20 21:05:18 +01:00
|
|
|
|
struct SymmetricFive
|
2023-11-21 22:07:51 +01:00
|
|
|
|
: function<Limited<int, 2,-2, 0>(size_t)>
|
2023-11-20 21:05:18 +01:00
|
|
|
|
{
|
2023-11-22 02:36:34 +01:00
|
|
|
|
/** by default use the hash directly as source of randomness */
|
2023-11-20 21:05:18 +01:00
|
|
|
|
static size_t defaultSrc (size_t hash) { return hash; }
|
|
|
|
|
|
|
2023-11-22 02:36:34 +01:00
|
|
|
|
/** Adaptor to handle further mapping functions */
|
2023-11-20 21:05:18 +01:00
|
|
|
|
template<class SIG>
|
|
|
|
|
|
struct Adaptor
|
|
|
|
|
|
{
|
|
|
|
|
|
static_assert (not sizeof(SIG), "Unable to adapt given functor.");
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2023-11-22 04:26:22 +01:00
|
|
|
|
/** allow a mapping function rely on quantisation cycles */
|
2023-11-20 21:05:18 +01:00
|
|
|
|
template<typename RES>
|
2023-11-22 04:26:22 +01:00
|
|
|
|
struct Adaptor<RES(uint,uint)>
|
2023-11-20 21:05:18 +01:00
|
|
|
|
{
|
|
|
|
|
|
template<typename FUN>
|
2023-11-22 04:26:22 +01:00
|
|
|
|
static auto
|
2023-11-20 21:05:18 +01:00
|
|
|
|
build (FUN&& fun)
|
|
|
|
|
|
{
|
2023-11-22 04:26:22 +01:00
|
|
|
|
return [functor=std::forward<FUN>(fun)]
|
2023-11-23 02:42:02 +01:00
|
|
|
|
(size_t hash) -> _FunRet<FUN>
|
2023-11-22 04:26:22 +01:00
|
|
|
|
{
|
|
|
|
|
|
return functor(uint(hash/64), uint(hash%64));
|
|
|
|
|
|
};
|
2023-11-20 21:05:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2023-11-22 04:26:22 +01:00
|
|
|
|
/** inject external contextual state into a mapping function */
|
2023-11-20 21:05:18 +01:00
|
|
|
|
template<typename RES>
|
2023-11-22 04:26:22 +01:00
|
|
|
|
struct Adaptor<RES(size_t, double)>
|
2023-11-20 21:05:18 +01:00
|
|
|
|
{
|
|
|
|
|
|
template<typename FUN>
|
|
|
|
|
|
static auto
|
|
|
|
|
|
build (FUN&& fun)
|
|
|
|
|
|
{
|
|
|
|
|
|
return [functor=std::forward<FUN>(fun)]
|
2023-11-22 22:11:59 +01:00
|
|
|
|
(size_t hash) -> _FunRet<FUN>
|
2023-11-20 21:05:18 +01:00
|
|
|
|
{
|
2023-11-22 04:26:22 +01:00
|
|
|
|
return functor(hash, ctxParameter);
|
2023-11-20 21:05:18 +01:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
2023-11-22 02:36:34 +01:00
|
|
|
|
//
|
|
|
|
|
|
}//(End) Test config
|
2023-11-20 16:38:55 +01:00
|
|
|
|
|
2023-11-20 21:05:18 +01:00
|
|
|
|
|
|
|
|
|
|
using Draw = RandomDraw<SymmetricFive>;
|
2023-11-20 16:38:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************************//**
|
|
|
|
|
|
* @test Verify a flexible builder for random-value generators; using a config template,
|
|
|
|
|
|
* these can be outfitted to use a suitable source of randomness and to produce
|
|
|
|
|
|
* values from a desired target type and limited range.
|
2023-11-22 02:36:34 +01:00
|
|
|
|
* - for this test, generated result values are ∈ [-2 .. 0 .. +2]
|
|
|
|
|
|
* - no actual randomness is used; rather a `size_t` challenge is
|
|
|
|
|
|
* sent in to verify precisely deterministic numeric results.
|
|
|
|
|
|
* @see random-draw.hpp
|
|
|
|
|
|
* @see vault::gear::TestChainLoad as usage example
|
|
|
|
|
|
* @see SchedulerStress_test
|
2023-11-20 16:38:55 +01:00
|
|
|
|
*/
|
|
|
|
|
|
class RandomDraw_test
|
|
|
|
|
|
: public Test
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
run (Arg)
|
|
|
|
|
|
{
|
|
|
|
|
|
simpleUse();
|
|
|
|
|
|
|
2023-11-20 21:05:18 +01:00
|
|
|
|
verify_policy();
|
2023-11-20 16:38:55 +01:00
|
|
|
|
verify_numerics();
|
2023-11-22 04:26:22 +01:00
|
|
|
|
verify_adaptMapping();
|
2023-11-20 16:38:55 +01:00
|
|
|
|
verify_dynamicChange();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-11-22 02:36:34 +01:00
|
|
|
|
/** @test demonstrate a basic usage scenario
|
2023-11-20 16:38:55 +01:00
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
simpleUse()
|
|
|
|
|
|
{
|
2023-11-20 18:44:51 +01:00
|
|
|
|
auto draw = Draw().probability(0.5);
|
2023-11-21 22:07:51 +01:00
|
|
|
|
CHECK (draw( 0) == 0);
|
|
|
|
|
|
CHECK (draw( 16) == 0);
|
|
|
|
|
|
CHECK (draw( 32) == 1);
|
|
|
|
|
|
CHECK (draw( 40) == 2);
|
|
|
|
|
|
CHECK (draw( 48) == -2);
|
|
|
|
|
|
CHECK (draw( 56) == -1);
|
2023-11-23 02:42:02 +01:00
|
|
|
|
CHECK (draw( 64) == 0); // values repeat after 64 steps
|
|
|
|
|
|
CHECK (draw( 95) == 0); // ~ half of each cycle yields the »neutral value«
|
2023-11-21 22:07:51 +01:00
|
|
|
|
CHECK (draw( 96) == 1);
|
|
|
|
|
|
CHECK (draw(127) == -1);
|
|
|
|
|
|
CHECK (draw(128) == 0);
|
|
|
|
|
|
CHECK (draw(168) == 2);
|
|
|
|
|
|
CHECK (draw(256) == 0);
|
2023-11-20 21:05:18 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-11-22 04:26:22 +01:00
|
|
|
|
/** @test verify configuration through policy template
|
2023-11-23 02:42:02 +01:00
|
|
|
|
* - use the default policy, which takes no input values,
|
|
|
|
|
|
* but rather directly generates a random number; in this
|
|
|
|
|
|
* case here, input values are ∈ [0 .. 5]
|
|
|
|
|
|
* - define another policy template, to produce char values,
|
|
|
|
|
|
* while always requiring two input data values `(char,uint)`;
|
|
|
|
|
|
* moreover, define the `defaultSrc()` directly to produce the
|
|
|
|
|
|
* raw mapping values (double) using a custom formula; the
|
|
|
|
|
|
* resulting RandomDraw instance is now a function with
|
|
|
|
|
|
* two input arguments, producing char values.
|
2023-11-20 21:05:18 +01:00
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
verify_policy()
|
|
|
|
|
|
{
|
2023-11-21 03:01:33 +01:00
|
|
|
|
auto d1 = RandomDraw<random_draw::LimitedRandomGenerate<5>>().probability(1.0);
|
|
|
|
|
|
uint v1 = d1();
|
|
|
|
|
|
CHECK (0 < v1 and v1 <=5);
|
|
|
|
|
|
|
|
|
|
|
|
struct SpecialPolicy
|
|
|
|
|
|
: function<Limited<char, 'Z','A'>(char,uint)>
|
|
|
|
|
|
{
|
|
|
|
|
|
static double defaultSrc (char b, uint off) { return fmod ((b-'A'+off)/double('Z'-'A'), 1.0); }
|
|
|
|
|
|
};
|
2023-11-23 02:42:02 +01:00
|
|
|
|
|
2023-11-21 03:01:33 +01:00
|
|
|
|
auto d2 = RandomDraw<SpecialPolicy>().probability(1.0);
|
|
|
|
|
|
CHECK (d2('A', 2) == 'D');
|
|
|
|
|
|
CHECK (d2('M',10) == 'X');
|
|
|
|
|
|
CHECK (d2('Y', 0) == 'Z');
|
|
|
|
|
|
CHECK (d2('Y',15) == 'P');
|
2023-11-20 16:38:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-11-23 02:42:02 +01:00
|
|
|
|
/** @test verify random number transformations.
|
2023-11-21 22:07:51 +01:00
|
|
|
|
* - use a Draw instance with result values `[-2..0..+2]`
|
|
|
|
|
|
* - values are evenly distributed within limits of quantisation
|
|
|
|
|
|
* - the probability parameter controls the amount of neutral results
|
2023-11-22 02:36:34 +01:00
|
|
|
|
* - maximum and minimum value settings will be respected
|
|
|
|
|
|
* - the interval [min..max] is independent from neutral value
|
|
|
|
|
|
* - probability defines the cases within [min..max] \ neutral
|
|
|
|
|
|
* - all other cases `q = 1 - p` will yield the neutral value
|
|
|
|
|
|
* - implausible max/min settings will be corrected automatically
|
2023-11-20 16:38:55 +01:00
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
verify_numerics()
|
|
|
|
|
|
{
|
2023-11-21 22:07:51 +01:00
|
|
|
|
auto distribution = [](Draw const& draw)
|
2023-11-23 02:42:02 +01:00
|
|
|
|
{ // investigate value distribution
|
2023-11-22 02:36:34 +01:00
|
|
|
|
using Arr = std::array<int,5>;
|
|
|
|
|
|
Arr step{-1,-1,-1,-1,-1};
|
2023-11-21 22:07:51 +01:00
|
|
|
|
Arr freq{0};
|
|
|
|
|
|
for (uint i=0; i<128; ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
int res = draw(i);
|
|
|
|
|
|
CHECK (-2 <= res and res <= +2);
|
|
|
|
|
|
int idx = res+2;
|
|
|
|
|
|
freq[idx] += 1;
|
2023-11-22 02:36:34 +01:00
|
|
|
|
if (step[idx] < 0)
|
2023-11-21 22:07:51 +01:00
|
|
|
|
step[idx] = i;
|
|
|
|
|
|
}
|
|
|
|
|
|
_Fmt line{"val:%+d (%02d|%5.2f%%)\n"};
|
|
|
|
|
|
string report;
|
|
|
|
|
|
for (int idx=0; idx<5; ++idx)
|
|
|
|
|
|
{
|
|
|
|
|
|
report += line % (idx-2) % step[idx] % (100.0*freq[idx]/128);
|
|
|
|
|
|
}
|
|
|
|
|
|
return report;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
auto draw = Draw();
|
|
|
|
|
|
string report{"+++| --empty-- \n"};
|
|
|
|
|
|
|
|
|
|
|
|
CHECK (draw( 0) == 0);
|
|
|
|
|
|
CHECK (draw( 32) == 0);
|
|
|
|
|
|
CHECK (draw( 96) == 0);
|
|
|
|
|
|
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| --empty-- \n"
|
2023-11-22 02:36:34 +01:00
|
|
|
|
"val:-2 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:-1 (-1| 0.00%)\n"
|
2023-11-21 22:07:51 +01:00
|
|
|
|
"val:+0 (00|100.00%)\n"
|
2023-11-22 02:36:34 +01:00
|
|
|
|
"val:+1 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+2 (-1| 0.00%)\n"_expect);
|
2023-11-21 22:07:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw.probability(1.0);
|
|
|
|
|
|
CHECK (draw( 0) == +1);
|
|
|
|
|
|
CHECK (draw( 15) == +1);
|
|
|
|
|
|
CHECK (draw( 16) == +2);
|
|
|
|
|
|
CHECK (draw( 31) == +2);
|
|
|
|
|
|
CHECK (draw( 32) == -2);
|
|
|
|
|
|
CHECK (draw( 47) == -2);
|
|
|
|
|
|
CHECK (draw( 48) == -1);
|
|
|
|
|
|
CHECK (draw( 63) == -1);
|
|
|
|
|
|
CHECK (draw( 64) == +1);
|
|
|
|
|
|
CHECK (draw( 96) == -2);
|
|
|
|
|
|
|
|
|
|
|
|
report = "+++| p ≔ 1.0 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 1.0 \n"
|
|
|
|
|
|
"val:-2 (32|25.00%)\n"
|
|
|
|
|
|
"val:-1 (48|25.00%)\n"
|
2023-11-22 02:36:34 +01:00
|
|
|
|
"val:+0 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+1 (00|25.00%)\n"
|
2023-11-21 22:07:51 +01:00
|
|
|
|
"val:+2 (16|25.00%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw.probability(0.99);
|
|
|
|
|
|
CHECK (draw( 0) == 0);
|
|
|
|
|
|
CHECK (draw( 1) == +1);
|
|
|
|
|
|
CHECK (draw( 16) == +1);
|
|
|
|
|
|
CHECK (draw( 17) == +2);
|
|
|
|
|
|
CHECK (draw( 32) == +2);
|
|
|
|
|
|
CHECK (draw( 33) == -2);
|
|
|
|
|
|
CHECK (draw( 48) == -2);
|
|
|
|
|
|
CHECK (draw( 49) == -1);
|
|
|
|
|
|
CHECK (draw( 63) == -1);
|
|
|
|
|
|
CHECK (draw( 64) == 0);
|
|
|
|
|
|
CHECK (draw( 65) == +1);
|
|
|
|
|
|
CHECK (draw( 80) == +1); // 64+16
|
|
|
|
|
|
CHECK (draw( 82) == +2); // 64+17
|
|
|
|
|
|
CHECK (draw( 97) == -2); // 64+33
|
|
|
|
|
|
CHECK (draw(352) == +2); // 64+32+256
|
|
|
|
|
|
CHECK (draw(353) == -2); // 64+33+256
|
|
|
|
|
|
|
|
|
|
|
|
report = "+++| p ≔ 0.99 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 0.99 \n"
|
|
|
|
|
|
"val:-2 (33|25.00%)\n"
|
|
|
|
|
|
"val:-1 (49|23.44%)\n"
|
|
|
|
|
|
"val:+0 (00| 1.56%)\n"
|
|
|
|
|
|
"val:+1 (01|25.00%)\n"
|
|
|
|
|
|
"val:+2 (17|25.00%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw.probability(0.98);
|
|
|
|
|
|
CHECK (draw( 0) == 0);
|
|
|
|
|
|
CHECK (draw( 1) == 0);
|
|
|
|
|
|
CHECK (draw( 2) == +1);
|
|
|
|
|
|
CHECK (draw( 63) == -1);
|
|
|
|
|
|
CHECK (draw( 64) == 0);
|
|
|
|
|
|
CHECK (draw( 65) == 0);
|
|
|
|
|
|
CHECK (draw( 66) == +1);
|
|
|
|
|
|
|
|
|
|
|
|
report = "+++| p ≔ 0.98 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 0.98 \n"
|
|
|
|
|
|
"val:-2 (33|25.00%)\n"
|
|
|
|
|
|
"val:-1 (49|23.44%)\n"
|
|
|
|
|
|
"val:+0 (00| 3.12%)\n"
|
|
|
|
|
|
"val:+1 (02|23.44%)\n"
|
|
|
|
|
|
"val:+2 (17|25.00%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw.probability(0.97);
|
|
|
|
|
|
report = "+++| p ≔ 0.97 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 0.97 \n"
|
|
|
|
|
|
"val:-2 (33|25.00%)\n"
|
|
|
|
|
|
"val:-1 (49|23.44%)\n"
|
|
|
|
|
|
"val:+0 (00| 3.12%)\n"
|
|
|
|
|
|
"val:+1 (02|25.00%)\n"
|
|
|
|
|
|
"val:+2 (18|23.44%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw.probability(0.75);
|
|
|
|
|
|
report = "+++| p ≔ 0.75 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 0.75 \n"
|
|
|
|
|
|
"val:-2 (40|18.75%)\n"
|
|
|
|
|
|
"val:-1 (52|18.75%)\n"
|
|
|
|
|
|
"val:+0 (00|25.00%)\n"
|
|
|
|
|
|
"val:+1 (16|18.75%)\n"
|
|
|
|
|
|
"val:+2 (28|18.75%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw.probability(0.5);
|
|
|
|
|
|
report = "+++| p ≔ 0.50 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 0.50 \n"
|
|
|
|
|
|
"val:-2 (48|12.50%)\n"
|
|
|
|
|
|
"val:-1 (56|12.50%)\n"
|
|
|
|
|
|
"val:+0 (00|50.00%)\n"
|
|
|
|
|
|
"val:+1 (32|12.50%)\n"
|
|
|
|
|
|
"val:+2 (40|12.50%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw.probability(0.2);
|
|
|
|
|
|
report = "+++| p ≔ 0.20 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 0.20 \n"
|
|
|
|
|
|
"val:-2 (58| 4.69%)\n"
|
|
|
|
|
|
"val:-1 (61| 4.69%)\n"
|
|
|
|
|
|
"val:+0 (00|81.25%)\n"
|
|
|
|
|
|
"val:+1 (52| 4.69%)\n"
|
|
|
|
|
|
"val:+2 (55| 4.69%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw.probability(0.1);
|
|
|
|
|
|
report = "+++| p ≔ 0.10 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 0.10 \n"
|
|
|
|
|
|
"val:-2 (61| 3.12%)\n"
|
|
|
|
|
|
"val:-1 (63| 1.56%)\n"
|
|
|
|
|
|
"val:+0 (00|90.62%)\n"
|
|
|
|
|
|
"val:+1 (58| 3.12%)\n"
|
|
|
|
|
|
"val:+2 (60| 1.56%)\n"_expect);
|
2023-11-22 02:36:34 +01:00
|
|
|
|
|
|
|
|
|
|
|
2023-11-26 19:46:48 +01:00
|
|
|
|
// ══════════
|
|
|
|
|
|
draw.probability(1.0).shuffle(1);
|
|
|
|
|
|
CHECK (draw( 6) == +1); // 6*1
|
|
|
|
|
|
CHECK (draw( 6) == +1); // 6*2
|
|
|
|
|
|
CHECK (draw( 6) == +2); // 6*3
|
|
|
|
|
|
CHECK (draw( 6) == +2); // 6*4
|
|
|
|
|
|
CHECK (draw( 6) == +2); // 6*5
|
|
|
|
|
|
CHECK (draw( 6) == -2); // 6*6
|
|
|
|
|
|
CHECK (draw(16) == -1); // 16*7 %64 = 48
|
|
|
|
|
|
CHECK (draw(16) == +1); // 16*8 %64 = 0
|
|
|
|
|
|
|
|
|
|
|
|
report = "+++| p ≔ 1.0 +shuffle \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 1.0 +shuffle \n"
|
|
|
|
|
|
"val:-2 (03|25.00%)\n"
|
|
|
|
|
|
"val:-1 (04|25.00%)\n"
|
|
|
|
|
|
"val:+0 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+1 (00|25.00%)\n"
|
|
|
|
|
|
"val:+2 (02|25.00%)\n"_expect);
|
|
|
|
|
|
draw.shuffle(0);
|
|
|
|
|
|
CHECK (draw(16) == +2); // shuffling disabled
|
|
|
|
|
|
CHECK (draw(16) == +2); // values reproducible
|
|
|
|
|
|
CHECK (draw(32) == -2);
|
|
|
|
|
|
CHECK (draw(32) == -2);
|
|
|
|
|
|
CHECK (draw(16) == +2);
|
|
|
|
|
|
CHECK (draw(16) == +2);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-11-22 02:36:34 +01:00
|
|
|
|
// ═════════
|
|
|
|
|
|
draw.probability(0.5).maxVal(1);
|
|
|
|
|
|
CHECK (draw( 0) == 0);
|
|
|
|
|
|
CHECK (draw( 16) == 0);
|
|
|
|
|
|
CHECK (draw( 31) == 0);
|
|
|
|
|
|
CHECK (draw( 32) == +1);
|
|
|
|
|
|
CHECK (draw( 42) == +1);
|
|
|
|
|
|
CHECK (draw( 43) == -2);
|
|
|
|
|
|
CHECK (draw( 53) == -2);
|
|
|
|
|
|
CHECK (draw( 54) == -1);
|
|
|
|
|
|
CHECK (draw( 63) == -1);
|
|
|
|
|
|
CHECK (draw( 64) == 0);
|
|
|
|
|
|
CHECK (draw( 95) == 0);
|
|
|
|
|
|
CHECK (draw( 96) == +1);
|
|
|
|
|
|
|
|
|
|
|
|
report = "+++| p ≔ 0.50 max ≔ 1 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 0.50 max ≔ 1 \n"
|
|
|
|
|
|
"val:-2 (43|17.19%)\n"
|
|
|
|
|
|
"val:-1 (54|15.62%)\n"
|
|
|
|
|
|
"val:+0 (00|50.00%)\n"
|
|
|
|
|
|
"val:+1 (32|17.19%)\n"
|
|
|
|
|
|
"val:+2 (-1| 0.00%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw.probability(1.0).maxVal(1);
|
|
|
|
|
|
CHECK (draw( 0) == +1);
|
|
|
|
|
|
CHECK (draw( 16) == +1);
|
|
|
|
|
|
CHECK (draw( 21) == +1);
|
|
|
|
|
|
CHECK (draw( 22) == -2);
|
|
|
|
|
|
CHECK (draw( 42) == -2);
|
|
|
|
|
|
CHECK (draw( 43) == -1);
|
|
|
|
|
|
CHECK (draw( 63) == -1);
|
|
|
|
|
|
CHECK (draw( 64) == +1);
|
|
|
|
|
|
CHECK (draw( 85) == +1);
|
|
|
|
|
|
CHECK (draw( 86) == -2);
|
|
|
|
|
|
CHECK (draw( 96) == -2);
|
|
|
|
|
|
|
|
|
|
|
|
report = "+++| p ≔ 1.0 max ≔ 1 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 1.0 max ≔ 1 \n"
|
|
|
|
|
|
"val:-2 (22|32.81%)\n"
|
|
|
|
|
|
"val:-1 (43|32.81%)\n"
|
|
|
|
|
|
"val:+0 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+1 (00|34.38%)\n"
|
|
|
|
|
|
"val:+2 (-1| 0.00%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ═════════
|
|
|
|
|
|
draw.probability(0.5).maxVal(0);
|
|
|
|
|
|
CHECK (draw( 0) == 0);
|
|
|
|
|
|
CHECK (draw( 31) == 0);
|
|
|
|
|
|
CHECK (draw( 32) == -2);
|
|
|
|
|
|
CHECK (draw( 47) == -2);
|
|
|
|
|
|
CHECK (draw( 48) == -1);
|
|
|
|
|
|
CHECK (draw( 63) == -1);
|
|
|
|
|
|
CHECK (draw( 64) == 0);
|
|
|
|
|
|
CHECK (draw( 95) == 0);
|
|
|
|
|
|
CHECK (draw( 96) == -2);
|
|
|
|
|
|
|
|
|
|
|
|
report = "+++| p ≔ 0.50 max ≔ 0 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 0.50 max ≔ 0 \n"
|
|
|
|
|
|
"val:-2 (32|25.00%)\n"
|
|
|
|
|
|
"val:-1 (48|25.00%)\n"
|
|
|
|
|
|
"val:+0 (00|50.00%)\n"
|
|
|
|
|
|
"val:+1 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+2 (-1| 0.00%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw.probability(1.0).maxVal(0);
|
|
|
|
|
|
CHECK (draw( 0) == -2);
|
|
|
|
|
|
CHECK (draw( 31) == -2);
|
|
|
|
|
|
CHECK (draw( 32) == -1);
|
|
|
|
|
|
CHECK (draw( 63) == -1);
|
|
|
|
|
|
CHECK (draw( 64) == -2);
|
|
|
|
|
|
CHECK (draw( 96) == -1);
|
|
|
|
|
|
|
|
|
|
|
|
report = "+++| p ≔ 1.0 max ≔ 0 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 1.0 max ≔ 0 \n"
|
|
|
|
|
|
"val:-2 (00|50.00%)\n"
|
|
|
|
|
|
"val:-1 (32|50.00%)\n"
|
|
|
|
|
|
"val:+0 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+1 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+2 (-1| 0.00%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ═════════
|
|
|
|
|
|
draw.probability(0.5).maxVal(-1);
|
|
|
|
|
|
CHECK (draw( 32) == -2);
|
|
|
|
|
|
CHECK (draw( 47) == -2);
|
|
|
|
|
|
CHECK (draw( 48) == -1);
|
|
|
|
|
|
CHECK (draw( 63) == -1);
|
|
|
|
|
|
CHECK (draw( 64) == 0);
|
|
|
|
|
|
CHECK (draw( 95) == 0);
|
|
|
|
|
|
CHECK (draw( 96) == -2);
|
|
|
|
|
|
|
|
|
|
|
|
report = "+++| p ≔ 0.50 max ≔ -1 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 0.50 max ≔ -1 \n"
|
|
|
|
|
|
"val:-2 (32|25.00%)\n"
|
|
|
|
|
|
"val:-1 (48|25.00%)\n"
|
|
|
|
|
|
"val:+0 (00|50.00%)\n"
|
|
|
|
|
|
"val:+1 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+2 (-1| 0.00%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw.probability(1.0).maxVal(-1);
|
|
|
|
|
|
CHECK (draw( 0) == -2);
|
|
|
|
|
|
CHECK (draw( 31) == -2);
|
|
|
|
|
|
CHECK (draw( 32) == -1);
|
|
|
|
|
|
CHECK (draw( 63) == -1);
|
|
|
|
|
|
CHECK (draw( 64) == -2);
|
|
|
|
|
|
|
|
|
|
|
|
report = "+++| p ≔ 1.0 max ≔ -1 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 1.0 max ≔ -1 \n"
|
|
|
|
|
|
"val:-2 (00|50.00%)\n"
|
|
|
|
|
|
"val:-1 (32|50.00%)\n"
|
|
|
|
|
|
"val:+0 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+1 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+2 (-1| 0.00%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ═════════
|
|
|
|
|
|
draw.probability(0.5).maxVal(2).minVal(1);
|
|
|
|
|
|
CHECK (draw( 32) == +1);
|
|
|
|
|
|
CHECK (draw( 48) == +2);
|
|
|
|
|
|
CHECK (draw( 63) == +2);
|
|
|
|
|
|
CHECK (draw( 64) == 0);
|
|
|
|
|
|
|
|
|
|
|
|
report = "+++| p ≔ 0.50 min ≔ 1 max ≔ 2 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 0.50 min ≔ 1 max ≔ 2 \n"
|
|
|
|
|
|
"val:-2 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:-1 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+0 (00|50.00%)\n"
|
|
|
|
|
|
"val:+1 (32|25.00%)\n"
|
|
|
|
|
|
"val:+2 (48|25.00%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draw.probability(1.0).maxVal(2).minVal(1);
|
|
|
|
|
|
CHECK (draw( 0) == +1);
|
|
|
|
|
|
CHECK (draw( 32) == +2);
|
|
|
|
|
|
CHECK (draw( 63) == +2);
|
|
|
|
|
|
CHECK (draw( 64) == +1);
|
|
|
|
|
|
|
|
|
|
|
|
report = "+++| p ≔ 1.0 min ≔ 1 max ≔ 2 \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 1.0 min ≔ 1 max ≔ 2 \n"
|
|
|
|
|
|
"val:-2 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:-1 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+0 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+1 (00|50.00%)\n"
|
|
|
|
|
|
"val:+2 (32|50.00%)\n"_expect);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ═════════
|
|
|
|
|
|
draw.probability(0.5).maxVal(0);
|
|
|
|
|
|
CHECK (draw( 32) == -1);
|
|
|
|
|
|
CHECK (draw( 63) == -1);
|
|
|
|
|
|
CHECK (draw( 64) == 0);
|
|
|
|
|
|
|
|
|
|
|
|
report = "+++| p ≔ 0.50 max ≔ 0 (-> min ≔ -1) \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| p ≔ 0.50 max ≔ 0 (-> min ≔ -1) \n"
|
|
|
|
|
|
"val:-2 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:-1 (32|50.00%)\n"
|
|
|
|
|
|
"val:+0 (00|50.00%)\n"
|
|
|
|
|
|
"val:+1 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+2 (-1| 0.00%)\n"_expect);
|
2023-11-30 03:20:23 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ═════════
|
|
|
|
|
|
draw.fixedVal(1);
|
|
|
|
|
|
report = "+++| fixedVal(1) \n";
|
|
|
|
|
|
report += distribution(draw);
|
|
|
|
|
|
CHECK (report ==
|
|
|
|
|
|
"+++| fixedVal(1) \n"
|
|
|
|
|
|
"val:-2 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:-1 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+0 (-1| 0.00%)\n"
|
|
|
|
|
|
"val:+1 (00|100.00%)\n"
|
|
|
|
|
|
"val:+2 (-1| 0.00%)\n"_expect);
|
2023-11-20 16:38:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-11-22 04:26:22 +01:00
|
|
|
|
/** @test bind custom mapping transformation functions.
|
2023-11-23 02:42:02 +01:00
|
|
|
|
* - use different translation into positional values
|
|
|
|
|
|
* as input for the actual result value mapping;
|
|
|
|
|
|
* - use a mapping function with different arguments,
|
|
|
|
|
|
* which is wired by the appropriate Adapter from the Policy;
|
2023-11-22 04:26:22 +01:00
|
|
|
|
* - moreover, the concrete Policy may tap into the context, which is
|
|
|
|
|
|
* demonstrated here by accessing a global variable. In practice,
|
|
|
|
|
|
* this capability allows to accept custom types as data source.
|
2023-11-20 18:44:51 +01:00
|
|
|
|
*/
|
|
|
|
|
|
void
|
2023-11-22 04:26:22 +01:00
|
|
|
|
verify_adaptMapping()
|
2023-11-20 18:44:51 +01:00
|
|
|
|
{
|
2023-11-22 04:26:22 +01:00
|
|
|
|
// Note: no special Adapter required for the following function,
|
|
|
|
|
|
// since it takes the same arguments as our RandomDraw (size_t);
|
|
|
|
|
|
// moreover, since the function yields a double, the adapter scheme
|
|
|
|
|
|
// concludes that this function wants to feed directly into the
|
|
|
|
|
|
// primary mapping function RandomDraw::limited(double)
|
|
|
|
|
|
auto d1 = Draw([](size_t hash) -> double { return hash / 10.0; });
|
|
|
|
|
|
CHECK (d1( 0) == +1);
|
|
|
|
|
|
CHECK (d1( 1) == +1);
|
|
|
|
|
|
CHECK (d1( 2) == +1);
|
|
|
|
|
|
CHECK (d1( 3) == +2);
|
|
|
|
|
|
CHECK (d1( 4) == +2);
|
|
|
|
|
|
CHECK (d1( 5) == -2);
|
|
|
|
|
|
CHECK (d1( 6) == -2);
|
|
|
|
|
|
CHECK (d1( 7) == -2);
|
|
|
|
|
|
CHECK (d1( 8) == -1);
|
|
|
|
|
|
CHECK (d1( 9) == -1);
|
|
|
|
|
|
CHECK (d1(10) == 0);
|
|
|
|
|
|
CHECK (d1(11) == 0);
|
|
|
|
|
|
CHECK (d1(12) == 0);
|
|
|
|
|
|
CHECK (d1(13) == 0);
|
|
|
|
|
|
|
|
|
|
|
|
d1.probability(0.4);
|
|
|
|
|
|
CHECK (d1( 0) == 0);
|
|
|
|
|
|
CHECK (d1( 1) == 0);
|
|
|
|
|
|
CHECK (d1( 2) == 0);
|
|
|
|
|
|
CHECK (d1( 3) == 0);
|
|
|
|
|
|
CHECK (d1( 4) == 0);
|
|
|
|
|
|
CHECK (d1( 5) == 0);
|
|
|
|
|
|
CHECK (d1( 6) == +1); // probability 0.4
|
|
|
|
|
|
CHECK (d1( 7) == +2);
|
|
|
|
|
|
CHECK (d1( 8) == -2);
|
|
|
|
|
|
CHECK (d1( 9) == -1);
|
|
|
|
|
|
CHECK (d1(10) == 0);
|
|
|
|
|
|
|
|
|
|
|
|
d1.minVal(-1).probability(0.7);
|
|
|
|
|
|
CHECK (d1( 0) == 0);
|
|
|
|
|
|
CHECK (d1( 1) == 0);
|
|
|
|
|
|
CHECK (d1( 2) == 0);
|
|
|
|
|
|
CHECK (d1( 3) == 0);
|
2023-11-23 02:42:02 +01:00
|
|
|
|
CHECK (d1( 4) == +1); // probability 0.7
|
2023-11-22 04:26:22 +01:00
|
|
|
|
CHECK (d1( 5) == +1);
|
|
|
|
|
|
CHECK (d1( 6) == +2);
|
|
|
|
|
|
CHECK (d1( 7) == +2);
|
|
|
|
|
|
CHECK (d1( 8) == -1);
|
|
|
|
|
|
CHECK (d1( 9) == -1);
|
|
|
|
|
|
CHECK (d1(10) == 0);
|
|
|
|
|
|
|
|
|
|
|
|
// The next example demonstrates accepting special input arguments;
|
|
|
|
|
|
// as defined in the policy, this function will get the `(div, mod)`
|
|
|
|
|
|
// of the hash with modulus 64
|
|
|
|
|
|
auto d2 = Draw([](uint cycle, uint rem){ return double(rem) / ((cycle+1)*5); });
|
|
|
|
|
|
CHECK (d2( 0) == +1);
|
|
|
|
|
|
CHECK (d2( 1) == +1);
|
|
|
|
|
|
CHECK (d2( 2) == +2);
|
|
|
|
|
|
CHECK (d2( 3) == -2);
|
|
|
|
|
|
CHECK (d2( 4) == -1); // the first cycle is only 5 steps long (0+1)*5
|
|
|
|
|
|
CHECK (d2( 5) == 0);
|
|
|
|
|
|
CHECK (d2( 6) == 0);
|
|
|
|
|
|
CHECK (d2( 7) == 0);
|
|
|
|
|
|
CHECK (d2( 8) == 0);
|
|
|
|
|
|
CHECK (d2( 9) == 0);
|
|
|
|
|
|
CHECK (d2(10) == 0);
|
|
|
|
|
|
CHECK (d2(63) == 0);
|
|
|
|
|
|
CHECK (d2(64) == +1); // the second cycle starts here...
|
|
|
|
|
|
CHECK (d2(65) == +1);
|
|
|
|
|
|
CHECK (d2(66) == +1);
|
|
|
|
|
|
CHECK (d2(67) == +2);
|
|
|
|
|
|
CHECK (d2(68) == +2);
|
|
|
|
|
|
CHECK (d2(69) == -2);
|
|
|
|
|
|
CHECK (d2(70) == -2);
|
|
|
|
|
|
CHECK (d2(71) == -2);
|
|
|
|
|
|
CHECK (d2(72) == -1);
|
|
|
|
|
|
CHECK (d2(73) == -1);
|
|
|
|
|
|
CHECK (d2(74) == 0); // and is 10 steps long (same pattern as in the first example above)
|
|
|
|
|
|
CHECK (d2(75) == 0);
|
|
|
|
|
|
|
|
|
|
|
|
// The next example uses the other Adapter variant, which „sneaks in“ a context value
|
|
|
|
|
|
// Moreover, we can change the mapping function of an existing RandomDraw, as demonstrated here
|
|
|
|
|
|
d2.mapping([](size_t hash, double ctx){ return hash / ctx; });
|
|
|
|
|
|
|
|
|
|
|
|
ctxParameter = 4.0;
|
|
|
|
|
|
CHECK (d2( 0) == +1);
|
|
|
|
|
|
CHECK (d2( 1) == +2);
|
|
|
|
|
|
CHECK (d2( 2) == -2);
|
|
|
|
|
|
CHECK (d2( 3) == -1); // cycle-length: 4
|
|
|
|
|
|
CHECK (d2( 4) == 0);
|
|
|
|
|
|
CHECK (d2( 5) == 0);
|
|
|
|
|
|
CHECK (d2( 6) == 0);
|
|
|
|
|
|
CHECK (d2( 7) == 0);
|
|
|
|
|
|
CHECK (d2( 8) == 0);
|
|
|
|
|
|
CHECK (d2( 9) == 0);
|
|
|
|
|
|
CHECK (d2(10) == 0);
|
|
|
|
|
|
|
|
|
|
|
|
ctxParameter = 8.0;
|
|
|
|
|
|
CHECK (d2( 0) == +1);
|
|
|
|
|
|
CHECK (d2( 1) == +1);
|
|
|
|
|
|
CHECK (d2( 2) == +2);
|
|
|
|
|
|
CHECK (d2( 3) == +2);
|
|
|
|
|
|
CHECK (d2( 4) == -2);
|
|
|
|
|
|
CHECK (d2( 5) == -2);
|
|
|
|
|
|
CHECK (d2( 6) == -1);
|
|
|
|
|
|
CHECK (d2( 7) == -1); // cycle-length: 8
|
|
|
|
|
|
CHECK (d2( 8) == 0);
|
|
|
|
|
|
CHECK (d2( 9) == 0);
|
|
|
|
|
|
CHECK (d2(10) == 0);
|
|
|
|
|
|
|
|
|
|
|
|
// and can of course dynamically tweak the mapping profile...
|
|
|
|
|
|
d2.maxVal(0).probability(0.5);
|
|
|
|
|
|
CHECK (d2( 0) == 0);
|
|
|
|
|
|
CHECK (d2( 1) == 0);
|
|
|
|
|
|
CHECK (d2( 2) == 0);
|
|
|
|
|
|
CHECK (d2( 3) == 0);
|
|
|
|
|
|
CHECK (d2( 4) == -2); // start here due to probability 0.5
|
|
|
|
|
|
CHECK (d2( 5) == -2);
|
|
|
|
|
|
CHECK (d2( 6) == -1);
|
2023-11-23 02:42:02 +01:00
|
|
|
|
CHECK (d2( 7) == -1); // cycle-length: 8
|
2023-11-22 04:26:22 +01:00
|
|
|
|
CHECK (d2( 8) == 0);
|
|
|
|
|
|
CHECK (d2( 9) == 0);
|
|
|
|
|
|
CHECK (d2(10) == 0);
|
2023-11-30 02:13:39 +01:00
|
|
|
|
|
|
|
|
|
|
// NOTE: once a custom mapping function has been installed,
|
|
|
|
|
|
// the object can no longer be moved, due to reference binding.
|
|
|
|
|
|
VERIFY_ERROR (LIFECYCLE, Draw dx{move(d2)} );
|
2023-11-20 18:44:51 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-11-22 22:11:59 +01:00
|
|
|
|
|
2023-11-30 02:13:39 +01:00
|
|
|
|
/** @test change the generation profile dynamically, based on current input;
|
2023-11-23 02:42:02 +01:00
|
|
|
|
* in the example here, the probability is manipulated in each cycle.
|
2023-11-20 16:38:55 +01:00
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
verify_dynamicChange()
|
|
|
|
|
|
{
|
2023-11-30 02:13:39 +01:00
|
|
|
|
auto d1 = Draw([](uint cycle, uint)
|
|
|
|
|
|
{ // dynamically control probability
|
|
|
|
|
|
return Draw().probability((cycle+1)*0.25);
|
2023-11-23 02:42:02 +01:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
CHECK (d1( 0) == 0);
|
|
|
|
|
|
CHECK (d1( 8) == 0);
|
|
|
|
|
|
CHECK (d1( 16) == 0);
|
|
|
|
|
|
CHECK (d1( 24) == 0);
|
|
|
|
|
|
CHECK (d1( 32) == 0);
|
|
|
|
|
|
CHECK (d1( 40) == 0);
|
|
|
|
|
|
CHECK (d1( 48) == 1); // 1st cycle: 25% probability
|
|
|
|
|
|
CHECK (d1( 56) == -2);
|
|
|
|
|
|
CHECK (d1( 63) == -1);
|
|
|
|
|
|
CHECK (d1( 64 +0) == 0);
|
|
|
|
|
|
CHECK (d1( 64 +8) == 0);
|
|
|
|
|
|
CHECK (d1( 64+16) == 0);
|
|
|
|
|
|
CHECK (d1( 64+24) == 0);
|
|
|
|
|
|
CHECK (d1( 64+32) == 1); // 2nd cycle: 50% probability
|
|
|
|
|
|
CHECK (d1( 64+40) == 2);
|
|
|
|
|
|
CHECK (d1( 64+48) == -2);
|
|
|
|
|
|
CHECK (d1( 64+56) == -1);
|
|
|
|
|
|
CHECK (d1( 64+63) == -1);
|
|
|
|
|
|
CHECK (d1(128 +0) == 0);
|
|
|
|
|
|
CHECK (d1(128 +8) == 0);
|
|
|
|
|
|
CHECK (d1(128 +16) == 1); // 3rd cycle: 75% probability
|
|
|
|
|
|
CHECK (d1(128 +24) == 1);
|
|
|
|
|
|
CHECK (d1(128 +32) == 2);
|
|
|
|
|
|
CHECK (d1(128 +40) == -2);
|
|
|
|
|
|
CHECK (d1(128 +48) == -2);
|
|
|
|
|
|
CHECK (d1(128 +56) == -1);
|
|
|
|
|
|
CHECK (d1(128 +63) == -1);
|
|
|
|
|
|
CHECK (d1(128+64 +0) == 1); // 4rth cycle: 100% probability
|
|
|
|
|
|
CHECK (d1(128+64 +8) == 1);
|
|
|
|
|
|
CHECK (d1(128+64+16) == 2);
|
|
|
|
|
|
CHECK (d1(128+64+24) == 2);
|
|
|
|
|
|
CHECK (d1(128+64+32) == -2);
|
|
|
|
|
|
CHECK (d1(128+64+40) == -2);
|
|
|
|
|
|
CHECK (d1(128+64+48) == -1);
|
|
|
|
|
|
CHECK (d1(128+64+56) == -1);
|
|
|
|
|
|
CHECK (d1(128+64+63) == -1);
|
|
|
|
|
|
CHECK (d1(128+64+64) == 1);
|
2023-11-20 16:38:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Register this test class... */
|
|
|
|
|
|
LAUNCHER (RandomDraw_test, "unit common");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}} // namespace lib::test
|