Ответ 1
Я вникнул в это еще немного, и похоже, что пакет rlecuyer
предоставляет независимые случайные потоки:
Предоставляет интерфейс для реализации C генератора случайных чисел с несколькими независимыми потоками, разработанными L'Ecuyer et al (2002). Основная цель этого пакета - включить использование этого генератора случайных чисел в параллельных приложениях R.
Первым шагом является глобальная инициализация независимых потоков:
library(rlecuyer)
.lec.CreateStream(c("stream.12", "stream.prod"))
Затем каждая функция должна быть изменена до reset соответствующего потока в его начальное состояние (.lec.RestartStartStream
), установите генератор случайных чисел R в соответствующий поток (.lec.CurrentStream
), а затем установите случайное число R генератор возвращается в свое состояние до того, как была вызвана функция (.lec.CurrentStreamEnd
).
sample.12 <- function(size) {
.lec.ResetStartStream("stream.12")
.lec.CurrentStream("stream.12")
x <- sample(1:2, size, replace=TRUE)
.lec.CurrentStreamEnd()
x
}
rand.prod <- function(x) {
.lec.ResetStartStream("stream.prod")
.lec.CurrentStream("stream.prod")
y <- runif(length(x)) * x
.lec.CurrentStreamEnd()
y
}
Это удовлетворяет условию "всегда возвращает тот же результат с учетом того же ввода":
all.equal(rand.prod(sample.12(10000)), rand.prod(sample.12(10000)))
# [1] TRUE
Потоки также работают независимо в нашем примере:
x <- sample.12(10000)
hist(rand.prod(x))
Обратите внимание, что это не дало бы согласованных значений во всех прогонах нашего script, потому что каждый вызов .lec.CreateStream
дал бы другое начальное состояние. Чтобы устранить это, мы могли бы отметить начальное состояние для каждого потока:
.lec.GetState("stream.12")
# [1] 3161578179 1307260052 2724279262 1101690876 1009565594 836476762
.lec.GetState("stream.prod")
# [1] 596094074 2279636413 3050913596 1739649456 2368706608 3058697049
Затем мы можем изменить инициализацию потока в начале script на:
library(rlecuyer)
.lec.CreateStream(c("stream.12", "stream.prod"))
.lec.SetSeed("stream.12", c(3161578179, 1307260052, 2724279262, 1101690876, 1009565594, 836476762))
.lec.SetSeed("stream.prod", c(596094074, 2279636413, 3050913596, 1739649456, 2368706608, 3058697049))
Теперь вызовы sample.12
и rand.prod
будут совпадать между вызовами script.