1 /********************************************************************
3 * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
5 * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
6 * PLEASE READ THESE TERMS DISTRIBUTING. *
8 * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
9 * by Monty <monty@xiph.org> and The XIPHOPHORUS Company *
10 * http://www.xiph.org/ *
12 ********************************************************************
14 function: train a VQ codebook
15 last mod: $Id: vqgen.c,v 1.30 2000/02/21 01:13:00 xiphmont Exp $
17 ********************************************************************/
19 /* This code is *not* part of libvorbis. It is used to generate
20 trained codebooks offline and then spit the results into a
21 pregenerated codebook that is compiled into libvorbis. It is an
22 expensive (but good) algorithm. Run it on big iron. */
24 /* There are so many optimizations to explore in *both* stages that
25 considering the undertaking is almost withering. For now, we brute
36 /* Codebook generation happens in two steps:
38 1) Train the codebook with data collected from the encoder: We use
39 one of a few error metrics (which represent the distance between a
40 given data point and a candidate point in the training set) to
41 divide the training set up into cells representing roughly equal
42 probability of occurring.
44 2) Generate the codebook and auxiliary data from the trained data set
47 /* Codebook training ****************************************************
49 * The basic idea here is that a VQ codebook is like an m-dimensional
50 * foam with n bubbles. The bubbles compete for space/volume and are
51 * 'pressurized' [biased] according to some metric. The basic alg
52 * iterates through allowing the bubbles to compete for space until
53 * they converge (if the damping is dome properly) on a steady-state
54 * solution. Individual input points, collected from libvorbis, are
55 * used to train the algorithm monte-carlo style. */
57 /* internal helpers *****************************************************/
58 #define vN(data,i) (data+v->elements*i)
60 /* default metric; squared 'distance' from desired value. */
61 double _dist(vqgen *v,double *a, double *b){
66 double val=(a[i]-b[i]);
72 double *_weight_null(vqgen *v,double *a){
76 /* *must* be beefed up. */
77 void _vqgen_seed(vqgen *v){
79 for(i=0;i<v->entries;i++)
80 memcpy(_now(v,i),_point(v,i),sizeof(double)*v->elements);
83 int directdsort(const void *a, const void *b){
84 double av=*((double *)a);
85 double bv=*((double *)b);
90 void vqgen_cellmetric(vqgen *v){
92 double min=-1.,max=-1.,mean=0.,acc=0.;
96 double spacings[v->entries];
99 sprintf(buff,"cellspace%d.m",v->it);
100 cells=fopen(buff,"w");
103 /* minimum, maximum, cell spacing */
104 for(j=0;j<v->entries;j++){
107 for(k=0;k<v->entries;k++){
109 double this=_dist(v,_now(v,j),_now(v,k));
111 if(v->assigned[k] && (localmin==-1 || this<localmin))
121 if(k<v->entries)continue;
123 if(v->assigned[j]==0){
128 localmin=v->max[j]+localmin/2; /* this gives us rough diameter */
129 if(min==-1 || localmin<min)min=localmin;
130 if(max==-1 || localmin>max)max=localmin;
134 spacings[count++]=localmin;
138 fprintf(stderr,"cell diameter: %.03g::%.03g::%.03g (%ld unused/%ld dup)\n",
139 min,mean/acc,max,unused,dup);
142 qsort(spacings,count,sizeof(double),directdsort);
144 fprintf(cells,"%g\n",spacings[i]);
150 /* External calls *******************************************************/
152 /* We have two forms of quantization; in the first, each vector
153 element in the codebook entry is orthogonal. Residues would use this
154 quantization for example.
156 In the second, we have a sequence of monotonically increasing
157 values that we wish to quantize as deltas (to save space). We
158 still need to quantize so that absolute values are accurate. For
159 example, LSP quantizes all absolute values, but the book encodes
160 distance between values because each successive value is larger
161 than the preceeding value. Thus the desired quantibits apply to
162 the encoded (delta) values, not abs positions. This requires minor
163 additional encode-side trickery. */
165 void vqgen_quantize(vqgen *v,quant_meta *q){
171 double maxquant=((1<<q->quant)-1);
175 mindel=maxdel=_now(v,0)[0];
177 for(j=0;j<v->entries;j++){
179 for(k=0;k<v->elements;k++){
180 if(mindel>_now(v,j)[k]-last)mindel=_now(v,j)[k]-last;
181 if(maxdel<_now(v,j)[k]-last)maxdel=_now(v,j)[k]-last;
182 if(q->sequencep)last=_now(v,j)[k];
187 /* first find the basic delta amount from the maximum span to be
188 encoded. Loosen the delta slightly to allow for additional error
189 during sequence quantization */
191 delta=(maxdel-mindel)/((1<<q->quant)-1.5);
193 q->min=float24_pack(mindel);
194 q->delta=float24_pack(delta);
196 for(j=0;j<v->entries;j++){
198 for(k=0;k<v->elements;k++){
199 double val=_now(v,j)[k];
200 double now=rint((val-last-mindel)/delta);
204 /* be paranoid; this should be impossible */
205 fprintf(stderr,"fault; quantized value<0\n");
210 /* be paranoid; this should be impossible */
211 fprintf(stderr,"fault; quantized value>max\n");
214 if(q->sequencep)last=(now*delta)+mindel+last;
219 /* much easier :-) */
220 void vqgen_unquantize(vqgen *v,quant_meta *q){
222 double mindel=float24_unpack(q->min);
223 double delta=float24_unpack(q->delta);
225 for(j=0;j<v->entries;j++){
227 for(k=0;k<v->elements;k++){
228 double now=_now(v,j)[k]*delta+last+mindel;
230 if(q->sequencep)last=now;
236 void vqgen_init(vqgen *v,int elements,int aux,int entries,double mindist,
237 double (*metric)(vqgen *,double *, double *),
238 double *(*weight)(vqgen *,double *)){
239 memset(v,0,sizeof(vqgen));
241 v->elements=elements;
245 v->pointlist=malloc(v->allocated*(v->elements+v->aux)*sizeof(double));
248 v->entrylist=malloc(v->entries*v->elements*sizeof(double));
249 v->assigned=malloc(v->entries*sizeof(long));
250 v->bias=calloc(v->entries,sizeof(double));
251 v->max=calloc(v->entries,sizeof(double));
253 v->metric_func=metric;
255 v->metric_func=_dist;
257 v->weight_func=weight;
259 v->weight_func=_weight_null;
263 void vqgen_addpoint(vqgen *v, double *p,double *a){
264 if(v->points>=v->allocated){
266 v->pointlist=realloc(v->pointlist,v->allocated*(v->elements+v->aux)*
270 memcpy(_point(v,v->points),p,sizeof(double)*v->elements);
271 if(v->aux)memcpy(_point(v,v->points)+v->elements,a,sizeof(double)*v->aux);
273 if(v->points==v->entries)_vqgen_seed(v);
274 if(!(v->points&0xff))spinnit("loading... ",v->points);
277 double vqgen_iterate(vqgen *v){
281 double fdesired=(double)v->points/v->entries;
282 long desired=fdesired;
283 long desired2=desired*2;
287 double *new=malloc(sizeof(double)*v->entries*v->elements);
288 long *nearcount=malloc(v->entries*sizeof(long));
289 double *nearbias=malloc(v->entries*desired2*sizeof(double));
295 sprintf(buff,"cells%d.m",v->it);
296 cells=fopen(buff,"w");
297 sprintf(buff,"assig%d.m",v->it);
298 assig=fopen(buff,"w");
299 sprintf(buff,"bias%d.m",v->it);
300 bias=fopen(buff,"w");
305 fprintf(stderr,"generation requires at least two entries\n");
309 /* fill in nearest points for entry biasing */
310 /*memset(v->bias,0,sizeof(double)*v->entries);*/
311 memset(nearcount,0,sizeof(long)*v->entries);
312 memset(v->assigned,0,sizeof(long)*v->entries);
314 for(i=0;i<v->points;i++){
315 double *ppt=v->weight_func(v,_point(v,i));
316 double firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
317 double secondmetric=v->metric_func(v,_now(v,1),ppt)+v->bias[1];
322 if(!(i&0xff))spinnit("biasing... ",v->points+v->points+v->entries-i);
324 if(firstmetric>secondmetric){
325 double temp=firstmetric;
326 firstmetric=secondmetric;
332 for(j=2;j<v->entries;j++){
333 double thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j];
334 if(thismetric<secondmetric){
335 if(thismetric<firstmetric){
336 secondmetric=firstmetric;
337 secondentry=firstentry;
338 firstmetric=thismetric;
341 secondmetric=thismetric;
348 for(j=0;j<v->entries;j++){
350 double thismetric,localmetric;
351 double *nearbiasptr=nearbias+desired2*j;
354 localmetric=v->metric_func(v,_now(v,j),ppt);
355 /* 'thismetric' is to be the bias value necessary in the current
356 arrangement for entry j to capture point i */
358 /* use the secondary entry as the threshhold */
359 thismetric=secondmetric-localmetric;
361 /* use the primary entry as the threshhold */
362 thismetric=firstmetric-localmetric;
365 /* support the idea of 'minimum distance'... if we want the
366 cells in a codebook to be roughly some minimum size (as with
367 the low resolution residue books) */
369 if(localmetric>=v->mindist){
371 /* a cute two-stage delayed sorting hack */
373 nearbiasptr[k]=thismetric;
376 spinnit("biasing... ",v->points+v->points+v->entries-i);
377 qsort(nearbiasptr,desired,sizeof(double),directdsort);
380 }else if(thismetric>nearbiasptr[desired-1]){
381 nearbiasptr[k]=thismetric;
384 spinnit("biasing... ",v->points+v->points+v->entries-i);
385 qsort(nearbiasptr,desired2,sizeof(double),directdsort);
396 /* inflate/deflate */
398 for(i=0;i<v->entries;i++){
399 double *nearbiasptr=nearbias+desired2*i;
401 spinnit("biasing... ",v->points+v->entries-i);
403 /* due to the delayed sorting, we likely need to finish it off....*/
404 if(nearcount[i]>desired)
405 qsort(nearbiasptr,nearcount[i],sizeof(double),directdsort);
407 /* desired is the *maximum* bias queue size. If we're using
408 minimum distance, we're not interested in the max size... we're
409 interested in the biasable number of points */
411 long localdesired=(double)biasable/v->entries;
413 v->bias[i]=nearbiasptr[localdesired-1];
415 v->bias[i]=nearbiasptr[0];
419 /* Now assign with new bias and find new midpoints */
420 for(i=0;i<v->points;i++){
421 double *ppt=v->weight_func(v,_point(v,i));
422 double firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
425 if(!(i&0xff))spinnit("centering... ",v->points-i);
427 for(j=0;j<v->entries;j++){
428 double thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j];
429 if(thismetric<firstmetric){
430 firstmetric=thismetric;
438 fprintf(cells,"%g %g\n%g %g\n\n",
439 _now(v,j)[0],_now(v,j)[1],
443 firstmetric-=v->bias[firstentry];
444 meterror+=firstmetric;
445 /* set up midpoints for next iter */
446 if(v->assigned[j]++){
447 for(k=0;k<v->elements;k++)
448 vN(new,j)[k]+=ppt[k];
449 if(firstmetric>v->max[firstentry])v->max[firstentry]=firstmetric;
451 for(k=0;k<v->elements;k++)
453 v->max[firstentry]=firstmetric;
457 /* assign midpoints */
459 for(j=0;j<v->entries;j++){
461 fprintf(assig,"%ld\n",v->assigned[j]);
462 fprintf(bias,"%g\n",v->bias[j]);
464 asserror+=fabs(v->assigned[j]-fdesired);
466 for(k=0;k<v->elements;k++)
467 _now(v,j)[k]=vN(new,j)[k]/v->assigned[j];
470 asserror/=(v->entries*fdesired);
472 fprintf(stderr,"Pass #%d... ",v->it);
473 fprintf(stderr,": dist %g(%g) metric error=%g \n",
474 asserror,fdesired,meterror/v->points);