Repository navigation
BUG: Cython Extension Fails to Compile if C variable I is used. #26787
Description
Describe the issue:
I have a Cython extension that uses the variable double I in a wrapped C function. This fails to compile with the introduction of NumPy 2.0. This specifically results when users in SymPy have chosen that a symbolic variable be named Symbol('I') and then we print C code using that variable and compile on the fly with Cython in our various code generation tools. I believe that this variable must clash with something defined in the included NumPy headers.
Reproduce the code example:
`ufuncify_matrix_1_h.h`:
void eval_matrix(double matrix[],
double thetai,
double omegai,
double thetap,
double omegap,
double Ti,
double I,
double m,
double g,
double d,
double h);
`ufuncify_matrix_1_c.c`:
```c
#include <math.h>
#include "ufuncify_matrix_1_h.h"
void eval_matrix(double matrix[],
double thetai,
double omegai,
double thetap,
double omegap,
double Ti,
double I,
double m,
double g,
double d,
double h)
{
double _z0 = 1.0/h;
matrix[0] = _z0;
matrix[1] = -1;
matrix[2] = -_z0;
matrix[3] = 0;
matrix[4] = 0;
matrix[5] = d*g*m*cos(thetai);
matrix[6] = I*_z0;
matrix[7] = 0;
matrix[8] = -I*_z0;
matrix[9] = -1;
}ufuncify_matrix_1.pyx:
import numpy as np
from cython.parallel import prange
cimport numpy as np
cimport cython
cdef extern from "ufuncify_matrix_1_h.h":
void eval_matrix(double matrix[],
double thetai,
double omegai,
double thetap,
double omegap,
double Ti,
double I,
double m,
double g,
double d,
double h)
@cython.boundscheck(False)
@cython.wraparound(False)
def eval_matrix_loop(matrix,
thetai,
omegai,
thetap,
omegap,
Ti,
double I,
double m,
double g,
double d,
double h):
cdef int n = matrix.shape[0]
cdef double[:, ::1] matrix_memview = matrix
cdef double[::1] thetai_memview = thetai
cdef double[::1] omegai_memview = omegai
cdef double[::1] thetap_memview = thetap
cdef double[::1] omegap_memview = omegap
cdef double[::1] Ti_memview = Ti
cdef int i
for i in range(n):
eval_matrix(
&matrix_memview[i, 0],
thetai_memview[i],
omegai_memview[i],
thetap_memview[i],
omegap_memview[i],
Ti_memview[i],
I,
m,
g,
d,
h)
return matrix.reshape(n, 2, 5)ufuncify_matrix_1_setup.py:
import numpy
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
extension = Extension(name="ufuncify_matrix_1",
sources=["ufuncify_matrix_1.pyx",
"ufuncify_matrix_1_c.c"],
extra_compile_args=[],
extra_link_args=[],
include_dirs=[numpy.get_include()])
setup(name="eval_matrix",
ext_modules=cythonize([extension]))
### Error message:
```shell
$ python ufuncify_matrix_1_setup.py build_ext --inplace
Compiling ufuncify_matrix_1.pyx because it changed.
[1/1] Cythonizing ufuncify_matrix_1.pyx
/home/moorepants/miniconda/envs/numpy-I/lib/python3.12/site-packages/Cython/Compiler/Main.py:381: FutureWarning: Cython directive 'language_level' not set, using '3str' for now (Py3). This has changed from earlier releases! File: /home/moorepants/src/cython-wrapper-example/ufuncify_matrix_1.pyx
tree = Parsing.p_module(s, pxd, full_module_name)
In file included from /home/moorepants/miniconda/envs/numpy-I/lib/python3.12/site-packages/numpy/_core/include/numpy/ndarraytypes.h:1909,
from /home/moorepants/miniconda/envs/numpy-I/lib/python3.12/site-packages/numpy/_core/include/numpy/ndarrayobject.h:12,
from /home/moorepants/miniconda/envs/numpy-I/lib/python3.12/site-packages/numpy/_core/include/numpy/arrayobject.h:5,
from ufuncify_matrix_1.c:1251:
/home/moorepants/miniconda/envs/numpy-I/lib/python3.12/site-packages/numpy/_core/include/numpy/npy_1_7_deprecated_api.h:17:2: warning: #warning "Using deprecated NumPy API, disable it with " "#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-Wcpp]
17 | #warning "Using deprecated NumPy API, disable it with " \
| ^~~~~~~
In file included from /home/moorepants/miniconda/envs/numpy-I/lib/python3.12/site-packages/numpy/_core/include/numpy/npy_common.h:376,
from /home/moorepants/miniconda/envs/numpy-I/lib/python3.12/site-packages/numpy/_core/include/numpy/ndarraytypes.h:4:
ufuncify_matrix_1_h.h:7:25: error: expected ‘)’ before ‘__extension__’
7 | double I,
| ^
In file included from ufuncify_matrix_1.c:1256:
ufuncify_matrix_1_h.h:8:18: error: expected ‘;’, ‘,’ or ‘)’ before ‘double’
8 | double m,
| ^~~~~~
ufuncify_matrix_1.c: In function ‘__pyx_pf_17ufuncify_matrix_1_eval_matrix_loop’:
ufuncify_matrix_1.c:20204:5: warning: implicit declaration of function ‘eval_matrix’ [-Wimplicit-function-declaration]
20204 | eval_matrix((&(*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_matrix_memview.data + __pyx_t_8 * __pyx_v_matrix_memview.strides[0]) )) + __pyx_t_9)) )))), (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_thetai_memview.data) + __pyx_t_11)) ))), (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_omegai_memview.data) + __pyx_t_12)) ))), (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_thetap_memview.data) + __pyx_t_13)) ))), (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_omegap_memview.data) + __pyx_t_14)) ))), (*((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_Ti_memview.data) + __pyx_t_15)) ))), __pyx_v_I, __pyx_v_m, __pyx_v_g, __pyx_v_d, __pyx_v_h);
| ^~~~~~~~~~~
error: command '/usr/bin/gcc' failed with exit code 1
### Python and NumPy Versions:
$ python
Python 3.12.4 | packaged by conda-forge | (main, Jun 17 2024, 10:23:07) [GCC 12.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
import sys, numpy; print(numpy.version); print(sys.version)
2.0.0
3.12.4 | packaged by conda-forge | (main, Jun 17 2024, 10:23:07) [GCC 12.3.0]
### Runtime Environment:
import numpy; numpy.show_runtime()
[{'numpy_version': '2.0.0',
'python': '3.12.4 | packaged by conda-forge | (main, Jun 17 2024, 10:23:07) '
'[GCC 12.3.0]',
'uname': uname_result(system='Linux', node='nandi', release='6.8.0-35-generic', version='#35-Ubuntu SMP PREEMPT_DYNAMIC Mon May 20 15:51:52 UTC 2024', machine='x86_64')},
{'simd_extensions': {'baseline': ['SSE', 'SSE2', 'SSE3'],
'found': ['SSSE3',
'SSE41',
'POPCNT',
'SSE42',
'AVX',
'F16C',
'FMA3',
'AVX2'],
'not_found': ['AVX512F',
'AVX512CD',
'AVX512_KNL',
'AVX512_KNM',
'AVX512_SKX',
'AVX512_CLX',
'AVX512_CNL',
'AVX512_ICL',
'AVX512_SPR']}},
{'architecture': 'Haswell',
'filepath': '/home/moorepants/miniconda/envs/numpy-I/lib/libopenblasp-r0.3.27.so',
'internal_api': 'openblas',
'num_threads': 8,
'prefix': 'libopenblas',
'threading_layer': 'pthreads',
'user_api': 'blas',
'version': '0.3.27'}]
### Context for the issue:
This breaks any use of `ufuncify()`, `autowrap()`, and custom C code generation in SymPy if the user happens to use a conflicting variable name. We can write some kind of intermediate solution to search for possible name clashes in the code generation processes and swap the name, if that is the issue.
Activity
moorepants commentedon Jun 23, 2024
Simpler example from SymPy:
rgommers commentedon Jun 23, 2024
This rings a bell, we had a very similar problem in SciPy: scipy/scipy#19726.
I think the changes in NumPy 2.0 related to complex numbers are probably triggering the issue somehow, but the problem is perhaps located in Cython, or interacting with the content in the platform's
complex.h. DefiningCYTHON_CCOMPLEXhas had various hiccups too.Is the problem you are seeing present on all platforms @moorepants, or specific to for example Windows?
moorepants commentedon Jun 23, 2024
Yes, this was failing on Windows, OSX, and Linux, see: https://github.com/csu-hmc/opty/actions/runs/9623455533
rgommers commentedon Jun 23, 2024
The relevant change from the 2.0.0 release notes is probably:
oscarbenjamin commentedon Jun 23, 2024
Looks like
Iis a macro incomplex.h. I guess that is so that you can do something like3.0 + 4.0*Iin C.The notes here suggest that you might want to use
#undef I:https://pubs.opengroup.org/onlinepubs/009695399/basedefs/complex.h.html