Я работаю над преобразованием сэмплера Гибба, написанного на питоне, в 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 бит.
Да, в C++ можно добиться тех же шагов генерации псевдослучайных чисел, что и в Python. Однако важно отметить, что разные генераторы случайных чисел могут иметь несколько разное поведение и детали реализации в разных языках программирования. Можете ли вы также показать, что вы написали на C++, чтобы получить представление о том, что вы ищете?
@πάνταῥεῖ Там есть std::random_device, это тоже не питон. С тегами проблем нет.
@Eldinur Извиняюсь, если я упустил какие-либо детали. Я не уверен, как реализовать часть Seedsequence. Итак, я использовал генератор случайных чисел pcg64 в С++.
@AdhithiS Как уже упоминалось выше, в вашем ответе нет кода C++. Пожалуйста, измените его, чтобы мы могли видеть, что вы сделали. (он не должен работать, он не должен быть идеальным. Но я хочу видеть код C++, а не только код Python)
@Eldinur Я обновил фрагмент кода.






В 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 :)
Для небольшого количества образцов я могу решить проблему воспроизводимости. Итак, я попробовал ''' 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()); '''
@AdhithiS Я не уверен, чего вы на самом деле хотите достичь ... Если rd действительно является std::random_device, как я понял из его названия, вы никогда не сможете воспроизвести. Вам нужны идентичные начальные числа для воспроизведения идентичных последовательностей, поэтому вы должны инициализировать генератор начальных значений с фиксированными значениями (или теми, которые вы анализируете из параметров командной строки), например std::seed_seq seq({12, 10, 51, 77, 54});
«И ниже приведен фрагмент, опробованный в cpp», нет, это не так.