[R-pkg-devel] Save and restoring random number seed in a package function

Bill Dunlap w||||@mwdun|@p @end|ng |rom gm@||@com
Thu Sep 15 00:06:11 CEST 2022


> Yes, set.seed() cannot accept .Random.Seed as an input; it can only take
a single integer.

If I recall correctly, S-plus's set.seed() would accept a .Random.seed
value as an input.  It did some basic validation checks on it and set it as
the current .Random.seed.  I don't recall the name of the argument.  The
format of the seed depends on the generator used - I think it used the
nature of the proffered seed to get the likely generator, but there may
have also been arguments to specify the generator explicitly.

I think this would be a nice thing to add to R's set.seed.

-Bill

On Wed, Sep 14, 2022 at 8:11 AM Noah Greifer <noah.greifer using gmail.com> wrote:

> Yes, set.seed() cannot accept .Random.Seed as an input; it can only take a
> single integer. As said in this answer
> <https://stackoverflow.com/a/13997608/6348551>, there is a one-way
> relationship between set.seed() and .Random.Seed. My understanding is that
> the recommended way to restore the seed is to assign the saved seed to
> .Random.Seed in the global environment, though this is the method that is
> not allowed by the CRAN policy. Unfortunately saving it in the environment
> of the inner function is not sufficient.
>
> One potential inconsistency with CRAN's policy is that generating a random
> number itself changes the global environment by changing the value of
> .Random.Seed. The boot.array() code just does it manually using assign().
> Indeed, the boot.array() code does less damage to the global environment in
> that it resets the seed to what it would have been had boot.array() not
> been run.
>
> Noah
>
> On Wed, Sep 14, 2022 at 10:39 AM James Pustejovsky <jepusto using gmail.com>
> wrote:
>
> > I'm interested in this question too. Noah, is there a reason you are
> using
> > assign(".Random.seed",...) rather than set.seed()?
> >
> > On Wed, Sep 14, 2022 at 9:31 AM Noah Greifer <noah.greifer using gmail.com>
> > wrote:
> >
> >> Hello fellow developers,
> >>
> >> I am attempting to solve the problem of saving the state of the random
> >> generator so that the state can be recovered in a future call.
> >> Essentially,
> >> my function generates random numbers, performs an operation on them
> >> (saving
> >> the result), and throws them out (saving them would require too much
> >> memory). A second function is meant to take the output of the first
> >> function, generate the same random numbers, and perform a different
> >> operation on them.
> >>
> >> This is exactly what happens in the *boot* package: the boot() function
> >> saves the random seed (extracted from .Random.Seed), and the
> boot.array()
> >> function extracts the saved seed from the boot() output, sets the seed
> to
> >> that value, re-generates the same set of random numbers, and then
> >> re-sets the seed to what it was before boot.array() was called. This has
> >> the following benefits: 1) it allows the same random numbers to be
> drawn;
> >> 2) the random numbers don't need to be saved, which is good because they
> >> would take up a lot of memory and boot.array() is an optional function
> (it
> >> is used in boot.ci() with type = "bca" for those curious); and 3) the
> >> seed
> >> carries on from where it left off before boot.array() was called instead
> >> of
> >> being set to what it was after boot() was called.
> >>
> >> This is implemented in boot in the following way (code abbreviated):
> >>
> >> boot <- function(...) {
> >>   seed <- .Random.Seed
> >>   #Random numbers generated
> >>   out <- list(seed = seed
> >>                   #Other stuff is in this list
> >>               )
> >>   out
> >> }
> >>
> >> boot.array <- function(boot.out) {
> >>   #Save current random seed in `temp`
> >>   if (exists(".Random.seed", envir = .GlobalEnv, inherits = FALSE))
> >>     temp <- get(".Random.seed", envir = .GlobalEnv, inherits = FALSE)
> >>   else temp <- NULL
> >>
> >>   #Assign saved seed from boot.out
> >>   assign(".Random.seed", boot.out$seed, envir = .GlobalEnv)
> >>
> >>   #Generate same random numbers from boot() call
> >>
> >>   #Restore random seed to what it was before boot.array() call
> >>   if (!is.null(temp))
> >>     assign(".Random.seed", temp, envir = .GlobalEnv)
> >>   else rm(.Random.seed, pos = 1)
> >> }
> >>
> >> This seems to work as intended. However, this violates the CRAN policy
> of
> >> changing the global environment. When I used this exact code in a
> package
> >> I
> >> submitted, the package was rejected for it. The message I received was
> >>
> >> > Please do not modify the .GlobalEnv (e.g.: by changing the
> .Random.seed
> >> > which is part of the global environment). This is not allowed by the
> >> CRAN
> >> > policies.
> >>
> >>
> >> I'm curious what you think the best course of action might be, and what
> >> the
> >> current policy means for the *boot* package. Thanks for your help.
> >>
> >> Noah
> >>
> >>         [[alternative HTML version deleted]]
> >>
> >> ______________________________________________
> >> R-package-devel using r-project.org mailing list
> >> https://stat.ethz.ch/mailman/listinfo/r-package-devel
> >>
> >
>
>         [[alternative HTML version deleted]]
>
> ______________________________________________
> R-package-devel using r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-package-devel
>

	[[alternative HTML version deleted]]



More information about the R-package-devel mailing list