Lumiera 0.pre.04
»edit your freedom«
Loading...
Searching...
No Matches
random-draw.hpp
Go to the documentation of this file.
1/*
2 RANDOM-DRAW.hpp - randomly pick limited values
3
4 Copyright (C)
5 2023, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12*/
13
86#ifndef LIB_RANDOM_DRAW_H
87#define LIB_RANDOM_DRAW_H
88
89
90#include "lib/error.h"
91#include "lib/random.hpp"
92#include "lib/lazy-init.hpp"
93#include "lib/meta/function.hpp"
95#include "lib/util-quant.hpp"
96#include "lib/util.hpp"
97
98#include <functional>
99#include <utility>
100
101
102namespace lib {
103 namespace err = lumiera::error;
104
106 using lib::meta::_Fun;
107 using std::function;
108 using std::forward;
109 using std::move;
110
111
112
120 template<typename T, T max, T min =T(0), T zero =min>
121 struct Limited
122 {
123 static_assert (min < max);
124 static_assert (min <= zero and zero < max);
125
126 static constexpr T maxVal() { return max; }
127 static constexpr T minVal() { return min; }
128 static constexpr T zeroVal(){ return zero;}
129
131
132 template<typename X>
133 Limited (X raw)
134 : val(util::limited (X(minVal()), raw, X(maxVal())))
135 { }
136
137 operator T&()
138 {
139 return val;
140 }
141 operator T const&() const
142 {
143 return val;
144 }
145 };
146
147
148
149 namespace random_draw { // Policy definitions
150
155 template<uint max>
157 : function<Limited<uint, max>(void)>
158 {
159 static double defaultSrc() { return lib::defaultGen.uni(); }
160 };
161
162 }//(End)Policy definitions
163
164
165
166
167 /**********************************************************/
174 template<class POL>
176 : public LazyInit<POL>
177 {
179 using Disabled = Lazy::MarkDisabled;
180
182 using Fun = function<Sig>;
184
185 Tar maxResult_{Tar::maxVal()};
186 Tar minResult_{Tar::minVal()};
187 double probability_{0};
188 size_t shuffle_{0};
189
190
192 Tar
193 limited (double val)
194 {
195 if (probability_ == 0.0)
196 return Tar::zeroVal();
197 //
198 REQUIRE (Tar::minVal() <= minResult_);
199 REQUIRE (Tar::maxVal() >= maxResult_);
200 REQUIRE (minResult_ < maxResult_);
201 REQUIRE (0.0 <= probability_);
202 REQUIRE (probability_ <= 1.0);
203 double q = (1.0 - probability_);
204 if (val < q) // control probability of values ≠ neutral
205 return Tar::zeroVal();
206 if (val > 1.0)
207 val = 1.0;
208 val -= q; // [0 .. [q .. 1[
209 val /= probability_; // [0 .. 1[
210 auto org = Tar::zeroVal();
211 if (org == minResult_)
212 { // simple standard case
213 val *= maxResult_ - org; // [0 .. m[
214 val += org+1; // [1 .. m]
215 val += CAP_EPSILON; // round down yet absorb dust
216 return Tar{floor (val)};
217 }
218 else
219 if (org < minResult_ or org > maxResult_)
220 { // disjoint form origin, but compact
221 org = minResult_; // ensure all values covered
222 val *= maxResult_ - org + 1; // [o .. m]
223 val += org;
224 val += CAP_EPSILON;
225 return Tar{floor (val)};
226 }
227 else// Origin is somewhere within value range
228 {// ==> wrap "negative" part above max
229 // to map 0.0 ⟼ org (≙neutral)
230 val *= maxResult_ - minResult_;
231 val += org+1; // max inclusive but <0 ⟼ org
232 if (val >= maxResult_+1) // wrap the "negatives"
233 val -= maxResult_+1 - minResult_;
234 val += CAP_EPSILON;
235 return Tar{floor (val)};
236 }
237 } //----headroom to accommodate low probabilities
238 static constexpr size_t QUANTISER = 1 << 4 + util::ilog2 (Tar::maxVal()-Tar::minVal());
239 static constexpr double CAP_EPSILON = 1/(2.0 * QUANTISER);
240
241
243 double
244 asRand (size_t hash)
245 {
246 if (shuffle_)
247 hash *= shuffle_++;
248 return double(hash % QUANTISER) / QUANTISER;
249 }
250
252 Tar
253 drawLimited (size_t hash)
254 {
255 return limited (asRand (hash));
256 }
257
258
259 public:
264 : Lazy{Disabled()}
265 {
266 mapping (POL::defaultSrc);
267 }
268
278 template<class FUN, typename =disable_if_self<RandomDraw, FUN>>
279 RandomDraw(FUN&& fun)
280 : Lazy{Disabled()}
281 , probability_{1.0}
282 {
283 mapping (forward<FUN> (fun));
284 }
285
286
287
288 /* ===== Builder API ===== */
289
290 RandomDraw&&
291 probability (double p)
292 {
293 probability_ = util::limited (0.0, p ,1.0);
294 return move (*this);
295 }
296
297 RandomDraw&&
299 {
300 maxResult_ = util::min (m, Tar::maxVal());
302 minVal (--m);
303 return move (*this);
304 }
305
306 RandomDraw&&
308 {
309 minResult_ = util::max (m, Tar::minVal());
311 maxVal (++m);
312 return move (*this);
313 }
314
315 RandomDraw&&
316 shuffle (size_t seed =55)
317 {
318 shuffle_ = seed;
319 return move (*this);
320 }
321
322 RandomDraw&&
324 {
325 mapping ([v](size_t){ return v; });
326 return move (*this);
327 }
328
329 template<class FUN>
330 RandomDraw&&
331 mapping (FUN&& fun)
332 {
333 Fun& thisMapping = static_cast<Fun&> (*this);
334 Lazy::installInitialiser (thisMapping
335 ,[theFun = forward<FUN> (fun)]
336 (RandomDraw* self)
337 { // when lazy init is performed....
338 self->installAdapted (theFun);
339 });
340 return move (*this);
341 }
342
343
344
345
346 private:
348 template<class FUN>
349 void
350 installAdapted (FUN&& fun)
351 {
352 Fun& thisMapping = static_cast<Fun&> (*this);
353 thisMapping = adaptOut(adaptIn(std::forward<FUN> (fun)));
354 }
355
356
360 template<class FUN>
361 auto
362 adaptIn (FUN&& fun)
363 {
365 static_assert (_Fun(), "Need something function-like.");
366
367 using Sig = _Fun::Sig;
368 using Args = _Fun::Args;
369 using BaseIn = lib::meta::_Fun<POL>::Args;
370
371 if constexpr (std::is_same_v<Args, BaseIn>)
372 // function accepts same arguments as this RandomDraw
373 return forward<FUN> (fun); // pass-through directly
374 else
375 {// attempt to find a custom adaptor via Policy template
376 using Adaptor = POL::template Adaptor<Sig>;
377 return Adaptor::build (forward<FUN> (fun));
378 }
379 }
380
390 template<class FUN>
391 auto
392 adaptOut (FUN&& fun)
393 {
394 static_assert (lib::meta::_Fun<FUN>(), "Need something function-like.");
395
396 using Res = lib::meta::_Fun<FUN>::Ret;
398 using lib::meta::_FunRet;
399
400 if constexpr (std::is_same_v<Res, Tar>)// ◁──────────────────────────┨ function produces result directly
401 return std::forward<FUN>(fun);
402 else
403 if constexpr (std::is_same_v<Res, size_t>)// ◁───────────────────────┨ function yields random source to draw value
404 return chained (std::forward<FUN>(fun)
405 ,[this](size_t hash){ return drawLimited(hash); }
406 );
407 else
408 if constexpr (std::is_same_v<Res, double>)// ◁───────────────────────┨ function yields mapping value to be quantised
409 return chained (std::forward<FUN>(fun)
410 ,[this](double rand){ return limited(rand); }
411 );
412 else
413 if constexpr (std::is_same_v<Res, RandomDraw>) // ◁───────────────────┨ RandomDraw with dynamically adjusted parameters
414 return [functor=std::forward<FUN>(fun)]
415 (auto&& ...inArgs) -> _FunRet<RandomDraw>
416 { // invoke manipulator with copy
417 RandomDraw adaptedDraw = functor(inArgs...);
418 return adaptedDraw (forward<decltype(inArgs)> (inArgs)...);
419 }; // forward arguments to mapping-fun
420 else
421 static_assert (not sizeof(Res), "unable to adapt / handle result type");
422 NOTREACHED("Handle based on return type");
423 }
424 };
425
426
427} // namespace lib
428#endif /*LIB_RANDOM_DRAW_H*/
Mix-in for lazy/delayed initialisation of an embedded functor.
void installInitialiser(std::function< SIG > &targetFunctor, INI &&initialiser)
A component and builder to draw limited parameter values based on some source of randomness (or hash ...
_Fun< POL >::Sig Sig
Tar limited(double val)
RandomDraw()
Drawing is disabled by default, always yielding "zero".
auto adaptOut(FUN &&fun)
static constexpr size_t QUANTISER
double asRand(size_t hash)
RandomDraw && fixedVal(Tar v)
function< Sig > Fun
RandomDraw && shuffle(size_t seed=55)
RandomDraw && maxVal(Tar m)
_Fun< POL >::Ret Tar
RandomDraw(FUN &&fun)
Build a RandomDraw by attaching a value-processing function, which is adapted to accept the nominal i...
Tar drawLimited(size_t hash)
void installAdapted(FUN &&fun)
Lazy::MarkDisabled Disabled
RandomDraw && mapping(FUN &&fun)
Tar maxResult_
maximum result val actually to produce < max
RandomDraw && minVal(Tar m)
Tar minResult_
minimum result val actually to produce > min
RandomDraw && probability(double p)
double probability_
probability that value is in [min .. max] \ neutral
static constexpr double CAP_EPSILON
auto adaptIn(FUN &&fun)
size_t shuffle_
statefull additional randomisation to inject into hash
double uni()
random double drawn from interval [0.0 ... 1.0[
Definition random.hpp:232
Lumiera error handling (C interface).
Partial function application and building a complete function closure.
Metaprogramming tools for detecting and transforming function types.
#define hash
Building block to allow delayed initialisation of infrastructure tied to a functor.
auto chained(FUN1 &&f1, FUN2 &&f2)
build a functor chaining the given functions: feed the result of f1 into f2.
disable_if< std::is_same< std::remove_cv_t< std::remove_reference_t< extractFirst_t< ARGS... > > >, SELF > > disable_if_self
helper to prevent a template constructor from shadowing inherited copy ctors
_Fun< FUN >::Ret _FunRet
abbreviation for referring to a function's return type
Definition function.hpp:253
enable_if_c< Cond::value, T >::type enable_if
SFINAE helper to control the visibility of specialisations and overloads.
Definition meta/util.hpp:87
Implementation namespace for support and library code.
Random defaultGen
a global default RandomSequencer for mundane purposes
Definition random.cpp:70
constexpr int ilog2(I num)
Integral binary logarithm (disregarding fractional part)
auto max(IT &&elms)
constexpr NUM limited(NB lowerBound, NUM val, NB upperBound)
force a numeric to be within bounds, inclusively
Definition util.hpp:91
auto min(IT &&elms)
Generating (pseudo) random numbers with controlled seed.
A Result Value confined into fixed bounds.
static constexpr T minVal()
static constexpr T zeroVal()
static constexpr T maxVal()
Trait template for uniform access to function signature types.
Definition function.hpp:144
Default policy for RandomDraw: generate limted-range random numbers.
Utilities for quantisation (grid alignment) and comparisons.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...