How to declare ndarray in cython with a common floating point type

What is the best way to declare a numpy array in cython if it should be able to handle both float and double?

I think this will not be possible with a memory representation, since there the data type is crucial, but for ndarray is there any way to give it a generic float type that still favors the speed of cython?

so this is what I usually did:

def F( np.ndarray A): A += 10 

I saw that there are also:

 def F( np.ndarray[np.float32_t, ndim=2] A): A += 10 

but this again will give a bit size for the type. I also thought about how to create a memory representation inside a function depending on the bit size (32 or 64).

Any thought is much appreciated.


Thanks so much for the tip like floating . I tried it like this:

 import numpy as np cimport numpy as np import cython cimport cython from libc.math cimport sqrt, abs from cython cimport floating @cython.boundscheck(False) @cython.wraparound(False) @cython.nonecheck(False) def Rot_Matrix(np.ndarray[floating, ndim=3] Fit_X, np.ndarray[floating, ndim=3] Ref_X, weight = None): cdef: unsigned int t, T = Fit_X.shape[0] unsigned int n, N = Fit_X.shape[1] np.ndarray[floating, ndim=3] Rot = np.empty((T,3,3)) return Rot 

when I now call a function with two arrays np.float32, I get an error

ValueError: buffer dtype mismatch expected by 'float' but receiving 'double'

If I do not use the type definition in the brakes for Rot , so it reads np.ndarray[floating, ndim=3] Rot = np.empty((T,3,3)) , then I return ndarray and it works fine. You will have a pointer to me, what am I doing wrong?

+7
python numpy cython
source share
2 answers

Well, actually it is very simple with support for smooth types:

This is included in your code.

 from cython cimport floating def cythonfloating_memoryview(floating[:, :] array): cdef int i, j for i in range(array.shape[0]): for j in range(array.shape[1]): array[i, j] += 10 

Of course, there are many ways to do this:

Name this fuzed.pyx . There is no need to compile or run cython ; It is processed by pyximport . However, do not use pyximport for production code, since usually you only send .c files.

 from cython cimport floating from numpy import float32_t, float64_t, ndarray ctypedef fused myfloating: float32_t float64_t def cythonfloating_memoryview(floating[:, :] array): # ... def cythonfloating_buffer(ndarray[floating, ndim=2] array): # ... def myfloating_memoryview(myfloating[:, :] array): # ... def myfloating_buffer(ndarray[myfloating, ndim=2] array): # ... 

and here is a little script test:

Name this test.py and run it like a regular Python script:

 import pyximport pyximport.install() import fuzed import numpy functions = [ fuzed.cythonfloating_memoryview, fuzed.cythonfloating_buffer, fuzed.myfloating_memoryview, fuzed.myfloating_buffer, ] for function in functions: floats_32 = numpy.zeros((100, 100), "float32") doubles_32 = numpy.zeros((100, 100), "float64") function(floats_32) function(doubles_32) print(repr(floats_32)) print(repr(doubles_32)) 

It is worth noting that fused types specialize in compilation and are constant for a particular function call. The empty Numpy array you make is always of type double , but you assign it to either a 32-bit float or a 64-bit float. Here is what you should do:

 from cython cimport floating import numpy def do_some_things(floating[:] input): cdef floating[:] output if floating is float: output = numpy.empty(10, dtype="float32") elif floating is double: output = numpy.empty(10, dtype="float64") else: raise ValueError("Unknown floating type.") return output 

and some tests to prove the point:

 import pyximport pyximport.install() #>>> (None, None) import floatingtest import numpy floatingtest.do_some_things(numpy.empty(10, dtype="float32")) #>>> <MemoryView of 'ndarray' at 0x7f0a514b3d88> floatingtest.do_some_things(numpy.empty(10, dtype="float32")).itemsize #>>> 4 floatingtest.do_some_things(numpy.empty(10, dtype="float64")) #>>> <MemoryView of 'ndarray' at 0x7f0a514b3d88> floatingtest.do_some_things(numpy.empty(10, dtype="float64")).itemsize #>>> 8 
+12
source share

Merged types can only be used in function declarations. The best analogy I can come up with is templates in C ++.

To create a function that can be used with float32 / 64 do

 from cython import floating, numeric cimport cython def func_float(floating a): print cython.typeof(a) 

however, you can use Fused Types only in a function that has already appeared in the function declaration.

+2
source share

All Articles