Cython dengan array dengan panjang variabel

Oct 06 2020

Array yang tumbuh secara dinamis adalah jenis larik. Mereka sangat berguna saat Anda tidak mengetahui ukuran pasti dari larik pada waktu desain. Pertama, Anda perlu menentukan jumlah awal elemen. ( Wikipedia )

Saya telah menulis solusi Python dan mengubahnya menjadi Cython . Cython dapat digunakan untuk meningkatkan kecepatan loop bersarang di Python. Dimana kode Cython saya sedikit lebih cepat. Solusi Cython saya jelas bukan yang tercepat. Saya mencoba melakukan loop bersarang yang mirip dengan yang ada di kode Python saya secepat mungkin di Cython.

Akan membantu untuk memiliki beberapa pengalaman dalam C, yang saya tidak. Masalah utama yang saya hadapi adalah bahwa Cython memiliki aturan pelingkupan yang berbeda dengan Python. Karena C dan Python memiliki aturan pelingkupan yang berbeda. Dengan kata lain, kita tidak dapat membuat vektor baru dalam loop dan menugaskannya ke nama yang sama.

Solusi saya berfungsi tetapi terlalu lambat. Adakah yang bisa memperbaiki kode Cython di atas dengan menggunakan pendekatan yang lebih mirip C.

Python

import numpy as np

my_list = [1,2,3]
n = 10
a = 0.5

Estimate_1_list = []
Estimate_2_list = []

for l in my_list:

    # Resizable matrices
    a_mat = np.zeros((l,n+1),float)
    b_mat = np.zeros((l,n+1),float)
    
    for i  in range(n):
        t = i*a
        
        for j in range(l):
            
            # Fill matrices
            a_mat[j,i+1] = a_mat[j,i+1] + np.random.random()
            
            b_mat[j,i+1] = a_mat[j,i+1]/(2*t+3)
    
    # Append values of interest to use at different values of matrix size
    Estimate_1_list.append(np.mean(a_mat[:,n]))
    Estimate_2_list.append(np.std(a_mat[:,n]))   
results = [Estimate_1_list,Estimate_2_list]

Cython

import cython
# Load cython extension
%load_ext Cython

%%cython
import numpy as np

def my_function(list my_list, int n, int a ):
cdef list Estimate_1_list = []
cdef list Estimate_2_list = []
cdef int l,i,t,j
for l in my_list:

    # Resizable matrices (could I use memory view?)
    a_mat = np.zeros((l,n+1),float)
    b_mat = np.zeros((l,n+1),float)

    for i  in range(n):
        t = i*a

        for j in range(l):

            # Fill matrices
            a_mat[j,i+1] = a_mat[j,i+1] + np.random.random()

            b_mat[j,i+1] = a_mat[j,i+1]/(2*t+3)

    # Append values of interest to use at different values of matrix size
    Estimate_1_list.append(np.mean(a_mat[:,n]))
    Estimate_2_list.append(np.std(a_mat[:,n]))  
    
# Return results 
results = [Estimate_1_list,Estimate_2_list]
return results

Tes

# Test cython to show that the function is running
my_list = [1,2,3]
n = 10
a = 0.5
my_function(my_list, n, a)

[[0.13545224609230933, 0.6603542545719762, 0.6632002117071227],
 [0.0, 0.19967544614685195, 0.22125180486616808]]

Jawaban

Reinderien Oct 10 2020 at 00:25

Nol

Ini:

a_mat = np.zeros

bukanlah panggilan yang tepat untuk tujuan Anda. Anda menginginkannya np.empty, karena Anda tidak benar-benar peduli apa nilai awal karena Anda melakukan loop inisialisasi komprehensif tepat setelahnya.

Selanjutnya: karena Anda menambahkan random()ke setiap elemen a_mat, cukup lakukan inisialisasi a_matke satu panggilan random()dengan bentuk yang benar, daripada harus melakukan penambahan elemen-bijaksana.

Vektorisasi

Anda memiliki dimensi luar ( lmelalui my_list), dimensi kedua ( l) dan dimensi ketiga ( n + 1). Dimensi kedua adalah variabel; yang pertama dan ketiga konstan. Ini berarti Anda dapat merepresentasikan ini dengan lebih efisien jika Anda mengatur ulang dimensi Anda sehingga dimensi tetap ada di interior. Dengan kata lain, jika Anda punya

len(my_list) = 3
l = 1, 2, 3
n = 10

maka Anda sebenarnya dapat merepresentasikan ini sebagai matriks tiga dimensi tunggal dengan dimensi 6 * 3 * 10, di mana 6 == len(my_list) * (len(my_list) - 1). Saya pikir itu mungkin untuk melakukan semua ini tanpa satu forloop, yang ideal untuk kinerja vektor.