Random MT19937不会通过将种子值保持为常量来复制相同的伪随机序列
我在Fortran 90/95的Monte Carlo模拟中编写了一个检查点函数,我使用的编译器是ifort 18.0.2,在详细说明我使用的伪随机生成器版本之前:Random MT19937不会通过将种子值保持为常量来复制相同的伪随机序列,random,fortran,mersenne-twister,Random,Fortran,Mersenne Twister,我在Fortran 90/95的Monte Carlo模拟中编写了一个检查点函数,我使用的编译器是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
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
有关源代码,请参阅
我的蒙特卡罗模拟代码的一般结构如下所示:
program montecarlo
call read_iseed(...)
call mc_subroutine(...)
end
在读取的文件中
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
输出出乎意料地不是我想的那样,无论如何,iseed
两次初始化之间的输出是相同的,但是,genrand\u real3()
输出是不相同的
由于这个意外的结果,我很难在系统的任意状态下恢复模拟,因为模拟没有再现我正在模拟的系统的最新配置状态
我不确定我是否提供了足够的信息,请让我知道这个问题的任何部分是否需要更具体?从您提供的源代码中(源代码请参见[mt19937]{}),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
第一个是“状态向量的数组”,第二个是确保我们不会从未初始化的数组开始的标志,第三个是一些位置标记,正如我在注释中所述的条件所猜测的那样
查看子例程init\u genrand(s)
,它设置mtinit
标志,并从1
到n
填充mt()
数组。好的
查看genrand\u real3
它基于genrand\u 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\u genrand
-记得吗?它一直在重置阵列mt()
,但没有将MTI重置回其起始位置MTI=n+1_wi
我打赌这就是您观察到的现象的原因,因为在使用相同的种子重新初始化后,数组将填充相同的值集,但稍后int32生成器将从不同的起点读取。我怀疑这是有意的,所以这可能是一个容易忽略的小错误。请在所有Fortran问题中使用tag[tagnfortran]。标记poth fortran90和fortran95没有任何意义,你的问题无论如何都不是版本指定。
init_genrand
如何填充完整的PRNG状态?@francescalus请参见[mt19937ar]{},我的第一次测试证明,它能够通过输入一个恒定的种子值来复制序列,但在我的第二次测试中,当我用相同的种子值重新初始化序列时,它不知何故没有将序列的状态重置回它开始的位置。函数init\u genrand
在我阅读子例程时,在我看来,init\u genrand()
通过给定种子值初始化序列的起始位置,genrand\u real3()
提供了(0,1)中的值。你有没有看到任何分歧?显然我不是唯一一个对这个bug感兴趣的人,这是一个基于mt19937实现检查点重启的已知问题,重置位置索引需要知道调用genrand_real()和genrand_int()的确切总次数,由于这取决于应用程序,因此没有通用的解决方案。但为指出问题而欢呼!
y = mt(mti)
mti = mti + 1_wi