我正在尝试加速我使用cython的算法。我已经按照this page上的大多数禁令来采用我的原始功能并将其转换为优化形式,但我似乎所做的只是放慢速度。我已经非常彻底地检查了这些类型,甚至查看了生成的C代码,我也进行了一些行分析,这表明花了很多时间来比较LONG类型,但除此之外我还没有运气好的话。我注意到内联似乎是最昂贵的循环。
我刚刚遇到一些非常紧张的情况?我发现很难相信cython无法优化这段代码,因此我认为某些地方的输入错误。
我的测试目录如下所示
cython_test
- test_package
- cython_fail
- __init__.py
- test_extension.pyx
- setup.py
- profiling.py
单个文件如下所示:
#__init__.py
__all__ = []
__version__ = 0.1
from . import test_extension
# test_extension.pyx
import numpy as np
def fun(lattice, default_val = -1, leave_bar = True):
if len(lattice.shape) != 2 or not np.all(
np.logical_or(lattice == 0, lattice == 1)):
raise RuntimeError(
"Function only defined for 2D binary grid!")
clusters = default_val*np.ones_like(lattice, dtype = DTYPE)
ids = np.reshape(
np.arange(
1, lattice.shape[0]*lattice.shape[1] + 1
),
lattice.shape)
for i in range(lattice.shape[0]):
for j in range(lattice.shape[1]):
if lattice[i, j]:
left_occ = lattice[i-1, j] if i != 0 else 0
up_occ = lattice[i, j-1] if j != 0 else 0
if not left_occ and not up_occ:
clusters[i, j] = ids[i, j]
elif left_occ and not up_occ:
clusters[i, j] = clusters[i-1, j]
elif not left_occ and up_occ:
clusters[i, j] = clusters[i, j-1]
else:
# Numbering scheme is row-major
lower_cluster, upper_cluster = \
(clusters[i-1, j], clusters[i, j-1]) \
if (clusters[i-1, j] < clusters[i, j-1]) \
else (clusters[i, j-1], clusters[i-1, j])
clusters[i, j] = lower_cluster
clusters[clusters == upper_cluster
] = lower_cluster
return clusters
cimport cython
cimport numpy as np
DTYPE=np.int
ctypedef np.int_t DTYPE_t
@cython.boundscheck(False)
@cython.wraparound(False)
def optimized_fun(np.ndarray[DTYPE_t, ndim=2] lattice, int default_val = -1):
cdef int shape0 = lattice.shape[0]
cdef int shape1 = lattice.shape[1]
cdef np.ndarray[DTYPE_t, ndim=2] ids = np.reshape(
np.arange(
1, shape0*shape1 + 1
),
(shape0, shape1))
cdef int i, j, jshift, ishift, x, y
cdef DTYPE_t left_occ, up_occ, lower_cluster, upper_cluster
cdef np.ndarray[DTYPE_t, ndim=2] clusters = default_val*np.ones_like(lattice, dtype = DTYPE)
for i in range(shape0):
for j in range(shape1):
if lattice[i, j]:
ishift = i-1
jshift = j-1
if i == 0:
left_occ = 0
else:
left_occ = lattice[ishift, j]
if j == 0:
up_occ = 0
else:
up_occ = lattice[i, jshift]
if not left_occ and not up_occ:
clusters[i, j] = ids[i, j]
elif left_occ and not up_occ:
clusters[i, j] = clusters[ishift, j]
elif not left_occ and up_occ:
clusters[i, j] = clusters[i, jshift]
else:
if (clusters[ishift, j] < clusters[i, jshift]):
lower_cluster = clusters[ishift, j]
upper_cluster = clusters[i, jshift]
else:
lower_cluster = clusters[i, jshift]
upper_cluster = clusters[ishift, j]
clusters[i, j] = lower_cluster
#clusters[clusters == upper_cluster
#] = lower_cluster
# Note that the above line using numpy logic performs substantially faster than the below loop. However, the types of upper_cluster, lower_cluster, and the clusters array all seem to match appropriately.
for x in range(shape0):
for y in range(shape1):
if clusters[x, y] == upper_cluster:
clusters[x, y] = lower_cluster
return clusters
# setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
from Cython.Compiler import Options
import numpy as np
directive_defaults = Options.get_directive_defaults()
directive_defaults['linetrace'] = True
directive_defaults['binding'] = True
extensions = [
Extension("cython_fail.test_extension", ["cython_fail/test_extension.pyx"], define_macros=[('CYTHON_TRACE', '1')])
]
includes = [
np.get_include()
]
setup(name = 'cython_fail',
packages = ['cython_fail'],
include_dirs = includes,
ext_modules = cythonize(extensions)
)
# filename: profiling.py
import cython_fail
import numpy as np
N = 100
p = 0.58
lattice = (np.random.rand(N, N) < p).astype(np.int)
#import line_profiler
#profile = line_profiler.LineProfiler(cython_fail.test_extension.fun)
#profile.runcall(cython_fail.test_extension.fun, lattice)
#profile.print_stats()
##
#profile = line_profiler.LineProfiler(cython_fail.test_extension.optimized_fun)
#profile.runcall(cython_fail.test_extension.optimized_fun, lattice)
#profile.print_stats()
#quit()
#
#
#
import timeit
original = timeit.timeit("cython_fail.test_extension.fun(lattice)",
setup="import cython_fail; from __main__ import lattice",
number=100)
optimized = timeit.timeit("cython_fail.test_extension.optimized_fun(lattice)",
setup="import cython_fail; from __main__ import lattice",
number=100)
print("Time to run normally: {}\nTime to run optimized: {}".format(original, optimized))
如果对使用Line Profiler模块的任何人都有帮助,我也会为行分析提供代码。作为参考,上面运行的简单时间的输出是:
Time to run normally: 3.9105381628032774
Time to run optimized: 9.10740948910825
我已将profiling.py脚本移到根目录中(它不是cython_test/test_package/profiling.py
而不是cython_test/profiling.py
,我现在正在使用这个简单的bash脚本来运行测试
# run_tests.sh
#!/bin/bash
if [ -f ]; then
rm -rf build
fi
if [ -f cython_fail/test_extension.c ]; then
rm cython_fail/test_extension.c
fi
if [ -f cython_fail/test_extension.cpython-34m.so ]; then
rm test_extension.cpython-34m.so
fi
python3 setup.py build_ext --inplace
python3 profiling.py
我已经确定,如果我将架构从Linux机箱切换到Mac,问题就不会持续存在。在Linux机器上运行逐行分析的结果如下。
Total time: 9.66717 s
File: cython_fail/test_extension.pyx
Function: optimized_fun at line 47
Line # Hits Time Per Hit % Time Line Contents
==============================================================
47 def optimized_fun(np.ndarray[DTYPE_t, ndim=2] lattice, int default_val = -1):
48 1 3 3.0 0.0 cdef int shape0 = lattice.shape[0]
49 1 1 1.0 0.0 cdef int shape1 = lattice.shape[1]
50
51 2 5 2.5 0.0 cdef np.ndarray[DTYPE_t, ndim=2] ids = np.reshape(
52 1 1 1.0 0.0 np.arange(
53 1 51 51.0 0.0 1, shape0*shape1 + 1
54 ),
55 1 25 25.0 0.0 (shape0, shape1))
56
57 cdef int i, j, jshift, ishift, x, y
58 cdef DTYPE_t left_occ, up_occ, lower_cluster, upper_cluster
59 1 143 143.0 0.0 cdef np.ndarray[DTYPE_t, ndim=2] clusters = default_val*np.ones_like(lattice, dtype = DTYPE)
60 1 6 6.0 0.0 for i in range(shape0):
61 100 48 0.5 0.0 for j in range(shape1):
62 10000 5129 0.5 0.1 if lattice[i, j]:
63 5818 2718 0.5 0.0 ishift = i-1
64 5818 2728 0.5 0.0 jshift = j-1
65
66 5818 2765 0.5 0.0 if i == 0:
67 57 28 0.5 0.0 left_occ = 0
68 else:
69 5761 2789 0.5 0.0 left_occ = lattice[ishift, j]
70
71 5818 2762 0.5 0.0 if j == 0:
72 60 24 0.4 0.0 up_occ = 0
73 else:
74 5758 2689 0.5 0.0 up_occ = lattice[i, jshift]
75
76 5818 2788 0.5 0.0 if not left_occ and not up_occ:
77 1032 582 0.6 0.0 clusters[i, j] = ids[i, j]
78 4786 2287 0.5 0.0 elif left_occ and not up_occ:
79 1431 692 0.5 0.0 clusters[i, j] = clusters[ishift, j]
80 3355 1607 0.5 0.0 elif not left_occ and up_occ:
81 1397 674 0.5 0.0 clusters[i, j] = clusters[i, jshift]
82 else:
83
84 1958 933 0.5 0.0 if (clusters[ishift, j] < clusters[i, jshift]):
85 526 236 0.4 0.0 lower_cluster = clusters[ishift, j]
86 526 259 0.5 0.0 upper_cluster = clusters[i, jshift]
87 else:
88 1432 688 0.5 0.0 lower_cluster = clusters[i, jshift]
89 1432 685 0.5 0.0 upper_cluster = clusters[ishift, j]
90
91 1958 937 0.5 0.0 clusters[i, j] = lower_cluster
92 #clusters[clusters == upper_cluster
93 #] = lower_cluster
94 1958 948 0.5 0.0 for x in range(shape0):
95 195800 91754 0.5 0.9 for y in range(shape1):
96 19580000 9274425 0.5 95.9 if clusters[x, y] == upper_cluster:
97 528427 265750 0.5 2.7 clusters[x, y] = lower_cluster
98
99 1 8 8.0 0.0 return clusters
这是生成的实际C文件的差异。几个笔记:
&lt; line是较慢的版本,&gt;线对应于更快的代码。
1c1
< /* Generated by Cython 0.26.1 */
---
> /* Generated by Cython 0.25.2 */
12,19c12
< "depends": [],
< "extra_compile_args": [
< "-g"
< ],
< "name": "cython_fail.test_extension",
< "sources": [
< "cython_fail/test_extension.pyx"
< ]
---
> "depends": []
32c25
< #define CYTHON_ABI "0_26_1"
---
> #define CYTHON_ABI "0_25_2"
54d46
< #define __PYX_COMMA ,
72,73d63
< #undef CYTHON_USE_PYTYPE_LOOKUP
< #define CYTHON_USE_PYTYPE_LOOKUP 0
101,102d90
< #undef CYTHON_USE_PYTYPE_LOOKUP
< #define CYTHON_USE_PYTYPE_LOOKUP 0
134,139d121
< #if PY_VERSION_HEX < 0x02070000
< #undef CYTHON_USE_PYTYPE_LOOKUP
< #define CYTHON_USE_PYTYPE_LOOKUP 0
< #elif !defined(CYTHON_USE_PYTYPE_LOOKUP)
< #define CYTHON_USE_PYTYPE_LOOKUP 1
< #endif
217,223c199,202
< #if PY_VERSION_HEX < 0x030700A0 || !defined(METH_FASTCALL)
< #ifndef METH_FASTCALL
< #define METH_FASTCALL 0x80
< #endif
< typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject **args, Py_ssize_t nargs);
< typedef PyObject *(*__Pyx_PyCFunctionFastWithKeywords) (PyObject *self, PyObject **args,
< Py_ssize_t nargs, PyObject *kwnames);
---
> #ifndef METH_FASTCALL
> #define METH_FASTCALL 0x80
> typedef PyObject *(*__Pyx_PyCFunctionFast) (PyObject *self, PyObject **args,
> Py_ssize_t nargs, PyObject *kwnames);
226d204
< #define __Pyx_PyCFunctionFastWithKeywords _PyCFunctionFastWithKeywords
230c208
< ((PyCFunction_Check(func) && (METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS)))))
---
> ((PyCFunction_Check(func) && (METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)))))
357,362d334
< #ifndef __has_attribute
< #define __has_attribute(x) 0
< #endif
< #ifndef __has_cpp_attribute
< #define __has_cpp_attribute(x) 0
< #endif
417,445d388
< #ifdef _MSC_VER
< #ifndef _MSC_STDINT_H_
< #if _MSC_VER < 1300
< typedef unsigned char uint8_t;
< typedef unsigned int uint32_t;
< #else
< typedef unsigned __int8 uint8_t;
< typedef unsigned __int32 uint32_t;
< #endif
< #endif
< #else
< #include <stdint.h>
< #endif
< #ifndef CYTHON_FALLTHROUGH
< #ifdef __cplusplus
< #if __has_cpp_attribute(fallthrough)
< #define CYTHON_FALLTHROUGH [[fallthrough]]
< #elif __has_cpp_attribute(clang::fallthrough)
< #define CYTHON_FALLTHROUGH [[clang::fallthrough]]
< #endif
< #endif
< #ifndef CYTHON_FALLTHROUGH
< #if __has_attribute(fallthrough) || (defined(__GNUC__) && defined(__attribute__))
< #define CYTHON_FALLTHROUGH __attribute__((fallthrough))
< #else
< #define CYTHON_FALLTHROUGH
< #endif
< #endif
< #endif
553,554c496,497
< static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject*);
< static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length);
---
> static CYTHON_INLINE char* __Pyx_PyObject_AsString(PyObject*);
> static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject*, Py_ssize_t* length);
567,571c510,511
< #define __Pyx_PyObject_AsWritableString(s) ((char*) __Pyx_PyObject_AsString(s))
< #define __Pyx_PyObject_AsWritableSString(s) ((signed char*) __Pyx_PyObject_AsString(s))
< #define __Pyx_PyObject_AsWritableUString(s) ((unsigned char*) __Pyx_PyObject_AsString(s))
< #define __Pyx_PyObject_AsSString(s) ((const signed char*) __Pyx_PyObject_AsString(s))
< #define __Pyx_PyObject_AsUString(s) ((const unsigned char*) __Pyx_PyObject_AsString(s))
---
> #define __Pyx_PyObject_AsSString(s) ((signed char*) __Pyx_PyObject_AsString(s))
> #define __Pyx_PyObject_AsUString(s) ((unsigned char*) __Pyx_PyObject_AsString(s))
693d632
< static CYTHON_INLINE void __Pyx_pretend_to_initialize(void* ptr) { (void)ptr; }
698d636
< static PyObject *__pyx_cython_runtime;
1268c1206
< #define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error) if ((1)); else goto_error;
---
> #define __Pyx_TraceCall(funcname, srcfile, firstlineno, nogil, goto_error) if (1); else goto_error;
1326c1264
< #define __Pyx_TraceLine(lineno, nogil, goto_error) if ((1)); else goto_error;
---
> #define __Pyx_TraceLine(lineno, nogil, goto_error) if (1); else goto_error;
1451,1453d1388
< /* IsLittleEndian.proto */
< static CYTHON_INLINE int __Pyx_Is_Little_Endian(void);
<
1461c1396
< __Pyx_TypeInfo* type);
---
> __Pyx_TypeInfo* type); // PROTO
1580,1582d1514
< /* CLineInTraceback.proto */
< static int __Pyx_CLineForTraceback(int c_line);
<
1845d1776
< static const char __pyx_k_cline_in_traceback[] = "cline_in_traceback";
1848c1779
< static const char __pyx_k_cython_fail_test_extension_pyx[] = "cython_fail/test_extension.pyx";
---
1867d1798
< static PyObject *__pyx_n_s_cline_in_traceback;
1870d1800
< static PyObject *__pyx_kp_s_cython_fail_test_extension_pyx;
6778d6697
< {&__pyx_n_s_cline_in_traceback, __pyx_k_cline_in_traceback, sizeof(__pyx_k_cline_in_traceback), 0, 0, 1, 1},
6781d6699
< {&__pyx_kp_s_cython_fail_test_extension_pyx, __pyx_k_cython_fail_test_extension_pyx, sizeof(__pyx_k_cython_fail_test_extension_pyx), 0, 0, 1, 0},
6951c6869
< __pyx_codeobj_ = (PyObject*)__Pyx_PyCode_New(3, 0, 11, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__13, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_cython_fail_test_extension_pyx, __pyx_n_s_fun, 4, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj_)) __PYX_ERR(0, 4, __pyx_L1_error)
---
6966c6884
< __pyx_codeobj__3 = (PyObject*)__Pyx_PyCode_New(2, 0, 16, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__15, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_cython_fail_test_extension_pyx, __pyx_n_s_optimized_fun, 47, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__3)) __PYX_ERR(0, 47, __pyx_L1_error)
---
7042d6959
< __pyx_cython_runtime = PyImport_AddModule((char *) "cython_runtime"); if (unlikely(!__pyx_cython_runtime)) __PYX_ERR(0, 1, __pyx_L1_error)
7167c7084
---
7184c7101
< __Pyx_AddTraceback("init cython_fail.test_extension", 0, __pyx_lineno, __pyx_filename);
---
> __Pyx_AddTraceback("init cython_fail.test_extension", __pyx_clineno, __pyx_lineno, __pyx_filename);
7686,7687c7603,7604
< #endif
< #endif
---
> #endif // CPython < 3.6
> #endif // CYTHON_FAST_PYCALL
7695d7611
< int flags = PyCFunction_GET_FLAGS(func);
7697c7613
< assert(METH_FASTCALL == (flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST | METH_KEYWORDS)));
---
> assert(METH_FASTCALL == (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)));
7704,7708c7620
< if ((PY_VERSION_HEX < 0x030700A0) || unlikely(flags & METH_KEYWORDS)) {
< return (*((__Pyx_PyCFunctionFastWithKeywords)meth)) (self, args, nargs, NULL);
< } else {
< return (*((__Pyx_PyCFunctionFast)meth)) (self, args, nargs);
< }
---
> return (*((__Pyx_PyCFunctionFast)meth)) (self, args, nargs, NULL);
7710c7622
< #endif
---
> #endif // CYTHON_FAST_PYCCALL
7769a7682,7684
> #ifdef __Pyx_CyFunction_USED
> if (likely(PyCFunction_Check(func) || PyObject_TypeCheck(func, __pyx_CyFunctionType))) {
> #else
7770a7686
> #endif
8096c8012
< static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
---
> static CYTHON_INLINE PyObject *__Pyx_GetItemInt_Generic(PyObject *o, PyObject* j) {
8107,8112c8023,8025
< Py_ssize_t wrapped_i = i;
< if (wraparound & unlikely(i < 0)) {
< wrapped_i += PyList_GET_SIZE(o);
< }
< if ((!boundscheck) || likely((0 <= wrapped_i) & (wrapped_i < PyList_GET_SIZE(o)))) {
< PyObject *r = PyList_GET_ITEM(o, wrapped_i);
---
> if (wraparound & unlikely(i < 0)) i += PyList_GET_SIZE(o);
> if ((!boundscheck) || likely((0 <= i) & (i < PyList_GET_SIZE(o)))) {
> PyObject *r = PyList_GET_ITEM(o, i);
8125,8130c8038,8040
< Py_ssize_t wrapped_i = i;
< if (wraparound & unlikely(i < 0)) {
< wrapped_i += PyTuple_GET_SIZE(o);
< }
< if ((!boundscheck) || likely((0 <= wrapped_i) & (wrapped_i < PyTuple_GET_SIZE(o)))) {
< PyObject *r = PyTuple_GET_ITEM(o, wrapped_i);
---
> if (wraparound & unlikely(i < 0)) i += PyTuple_GET_SIZE(o);
> if ((!boundscheck) || likely((0 <= i) & (i < PyTuple_GET_SIZE(o)))) {
> PyObject *r = PyTuple_GET_ITEM(o, i);
8343,8353d8252
< /* IsLittleEndian */
< static CYTHON_INLINE int __Pyx_Is_Little_Endian(void)
< {
< union {
< uint32_t u32;
< uint8_t u8[4];
< } S;
< S.u32 = 0x01020304;
< return S.u8[0] == 4;
< }
<
8355c8254,8258
< static void __Pyx_BufFmt_Init(__Pyx_BufFmt_Context* ctx,
---
> static CYTHON_INLINE int __Pyx_IsLittleEndian(void) {
> unsigned int n = 1;
> return *(unsigned char*)(&n) != 0;
> }
> static void __Pyx_BufFmt_Init(__Pyx_BufFmt_Context* ctx,
8741c8644
< if (!__Pyx_Is_Little_Endian()) {
---
> if (!__Pyx_IsLittleEndian()) {
8750c8653
< if (__Pyx_Is_Little_Endian()) {
---
> if (__Pyx_IsLittleEndian()) {
8901c8804
< static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
---
> static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
8914c8817
< static void __Pyx_WriteUnraisable(const char *name, CYTHON_UNUSED int clineno,
---
> static void __Pyx_WriteUnraisable(const char *name, CYTHON_UNUSED int clineno,
8956c8859
< #if CYTHON_FAST_THREAD_STATE
---
> #if CYTHON_FAST_THREAD_STATE
8980c8883
< #if CYTHON_FAST_THREAD_STATE
---
> #if CYTHON_FAST_THREAD_STATE
8990c8893
< #if CYTHON_FAST_THREAD_STATE
---
> #if CYTHON_FAST_THREAD_STATE
9051c8954
< static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) {
---
> static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) {
9125c9028
< static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) {
---
> static PyTypeObject* __Pyx_FetchCommonType(PyTypeObject* type) {
9164c9067
< static PyObject *
---
> static PyObject *
9746,9781d9648
< /* CLineInTraceback */
< static int __Pyx_CLineForTraceback(int c_line) {
< #ifdef CYTHON_CLINE_IN_TRACEBACK
< return ((CYTHON_CLINE_IN_TRACEBACK)) ? c_line : 0;
< #else
< PyObject *use_cline;
< #if CYTHON_COMPILING_IN_CPYTHON
< PyObject **cython_runtime_dict = _PyObject_GetDictPtr(__pyx_cython_runtime);
< if (likely(cython_runtime_dict)) {
< use_cline = PyDict_GetItem(*cython_runtime_dict, __pyx_n_s_cline_in_traceback);
< } else
< #endif
< {
< PyObject *ptype, *pvalue, *ptraceback;
< PyObject *use_cline_obj;
< PyErr_Fetch(&ptype, &pvalue, &ptraceback);
< use_cline_obj = __Pyx_PyObject_GetAttrStr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback);
< if (use_cline_obj) {
< use_cline = PyObject_Not(use_cline_obj) ? Py_False : Py_True;
< Py_DECREF(use_cline_obj);
< } else {
< use_cline = NULL;
< }
< PyErr_Restore(ptype, pvalue, ptraceback);
< }
< if (!use_cline) {
< c_line = 0;
< PyObject_SetAttr(__pyx_cython_runtime, __pyx_n_s_cline_in_traceback, Py_False);
< }
< else if (PyObject_Not(use_cline) != 0) {
< c_line = 0;
< }
< return c_line;
< #endif
< }
<
9922,9925c9789
< if (c_line) {
< c_line = __Pyx_CLineForTraceback(c_line);
< }
< py_code = __pyx_find_code_object(c_line ? -c_line : py_line);
---
> py_code = __pyx_find_code_object(c_line ? c_line : py_line);
9930c9794
< __pyx_insert_code_object(c_line ? -c_line : py_line, py_code);
---
> __pyx_insert_code_object(c_line ? c_line : py_line, py_code);
9960,9962c9824
< if ((0)) {}
< else if (PyObject_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) __pyx_pw_5numpy_7ndarray_3__releasebuffer__(obj, view);
< view->obj = NULL;
---
> if (PyObject_TypeCheck(obj, __pyx_ptype_5numpy_ndarray)) { __pyx_pw_5numpy_7ndarray_3__releasebuffer__(obj, view); return; }
9963a9826
> view->obj = NULL;
9968,9969c9831,9832
< /* CIntFromPyVerify */
< #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\
---
> /* CIntFromPyVerify */
> #define __PYX_VERIFY_RETURN_INT(target_type, func_type, func_value)\
10927,10928d10789
< if (PyObject_Hash(*t->p) == -1)
< PyErr_Clear();
10937c10798
< static CYTHON_INLINE const char* __Pyx_PyObject_AsString(PyObject* o) {
---
> static CYTHON_INLINE char* __Pyx_PyObject_AsString(PyObject* o) {
10941c10802
< static CYTHON_INLINE const char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) {
---
> static CYTHON_INLINE char* __Pyx_PyObject_AsStringAndSize(PyObject* o, Py_ssize_t *length) {