diff --git a/report/report.qmd b/report/report.qmd index 82a80503a768454eb5d84d996a5d2c2eeac11c16..0d4ecc7422f0e09b2d36e12810f8cbc7326a8abc 100644 --- a/report/report.qmd +++ b/report/report.qmd @@ -420,4 +420,176 @@ Node(weight=9, Pour le décodage, nous allons appliquer l'algorithme présenté dans le cours n°5. Celui-ci stripule qu'il est nécessaire de parcourir l'arbre au fur et à -mésure jusqu'à retrouver la feuille NYT. À ce moment il est +mésure jusqu'à retrouver la feuille NYT. À ce moment, il est nécessaire de +lire les $e$ bits suivants. Si la valeur de ceux-ci en base 10 est inférieur +à $r$, alors pour obtenir le symbole correspondant il est nécessaire de lire +les $(e + 1)$, de les convertir en base 10 et d'y ajouter 1. La valeur numérique +résultante sera la position dans du symbole dans l'alphabet. Si la valeur de +$e$ est inférieur ou égale à $r$, il faut convertir ces bits en base 10 et d'y +ajouter la valeur $r + 1$. + +Plus concrètement, nous allons en premier lieu nous débarasser des éventuels +espaces dans la chaîne de caractères codées, puis nous allons lire cette chaîne +jusqu'à l'épuisement des bits dans celles-ci. À l'intérieur de la boucle, nous +commencerons par parcourir l'arbre jusqu'à la feuille NYT. Si la valeur du bit +actuel est 0, nous allons bifurquer à gauche, sinon à droite. Ayant recontré +la feuille NYT, nous appliquerons l'algorithme énoncé précédemment pour +déterminer le caractère rencontré. Celui-ci, sera rajouté à la chaîne de +caractère finale et sera aussi insérer dans un `set` afin d'indiquer que ce +caractère fut recontré. Ceci est important du fait que lorsque ce caractère +sera à nouveau rencontré, le parcours de l'arbre ne se fera plus jusqu'à une +feuille NYT et par conséquent le code NYT ne sera plus présent dans la chaîne +décodée. Ce cas est présenté par le branchement conditionnel à la ligne 43. +L'implémentation de cette fonction se trouve ci-dessous : + +```python +def decode(encoded: str) -> (str, str): + bits = encoded.replace(' ', '') + tree = Node() + result = '' + seen = set() + i = 0 + + message_with_nyt: list[str] = [] + message_without_nyt: list[str] = [] + + while i < len(bits): + node = tree + + while node.left or node.right: + if bits[i] == '0': + node = node.left + else: + node = node.right + i += 1 + + if node.value == 'NYT': + e, r = compute_vitter_params(len(LIST_ALPHABET)) + prefix_bits = bits[i:i+e] + val = int(prefix_bits, 2) + + if val < r: + code_bits = bits[i:i+e+1] + k = int(code_bits, 2) + 1 + i += e + 1 + else: + k = val + r + 1 + i += e + + char = LIST_ALPHABET[k - 1] + result += char + seen.add(char) + insert_char(tree, char) + + message_with_nyt.append('NYT') + message_with_nyt.append(char) + message_without_nyt.append(char) + + else: + char = node.value + result += char + insert_char(tree, char) + + message_with_nyt.append(char) + message_without_nyt.append(char) + pprint.pp(tree) + + pprint.pp(tree) + + return ' '.join(message_with_nyt[1:]), ''.join(message_without_nyt) +``` + +### Résultat du décodage + +Pour la chaîne de caractères encodées `Code final: 000011 0 000000 00 01101 100 +00110 1100 10001 10 0 11100 01010 110`, nous allons à nouveau obtenir la +chaîne initiale "darkvador" tout en reconstruisant l'arbre au fur et à mesure +du décodage. + +```bash +Message initial avec NYT : d NYT a NYT r NYT k NYT v a d NYT o r +Message initial sans NYT : darkvador +``` + +L'arbre résultant de ce décodage sera donc le même que celui construit au moment +de l'encodage : + +```bash +Node(weight=9, + nyt_code=None, + value='NYT', + left=Node(weight=2, nyt_code='', value='d', left=None, right=None), + right=Node(weight=7, + nyt_code=None, + value='NYT', + left=Node(weight=2, + nyt_code='0', + value='a', + left=None, + right=None), + right=Node(weight=5, + nyt_code=None, + value='NYT', + left=Node(weight=2, + nyt_code='00', + value='r', + left=None, + right=None), + right=Node(weight=3, + nyt_code=None, + value='NYT', + left=Node(weight=1, + nyt_code='100', + value='k', + left=None, + right=None), + right=Node(weight=2, + nyt_code=None, + value='NYT', + left=Node(weight=1, + nyt_code=None, + value='NYT', + left=Node(weight=0, + nyt_code=None, + value='NYT', + left=None, + right=None), + right=Node(weight=1, + nyt_code='11100', + value='o', + left=None, + right=None)), + right=Node(weight=1, + nyt_code='1100', + value='v', + left=None, + right=None)))))) +``` + +\newpage + +## Utilisation du programme + +Le programme `dyn_huffman.py` est utilisé de la manière suivante : + +- Si l'on souhaite encoder une chaîne de caractère, il est nécessaire de +la préfixer du flag `-e` (pour _encode_) avant de la fournir à la ligne de +commande comme ceci : +```bash +python3 dyn_huffman.py -e "darkvador" +``` +- Inversement, si l'on souhaite décoder une chaîne binaire il est nécessaire +de spécifier le _flag_ `-d``(pour _decode_) +```bash +python3 dyn_huffman.py -d "000011 0 000000 00 01101 100 00110 1100 10001 10 0 \ +11100 01010 110" +``` + +## Résumé du travail + +Ce travail pratique nous a permis de mettre en œuvre l'algorithme d'Huffman +adaptatif pour la compression optimale de chaîne de caractères. C'est avec un +franc succès que nous avons réussi à encoder correctement une chaîne de +caractères fournies en argument au programme grâce à la construction itérative +de l'arbre binaire, puis implémenter le décodage associé afin de retrouver la +chaîne de caractère initiale.