[Numpy-discussion] Writing new ufuncs

Robert Kern robert.kern@gmail....
Sun May 11 21:35:03 CDT 2008


On Sun, May 11, 2008 at 1:04 PM, Anne Archibald
<peridot.faceted@gmail.com> wrote:
> Hi,
>
> Suppose I have a C function,
> double logsum(double a, double b);
> What is needed to produce a ufunc object whose elementwise operation
> is done by calling this function?

Basically, you need 3 arrays: functions implementing the type-specific
inner loops, void* extra data to pass to these functions, and an array
of arrays containing the type signatures of the ufunc. In numpy, we
already have generic implementations of the loop functions for common
combinations of types. In your case, for a binary function taking two
doubles and returning a double, we have PyUFunc_dd_d(). As its extra
void* data, it takes a function pointer that actually implements the
element-wise operation. So lets start making the arrays:

static char logsum_sigs[] = {
    NPY_FLOAT64, NPY_FLOAT64, NPY_FLOAT64
};
static PyUFuncGenericFunction logsum_functions[] = {PyUFunc_dd_d};
static void* logsum_data[] = {logsum};
static char logsum_doc[] = "Some kind of docstring.";

Now in your initmodule() function, we will call PyUFunc
FromFuncAndData() with this information.

PyMODINIT_FUNC initmodule(void)
{
    PyObject *m, *f, *d;
    m = Py_InitModule3("module", module_methods,
        "Some new ufuncs.\n"
    );
    if (m == NULL)
        return;
    d = PyModule_GetDict(m);
    if (d == NULL)
        return;
    import_array();
    import_umath();

    f = PyUFunc_FromFuncAndData(
            logsum_functions,
            logsum_data,
            logsum_sigs,
            1,  // The number of type signatures.
            2,  // The number of inputs.
            1,  // The number of outputs.
            PyUFunc_None,  // The identity element for reduction.
                           // No good one to use for this function,
                           // unfortunately.
            "logsum",  // The name of the ufunc.
            logsum_doc,
            0  // Dummy for API backwards compatibility.
    );
    PyDict_SetItemString(d, "logsum", f);
    Py_DECREF(f);
}

Since double functions can easily be used on float32's, too, you can
also add PyUFunc_ff_f to the logsum_functions array and

  NPY_FLOAT32, NPY_FLOAT32, NPY_FLOAT32,

to the corresponding place in the logsum_sigs array. Just bump the
number of signatures up to 2.

-- 
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless
enigma that is made terrible by our own mad attempt to interpret it as
though it had an underlying truth."
 -- Umberto Eco


More information about the Numpy-discussion mailing list