制作一个布尔数组
Making a boolean array
我想在 cython 中创建一个 boolean
numpy 数组,给定大小为另一个 numpy.array但它会引发一条错误消息:
CosmoTest.pyx
import numpy as np
cimport numpy as np
cimport cython
from libcpp cimport bool
x=np.array([[-0.3,1.2],[2.5,0.82],[0.61,-0.7]])
mask= np.ones_like(x,dtype=bool)
错误:
mask= np.ones_like(x,dtype=bool)
^
------------------------------------------------------------
CosmoTest.pyx:318:39: 'bool' is not a constant, variable or function identifier
在cython中应该如何定义?
更新:
cpdef np.ndarray arc( np.ndarray x):
cdef np.ndarray[double, ndim=1, mode='c'] out = np.zeros_like(x)
cdef np.ndarray[np.uint8_t,cast=True, ndim=1] mask = (x < 0.999).view(dtype=np.uint8)
if mask.any():
out[mask] = 0.5*np.log((1.+((1.-x[mask])/(x[mask]+1.))**0.5)/(1.-((1.-x[mask])/(x[mask]+1.))**0.5))/(1-x[mask]**2)**0.5
cdef np.ndarray[np.uint8_t,cast=True, ndim=1] mask = (x > 1.001).view(dtype=np.uint8)
if mask.any():
out[mask] = np.arctan(((x[mask]-1.)/(x[mask]+1.))**0.5)/(x[mask]**2 - 1)**0.5
cdef np.ndarray[np.uint8_t,cast=True , ndim=1] mask = ((x >= 0.999) & (x <= 1.001)).view(dtype=np.uint8)
if mask.any():
out[mask] = 5./6. - x[mask]/3.
return out
错误信息:
Error compiling Cython file:
------------------------------------------------------------
...
if mask.any():
out[mask] = 0.5*np.log((1.+((1.-x[mask])/(x[mask]+1.))**0.5)/(1.-((1.-x[mask])/(x[mask]+1.))**0.5))/(1-x[mask]**2)**0.5
cdef np.ndarray[np.uint8_t,cast=True, ndim=1] mask = (x > 1.001).view(dtype=np.uint8)
if mask.any():
out[mask] = np.arctan(((x[mask]-1.)/(x[mask]+1.))**0.5)/(x[mask]**2 - 1)**0.5
^
------------------------------------------------------------
CosmoTest.pyx:9:55: local variable 'mask' referenced before assignment
如果您将代码(的最后一行)更改为
mask= np.ones_like(x,dtype=np.bool)
它将起作用(从 numpy 获取 bool
而不是尝试使用 lipcpp 定义)。然而,实际上静态输入布尔 numpy 数组目前并不完全有效(参见 Passing a numpy pointer (dtype=np.bool) to C++)。
目前最好的方法是将它们静态键入
def f(np.ndarray[dtype=np.int8_t,ndim=1] x):
cdef np.ndarray[dtype=np.int8_t,ndim=1] y
y = np.ones_like(x,dtype=np.int8)
return y.view(dtype=np.bool) # returns as boolean array
在 numpy 内部使用一个 8 位整数来存储一个 bool,因此你可以只使用 view
来重新解释数组而无需复制。
如果你有一个布尔数组并想调用 f
你会做
mask = np.array([True,False,True])
f(mask.view(dtype=np.int8))
您总是可以编写一个小的包装函数作为 public 与 f
的接口,以自动进行重新解释。
它比需要的更繁琐,但可以使用。
回复评论补充
我链接到的文章建议使用 cast=True
:
cdef np.ndarray[np.uint8_t,cast=True] mask = (x > 0.01)
这也很好用。用我的方法写成
cdef np.ndarray[np.uint8_t] mask = (x > 0.01).view(dtype=np.uint8)
(即没有演员表,但有 view
)。据我所知,没有实际区别,所以请选择您认为更好看的那个。
并编辑以回应其他问题
工作代码如下(我已经检查并编译 - 我没有检查以确保它运行)。您收到编译器错误是因为您多次定义了 mask
的类型。每个函数的每个变量只允许使用一次 cdef
,但定义了类型后,您可以随意分配给它。
cpdef np.ndarray arc( np.ndarray x):
cdef np.ndarray[double, ndim=1, mode='c'] out = np.zeros_like(x)
cdef np.ndarray[np.uint8_t, ndim=1] mask = (x < 0.999).view(dtype=np.uint8)
if mask.any():
out[mask] = 0.5*np.log((1.+((1.-x[mask])/(x[mask]+1.))**0.5)/(1.-((1.-x[mask])/(x[mask]+1.))**0.5))/(1-x[mask]**2)**0.5
mask = (x > 1.001).view(dtype=np.uint8) # REMOVED cdef!
if mask.any():
out[mask] = np.arctan(((x[mask]-1.)/(x[mask]+1.))**0.5)/(x[mask]**2 - 1)**0.5
mask = ((x >= 0.999) & (x <= 1.001)).view(dtype=np.uint8) # REMOVED cdef!
if mask.any():
out[mask] = 5./6. - x[mask]/3.
return out
(我还从定义中删除了 cast=True
。这并不重要。您可以使用它,也可以使用 view(dtype=np.uint8)
。如果您愿意,可以同时使用两者,但它更多打字!)
我想在 cython 中创建一个 boolean
numpy 数组,给定大小为另一个 numpy.array但它会引发一条错误消息:
CosmoTest.pyx
import numpy as np
cimport numpy as np
cimport cython
from libcpp cimport bool
x=np.array([[-0.3,1.2],[2.5,0.82],[0.61,-0.7]])
mask= np.ones_like(x,dtype=bool)
错误:
mask= np.ones_like(x,dtype=bool)
^
------------------------------------------------------------
CosmoTest.pyx:318:39: 'bool' is not a constant, variable or function identifier
在cython中应该如何定义?
更新:
cpdef np.ndarray arc( np.ndarray x):
cdef np.ndarray[double, ndim=1, mode='c'] out = np.zeros_like(x)
cdef np.ndarray[np.uint8_t,cast=True, ndim=1] mask = (x < 0.999).view(dtype=np.uint8)
if mask.any():
out[mask] = 0.5*np.log((1.+((1.-x[mask])/(x[mask]+1.))**0.5)/(1.-((1.-x[mask])/(x[mask]+1.))**0.5))/(1-x[mask]**2)**0.5
cdef np.ndarray[np.uint8_t,cast=True, ndim=1] mask = (x > 1.001).view(dtype=np.uint8)
if mask.any():
out[mask] = np.arctan(((x[mask]-1.)/(x[mask]+1.))**0.5)/(x[mask]**2 - 1)**0.5
cdef np.ndarray[np.uint8_t,cast=True , ndim=1] mask = ((x >= 0.999) & (x <= 1.001)).view(dtype=np.uint8)
if mask.any():
out[mask] = 5./6. - x[mask]/3.
return out
错误信息:
Error compiling Cython file:
------------------------------------------------------------
...
if mask.any():
out[mask] = 0.5*np.log((1.+((1.-x[mask])/(x[mask]+1.))**0.5)/(1.-((1.-x[mask])/(x[mask]+1.))**0.5))/(1-x[mask]**2)**0.5
cdef np.ndarray[np.uint8_t,cast=True, ndim=1] mask = (x > 1.001).view(dtype=np.uint8)
if mask.any():
out[mask] = np.arctan(((x[mask]-1.)/(x[mask]+1.))**0.5)/(x[mask]**2 - 1)**0.5
^
------------------------------------------------------------
CosmoTest.pyx:9:55: local variable 'mask' referenced before assignment
如果您将代码(的最后一行)更改为
mask= np.ones_like(x,dtype=np.bool)
它将起作用(从 numpy 获取 bool
而不是尝试使用 lipcpp 定义)。然而,实际上静态输入布尔 numpy 数组目前并不完全有效(参见 Passing a numpy pointer (dtype=np.bool) to C++)。
目前最好的方法是将它们静态键入
def f(np.ndarray[dtype=np.int8_t,ndim=1] x):
cdef np.ndarray[dtype=np.int8_t,ndim=1] y
y = np.ones_like(x,dtype=np.int8)
return y.view(dtype=np.bool) # returns as boolean array
在 numpy 内部使用一个 8 位整数来存储一个 bool,因此你可以只使用 view
来重新解释数组而无需复制。
如果你有一个布尔数组并想调用 f
你会做
mask = np.array([True,False,True])
f(mask.view(dtype=np.int8))
您总是可以编写一个小的包装函数作为 public 与 f
的接口,以自动进行重新解释。
它比需要的更繁琐,但可以使用。
回复评论补充
我链接到的文章建议使用 cast=True
:
cdef np.ndarray[np.uint8_t,cast=True] mask = (x > 0.01)
这也很好用。用我的方法写成
cdef np.ndarray[np.uint8_t] mask = (x > 0.01).view(dtype=np.uint8)
(即没有演员表,但有 view
)。据我所知,没有实际区别,所以请选择您认为更好看的那个。
并编辑以回应其他问题
工作代码如下(我已经检查并编译 - 我没有检查以确保它运行)。您收到编译器错误是因为您多次定义了 mask
的类型。每个函数的每个变量只允许使用一次 cdef
,但定义了类型后,您可以随意分配给它。
cpdef np.ndarray arc( np.ndarray x):
cdef np.ndarray[double, ndim=1, mode='c'] out = np.zeros_like(x)
cdef np.ndarray[np.uint8_t, ndim=1] mask = (x < 0.999).view(dtype=np.uint8)
if mask.any():
out[mask] = 0.5*np.log((1.+((1.-x[mask])/(x[mask]+1.))**0.5)/(1.-((1.-x[mask])/(x[mask]+1.))**0.5))/(1-x[mask]**2)**0.5
mask = (x > 1.001).view(dtype=np.uint8) # REMOVED cdef!
if mask.any():
out[mask] = np.arctan(((x[mask]-1.)/(x[mask]+1.))**0.5)/(x[mask]**2 - 1)**0.5
mask = ((x >= 0.999) & (x <= 1.001)).view(dtype=np.uint8) # REMOVED cdef!
if mask.any():
out[mask] = 5./6. - x[mask]/3.
return out
(我还从定义中删除了 cast=True
。这并不重要。您可以使用它,也可以使用 view(dtype=np.uint8)
。如果您愿意,可以同时使用两者,但它更多打字!)