Just another update

This commit is contained in:
Ingy döt Net 2015-02-20 00:35:01 -05:00
parent a25938f123
commit 00a190b0a6
6591 changed files with 94363 additions and 23227 deletions

View file

@ -0,0 +1,85 @@
huffman_encoding_table = (counts) ->
# counts is a hash where keys are characters and
# values are frequencies;
# return a hash where keys are codes and values
# are characters
build_huffman_tree = ->
# returns a Huffman tree. Each node has
# cnt: total frequency of all chars in subtree
# c: character to be encoded (leafs only)
# children: children nodes (branches only)
q = min_queue()
for c, cnt of counts
q.enqueue cnt,
cnt: cnt
c: c
while q.size() >= 2
a = q.dequeue()
b = q.dequeue()
cnt = a.cnt + b.cnt
node =
cnt: cnt
children: [a, b]
q.enqueue cnt, node
root = q.dequeue()
root = build_huffman_tree()
codes = {}
encode = (node, code) ->
if node.c?
codes[code] = node.c
else
encode node.children[0], code + "0"
encode node.children[1], code + "1"
encode(root, "")
codes
min_queue = ->
# This is very non-optimized; you could use a binary heap for better
# performance. Items with smaller priority get dequeued first.
arr = []
enqueue: (priority, data) ->
i = 0
while i < arr.length
if priority < arr[i].priority
break
i += 1
arr.splice i, 0,
priority: priority
data: data
dequeue: ->
arr.shift().data
size: -> arr.length
_internal: ->
arr
freq_count = (s) ->
cnts = {}
for c in s
cnts[c] ?= 0
cnts[c] += 1
cnts
rpad = (s, n) ->
while s.length < n
s += ' '
s
examples = [
"this is an example for huffman encoding"
"abcd"
"abbccccddddddddeeeeeeeee"
]
for s in examples
console.log "---- #{s}"
counts = freq_count(s)
huffman_table = huffman_encoding_table(counts)
codes = (code for code of huffman_table).sort()
for code in codes
c = huffman_table[code]
console.log "#{rpad(code, 5)}: #{c} (#{counts[c]})"
console.log()

View file

@ -1,21 +1,21 @@
import std.stdio, std.algorithm, std.typecons, std.container,std.array;
import std.stdio, std.algorithm, std.typecons, std.container, std.array;
auto encode(T)(Group!("a == b", T[]) sf) {
auto encode(alias eq, R)(Group!(eq, R) sf) /*pure nothrow @safe*/ {
auto heap = sf.map!(s => tuple(s[1], [tuple(s[0], "")]))
.array.heapify!q{b < a};
while (heap.length > 1) {
auto lo = heap.front; heap.removeFront;
auto hi = heap.front; heap.removeFront;
foreach (ref pair; lo[1]) pair[1] = '0' ~ pair[1];
foreach (ref pair; hi[1]) pair[1] = '1' ~ pair[1];
lo[1].each!((ref pair) => pair[1] = '0' ~ pair[1]);
hi[1].each!((ref pair) => pair[1] = '1' ~ pair[1]);
heap.insert(tuple(lo[0] + hi[0], lo[1] ~ hi[1]));
}
return heap.front[1].schwartzSort!q{tuple(a[1].length, a[0])};
return heap.front[1].schwartzSort!q{ tuple(a[1].length, a[0]) };
}
void main() {
auto s = "this is an example for huffman encoding"d;
foreach (p; s.dup.sort().release.group.encode)
void main() /*@safe*/ {
immutable s = "this is an example for huffman encoding"d;
foreach (const p; s.dup.sort().group.encode)
writefln("'%s' %s", p[]);
}

View file

@ -0,0 +1,188 @@
class HUFFMAN_NODE[T -> COMPARABLE]
inherit
COMPARABLE
redefine
three_way_comparison
end
create
leaf_node, inner_node
feature {NONE}
leaf_node (a_probability: REAL_64; a_value: T)
do
probability := a_probability
value := a_value
is_leaf := true
left := void
right := void
parent := void
end
inner_node (a_left, a_right: HUFFMAN_NODE[T])
do
left := a_left
right := a_right
a_left.parent := Current
a_right.parent := Current
a_left.is_zero := true
a_right.is_zero := false
probability := a_left.probability + a_right.probability
is_leaf := false
end
feature
probability: REAL_64
value: detachable T
is_leaf: BOOLEAN
is_zero: BOOLEAN assign set_is_zero
set_is_zero (a_value: BOOLEAN)
do
is_zero := a_value
end
left: detachable HUFFMAN_NODE[T]
right: detachable HUFFMAN_NODE[T]
parent: detachable HUFFMAN_NODE[T] assign set_parent
set_parent (a_parent: detachable HUFFMAN_NODE[T])
do
parent := a_parent
end
is_root: BOOLEAN
do
Result := parent = void
end
bit_value: INTEGER
do
if is_zero then
Result := 0
else
Result := 1
end
end
feature -- comparable implementation
is_less alias "<" (other: like Current): BOOLEAN
do
Result := three_way_comparison (other) = -1
end
three_way_comparison (other: like Current): INTEGER
do
Result := -probability.three_way_comparison (other.probability)
end
end
class HUFFMAN
create
make
feature {NONE}
make(a_string: STRING)
require
non_empty_string: a_string.count > 0
local
l_queue: HEAP_PRIORITY_QUEUE[HUFFMAN_NODE[CHARACTER]]
l_counts: HASH_TABLE[INTEGER, CHARACTER]
l_node: HUFFMAN_NODE[CHARACTER]
l_left, l_right: HUFFMAN_NODE[CHARACTER]
do
create l_queue.make (a_string.count)
create l_counts.make (10)
across a_string as char
loop
if not l_counts.has (char.item) then
l_counts.put (0, char.item)
end
l_counts.replace (l_counts.at (char.item) + 1, char.item)
end
create leaf_dictionary.make(l_counts.count)
across l_counts as kv
loop
create l_node.leaf_node ((kv.item * 1.0) / a_string.count, kv.key)
l_queue.put (l_node)
leaf_dictionary.put (l_node, kv.key)
end
from
until
l_queue.count <= 1
loop
l_left := l_queue.item
l_queue.remove
l_right := l_queue.item
l_queue.remove
create l_node.inner_node (l_left, l_right)
l_queue.put (l_node)
end
root := l_queue.item
root.is_zero := false
end
feature
root: HUFFMAN_NODE[CHARACTER]
leaf_dictionary: HASH_TABLE[HUFFMAN_NODE[CHARACTER], CHARACTER]
encode(a_value: CHARACTER): STRING
require
encodable: leaf_dictionary.has (a_value)
local
l_node: HUFFMAN_NODE[CHARACTER]
do
Result := ""
if attached leaf_dictionary.item (a_value) as attached_node then
l_node := attached_node
from
until
l_node.is_root
loop
Result.append_integer (l_node.bit_value)
if attached l_node.parent as parent then
l_node := parent
end
end
Result.mirror
end
end
end
class
APPLICATION
create
make
feature {NONE}
make -- entry point
local
l_str: STRING
huff: HUFFMAN
chars: BINARY_SEARCH_TREE_SET[CHARACTER]
do
l_str := "this is an example for huffman encoding"
create huff.make (l_str)
create chars.make
chars.fill (l_str)
from
chars.start
until
chars.off
loop
print (chars.item.out + ": " + huff.encode (chars.item) + "%N")
chars.forth
end
end
end

View file

@ -0,0 +1,50 @@
import groovy.transform.*
@Canonical
@Sortable(includes = ['freq', 'letter'])
class Node {
String letter
int freq
Node left
Node right
boolean isLeaf() { left == null && right == null }
}
Map correspondance(Node n, Map corresp = [:], String prefix = '') {
if (n.isLeaf()) {
corresp[n.letter] = prefix ?: '0'
} else {
correspondance(n.left, corresp, prefix + '0')
correspondance(n.right, corresp, prefix + '1')
}
return corresp
}
Map huffmanCode(String message) {
def queue = message.toList().countBy { it } // char frequencies
.collect { String letter, int freq -> // transformed into tree nodes
new Node(letter, freq)
} as TreeSet // put in a queue that maintains ordering
while(queue.size() > 1) {
def (nodeLeft, nodeRight) = [queue.pollFirst(), queue.pollFirst()]
queue << new Node(
freq: nodeLeft.freq + nodeRight.freq,
letter: nodeLeft.letter + nodeRight.letter,
left: nodeLeft, right: nodeRight
)
}
return correspondance(queue.pollFirst())
}
String encode(CharSequence msg, Map codeTable) {
msg.collect { codeTable[it] }.join()
}
String decode(String codedMsg, Map codeTable, String decoded = '') {
def pair = codeTable.find { k, v -> codedMsg.startsWith(v) }
pair ? pair.key + decode(codedMsg.substring(pair.value.size()), codeTable)
: decoded
}

View file

@ -0,0 +1,10 @@
def message = "this is an example for huffman encoding"
def codeTable = huffmanCode(message)
codeTable.each { k, v -> println "$k: $v" }
def encoded = encode(message, codeTable)
println encoded
def decoded = decode(encoded, codeTable)
println decoded

View file

@ -0,0 +1,13 @@
huffman[s_String] := huffman[Characters[s]];
huffman[l_List] := Module[{merge, structure, rules},
(*merge front two branches. list is assumed to be sorted*)
merge[k_] := Replace[k, {{a_, aC_}, {b_, bC_}, rest___} :> {{{a, b}, aC + bC}, rest}];
structure = FixedPoint[
Composition[merge, SortBy[#, Last] &],
Tally[l]][[1, 1]];
rules = (# -> Flatten[Position[structure, #] - 1]) & /@ DeleteDuplicates[l];
{Flatten[l /. rules], rules}];

View file

@ -4,13 +4,13 @@
@interface HuffmanTree : NSObject {
int freq;
}
-(id)initWithFreq:(int)f;
-(instancetype)initWithFreq:(int)f;
@property (nonatomic, readonly) int freq;
@end
@implementation HuffmanTree
@synthesize freq; // the frequency of this tree
-(id)initWithFreq:(int)f {
-(instancetype)initWithFreq:(int)f {
if (self = [super init]) {
freq = f;
}
@ -41,12 +41,12 @@ CFComparisonResult HuffmanCompare(const void *ptr1, const void *ptr2, void *unus
char value; // the character this leaf represents
}
@property (readonly) char value;
-(id)initWithFreq:(int)f character:(char)c;
-(instancetype)initWithFreq:(int)f character:(char)c;
@end
@implementation HuffmanLeaf
@synthesize value;
-(id)initWithFreq:(int)f character:(char)c {
-(instancetype)initWithFreq:(int)f character:(char)c {
if (self = [super initWithFreq:f]) {
value = c;
}
@ -59,12 +59,12 @@ CFComparisonResult HuffmanCompare(const void *ptr1, const void *ptr2, void *unus
HuffmanTree *left, *right; // subtrees
}
@property (readonly) HuffmanTree *left, *right;
-(id)initWithLeft:(HuffmanTree *)l right:(HuffmanTree *)r;
-(instancetype)initWithLeft:(HuffmanTree *)l right:(HuffmanTree *)r;
@end
@implementation HuffmanNode
@synthesize left, right;
-(id)initWithLeft:(HuffmanTree *)l right:(HuffmanTree *)r {
-(instancetype)initWithLeft:(HuffmanTree *)l right:(HuffmanTree *)r {
if (self = [super initWithFreq:l.freq+r.freq]) {
left = l;
right = r;

View file

@ -0,0 +1,57 @@
use 5.10.0;
use strict;
# produce encode and decode dictionary from a tree
sub walk {
my ($node, $code, $h, $rev_h) = @_;
my $c = $node->[0];
if (ref $c) { walk($c->[$_], $code.$_, $h, $rev_h) for 0,1 }
else { $h->{$c} = $code; $rev_h->{$code} = $c }
$h, $rev_h
}
# make a tree, and return resulting dictionaries
sub mktree {
my (%freq, @nodes);
$freq{$_}++ for split '', shift;
@nodes = map([$_, $freq{$_}], keys %freq);
do { # poor man's priority queue
@nodes = sort {$a->[1] <=> $b->[1]} @nodes;
my ($x, $y) = splice @nodes, 0, 2;
push @nodes, [[$x, $y], $x->[1] + $y->[1]]
} while (@nodes > 1);
walk($nodes[0], '', {}, {})
}
sub encode {
my ($str, $dict) = @_;
join '', map $dict->{$_}//die("bad char $_"), split '', $str
}
sub decode {
my ($str, $dict) = @_;
my ($seg, @out) = ("");
# append to current segment until it's in the dictionary
for (split '', $str) {
$seg .= $_;
my $x = $dict->{$seg} // next;
push @out, $x;
$seg = '';
}
die "bad code" if length($seg);
join '', @out
}
my $txt = 'this is an example for huffman encoding';
my ($h, $rev_h) = mktree($txt);
for (keys %$h) { print "'$_': $h->{$_}\n" }
my $enc = encode($txt, $h);
print "$enc\n";
print decode($enc, $rev_h), "\n";

View file

@ -0,0 +1,54 @@
(define (char-freq port table)
(if
(eof-object? (peek-char port))
table
(char-freq port (add-char (read-char port) table))))
(define (add-char char table)
(cond
((null? table) (list (list char 1)))
((eq? (caar table) char) (cons (list char (+ (cadar table) 1)) (cdr table)))
(#t (cons (car table) (add-char char (cdr table))))))
(define (nodeify table)
(map (lambda (x) (list x '() '())) table))
(define node-freq cadar)
(define (huffman-tree nodes)
(let ((queue (sort nodes (lambda (x y) (< (node-freq x) (node-freq y))))))
(if
(null? (cdr queue))
(car queue)
(huffman-tree
(cons
(list
(list 'notleaf (+ (node-freq (car queue)) (node-freq (cadr queue))))
(car queue)
(cadr queue))
(cddr queue))))))
(define (list-encodings tree chars)
(for-each (lambda (c) (format #t "~a:~a~%" c (encode c tree))) chars))
(define (encode char tree)
(cond
((null? tree) #f)
((eq? (caar tree) char) '())
(#t
(let ((left (encode char (cadr tree))) (right (encode char (caddr tree))))
(cond
((not (or left right)) #f)
(left (cons #\1 left))
(right (cons #\0 right)))))))
(define (decode digits tree)
(cond
((not (eq? (caar tree) 'notleaf)) (caar tree))
((eq? (car digits) #\0) (decode (cdr digits) (cadr tree)))
(#t (decode (cdr digits) (caddr tree)))))
(define input "this is an example for huffman encoding")
(define freq-table (char-freq (open-input-string input) '()))
(define tree (huffman-tree (nodeify freq-table)))
(list-encodings tree (map car freq-table))