Created
February 12, 2021 13:52
-
-
Save danieljfarrell/7440be77b3e4d975469af3307f9cb19a to your computer and use it in GitHub Desktop.
Cython example showing numpy to C struct
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#cython: language_level=3 | |
import cython | |
import numpy | |
cimport numpy as cnumpy | |
# Silly example C struct | |
cdef struct example: | |
int a | |
double b | |
ctypedef example example_t | |
# Numpy dtype with same memory layout as the C struct | |
example_dtype = numpy.dtype( | |
[ | |
("a", numpy.int32), | |
("b", numpy.float64) | |
], | |
align=True | |
) | |
# align=True is important to get the same layout in memory | |
# as the C struct defined above. | |
@cython.boundscheck(False) | |
@cython.wraparound(False) | |
@cython.nonecheck(False) | |
@cython.cdivision(True) | |
def create(int n): | |
""" Return a numpy array of custom data type. | |
Numpy is fast! We want to use when we easily vectorise things. | |
Cython will still be faster! But using Numpy's helpful function | |
can save a huge amount of development time for pretty good | |
performance. | |
""" | |
arr = numpy.empty(n, dtype=example_dtype) | |
arr["a"][:] = 1 | |
arr["b"][:] = 2.0 | |
return arr | |
# Want to access the memory in the Numpy array as it is | |
# was C structures. | |
@cython.boundscheck(False) | |
@cython.wraparound(False) | |
@cython.nonecheck(False) | |
@cython.cdivision(True) | |
def number_crunch(cnumpy.ndarray arr): | |
""" Some algorithms are very hard to vectorise; it can be done but | |
the code is not so easy to read and can be prone to bugs. | |
This function demonstates direct acess to the Numpy arrays' | |
data buffer via a memory view. Direct access is fast, does | |
not need Python, and allows algorithms to be coded up using | |
for-loops. | |
""" | |
# Make sure struct and dtype have the same layout! | |
assert sizeof(example_t) == example_dtype.itemsize | |
cdef int i | |
cdef n = arr.shape[0] | |
# Make memory view of the array as the C struct! | |
cdef example_t [:] items = arr | |
for i in range(n): | |
# Fast C for-loop! No Python here. | |
# We are accessing the memory locations directly | |
items[i].a = 42 | |
items[i].b = 42 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from example import create, number_crunch | |
# Often we want to be able to do as much as possible in Python | |
# and Numpy and then drop down in C-level code when we need. | |
# | |
# This example shows how to inter-operate between Numpy and Cython | |
if __name__ == "__main__": | |
arr = create(3) | |
print("Create:", arr) | |
number_crunch(arr) | |
print("After:", arr) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment