制作一个布尔数组

Dal*_*lek 2 python arrays numpy cython

我想booleancython中使用另一个numpy.array的给定大小制作一个numpy数组,但它会引发一条错误消息:

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)
Run Code Online (Sandbox Code Playgroud)

错误:

        mask= np.ones_like(x,dtype=bool)
                                      ^
------------------------------------------------------------

CosmoTest.pyx:318:39: 'bool' is not a constant, variable or function identifier
Run Code Online (Sandbox Code Playgroud)

如何在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
Run Code Online (Sandbox Code Playgroud)

错误信息:

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
Run Code Online (Sandbox Code Playgroud)

Dav*_*idW 8

如果您将代码更改为(最后一行)

mask= np.ones_like(x,dtype=np.bool)
Run Code Online (Sandbox Code Playgroud)

它会起作用(bool取自numpy而不是尝试使用lipcpp定义).但是,实际上静态键入boolean numpy数组当前并不是很有效(请参阅将numpy指针(dtype = np.bool)传递给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
Run Code Online (Sandbox Code Playgroud)

内部numpy使用8位整数来存储bool,因此您可以使用view重新解释数组而无需复制.

如果你有一个布尔数组,并想打电话给f

mask = np.array([True,False,True])
f(mask.view(dtype=np.int8))
Run Code Online (Sandbox Code Playgroud)

您总是可以编写一个小的包装函数作为公共接口来f自动进行重新解释.

它比它需要的更加繁琐,但它可以使用.

添加以回应评论

我链接的文章建议使用cast=True:

cdef np.ndarray[np.uint8_t,cast=True] mask = (x > 0.01)
Run Code Online (Sandbox Code Playgroud)

这也很好.用我的方法写的

cdef np.ndarray[np.uint8_t] mask = (x > 0.01).view(dtype=np.uint8)
Run Code Online (Sandbox Code Playgroud)

(即没有演员,但有a 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
Run Code Online (Sandbox Code Playgroud)

(我也cast=True从定义中删除了.这并不重要.你可以使用它,也可以使用view(dtype=np.uint8).如果你愿意,你可以使用两者,但它更适合打字!)