.. default-domain:: chpl .. module:: NPBRandom :synopsis: NAS Parallel Benchmark Random Number Generator. NPBRandom ========= **Usage** .. code-block:: chapel use NPBRandom; or .. code-block:: chapel import NPBRandom; .. warning:: The 'NPBRandom' module is unstable and subject to change NAS Parallel Benchmark Random Number Generator. The pseudorandom number generator (PRNG) implemented by this module uses the algorithm from the NAS Parallel Benchmarks (NPB, available at: https://www.nas.nasa.gov/publications/npb.html which can be used to generate random values of type `real(64)`, `imag(64)`, and `complex(128)`. Paraphrasing the comments from the NPB reference implementation: This generator returns uniform pseudorandom real values in the range (0, 1) by using the linear congruential generator `x_{k+1} = a x_k (mod 2**46)` where 0 < x_k < 2**46 and 0 < a < 2**46. This scheme generates 2**44 numbers before repeating. The generated values are normalized to be between 0 and 1, i.e., 2**(-46) * x_k. This generator should produce the same results on any computer with at least 48 mantissa bits for `real(64)` data. To generate `complex` elements, consecutive pairs of random numbers are assigned to the real and imaginary components, respectively. The values generated by this NPB RNG do not include 0.0 and 1.0. We have tested this implementation with TestU01 (available at http://simul.iro.umontreal.ca/testu01/tu01.html ). In our experiments with TestU01 1.2.3 and the Crush suite (which consists of 144 statistical tests), this NPB RNG failed 41/144 tests. As a linear congruential generator, this RNG has known statistical problems that TestU01 was able to detect. .. note:: This module is currently restricted to generating `real(64)`, `imag(64)`, and `complex(128)` complex values. .. function:: proc oddTimeSeed(): int(64) Generate an odd integer seed value based on the current time. .. function:: proc fillRandom(ref arr: [] ?t, seed: int) where isRealOrComplexType(t) && arr.isRectangular() Fill a rectangular array of numeric values with pseudorandom values in parallel using a new :class:`NPBRandomStream`. The first `arr.size` values from the stream will be assigned to the array's elements in row-major order. The parallelization strategy is determined by the array. :arg arr: An array of numeric values :arg seed: The seed to use to create the ``NPBRandomStream`` .. function:: proc fillRandom(ref arr: [] ?t) where isRealOrComplexType(t) && arr.isRectangular() Fill a rectangular array of numeric values with pseudorandom values in parallel using a new :class:`NPBRandomStream`. The first `arr.size` values from the stream will be assigned to the array's elements in row-major order. The parallelization strategy is determined by the array. .. note:: a seed will be generated in an implementation specific manner that depends on the current time. :arg arr: An array of numeric values .. class:: NPBRandomStream : writeSerializable Models a stream of pseudorandom numbers. See the module-level notes for :mod:`NPBRandom` for details on the PRNG used. .. attribute:: type eltType = real(64) Specifies the type of value generated by the NPBRandomStream. Currently, only `real(64)`, `imag(64)`, and `complex(128)` are supported. .. attribute:: const seed: int(64) The seed value for the PRNG. It must be an odd integer in the interval [1, 2**46). .. attribute:: param parSafe: bool = true Indicates whether or not the NPBRandomStream needs to be parallel-safe by default. If multiple tasks interact with it in an uncoordinated fashion, this must be set to `true`. If it will only be called from a single task, or if only one task will call into it at a time, setting to `false` will reduce overhead related to ensuring mutual exclusion. .. method:: proc init(type eltType = real(64), seed: int(64) = oddTimeSeed(), param parSafe: bool = true) Creates a new stream of random numbers using the specified seed and parallel safety. .. note:: The NPB generator requires an odd seed value. Constructing an NPBRandomStream with an even seed value will cause a call to halt(). Only the lower 46 bits of the seed will be used. :arg eltType: The element type to be generated. :type eltType: `type` :arg seed: The seed to use for the RNG. Defaults to a value based on the current time. :type seed: `int(64)` :arg parSafe: The parallel safety setting. Defaults to `true`. :type parSafe: `bool` .. method:: proc getNext(): eltType Returns the next value in the random stream. Real numbers generated by the NPB RNG are in (0,1). It is not possible for this particular RNG to generate 0.0 or 1.0. :returns: The next value in the random stream as type :type:`eltType`. .. method:: proc skipToNth(n: integral) throws Advances/rewinds the stream to the `n`-th value in the sequence. The first value corresponds to n=0. n must be >= 0, otherwise an IllegalArgumentError is thrown. :arg n: The position in the stream to skip to. Must be >= 0. :type n: `integral` :throws IllegalArgumentError: When called with negative `n` value. .. method:: proc getNth(n: integral): eltType throws Advance/rewind the stream to the `n`-th value and return it (advancing the stream by one). n must be >= 0, otherwise an IllegalArgumentError is thrown. This is equivalent to :proc:`skipToNth()` followed by :proc:`getNext()`. :arg n: The position in the stream to skip to. Must be >= 0. :type n: `integral` :returns: The `n`-th value in the random stream as type :type:`eltType`. :throws IllegalArgumentError: When called with negative `n` value. .. method:: proc fillRandom(ref arr: [] eltType) Fill the argument array with pseudorandom values. This method is identical to the standalone :proc:`~Random.fillRandom` procedure, except that it consumes random values from the :class:`NPBRandomStream` object on which it's invoked rather than creating a new stream for the purpose of the call. :arg arr: The array to be filled :type arr: [] :type:`eltType` .. method:: proc iterate(D: domain, type resultType = real) Returns an iterable expression for generating `D.size` random numbers. The RNG state will be immediately advanced by `D.size` before the iterable expression yields any values. The returned iterable expression is useful in parallel contexts, including standalone and zippered iteration. The domain will determine the parallelization strategy. :arg D: a domain :arg resultType: the type of number to yield :return: an iterable expression yielding random `resultType` values