Skip to content

Instantly share code, notes, and snippets.

@danieljfarrell
Created February 12, 2021 13:52
Show Gist options
  • Save danieljfarrell/7440be77b3e4d975469af3307f9cb19a to your computer and use it in GitHub Desktop.
Save danieljfarrell/7440be77b3e4d975469af3307f9cb19a to your computer and use it in GitHub Desktop.
Cython example showing numpy to C struct
#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
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