Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libvcodex/Vchuff/vchsize.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 2003-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Phong Vo <[email protected]> *
18
* *
19
***********************************************************************/
20
#include "vchhdr.h"
21
22
/* Compute the code lengths for symbols based on their frequencies.
23
** This uses a linear-time algorithm after frequency sorting.
24
** Frequencies are scaled to be <= VCH_MAXWEIGHT so that max code
25
** length will be < VCH_MAXLENGTH.
26
**
27
** Written by Kiem-Phong Vo
28
*/
29
30
#define VCH_MAXWEIGHT 2178308.0 /* fibonacci(32)-1 */
31
#define VCH_MAXLENGHTH 32 /* max length of any code */
32
33
/* node in a kind-of-flattened Huffman tree */
34
typedef struct _vchtree_s
35
{ ssize_t freq; /* frequency of a symbol */
36
struct _vchtree_s* next; /* link for the sorted lists */
37
struct _vchtree_s* link; /* subtree linkage */
38
} Vchtree_t;
39
40
/* sort by frequencies */
41
#if __STD_C
42
static int huffcmp(Void_t* one, Void_t* two, Void_t* disc)
43
#else
44
static int huffcmp(one, two, disc)
45
Void_t* one;
46
Void_t* two;
47
Void_t* disc;
48
#endif
49
{
50
int d;
51
Vchtree_t *o = *((Vchtree_t**)one);
52
Vchtree_t *t = *((Vchtree_t**)two);
53
54
if((d = o->freq - t->freq) != 0 )
55
return d;
56
else return o < t ? -1 : o == t ? 0 : 1;
57
}
58
59
#if __STD_C
60
ssize_t vchsize(ssize_t nsym, ssize_t* freq, ssize_t* size, int* runb)
61
#else
62
ssize_t vchsize(nsym, freq, size, runb)
63
ssize_t nsym; /* alphabet size */
64
ssize_t* freq; /* code frequencies */
65
ssize_t* size; /* computed code sizes */
66
int* runb; /* the run byte if any */
67
#endif
68
{
69
ssize_t k, c, notz, max, min;
70
Vchtree_t *tree, **sort;
71
Vchtree_t *f, *s, *p, *list, *tail, *head;
72
73
if(!(tree = (Vchtree_t*)malloc(nsym*sizeof(Vchtree_t))) ||
74
!(sort = (Vchtree_t**)malloc(nsym*sizeof(Vchtree_t*))) )
75
return -1;
76
77
/* construct list of elements with non-zero weights */
78
notz = 0;
79
max = min = freq[c = 0];
80
for(k = 0, f = tree; k < nsym; ++k, ++f, ++c)
81
{ size[c] = 0;
82
83
f->next = f->link = NIL(Vchtree_t*);
84
if((f->freq = freq[c]) == 0 )
85
continue;
86
87
if(min > f->freq)
88
min = f->freq;
89
else if(max < f->freq)
90
max = f->freq;
91
92
sort[notz++] = f;
93
}
94
95
if(runb)
96
*runb = -1;
97
if(notz <= 1) /* no Huffman code needed */
98
{ if(notz == 1 && runb)
99
*runb = (int)(sort[0]-tree);
100
free(tree);
101
free(sort);
102
return 0;
103
}
104
105
/* scale to bound max # of bits for a code */
106
if((max -= min) > VCH_MAXWEIGHT)
107
for(k = 0; k < notz; ++k)
108
sort[k]->freq = (sort[k]->freq - min)*(VCH_MAXWEIGHT/max) + 1;
109
110
/* build linked list sorted by frequencies */
111
vcqsort(sort, notz, sizeof(Vchtree_t*), huffcmp, 0);
112
for(f = sort[k = 0]; f != NIL(Vchtree_t*); f = f->next)
113
{ f->link = f; /* nodes in each subtree are kept in a circular list */
114
f->next = (k += 1) < notz ? sort[k] : NIL(Vchtree_t*);
115
}
116
117
/* linear-time construction of a Huffman tree */
118
for(head = tail = NIL(Vchtree_t*), list = sort[0];; )
119
{ /* The invariant (I) needed at this point is this:
120
** 0. The lists "list" and "head" are sorted by frequency.
121
** 1. list and list->next are not NULL;
122
** 2. head == NULL or head->freq >= list->next->freq
123
** 3. tail == NULL or list->freq+list->next->freq >= tail->freq.
124
** Then, list and list->next can be merged into a subtree.
125
*/
126
f = list; s = list->next; list = s->next;
127
128
/* the difference in depths of s and f will be fixed from now on */
129
size[s-tree] -= size[f-tree];
130
s->next = f; /* final_depth(s) = final_depth(f) + above difference */
131
132
/* tree depth for subtree represented by f increases by 1 */
133
size[f-tree] += 1;
134
135
/* merge subtrees, ie, link the two circular lists */
136
f->freq += s->freq;
137
p = f->link; f->link = s->link; s->link = p;
138
139
/* move f to the list of merged pairs */
140
tail = head ? (tail->next = f) : (head = f);
141
tail->next = NIL(Vchtree_t*);
142
143
if(list)
144
{ if(list->next && list->next->freq <= head->freq)
145
continue; /* invariant (I) satisfied, merge them */
146
147
/* find the segment in "head" movable to start of list */
148
for(p = NIL(Vchtree_t*), f = head; f; p = f, f = f->next)
149
if(f->freq > list->freq)
150
break;
151
152
/* going back to top of loop, so we need invariant (I).
153
** I.0, I.1 and I.2 will clearly be true after below move.
154
** Now observe that tail->freq <= 2*head->freq and
155
** tail->freq <= 2*list->freq. This gives I.3 in all cases.
156
*/
157
if(p)
158
{ p->next = list;
159
list = head;
160
}
161
else
162
{ f = head->next;
163
head->next = list->next;
164
list->next = head;
165
}
166
if(!(head = f) )
167
tail = NIL(Vchtree_t*);
168
}
169
else
170
{ if((list = head)->next == NIL(Vchtree_t*) )
171
break; /* tree completed */
172
head = tail = NIL(Vchtree_t*);
173
}
174
}
175
176
/* turn circular list into forward list, then compute final depths */
177
for(s = NIL(Vchtree_t*), f = list->link; f != list; f = p)
178
{ p = f->link;
179
f->link = s;
180
s = f;
181
}
182
for(c = 0; s; s = s->link)
183
{ if((size[s-tree] += size[s->next-tree]) > c)
184
c = size[s-tree];
185
/**/DEBUG_ASSERT(size[s-tree] > 0 && size[s-tree] <= 32);
186
}
187
188
free(tree);
189
free(sort);
190
191
return c;
192
}
193
194