Cython avec des tableaux de longueur variable

Oct 06 2020

Les baies à croissance dynamique sont un type de baie. Ils sont très utiles lorsque vous ne connaissez pas la taille exacte du tableau au moment de la conception. Vous devez d'abord définir un nombre initial d'éléments. ( Wikipédia )

J'ai écrit une solution Python et l'ai convertie en Cython . Cython peut être utilisé pour améliorer la vitesse des boucles for imbriquées en Python. Où mon code Cython est légèrement plus rapide. Ma solution Cython n'est évidemment pas la plus rapide. J'essaie d'effectuer une boucle for imbriquée similaire à celle de mon code Python aussi vite que possible en Cython.

Il serait utile d'avoir une certaine expérience en C, ce que je n'ai pas. Le principal problème que j'ai rencontré est que Cython a des règles de portée différentes de Python. Puisque C et Python ont des règles de portée différentes. En d'autres termes, nous ne pouvons pas créer un nouveau vecteur dans la boucle et lui attribuer le même nom.

Ma solution fonctionne mais est trop lente. Quelqu'un peut-il améliorer le code Cython ci-dessus en utilisant une approche plus semblable au 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

Des tests

# 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]]

Réponses

Reinderien Oct 10 2020 at 00:25

Zéros

Cette:

a_mat = np.zeros

n'est pas le bon appel pour votre objectif. Vous voulez à la np.emptyplace, car vous ne vous souciez pas réellement des valeurs initiales puisque vous effectuez une boucle d'initialisation complète juste après.

De plus: puisque vous ajoutez random()à chaque élément de a_mat, initialisez simplement a_matà un seul appel de random()avec la forme correcte, plutôt que d'avoir à faire une addition par élément.

Vectorisation

Vous avez une dimension extérieure (à ltravers my_list), une deuxième dimension ( l) et une troisième dimension ( n + 1). La deuxième dimension est variable; le premier et le troisième sont constants. Cela signifie que vous pouvez représenter cela plus efficacement si vous réorganisez vos dimensions de sorte que les dimensions fixes soient à l'intérieur. En d'autres termes, si vous aviez

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

alors vous pouvez réellement représenter cela comme une seule matrice tridimensionnelle de dimensions 6 * 3 * 10, où 6 == len(my_list) * (len(my_list) - 1). Je pense qu'il est possible de faire tout cela sans une seule forboucle, ce qui est l'idéal pour des performances vectorisées.