Skip to content
Snippets Groups Projects
Commit cc6b19b5 authored by Samuel Nguyen's avatar Samuel Nguyen
Browse files

Partie 2 finie. A retravailler

parent 7881f86a
Branches
No related tags found
No related merge requests found
tp_2_miso_dict.py
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" /> <component name="Black">
<option name="sdkName" value="Python 3.12" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12" project-jdk-type="Python SDK" />
</project> </project>
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<module type="PYTHON_MODULE" version="4"> <module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager"> <component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" /> <orderEntry type="jdk" jdkName="Python 3.12" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>
<component name="PyDocumentationSettings"> <component name="PyDocumentationSettings">
......
...@@ -2,6 +2,7 @@ import matplotlib.pyplot as plt ...@@ -2,6 +2,7 @@ import matplotlib.pyplot as plt
import numpy as np import numpy as np
import time import time
import sys import sys
import statistics #pour faire la moyenne des temps d'insertion pour chaque facteur de charge
...@@ -21,13 +22,38 @@ def experiment_load_factor(load_factors : list): ...@@ -21,13 +22,38 @@ def experiment_load_factor(load_factors : list):
Les nombres de réallocations de mémoire Les nombres de réallocations de mémoire
Les tailles de mémoire occupée par le dictionnaire pour chaque facteur de charge Les tailles de mémoire occupée par le dictionnaire pour chaque facteur de charge
""" """
# Initialisation
insertion_times = [] insertion_times = []
num_resizes = [] num_resizes = []
sizes = [] sizes = []
for factor in load_factors : for factor in load_factors :
dictio = {} dictio = {}
# num_elements = .......... QUESTION 2 PARTIE 2 num_resize=0
return [],[],[] last_size = sys.getsizeof(dictio)
num_elements = int(factor*100)
tempsecoules = []
for i in range(num_elements) :
cle = 'cle'+str(i)
start_time = time.time()
dictio[cle] = i
end_time = time.time()
tempsecoule = end_time - start_time
tempsecoules.append(tempsecoule)
current_size = sys.getsizeof(dictio)
if current_size > last_size :
num_resize += 1
last_size = current_size
size = sys.getsizeof(dictio)
insertion_time = statistics.mean(tempsecoules)
insertion_times.append(insertion_time)
num_resizes.append(num_resize)
sizes.append(size)
return insertion_times, num_resizes, sizes
def experiment_longest(): def experiment_longest():
""" """
...@@ -50,24 +76,42 @@ def visualisation(load_factors, insertion_times, num_resizes, sizes, frequencies ...@@ -50,24 +76,42 @@ def visualisation(load_factors, insertion_times, num_resizes, sizes, frequencies
""" """
Visualisation des résultats Visualisation des résultats
""" """
num_elements = []
for factor in load_factors :
num_elements.append(factor*100)
# Temps d'insertion en fonction du facteur de charge # Temps d'insertion en fonction du facteur de charge
plt.plot(load_factors, insertion_times)
plt.xlabel('Facteur de charge')
plt.xticks(load_factors, [str(x) for x in load_factors], rotation=45)
plt.ylabel("Temps d'insertion (secondes)")
plt.title("Temps d'insertion en fonction du facteur de charge")
plt.savefig("temps_d_insertion.png")
# Nombre de réallocations de mémoire en fonction du facteur de charge # Nombre de réallocations de mémoire en fonction du facteur de charge
plt.plot(load_factors, num_resizes)
plt.xlabel('Facteur de charge')
plt.xticks(load_factors, [str(x) for x in load_factors], rotation=45)
plt.ylabel("Nombre de réallocations de mémoire")
plt.title("Nombre de réallocations de mémoire en fonction du facteur de charge")
plt.savefig("nombre_reallocations.png")
# Taille de mémoire occupée en fonction du nombre d'éléments # Taille de mémoire occupée en fonction du nombre d'éléments
plt.plot(sizes, num_elements)
plt.xlabel("Nombre d'éléments")
plt.xticks(num_elements, [str(x) for x in num_elements], rotation=45)
plt.ylabel("Taille de mémoire occupée (octets)")
plt.title("Taille de mémoire occupée en fonction du nombre d'éléments")
plt.savefig("taille_memoire.png")
# Deuxième étude # Deuxième étude
f = list() f = list(frequencies)
plt.figure(figsize=(10, 6)) plt.figure(figsize=(10, 6))
plt.bar(range(len(f)), f) plt.bar(range(len(f)), f)
plt.xlabel('Temps d\'insertion (s)') plt.xlabel('Temps d\'insertion (s)')
plt.ylabel('Fréquence') plt.ylabel('Fréquence')
plt.title('Histogramme des fréquences des temps d\'insertions') plt.title('Histogramme des fréquences des temps d\'insertions')
plt.yscale('log') plt.yscale('log')
xticks = np.logspace(-6, 1, 3) xticks = np.logspace(-6, 1, 3)
xtick_labels = [f'{x:.1e}' for x in xticks] xtick_labels = [f'{x:.1e}' for x in xticks]
plt.xticks(xticks, xtick_labels) plt.xticks(xticks, xtick_labels)
plt.savefig('histogramme.png') plt.savefig('deuxieme_etude.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] 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) insertion_times, num_resizes, sizes = experiment_load_factor(load_factors)
......
...@@ -8,8 +8,7 @@ import random ...@@ -8,8 +8,7 @@ import random
###### PARTIE 1 ###### ###### PARTIE 1 ######
def construction_mphf(set_kmer, n, gamma=2, nb_niveaux=3): def construction_mphf(set_kmer, n, gamma=2, nb_niveaux=3):
"""
"""
Construit une fonction de hachage minimale parfaite (MPHF) pour un ensemble de k-mers. Construit une fonction de hachage minimale parfaite (MPHF) pour un ensemble de k-mers.
Parameters: Parameters:
...@@ -32,76 +31,76 @@ def construction_mphf(set_kmer, n, gamma=2, nb_niveaux=3): ...@@ -32,76 +31,76 @@ def construction_mphf(set_kmer, n, gamma=2, nb_niveaux=3):
>>> len(mphf) == n >>> len(mphf) == n
True True
""" """
# Initialisation # Initialisation
set_kmer_courant = set_kmer.copy() set_kmer_courant = set_kmer.copy()
tableaux = [] tableaux = []
collision = set() collision = set()
for _ in range(nb_niveaux): for _ in range(nb_niveaux):
if len(set_kmer_courant) > 0: if len(set_kmer_courant) > 0:
l = len(set_kmer_courant) l = len(set_kmer_courant)
if l==0 : if l == 0:
break #Evite une division par 0 break # Evite une division par 0
tableau_principal = [-1] * (gamma * l) tableau_principal = [-1] * (gamma * l)
for kmer in set_kmer_courant: for kmer in set_kmer_courant:
# hacher le k-mer (attention, hash() peut rendre des entiers signés, nous voulons des entiers positifs) # hacher le k-mer (attention, hash() peut rendre des entiers signés, nous voulons des entiers positifs)
hachage = abs(hash(kmer)) hachage = abs(hash(kmer))
# récupérer l'adresse # récupérer l'adresse
# si le tableau principal est déjà rempli à l'adresse: # si le tableau principal est déjà rempli à l'adresse:
# mettre le kmer dans collision() # mettre le kmer dans collision()
# sinon, écrire le hash à l'adresse dans le tableau principal # sinon, écrire le hash à l'adresse dans le tableau principal
adresse = hachage % (gamma * l) adresse = hachage % (gamma * l)
if tableau_principal[adresse] != -1: if tableau_principal[adresse] != -1:
collision.add(kmer) collision.add(kmer)
else: else:
tableau_principal[adresse] = hachage tableau_principal[adresse] = hachage
tableaux.append(tableau_principal) # expliquer tableaux.append(tableau_principal) # expliquer
# Chaque niveau de hachage produit un nouveau tableau de hachage. # Chaque niveau de hachage produit un nouveau tableau de hachage.
# Donc on enregistre le tableau dans tableaux pour garder une trace des niveaux. # Donc on enregistre le tableau dans tableaux pour garder une trace des niveaux.
set_kmer_courant = collision.copy() # expliquer set_kmer_courant = collision.copy() # expliquer
# On hache à nouveau les k-mers qui ont causé des collisions. # On hache à nouveau les k-mers qui ont causé des collisions.
collision = set() # expliquer collision = set() # expliquer
# On réinitialise collision pour le prochain niveau de hachage, pour pas que les valeurs dont on n'a plus besoin s'accumulent. # On réinitialise collision pour le prochain niveau de hachage, pour pas que les valeurs dont on n'a plus besoin s'accumulent.
if not set_kmer_courant: # Arrête la boucle si plus de collisions if not set_kmer_courant: # Arrête la boucle si plus de collisions
break break
# Construction de la MPHF # Construction de la MPHF
mphf = [] mphf = []
grand_tableau = [] grand_tableau = []
for tableau in tableaux: for tableau in tableaux:
grand_tableau.extend(tableau) # expliquer grand_tableau.extend(tableau) # expliquer
# Après avoir fait tous les hachages, on regroupe les tableaux finaux de hachage dans un seul tableau. # Après avoir fait tous les hachages, on regroupe les tableaux finaux de hachage dans un seul tableau.
grand_tableau_dict = {val: i for i, val in enumerate(grand_tableau)} grand_tableau_dict = {val: i for i, val in enumerate(grand_tableau)}
max_rang = 0 max_rang = 0
i = 0 i = 0
for kmer in set_kmer: for kmer in set_kmer:
# hacher le kmer # hacher le kmer
hache = abs(hash(kmer)) hache = abs(hash(kmer))
# si le hash est dans le grand_tableau # si le hash est dans le grand_tableau
# récupérer son index # récupérer son index
# récupérer son rang (utiliser la fonction count()) # récupérer son rang (utiliser la fonction count())
# ajouter à la mphf [h, rang] # ajouter à la mphf [h, rang]
# mettre à jour max_rang # mettre à jour max_rang
if hache in grand_tableau_dict : if hache in grand_tableau_dict:
index = grand_tableau_dict[hache] index = grand_tableau_dict[hache]
rang = grand_tableau[:index].count(hache) rang = grand_tableau[:index].count(hache)
mphf.append([hache, rang]) mphf.append([hache, rang])
max_rang = max(max_rang, rang) max_rang = max(max_rang, rang)
for kmer in set_kmer_courant: #gestion des collisions: expliquer les 3 lignes du dessous for kmer in set_kmer_courant: # gestion des collisions: expliquer les 3 lignes du dessous
max_rang += 1 # On attribue un nouveau rang unique à chaque élément en collision. max_rang += 1 # On attribue un nouveau rang unique à chaque élément en collision.
h = abs(hash(kmer)) # Recalcul du hash, on veut uniquement des entiers positifs. h = abs(hash(kmer)) # Recalcul du hash, on veut uniquement des entiers positifs.
mphf.append([h, max_rang]) # On ajoute le k-mer à mphf mphf.append([h, max_rang]) # On ajoute le k-mer à mphf
# On fait ces étapes car les collisions n'ont pas pu être placées avant, # On fait ces étapes car les collisions n'ont pas pu être placées avant,
# on leur attribue un rang plus grand pour ne pas perturber l'ordre précédent # on leur attribue un rang plus grand pour ne pas perturber l'ordre précédent
if not mphf: if not mphf:
print("⚠️ Attention : MPHF vide, vérifiez les données en entrée.") print("Attention : MPHF vide, vérifiez les données en entrée.")
return mphf return mphf
def get_hash_mphf(mphf, kmer): def get_hash_mphf(mphf, kmer):
""" """
Calcule le hash d'un k-mer à l'aide d'une fonction de hachage minimale parfaite (MPHF). Calcule le hash d'un k-mer à l'aide d'une fonction de hachage minimale parfaite (MPHF).
Parameters: Parameters:
...@@ -120,15 +119,15 @@ def get_hash_mphf(mphf, kmer): ...@@ -120,15 +119,15 @@ def get_hash_mphf(mphf, kmer):
>>> 0 <= hash_mphf < n >>> 0 <= hash_mphf < n
True True
""" """
hache = abs(hash(kmer)) hache = abs(hash(kmer))
for h, rang in mphf : for h, rang in mphf:
if h == hache : if h == hache:
return rang return rang
return -1 return -1
def create_hash_table(set_kmer, n): def create_hash_table(set_kmer, n):
""" """
Crée une table de hachage à partir d'un ensemble de k-mers et d'une mphf Crée une table de hachage à partir d'un ensemble de k-mers et d'une mphf
Parameters: Parameters:
...@@ -148,59 +147,61 @@ def create_hash_table(set_kmer, n): ...@@ -148,59 +147,61 @@ def create_hash_table(set_kmer, n):
>>> all(kmer in tableau for kmer in set_kmer) >>> all(kmer in tableau for kmer in set_kmer)
True True
""" """
mphf = construction_mphf(set_kmer, n) # créer la mphf pour les kmers mphf = construction_mphf(set_kmer, n) # créer la mphf pour les kmers
# initialiser un tableau de taille n (une liste) # initialiser un tableau de taille n (une liste)
tableau = [None]*n tableau = [None] * n
# écrire les kmers aux adresses du tableau données par la mphf # écrire les kmers aux adresses du tableau données par la mphf
for kmer in set_kmer : for kmer in set_kmer:
adresse = get_hash_mphf(mphf, kmer) adresse = get_hash_mphf(mphf, kmer)
if adresse == -1: if adresse == -1:
print(f"Erreur : Impossible de trouver l'adresse pour {kmer} (MPHF renvoie -1)") print(f"Erreur : Impossible de trouver l'adresse pour {kmer} (MPHF renvoie -1)")
continue continue
if 0 <= adresse < n: if 0 <= adresse < n:
tableau[adresse]=kmer tableau[adresse] = kmer
return tableau, mphf # retourner le tableau et la mphf return tableau, mphf # retourner le tableau et la mphf
def generer_kmers(n, k): def generer_kmers(n, k):
''' '''
genere un set de n k-mers genere un set de n k-mers
''' '''
kmers = set() kmers = set()
while len(kmers) < n: while len(kmers) < n:
kmer = ''.join(random.choice('ATCG') for _ in range(k)) kmer = ''.join(random.choice('ATCG') for _ in range(k))
kmers.add(kmer) kmers.add(kmer)
return kmers return kmers
def compare_taille(n_max, fichier_sortie): def compare_taille(n_max, fichier_sortie):
n_values = [] n_values = []
table_size = [] table_size = []
dict_size = [] dict_size = []
k = 21 k = 21
for n in range(100, n_max, 1000): for n in range(100, n_max, 1000):
set_kmer = generer_kmers(n, k) set_kmer = generer_kmers(n, k)
tableau, mphf = create_hash_table(set_kmer, n) tableau, mphf = create_hash_table(set_kmer, n)
n_values.append(n) n_values.append(n)
table_size.append(sys.getsizeof(tableau)+sys.getsizeof(mphf)) # pourquoi ici on ne mesure pas juste la taille en mémoire du tableau ? table_size.append(sys.getsizeof(tableau) + sys.getsizeof(
#Car sys.getsizeof(tableau) ne mesure que la liste elle-même, pas les objets stockés dedans. mphf)) # pourquoi ici on ne mesure pas juste la taille en mémoire du tableau ?
# On veut mesurer la mémoire totale du système de hachage, pas seulement la liste. # Car sys.getsizeof(tableau) ne mesure que la liste elle-même, pas les objets stockés dedans.
dict_size.append(sys.getsizeof(set_kmer)) # On veut mesurer la mémoire totale du système de hachage, pas seulement la liste.
dict_size.append(sys.getsizeof(set_kmer))
plt.plot(n_values, table_size, label='Table avec MPHF')
plt.plot(n_values, dict_size, label='Dict') plt.plot(n_values, table_size, label='Table avec MPHF')
plt.xlabel('n') plt.plot(n_values, dict_size, label='Dict')
plt.xticks(n_values, [str(x) for x in n_values], rotation=45) plt.xlabel('n')
plt.ylabel('Taille (octets)') plt.xticks(n_values, [str(x) for x in n_values], rotation=45)
plt.title('Évolution de la taille de la table de hachage avec MPHF et du dict') plt.ylabel('Taille (octets)')
plt.legend() plt.title('Évolution de la taille de la table de hachage avec MPHF et du dict')
plt.savefig(fichier_sortie) plt.legend()
plt.close() plt.savefig(fichier_sortie)
plt.close()
# dé-commenter quand vous êtes prêts, expliquer les résultats # dé-commenter quand vous êtes prêts, expliquer les résultats
compare_taille(10000,"mphf.png") compare_taille(10000, "mphf.png")
# Sur le graphe obtenu, on observe que la taille de la table de hachage du dictionnaire augmente par paliers, # Sur le graphe obtenu, on observe que la taille de la table de hachage du dictionnaire augmente par paliers,
# alors que celle de la MPHF augmente de manière linéaire, et beaucoup plus progressivement. # alors que celle de la MPHF augmente de manière linéaire, et beaucoup plus progressivement.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment