簡體   English   中英

Cython:融合類型的使用無效,類型不能專門化

[英]Cython: Invalid use of fused types, type cannot be specialized

我有以下MCVE:

import numpy as np

cimport numpy as np
cimport cython

from cython cimport floating


def func1(floating[:] X_data, floating alpha):
    if floating is double:
        dtype = np.float64
    else:
        dtype = np.float32

    cdef floating[:] prios = np.empty(12, dtype=dtype)
    cdef int ws_size = 10

    C = np.argpartition(np.asarray(prios), ws_size)[:ws_size].astype(np.int32)

    cdef int res = func2(X_data, alpha, C)


cpdef int func2(floating[:] X_data, floating alpha, int[:] C):
    cdef int epoch = 1
    return epoch

試圖運行cython test_fused.pyx給了我:

Error compiling Cython file:
------------------------------------------------------------
...
    cdef floating[:] prios = np.empty(12, dtype=dtype)
    cdef int ws_size = 10

    C = np.argpartition(np.asarray(prios), ws_size)[:ws_size].astype(np.int32)

    cdef int res = func2(X_data, alpha, C)
                       ^
------------------------------------------------------------

test_fused.pyx:21:24: no suitable method found

    Error compiling Cython file:
    ------------------------------------------------------------
    ...
        cdef floating[:] prios = np.empty(12, dtype=dtype)
        cdef int ws_size = 10

        C = np.argpartition(np.asarray(prios), ws_size)[:ws_size].astype(np.int32)

        cdef int res = func2(X_data, alpha, C)
                           ^
    ------------------------------------------------------------

    test_fused.pyx:21:24: no suitable method found

    Error compiling Cython file:
    ------------------------------------------------------------
    ...
        cdef floating[:] prios = np.empty(12, dtype=dtype)
        cdef int ws_size = 10

        C = np.argpartition(np.asarray(prios), ws_size)[:ws_size].astype(np.int32)

        cdef int res = func2(X_data, alpha, C)
                      ^
    ------------------------------------------------------------

    test_fused.pyx:21:19: Invalid use of fused types, type cannot be specialized

    Error compiling Cython file:
    ------------------------------------------------------------
    ...
        cdef floating[:] prios = np.empty(12, dtype=dtype)
        cdef int ws_size = 10

        C = np.argpartition(np.asarray(prios), ws_size)[:ws_size].astype(np.int32)

        cdef int res = func2(X_data, alpha, C)
                      ^
    ------------------------------------------------------------

    test_fused.pyx:21:19: Invalid use of fused types, type cannot be specialized

我有一個更復雜的代碼,它也將數組C作為運行時定義的值傳遞,這不會導致任何問題。 這個編譯錯誤的原因是什么?

我很困惑,因為稍微修改(向func1添加一個偽關鍵字arg和向func2添加兩個關鍵字args)使代碼編譯:

def func1(floating[:] X_data, floating alpha,
          int dummy_variable=1):  # added dummy_variable here

    # same as before here

    cdef int res = func2(X_data, alpha, C,
                       dummy_variable=dummy_variable)


cpdef int func2(floating[:] X_data, floating alpha, int[:] C, 
    int K=6, int dummy_variable=1):  # added K and dummy variable here

    cdef int epoch = 1
    return epoch

讓我們從一個較小的重現者開始:

%%cython
import numpy as np
from cython cimport floating

def func1(floating[:] X_data):
    C = np.empty(12, dtype=np.int_32)
    func2(X_data, C)

cpdef func2(floating[:] X_data, int[:] C):
    pass

它不編譯。

一個重要的觀察結果: func2是一個cpdef ,這意味着Cython會將其稱為func1的原始C函數。 這兩個C簽名將由Cython生成,用於融合的func2函數(一個用於double ,一個用於float ):

static PyObject *__pyx_fuse_0__pyx_f_4test_func2(__Pyx_memviewslice, __Pyx_memviewslice, int __pyx_skip_dispatch); /*proto*/
static PyObject *__pyx_fuse_1__pyx_f_4test_func2(__Pyx_memviewslice, __Pyx_memviewslice, int __pyx_skip_dispatch); /*proto*/

所以C應該是一個__Pyx_memviewslice ,但只要Cython關注它就是func1PyObject ,所以這個函數無法被稱為cdef 我不明白:為什么Cython不回歸python- def版本?

C簽名有點誤導,Cython在編譯期間進行了更多類型檢查,因此將C定義為

cdef float[:] C

因為即使C在這種情況下也是__Pyx_memviewslice它沒有正確的類型,只有

cdef int[:] C

會工作。

如果func2被定義為

cpdef func2(floating[:] X_data, C):

相應的兩個C簽名將是

static PyObject *__pyx_fuse_0__pyx_f_4test_func2(__Pyx_memviewslice, PyObject *, int __pyx_skip_dispatch); /*proto*/
static PyObject *__pyx_fuse_1__pyx_f_4test_func2(__Pyx_memviewslice, PyObject *, int __pyx_skip_dispatch); /*proto*/

所以可以將C這是一個PyObject傳遞給這些函數。

因此有兩種方法可以解決編譯問題:

  • func1使用cdef int[:] C ,或
  • drop int[:] Cfunc2的簽名中

那么為什么要添加一個虛擬參數,即

%%cython -a
import numpy as np
from cython cimport floating

def func1(floating[:] X_data, int dummy_variable=1):
    C = np.empty(12, dtype=np.int_32)
    func2(X_data, C, dummy_variable=dummy_variable)

cpdef func2(floating[:] X_data, int[:] C, int k=6, dummy_variable = 1):
    pass

作品?

其實,有使代碼編譯第三種方式:通過使func2蟒蛇只def -功能。 在這種情況下, C的類型在編譯期間不起作用,並且將在運行時檢查。

問題是:使用虛擬變量的情況,Cython決定將func2調用為Python函數而不是C函數,因此類型不匹配不起作用。

您可以通過檢查帶注釋的html文件輕松查看。

但是,我不能說,Cython回歸到Python函數調用的原因是什么。 我只能說:不為k提供價值起着重要作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM