MT19937 不会通过保持种子值不变来重现相同的伪随机序列
MT19937 does NOT reproduce the same pseudo-random sequence by holding the seed value a constant
我正在 Fort运行 90/95 中的 Monte Carlo 模拟中编写一个检查点函数,我使用的编译器是 ifort 18.0.2,在详细说明之前只是为了澄清我使用的伪运行dom生成器的版本:
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 获取源代码。
我的Monte Carlo模拟代码的大致结构如下:
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应该每次都能重现伪运行dom序列?
为了证明是这样,我运行 两个单独的模拟通过使用相同的种子值,它们能够重现准确的序列。到目前为止一切顺利!
根据之前的测试,我进一步假设,无论在一次模拟中被调用的次数init_genrand()
,PRNG也应该能够重现伪运行dom值序列?所以我对 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()
输出不相同。
由于这个意外的结果,我很难在系统的任意状态下恢复模拟,因为模拟没有再现我正在模拟的系统的最新配置状态。
我不确定我是否提供了足够的信息,如果这个问题的任何部分需要更具体,请告诉我?
根据您提供的源代码(请参阅 [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
第一个是 "array for the state vector",第二个是确保我们不会从未初始化的数组开始的标志,第三个是一些位置标记,正如我从评论。
查看 subroutine init_genrand( s )
,它设置 mtinit
标志,并从 1
到 n
填充 mt()
数组。好的。
查看 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
so.. mti
是 'state array' 中的位置索引,并且在从生成器读取每个整数后它递增 1。
返回 init_genrand
- 还记得吗?它一直在重置数组 mt()
但它 尚未将 MTI 重置回其起始 mti = n + 1_wi
.
我打赌这就是您观察到的现象的原因,因为在用相同的种子重新初始化后,数组将填充相同的一组值,但稍后 int32 生成器将从起点不同。我怀疑它是故意的,所以它可能是一个容易被忽视的小错误。
我正在 Fort运行 90/95 中的 Monte Carlo 模拟中编写一个检查点函数,我使用的编译器是 ifort 18.0.2,在详细说明之前只是为了澄清我使用的伪运行dom生成器的版本:
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 获取源代码。
我的Monte Carlo模拟代码的大致结构如下:
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应该每次都能重现伪运行dom序列?
为了证明是这样,我运行 两个单独的模拟通过使用相同的种子值,它们能够重现准确的序列。到目前为止一切顺利!
根据之前的测试,我进一步假设,无论在一次模拟中被调用的次数init_genrand()
,PRNG也应该能够重现伪运行dom值序列?所以我对 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()
输出不相同。
由于这个意外的结果,我很难在系统的任意状态下恢复模拟,因为模拟没有再现我正在模拟的系统的最新配置状态。
我不确定我是否提供了足够的信息,如果这个问题的任何部分需要更具体,请告诉我?
根据您提供的源代码(请参阅 [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
第一个是 "array for the state vector",第二个是确保我们不会从未初始化的数组开始的标志,第三个是一些位置标记,正如我从评论。
查看 subroutine init_genrand( s )
,它设置 mtinit
标志,并从 1
到 n
填充 mt()
数组。好的。
查看 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
so.. mti
是 'state array' 中的位置索引,并且在从生成器读取每个整数后它递增 1。
返回 init_genrand
- 还记得吗?它一直在重置数组 mt()
但它 尚未将 MTI 重置回其起始 mti = n + 1_wi
.
我打赌这就是您观察到的现象的原因,因为在用相同的种子重新初始化后,数组将填充相同的一组值,但稍后 int32 生成器将从起点不同。我怀疑它是故意的,所以它可能是一个容易被忽视的小错误。