Formats for User-Designed Generators
To register a user-designed basic generator using
vslRegisterBrng
function, you need to pass the pointer
iBrng
to the integer-value implementation of the generator; the pointers
sBrng
and
dBrng
to the generator implementations for single and double precision values, respectively; and pass the pointer
InitStream
to the stream initialization routine. See recommendations below on defining such functions with input and output arguments. An example of the registration procedure for a user-designed generator can be found in the respective directory of VS examples.
The respective pointers are defined as follows:
typedef int(*InitStreamPtr)( int method, VSLStreamStatePtr stream, int n, const unsigned int params[] );
typedef int(*sBRngPtr)( VSLStreamStatePtr stream, int n, float r[], float a, float b );
typedef int(*dBRngPtr)( VSLStreamStatePtr stream, int n, double r[], double a, double b );
typedef int(*iBRngPtr)( VSLStreamStatePtr stream, int n, unsigned int r[] );
InitStream
int MyBrngInitStream( int method, VSLStreamStatePtr stream, int n, const unsigned int params[] ) { /* Initialize the stream */ ... } /* MyBrngInitStream */
Description
The initialization routine of a user-designed generator must initialize
stream
according to the specified initialization
method
, initial conditions
params
and the argument
n
. The value of
method
determines the initialization method to be used.
- Ifmethodis equal to1, the initialization is by the standard generation method, which must be supported by all basic generators. In this case the function assumes that thestreamstructure was not previously initialized. The value ofnis used as the actual number of 32-bit values passed as initial conditions throughparams. Note, that the situation when the actual number of initial conditions passed to the function is not sufficient to initialize the generator is not an error. Whenever it occurs, the basic generator must initialize the missing conditions using default settings.
- Ifmethodis equal to2, the generation is by the leapfrog method, wherenspecifies the number of computational nodes (independent streams). Here the function assumes that thestreamwas previously initialized by the standard generation method. In this caseparamscontains only one element, which identifies the computational node. If the generator does not support the leapfrog method, the function must return the error codeVSL_RNG_ERROR_LEAPFROG_UNSUPPORTED.
- Ifmethodis equal to3, the generation is by the block-splitting method. Same as above, thestreamis assumed to be previously initialized by the standard generation method;paramsis not used,nidentifies the number of skipped elements. If the generator does not support the block-splitting method, the function must return the error codeVSL_RNG_ERROR_SKIPAHEAD_UNSUPPORTED.
- Ifmethodis equal to4, the generation is by the advanced block-splitting method. The stream is assumed to be previously initialized by the standard generation method;paramsis converted toMKL_UINT64[]andnis used as actual number of 64-bit values inparams. If the generator does not support the advanced block-splitting method, the function must return the error codeVSL_RNG_ERROR_SKIPAHEADEX_UNSUPPORTED.
For a more detailed description of the leapfrog and the block-splitting methods, refer to the description of
vslLeapfrogStream
,
vslSkipAheadStream
, and
vslSkipAheadStreamEx
, respectively.
Stream state structure is individual for every generator. However, each structure has a number of fields that are the same for all the generators:
typedef struct { unsigned int Reserved1[2]; unsigned int Reserved2[2]; [fields specific for the given generator] } MyStreamState;
The fields
Reserved1
and
Reserved2
are reserved for private needs only, and must not be modified by the user. When including specific fields into the structure, follow the rules below:
- The fields must fully describe the current state of the generator. For example, the state of a linear congruential generator can be identified by only one initial condition;
- If the generator can use both the leapfrog and the block-splitting methods, additional fields should be introduced to identify the independent streams. For example, in, apart from the initial conditions, two more fields should be specified: the value of the multiplierLCG(a,c,m)aand the value of the increment (k).a-1)kc/(a-1
iBRng
int iMyBrng( VSLStreamStatePtr stream, int n, unsigned int r[] ) { int i; /* Loop variable */ /* Generating integer random numbers */ /* Pay attention to word size needed to store only random number */ for( i = 0; i < n; i++) { r[i] = ...; } /* Update stream state */ ... return errcode; } /* iMyBrng */
When using 64 and 128-bit generators, consider digit capacity to store the numbers to the random vector
r
correctly. For example, storing one 64-bit value requires two elements of
r
, the first to store the lower 32 bits and the second to store the higher 32 bits. Similarly, use 4 elements of
r
to store a 128-bit value.
sBRng
int sMyBrng( VSLStreamStatePtr stream, int n, float r[], float a, float b ) { int i; /* Loop variable */ /* Generating float (a,b) random numbers */ for ( i = 0; i < n; i++ ) { r[i] = ...; } /* Update stream state */ ... return errcode; } /* sMyBrng */
dBRng
int dMyBrng( VSLStreamStatePtr stream, int n, double r[], double a, double b ) { int i; /* Loop variable */ /* Generating double (a,b) random numbers */ for ( i = 0; i < n; i++ ) { r[i] = ...; } /* Update stream state */ ... return errcode; } /* dMyBrng */