2017-01-05 4 views
2

In Cython kann man Array-Ansichten verwenden, z.Cython statisch geformte Array-Ansichten

In meiner Verwendung sollte die zweite Dimension immer eine Form von 2 haben. Kann ich Cython dies sagen? Ich dachte an etwas wie:

aber dies führt zu einer ungültigen Syntax; Oder ist es möglich, etwas ähnliches wie C++ zu haben, z.

cdef void func(tuple<float, float>[:] arr) 

Vielen Dank im Voraus!

Antwort

1

Sie können stattdessen ein statisches 2D-Array verwenden. Verwenden Sie einfach die Zeiger-Notation. Hier ist, wie Sie erreichen es

def pyfunc(): 
    # static 1D array 
    cdef float *arr1d = [1,-1, 0, 2,-1, -1, 4] 
    # static 2D array 
    cdef float[2] *arr2d = [[1,.2.],[3.,4.]] 
    # pass to a "cdef"ed function 
    cfunc(arr2d) 

# your function signature would now look like this 
cdef void cfunc(float[2] *arr2d): 
    print("my 2D static array") 
    print(arr2d[0][0],arr2d[0][1],arr2d[1][0],arr2d[1][1]) 

es aufrufen erhalten Sie:

>>> pyfunc() 
my 2D static array 
1.0, 2.0, 3.0, 4.0 
+0

Folgefrage: Wie kann ich die Daten eines numpy Arrays in 'float [2] *' konvertieren? – user1447257

+0

@ user1447257 Was möchten Sie damit erreichen? Es klang so, als ob Sie ein statisch geformtes Array für Performance-Zwecke haben wollten. Wenn dies jedoch nur ein syntaktischer Zucker in Ihrem Code ist, können Sie auch die generische Memory View-Syntax 'float [:,:]' 'verwenden. Da 'numpy' Arrays dynamisch sind, werden sie nicht an' float [2] * 'gebunden, es sei denn, Sie möchten die Daten explizit kopieren. – romeric

+0

Für weniger Cache-Fehler würde ich sowieso auf ein zusammenhängendes Array kopieren, da mein Code mehrmals über die Einträge iteriert. Ich habe mir gedacht, dass eine Umwandlung in einen 'float [2] *' -Datentyp die Leistung ein wenig erhöht, weil der Zeiger vollständig linear inkrementiert werden könnte. – user1447257

0

Ich glaube nicht wirklich unterstützt wird, aber wenn Sie dies tun wollen, dann der beste Weg ist wahrscheinlich zu verwenden memoryviews von structs (die mit numpys benutzerdefinierten dtypes kompatibel sind):

import numpy as np 

cdef packed struct Pair1: # packed ensures it matches custom numpy dtypes 
       # (but probably doesn't matter here!) 
    double x 
    double y 

# pair 1 matches arrays of this dtype  
pair_1_dtype = [('x',np.float64), ('y',np.float64)] 

cdef packed struct Pair2: 
    double data[2] 

pair_2_dtype = [('data',np.float64, (2,))] 

def pair_func1(Pair1[::1] x): 
    # do some very basic work 
    cdef Pair1 p 
    cdef Py_ssize_t i 
    p.x = 0; p.y = 0 
    for i in range(x.shape[0]): 
     p.x += x[i].x 
     p.y += x[i].y 

    return p # take advantage of auto-conversion to a dict 

def pair_func2(Pair2[::1] x): 
    # do some very basic work 
    cdef Pair2 p 
    cdef Py_ssize_t i 
    p.data[0] = 0; p.data[1] = 0 
    for i in range(x.shape[0]): 
     p.data[0] += x[i].data[0] 
     p.data[1] += x[i].data[1] 

    return p # take advantage of auto-conversion to a dict 

und eine Funktion, die Sie zeigen, wie man es nennen:

def call_pair_funcs_example(): 
    # generate data of correct dtype 
    d = np.random.rand(100,2) 
    d1 = d.view(dtype=pair_1_dtype).reshape(-1) 
    print(pair_func1(d1)) 

    d2 = d.view(dtype=pair_2_dtype).reshape(-1) 
    print(pair_func2(d2)) 

Die Sache Ich mag würde getan haben ist:

ctypedef double[2] Pair3 

def pair_func3(Pair3[::1] x): 
    # do some very basic work 
    cdef Pair3 p 
    cdef Py_ssize_t i 
    p[0] = 0; p[1] = 0 
    for i in range(x.shape[0]): 
     p[0] += x[i][0] 
     p[1] += x[i][1] 

    return p # ??? 

die erfolgreich kompiliert, aber ich konnte jede mögliche Weise nicht gefunden davon aus numpy konvertieren. Wenn Sie herausfinden könnten, wie Sie diese Version zum Laufen bringen, dann wäre das wohl die eleganteste Lösung.


Beachten Sie, dass ich von den Leistungsvorteilen dieser Lösungen nicht überzeugt bin. Ihre beste Bewegung ist wahrscheinlich, Cython mitzuteilen, dass die abschließende Dimension zusammenhängend im Speicher ist (z. B. double [:,::1]), aber lassen Sie sie eine beliebige Größe haben.