Skip to content
Snippets Groups Projects
Commit 377f8932 authored by Antaaa28's avatar Antaaa28
Browse files

bonus partie 1 + question 6,7,10 partie 2 + maj

parent d0c00a82
No related branches found
No related tags found
No related merge requests found
......@@ -29,6 +29,9 @@ La courbe est beaucoup moins fluide. Elle monte par paliers, car le dictionnaire
La MPHF est clairement plus avantageuse en termes de mémoire, surtout quand on travaille avec de très grands ensembles de k-mers, comme c’est souvent le cas en bioinformatique. Le dictionnaire, lui, reste pratique et facile à utiliser, mais il devient vite inefficace quand on monte en volume.
Bonus : faites varier `nb_niveaux` et `gamma`, voyez quelle influence ils peuvent avoir.
On constate qu'augmenter gamma ou nb_niveaux ne change pas la taille finale de la structure (elle reste fixe car on stocke une paire par k-mer),
mais cela ralentit la construction de la MPHF.
Autrement dit, ces paramètres font travailler le code un peu plus pour mieux gérer les collisions, ce qui allonge le temps de calcul sans affecter la taille finale.
# Partie 2 - Analyse de performance de dictionnaires en Python
......@@ -75,3 +78,17 @@ Initialiser dans la fonction `experiment_load_factor` des listes `insertion_time
- Un histogramme des fréquences des temps d'insertions discrétisés (code fourni, remplacer la liste vide par la bonne entrée)
10. Commentez vos résultats.
-Pour le graphique du temps d'insertion en fonction du facteur de charge ,on constate que l’insertion dans un dictionnaire Python demeure rapide même lorsque le facteur de charge est proche de 1.0.
Les sauts traduisent les réallocations internes et la gestion mémoire dynamique de Python, qui peuvent se produire à des moments différents d’une exécution à l’autre
-Pour le graphique du nombre de réallocations de mémoire en fonction du facteur de charge , on constate que plus on insère d’éléments (donc plus le facteur de charge est élevé),
plus le dictionnaire Python se réalloue en mémoire, jusqu’à atteindre un plateau autour de 12 réallocations.
Python effectue ces réallocations par paliers, ce qui explique pourquoi le nombre total de «resizes» reste finalement assez limité malgré un grand nombre d’insertions.
-Pour le graphique de la taille de mémoire occupée en fonction du nombre d'éléments ,On voit que la mémoire occupée par le dictionnaire augmente à mesure que le nombre d’éléments insérés croît,
avec des sauts plus ou moins marqués qui correspondent aux réallocations internes. Au-delà d’un certain seuil (environ 6000 éléments ici), la taille mémoire se stabilise, car le dictionnaire a suffisamment grandi pour accueillir la totalité des clés.
-On constate sur l'histogramme des fréquences des temps d'insertions discrétisés que La majorité des insertions se font en un temps quasi nul , tandis qu’une poignée d’insertions plus longues apparaissent dans la seconde barre,
probablement lors des réallocations.
Cela souligne qu’en Python, la plupart des insertions sont très rapides, mais certaines opérations de réallocation peuvent entraîner un temps d’insertion plus élevé.
\ No newline at end of file
from re import search
from typing import List
import matplotlib.pyplot as plt
import numpy as np
......@@ -10,100 +11,126 @@ import sys
###### PARTIE 2 ######
def experiment_load_factor(load_factors):
"""
Etude l'inmpact du facteur de charge sur les performances d'un dictionnaire Python.
Mesure les temps d'insertion, de recherche et de suppression pour différents facteurs de charge.
Returns:
insetion_times: liste contenant les temps d'insertion (en secondes) pour chaque facteur de charge.
search_times: Liste contenant les temps de recherchde (en secondes) pour chaque facteur de charge.
deletion_times: Liste contenant les temps de suppression (en secondes) pour chaque facteur de charge
"""
# 1- Initialisation des listes pour stocker les résultats
insertion_times = [] # Temps d'insertion pour chaque facteur de charge
search_times = [] # Temps de recherche pour chaque facteur de charge
deletion_times = [] # Temps de suppression pour chaque facteur de charge
# 2. Boucle sur chaque facteur de charge donné en entrée
for load_factor in load_factors:
# Création d'un dictionnaire vide au départ
d = {}
# Calcul de la taille du dictionnaire en fonction du facteur de charge
size = int(10000 * load_factor)
# Mesure du temps d'insertion
start_time = time.time()
for i in range(size):
key = str(i)
value = i
d[key] = value # Insertion de la clé et de la valeur
insertion_time = time.time() - start_time
insertion_times.append(insertion_time)
# Mesure du temps de recherche
start_time = time.time()
for i in range(size):
key = str(i)
_ = d.get(key) # Recherche de la clé
search_time = time.time() - start_time
search_times.append(search_time)
# Réinitialisation du dictionnaire pour la suppression
d = {str(i): i for i in range(size)}
# Mesure du temps de suppression
start_time = time.time()
for i in range(size):
key = str(i)
del d[key] # Suppression de la clé
deletion_time = time.time() - start_time
deletion_times.append(deletion_time)
# Retour des résultats
return insertion_times, search_times, deletion_times
"""
Etude l'inmpact du facteur de charge sur les performances d'un dictionnaire Python.
Mesure les temps d'insertion, de recherche et de suppression pour différents facteurs de charge.
Returns:
insetion_times: liste contenant les temps d'insertion (en secondes) pour chaque facteur de charge.
search_times: Liste contenant les temps de recherchde (en secondes) pour chaque facteur de charge.
deletion_times: Liste contenant les temps de suppression (en secondes) pour chaque facteur de charge
"""
insertion_times = [] # Pour stocker le temps total d'insertion
num_resizes = [] # Pour stocker le nombre de réallocations
sizes = [] # Pour stocker la taille mémoire finale
for lf in load_factors:
# Crée un dictionnaire vide
d = {}
# Nombre d'éléments à insérer pour ce facteur de charge
num_elements = int(10000 * lf)
# Variables pour suivre la taille courante et détecter une réallocation
last_size = sys.getsizeof(d) # taille mémoire initiale
resize_count = 0
# Mesure du temps d'insertion (global)
start_time = time.time()
for i in range(num_elements):
d[i] = i
# Après chaque insertion, vérifie si la taille mémoire a augmenté
current_size = sys.getsizeof(d)
if current_size > last_size:
resize_count += 1
last_size = current_size
end_time = time.time()
total_insertion_time = end_time - start_time
# Stockage des résultats pour ce facteur de charge
insertion_times.append(total_insertion_time)
num_resizes.append(resize_count)
sizes.append(sys.getsizeof(d))
return insertion_times, num_resizes, sizes
def experiment_longest():
"""
TODO: que fait cette fonction
"""
d = {}
insertion_times = []
for i in range(10000):
key = str(i)
value = i
start_time = time.time()
d[key] = value
insertion_time = time.time() - start_time
insertion_times.append(insertion_time)
frequencies = np.histogram(insertion_times)[0]
return frequencies
"""
Effectue 10 000 insertions successives dans un dict, en mesurant
le temps d'insertion pour chacune.
Retourne l'histogramme (fréquences) de ces temps d'insertion,
discrétisés en bacs (bins).
"""
d = {}
insertion_times = []
for i in range(10000):
key = str(i)
value = i
start_time = time.time()
d[key] = value
insertion_time = time.time() - start_time
insertion_times.append(insertion_time)
frequencies = np.histogram(insertion_times)[0]
return frequencies
def visualisation(load_factors, insertion_times, num_resizes, sizes, frequencies):
"""
Visualisation des résultats
"""
# Temps d'insertion en fonction du facteur de charge
# Nombre de réallocations de mémoire en fonction du facteur de charge
# Taille de mémoire occupée en fonction du nombre d'éléments
# Deuxième étude
f = list()
plt.figure(figsize=(10, 6))
plt.bar(range(len(f)), f)
plt.xlabel('Temps d\'insertion (s)')
plt.ylabel('Fréquence')
plt.title('Histogramme des fréquences des temps d\'insertions')
plt.yscale('log')
xticks = np.logspace(-6, 1, 3)
xtick_labels = [f'{x:.1e}' for x in xticks]
plt.xticks(xticks, xtick_labels)
plt.savefig('histogramme.png')
"""
Visualisation des résultats
"""
# Temps d'insertion en fonction du facteur de charge
plt.figure(figsize=(6, 4))
plt.plot(load_factors, insertion_times, marker='o')
plt.xlabel('Facteur de charge (load_factor)')
plt.ylabel('Temps total d\'insertion (secondes)')
plt.title('Temps d\'insertion en fonction du facteur de charge')
plt.grid(True)
plt.tight_layout()
plt.savefig('Tps_insertion.facteur_de_charge.png')
plt.close()
# Nombre de réallocations de mémoire en fonction du facteur de charge
plt.figure(figsize=(6, 4))
plt.plot(load_factors, num_resizes, marker='o')
plt.xlabel('Facteur de charge (load_factor)')
plt.ylabel('Nombre de réallocations (resizes)')
plt.title('Nombre de réallocations de mémoire en fonction du facteur de charge')
plt.grid(True)
plt.tight_layout()
plt.savefig('nb_reallocation.facteur_de_charge.png')
plt.close()
# Taille de mémoire occupée en fonction du nombre d'éléments
# Le nombre d'éléments insérés = 10000 * load_factor
nb_elements = [int(10000 * lf) for lf in load_factors]
plt.figure(figsize=(6, 4))
plt.plot(nb_elements, sizes, marker='o')
plt.xlabel('Nombre d\'éléments insérés')
plt.ylabel('Taille mémoire du dict (octets)')
plt.title('Taille de mémoire occupée en fonction du nombre d\'éléments')
plt.grid(True)
plt.tight_layout()
plt.savefig('courbe_memoire.nombre_delement.png')
plt.close()
# Deuxième étude
f = frequencies
plt.figure(figsize=(10, 6))
plt.bar(range(len(f)), f)
plt.xlabel('Temps d\'insertion (s)')
plt.ylabel('Fréquence')
plt.title('Histogramme des fréquences des temps d\'insertions')
plt.yscale('log')
xticks = np.logspace(-6, 1, 3)
xtick_labels = [f'{x:.1e}' for x in xticks]
plt.xticks(xticks, xtick_labels)
plt.savefig('histogramme.png')
load_factors = [0.01, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]
insertion_times, num_resizes, sizes = experiment_load_factor(load_factors)
......
......@@ -200,4 +200,27 @@ def compare_taille(n_max, fichier_sortie):
# dé-commenter quand vous êtes prêts, expliquer les résultats
compare_taille(10000,"mphf.png")
#bonus
def experiment_mphf_variation(set_kmer, n, gamma_values, niveaux_values):
"""
Compare l'influence de gamma et nb_niveaux sur la taille et/ou le temps de construction
de la MPHF pour un ensemble set_kmer.
"""
for gamma in gamma_values:
for nb_niveaux in niveaux_values:
start = time.time()
mphf = construction_mphf(set_kmer, n, gamma=gamma, nb_niveaux=nb_niveaux)
end = time.time()
size_mphf = sys.getsizeof(mphf)
print(f"gamma={gamma}, nb_niveaux={nb_niveaux} | "
f"Taille MPHF: {size_mphf} octets | "
f"Temps construction: {end - start:.5f} s")
set_kmer = generer_kmers(1000, 21) # Par exemple, 1000 k-mers de taille 21
experiment_mphf_variation(set_kmer, n=1000,
gamma_values=[1,2,3,4],
niveaux_values=[1,2,3])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment