I have implement myself defined a chainer Link, but because it is too slow.
I have implemented cython CPU version of my code. But I want to further boost speed via GPU. So I test the following code , but it failed:
%%cython
import numpy as np
cimport numpy as np
import cupy as cp
cimport cupy as cp
cdef class A:
def __init__(self):
pass
cdef cp_test(self, cp.ndarray[cp.float_t, ndim=2] arr):
return cp.sum(arr)
a = A()
arr = cp.arange(100).reshape(20,50)
print(a.cp_test(arr))
reporting:
cdef cp_test(self, cp.ndarray[cp.float_t, ndim=2] arr):
^
------------------------------------------------------------
C:\Users\.ipython\cython\_cython_magic_d4940a274af88f0257c368b8a5d0e3f5.pyx:13:23: 'ndarray' is not a type identifier
Sorry, but CuPy does not provide cython interface currently (I am one of CuPy developers).
Related
I am new to Cython. I have written a pyx file that returns a 2D Numpy or a memoryview array.
Here is the pyx code:
import numpy as np
import cython
cimport numpy as np
from libc.math cimport int
#cython.wraparound(False)
#cython.boundscheck(False)
#cython.cdivision(True)
#cython.nonecheck(False)
cdef class TwoDMatrix():
''' make a two dimensional matrix '''
cdef int N
def __init__(self,N):
self.N = N
cpdef twoD(self, int [:,:] vector,str array):
if array == 'numpy':
state = 2*np.random.randint(2,size=(self.N,self.N))-1
return state
else:
vec=self.initialise(vector,self.N)
return vec
cdef int [:,:] initialise(self, int [:,:] s,k) :
cdef int i,j
for i in range(k+1):
for j in range(k+1):
if np.random.rand() <0.5:
s[i,j] = -1
else:
s[i,j] = 1
return s
And here is the main py file where I give input:
import numpy as np
import main
def matrix():
N = 10
vector = main.TwoDMatrix(N)
spin = np.zeros((N,N),dtype=np.int32)
print(f"from numpy: {vector.twoD(spin,'numpy')}")
print(f"from memoryview: {vector.twoD(spin,'memoryview')}")
print("program successfully exited")
if __name__ == "__main__":
matrix()
The problem is for N >5 , when I run in terminal it always shows a segmentation fault(core dumped) message at the bottom. And for N>1, a similar following message is shown:
"corrupted size vs. prev_size while consolidating
Aborted (core dumped)"
Why is this message popping up? Is there anything that I should consider about memory allocation?
The segmentation fault is due to out-of-bounds accesses. Indeed, you create matrices of size (N,N) while initialise iterate over range range(0, k+1) where k=N. Thus you need to either use bigger matrices or to fix the two nested loops so to iterate over range(0, k) / range(0, N).
I'd like to initialize a C++ STL vector by using the
template<class InputIt>
std::vector(InputIt first, InputIt last);
constructor in Cython. Here's a simple example:
from libcpp.vector cimport vector
import numpy as np
cimport numpy as cnp
cnp.import_array()
def foo(double[::1] a):
cdef vector[double] vec = vector[double](&a[0], &a[0] + a.size)
# do something with vec..
However, this yields the error message
from libcpp.vector cimport vector
def foo(double[::1] a):
cdef vector[double] vec = vector[double](&a[0], &a[0] + a.size)
^
------------------------------------------------------------
.ipython/cython/_cython_magic_c522d88d9553084771dd501620335f85a93b04ae.pyx:5:52: Cannot convert 'double *' to Python object
Error compiling Cython file:
------------------------------------------------------------
...
from libcpp.vector cimport vector
def foo(double[::1] a):
cdef vector[double] vec = vector[double](&a[0], &a[0] + a.size)
^
------------------------------------------------------------
.ipython/cython/_cython_magic_c522d88d9553084771dd501620335f85a93b04ae.pyx:5:45: Cannot assign type 'double *' to 'size_type
Any idea what I am doing wrong?
As mentioned in the comments, your desired constructor is not available inside Cython. AFAIK, Cython doesn't support templated constructors yet. As a workaround, you could use .assign(), i.e.:
from libcpp.vector cimport vector
def foo(double[::1] a):
cdef vector[double] vec
vec.assign(&a[0], &a[0] + <size_t>a.size)
# do something with vec..
It seems that one can't declare np.ndarray in cython.locals in .pxd files. It works with memoryviews but not with np.ndarray. However, there are cases where we need np.ndarray.
In notsupported.py
import numpy as np
def func():
arr = np.ones(2)
return arr**2
In notsupported.pxd
import cython
import numpy as np
cimport numpy as np
#cython.locals(arr=np.ndarray[np.int_t, ndim=1])
cpdef func()
Error log:
Error compiling Cython file:
------------------------------------------------------------
...
import cython
import numpy as np
cimport numpy as np
#cython.locals(arr=np.ndarray[np.int_t, ndim=1])
^
------------------------------------------------------------
notsupported.pxd:6:44: Expected ']', found '='
Is there something wrong with this code? What is the alternative?
Since it looks like this isn't supported I assume you're really interested in workarounds. For the purpose of this question I'm assuming you want your code to also be valid in pure Python. I'm also assuming that your code is of the form:
def func():
arr = np.ones(2)
for n in range(arr.shape[0]):
arr[n] = # some operation element-by-element
return arr**2
If your code doesn't have the element-by-element section then there's really no benefit to setting the type at all - I don't believe Cython uses the type for Numpy "whole array" operations like the power operator you show here.
My first choice would be to have two variables: arr and arr_view. arr should be untyped, and arr_view a memoryview. You only use the memoryview in the element-by-element section. Provided you stick to in-place operations the two share the same memory so modifying one modifies the other:
def func():
arr = np.ones(2)
arr_view = arr
for n in range(arr_view.shape[0]):
arr_view[n] = ...
return arr**2
The pxd file is then:
#cython.locals(arr_view=np.int_t[:])
cpdef func()
My second choice would be to type arr as a memoryview, and use np.asarray when you want to do "whole array" operations
def func():
arr = np.ones(2)
for n in range(arr.shape[0]):
arr[n] = # some operation element-by-element
return np.asarray(arr)**2
with pxd:
#cython.locals(arr=nnp.int_t[:])
cpdef func()
np.asarray is essentially a no-op if it's passed an array, and can usuaully avoid a copy if passed a memoryview, so it won't slow things down too much.
A third option is to use the arr.base object of a memoryview to get the underlying Numpy array. This loses pure Python compatibility though since arr.base is often None when arr is a Numpy array. Therefore I don't really recommend it here.
I have a cython extension type that I want to make more general. One of the attributes of this extension type is a double and I want it to be a memoryview (double[::1]) when needed.
Here is a simple example :
import numpy as np
cimport numpy as np
cimport cython
cdef class Test:
cdef bint numeric
cdef double du
def __init__(self, bint numeric):
self.numeric = numeric
if self.numeric:
self.du = 1
else:
self.du = np.ones(10)
def disp(self)
print(self.du)
Test(True).disp() # returns 1
Test(False).disp() # gives of course an error
I tried to subclass Test changing du type to double[::1] and implementing a new __init__ but it seems that we can't override class attributes of extension types. Even if it worked, it wouldn't be satisfactory because I don't really want to have one extension type for each case.
The best would be that my extension type directly handle both cases (scalar du and memoryview du).
Is there a way to do this with Cython ?
Unfortunately, you cannot use fused_type as attributes type. You can have two options here:
You could try to use the memory adress of the variable you want to call, and cast it when needed (everything is explained here.) Unfortunately, I did not succeed at making it work with typed memory views.
Or you can use your defined attribute numeric to call the appropriate method:
import numpy as np
cimport numpy as np
cimport cython
cdef class Test:
cdef bint numeric
cdef double du_numeric
cdef double[:] du_mem_view
def __init__(self, bint numeric):
self.numeric = numeric
if self.numeric:
self.du_numeric = 1
else:
self.du_mem_view = np.ones(10)
def disp(self):
if self.numeric:
print(self.du_numeric)
else:
print(self.du_numeric_mem_view)
Test(True).disp() # returns 1
Test(False).disp() # Does not give an error anymore !
I implemented a pure Python code in object-oriented style. In some of the methods there are time intensive loops, which I hope to speed up by cythonizing the code.
I am using a lot of numpy arrays and struggle with converting classes into Cython extension types.
Here I declare two numpy arrays 'verteces' and 'norms' as attributes:
import numpy as np
cimport numpy as np
cdef class Geometry(object):
cdef:
np.ndarray verteces
np.ndarray norms
def __init__(self, config):
""" Initialization"""
self.config = config
self.verteces = np.empty([1,3,3],dtype=np.float32)
self.norms = np.empty(3,dtype=np.float32)
During runtime the actual size of the arrays will be defined. This happens when calling the Geometry.load() method of the same class. The method opens an STL-file and loops over the triangle entries.
Finally I want to determine the intersection points of the triangles and a ray. In the respective method I use the following declarations.
cdef void hit(self, object photon):
""" Ray-triangle intersection according to Moeller and Trumbore algorithm """
cdef:
np.ndarray[DTYPE_t, ndim=3] verteces = self.verteces # nx3x3
np.ndarray[DTYPE_t, ndim=2] norms = self.norms
np.ndarray[DTYPE_t, ndim=1] ph_dir = photon.direction
np.ndarray[DTYPE_t, ndim=1] ph_origin = photon.origin
np.ndarray[DTYPE_t, ndim=1] v0, v1, v2, vec1, vec2, trsc, norm, v, p_inter
float a, b, par, q, q0, q1, s0, s1
int i_tri
When I try to compile this code I get the following error message:
'dimensions' is not a member of 'tagPyArrayObject'
I am not very familiar cython programming, but maybe the error is do to the fact that I have to initialize an array of fixed size in a C-extension type? The size of the array is, however, unkown until the STL-file is read.
Not sure if this is related to your problem, but I've got the same identical error message when specifying the "NPY_1_7_API_VERSION" macro in my setup.py file.
extension_module = Extension(
'yourfilename',
sources=["yourfilename.pyx],
include_dirs=[numpy.get_include()],
define_macros=[("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")],
)
With this macro, a simple npmatrix.shape[0] numpy function is compiled as:
/* "yourfilename.pyx":35
*
* cpdef int vcount(self):
* return self.npmatrix.shape[0]
*
*/
__pyx_r = (__pyx_v_self->npmatrix->dimensions[0]);
which causes the error. Just removing the macro resolved this error to me.