--- title: "Random Number Generation" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Random Number Generation} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` In this vignette, you will learn how to generate random numbers in {anvl}, which is different from base R, where random number generation uses a global state (`.Random.seed`) that is automatically updated after each call: ```{r} set.seed(42) .Random.seed[2:4] rnorm(3) .Random.seed[2:4] rnorm(3) .Random.seed[2:4] ``` In {anvl}, the random state must be explicitly passed around. This is because we are following a functional programming paradigm where functions are pure and don't have side effects. **Note:** This explicit state-passing behavior might change in the future to provide a more R-like experience, but for now you need to manage the state yourself. To generate random numbers, you first need to create an initial RNG state, which is simply a `ui64[2]`. You can convert a seed into a state using `nv_rng_state()`: ```{r} library(anvl) state <- nv_rng_state(42L) state ``` The main functions for generating random numbers are `nv_runif()`, `nv_rdunif()`, `nv_rbinom()`, and `nv_rnorm()`. All those functions return a list with two elements: 1. The **new** RNG state (to be used for subsequent random number generation). 2. The generated random numbers. Let's generate some uniform random numbers: ```{r} result <- nv_runif(state, dtype = "f32", shape = c(2, 3)) result[[1]] # new state result[[2]] # random numbers ``` For normally distributed random numbers: ```{r} result <- nv_rnorm(state, dtype = "f32", shape = c(2, 3), mu = 0, sigma = 1) result[[2]] ``` One thing to avoid is to reuse the same state for multiple calls as done in the example below: ```{r} result1 <- nv_runif(state, dtype = "f32", shape = 3L) result2 <- nv_runif(state, dtype = "f32", shape = 3L) list(first = result1[[2]], second = result2[[2]]) ``` As you can see, both calls produced identical random numbers because we used the same state for both. To get different random numbers in subsequent calls, you need to pass the **new** state returned by the previous call: ```{r} result1 <- nv_runif(state, dtype = "f32", shape = 3L) new_state <- result1[[1]] result2 <- nv_runif(new_state, dtype = "f32", shape = 3L) list(first = result1[[2]], second = result2[[2]]) ``` Now we get different random numbers because we properly propagated the state.