summaryrefslogtreecommitdiff
path: root/docs/src/userguide/numpy_ufuncs.rst
blob: b5df3686143585474e005c93123028d504c7bb96 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
.. highlight:: cython

.. _numpy-ufuncs:

*********************
Creating Numpy ufuncs
*********************

.. include::
    ../two-syntax-variants-used

Numpy supports a `special type of function called a ufunc
<https://numpy.org/doc/stable/reference/ufuncs.html>`_ .
These support array broadcasting (i.e. the ability to handle arguments with any
number of dimensions), alongside other useful features.

Cython can generate a ufunc from a Cython C function by tagging it with the ``@cython.ufunc``
decorator. The input and output argument types should be scalar variables ("generic ufuncs" are
not yet supported) and should either by Python objects or simple numeric types. The body
of such a function is inserted into an efficient, compiled loop.

.. tabs::

    .. group-tab:: Pure Python

        .. literalinclude:: ../../examples/userguide/numpy_ufuncs/ufunc.py
            :lines: 2-

    .. group-tab:: Cython

        .. literalinclude:: ../../examples/userguide/numpy_ufuncs/ufunc.pyx
            :lines: 2-

You can have as many arguments to your function as you like. If you want to have multiple
output arguments then you can use the :ref:`ctuple syntax<typing_types>`:

.. tabs::

    .. group-tab:: Pure Python

        .. literalinclude:: ../../examples/userguide/numpy_ufuncs/ufunc_ctuple.py
            :lines: 2-

    .. group-tab:: Cython

        .. literalinclude:: ../../examples/userguide/numpy_ufuncs/ufunc_ctuple.pyx
            :lines: 2-

If you want to accept multiple different argument types then you can use :ref:`fusedtypes`:

.. tabs::

    .. group-tab:: Pure Python

        .. literalinclude:: ../../examples/userguide/numpy_ufuncs/ufunc_fused.py
            :lines: 2-

    .. group-tab:: Cython

        .. literalinclude:: ../../examples/userguide/numpy_ufuncs/ufunc_fused.pyx
            :lines: 2-

Finally, if you declare the ``cdef``/``@cfunc`` function as ``nogil`` then Cython will release the
:term:`GIL<Global Interpreter Lock or GIL>` once in the generated ufunc. This is a slight difference
from the general behaviour of ``nogil`` functions (they generally do not automatically
release the GIL, but instead can be run without the GIL).

This feature relies on Numpy. Therefore if you create a ufunc in
Cython, you must have the Numpy headers available when you build the generated C code, and
users of your module must have Numpy installed when they run it.