简体   繁体   English

如何在ufunc中使用numpy的随机数生成器?

[英]How to use numpy's random number generator in a ufunc?

Basically I have a ufunc that requires some randomness. 基本上我有一个需要一些随机性的ufunc。 In order to keep the ufuncs as reproducible as possible I would like to use numpy's random number generator for that; 为了使ufunc尽可能地可重现,我想使用numpy的随机数生成器。 basically because setting the seed will be more intuitive this way. 基本上是因为通过这种方式设置种子会更加直观。

However I cannot find the documentation of the numpy.random C-API (does it have one?). 但是我找不到numpy.random C-API的文档(它有一个吗?)。

My current approach looks like that: 我当前的方法如下所示:

#include <numpy/random.h> // does not exist
...

static void
ufunc_M( char ** args
       , npy_intp * dimensions
       , npy_intp * steps
       , void * data)
{
    basic_gate_argument_t argument = *((basic_gate_argument_t *) data);
    PYQCS_GATE_GENERIC_SETUP;
    npy_intp i;


    npy_double amplitude_1 = 0;

    for(i = 0; i < ndim; i++)
    {
        if(i & (1 << argument.act))
        {
            amplitude_1 += qm_in[i].real * qm_in[i].real;
            amplitude_1 += qm_in[i].imag * qm_in[i].imag;
        }
    }

    npy_double rand = random_uniform(0, 1); // does not exist

    ...

    *measured_out = 1 << argument.act;
}

...

As it turns out: one cannot do it using the numpy.random library directly. 事实证明:不能直接使用numpy.random库来做到这一点。 I found out about that after searching the numpy headers for a while. 在搜索了numpy标头一段时间后,我发现了这一点。 The random library is just not exported. 只是不导出随机库。

My workaround is passing a python callable to the ufunc: 我的解决方法是将可调用的python传递给ufunc:

static void
ufunc_M( char ** args
       , npy_intp * dimensions
       , npy_intp * steps
       , void * data)
{
    basic_gate_argument_t argument = *((basic_gate_argument_t *) data);
    PYQCS_GATE_GENERIC_SETUP;
    npy_intp i;

    ...

    npy_double randr;
    //==================================================//
    // Get some random value. I do not like the way this
    // is done but it seems like there is no better way.
    PyObject * random_result = PyObject_CallFunctionObjArgs(argument.rng, NULL);

    if(!PyFloat_Check(random_result))
    {
        randr = 0;
    }
    else
    {
        randr = PyFloat_AsDouble(random_result);
    }
    Py_DECREF(random_result);
    //==================================================//

    ...
}

One must check wheter the passed object is a callable when constructing the ufunc: 在构造ufunc时,必须检查传递的对象是否可调用:

static int
BasicGate_init
    ( BasicGate * self
    , PyObject * args)
{
    char type;

    if(!PyArg_ParseTuple(args, "ClldO"
                , &type
                , &(self->argument.act)
                , &(self->argument.control)
                , &(self->argument.r)
                , &(self->argument.rng))
            )
    {
        return -1;
    }

    if(!PyCallable_Check(self->argument.rng))
    {
        PyErr_SetString(PyExc_TypeError, "random (5th argument) must be a callable (returning float)");
        return -1;
    }

  ...

        case 'M':
        {
            self->ufunc = PyUFunc_FromFuncAndDataAndSignature(
                ufunc_M_funcs // func
                , self->data // data
                , ufunc_types //types
                , 1 // ntypes
                , 2 // nin
                , 3 // nout
                , PyUFunc_None // identity
                , "M_function" // name
                , "Computes the M (Measurement) gate on a state." // doc
                , 0 // unused
                , "(n),(m)->(n),(m),()"); 

    ...
}

Ufuncs however cannot fail, so when the passed function does not return PyFloat s the ufunc will produce nonsense. 但是,ufunc不会失败,因此当传递的函数不返回PyFloat会产生废话。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM