Dans les exemples suivants, nous allons voir l’intérêt de passer par des bibliothèques préconçues, notamment en terme de temps de calcul.

Cas des vecteurs

Pour cet exemple, nous allons nous baser sur les vecteurs suivants :

import numpy as np

v_time = np.linspace(0,1,4000)
f0 = 100
v_signal = np.sin(2 * np.pi * f0 * v_time)

Ce code génère deux vecteurs v_time et v_signal de 4000 échantillons chacun.

Par le suite, on va chercher à copier une partie des données (les 400 premiers échantillons) vers un autre vecteur.

n_max = 400
v_time_imp = np.zeros(n_max)
v_time_mat = np.zeros(n_max)

On définit alors deux nouveaux vecteurs de 400 éléments remplis de 0.

Afin de pouvoir mesurer le temps d’exécution des programmes réalisés, nous allons nous appuyer sur la bibliothèque time de Python. Afin de pouvoir mesurer des temps faibles d’exécution, nous allons réaliser l’opération un certains nombres de fois.

Calcul itératif en Python

On réalise ici l’opération 100 fois.

import time
start1 = time.time()

for k in range(100):
    for i in range(n_max):
        v_time_imp[i] = v_time[i]

end1 = time.time()
elapsed1 = end1 - start1
print(f'Temps d\'exécution (100 exécutions) : {elapsed1:.8}ms')

Utilisation de la bibliothèque Numpy

On réalise ici l’opération 10 000 fois.

start2 = time.time()

for k in range(int(1e4)):
    v_time_mat[0:n_max] = v_time[0:n_max]

end2 = time.time()
elapsed2 = end2 - start2
print(f'Temps d\'exécution (10^4 executions) : {elapsed2:.8}ms')

Comparaison

Les deux codes précédents fournissent le résultat suivant (avec un processeur Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz, 32 Go de RAM et sous Windows 10) :

Temps d'exécution (100 exécutions) : 0.0079784393ms
Temps d'exécution (10^4 executions) : 0.0069489479ms

On s’aperçoit sur cet exemple simple que le calcul matriciel est environ 100 fois plus performant en terme de temps de calcul (100 exécutions pour le calcul itératif contre 10 000 exécutions pour le calcul matriciel donnant un temps d’exécution entre 7 et 8 us).

Autre exemple / Utilisation d’un meshgrid

Un autre exemple basé sur l’utilisation d’un meshgrid pour la génération de matrices permet d’aboutir à des conclusions similaires.

L’utilisation de boucles en Python (langage interprété) est souvent plus couteux en temps de calcul, contrairement à l’utilisation de bibliothèques (de type Numpy) qui se basent sur des instructions pré-compilées en langage C/C++. L’exécution se base également sur des boucles mais dans un langage compilé et donc plus rapide à l’exécution.

import numpy as np
import time

N = 2000

sum = 0
x = np.linspace(1,N,N)

start_time = time.time()
for i in range(1,N):
    for j in range(1,N):
        sum = sum + i
time_spent_sum_loop = 1000*(time.time() - start_time)
    

XX,XX = np.meshgrid(x,x)

start_time = time.time()
sum = np.sum(XX)
time_spent_sum_np = 1000*(time.time() - start_time)
print(f"Loop: {time_spent_sum_loop} ms \nNumPy {time_spent_sum_np} ms")
print(f"Numpy is {round(time_spent_sum_loop/time_spent_sum_np)} times faster")

start_time = time.time()
XX2 = np.zeros((N, N))
for i in range(1,N):
    for j in range(1,N):
        XX2[i,j] = XX[i,j]*XX[i,j]
time_spent_product_loop = 1000*(time.time() - start_time)

start_time = time.time()
XX2 = XX*XX
time_spent_product_np = 1000*(time.time() - start_time)
print(f"Loop: {time_spent_product_loop} ms \nNumPy {time_spent_product_np} ms")
print(f"Numpy is {round(time_spent_product_loop/time_spent_product_np)} times faster")
Python / Comparatif C/C++ vs Python