cython和numpy:'cfunc.to_py:65:25:'ndarray'不是类型标识符'

时间:2015-09-03 00:11:56

标签: numpy cython

我有一个cdef函数,它将两个numpy.ndarrays作为参数(1)。它给了我一个'cfunc.to_py:65:25:'ndarray'不是类型标识符'错误。 当我用def(python)函数(2)或cpdef(3)替换cdef时,错误消失。这是一个错误吗?我怎么解决这个问题?代码如下。

(1)cdef float F(np.ndarray xx, np.ndarray y_non_labor, float wage, float gamma, float one_by_gamma, float l, float one_minus_l, int lenx):

(2)def F(np.ndarray xx, np.ndarray y_non_labor, float wage, float gamma, float one_by_gamma, float l, float one_minus_l, int lenx):

(3)cpdef float F(np.ndarray xx, np.ndarray y_non_labor, float wage, float gamma, float one_by_gamma, float l, float one_minus_l, int lenx):

# cython: profile=True
# cython: boundscheck=False
# cython: wraparound=False
cimport cython
from libc.stdlib cimport malloc
from scipy.optimize import minimize
cimport numpy as np
import numpy as np


# due to instabilities associated with "constraint optimization" with bounds
# we will transform the problem so that that it becomes an unconstraint optimization problem without bounds

def transform(x):
    x1 = x * x / (1 + x * x)
    s =  1 - sum(x1)
    return x1, s

# on the next cython update try cdef float F(..)
@cython.cdivision(True)
cdef float F(np.ndarray xx, np.ndarray y_non_labor, float wage, float gamma, float one_by_gamma, float l, float one_minus_l, int lenx):
    cdef float s
    cdef float *z_non_labor = <float *>malloc(lenx * sizeof(float))
    cdef float z_labor
    cdef float labor
    cdef float value
    cdef float summation
    cdef float non_labor
    cdef float x
    cdef float ynl

    for i from 0 <= i < lenx:
        x = xx[i]
        z_non_labor[i] = x * x / (1 + x * x)

    s = 0
    for i from 0 <= i < lenx:
        s += z_non_labor[i]

    z_labor = 1 - s

    summation = 0
    for i from 0 <= i < lenx:
        ynl = y_non_labor[i]
        summation += (z_non_labor[i] / ynl) ** gamma

    non_labor = summation ** one_by_gamma
    labor = z_labor / wage
    # labor and non-labor inputs together
    value = (labor ** l) * (non_labor ** one_minus_l)
    return - value

def optimization(np.ndarray seed_weights,
                 np.ndarray input_prices,
                 float wage,
                 float gamma,
                 float one_by_gamma,
                 float l,
                 float one_minus_l):

    cdef int lenx

    lenx = len(seed_weights)

    args=(input_prices,
          wage,
          gamma,
          one_by_gamma,
          l,
          one_minus_l,
          lenx)

    return minimize(F, seed_weights, args=args, method='Nelder-Mead')

1 个答案:

答案 0 :(得分:12)

我认为这是一个相当模糊的错误。说明如下。工作回合即将结束。

在Cython 0.21上我得到了一个不同的错误

filename.pyx:73:21: Cannot convert 'float (ndarray, ndarray, float,
float, float, float, float, int)' to Python object.

这对我有意义,因为minimise将可调用的Python对象作为其第一个答案,而cdef仅生成C函数。 [cpdef生成两者并在其可以调用C函数的地方实现]

在Cython 0.22和0.23上,我得到你描述的错误。完整错误是

@cname("__Pyx_CFunc_float____ndarray____ndarray____float____float____float____float____float____int___to_py")
cdef object __Pyx_CFunc_float____ndarray____ndarray____float____float____float____float____float____int___to_py(float (*f)(ndarray, ndarray, float, float, float, float, float, int) except *):
    def wrap(ndarray xx, ndarray y_non_labor, float wage, float gamma, float one_by_gamma, float l, float one_minus_l, int lenx):
                        ^
------------------------------------------------------------

cfunc.to_py:30:25: 'ndarray' is not a type identifier

您需要注意,这是针对您未定义的功能wrapwrap似乎只是因为您正在调用minimize而生成,并且它意识到您需要一个Python对象,因此有助于为您创建一个def函数(如果您注释掉了)对minimize的调用错误消失了。这似乎是围绕Cython 0.22进行的增强。

不幸的是,换行代码使用ndarray而不是np.ndarray,因为您已经定义了它(这必须是一个错误!)。 workround是添加以下行

from numpy cimport ndarray

(这使得ndarray本身就是一个有效的类型)。

但是,鉴于minimize必须通过兼容Python的包装器调用它,你也可以使用cpdef(也可以通过Python兼容的包装器调用,但是在没有bug的不同方式)。使用cpdef几乎没有任何缺点 - 在可能的情况下,该函数仍然可以作为纯C函数快速调用,并且也可以在Python中正常工作(尽管速度稍慢)。