3

Suppose I have the following (MCVE...) cython function

cimport cython

from scipy.linalg.cython_blas cimport dnrm2


cpdef double func(int n, double[:] x):
   cdef int inc = 1
   return dnrm2(&n, &x[0], &inc)

Then, I cannot call it on a np.float32 array x.

How could I make func accept a double[:] or a float[:], and call dnrm2 or snrm2 alternatively? The only solution I have currently is to have two functions, which creates a huge quantity of duplicated code.

P. Camilleri
  • 12,664
  • 7
  • 41
  • 76

1 Answers1

4

You could use a fused type. Please note that the below doesn't compile on my system because ddot and sdot apparently require 5 parameters:

# cython: infer_types=True
cimport cython

from scipy.linalg.cython_blas cimport ddot, sdot

ctypedef fused anyfloat:
   double
   float

cpdef anyfloat func(int n, anyfloat[:] x):
   cdef int inc = 1
   if anyfloat is double:
      return ddot(&n, &x[0], &inc)
   else:
      return sdot(&n, &x[0], &inc)
Paul Panzer
  • 51,835
  • 3
  • 54
  • 99
  • yep I got confused, I meant dnrm2 (anyway, it's just a dummy example) Is the "anyfloat is double" a costly overhead? – P. Camilleri May 04 '18 at 03:11
  • @P.Camilleri I don't really know, but my guess would be no. – Paul Panzer May 04 '18 at 03:24
  • 1
    The if statement is evaluated at compile time so no overhead at all (you can inspect the generated C code to confirm). The overhead happens when the function is called from Python and it has to pick which version (it can often directly use the right version from Cython though) – DavidW May 04 '18 at 06:11