5

I have many independent random processes (arrival processes say) that require me to generate random numbers. I want to use common random numbers for each of these processes that I can compare how different policies perform when controlling these policies.

I want Process A to be governed by Generator A (using seed A) I want Process B to be governed by Generator B (using seed B) ..

and so on.

Is this possible to implement in R. I can't find anyone who has done it. I have tried. Forgive me if this is a repeated question.

Thanks

Jak

  • C++11 support in compiler? – Yakk - Adam Nevraumont Apr 04 '14 at 13:16
  • 2
    Why don't you pre-generate all your random numbers using the different seeds? A and B can have a policy on choosing numbers from the generated set without repetitions (odd / even indices where odds have one seed and evens another, sequential, etc). When you run out of numbers, if that's a problem, generate more. – mockinterface Apr 04 '14 at 13:20
  • I think that's the best approach I have. It may be inefficient that I generate and store way more numbers than I'll ever need to use but if there's no way to have 'several independent piles' of random numbers on offer I'll have to think of a clever implementation of mockinterface's suggestion. Thank you for your swift replies. – Jak Marshall Apr 04 '14 at 13:25
  • If you are computing on different cores you can, see: http://stats.stackexchange.com/q/3532/229 – James Apr 04 '14 at 13:29
  • Since `R` really only does "one thing at a time" all you need to do is set the desired seed before calling your functions `A` and `B` . But let me ask: once you set a seed, the number sequence is defined. What difference does it make if you draw (in the same order) from one or multiple pseudorandom number sequences? – Carl Witthoft Apr 04 '14 at 13:30
  • I'd like to compare the performance of various policies. To that end I'd like the problems seen by each of the policies to be as similar as possible to reduce noise and create a 'standard' set of problems. Due to the policy based nature of the sampling and the finite time horizon, I never need to use (Horizon_Length*Number_of_sources) values as I only sample (Horizon_Length) times. So rather than storing them ahead of time, which would certainly work but would require a lot of storage, I just want to grab the number I care about, only when I want it, without having to store everything. – Jak Marshall Apr 04 '14 at 13:36

2 Answers2

4

This is something that I've occassionally wanted to do - and haven't yet come up with much better than the following kludge (which is only really useful if you're using just 1 or 2 different random distributions, as you have to write a function for each:

#Make a list of seeds - generalises to mkore than 2
seed <- list(NA,NA)
set.seed(1)
seed[[1]] <- .Random.seed
set.seed(2)
seed[[2]] <- .Random.seed

my_runif <- function(...,which.seed=1)
{
  .Random.seed <<- seed[[which.seed]]
  x <-runif(...)
  seed[[which.seed]] <<- .Random.seed
  x
}

##Print some data for comparison
> set.seed(1); runif(10)
 [1] 0.26550866 0.37212390 0.57285336 0.90820779 0.20168193 0.89838968 0.94467527 0.66079779 0.629114040.06178627
> set.seed(2); runif(10)
 [1] 0.1848823 0.7023740 0.5733263 0.1680519 0.9438393 0.9434750 0.1291590 0.8334488 0.4680185 0.5499837

#Test
> my_runif(1,which.seed=1)
[1] 0.2655087
> my_runif(1,which.seed=1)
[1] 0.3721239
> my_runif(1,which.seed=1)
[1] 0.5728534
> my_runif(1,which.seed=2)
[1] 0.1848823
> my_runif(1,which.seed=1)
[1] 0.9082078

I'd imagine that the <<- will break if you call my_runif from inside another function.

fortunes::fortune("<<-")

ETA: The following might be more robust

my_runif <- function(...,which.seed=1)
{
  assign(".Random.seed", seed[[which.seed]], envir = .GlobalEnv)
  x <-runif(...)
  seed <- seed #Bring into local envir
  seed[[which.seed]] <- .Random.seed
  assign("seed", seed, envir = .GlobalEnv)
  x
}
Miff
  • 7,486
  • 20
  • 20
4

Well the good news is that you already do -- see help(RNGkind):

 The currently available RNG kinds are given below.  ‘kind’ is
 partially matched to this list.  The default is
 ‘"Mersenne-Twister"’.

 ‘"Wichmann-Hill"’ [...]

 ‘"Marsaglia-Multicarry"’: [...]

 ‘"Super-Duper"’: [...]

 ‘"Mersenne-Twister"’: [...]

 ‘"Knuth-TAOCP-2002"’: [...]

 ‘"Knuth-TAOCP"’: [...]

 ‘"L'Ecuyer-CMRG"’: 

 ‘"user-supplied"’: Use a user-supplied generator.  See
      ‘Random.user’ for details.

and user-supplied lets you use your own.

And for N(0,1), you also have

 ‘normal.kind’ can be ‘"Kinderman-Ramage"’, ‘"Buggy
 Kinderman-Ramage"’ (not for ‘set.seed’), ‘"Ahrens-Dieter"’,
 ‘"Box-Muller"’, ‘"Inversion"’ (the default), or ‘"user-supplied"’.
 (For inversion, see the reference in ‘qnorm’.)  [...]

For parallel work, see the (excellent) vignette of the parallel package that came with R. There are existing generators for multiple threads/cores/... etc.

Last but not least, R is of course extensible and you could for example use Rcpp where we have a few posts on random numbers over at the Rcpp Gallery site.

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725