View difference between Paste ID: QmjR1pSA and aNHCryiY
SHOW: | | - or go back to the newest paste.
1
datatype HuffmanTree =
2
    Node of (string * int) * HuffmanTree * HuffmanTree
3
  | Symbol of char * int;
4
 
5
local
6
    fun unique [] = []
7
    | unique (x::xs) = x:: unique (List.filter (fn y => y<>x) xs);
8
    fun countLetterAux (x:string,a:char,i:int) = if i=size(x) then 0 else (if String.sub(x,i)=a then 1+countLetterAux(x,a,i+1) else countLetterAux(x,a,i+1));
9
    fun countLetter (x:string,a:char) = if size(x)=0 then 0 else countLetterAux(x,a,0);
10
 
11
in  
12
    fun computeHistogram "" = []
13
    |  computeHistogram s = map (fn x => (x,countLetter(s,x))) (unique(explode s))
14
end;
15
 
16
local
17
    local
18
        fun merge _ [] [] = []
19
            | merge _ list [] = list
20
            | merge _ [] list = list
21
            | merge pred (x::xs) (y::ys) = if pred(x,y) then (y::(merge pred (x::xs) ys))
22
                                                      else (x::(merge pred xs (y::ys)))
23
    in
24
        fun mergesort _ [] = []
25
            | mergesort _ [x] = [x]
26
            | mergesort pred l = merge pred
27
                (mergesort pred (List.take (l,((length l) div 2))))
28
                (mergesort pred (List.drop (l,((length l) div 2))))
29
    end;
30
    fun compareTuple ((x:string,n1),(y:string,n2)) = if n1=n2 then y<x else n2<n1
31
    fun compareTuple2 ((x:char,n1),(y:char,n2)) = compareTuple((str(x),n1),(str(y),n2))
32
    fun sortAndConvert lst = map (fn (x,n) => Symbol(x,n)) (mergesort compareTuple2 lst)
33
    fun buildHuffmanTreeAux (Symbol(x,n1)::Symbol(y,n2)::_) = Node(((str(x)^str(y)),(n1+n2)),Symbol(x,n1),Symbol(y,n2))
34
    | buildHuffmanTreeAux (Node((s,n1),T1,T2)::Symbol(y,n2)::_) = if compareTuple((s,n1),(str(y),n2))
35
                          then Node((str(y)^s,n1+n2),Symbol(y,n2),Node((s,n1),T1,T2))
36
                          else Node((s^str(y),n1+n2),Node((s,n1),T1,T2),Symbol(y,n2))
37
    fun buildHuffmanList (x::[]) = x
38
    | buildHuffmanList lst = buildHuffmanList((buildHuffmanTreeAux (List.take(lst,2)))::(List.drop(lst,2)))
39
in
40
    fun buildHuffmanTree lst = buildHuffmanList (sortAndConvert lst)  
41
end;
42
 
43
fun encodeMessage tree s =
44
let
45
    fun LetterEncodingHist (Symbol(x,n),s) = [(x,s)]
46
    | LetterEncodingHist (Node(_,T1,T2),s) = (LetterEncodingHist (T1,s^"0"))@(LetterEncodingHist (T2,s^"1"))
47
    fun LetterEncoding ([],_) = ""
48
    | LetterEncoding ((y,s)::lst,x) = if y=x then s else LetterEncoding (lst,x)
49
    val hist = LetterEncodingHist(tree,"")
50
in
51
    foldr op^ "" (map (fn c => LetterEncoding(hist,c)) (explode s))
52
end;
53
 
54
local
55
    fun decodeMessageAux (Symbol(a,n)) _ [] = str(a)
56
    |   decodeMessageAux (Symbol(a,n)) T2 lst = str(a)^(decodeMessageAux T2 T2 lst)
57
    |   decodeMessageAux (Node((x,n),TL,TR)) T2 lst = if (hd lst) = #"0" then decodeMessageAux TL T2 (tl lst)
58
                                                    else decodeMessageAux TR T2 (tl lst)
59
in
60
    fun decodeMessage tree s = decodeMessageAux tree tree (explode s)
61
end;
62
63
fun encodeTree tree =
64
let
65
	(*convert positive base10 number into binary number*)
66
	fun num2binary_aux(0,false) = "0"
67
    | num2binary_aux(0,true) = ""
68
	| num2binary_aux(n,_) = if (n mod 2) = 0 then num2binary_aux((n div 2),true)^"0"
69
	    else num2binary_aux((n div 2),true)^"1"			
70
	fun num2binary 0 = num2binary_aux(0,false)
71
		| num2binary n = num2binary_aux(n,true) 
72
	(*convert the char into binary number which is the ascii encoding*)	
73
    fun char2binary c = num2binary(ord(c))
74
	(*find the max appearance of a char in huffman tree*)
75
	fun maxAppearance (Symbol(x,n)) = n
76
		| maxAppearance (Node((_,_),Symbol(_,n),_)) = n
77
		| maxAppearance (Node((_,_),_,Symbol(_,n))) = n
78
	(*create histogram of the letter appearances*)
79
	fun LetterEncodingHist (Symbol(x,n)) = [(x,n)]
80
    | LetterEncodingHist (Node(_,T1,T2)) = (LetterEncodingHist T1)@(LetterEncodingHist T2)
81
	(*add Zeros in the start of the list untill the length of the list is equal to the given number*)
82
	fun addZeros(n,lst) = if length(lst) = n then lst else #"0"::addZeros(n-1,lst)
83
	(*calculate the ceiling of log of the number*)
84
	fun log2 0 = 0 | log2 n = 1 + log2(n div 2)    
85
	val max_app = maxAppearance(tree)
86
	(*save the number of bits needed to encode the number of char appearances*)
87
	val max_app_encode = addZeros(5,explode(num2binary(log2(max_app))))
88
	(*encode the first var of the Tuple to it binary which represent the ascii of the char and the appearance of the char to binary*)
89
	fun encode_tuple (x,y) = addZeros(8,explode(char2binary(x))) @ (addZeros(log2(max_app),explode(num2binary(y))))
90
	(* add zeros at the end that the list length will be multiply of 8*)
91
	fun append_to_complete lst = if (length(lst) mod 8) = 0 then lst else append_to_complete(lst@[#"0"]) 	
92
	fun binary_to_num [] _ = 0
93
	    | binary_to_num (x::xs) m = if x = #"1" then (m + (binary_to_num xs (2*m))) else (binary_to_num xs (2*m))
94
	fun encode_list [] _= ""
95
	    | encode_list (x::xs) temp = if length(temp) = 8 then str(chr(binary_to_num temp 1))^(encode_list xs [x]) 
96
	                               else (encode_list xs (temp@[x]))
97
in 
98
	encode_list (append_to_complete(max_app_encode @ (foldr op@ [] (map encode_tuple LetterEncodingHist(tree))))) []
99
end;
100
101
fun decodeHuffmanTree s =
102
let	
103
	fun powerOfTwo 0 = 1
104
	|	powerOfTwo n = 2*(powerOfTwo n-1)
105
	fun NumToBinary (_,~1,lst) = lst (*convert char to binary code list*)
106
	| NumToBinary (0,i,lst) = NumToBinary (0,i-1,lst@[0])
107
	| NumToBinary (n,i,lst) = 
108
	let 
109
		val power = powerOfTwo i
110
	in
111
		if n>=power then NumToBinary(n-power,i-1,lst@[1]) else NumToBinary(n,i-1,lst@[0])
112
	end
113
	fun BinaryToNum (0,lst) = hd lst
114
	| 	BinaryToNum (i,lst) = ((hd lst)*(powerOfTwo i))+BinaryToNum(i-1,tl lst)
115
	
116
	val char_list = explode s 
117
	val BinaryList = foldr op@ [] (map (fn c => NumToBinary(ord(c),7,[])) char_list)
118
	val max_len = BinaryToNum(4,List.take(BinaryList,5))
119
	
120
	fun createPair lst = (chr(BinaryToNum(7,List.take(lst,8))),BinaryToNum(max_len,List.drop(lst,8))) (*creates a pair of (char,int) from a list*)
121
	fun BinaryCodeToHist (lst,hist) = if (length lst)<(8+max_len) then hist (*creates a hist of (char,int) from the binary list*)
122
		else BinaryCodeToHist (List.drop(lst,(8+max_len))) ((createPair List.take(lst,(8+max_len)))::hist)
123
in
124
	buildHuffmanTree (BinaryCodeToHist List.drop(BinaryList,5) [])
125
end;