Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • samuel.nguyen.etu/tp2_hachage
1 result
Select Git revision
Show changes
Commits on Source (2)
# Default ignored files
/shelf/
/workspace.xml
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="LanguageDetectionInspection" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>
\ No newline at end of file
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/tp2_hachage.iml" filepath="$PROJECT_DIR$/.idea/tp2_hachage.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="NUMPY" />
<option name="myDocStringFormat" value="NumPy" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
mphf.png

33.5 KiB

...@@ -7,10 +7,26 @@ import sys ...@@ -7,10 +7,26 @@ import sys
###### PARTIE 2 ###### ###### PARTIE 2 ######
def experiment_load_factor(load_factors): def experiment_load_factor(load_factors : list):
""" """
Étude du facteur de charge Étude du facteur de charge
Parameters
----------
load_factors : list
Une liste de facteurs de charge
Returns
-------
lists
Les temps d'insertion de clefs
Les nombres de réallocations de mémoire
Les tailles de mémoire occupée par le dictionnaire pour chaque facteur de charge
""" """
insertion_times = []
num_resizes = []
sizes = []
for factor in load_factors :
dictio = {}
# num_elements = .......... QUESTION 2 PARTIE 2
return [],[],[] return [],[],[]
def experiment_longest(): def experiment_longest():
......
...@@ -39,17 +39,17 @@ def construction_mphf(set_kmer, n, gamma=2, nb_niveaux=3): ...@@ -39,17 +39,17 @@ def construction_mphf(set_kmer, n, gamma=2, nb_niveaux=3):
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 :
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 = hash(kmer) hachage = abs(hash(kmer))
if hachage < 0:
hachage = -1 * hachage
# 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:
...@@ -61,7 +61,8 @@ def construction_mphf(set_kmer, n, gamma=2, nb_niveaux=3): ...@@ -61,7 +61,8 @@ def construction_mphf(set_kmer, n, gamma=2, nb_niveaux=3):
# 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
break
# Construction de la MPHF # Construction de la MPHF
mphf = [] mphf = []
...@@ -69,24 +70,23 @@ def construction_mphf(set_kmer, n, gamma=2, nb_niveaux=3): ...@@ -69,24 +70,23 @@ def construction_mphf(set_kmer, n, gamma=2, nb_niveaux=3):
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)}
rangs = []
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 = 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 : if hache in grand_tableau_dict :
index = grand_tableau.index(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])
if rang > max_rang : max_rang = max(max_rang, rang)
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.
...@@ -94,7 +94,9 @@ def construction_mphf(set_kmer, n, gamma=2, nb_niveaux=3): ...@@ -94,7 +94,9 @@ def construction_mphf(set_kmer, n, gamma=2, nb_niveaux=3):
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:
print("⚠️ Attention : MPHF vide, vérifiez les données en entrée.")
return mphf return mphf
...@@ -122,38 +124,42 @@ def get_hash_mphf(mphf, kmer): ...@@ -122,38 +124,42 @@ def get_hash_mphf(mphf, kmer):
for h, rang in mphf : for h, rang in mphf :
if h == hache : if h == hache :
return rang return rang
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:
set_kmer (set): Ensemble de k-mers. set_kmer (set): Ensemble de k-mers.
n (int): Taille de la table de hachage. n (int): Taille de la table de hachage.
Returns: Returns:
list: Table de hachage créée à partir des k-mers list: Table de hachage créée à partir des k-mers
mphf: la mphf mphf: la mphf
Examples: Examples:
>>> set_kmer = {'ATCG', 'TGCA', 'GCTA'} >>> set_kmer = {'ATCG', 'TGCA', 'GCTA'}
>>> n = 10 >>> n = 10
>>> tableau = create_hash_table(set_kmer, n) >>> tableau = create_hash_table(set_kmer, n)
>>> len(tableau) == n >>> len(tableau) == n
True True
>>> 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 0 <= adresse < n: if adresse == -1:
tableau[adresse]=kmer print(f"Erreur : Impossible de trouver l'adresse pour {kmer} (MPHF renvoie -1)")
return tableau, mphf # retourner le tableau et la mphf continue
if 0 <= adresse < n:
tableau[adresse]=kmer
return tableau, mphf # retourner le tableau et la mphf
def generer_kmers(n, k): def generer_kmers(n, k):
...@@ -178,7 +184,9 @@ def compare_taille(n_max, fichier_sortie): ...@@ -178,7 +184,9 @@ def compare_taille(n_max, fichier_sortie):
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(mphf)) # pourquoi ici on ne mesure pas juste la taille en mémoire du tableau ?
#Car sys.getsizeof(tableau) ne mesure que la liste elle-même, pas les objets stockés dedans.
# On veut mesurer la mémoire totale du système de hachage, pas seulement la liste.
dict_size.append(sys.getsizeof(set_kmer)) dict_size.append(sys.getsizeof(set_kmer))
plt.plot(n_values, table_size, label='Table avec MPHF') plt.plot(n_values, table_size, label='Table avec MPHF')
...@@ -193,3 +201,9 @@ def compare_taille(n_max, fichier_sortie): ...@@ -193,3 +201,9 @@ def compare_taille(n_max, fichier_sortie):
# 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,
# alors que celle de la MPHF augmente de manière linéaire, et beaucoup plus progressivement.
# Cela est cohérent, en effet le dictionnaire va allouer plus d'espace dès que le nombre d'éléments atteint un seuil.
# Quant à la MPHF, elle minimise la mémoire en évitant les collisions.