Advertisement
maurol22

huffman

May 16th, 2019
161
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.44 KB | None | 0 0
  1. from operator import itemgetter
  2. from string import ascii_lowercase
  3. from math import isclose
  4. letters = [letter for letter in ascii_lowercase]
  5.  
  6.  
  7. def phase_one(alphabet:list) -> tuple:
  8.     """
  9.    Fase 1 dell'algoritmo: riduce la lista di tuple in un'unica tupla contente tutti gli elementi dell'alfabeto
  10.    Ad ogni passo i due simboli meno probabili vengono fusi insieme
  11.    :param alphabet: lista di tuple relativa alla distribuzione dei simboli
  12.    :return: tupla contenente tutti gli elementi dell'alfabeto
  13.    """
  14.  
  15.     # ordinamento in base alla probabilità
  16.     alphabet.sort(key=itemgetter(1))
  17.  
  18.     while len(alphabet) > 1:
  19.         # dato che la lista è ordinata, i due elementi con probabilità minore sono i primi due
  20.         min_1, min_2 = alphabet[0], alphabet[1]
  21.  
  22.         alphabet.remove(min_1)
  23.         alphabet.remove(min_2)
  24.  
  25.         # si fa in modo che l'eventuale lettera singola viene messa come prima nella tupla
  26.         if isinstance(min_2[0], str) and not isinstance(min_1[0], str):
  27.             newElem = ((min_2[0], min_1[0]), min_1[1] + min_2[1])
  28.         else:
  29.             newElem = ((min_1[0], min_2[0]), min_1[1] + min_2[1])
  30.  
  31.         # aggiunta del nuovo elemento
  32.         alphabet.append(newElem)
  33.         # ordinamento in base alla probabilità
  34.         alphabet.sort(key=itemgetter(1))
  35.  
  36.     return alphabet[0][0]
  37.  
  38. def phase_two(element, li, code) -> None:
  39.     """
  40.    Fase 2 dell'algoritmo di Huffman. Si aggiungono i codici in maniera ricorsiva
  41.    :param element: elemento da codificare
  42.    :param li: lista in cui inserire i simboli con relativa codifica
  43.    :param code: codifica per il simbolo
  44.    """
  45.  
  46.     if isinstance(element, str):
  47.         li.append((element, code))
  48.     else:
  49.         # chiamata sull'elemento sinistro della tupla
  50.         phase_two(element[0], li, code + "0")
  51.         # chiamata sull'elemento destro della tupla
  52.         phase_two(element[1], li, code + "1")
  53.  
  54. def huffman(alphabet) -> list:
  55.     mergedElements = phase_one(alphabet)
  56.     print("Phase one output: " + str(mergedElements))
  57.     li = []
  58.     phase_two(mergedElements, li, "")
  59.     print("Phase two output: " + str(li))
  60.     return li
  61.  
  62. def encoding(string, code):
  63.     encodedStr = ""
  64.     code = dict(code)
  65.  
  66.     for letter in string:
  67.         encodedStr += code[letter]
  68.  
  69.     return encodedStr
  70.  
  71. def prefixFreeDecoding(string, code):
  72.     """
  73.    Decodifica una stringa binaria codificata tramite codice prefix-free
  74.    :param string: stringa binaria da decodifcare
  75.    :param code: codice prefix-free
  76.    :return: messaggio decodificato
  77.    """
  78.  
  79.     codings = [elem[1] for elem in code]
  80.     message = ""
  81.  
  82.     while string != "":
  83.         block = ''
  84.         index = 0
  85.  
  86.         # lettera di un bit alla volta e ci si ferma appena si incontra un blocco di bit presente tra le possibili codifiche. Ciò è possibile perchè il codice è prefix-free
  87.         while block not in codings:
  88.             block += string[index]
  89.             index += 1
  90.  
  91.         # ricerca del blocco di bit nelle tuple
  92.         symbol = [elem for elem in code if block in elem]
  93.         message += symbol[0][0]
  94.         # rimozione del blocco nella stringa
  95.         string = string[len(block):]
  96.  
  97.     return message
  98.  
  99. def main():
  100.  
  101.     # inserimento della distribuzione di probabilità
  102.     distribution = []
  103.     value = float(input("Please insert next value of the distribution or -1 to exit: "))
  104.     while value != -1:
  105.         if value > 0 and value < 1:
  106.             distribution.append(value)
  107.         else:
  108.             print("ERROR: value not inserted. Try another")
  109.  
  110.         value = float(input("Please insert next value of the distribution or -1 to exit: "))
  111.  
  112.     sum = 0
  113.     for elem in distribution:
  114.         sum += elem
  115.  
  116.     if not isclose(sum, 1, rel_tol=1e-6):
  117.         print("ERROR: insert a valid probability distribution (sum : " + str(sum) + ")")
  118.         return
  119.  
  120.  
  121.     alphabet = []
  122.     for i in range(len(distribution)):
  123.         elem = (letters[i], distribution[i])
  124.         alphabet.append(elem)
  125.  
  126.     print("Alphabet: " + str(alphabet))
  127.     alphabet.sort(key=itemgetter(1))
  128.     print("Sorted Alphabet: " + str(alphabet))
  129.  
  130.     code = huffman(alphabet)
  131.  
  132.     string = input("insert a string for encoding/decoding test: ")
  133.     encodedStr = encoding(string, code)
  134.  
  135.     print("encoded string: " + encodedStr)
  136.     message = prefixFreeDecoding(encodedStr, code)
  137.     print("decoded string: " + message)
  138.  
  139. if __name__ == '__main__':
  140.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement