Skip to content

BUG: Cython Extension Fails to Compile if C variable I is used. #26787

Closed

Description

@moorepants

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

  1. moorepants commented on Jun 23, 2024

    @moorepants
    Author

    Simpler example from SymPy:

    import sympy as sm
    from sympy.utilities.autowrap import ufuncify
    import numpy as np
    
    I, J, K = sm.symbols('I, J, K')
    
    f = ufuncify([I, J, K], I + J + K)
    
    print(f(np.ones(10), np.ones(10), np.ones(10)))
  2. rgommers commented on Jun 23, 2024

    @rgommers
    Member

    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. Defining CYTHON_CCOMPLEX has had various hiccups too.

    Is the problem you are seeing present on all platforms @moorepants, or specific to for example Windows?

  3. moorepants commented on Jun 23, 2024

    @moorepants
    Author

    Yes, this was failing on Windows, OSX, and Linux, see: https://github.com/csu-hmc/opty/actions/runs/9623455533

  4. rgommers commented on Jun 23, 2024

    @rgommers
    Member

    The relevant change from the 2.0.0 release notes is probably:

    ``numpy/npy_common.h`` now includes ``complex.h``, which means that ``complex``
      is now a reserved keyword.
    
  5. oscarbenjamin commented on Jun 23, 2024

    @oscarbenjamin

    Looks like I is a macro in complex.h. I guess that is so that you can do something like 3.0 + 4.0*I in C.

    The notes here suggest that you might want to use #undef I:
    https://pubs.opengroup.org/onlinepubs/009695399/basedefs/complex.h.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions