934d26420b36ee33af9bcea995ae682283ad889e
[platform/upstream/libvorbis.git] / vq / vqgen.c
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
5  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
7  *                                                                  *
8  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001             *
9  * by the Xiph.Org Foundation http://www.xiph.org/                  *
10  *                                                                  *
11  ********************************************************************
12
13  function: train a VQ codebook
14
15  ********************************************************************/
16
17 /* This code is *not* part of libvorbis.  It is used to generate
18    trained codebooks offline and then spit the results into a
19    pregenerated codebook that is compiled into libvorbis.  It is an
20    expensive (but good) algorithm.  Run it on big iron. */
21
22 /* There are so many optimizations to explore in *both* stages that
23    considering the undertaking is almost withering.  For now, we brute
24    force it all */
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <math.h>
29 #include <string.h>
30
31 #include "vqgen.h"
32 #include "bookutil.h"
33
34 /* Codebook generation happens in two steps:
35
36    1) Train the codebook with data collected from the encoder: We use
37    one of a few error metrics (which represent the distance between a
38    given data point and a candidate point in the training set) to
39    divide the training set up into cells representing roughly equal
40    probability of occurring.
41
42    2) Generate the codebook and auxiliary data from the trained data set
43 */
44
45 /* Codebook training ****************************************************
46  *
47  * The basic idea here is that a VQ codebook is like an m-dimensional
48  * foam with n bubbles.  The bubbles compete for space/volume and are
49  * 'pressurized' [biased] according to some metric.  The basic alg
50  * iterates through allowing the bubbles to compete for space until
51  * they converge (if the damping is dome properly) on a steady-state
52  * solution. Individual input points, collected from libvorbis, are
53  * used to train the algorithm monte-carlo style.  */
54
55 /* internal helpers *****************************************************/
56 #define vN(data,i) (data+v->elements*i)
57
58 /* default metric; squared 'distance' from desired value. */
59 float _dist(vqgen *v,float *a, float *b){
60   int i;
61   int el=v->elements;
62   float acc=0.f;
63   for(i=0;i<el;i++){
64     float val=(a[i]-b[i]);
65     acc+=val*val;
66   }
67   return sqrt(acc);
68 }
69
70 float *_weight_null(vqgen *v,float *a){
71   return a;
72 }
73
74 /* *must* be beefed up. */
75 void _vqgen_seed(vqgen *v){
76   long i;
77   for(i=0;i<v->entries;i++)
78     memcpy(_now(v,i),_point(v,i),sizeof(float)*v->elements);
79   v->seeded=1;
80 }
81
82 int directdsort(const void *a, const void *b){
83   float av=*((float *)a);
84   float bv=*((float *)b);
85   return (av<bv)-(av>bv);
86 }
87
88 void vqgen_cellmetric(vqgen *v){
89   int j,k;
90   float min=-1.f,max=-1.f,mean=0.f,acc=0.f;
91   long dup=0,unused=0;
92  #ifdef NOISY
93   int i;
94    char buff[80];
95    float spacings[v->entries];
96    int count=0;
97    FILE *cells;
98    sprintf(buff,"cellspace%d.m",v->it);
99    cells=fopen(buff,"w");
100 #endif
101
102   /* minimum, maximum, cell spacing */
103   for(j=0;j<v->entries;j++){
104     float localmin=-1.;
105
106     for(k=0;k<v->entries;k++){
107       if(j!=k){
108         float this=_dist(v,_now(v,j),_now(v,k));
109         if(this>0){
110           if(v->assigned[k] && (localmin==-1 || this<localmin))
111             localmin=this;
112         }else{
113           if(k<j){
114             dup++;
115             break;
116           }
117         }
118       }
119     }
120     if(k<v->entries)continue;
121
122     if(v->assigned[j]==0){
123       unused++;
124       continue;
125     }
126
127     localmin=v->max[j]+localmin/2; /* this gives us rough diameter */
128     if(min==-1 || localmin<min)min=localmin;
129     if(max==-1 || localmin>max)max=localmin;
130     mean+=localmin;
131     acc++;
132 #ifdef NOISY
133     spacings[count++]=localmin;
134 #endif
135   }
136
137   fprintf(stderr,"cell diameter: %.03g::%.03g::%.03g (%ld unused/%ld dup)\n",
138           min,mean/acc,max,unused,dup);
139
140 #ifdef NOISY
141   qsort(spacings,count,sizeof(float),directdsort);
142   for(i=0;i<count;i++)
143     fprintf(cells,"%g\n",spacings[i]);
144   fclose(cells);
145 #endif
146
147 }
148
149 /* External calls *******************************************************/
150
151 /* We have two forms of quantization; in the first, each vector
152    element in the codebook entry is orthogonal.  Residues would use this
153    quantization for example.
154
155    In the second, we have a sequence of monotonically increasing
156    values that we wish to quantize as deltas (to save space).  We
157    still need to quantize so that absolute values are accurate. For
158    example, LSP quantizes all absolute values, but the book encodes
159    distance between values because each successive value is larger
160    than the preceeding value.  Thus the desired quantibits apply to
161    the encoded (delta) values, not abs positions. This requires minor
162    additional encode-side trickery. */
163
164 void vqgen_quantize(vqgen *v,quant_meta *q){
165
166   float maxdel;
167   float mindel;
168
169   float delta;
170   float maxquant=((1<<q->quant)-1);
171
172   int j,k;
173
174   mindel=maxdel=_now(v,0)[0];
175
176   for(j=0;j<v->entries;j++){
177     float last=0.f;
178     for(k=0;k<v->elements;k++){
179       if(mindel>_now(v,j)[k]-last)mindel=_now(v,j)[k]-last;
180       if(maxdel<_now(v,j)[k]-last)maxdel=_now(v,j)[k]-last;
181       if(q->sequencep)last=_now(v,j)[k];
182     }
183   }
184
185
186   /* first find the basic delta amount from the maximum span to be
187      encoded.  Loosen the delta slightly to allow for additional error
188      during sequence quantization */
189
190   delta=(maxdel-mindel)/((1<<q->quant)-1.5f);
191
192   q->min=_float32_pack(mindel);
193   q->delta=_float32_pack(delta);
194
195   mindel=_float32_unpack(q->min);
196   delta=_float32_unpack(q->delta);
197
198   for(j=0;j<v->entries;j++){
199     float last=0;
200     for(k=0;k<v->elements;k++){
201       float val=_now(v,j)[k];
202       float now=rint((val-last-mindel)/delta);
203
204       _now(v,j)[k]=now;
205       if(now<0){
206         /* be paranoid; this should be impossible */
207         fprintf(stderr,"fault; quantized value<0\n");
208         exit(1);
209       }
210
211       if(now>maxquant){
212         /* be paranoid; this should be impossible */
213         fprintf(stderr,"fault; quantized value>max\n");
214         exit(1);
215       }
216       if(q->sequencep)last=(now*delta)+mindel+last;
217     }
218   }
219 }
220
221 /* much easier :-).  Unlike in the codebook, we don't un-log log
222    scales; we just make sure they're properly offset. */
223 void vqgen_unquantize(vqgen *v,quant_meta *q){
224   long j,k;
225   float mindel=_float32_unpack(q->min);
226   float delta=_float32_unpack(q->delta);
227
228   for(j=0;j<v->entries;j++){
229     float last=0.f;
230     for(k=0;k<v->elements;k++){
231       float now=_now(v,j)[k];
232       now=fabs(now)*delta+last+mindel;
233       if(q->sequencep)last=now;
234       _now(v,j)[k]=now;
235     }
236   }
237 }
238
239 void vqgen_init(vqgen *v,int elements,int aux,int entries,float mindist,
240                 float  (*metric)(vqgen *,float *, float *),
241                 float *(*weight)(vqgen *,float *),int centroid){
242   memset(v,0,sizeof(vqgen));
243
244   v->centroid=centroid;
245   v->elements=elements;
246   v->aux=aux;
247   v->mindist=mindist;
248   v->allocated=32768;
249   v->pointlist=_ogg_malloc(v->allocated*(v->elements+v->aux)*sizeof(float));
250
251   v->entries=entries;
252   v->entrylist=_ogg_malloc(v->entries*v->elements*sizeof(float));
253   v->assigned=_ogg_malloc(v->entries*sizeof(long));
254   v->bias=_ogg_calloc(v->entries,sizeof(float));
255   v->max=_ogg_calloc(v->entries,sizeof(float));
256   if(metric)
257     v->metric_func=metric;
258   else
259     v->metric_func=_dist;
260   if(weight)
261     v->weight_func=weight;
262   else
263     v->weight_func=_weight_null;
264
265   v->asciipoints=tmpfile();
266
267 }
268
269 void vqgen_addpoint(vqgen *v, float *p,float *a){
270   int k;
271   for(k=0;k<v->elements;k++)
272     fprintf(v->asciipoints,"%.12g\n",p[k]);
273   for(k=0;k<v->aux;k++)
274     fprintf(v->asciipoints,"%.12g\n",a[k]);
275
276   if(v->points>=v->allocated){
277     v->allocated*=2;
278     v->pointlist=_ogg_realloc(v->pointlist,v->allocated*(v->elements+v->aux)*
279                          sizeof(float));
280   }
281
282   memcpy(_point(v,v->points),p,sizeof(float)*v->elements);
283   if(v->aux)memcpy(_point(v,v->points)+v->elements,a,sizeof(float)*v->aux);
284
285   /* quantize to the density mesh if it's selected */
286   if(v->mindist>0.f){
287     /* quantize to the mesh */
288     for(k=0;k<v->elements+v->aux;k++)
289       _point(v,v->points)[k]=
290         rint(_point(v,v->points)[k]/v->mindist)*v->mindist;
291   }
292   v->points++;
293   if(!(v->points&0xff))spinnit("loading... ",v->points);
294 }
295
296 /* yes, not threadsafe.  These utils aren't */
297 static int sortit=0;
298 static int sortsize=0;
299 static int meshcomp(const void *a,const void *b){
300   if(((sortit++)&0xfff)==0)spinnit("sorting mesh...",sortit);
301   return(memcmp(a,b,sortsize));
302 }
303
304 void vqgen_sortmesh(vqgen *v){
305   sortit=0;
306   if(v->mindist>0.f){
307     long i,march=1;
308
309     /* sort to make uniqueness detection trivial */
310     sortsize=(v->elements+v->aux)*sizeof(float);
311     qsort(v->pointlist,v->points,sortsize,meshcomp);
312
313     /* now march through and eliminate dupes */
314     for(i=1;i<v->points;i++){
315       if(memcmp(_point(v,i),_point(v,i-1),sortsize)){
316         /* a new, unique entry.  march it down */
317         if(i>march)memcpy(_point(v,march),_point(v,i),sortsize);
318         march++;
319       }
320       spinnit("eliminating density... ",v->points-i);
321     }
322
323     /* we're done */
324     fprintf(stderr,"\r%ld training points remining out of %ld"
325             " after density mesh (%ld%%)\n",march,v->points,march*100/v->points);
326     v->points=march;
327
328   }
329   v->sorted=1;
330 }
331
332 float vqgen_iterate(vqgen *v,int biasp){
333   long   i,j,k;
334
335   float fdesired;
336   long  desired;
337   long  desired2;
338
339   float asserror=0.f;
340   float meterror=0.f;
341   float *new;
342   float *new2;
343   long   *nearcount;
344   float *nearbias;
345  #ifdef NOISY
346    char buff[80];
347    FILE *assig;
348    FILE *bias;
349    FILE *cells;
350    sprintf(buff,"cells%d.m",v->it);
351    cells=fopen(buff,"w");
352    sprintf(buff,"assig%d.m",v->it);
353    assig=fopen(buff,"w");
354    sprintf(buff,"bias%d.m",v->it);
355    bias=fopen(buff,"w");
356  #endif
357
358
359   if(v->entries<2){
360     fprintf(stderr,"generation requires at least two entries\n");
361     exit(1);
362   }
363
364   if(!v->sorted)vqgen_sortmesh(v);
365   if(!v->seeded)_vqgen_seed(v);
366
367   fdesired=(float)v->points/v->entries;
368   desired=fdesired;
369   desired2=desired*2;
370   new=_ogg_malloc(sizeof(float)*v->entries*v->elements);
371   new2=_ogg_malloc(sizeof(float)*v->entries*v->elements);
372   nearcount=_ogg_malloc(v->entries*sizeof(long));
373   nearbias=_ogg_malloc(v->entries*desired2*sizeof(float));
374
375   /* fill in nearest points for entry biasing */
376   /*memset(v->bias,0,sizeof(float)*v->entries);*/
377   memset(nearcount,0,sizeof(long)*v->entries);
378   memset(v->assigned,0,sizeof(long)*v->entries);
379   if(biasp){
380     for(i=0;i<v->points;i++){
381       float *ppt=v->weight_func(v,_point(v,i));
382       float firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
383       float secondmetric=v->metric_func(v,_now(v,1),ppt)+v->bias[1];
384       long   firstentry=0;
385       long   secondentry=1;
386
387       if(!(i&0xff))spinnit("biasing... ",v->points+v->points+v->entries-i);
388
389       if(firstmetric>secondmetric){
390         float temp=firstmetric;
391         firstmetric=secondmetric;
392         secondmetric=temp;
393         firstentry=1;
394         secondentry=0;
395       }
396
397       for(j=2;j<v->entries;j++){
398         float thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j];
399         if(thismetric<secondmetric){
400           if(thismetric<firstmetric){
401             secondmetric=firstmetric;
402             secondentry=firstentry;
403             firstmetric=thismetric;
404             firstentry=j;
405           }else{
406             secondmetric=thismetric;
407             secondentry=j;
408           }
409         }
410       }
411
412       j=firstentry;
413       for(j=0;j<v->entries;j++){
414
415         float thismetric,localmetric;
416         float *nearbiasptr=nearbias+desired2*j;
417         long k=nearcount[j];
418
419         localmetric=v->metric_func(v,_now(v,j),ppt);
420         /* 'thismetric' is to be the bias value necessary in the current
421            arrangement for entry j to capture point i */
422         if(firstentry==j){
423           /* use the secondary entry as the threshhold */
424           thismetric=secondmetric-localmetric;
425         }else{
426           /* use the primary entry as the threshhold */
427           thismetric=firstmetric-localmetric;
428         }
429
430         /* support the idea of 'minimum distance'... if we want the
431            cells in a codebook to be roughly some minimum size (as with
432            the low resolution residue books) */
433
434         /* a cute two-stage delayed sorting hack */
435         if(k<desired){
436           nearbiasptr[k]=thismetric;
437           k++;
438           if(k==desired){
439             spinnit("biasing... ",v->points+v->points+v->entries-i);
440             qsort(nearbiasptr,desired,sizeof(float),directdsort);
441           }
442
443         }else if(thismetric>nearbiasptr[desired-1]){
444           nearbiasptr[k]=thismetric;
445           k++;
446           if(k==desired2){
447             spinnit("biasing... ",v->points+v->points+v->entries-i);
448             qsort(nearbiasptr,desired2,sizeof(float),directdsort);
449             k=desired;
450           }
451         }
452         nearcount[j]=k;
453       }
454     }
455
456     /* inflate/deflate */
457
458     for(i=0;i<v->entries;i++){
459       float *nearbiasptr=nearbias+desired2*i;
460
461       spinnit("biasing... ",v->points+v->entries-i);
462
463       /* due to the delayed sorting, we likely need to finish it off....*/
464       if(nearcount[i]>desired)
465         qsort(nearbiasptr,nearcount[i],sizeof(float),directdsort);
466
467       v->bias[i]=nearbiasptr[desired-1];
468
469     }
470   }else{
471     memset(v->bias,0,v->entries*sizeof(float));
472   }
473
474   /* Now assign with new bias and find new midpoints */
475   for(i=0;i<v->points;i++){
476     float *ppt=v->weight_func(v,_point(v,i));
477     float firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
478     long   firstentry=0;
479
480     if(!(i&0xff))spinnit("centering... ",v->points-i);
481
482     for(j=0;j<v->entries;j++){
483       float thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j];
484       if(thismetric<firstmetric){
485         firstmetric=thismetric;
486         firstentry=j;
487       }
488     }
489
490     j=firstentry;
491
492 #ifdef NOISY
493     fprintf(cells,"%g %g\n%g %g\n\n",
494           _now(v,j)[0],_now(v,j)[1],
495           ppt[0],ppt[1]);
496 #endif
497
498     firstmetric-=v->bias[j];
499     meterror+=firstmetric;
500
501     if(v->centroid==0){
502       /* set up midpoints for next iter */
503       if(v->assigned[j]++){
504         for(k=0;k<v->elements;k++)
505           vN(new,j)[k]+=ppt[k];
506         if(firstmetric>v->max[j])v->max[j]=firstmetric;
507       }else{
508         for(k=0;k<v->elements;k++)
509           vN(new,j)[k]=ppt[k];
510         v->max[j]=firstmetric;
511       }
512     }else{
513       /* centroid */
514       if(v->assigned[j]++){
515         for(k=0;k<v->elements;k++){
516           if(vN(new,j)[k]>ppt[k])vN(new,j)[k]=ppt[k];
517           if(vN(new2,j)[k]<ppt[k])vN(new2,j)[k]=ppt[k];
518         }
519         if(firstmetric>v->max[firstentry])v->max[j]=firstmetric;
520       }else{
521         for(k=0;k<v->elements;k++){
522           vN(new,j)[k]=ppt[k];
523           vN(new2,j)[k]=ppt[k];
524         }
525         v->max[firstentry]=firstmetric;
526       }
527     }
528   }
529
530   /* assign midpoints */
531
532   for(j=0;j<v->entries;j++){
533 #ifdef NOISY
534     fprintf(assig,"%ld\n",v->assigned[j]);
535     fprintf(bias,"%g\n",v->bias[j]);
536 #endif
537     asserror+=fabs(v->assigned[j]-fdesired);
538     if(v->assigned[j]){
539       if(v->centroid==0){
540         for(k=0;k<v->elements;k++)
541           _now(v,j)[k]=vN(new,j)[k]/v->assigned[j];
542       }else{
543         for(k=0;k<v->elements;k++)
544           _now(v,j)[k]=(vN(new,j)[k]+vN(new2,j)[k])/2.f;
545       }
546     }
547   }
548
549   asserror/=(v->entries*fdesired);
550
551   fprintf(stderr,"Pass #%d... ",v->it);
552   fprintf(stderr,": dist %g(%g) metric error=%g \n",
553           asserror,fdesired,meterror/v->points);
554   v->it++;
555
556   free(new);
557   free(nearcount);
558   free(nearbias);
559 #ifdef NOISY
560   fclose(assig);
561   fclose(bias);
562   fclose(cells);
563 #endif
564   return(asserror);
565 }
566