-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathCompressionAlgo.hs
61 lines (48 loc) · 2.6 KB
/
CompressionAlgo.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import Data.List
import Data.Function
import Data.Char
import qualified Data.Map as Map
main = print output
output = (==source) $map chr $lzwDecode $lzwEncode $ map ord source
where source = "aaaaa"
------------------------------
-- binary stream encoding
bitsPerInt = 32
bitsEncode bits = length bits:encode bits
where encode [] = []
encode l = (foldl (\v b->v*2+b) 0 $reverse left):encode right
where (left,right) = (take bitsPerInt l, drop bitsPerInt l)
bitsDecode (len:ints) = take len . concat . map (int2Bits 0) $ ints
where int2Bits w 0 = replicate (bitsPerInt - w) 0
int2Bits w x = (x `mod` 2):int2Bits (w + 1) (x `div` 2)
------------------------------
-- huffman encoding
data HuffNode a = HuffLeaf a | HuffBranch (HuffNode a) (HuffNode a) deriving(Show)
huffmanEncode l = (bitsEncode bits, huffTree)
where newl = addHead l
huffTree = buildHuffTree $ sortBy (compare `on` fst) $ map (\(x:xs)->(1+length xs,HuffLeaf x)) $ group $ sort newl
charMap = Map.fromList $ huffTree2AssocList huffTree []
bits = concat $map (\c-> charMap Map.! c) newl
addHead l@(x:xs) | x == maxBound = pred x:l | otherwise = succ x:l
buildHuffTree [(f1,n1)] = n1
buildHuffTree ((f1,n1):(f2,n2):rest) = buildHuffTree (insertBy (compare `on` fst) (f1+f2,HuffBranch n1 n2) rest)
huffTree2AssocList (HuffLeaf c) bits = [(c,reverse bits)]
huffTree2AssocList (HuffBranch n1 n2) bits = huffTree2AssocList n1 (0:bits) ++ huffTree2AssocList n2 (1:bits)
huffmanDecode (encodedBits, huffTree) = drop 1 $ decode huffTree $ bitsDecode encodedBits
where decode (HuffLeaf c) bits = c:decode huffTree bits
decode node [] = []
decode (HuffBranch n1 n2) (0:bits) = decode n1 bits
decode (HuffBranch n1 n2) (1:bits) = decode n2 bits
------------------------------
-- lzw encoding
lzwEncode l = encode l [] $ Map.fromList $ zip [[x]|x<-[0..255]] [0..255]
where encode [] [] table = []
encode [] curr table = [table Map.! curr]
encode (x:xs) curr table
| Map.member (x:curr) table = encode xs (x:curr) table
| otherwise = (table Map.! curr):encode xs [x] (Map.insert (x:curr) (Map.size table) table)
lzwDecode tokens = concat $decode tokens $ Map.fromList $zip [0..255] [[x]|x<-[0..255]]
where decode (id:[]) table = [table Map.! id]
decode (id1:id2:rest) table = curr:decode (id2:rest) newTable
where curr = table Map.! id1
newTable = Map.insert (Map.size table) (curr ++ [(Map.findWithDefault curr id2 table) !! 0]) table