MT19937 НЕ воспроизводит одну и ту же псевдослучайную последовательность, сохраняя начальное значение постоянным
Я пишу функцию контрольной точки в моем симуляции Монте-Карло в Fortran 90/95, компилятор, который я использую, это ifort 18.0.2, прежде чем перейти к деталям, просто чтобы уточнить версию генератора псевдослучайных сигналов, который я использую:
A C-program for MT19937, with initialization, improved 2002/1/26.
Coded by Takuji Nishimura and Makoto Matsumoto.
Code converted to Fortran 95 by Josi Rui Faustino de Sousa
Date: 2002-02-01
См. Mt19937 для исходного кода.
Общая структура моего кода моделирования Монте-Карло приведена ниже:
program montecarlo
call read_iseed(...)
call mc_subroutine(...)
end
В пределах read_iseed
subroutine read_iseed(...)
use mt19937
if (Restart == 'n') then
call system('od -vAn -N4 -td4 < /dev/urandom > '//trim(IN_ISEED)
open(unit=7,file=trim(IN_ISEED),status='old')
read(7,*) i
close(7)
!This is only used to initialise the PRNG sequence
iseed = abs(i)
else if (Restart == 'y') then
!Taking seed value from the latest iteration of previous simulation
iseed = RestartSeed
endif
call init_genrand(iseed)
print *, 'first pseudo-random value ',genrand_real3(), 'iseed ',iseed
return
end subroutine
Исходя из моего понимания, если начальное значение содержит константу, PRNG должен каждый раз воспроизводить псевдослучайную последовательность?
Чтобы доказать это, я провел два отдельных моделирования, используя одно и то же начальное значение, они в состоянии воспроизвести точную последовательность. Все идет нормально!
Основываясь на предыдущем тесте, я бы также предположил, что независимо от того, сколько раз init_genrand()
вызывается в рамках одного отдельного моделирования, PRNG также должен быть в состоянии воспроизвести псевдослучайную последовательность значений? Так что я сделал небольшую модификацию моего read_iseed()
подпрограмма
subroutine read_iseed(...)
use mt19937
if (Restart == 'n') then
call system('od -vAn -N4 -td4 < /dev/urandom > '//trim(IN_ISEED)
open(unit=7,file=trim(IN_ISEED),status='old')
read(7,*) i
close(7)
!This is only used to initialise the PRNG sequence
iseed = abs(i)
else if (Restart == 'y') then
!Taking seed value from the latest iteration of the previous simulation
iseed = RestartSeed
endif
call init_genrand(iseed)
print *, 'first time initialisation ',genrand_real3(), 'iseed ',iseed
call init_genrand(iseed)
print *, 'second time initialisation ',genrand_real3(), 'iseed ',iseed
return
end subroutine
Вывод на удивление не тот случай, который я думал, будет непременно iseed
выходы идентичны между двумя инициализациями, однако, genrand_real3()
выходы не идентичны.
Из-за этого неожиданного результата я изо всех сил пытался возобновить моделирование в произвольном состоянии системы, поскольку моделирование не воспроизводит последнее состояние конфигурации системы, которую я моделирую.
Я не уверен, предоставил ли я достаточно информации, пожалуйста, дайте мне знать, если какая-то часть этого вопроса должна быть более конкретной?
1 ответ
Из предоставленного вами исходного кода (см. [Mt19937] { http://web.mst.edu/~vojtat/class_5403/mt19937/mt19937ar.f90} для исходного кода.), init_genrand
не очищает все состояние.
Есть 3 критических переменных состояния:
integer( kind = wi ) :: mt(n) ! the array for the state vector
logical( kind = wi ) :: mtinit = .false._wi ! means mt[N] is not initialized
integer( kind = wi ) :: mti = n + 1_wi ! mti==N+1 means mt[N] is not initialized
Первый - это "массив для вектора состояния", второй - это флаг, который гарантирует, что мы не начинаем с неинициализированного массива, а третий - это некоторый маркер позиции, как я предполагаю из условия, указанного в комментарии.
Смотря на subroutine init_genrand( s )
это устанавливает mtinit
флаг и заполняет mt()
массив из 1
вплоть до n
, Хорошо.
Смотря на genrand_real3
это основано на genrand_int32
,
Смотря на genrand_int32
, начинается с
if ( mti > n ) then ! generate N words at one time
! if init_genrand() has not been called, a default initial seed is used
if ( .not. mtinit ) call init_genrand( seed_d )
и выполняет свою арифметическую магию, а затем начинает получать результат:
y = mt(mti)
mti = mti + 1_wi
так.. mti
является позиционным индексом в "массиве состояний", и он увеличивается на 1 после каждого целочисленного чтения из генератора.
Вернуться к init_genrand
- Помните? это был сброс массива mt()
но он не сбросил MTI обратно к его запуску mti = n + 1_wi
,
Могу поспорить, что это является причиной явления, которое вы наблюдали, так как после повторной инициализации с тем же начальным значением массив будет заполнен тем же набором значений, но позже генератор int32 будет считывать данные из другой начальной точки. Я сомневаюсь, что это было задумано, так что это, вероятно, крошечная ошибка, которую легко не заметить.