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

.

parent 90b698b0
No related branches found
No related tags found
No related merge requests found
# TP Hachage
# Partie 1 - Réaliser une fonction de hachage minimale parfaite
On travaillera sur `tp_2_miso_mphf.py`.
Tout d'abord, voyons ensemble l'idée de la construction de la MPHF.
Puis suivez les commentaires dans le code à compléter.
Vous devez
- finaliser la fonction pour construire la MPHF (`construction_mphf`),
- écrire la fonction pour obtenir le hash d'un élément par la MPHF (`get_hash_mphf`),
- écrire la fonction pour créer une table de hachage avec cette mphf (`create_hash_table`)
Ecrivez vos réponses et commentaires dans ce document.
Puis décommenter `compare_taille` à la fin et expliquer les résultats.
Bonus : faites varier `nb_niveaux` et `gamma`, voyez quelle influence ils peuvent avoir.
# Partie 2 - Analyse de performance de dictionnaires en Python
On travaillera sur `tp_2_miso_dict.py`
A la fin de cette partie, en lançant `python tp_2_miso_dict.py` on doit obtenir 4 graphiques.
## Introduction
Nous allons analyser la performance de dictionnaires `dict` en Python en fonction de différents facteurs : que le facteur de charge (loading factor),
le temps d'insertion et la taille de la mémoire occupée. Vous pourrez utiliser matplotlib et numpy pour visualiser les résultats.
## Étude du facteur de charge
Fonction `experiment_load_factor`:
0. La fonction `experiment_load_factor` doit être définie pour prendre en entrée une liste de facteurs de charge (`load_factors`) et renvoyer les temps
- d'insertion de clefs,
- les nombres de réallocations de mémoire (quand le dictionnaire est ré-écrit en mémoire pour agrandir sa taille)
- et les tailles de mémoire occupées par le dictionnaire pour chaque facteur de charge.
1. Initialisation des listes pour stocker les résultats.
Initialiser dans la fonction `experiment_load_factor` des listes `insertion_times`, `num_resizes` et `sizes` seront utilisées pour stocker les trois résultats décrits au dessus.
2. La fonction `experiment_load_factor` doit boucler sur chaque facteur de charge de la liste en entrée `load_factors`. Créer un dictionnaire d'abord vide à chaque fois.
3. Initialiser les variables `num_elements`, `start_time`, `num_resize` et `last_size` pour respectivement mesurer le nombre d'éléments, le temps d'insertion et le nombre de réallocations de mémoire.
4. Insérer les éléments dans le dictionnaire et mesurer le temps d'insertion pour chaque élément, vérifier le nombre de réallocations mémoire (utiliser par exemple `time.time()` et `sys.getsizeof()` pour mesurer le temps et la taille du dictionnaire avant et après chaque insertion).
5. Pour un facteur de charge donné, stocker les résultats dans les listes `insertion_times`, `num_resizes` et `sizes`.
## Deuxième étude
6. A quoi sert la fonction `experiment_longest` ?
## Visualisation des résultats
7. Créez quatre graphiques au format png ou pdf :
- Un graphique du temps d'insertion en fonction du facteur de charge (obtenu question 5)
- Un graphique du nombre de réallocations de mémoire en fonction du facteur de charge (obtenu question 5)
- Un graphique de la taille de mémoire occupée en fonction du nombre d'éléments (obtenu question 5)
- 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.
File added
import matplotlib.pyplot as plt
import numpy as np
import time
import sys
###### PARTIE 2 ######
def experiment_load_factor(load_factors):
"""
Étude du facteur de charge
"""
return [],[],[]
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
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')
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)
frequencies = experiment_longest()
visualisation(load_factors, insertion_times, num_resizes, sizes, frequencies)
import matplotlib.pyplot as plt
import numpy as np
import time
import sys
import random
###### PARTIE 1 ######
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.
Parameters:
set_kmer (set): Ensemble de k-mers.
n (int): Taille de l'ensemble de k-mers.
gamma (int): Facteur de réduction de la taille de la table de hachage. Default: 2.
nb_niveaux (int): Nombre de niveaux de réduction de la taille de la table de hachage. Default: 3.
Returns:
mphf (list): Table de hachage minimale parfaite.
Examples:
>>> set_kmer = {str(i) for i in range(10)}
>>> n = 10
>>> mphf = construction_mphf(set_kmer, n)
>>> len(mphf) == n
True
>>> all(0 <= mphf[i] < n for i in range(n))
True
>>> len(mphf) == n
True
"""
# Initialisation
set_kmer_courant = set_kmer.copy()
tableaux = []
collision = set()
for _ in range(nb_niveaux):
if len(set_kmer_courant) > 0:
l = len(set_kmer_courant)
tableau_principal = [-1] * (gamma * l)
for kmer in set_kmer_courant:
pass # compléter
# hacher le k-mer (attention, hash() peut rendre des entiers signés, nous voulons des entiers positifs)
# récupérer l'adresse
# si le tableau principal est déjà rempli à l'adresse:
# mettre le kmer dans collision()
#sinon, écrire le hash à l'adresse dans le tableau principal
tableaux.append(tableau_principal) # expliquer
set_kmer_courant = collision.copy() # expliquer
collision = set() # expliquer
# Construction de la MPHF
mphf = []
grand_tableau = []
for tableau in tableaux:
grand_tableau.extend(tableau) # expliquer
rangs = []
max_rang = 0
i = 0
for kmer in set_kmer:
pass # compléter:
# hacher le kmer
# si le hash est dans le grand_tableau
# récupérer son index
# récupérer son rang (utiliser la fonction count())
# ajouter à la mphf [h, rang]
# mettre à jour max_rang
for kmer in set_kmer_courant: #gestion des collisions: expliquer les 3 lignes du dessous
max_rang += 1
h = abs(hash(kmer))
mphf.append([h, max_rang])
return mphf
def get_hash_mphf(mphf, kmer):
"""
Calcule le hash d'un k-mer à l'aide d'une fonction de hachage minimale parfaite (MPHF).
Parameters:
mphf (list): Table de hachage minimale parfaite.
kmer (str): K-mer à hasher.
Returns:
int: Hash du k-mer.
Examples:
>>> set_kmer = {str(i) for i in range(10)}
>>> n = 10
>>> mphf = construction_mphf(set_kmer, n)
>>> kmer = "5"
>>> hash_mphf = get_hash_mphf(mphf, kmer)
>>> 0 <= hash_mphf < n
True
"""
pass # TODO modifier
def create_hash_table(set_kmer, n):
"""
Crée une table de hachage à partir d'un ensemble de k-mers et d'une mphf
Parameters:
set_kmer (set): Ensemble de k-mers.
n (int): Taille de la table de hachage.
Returns:
list: Table de hachage créée à partir des k-mers
mphf: la mphf
Examples:
>>> set_kmer = {'ATCG', 'TGCA', 'GCTA'}
>>> n = 10
>>> tableau = create_hash_table(set_kmer, n)
>>> len(tableau) == n
True
>>> all(kmer in tableau for kmer in set_kmer)
True
"""
pass # TODO modifier
# créer la mphf pour les kmers
# initialiser un tableau de taille n (une liste)
# écrire les kmers aux adresses du tableau données par la mphf
# retourner le tableau et la mphf
def generer_kmers(n, k):
'''
genere un set de n k-mers
'''
kmers = set()
while len(kmers) < n:
kmer = ''.join(random.choice('ATCG') for _ in range(k))
kmers.add(kmer)
return kmers
def compare_taille(n_max, fichier_sortie):
n_values = []
table_size = []
dict_size = []
k = 21
for n in range(100, n_max, 1000):
set_kmer = generer_kmers(n, k)
tableau, mphf = create_hash_table(set_kmer,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 ?
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.xlabel('n')
plt.xticks(n_values, [str(x) for x in n_values], rotation=45)
plt.ylabel('Taille (octets)')
plt.title('Évolution de la taille de la table de hachage avec MPHF et du dict')
plt.legend()
plt.savefig(fichier_sortie)
plt.close()
# dé-commenter quand vous êtes prêts, expliquer les résultats
#compare_taille(10000,"mphf.png")
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