FsRandom


FsRandom Documentation

First Random Number

Let's try to get a first random number z ~ N(0, 1). It is easy to do with normal random number generator in the Statistics module. To give the specific parameter, say the mean of 0 and the variance of 1, do:

1: 
let generator = Statistics.normal (0.0, 1.0)

The generator function is only able to use with a pseudo-random number generator (PRNG). The PRNG constructs a computation expression to generate random numbers. The computation expression is a function which takes a random seed and returns a random number and a new seed for the next call. It is important to keep the new state because it is used when you generate a new random number.

Here for example, you choose xorshift PRNG, which is implemented in FsRandom. You need to define an initial random seed first for xorshift algorithm (of course, another algorithm is available rather than xorshift, as described later). It is a tuple composed of four 32-bit unsigned integers. And then, you should combine the PRNG and the seed using createState function.

1: 
2: 
let seed = 123456789u, 362436069u, 521288629u, 88675123u
let state = createState xorshift seed

FsRandom also provides a default random state and a method to create a random state randomly for ease of use:

1: 
2: 
Utility.defaultState
Utility.createRandomState ()

Now you can retrieve a random number using Random.get function.

1: 
2: 
let z1 = Random.get generator state
printf "z1 = %f" z1
z1 = -0.276323

Since Random.get returns a stateless function, if you do the code above, the same thing occurs.

1: 
2: 
let z2 = Random.get generator state
printf "z2 = %f" z2
z2 = -0.276323

To generate a new random number, you need to get next state using Random.next instead of Random.get:

1: 
2: 
3: 
let _, nextState = Random.next generator state
let z3 = Random.get generator nextState
printf "z3 = %f" z3
z3 = -1.561583

Transforming Random Numbers

Transformation of random numbers is a regular work. FsRandom defines Random.map function for the purpose. The following code shows how to use it.

1: 
2: 
3: 
4: 
let plusOne x = x + 1.0
Random.map plusOne <| Statistics.uniform (0.0, 1.0)
|> Random.get
<| state

plusOne is a function that takes an argument and adds one to it. uniform is a uniform random number generator between its two arguments. So x finally becomes a uniform random number between 1 and 2.

The both following codes return the same results as above.

1: 
2: 
3: 
4: 
Random.identity <| Statistics.uniform (0.0, 1.0)
|> Random.get
<| state
|> plusOne
1: 
2: 
3: 
4: 
Statistics.uniform (0.0, 1.0)
|> Random.get
<| state
|> plusOne

Random Number Sequence

Usually, you use a lot of random numbers for our needs. The following code defines a function generating an infinite binary sequence using Bernoulli random number generator, and it illustrates how you can generate a number of random numbers.

1: 
2: 
3: 
4: 
5: 
let rec binaries initialState = seq {
   let binary, nextState = Random.next (Statistics.bernoulli 0.5) initialState
   yield binary
   yield! binaries nextState // recursively generating binaries.
}

Or, more precisely like the following:

1: 
let binaries2 state = Seq.ofRandom (Statistics.bernoulli 0.5) state

Using System.Random

The examples above uses xorshift to generate random numbers. The familliar System.Random (and its subclasses) is available in the workflow. Just use systemrandom instead of xorshift.

1: 
2: 
let r0 = System.Random ()
let s = createState systemrandom r0

Because System.Random is a stateful object, unlike xorshift, you will get different result on each call.

1: 
2: 
let u1 = Random.get generator s
let u2 = Random.get generator s

Generator function

This section explains how to construct generator functions such like normal and uniform.

The type of generator function is GeneratorFunction<'a>, where 'a is a type of random numbers the generator function returns.

As an example of user-defined generator function, let's construct a random number generator to produce an approximate standard normal random number (approximately ~ N(0, 1)). Theorem says that the mean of 12 standard random numbers, namely, 12 random numbers between 0 and 1, approximates a normal random number with mean of 1/2 and variance of 1/12. Therefore, if you subtract 6 from the sum of 12 standard random numbers, the result approximates a standard normal random number.

1: 
2: 
3: 
4: 
let approximatelyStandardNormal = random {
   let! values = Array.randomCreate 12 ``(0, 1)``
   return Array.sum values - 6.0
}

The approximatelyStandardNormal can be used in the generating process as the following.

1: 
Random.get approximatelyStandardNormal state

Don't forget that FsRandom has a normal random number generator normal.

Pseudo-random number generators

This section explains how to implement pseudo-random number generator (PRNG) algorithms such as xorshift and systemrandom.

A PRNG is often defined as a simple series of numbers whose next number is determined by the current state. For example, the Xorshift algorithm has four 32-bit integers as a state. To describe such PRNGs, the type of PRNGs in FsRandom is defined as type Prng<'s> = 's -> uint64 * 's. Here 's is the type of random state of the PRNG.

As an example of user-defined Prng, let's implement linear congruential generator. First, you make a function of Prng.

1: 
2: 
// Coefficients are cited from Wikipedia
let linear x = x, 6364136223846793005uL * x + 1442695040888963407uL

The first returned value is a random number and the second returned value is a next state. Note that modulus is not defined because Prng is required to return random numbers in 64-bit resolution.

Hereafter you can use the linear PRNG to generate random numbers.

1: 
2: 
let linearState = createState linear 0x123456789ABCDEFuL
Random.get generator linearState
namespace FsRandom
val generator : GeneratorFunction<float>

Full name: Documentation.generator
module Statistics

from FsRandom
val normal : mean:float * standardDeviation:float -> GeneratorFunction<float>

Full name: FsRandom.Statistics.normal
val seed : uint32 * uint32 * uint32 * uint32

Full name: Documentation.seed
val state : PrngState

Full name: Documentation.state
val createState : prng:Prng<'s> -> seed:'s -> PrngState

Full name: FsRandom.RandomNumberGenerator.createState
val xorshift : Prng<uint32 * uint32 * uint32 * uint32>

Full name: FsRandom.RandomNumberGenerator.xorshift
module Utility

from FsRandom
val defaultState : PrngState

Full name: FsRandom.Utility.defaultState
val createRandomState : unit -> PrngState

Full name: FsRandom.Utility.createRandomState
val z1 : float

Full name: Documentation.z1
module Random

from FsRandom
val get : generator:GeneratorFunction<'a> -> PrngState -> 'a

Full name: FsRandom.Random.get
val printf : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printf
val z2 : float

Full name: Documentation.z2
val nextState : PrngState

Full name: Documentation.nextState
val next : generator:GeneratorFunction<'a> -> PrngState -> 'a * PrngState

Full name: FsRandom.Random.next
val z3 : float

Full name: Documentation.z3
val plusOne : x:float -> float

Full name: Documentation.plusOne
val x : float
val map : transformation:('a -> 'b) -> generator:GeneratorFunction<'a> -> GeneratorFunction<'b>

Full name: FsRandom.Random.map
val uniform : min:float * max:float -> GeneratorFunction<float>

Full name: FsRandom.Statistics.uniform
val identity : generator:GeneratorFunction<'a> -> GeneratorFunction<'a>

Full name: FsRandom.Random.identity
val binaries : initialState:PrngState -> seq<int>

Full name: Documentation.binaries
val initialState : PrngState
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
val binary : int
val nextState : PrngState
val bernoulli : probability:float -> GeneratorFunction<int>

Full name: FsRandom.Statistics.bernoulli
val binaries2 : state:PrngState -> seq<int>

Full name: Documentation.binaries2
val state : PrngState
Multiple items
module Seq

from FsRandom

--------------------
module Seq

from Microsoft.FSharp.Collections
val ofRandom : generator:GeneratorFunction<'a> -> (PrngState -> seq<'a>)

Full name: FsRandom.Seq.ofRandom
val r0 : System.Random

Full name: Documentation.r0
namespace System
Multiple items
type Random =
  new : unit -> Random + 1 overload
  member Next : unit -> int + 2 overloads
  member NextBytes : buffer:byte[] -> unit
  member NextDouble : unit -> float

Full name: System.Random

--------------------
System.Random() : unit
System.Random(Seed: int) : unit
val s : PrngState

Full name: Documentation.s
val systemrandom : Prng<System.Random>

Full name: FsRandom.RandomNumberGenerator.systemrandom
val u1 : float

Full name: Documentation.u1
val u2 : float

Full name: Documentation.u2
val approximatelyStandardNormal : GeneratorFunction<float>

Full name: Documentation.approximatelyStandardNormal
val random : RandomBuilder

Full name: FsRandom.RandomNumberGenerator.random
val values : float []
Multiple items
module Array

from FsRandom

--------------------
module Array

from Microsoft.FSharp.Collections
val randomCreate : count:int -> generator:GeneratorFunction<'a> -> GeneratorFunction<'a []>

Full name: FsRandom.Array.randomCreate
val ( (0, 1) ) : GeneratorFunction<float>

Full name: FsRandom.RandomNumberGenerator.( (0, 1) )
val sum : array:'T [] -> 'T (requires member ( + ) and member get_Zero)

Full name: Microsoft.FSharp.Collections.Array.sum
val linear : x:uint64 -> uint64 * uint64

Full name: Documentation.linear
val x : uint64
val linearState : PrngState

Full name: Documentation.linearState
Fork me on GitHub