Library: RandomDraw - adaptor and mapping functions

...the beautiful thing with functions and Metaprogramming is:
it mostly works as designed out of the box, once you make it
past the Compiler.
This commit is contained in:
Fischlurch 2023-11-22 04:26:22 +01:00
parent 2578df7c1d
commit 75cbfa8991
3 changed files with 214 additions and 45 deletions

View file

@ -162,7 +162,8 @@ namespace lib {
class RandomDraw
: public POL
{
using Fun = typename _Fun<POL>::Functor;
using Sig = typename _Fun<POL>::Sig;
using Fun = function<Sig>;
using Tar = typename _Fun<POL>::Ret;
Tar maxResult_{Tar::maxVal()}; ///< maximum result val actually to produce < max
@ -185,6 +186,8 @@ namespace lib {
double q = (1.0 - probability_);
if (val < q) // control probability of values ≠ neutral
return Tar::zeroVal();
if (val > 1.0)
val = 1.0;
val -= q; // [0 .. [q .. 1[
val /= probability_; // [0 .. 1[
auto org = Tar::zeroVal();
@ -239,7 +242,7 @@ namespace lib {
* Drawing is _disabled_ by default, always yielding "zero"
*/
RandomDraw()
: Fun{adaptOut(POL::defaultSrc)}
: POL{adaptOut(POL::defaultSrc)}
{ }
/**
@ -254,8 +257,8 @@ namespace lib {
*/
template<class FUN>
RandomDraw(FUN&& fun)
: probability_{1.0}
, Fun{adaptOut(adaptIn(std::forward<FUN> (fun)))}
: POL{adaptOut(adaptIn(std::forward<FUN> (fun)))}
, probability_{1.0}
{ }
@ -290,7 +293,8 @@ namespace lib {
RandomDraw&&
mapping (FUN&& fun)
{
Fun(*this) = adaptOut(adaptIn(std::forward<FUN> (fun)));
Fun& thisMapping = static_cast<Fun&> (*this);
thisMapping = adaptOut(adaptIn(std::forward<FUN> (fun)));
return move (*this);
}
@ -305,12 +309,19 @@ namespace lib {
decltype(auto)
adaptIn (FUN&& fun)
{
static_assert (lib::meta::_Fun<FUN>(), "Need something function-like.");
using _Fun = lib::meta::_Fun<FUN>;
static_assert (_Fun(), "Need something function-like.");
using Sig = typename lib::meta::_Fun<FUN>::Sig;
using Sig = typename _Fun::Sig;
using Args = typename _Fun::Args;
using BaseIn = typename lib::meta::_Fun<POL>::Args;
using Adaptor = typename POL::template Adaptor<Sig>;
return Adaptor::build (forward<FUN> (fun));
if constexpr (std::is_same_v<Args, BaseIn>)
// function accepts same arguments as this RandomDraw
return forward<FUN> (fun); // pass-through directly
else
return Adaptor::build (forward<FUN> (fun));
}
/** @internal adapt output side of a given function, allowing to handle it's results

View file

@ -46,7 +46,9 @@ namespace test{
namespace { // policy and configuration for test...
double ctxParameter = 1.0;
/**
* @note the test uses a rather elaborate result value setting
* - produces five distinct values
@ -67,28 +69,34 @@ namespace test{
static_assert (not sizeof(SIG), "Unable to adapt given functor.");
};
/** allow a mapping function rely on quantisation cycles */
template<typename RES>
struct Adaptor<RES(size_t)>
{
template<typename FUN>
static decltype(auto)
build (FUN&& fun)
{
return std::forward<FUN>(fun);
}
};
template<typename RES>
struct Adaptor<RES(void)>
struct Adaptor<RES(uint,uint)>
{
template<typename FUN>
static auto
build (FUN&& fun)
{
return [functor=std::forward<FUN>(fun)]
(size_t)
(size_t hash)
{
return functor();
return functor(uint(hash/64), uint(hash%64));
};
}
};
/** inject external contextual state into a mapping function */
template<typename RES>
struct Adaptor<RES(size_t, double)>
{
template<typename FUN>
static auto
build (FUN&& fun)
{
return [functor=std::forward<FUN>(fun)]
(size_t hash)
{
return functor(hash, ctxParameter);
};
}
};
@ -123,7 +131,7 @@ namespace test{
verify_policy();
verify_numerics();
verify_buildProfile();
verify_adaptMapping();
verify_dynamicChange();
}
@ -153,8 +161,8 @@ namespace test{
/** @test TODO verify configuration through policy template
* @todo WIP 11/23 🔁 define 🔁 implement
/** @test verify configuration through policy template
* @todo WIP 11/23 define implement
*/
void
verify_policy()
@ -549,13 +557,138 @@ namespace test{
/** @test TODO verify the Builder-API to define the profile of result values.
* @todo WIP 11/23 🔁 define implement
/** @test bind custom mapping transformation functions.
* - 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
* - 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.
* @todo WIP 11/23 define implement
*/
void
verify_buildProfile()
verify_adaptMapping()
{
UNIMPLEMENTED ("verify random number profile configuration");
// 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);
CHECK (d1( 4) == +1);
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);
CHECK (d2( 7) == -1); // cycle-length: 4
CHECK (d2( 8) == 0);
CHECK (d2( 9) == 0);
CHECK (d2(10) == 0);
}
@ -567,6 +700,30 @@ namespace test{
verify_dynamicChange()
{
UNIMPLEMENTED ("change the generation profile dynamically");
SHOW_EXPR(int(d2( 0)));
SHOW_EXPR(int(d2( 1)));
SHOW_EXPR(int(d2( 2)));
SHOW_EXPR(int(d2( 3)));
SHOW_EXPR(int(d2( 4)));
SHOW_EXPR(int(d2( 5)));
SHOW_EXPR(int(d2( 6)));
SHOW_EXPR(int(d2( 7)));
SHOW_EXPR(int(d2( 8)));
SHOW_EXPR(int(d2( 9)));
SHOW_EXPR(int(d2(10)));
SHOW_EXPR(int(d2(63)));
SHOW_EXPR(int(d2(64)));
SHOW_EXPR(int(d2(65)));
SHOW_EXPR(int(d2(66)));
SHOW_EXPR(int(d2(67)));
SHOW_EXPR(int(d2(68)));
SHOW_EXPR(int(d2(69)));
SHOW_EXPR(int(d2(70)));
SHOW_EXPR(int(d2(71)));
SHOW_EXPR(int(d2(72)));
SHOW_EXPR(int(d2(73)));
SHOW_EXPR(int(d2(74)));
SHOW_EXPR(int(d2(75)));
}
};

View file

@ -96626,8 +96626,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node COLOR="#338800" CREATED="1700491829216" ID="ID_1294373641" MODIFIED="1700502015751" TEXT="den Spec-Subtyp in RandomDraw integrieren">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1700491953800" ID="ID_75649548" MODIFIED="1700515755282" TEXT="Policy-Template einf&#xfc;hren">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1700491953800" ID="ID_75649548" MODIFIED="1700623416307" TEXT="Policy-Template einf&#xfc;hren">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1700513461881" ID="ID_1696400503" MODIFIED="1700513889095" TEXT="definiert den Basis-Funktionstyp"/>
<node COLOR="#435e98" CREATED="1700513505882" ID="ID_1225658406" MODIFIED="1700513889096" TEXT="definiert dar&#xfc;ber auch implizit den Ergebnistyp"/>
<node COLOR="#435e98" CREATED="1700513474582" ID="ID_1399385360" MODIFIED="1700513889096" TEXT="liefert spezielle Adapter f&#xfc;r alle unterst&#xfc;tzten Eingangs-Typen"/>
@ -96717,13 +96717,13 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1700542362630" ID="ID_730331755" MODIFIED="1700542375501" TEXT="mit speziellem Test ausleuchten...">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1700542362630" ID="ID_730331755" MODIFIED="1700623412095" TEXT="mit speziellem Test ausleuchten...">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1700542382819" ID="ID_1832228113" MODIFIED="1700574242519" TEXT="eine Policy die zwei Eingangs-Argumente nimmt">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700574245126" ID="ID_1720583823" MODIFIED="1700574258660" TEXT="Adaption von Manipulator-Funktionen">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1700574245126" ID="ID_1720583823" MODIFIED="1700623413497" TEXT="Adaption von Manipulator-Funktionen">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
@ -96958,21 +96958,22 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700491985219" ID="ID_460437503" MODIFIED="1700577836021" TEXT="Adaptierung restrukturieren">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1700491985219" ID="ID_460437503" MODIFIED="1700623393034" TEXT="Adaptierung restrukturieren">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1700577811739" ID="ID_1356052727" MODIFIED="1700615790193" TEXT="Konfigurations-DSL aufbauen">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1700577811739" ID="ID_1356052727" MODIFIED="1700623391805" TEXT="Konfigurations-DSL aufbauen">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1700615802219" ID="ID_1202526627" MODIFIED="1700615816505" TEXT="probability"/>
<node COLOR="#435e98" CREATED="1700615805467" ID="ID_1780693023" MODIFIED="1700615816505" TEXT="maxVal"/>
<node COLOR="#435e98" CREATED="1700615809354" ID="ID_664060947" MODIFIED="1700615816506" TEXT="minVal"/>
<node CREATED="1700615812738" ID="ID_1089110674" MODIFIED="1700615814517" TEXT="mapping"/>
<node COLOR="#435e98" CREATED="1700615812738" ID="ID_1089110674" MODIFIED="1700623389853" TEXT="mapping"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1700491877926" ID="ID_1958310493" MODIFIED="1700502021655" TEXT="Test zur Dokumentation">
<icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1700491902622" ID="ID_523469259" MODIFIED="1700615927608" TEXT="soll auch das Vorgehen zur Spezialisierung demonstrieren">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1700491902622" ID="ID_523469259" MODIFIED="1700623361146" TEXT="soll auch das Vorgehen zur Spezialisierung demonstrieren">
<icon BUILTIN="button_ok"/>
<node CREATED="1700623368176" ID="ID_1117750034" MODIFIED="1700623381554" TEXT="demonstriert Kontext-Parameter und Adapter"/>
<node CREATED="1700615879735" ID="ID_1206033672" MODIFIED="1700615946925" TEXT="verwende schon mal spezielle Ergebniswerte">
<arrowlink COLOR="#382e90" DESTINATION="ID_1803348383" ENDARROW="Default" ENDINCLINATION="131;-8;" ID="Arrow_ID_1166708502" STARTARROW="None" STARTINCLINATION="-7;7;"/>
</node>
@ -97054,8 +97055,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700501979956" ID="ID_571312425" MODIFIED="1700577970844" TEXT="Wirkung des Builder-API dokumentieren">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1700501979956" ID="ID_571312425" MODIFIED="1700617387689" TEXT="Wirkung des Builder-API dokumentieren">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1700501993218" ID="ID_271630234" MODIFIED="1700577970844" TEXT="dynamische Parametrisierung demonstrieren">
<icon BUILTIN="flag-yellow"/>