Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Magical libc.math.abs in Cython

How does cython manage to cimport abs from libc.math

from libc.math cimport abs

if it is not there?

> grep abs Cython/Includes/libc/math.pxd
<nothing>

I even tried deleting everything from that file (I got a 0 length math.pxd) yet it somehow contrives to find abs there.

Update

This is my third question about cython:

In the first question I found out that libcpp.complex is not written quite correctly, @axil raised a ticket in cython github repo then made a pull request with my fix that replaces about 20% of complex.pyd lines. So it makes sense for cython user to look into includes directory from time to time.

The second question addressed the abs builtin which supposedly was overlooked by cython authors in that it doesn't translate python code to c at all and calls the original python abs function. The solution involves patching cython/compiler/Builtin.py file.

Now my third question is again about abs function, now imported from 'libc.math'. It does work, but they way it works looks really bizzare to me. In my opinion there's quite enough magic in Cython without importing a function from a module that doesn't have it.

Update 2:

It turns out that is that abs() does not get imported from lib.math. In fact, this import is just ignored:

 1: from libc.math cimport abs                   # nothing changes when I comment it out
 2: 
+3: def f():                                     # yellow
+4:     cdef double complex aaa = 1 + 2j         # white 
+5:     cdef double bbb = abs(aaa)               # yellow

__pyx_t_1 = __pyx_PyComplex_FromComplex(__pyx_v_aaa); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 5, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_2 = PyNumber_Absolute(__pyx_t_1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 5, __pyx_L1_error)
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_3 = __pyx_PyFloat_AsDouble(__pyx_t_2); if (unlikely((__pyx_t_3 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 5, __pyx_L1_error)
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_v_bbb = __pyx_t_3;

It should be noted though that @DavidW's patch from my previous question fixes it in the sense that last line becomes white (gets compiled to c). Yet I don't understand why cimporting abs is ignored.

Update 3

Yet another observation is that importing abs() from libcpp.complex works as expected:

# distutils: language = c++
from libcpp.complex cimport complex, abs

ctypedef complex[double] dcomplex

def f():
    cdef dcomplex aaa = dcomplex(1, 2)
    cdef double bbb = abs[double](aaa)
    return bbb

So it isn't a big deal for cython to cimport a builtin.

like image 607
Antony Hatchkins Avatar asked Mar 29 '17 04:03

Antony Hatchkins


2 Answers

In C, the "built-in" or globally-available absolute-value function abs is only for integers (and labs for longs). The absolute-value function or floating-point numbers is fabs, found in "math.h".

This translates to using libc.stdlib.abs for integers, libc.math.fabs for doubles, and abs (built-in) for all Python objects. Only the built-in abs requires GIL.

like image 61
Epic Wink Avatar answered Nov 05 '22 07:11

Epic Wink


Cython pxd files located in {Python_path}/.../site_packages/Cython/Includes So if look at libc/stdlib.pxd then you will see that stdlib.pxd got abs() and libcpp/complex.pxd have a template function abs for complex numbers template class. In libc/math.pxd you can find fabs() for floating point types.

like image 41
Кирилл Солодских Avatar answered Nov 05 '22 07:11

Кирилл Солодских