Haskell을 사용한 Huffman 코드 기반 데이터 압축 유틸리티 개발
(lazamar.github.io)Huffman 코딩을 사용한 데이터 압축 프로그램 구현
- 
Huffman 코드란?
- 각 문자를 고유한 비트 시퀀스로 매핑하여 데이터 압축을 수행함
 - 자주 등장하는 문자는 짧은 비트 시퀀스로, 드물게 등장하는 문자는 긴 비트 시퀀스로 매핑함
 - 예: 문자열 
aaab의 경우,a는1,b는0으로 매핑되어1110으로 압축됨 
 
접두사 없는 코드
- 
접두사 없는 코드란?
- 어떤 코드 단어도 다른 코드 단어의 접두사가 되지 않도록 함
 - 예: 
aaabc의 경우,a는1,b는00,c는01로 매핑되어1110001로 압축됨 
 
접두사 없는 코드 생성
- 
접두사 없는 코드 생성 방법
- 모든 문자를 완전 이진 트리의 잎으로 배치
 - 왼쪽 가지는 
1, 오른쪽 가지는0으로 라벨링 - 루트에서 잎까지의 경로가 각 문자의 코드 단어를 설명함
 
 
코더 작성
- 
타입 정의
- 
Bit,Code,FreqMap,CodeMap,Weight,HTree타입 정의 - 
HTree는Leaf와Fork로 구성됨 
 - 
 - 
인코딩 함수
- 문자열을 비트로 변환하는 함수
 - 
FreqMap을 사용하여 각 문자의 빈도를 계산하고, 이를 기반으로 Huffman 트리를 생성함 - Huffman 트리에서 각 문자의 코드 단어를 생성함
 
 - 
디코딩 함수
- 비트를 원래 문자열로 변환하는 함수
 - Huffman 트리를 사용하여 비트를 순차적으로 디코딩함
 
 
바이너리 파일과의 연동
- 
바이너리 데이터 인코딩
- 
Data.ByteString.Char8모듈을 사용하여 바이트를 문자로 읽음 - 텍스트 코더를 사용하여 바이너리 데이터를 인코딩함
 
 - 
 
직렬화
- 
직렬화 함수
- 
FreqMap과 비트를 실제 바이트로 변환하여 파일에 저장함 - 
Put모나드를 사용하여 효율적으로ByteString을 생성함 
 - 
 
역직렬화
- 
역직렬화 함수
- 파일에서 읽은 데이터를 
FreqMap과 비트로 변환함 - 
Get모나드를 사용하여FreqMap을 역직렬화함 
 - 파일에서 읽은 데이터를 
 
전체 코드 통합
- 
파일 압축 및 해제 함수
- 
compress함수: 파일을 읽어 빈도 맵을 생성하고, 데이터를 인코딩하여 압축 파일로 저장함 - 
decompress함수: 압축 파일을 읽어 데이터를 디코딩하여 원래 파일로 저장함 
 - 
 
개선 사항
- 
멀티스레딩
- 파일의 섹션을 병렬로 디코딩함
 - 섹션 경계와 예상 디코딩 크기를 지정하는 테이블을 추가하여 병렬 처리를 가능하게 함
 
 - 
단일 패스 인코딩
- 빈도 맵을 실시간으로 생성하며 인코딩함
 - 파일 시작 부분에 빈도 맵을 포함할 필요가 없음
 
 - 
정규 Huffman 코드
- 트리를 탐색하는 대신 벡터를 인덱싱하여 
O(1)시간 복잡도로 디코딩함 
 - 트리를 탐색하는 대신 벡터를 인덱싱하여 
 - 
더 빠른 코드 생성
- 단일 패스 인코딩을 시도할 경우, 코드맵 생성 속도를 높여야 함
 
 
GN⁺의 의견
- 
Huffman 코딩의 장점
- 자주 등장하는 문자를 짧은 비트 시퀀스로 매핑하여 효율적인 데이터 압축을 가능하게 함
 - 메모리 사용을 최소화하면서도 큰 데이터를 처리할 수 있음
 
 - 
Haskell의 장점
- 함수형 프로그래밍의 장점을 활용하여 모듈화된 코드를 작성할 수 있음
 - 게으른 평가를 통해 메모리 사용을 최적화할 수 있음
 
 - 
비슷한 기능을 가진 프로젝트
- gzip, bzip2 등 다양한 데이터 압축 도구가 존재함
 - 각 도구의 장단점을 비교하여 적절한 도구를 선택하는 것이 중요함
 
 - 
새로운 기술 도입 시 고려 사항
- 성능과 메모리 사용량을 고려하여 적절한 알고리듬을 선택해야 함
 - 단일 패스 인코딩과 같은 최적화 기법을 적용하여 효율성을 높일 수 있음
 
 
Hacker News 의견
- 
배열 기반의 인플레이스 알고리즘이 존재하여 트리를 할당하고 포인터를 추적할 필요가 줄어듦
- 대학에서 트리 기반 접근 방식을 배울 때 다른 방법이 있는지 몰랐음
 - 트리 접근 방식이 직관적이고 유익하지만, 많은 데이터를 빠르게 처리해야 할 때는 인플레이스 배열을 사용하는 것이 더 합리적임
 - 참고 문헌: "In-Place Calculation of Minimum-Redundancy Codes" (Moffat, Katajainen, 1995)
 
 - 
코드 단어가 다른 코드 단어의 접두사가 되지 않도록 해야 한다는 것은 기술적으로 정확하지 않음
- 유일하게 디코딩 가능한 코드 클래스는 접두사 코드의 상위 집합임
 - 예를 들어, 접두사 코드의 역순은 여전히 명확하게 디코딩 가능함
 - 예시 코드:
a 1 b 00 c 10 - 'a'의 코드가 'c'의 코드의 접두사이지만, 역순으로 처리하면 명확하게 디코딩 가능함
 
 - 
Haskell 프로그램 작성에 대한 더 고급 기능(모나드 변환기, 렌즈 등)을 다루는 유사한 튜토리얼이 있는지 궁금함
 - 
Coursera의 함수형 프로그래밍 코스(Scala)에서 유사한 Huffman 코딩 과제를 제공함
 - 
Huffman 코드를 사용하여 MICMAC 프로세서 매크로 프로그램을 최소한의 마이크로사이클과 마이크로명령으로 실행했음
- 매크로 명령어의 히스토그램을 작성하고, 이를 기반으로 프로그레시브 디코딩 마이크로코드 프로그램을 작성했음
 - 실제로는 느리고 불편했을 것임
 - Huffman 코드의 장점은 값의 분포에 따라 접두사 깊이를 조절할 수 있다는 것임
 - 비초과파이프라인 프로세서 모델에서 분기 예측을 처리해야 했음
 
 - 
Huffman 코딩에 대한 추가 정보: Rosetta Code Huffman Coding
 - 
Haskell 프로그래머를 위한 질문: 최적화된 코드를 작성하려는 프로그래머에게 Haskell의 성능은 어떤지 궁금함
- 특히 행렬 연산과 SIMD를 활용하는 수치 계산 성능에 관심이 있음
 
 - 
공유해줘서 고맙다는 의견
 - 
"Creating prefix-free codes" 섹션의 표에 오타가 있음
- D는 '0010'이어야 함 (현재는 '0110'으로 잘못 표기됨)
 - 그 외에는 훌륭한 읽을거리였음
 
 - 
산술 코드는 거의 모든 면에서 더 나음
- 더 적은 RAM과 코드로 구현 가능함
 - 더 나은 압축 및 디컴프레션 비율을 제공함
 - 스트림 중에 다른 기호가 나타날 확률을 동적으로 업데이트하기 더 쉬움
 - Huffman 코드는 먼저 발명되었고 산술 코드는 특허가 있었기 때문에 사용됨
 - 현재 특허가 만료되었으므로 더 나은 설계를 사용해야 함