我有一个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')
答案 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
您需要注意,这是针对您未定义的功能wrap
。 wrap
似乎只是因为您正在调用minimize
而生成,并且它意识到您需要一个Python对象,因此有助于为您创建一个def
函数(如果您注释掉了)对minimize
的调用错误消失了。这似乎是围绕Cython 0.22进行的增强。
不幸的是,换行代码使用ndarray
而不是np.ndarray
,因为您已经定义了它(这必须是一个错误!)。 workround是添加以下行
from numpy cimport ndarray
(这使得ndarray
本身就是一个有效的类型)。
但是,鉴于minimize
必须通过兼容Python的包装器调用它,你也可以使用cpdef
(也可以通过Python兼容的包装器调用,但是在没有bug的不同方式)。使用cpdef
几乎没有任何缺点 - 在可能的情况下,该函数仍然可以作为纯C函数快速调用,并且也可以在Python中正常工作(尽管速度稍慢)。