Learn Julia (10): apropos Random
Tags: random, julia
Published: 2020-11-25 11:15:58

In **Python**, we use often `numpy.random`  for generating random numbers and arrays. In **Julia**, we do this by using `Random` module.
See [official doc](https://docs.julialang.org/en/v1/stdlib/Random/).

Some concept to learn in this module:
* RNG: random number generator
* Seed vs RNG
* Normal and exponential distributions
* Random string and bit-array
* Random permutation


Let's see firstly what is in this module:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/zupkickh9yxitvx74b4v.PNG)
To remind, the two most used functions `rand()` and `randn()` are not contained in the **Random** module, in fact, they are defined in **Base** module, namely we shall use `Base.rand` and `Base.randn`. On the contrary, `rand!()` and `randn!()` are indeed contained in the **Random** module, not in **Random** module.

My learning code today: 
```julia
#### https://docs.julialang.org/en/v1/stdlib/Random/
using Random
# names(Random): check names in this module

println("     ")

#=
rand([rng=GLOBAL_RNG], [S], [dims...])
Pick a random element or array of random elements from the set of values specified by S; S can be

 - an indexable collection (for example 1:9 or ('x', "y", :z)),
 - an AbstractDict or AbstractSet object,
 - a string (considered as a collection of characters), or
 - a type: the set of values to pick from is then equivalent to typemin(S):typemax(S) for integers (this is not applicable to BigInt), to [0, 1) for floating point numbers and to [0, 1)+i[0, 1) for complex floating point numbers;
S defaults to Float64. When only one argument is passed besides the optional rng and is a Tuple, it is interpreted as a collection of values (S) and not as dims.
=#
a = rand(Int, 2)
println("a: $a, Typeof a", typeof(a))


#=  
RNG: random number generator. All rand-generation functions such like rand() and randn() can be called with a rng object as argument.

MersenneTwister rng object construction:

 - MersenneTwister(seed) where seed is a non-negative integer
 - MersenneTwister()
=#

rng = MersenneTwister(20);

b = rand(rng, Float64, 3)
println("b: $b, Typeof b", typeof(b))


c = rand( [2,3,4,7,9])  #  => yields one of the five numbers in this array
println("c: $c ")


d = rand(MersenneTwister(0), Dict("x1"=>2, "x2"=>4))  #  => yields one of the two items of a dict
println("d: $d ")


e = rand(Float64, (2, 3))    #  => yields 2x3 array
println("e: $e, shape of e: ", size(e))

f = zeros(5)
println("initial f: $f")
rand!(rng, f)    # pass an existing array and modify it in place
println("rand f: $f")

## Generate a BitArray of random boolean values.
g = bitrand( 10)  # or g = bitrand(rng, 10)

println("rand g: $g")


 # Fill an array  with normally-distributed (mean 0, standard deviation 1) random numbers. 
h = randn(Float64, (3, 5))
## can alo be : randn(rng, ComplexF32, (3, 5))
println("randn h: $h")


## Generate a random number of type T according to the exponential distribution with scale 1. 
i = randexp(rng, 3, 3) 
println("randexp i: $i")

j = randstring(MersenneTwister(3), 'a':'z', 6)
println("randstring j: $j")

k = shuffle(rng, Vector(1:10))
println("shuffle k: $k")

### same as in Python, we can use the same seed to generate the same random result 
Random.seed!(1)
x1 = randn(Float64, (3, 3))

x2 = randn(Float64, (3, 3))

Random.seed!(1)
x3 = randn(Float64, (3, 3))

println(typeof(Random.seed!(1)))  # seed  shall be passed to the global/default rng object 

println("x1 == x2?  : ", x1==x2)
println("x1 == x3?  : ", x1==x3)

```

Voilà the execution output:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/o3y575x2r47wolfox595.PNG)