Повторить генерацию генераторов случайных чисел с помощью Seedsequence в cpp

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

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

ss=np.random.SeedSequence()
child_states = ss.spawn(n) #n is the number of iterations
for i in range(0,n):   
     inference(child_states[i]); 
def inference(seed):
     child_states = seed.spawn(len(Docs))
     for i in range(len(Docs)):
            seq(seed);
def seq(seed):
     rng = np.random.default_rng(seed)
     for i in range(0,V):
        z=rng.multinomial(................)

И ниже приведен фрагмент, испробованный на С++ с использованием объекта pcg64:

void inference(){
     pcg_extras::seed_seq_from<std::random_device> seedSource;
     pcg64 rng(seedSource);
     for(int i=0;i<m;i++)
         gsl_rng_set(r, rng());
         for(int j=0;j<V;j++)
             gsl_ran_multinomial(..................)
                
}

Есть ли способ добиться тех же шагов генерации псевдослучайных чисел в CPP?

Обновление модификации: Для небольшого количества образцов я могу решить проблему воспроизводимости. Итак, что я пробовал, это

    std::vector<unsigned int> seed_values(10);
    std::generate(seed_values.begin(), seed_values.end(),        
    std::ref(rd));
    std::seed_seq seq(seed_values.begin(), seed_values.end()); 

сгенерировать набор из m семян и использовать его для генерации m последовательностей семян, подобных этому

    std::seed_seq seq{seed};
    std::vector<std::uint64_t> seeds(m);
    seq.generate(seeds.begin(), seeds.end()); 

Это хорошо работает для небольшого количества выборок, но когда количество выборок велико, кажется, что двум выборкам присваиваются одинаковые случайные числа. Будет ли проблемой количество битов семени, поскольку количество битов семени составляет не менее 128 бит в Python, тогда как в cpp оно достигает 64 бит.

«И ниже приведен фрагмент, опробованный в cpp», нет, это не так.

Passer By 30.05.2023 18:34

Да, в C++ можно добиться тех же шагов генерации псевдослучайных чисел, что и в Python. Однако важно отметить, что разные генераторы случайных чисел могут иметь несколько разное поведение и детали реализации в разных языках программирования. Можете ли вы также показать, что вы написали на C++, чтобы получить представление о том, что вы ищете?

Eldinur 30.05.2023 18:34

@πάνταῥεῖ Там есть std::random_device, это тоже не питон. С тегами проблем нет.

Passer By 30.05.2023 18:37

@Eldinur Извиняюсь, если я упустил какие-либо детали. Я не уверен, как реализовать часть Seedsequence. Итак, я использовал генератор случайных чисел pcg64 в С++.

Adhithi S 30.05.2023 18:46

@AdhithiS Как уже упоминалось выше, в вашем ответе нет кода C++. Пожалуйста, измените его, чтобы мы могли видеть, что вы сделали. (он не должен работать, он не должен быть идеальным. Но я хочу видеть код C++, а не только код Python)

Eldinur 30.05.2023 18:49

@Eldinur Я обновил фрагмент кода.

Adhithi S 30.05.2023 18:53
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
6
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В C++ генераторы псевдослучайных чисел обычно инициализируются следующим образом:

std::default_random_engine e((std::random_device())());

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

Если вы замените это фиксированным начальным числом, вы получите идентичную последовательность псевдослучайных чисел независимо от того, как часто вы запускаете скомпилированную программу; попробуйте, например,

std::default_random_engine e(1012);
std::uniform_int_distribution<int> uid(0, 1000);
for(size_t i = 1; i <= 100; ++i)
{
    std::cout << std::setw(3) << uid(e) << (i % 10 ? ' ' : '\n');
}
std::cout.flush();

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

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

Выше используется стандартная случайная библиотека С++ (которую я бы рекомендовал вместо какой-либо сторонней библиотеки), поскольку я не знаком с библиотекой PCG. Если вы предпочитаете продолжить с последним: этот использует генератор семян, я не знаю, как часто он будет вызывать его, хотя мне кажется разумным предположить, что только один раз. Если теперь вы замените std::random_device в своем фрагменте кода на пользовательский, вы позволите всегда возвращать одно и то же предопределенное начальное число в его operator() (вы можете настроить статическую переменную для управления им с помощью параметров командной строки), тогда вы можете снова надежно воспроизвести те же последовательности ( но вам нужно проверить самостоятельно...).

Большое спасибо за ссылку cppreference. Я могу воспроизвести результаты, используя функцию генерации, определенную в классе seed_seq :)

Adhithi S 30.05.2023 19:32

Для небольшого количества образцов я могу решить проблему воспроизводимости. Итак, я попробовал ''' std::vector<unsigned int> seed_values(10); std::generate(seed_values.begin(), seed_values.end(), std::ref(rd)); std::seed_seq seq(seed_values.begin(), seed_values.end()); ''' сгенерировать набор из m начальных чисел и использовать его для создания m последовательностей начальных значений, подобных этому ''' std::seed_seq seq{seed}; std::vector<std::uint64_t> семена (м); seq.generate(seeds.begin(), seed.end()); '''

Adhithi S 31.05.2023 05:56

@AdhithiS Я не уверен, чего вы на самом деле хотите достичь ... Если rd действительно является std::random_device, как я понял из его названия, вы никогда не сможете воспроизвести. Вам нужны идентичные начальные числа для воспроизведения идентичных последовательностей, поэтому вы должны инициализировать генератор начальных значений с фиксированными значениями (или теми, которые вы анализируете из параметров командной строки), например std::seed_seq seq({12, 10, 51, 77, 54});

Aconcagua 31.05.2023 10:20

Другие вопросы по теме