Возможные источники для случайного числа семян - PullRequest
7 голосов
/ 19 января 2012

Два пункта - во-первых, пример написан на Фортране, но я думаю, что он подходит для любого языка; во-вторых, встроенные генераторы случайных чисел не являются действительно случайными, и существуют другие генераторы, но мы не заинтересованы в их использовании для того, что мы делаем.

Большинство дискуссий по случайным начальным числам подтверждают, что если программа не заполняет их во время выполнения, то начальное число создается во время компиляции. Таким образом, при каждом запуске программы генерируется одна и та же последовательность чисел, что не подходит для случайных чисел. Одним из способов преодоления этого является заполнение генератора случайных чисел системными часами.

Однако, при работе параллельно с MPI на многоядерной машине, системный тактовый подход для нас породил такие же проблемы. В то время как последовательности менялись от запуска к запуску, все процессоры получали одинаковые системные часы и, таким образом, одинаковое случайное начальное число и одинаковые последовательности.

Итак, рассмотрим следующий пример кода:

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

Что при запуске на моей рабочей станции с 2 ядрами дает:

OLD Rank, dev =            0  0.330676306089146     
OLD Rank, dev =            1  0.330676306089146     
NEW Rank, dev =            0  0.531503215980609     
NEW Rank, dev =            1  0.747413828750221     

Итак, мы преодолели проблему с часами, прочитав вместо этого начальное число из /dev/urandom. Таким образом, каждое ядро ​​получает свое случайное число.

Какие существуют другие начальные подходы, которые будут работать в многоядерной системе MPI и при этом быть уникальными для каждого ядра, от запуска к запуску?

Ответы [ 2 ]

10 голосов
/ 19 января 2012

Если взглянуть на Случайные числа в научных вычислениях: введение от Кацграббера (которое является отличным, ясным обсуждением входов и выходов использования PRNG для технических вычислений), параллельно они предлагаютиспользование хэш-функции времени и PID для генерации начального числа.Из их раздела 7.1:

long seedgen(void)  {
    long s, seed, pid;

    pid = getpid();
    s = time ( &seconds ); /* get CPU seconds since 01/01/1970 */

    seed = abs(((s*181)*((pid-83)*359))%104729); 
    return seed;
}

конечно, в Фортране это было бы что-то вроде

function seedgen(pid)
    use iso_fortran_env
    implicit none
    integer(kind=int64) :: seedgen
    integer, intent(IN) :: pid
    integer :: s

    call system_clock(s)
    seedgen = abs( mod((s*181)*((pid-83)*359), 104729) ) 
end function seedgen

Иногда также удобно иметь возможность передавать время, а не вызывать егоиз seedgen, чтобы при тестировании вы могли присвоить ему фиксированные значения, которые затем генерируют воспроизводимую (== тестируемую) последовательность.

0 голосов
/ 19 января 2012

Системное время обычно возвращается (или, по крайней мере, легко преобразуется в) в целочисленный тип: просто добавьте ранг процесса к значению и используйте его для заполнения генератора случайных чисел.

...