我正试图从Python调用SFMT Mersenne Twister实现(在http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/找到)。我这样做是因为我希望能够从具有4个概率的离散pdf中快速采样。我正在编写一些模拟,这是我代码中最慢的一部分。
我设法编写了一些有效的C代码,并使用SFMT算法创建的[0,1]中的随机数对输入PDF进行采样。
然而我不知道如何在从Python 调用时正确初始化SFMT随机数生成器。我当然只想初始化它一次,然后我需要将用于初始化它的结构的地址(sfmt
)传递给我对sfmt_genrand_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_genrand_real1()
调用。
但是因为我正在编译这个C代码,然后从Python调用它,我不能初始化该变量一次。就目前而言,我已经在sfmt_genrand_real1()
调用之前停留了初始化,因为这是我能够让代码甚至编译并且能够在随机调用中访问sfmt
变量的唯一方法数字生成器。我试图以某种方式使sfmt
变量“全局”适得其反。
所以我的问题是:有没有办法初始化C SFMT随机数生成器一次,然后在sfmt
的所有后续调用中访问c_random_sample
struct用于初始化来自Python?
非常感谢任何可以提供帮助的人。
这是我的C代码。 (要编译,您需要将所有SMFT .c
和.h
文件放在同一文件夹中,然后使用python setup.py build_ext --inplace
进行编译。
#include "Python.h"
#include <stdio.h>
#include <time.h>
#include "SFMT.h"
static double*
get_double_array(PyObject* data)
{
int i, size;
double* out;
PyObject* seq;
seq = PySequence_Fast(data, "expected a sequence");
if (!seq)
return NULL;
size = PySequence_Size(seq);
if (size < 0)
return NULL;
out = (double*) PyMem_Malloc(size * sizeof(double));
if (!out) {
Py_DECREF(seq);
PyErr_NoMemory();
return NULL;
}
for (i=0; i<size; i++) {
out[i] = PyFloat_AsDouble(PySequence_Fast_GET_ITEM(seq, i));
}
Py_DECREF(seq);
if (PyErr_Occurred()) {
PyMem_Free(out);
out = NULL;
}
return out;
}
static PyObject*
c_random_sample(PyObject* self, PyObject* args)
{
int i;
double* pdf;
PyObject* pdf_in;
if (!PyArg_ParseTuple(args, "O:c_random_sample", &pdf_in))
return NULL;
pdf = get_double_array(pdf_in);
if (!pdf)
return NULL;
// Create a struct which stores the Mersenne Twister's state
sfmt_t sfmt;
int seed = time(NULL);
// Initialise the MT with a random seed from the system time
sfmt_init_gen_rand(&sfmt, seed);
// NOTE: This simply re-initialises the random number generator
// on every call. We need to only initialise it once...
double r = sfmt_genrand_real1(&sfmt);
for (i=0; i<4; i++) {
r -= pdf[i];
if (r < 0) {
break;
}
}
PyMem_Free(pdf);
return PyInt_FromLong(i);
}
static PyMethodDef functions[] = {
{"c_random_sample", c_random_sample, METH_VARARGS},
{NULL, NULL}
};
PyMODINIT_FUNC initc_random_sample(void)
{
Py_InitModule4(
"c_random_sample", functions, "Trying to implement random number sampling in C", NULL, PYTHON_API_VERSION
);
}
答案 0 :(得分:0)
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);
}
答案 1 :(得分:0)
这并不是你想要的,但如果你不介意依赖(主要是Numpy和Cython),你会发现有用的ng-numpy-randomstate库有很多快速随机数生成器(特别是dSFMT)。
如果你可以使用它,它将为你节省编写C包装器的工作。
此外,此模块(或至少某些功能?)将来可能会在Numpy中合并(参见Numpy open issue #6967)。