엔트로피 문서의 구현 코드다. if __name__ == "__main__": 아래가 자체 테스트다.
"""허프만 부호 구현과 자체 테스트.
문서: 37.엔트로피
huffman(probs) -> 기호별 부호 길이 목록
가장 작은 확률 둘을 합치는 일을 하나가 남을 때까지 되풀이한다. 합쳐질 때마다 그 안의 기호들의 부호가 한 비트씩 길어진다.
entropy(probs) -> 비트 단위 엔트로피
"""
import heapq
import math
def entropy(probs):
return -sum(p * math.log2(p) for p in probs if p > 0)
def huffman(probs):
if len(probs) == 1:
return [1]
heap = [(p, i, [i]) for i, p in enumerate(probs)]
heapq.heapify(heap)
lengths = [0] * len(probs)
tie = len(probs)
while len(heap) > 1:
p1, _, s1 = heapq.heappop(heap)
p2, _, s2 = heapq.heappop(heap)
for s in s1 + s2:
lengths[s] += 1
heapq.heappush(heap, (p1 + p2, tie, s1 + s2))
tie += 1
return lengths
if __name__ == "__main__":
p = [0.5, 0.25, 0.125, 0.125]
L = huffman(p)
assert sorted(L) == [1, 2, 3, 3] and abs(sum(a * b for a, b in zip(p, L)) - 1.75) < 1e-12
assert abs(entropy(p) - 1.75) < 1e-12
assert sum(2 ** -l for l in L) <= 1 + 1e-12 # 크래프트 부등식
q = [0.9, 0.1]
assert huffman(q) == [1, 1] and abs(entropy(q) - 0.469) < 1e-3
print("impl tests passed")