Skip to content

DOCS: New ufunc creation docs #132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions doc/source/reference/c-api.coremath.rst
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,9 @@ Linking against the core math library in an extension
To use the core math library in your own extension, you need to add the npymath
compile and link options to your extension in your setup.py:

>>> from numpy.distutils.misc_utils import get_info
>>> from numpy.distutils.misc_util import get_info
>>> info = get_info('npymath')
>>> config.add_extension('foo', sources=['foo.c'], extra_info=**info)
>>> config.add_extension('foo', sources=['foo.c'], extra_info=info)

In other words, the usage of info is exactly the same as when using blas_info
and co.
Expand Down
180 changes: 0 additions & 180 deletions doc/source/user/c-info.beyond-basics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -204,186 +204,6 @@ There are several examples of using the multi-iterator in the NumPy
source code as it makes N-dimensional broadcasting-code very simple to
write. Browse the source for more examples.

.. _`sec:Creating-a-new`:

Creating a new universal function
=================================

.. index::
pair: ufunc; adding new

The umath module is a computer-generated C-module that creates many
ufuncs. It provides a great many examples of how to create a universal
function. Creating your own ufunc that will make use of the ufunc
machinery is not difficult either. Suppose you have a function that
you want to operate element-by-element over its inputs. By creating a
new ufunc you will obtain a function that handles

- broadcasting

- N-dimensional looping

- automatic type-conversions with minimal memory usage

- optional output arrays

It is not difficult to create your own ufunc. All that is required is
a 1-d loop for each data-type you want to support. Each 1-d loop must
have a specific signature, and only ufuncs for fixed-size data-types
can be used. The function call used to create a new ufunc to work on
built-in data-types is given below. A different mechanism is used to
register ufuncs for user-defined data-types.

.. cfunction:: PyObject *PyUFunc_FromFuncAndData( PyUFuncGenericFunction* func,
void** data, char* types, int ntypes, int nin, int nout, int identity,
char* name, char* doc, int check_return)

*func*

A pointer to an array of 1-d functions to use. This array must be at
least ntypes long. Each entry in the array must be a
``PyUFuncGenericFunction`` function. This function has the following
signature. An example of a valid 1d loop function is also given.

.. cfunction:: void loop1d(char** args, npy_intp* dimensions,
npy_intp* steps, void* data)

*args*

An array of pointers to the actual data for the input and output
arrays. The input arguments are given first followed by the output
arguments.

*dimensions*

A pointer to the size of the dimension over which this function is
looping.

*steps*

A pointer to the number of bytes to jump to get to the
next element in this dimension for each of the input and
output arguments.

*data*

Arbitrary data (extra arguments, function names, *etc.* )
that can be stored with the ufunc and will be passed in
when it is called.

.. code-block:: c

static void
double_add(char *args, npy_intp *dimensions, npy_intp *steps,
void *extra)
{
npy_intp i;
npy_intp is1=steps[0], is2=steps[1];
npy_intp os=steps[2], n=dimensions[0];
char *i1=args[0], *i2=args[1], *op=args[2];
for (i=0; i<n; i++) {
*((double *)op) = *((double *)i1) + \
*((double *)i2);
i1 += is1; i2 += is2; op += os;
}
}

*data*

An array of data. There should be ntypes entries (or NULL) --- one for
every loop function defined for this ufunc. This data will be passed
in to the 1-d loop. One common use of this data variable is to pass in
an actual function to call to compute the result when a generic 1-d
loop (e.g. :cfunc:`PyUFunc_d_d`) is being used.

*types*

An array of type-number signatures (type ``char`` ). This
array should be of size (nin+nout)*ntypes and contain the
data-types for the corresponding 1-d loop. The inputs should
be first followed by the outputs. For example, suppose I have
a ufunc that supports 1 integer and 1 double 1-d loop
(length-2 func and data arrays) that takes 2 inputs and
returns 1 output that is always a complex double, then the
types array would be


The bit-width names can also be used (e.g. :cdata:`NPY_INT32`,
:cdata:`NPY_COMPLEX128` ) if desired.

*ntypes*

The number of data-types supported. This is equal to the number of 1-d
loops provided.

*nin*

The number of input arguments.

*nout*

The number of output arguments.

*identity*

Either :cdata:`PyUFunc_One`, :cdata:`PyUFunc_Zero`,
:cdata:`PyUFunc_None`. This specifies what should be returned when
an empty array is passed to the reduce method of the ufunc.

*name*

A ``NULL`` -terminated string providing the name of this ufunc
(should be the Python name it will be called).

*doc*

A documentation string for this ufunc (will be used in generating the
response to ``{ufunc_name}.__doc__``). Do not include the function
signature or the name as this is generated automatically.

*check_return*

Not presently used, but this integer value does get set in the
structure-member of similar name.

.. index::
pair: ufunc; adding new

The returned ufunc object is a callable Python object. It should be
placed in a (module) dictionary under the same name as was used in the
name argument to the ufunc-creation routine. The following example is
adapted from the umath module

.. code-block:: c

static PyUFuncGenericFunction atan2_functions[]=\
{PyUFunc_ff_f, PyUFunc_dd_d,
PyUFunc_gg_g, PyUFunc_OO_O_method};
static void* atan2_data[]=\
{(void *)atan2f,(void *) atan2,
(void *)atan2l,(void *)"arctan2"};
static char atan2_signatures[]=\
{NPY_FLOAT, NPY_FLOAT, NPY_FLOAT,
NPY_DOUBLE, NPY_DOUBLE,
NPY_DOUBLE, NPY_LONGDOUBLE,
NPY_LONGDOUBLE, NPY_LONGDOUBLE
NPY_OBJECT, NPY_OBJECT,
NPY_OBJECT};
...
/* in the module initialization code */
PyObject *f, *dict, *module;
...
dict = PyModule_GetDict(module);
...
f = PyUFunc_FromFuncAndData(atan2_functions,
atan2_data, atan2_signatures, 4, 2, 1,
PyUFunc_None, "arctan2",
"a safe and correct arctan(x1/x2)", 0);
PyDict_SetItemString(dict, "arctan2", f);
Py_DECREF(f);
...


.. _user.user-defined-data-types:

User-defined data-types
Expand Down
1 change: 1 addition & 0 deletions doc/source/user/c-info.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ Using Numpy C-API

c-info.how-to-extend
c-info.python-as-glue
c-info.ufunc-tutorial
c-info.beyond-basics
Loading