Search code examples
rmontecarlorandomagent-based-modeling

Fixing set.seed for an entire session


I am using R to construct an agent based model with a monte carlo process. This means I got many functions that use a random engine of some kind. In order to get reproducible results, I must fix the seed. But, as far as I understand, I must set the seed before every random draw or sample. This is a real pain in the neck. Is there a way to fix the seed?

set.seed(123)
print(sample(1:10,3))
# [1] 3 8 4
print(sample(1:10,3))
# [1]  9 10  1
set.seed(123)
print(sample(1:10,3))
# [1] 3 8 4

Solution

  • There are several options, depending on your exact needs. I suspect the first option, the simplest is not sufficient, but my second and third options may be more appropriate, with the third option the most automatable.

    Option 1

    If you know in advance that the function using/creating random numbers will always draw the same number, and you don't reorder the function calls or insert a new call in between existing ones, then all you need do is set the seed once. Indeed, you probably don't want to keep resetting the seed as you'll just keep on getting the same set of random numbers for each function call.

    For example:

    > set.seed(1)
    > sample(10)
     [1]  3  4  5  7  2  8  9  6 10  1
    > sample(10)
     [1]  3  2  6 10  5  7  8  4  1  9
    > 
    > ## second time round
    > set.seed(1)
    > sample(10)
     [1]  3  4  5  7  2  8  9  6 10  1
    > sample(10)
     [1]  3  2  6 10  5  7  8  4  1  9
    

    Option 2

    If you really want to make sure that a function uses the same seed and you only want to set it once, pass the seed as an argument:

    foo <- function(...., seed) {
      ## set the seed
      if (!missing(seed)) 
        set.seed(seed) 
      ## do other stuff
      ....
    }
    
    my.seed <- 42
    bar <- foo(...., seed = my.seed)
    fbar <- foo(...., seed = my.seed)
    

    (where .... means other args to your function; this is pseudo code).

    Option 3

    If you want to automate this even more, then you could abuse the options mechanism, which is fine if you are just doing this in a script (for a package you should use your own options object). Then your function can look for this option. E.g.

    foo <- function() {
      if (!is.null(seed <- getOption("myseed")))
        set.seed(seed)
      sample(10)
    }
    

    Then in use we have:

    > getOption("myseed")
    NULL
    > foo()
     [1]  1  2  9  4  8  7 10  6  3  5
    > foo()
     [1]  6  2  3  5  7  8  1  4 10  9
    > options(myseed = 42)
    > foo()
     [1] 10  9  3  6  4  8  5  1  2  7
    > foo()
     [1] 10  9  3  6  4  8  5  1  2  7
    > foo()
     [1] 10  9  3  6  4  8  5  1  2  7
    > foo()
     [1] 10  9  3  6  4  8  5  1  2  7