Dos puntos: primero, el ejemplo está en Fortran, pero creo que debería ser válido para cualquier idioma; segundo, los generadores de números aleatorios incorporados no son realmente aleatorios y existen otros generadores, pero no estamos interesados en usarlos para lo que estamos haciendo.Posibles fuentes de semillas de números aleatorios
La mayoría de las discusiones sobre semillas aleatorias reconocen que si el programa no lo inicializa en tiempo de ejecución, entonces la semilla se genera en tiempo de compilación. Entonces, la misma secuencia de números se genera cada vez que se ejecuta el programa, lo que no es bueno para números aleatorios. Una forma de superar esto es sembrar el generador de números aleatorios con el reloj del sistema.
Sin embargo, cuando se ejecuta en paralelo con MPI en una máquina multi-core, el enfoque de reloj del sistema para nosotros generó los mismos tipos de problemas. Si bien las secuencias cambiaron de ejecución a ejecución, todos los procesadores obtuvieron el mismo reloj del sistema y, por lo tanto, la misma semilla aleatoria y las mismas secuencias.
así que considere el siguiente código de ejemplo:
PROGRAM clock_test
IMPLICIT NONE
INCLUDE "mpif.h"
INTEGER :: ierr, rank, clock, i, n, method
INTEGER, DIMENSION(:), ALLOCATABLE :: seed
REAL(KIND=8) :: random
INTEGER, PARAMETER :: OLD_METHOD = 0, &
NEW_METHOD = 1
CALL MPI_INIT(ierr)
CALL MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
CALL RANDOM_SEED(SIZE=n)
ALLOCATE(seed(n))
DO method = 0, 1
SELECT CASE (method)
CASE (OLD_METHOD)
CALL SYSTEM_CLOCK(COUNT=clock)
seed = clock + 37 * (/ (i - 1, i = 1, n) /)
CALL RANDOM_SEED(put=seed)
CALL RANDOM_NUMBER(random)
WRITE(*,*) "OLD Rank, dev = ", rank, random
CASE (NEW_METHOD)
OPEN(89,FILE='/dev/urandom',ACCESS='stream',FORM='UNFORMATTED')
READ(89) seed
CLOSE(89)
CALL RANDOM_SEED(put=seed)
CALL RANDOM_NUMBER(random)
WRITE(*,*) "NEW Rank, dev = ", rank, random
END SELECT
CALL MPI_BARRIER(MPI_COMM_WORLD, ierr)
END DO
CALL MPI_FINALIZE(ierr)
END PROGRAM clock_test
que cuando se ejecutan en mi estación de trabajo con 2 núcleos, da:
OLD Rank, dev = 0 0.330676306089146
OLD Rank, dev = 1 0.330676306089146
NEW Rank, dev = 0 0.531503215980609
NEW Rank, dev = 1 0.747413828750221
Por lo tanto, hemos superado el problema del reloj mediante la lectura de la semilla de la /dev/urandom
en lugar. De esta forma, cada núcleo obtiene su propio número aleatorio.
¿Qué otros enfoques de semilla existen que funcionen en un sistema MPI de múltiples núcleos y sigan siendo únicos en cada núcleo, desde la ejecución hasta la ejecución?
Basado en la discusión en http://stackoverflow.com/questions/1554958/how-different-do-random-seeds-need-to-be y el artículo citado en la respuesta, simplemente agregando el rango al tiempo genera algunos números no tan pseudoaleatorios porque todas las semillas serían lineales. Pero si solo está muy pseudoaleatorio, entonces el enfoque de tiempo + rango es muy simple e independiente de la plataforma. – tpg2114