How to represent inf or -inf in Cython with numpy?

23,954

Solution 1

There's no literal for it, but float can parse it from a string:

>>> float('inf')
inf
>>> np.inf == float('inf')
True

Alternatively, math.h may (almost certainly will) declare a macro that evaluates to inf, in which case you can just use that:

cdef extern from "math.h":
    float INFINITY

(There's no clean way to check if INFINITY is defined in pure Cython, so if you want to cover all your bases you'll need to get hacky. One way of doing it is to create a small C header, say fallbackinf.h:

#ifndef INFINITY
#define INFINITY 0
#endif

And then in your .pyx file:

cdef extern from "math.h":
    float INFINITY

cdef extern from "fallbackinf.h":
    pass

inf = INFINITY if INFINITY != 0 else float('inf')

(You can't assign to INFINITY, because it's an rvalue. You could do away with the ternary operator if you #defined INFINITY as 1.0/0.0 in your header, but that might raise SIGFPE, depending on your compiler.)

This is definitely in the realm of cargo cult optimisation, though.)

Solution 2

The recommended way of doing this in Cython is:

from numpy.math cimport INFINITY

Note, that this is a "cimport" rather than a regular import. This is Cython's official wrapper around NumPy's npymath.

Solution 3

You can use Numpy's math library, see here for what's available:

cdef extern from "numpy/npy_math.h":
    double inf "NPY_INFINITY"

When building the Cython extension module, you need to specify the correct include directory and library to link:

>>> from numpy.distutils.misc_util import get_info
>>> get_info('npymath')
{'define_macros': [], 
 'libraries': ['npymath', 'm'], 
 'library_dirs': ['/usr/lib/python2.7/dist-packages/numpy/core/lib'], 
 'include_dirs': ['/usr/lib/python2.7/dist-packages/numpy/core/include']}

The information obtained from that function can be passed onto Python distutils, or whatever build system you use.

Share:
23,954
Admin
Author by

Admin

Updated on December 09, 2020

Comments

  • Admin
    Admin over 3 years

    I am building an array with cython element by element. I'd like to store the constant np.inf (or -1 * np.inf) in some entries. However, this will require the overhead of going back into Python to look up inf. Is there a libc.math equivalent of this constant? Or some other value that could easily be used that's equivalent to (-1*np.inf) and can be used from Cython without overhead?

    EDIT example, you have:

    cdef double value = 0
    for k in xrange(...):
      # use -inf here -- how to avoid referring to np.inf and calling back to python?
      value = -1 * np.inf
    
  • Admin
    Admin about 11 years
    but if I use float within a Cython loop, will that involve calling back to Python? I edited my answer to give an example.
  • Cairnarvon
    Cairnarvon about 11 years
    Ultimately that calls PyFloat_AsDouble every time, which isn't that slow, but not something you want to do more often than necessary; assign it to a constant once, outside the loop. But I've updated my answer with a different, compile-time method.
  • Admin
    Admin about 11 years
    Thanks! your cdef extern... works great. Are there systems/conditions where it might not work, or should it work on any python distribution / OS?
  • Cairnarvon
    Cairnarvon about 11 years
    The INFINITY macro was added in C99; if your math.h is older, it's not guaranteed to be there (though it probably still will be). In practice, it should be fine.
  • Admin
    Admin about 11 years
    Last question: is it possible to programmatically check for INFINITY (if it exists) through Cython and if not, default to float('inf')?
  • Cairnarvon
    Cairnarvon about 11 years
    Not cleanly. I've added what I believe to be the easiest way to my answer.
  • hlin117
    hlin117 over 8 years
    I get the error fatal error: 'numpy/npy_math.h' file not found. Anyone else get this?
  • Tom
    Tom over 7 years
    @hlin117, nope. Probably something wrong with your setup. This answer is still the recommended way to get infinity.
  • The Unfun Cat
    The Unfun Cat almost 6 years
    Can you provide a cite for "the recommended way..."?
  • Tom
    Tom almost 6 years
    Are you being overly pedantic? If you want to use Numpy's stuff, then this a cleaner way than using a cdef extern. If you want to use math.h, then it looks like from libc.math cimport INFINITY is now available, which could also work. Both of these options are better than the other two answers given, especially if you are working on any modern platform.
  • Tom
    Tom almost 6 years
    Also, see the example of using cimport here: cython.readthedocs.io/en/latest/src/tutorial/…