Случайное число, сгенерированное для каждого процесса в MPI C - PullRequest
0 голосов
/ 19 апреля 2019

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

Если каждая задача MPI инициализирует свой собственный массив случайными числами (например, код, который я прикрепил), отличаются ли эти числа среди задач?

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

Большое спасибо заранее за любую информацию.

void initialize(float* inarray, int n){
    int i;
    for (i=0; i<n; i++){
            inarray[i] = random() / (float)RAND_MAX;
        }
    }
}

void main(int argc, char* argv[]){

    MPI_Comm comm=MPI_COMM_WORLD;
    int numnodes, myid, ierr;
    ierr=MPI_Init(&argc, &argv);
    ierr=MPI_Comm_size(comm, &numnodes);
    ierr=MPI_Comm_rank(comm, &myid);

    int n = 100;
    float *x = malloc(sizeof(float)*n);
    initialize(x, n);

    ierr=MPI_Finalize();
}

Ответы [ 3 ]

0 голосов
/ 19 апреля 2019

(псевдо) генератор случайных чисел должен быть засеян и иметь разные начальные числа для каждого ранга.

В моей среде (CentOS 7):

#include <stdio.h>
#include <stdlib.h>

#include <mpi.h>

int main(int argc, char *argv[]) {
    int rank;
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    srand(rank+1);
    float f = (float)random() / (float)RAND_MAX;
    printf ("%d: %f\n", rank, f);
    MPI_Finalize();
    return 0;
}

производит

0: 0.840188
1: 0.700976
2: 0.561380
3: 0.916458
4: 0.274746
5: 0.135439
6: 0.486904
7: 0.352761
8: 0.206965
9: 0.565811
10: 0.926345
11: 0.785600
12: 0.632643
13: 0.999498
14: 0.354973
15: 0.215437
0 голосов
/ 20 апреля 2019

Так что на самом деле это сложнее, чем ожидалось. Есть два вопроса:

Во-первых, допустим, у вас есть 40 mpi-процессов, которым нужно нарисовать 10 чисел, используя равномерное распределение между 0 и 1. Затем, если вы возьмете 400 чисел, используя одну цепочку, вы получите довольно хорошее равномерное распределение. , Но если вы нарисуете только 10 число, вы, вероятно, не будете. Рисунок 10 числа из 40 цепочек не является строго эквивалентным рисунку 400 числа из одной цепочки. Но эта проблема появится, только если вам нужен хороший контроль над вашим дистрибутивом.

Во-вторых, допустим, вы хотите изучить данную проблему численно. То, что вы должны проверить, - это сходимость вашего решателя. Для этого вам нужно посмотреть, хорошо ли работает ваш решатель при уточнении разрешения. Так что вам нужно генерировать различные реализации (ваши случайные числа) таким образом, чтобы вы сохраняли одни и те же низкие частоты (если вы думаете в пространстве Фурье). Для этого вы должны быть уверены, что случайное число, которое находится в данном месте (скажем, 327 из ваших 400), всегда одинаково, независимо от количества процессов, которые вы используете.

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

Итак, что вы можете сделать, это: -использовать одну цепь - 1-й процесс использует первые 10 номеров цепочки. - 2-й процесс использует 11-20-й номер цепочки. ......

Но это означает, что данный процесс должен отказаться от заданного количества элементов в цепочке. Если вы используете «обычный» генератор случайных чисел, отбрасывание n чисел является операцией O (n). Это означает, что вы не можете распараллелить вашу проблему. Что вам нужно, так это использовать генератор случайных чисел, который содержит метод для отбрасывания n draw в O (1). Существует множество таких методов, которые вы можете найти в Интернете. Или вы можете написать его самостоятельно (но это действительно попытка изобретать велосипед).

Сам использую: https://rdrr.io/cran/sitmo/
Но это для C ++, но вы наверняка сможете найти версию для C или откомпилировать только эту часть с C ++ ...

0 голосов
/ 19 апреля 2019

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

    if (myid == 0){
        int i;
        for (i=0; i<n; i++){
            initialize(x, n);
            if (i != myid){
                MPI_Send(&x[0], n, MPI_FLOAT, i, 0, comm);
            }
        }
    }else{
        MPI_Recv(&x[0], n, MPI_FLOAT, 0, 0, comm, MPI_STATUS_IGNORE);
    }
...