Lumiera
0.pre.03
»edit your freedom«
|
Go to the source code of this file.
Build a component to select limited values randomly.
Generally speaking, RandomDraw uses some suitable source of randomness to "draw" a result value with a limited target domain. The intended usage scenario is to parametrise some configuration or computation »randomly«, with well defined probabilities and value ranges. A DSL is provided to simplify the common configuration and value mapping scenarios.
TestChainLoad; there, random numbers are derived from node hash values and must be mapped to yield control parameters governing the topology of a DAG datastructure. Notably, a draw is performed on each step to decide if the graph should fork. While numerically simple, this turned out to be rather error-prone, and resulting code is dense and difficult to understand, hence the desire to wrap it into a library component.
RandomDraw inherits from a policy template, which in turn is-a std::function. The signature of this function defines the input to work on; its output is assumed to be some variation of a »limited value«. Notably, results are assumed to conform to an ordered interval of integral values. The core functionality is to use the value from the random source (a size_t
hash), break it down by some modulus to create an arbitrary selection, followed by mapping this drawn value into the target value range. This mapping allows to discard some of the possible drawn values however — which equates to define a probability of producing a result different than "zero" (the neutral value of the result range). Moreover, the actual value mapping can be limited and configured within the confines of the target type.
Additional flexibility can be gained by binding a functor, thereby defining further mapping and transformations. A wide array of function signatures can be accepted, as long as it is possible somehow to adapt those functions to conform to the overall scheme as defined by the Policy base. Such a mapping function can be given directly at construction, or it can be set up later through the configuration DSL. As a special twist, it is even possible to change parameters dynamically, based on the current input value. This requires the mapping function to construct a pristine instance of RandomDraw, apply configuration based on the input and then return this instance by value — without ever »engaging« and invoking; this dynamically configured instance will then be invoked once, passing the current input values to yield the result value.
For practical use, the RandomDraw template must be instantiated with a custom provided policy template. This configuration allows to attach to locally defined types and facilities. The policy template is assumed to conform to the following requirements:
minVal()
, maxVal()
and zeroVal()
defaultSrc(args...)
; this function must accept input arguments in accordance to the function signature of the Policy (i.e. it must read "the randomness source") and produce a result that can be adapted and fed into the regular processing chain (the same as for any mapping function)Adaptor<Sig>
, possibly with specialisations for various function signatures. These adaptors are used to conform any mapping function and thus allow to simplify or widen the possible configurations at usage site.The configuration of the RandomDraw processing pipeline makes heavy use of function composition and adaptation to handle a wide selection of input types and usage patterns. Unfortunately this requires to like the generated configuration-λ to the object instance (capturing by reference); not allowing this would severely limit the possible configurations. This implies that an object instance must not be moved anymore, once the processing pipeline has been configured. And this in turn would severely limit it's usage in a DSL. As a compromise, RandomDraw relies on lazy on-demand initialisation: as long as the processing function has not been invoked, the internal pipeline is unconfigured, and the object can be moved and copied. Once invoked, the prepared configuration is assembled and the function »engaged«; from this point on, any attempt to move or copy the object will throw an exception, while it is still possible to assign other RandomDraw instances to this object.
Definition in file random-draw.hpp.
#include "lib/error.h"
#include "lib/lazy-init.hpp"
#include "lib/meta/function.hpp"
#include "lib/meta/function-closure.hpp"
#include "lib/util-quant.hpp"
#include "lib/util.hpp"
#include <functional>
#include <utility>
Classes | |
struct | Limited< T, max, min, zero > |
A Result Value confined into fixed bounds. More... | |
struct | LimitedRandomGenerate< max > |
Default policy for RandomDraw: generate limted-range random numbers. More... | |
class | RandomDraw< POL > |
A component and builder to draw limited parameter values based on some source of randomness (or hash input). More... | |
Namespaces | |
lib | |
Implementation namespace for support and library code. | |