diff --git a/Readme.md b/Readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..c66afd82f9b56ffd28631c8efd87208dd6e36278
--- /dev/null
+++ b/Readme.md
@@ -0,0 +1,67 @@
+# 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.
diff --git a/slides_hash.pdf b/slides_hash.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..14c5b9bfa6eae0bc85a8906f50d9497b415cd48b
Binary files /dev/null and b/slides_hash.pdf differ
diff --git a/tp_2_miso_dict.py b/tp_2_miso_dict.py
new file mode 100644
index 0000000000000000000000000000000000000000..98d2a0c91f569e81c4b9ba67b1cf7bf2a35c8f82
--- /dev/null
+++ b/tp_2_miso_dict.py
@@ -0,0 +1,59 @@
+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)
diff --git a/tp_2_miso_mphf.py b/tp_2_miso_mphf.py
new file mode 100644
index 0000000000000000000000000000000000000000..ebc3d3328dd4c33b1c29a5692f95b319518eb291
--- /dev/null
+++ b/tp_2_miso_mphf.py
@@ -0,0 +1,169 @@
+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")