ibell
ibell

Reputation: 1080

Overloading Python math functions using Cython

Here is my basic problem:

I have a Python file with an import of

from math import sin,cos,sqrt

I need this file to still be 100% CPython compatible to allow my developers to write 100% CPython code and employ the great tools developed for Python.

Now enter Cython. In my Python file, the trig functions get called millions of times (fundamental to the code, can't change this). Is there any way that through some Python-fu in the main python file, or Cython magic otherwise I can instead use the C/C++ math functions using some variation on the Cython code

cdef extern from "math.h":
    double sin(double)

That would give me near-C performance, which would be awesome.

Stefan's talk says specifically this can't be done, but the talk is two years old, and there are many creative people out there

Upvotes: 10

Views: 6970

Answers (4)

Dave Rove
Dave Rove

Reputation: 953

Answering this question eight years later, this is what worked for me on Ubuntu 19.10 using the system CPython vesion 3.7.5 and Cython3 version 0.29.10 from the Ubuntu repostory.

The Cython documents on Pure Python Mode give an example that works. It looks a bit different to the examples in the old answers here so I guess the document has been updated since.

The Python file needs a conditional import, which works fine using normal CPython:

#!/usr/bin/env python3
# from: https://cython.readthedocs.io/en/latest/src/tutorial/pure.html
# mymodule.py

import cython

# override with Python import if not in compiled code
if not cython.compiled:
    from math import sin

# calls sin() from math.h when compiled with Cython and math.sin() in Python
print(sin(0.5))

The Cython language constructs must be put in a file with the same name but a ".pxd" suffix:

#cython: language_level=3
# from: https://cython.readthedocs.io/en/latest/src/tutorial/pure.html
# mymodule.pxd

# declare a C function as "cpdef" to export it to the module
cdef extern from "math.h":
    cpdef double sin(double x)

I used the "--embed" option to create C-code for a stand-alone Linux ELF executable to test this. The GCC compiler line needs "-lm" to import the maths module that contains sin.

cython3 --embed mymodule.py

gcc -o mymodule mymodule.c -I/usr/include/python3.7 -lpython3.7m -lm

Upvotes: 1

Brett Morris
Brett Morris

Reputation: 831

In an example from Cython's documentation, they use a cimport from a C library to achieve this:

from libc.math cimport sin

Upvotes: 4

James
James

Reputation: 3231

I may have misunderstood your problem, but the Cython documentation on interfacing with external C code seems to suggest the following syntax:

cdef extern from "math.h":
    double c_sin "sin" (double)

which gives the function the name sin in the C code (so that it correctly links to the function from math.h), and c_sin in the Python module. I'm not really sure I understand what this achieves in this case, though - why would you want to use math.sin in Cython code? Do you have some statically typed variables, and some dynamically typed ones?

Upvotes: 0

Danica
Danica

Reputation: 28846

I'm not a Cython expert, but AFAIK, all you could do is write a Cython wrapper around sin and call that. I can't imagine that's really going to be faster than math.sin, though, since it's still using Python calling semantics -- the overhead is in all the Python stuff to call the function, not the actual trig calculations, which are done in C when using CPython too.

Have you considered using Cython pure mode, which makes the source CPython-compatible?

Upvotes: 2

Related Questions