Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rand: Reorganize random: Phase 1 #5143

Merged
merged 48 commits into from Jun 1, 2020
Merged

rand: Reorganize random: Phase 1 #5143

merged 48 commits into from Jun 1, 2020

Conversation

hungrybluedev
Copy link
Member

@hungrybluedev hungrybluedev commented May 31, 2020

Phase 1 out of 3: Introduction of RNG structs

This three phase project is a reorganization of the rand module currently present in vlib.

The first phase aims to include portable RNG implementations, impose a structure for all generators, and still allow access to the default RNG provided by libc via SysRNG.

What changes does it bring?

  1. Defines a standard model to follow for all Random Number Generators (RNGs).
    • The system_rng.v and splitmix64.v files contain reference implementations for RNGs.
    • The corresponding system_rng_test.v and splitmix64_test.v contain uniformity, variability, reproducibility, and range checks that must pass as a bare minimum.
  2. Improved wrapping of the C.rand() function with the SysRNG struct.
  3. A default generator is accessible for users who do not want to think about what generator they want.
    • They can simply do rng := rand.new_default({}) with an optional seed parameter. (Note that {} is a configuration struct. See the main documentation for the details on how to use short-hand syntax.)
    • If no seed is provided, the default RNG will be time seeded. Users can also use time seeding by doing: seed_data := rand.time_seed_array(1) // or however many u32s you need
  4. If the user doesn't want to declare a separate rng variable, and they want to use the functions directly, they can do so:
    • All methods defined on the RNGs will be accessible as module level functions.
    • A user can simply do: value := rand.intn(100).
    • If they have a generator rng, they can equivalently do: value := rng.intn(100)

Generators added

  • SysRNG - default RNG wrapping the libc implementation.
  • SplitMix64RNG - 64-bit version of the Split-Mix algorithm
  • MT19937RNG - 64-bit version of the Mersenne Prime Twister
  • WyRandRNG - 64-bit RNG using the wyhash module.
  • PCG32RNG - 32-bit RNG using the PCG 32 algorithm
  • MuslRNG - 32-bit RNG using the implementation provided in musl-libc. Intended to replace rand_r

The standard API for all RNGs in V

  1. All RNGs are defined as mutable structs with an RNG suffix in the name.
    • For example: SysRNG, SplitMix64RNG, etc.
  2. All RNGs are guaranteed to have the following functions:
    • rng.seed(seed_data) - where seed_data is a []u32 array containing the 32bit chunks in little endian format (i.e. lower order first). It will mutate the internal state of the RNGs and cause the generated sequence to change. Reproducibility of the sequences with the corresponding seeds is guaranteed.
    • rng.u32() and rng.u64() - these functions will return uniformly distributed 32-bit and 64-bit unsigned integers respectively.
    • rng.int() and rng.i64() - the signed counterparts of the previous two functions; return int and i64, correspondingly.
    • rng.int31() and rng.int63() - will generate 31 and 63 bits of signed data as int and i64, respectively.
    • rng.u32n(max), rng.intn(max), rng.i64n(max), and rng.u64n(max) - return integers uniformly distributed in [0, max) (i.e. 0 inclusive and max exclusive).
    • rng.{type}_in_range(min, max) for same types as above (u32, int, u64, and i64) - return integers uniformly distributed in [min, max).
    • rng.f32() and rng.f64() - for floating point values of the corresponding type. They will be uniformly distributed in [0.0, 1.0)
    • f32n(max), f64n(max), f32_in_range(min, max) and f64_in_range(min, max) - floating point counterparts to the integer functions.
  3. All methods described above can also be called from the rand package directly, except for seeding the default RNG.
    • The user is instructed to use rng := rand.new_default({seed: seed_data}) to use the default RNG type with a custom seed.
    • This rng can be re-seeded with rng.seed(seed_data) later.

What it does not bring? (i.e. TODO)

Remaining for phase 2

  1. Remove old functions that are deprecated in phase 1.
  2. Modify the codebase to update any references to old deprecated functions.
  3. Possibly add XoroshiroRNG

Remaining for phase 3

  1. Add functions for non-uniform distributions like normal, exponential, beta, gamma, etc.
  2. Support for utility functions like shuffle. perm, etc.
  3. Bernoulli trial, i.e. obtaining true with a probability of p in [0.0, 1.0), and other functions. (Suggestions welcome in the Discord server in the #v-development channel)

hungrybluedev and others added 30 commits May 28, 2020 20:23
@hungrybluedev hungrybluedev marked this pull request as ready for review June 1, 2020 13:23
@medvednikov medvednikov merged commit a7c8483 into vlang:master Jun 1, 2020
@hungrybluedev hungrybluedev changed the title Reorganize random: Phase 1 rand: Reorganize random: Phase 1 Jan 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants