Random 从Python调用快速C Mersenne Twister实现(SFMT)

Random 从Python调用快速C Mersenne Twister实现(SFMT),random,python-c-api,mersenne-twister,Random,Python C Api,Mersenne Twister,我试图从Python中调用SFMT Mersenne Twister实现(位于)。我这样做是因为我希望能够快速地从一个离散的pdf样本中抽取4个概率。我正在写一些模拟,这是我代码中最慢的部分 我成功地编写了一些C代码,并使用SFMT算法创建的[0,1]中的随机数对输入PDF进行采样 但是,当从Python调用时,我不知道如何正确初始化SFMT随机数生成器。当然,我只想初始化它一次,然后我需要将用于初始化它的结构的地址(sfmt)传递到我对sfmt\u genrand\u real1的调用中 因此

我试图从Python中调用SFMT Mersenne Twister实现(位于)。我这样做是因为我希望能够快速地从一个离散的pdf样本中抽取4个概率。我正在写一些模拟,这是我代码中最慢的部分

我成功地编写了一些C代码,并使用SFMT算法创建的[0,1]中的随机数对输入PDF进行采样

但是,当从Python调用时,我不知道如何正确初始化SFMT随机数生成器。当然,我只想初始化它一次,然后我需要将用于初始化它的结构的地址(
sfmt
)传递到我对
sfmt\u genrand\u real1
的调用中

因此,一些示例代码是:

// Create a struct which stores the Mersenne Twister's state
sfmt_t sfmt;

// Initialise the MT with a random seed from the system time
// NOTE: Only want to do this once
int seed = time(NULL);
sfmt_init_gen_rand(&sfmt, seed);

// Get a random number
double random_number = sfmt_genrand_real1(&sfmt);
问题是,当从Python调用此代码时,我不知道如何仅为SFMT随机数生成器种子设定一次。如果我只是用C编写所有内容,我会在main()函数中进行初始化,然后将
&sfmt
参数传递给所有后续的
sfmt\u genrand\u real1()
调用

但是因为我正在编译这个C代码,然后从Python调用它,所以我不能初始化这个变量一次。现在,我在调用
sfmt\u genrand\u real1()
之前就坚持了初始化,因为这是唯一可以让代码编译并能够访问随机数生成器调用中的
sfmt
变量的方法。我所有试图以某种方式使
sfmt
变量“全局”的尝试都适得其反

因此,我的问题是:是否有一种方法可以只初始化C SFMT随机数生成器一次,然后在我随后从Python调用
C\u random\u sample
时访问用于该初始化的
SFMT
结构?

在此,非常感谢任何能提供帮助的人

这是我的C代码全文。(要进行编译,需要将所有SMFT
.c
.h
文件放在同一个文件夹中,然后使用
python setup.py build\u ext--inplace
进行编译)

#包括“Python.h”
#包括
#包括
#包括“SFMT.h”
双稳态*
获取双数组(PyObject*数据)
{
int i,大小;
双重*输出;
PyObject*seq;
seq=PySequence_Fast(数据,“预期序列”);
如果(!seq)
返回NULL;
尺寸=PySequence_尺寸(序号);
如果(尺寸<0)
返回NULL;
out=(双精度*)PyMem_Malloc(尺寸*sizeof(双精度));
如果(!out){
Py_DECREF(seq);
PyErr_nomery();
返回NULL;
}

对于(i=0;i
sfmt
在C中处于全局范围:

static sfmt_t sfmt; /* outside any functions */
初始化在模块
init
函数中进行-当模块第一次导入Python时,调用一次:

PyMODINIT_FUNC initc_random_sample(void)
{
    /* Py_InitModule4 to initialize the module as before */ 

    int seed = time(NULL);
    sfmt_init_gen_rand(&sfmt, seed);
}

这并不完全是您想要的,但是如果您不介意依赖项(主要是Numpy和Cython),您可能会发现包含许多快速随机数生成器(特别是dSFMT)的库非常有用

如果您可以使用它,它将为您节省编写C包装器的工作


此外,该模块(或至少某些功能?)将来可能会合并到Numpy中(参见Numpy公开发行版)。

这种PRNG可能仍然比较新的模块(PCG、xoroshiro和co.)慢得多。甚至可以在python中使用(通过外部libs)。但更重要的是:也许你应该先展示你的代码来解释这一性能。我可以想象出除了PRNG之外的一些原因是造成这种缓慢的原因。感谢你的回复sascha。我正在编写一个模拟器,它需要从依赖于系统当前状态的分布中随机抽取数字。所以我不能轻易地提前缓存样本。基本上Python对于我所追求的东西来说太慢了,这就是为什么我转向C。不过我会看看你提到的那些PRNG,谢谢。我刚刚对SFMT和PCG进行了快速测试。SFMT创建10亿uint32\t随机数的速度似乎是前者的两倍。虽然建议它可以很快。也许我做错了什么。谢谢你向我指出sascha。通过在C中定义Python类,并在类的构造函数中初始化随机数生成器,我已经克服了初始化问题。我明白了。我认为离散采样的用法有点错误(如果使用O(1)采样,则每次都要为设置付费)。但我现在看到,您的案例是高度动态的,变化很大。请记住,Python在core+numpy中的PRNG实现也是C代码。但如果正确完成,相信您的基准测试肯定没有错。
PyMODINIT_FUNC initc_random_sample(void)
{
    /* Py_InitModule4 to initialize the module as before */ 

    int seed = time(NULL);
    sfmt_init_gen_rand(&sfmt, seed);
}