Updates to Tomato RAF including NGINX && PHP
[tomato.git] / release / src / router / libvorbis / vq / vqsplit.c
blob1fecfa1f454fdd9eec680668bffe6b4da889dd18
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 ********************************************************************
13 function: build a VQ codebook and the encoding decision 'tree'
14 last mod: $Id: vqsplit.c 16037 2009-05-26 21:10:58Z xiphmont $
16 ********************************************************************/
18 /* This code is *not* part of libvorbis. It is used to generate
19 trained codebooks offline and then spit the results into a
20 pregenerated codebook that is compiled into libvorbis. It is an
21 expensive (but good) algorithm. Run it on big iron. */
23 /* There are so many optimizations to explore in *both* stages that
24 considering the undertaking is almost withering. For now, we brute
25 force it all */
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <math.h>
30 #include <string.h>
31 #include <sys/time.h>
33 #include "vqgen.h"
34 #include "vqsplit.h"
35 #include "bookutil.h"
37 /* Codebook generation happens in two steps:
39 1) Train the codebook with data collected from the encoder: We use
40 one of a few error metrics (which represent the distance between a
41 given data point and a candidate point in the training set) to
42 divide the training set up into cells representing roughly equal
43 probability of occurring.
45 2) Generate the codebook and auxiliary data from the trained data set
48 /* Building a codebook from trained set **********************************
50 The codebook in raw form is technically finished once it's trained.
51 However, we want to finalize the representative codebook values for
52 each entry and generate auxiliary information to optimize encoding.
53 We generate the auxiliary coding tree using collected data,
54 probably the same data as in the original training */
56 /* At each recursion, the data set is split in half. Cells with data
57 points on side A go into set A, same with set B. The sets may
58 overlap. If the cell overlaps the deviding line only very slightly
59 (provided parameter), we may choose to ignore the overlap in order
60 to pare the tree down */
62 long *isortvals;
63 int iascsort(const void *a,const void *b){
64 long av=isortvals[*((long *)a)];
65 long bv=isortvals[*((long *)b)];
66 return(av-bv);
69 static float _Ndist(int el,float *a, float *b){
70 int i;
71 float acc=0.f;
72 for(i=0;i<el;i++){
73 float val=(a[i]-b[i]);
74 acc+=val*val;
76 return sqrt(acc);
79 #define _Npoint(i) (pointlist+dim*(i))
80 #define _Nnow(i) (entrylist+dim*(i))
83 /* goes through the split, but just counts it and returns a metric*/
84 int vqsp_count(float *entrylist,float *pointlist,int dim,
85 long *membership,long *reventry,
86 long *entryindex,long entries,
87 long *pointindex,long points,int splitp,
88 long *entryA,long *entryB,
89 long besti,long bestj,
90 long *entriesA,long *entriesB,long *entriesC){
91 long i,j;
92 long A=0,B=0,C=0;
93 long pointsA=0;
94 long pointsB=0;
95 long *temppointsA=NULL;
96 long *temppointsB=NULL;
98 if(splitp){
99 temppointsA=_ogg_malloc(points*sizeof(long));
100 temppointsB=_ogg_malloc(points*sizeof(long));
103 memset(entryA,0,sizeof(long)*entries);
104 memset(entryB,0,sizeof(long)*entries);
106 /* Do the points belonging to this cell occur on sideA, sideB or
107 both? */
109 for(i=0;i<points;i++){
110 float *ppt=_Npoint(pointindex[i]);
111 long firstentry=membership[pointindex[i]];
113 if(firstentry==besti){
114 entryA[reventry[firstentry]]=1;
115 if(splitp)temppointsA[pointsA++]=pointindex[i];
116 continue;
118 if(firstentry==bestj){
119 entryB[reventry[firstentry]]=1;
120 if(splitp)temppointsB[pointsB++]=pointindex[i];
121 continue;
124 float distA=_Ndist(dim,ppt,_Nnow(besti));
125 float distB=_Ndist(dim,ppt,_Nnow(bestj));
126 if(distA<distB){
127 entryA[reventry[firstentry]]=1;
128 if(splitp)temppointsA[pointsA++]=pointindex[i];
129 }else{
130 entryB[reventry[firstentry]]=1;
131 if(splitp)temppointsB[pointsB++]=pointindex[i];
136 /* The entry splitting isn't total, so that storage has to be
137 allocated for recursion. Reuse the entryA/entryB vectors */
138 /* keep the entries in ascending order (relative to the original
139 list); we rely on that stability when ordering p/q choice */
140 for(j=0;j<entries;j++){
141 if(entryA[j] && entryB[j])C++;
142 if(entryA[j])entryA[A++]=entryindex[j];
143 if(entryB[j])entryB[B++]=entryindex[j];
145 *entriesA=A;
146 *entriesB=B;
147 *entriesC=C;
148 if(splitp){
149 memcpy(pointindex,temppointsA,sizeof(long)*pointsA);
150 memcpy(pointindex+pointsA,temppointsB,sizeof(long)*pointsB);
151 free(temppointsA);
152 free(temppointsB);
154 return(pointsA);
157 int lp_split(float *pointlist,long totalpoints,
158 codebook *b,
159 long *entryindex,long entries,
160 long *pointindex,long points,
161 long *membership,long *reventry,
162 long depth, long *pointsofar){
164 encode_aux_nearestmatch *t=b->c->nearest_tree;
166 /* The encoder, regardless of book, will be using a straight
167 euclidian distance-to-point metric to determine closest point.
168 Thus we split the cells using the same (we've already trained the
169 codebook set spacing and distribution using special metrics and
170 even a midpoint division won't disturb the basic properties) */
172 int dim=b->dim;
173 float *entrylist=b->valuelist;
174 long ret;
175 long *entryA=_ogg_calloc(entries,sizeof(long));
176 long *entryB=_ogg_calloc(entries,sizeof(long));
177 long entriesA=0;
178 long entriesB=0;
179 long entriesC=0;
180 long pointsA=0;
181 long i,j,k;
183 long besti=-1;
184 long bestj=-1;
186 char spinbuf[80];
187 sprintf(spinbuf,"splitting [%ld left]... ",totalpoints-*pointsofar);
189 /* one reverse index needed */
190 for(i=0;i<b->entries;i++)reventry[i]=-1;
191 for(i=0;i<entries;i++)reventry[entryindex[i]]=i;
193 /* We need to find the dividing hyperplane. find the median of each
194 axis as the centerpoint and the normal facing farthest point */
196 /* more than one way to do this part. For small sets, we can brute
197 force it. */
199 if(entries<8 || (float)points*entries*entries<16.f*1024*1024){
200 /* try every pair possibility */
201 float best=0;
202 float this;
203 for(i=0;i<entries-1;i++){
204 for(j=i+1;j<entries;j++){
205 spinnit(spinbuf,entries-i);
206 vqsp_count(b->valuelist,pointlist,dim,
207 membership,reventry,
208 entryindex,entries,
209 pointindex,points,0,
210 entryA,entryB,
211 entryindex[i],entryindex[j],
212 &entriesA,&entriesB,&entriesC);
213 this=(entriesA-entriesC)*(entriesB-entriesC);
215 /* when choosing best, we also want some form of stability to
216 make sure more branches are pared later; secondary
217 weighting isn;t needed as the entry lists are in ascending
218 order, and we always try p/q in the same sequence */
220 if( (besti==-1) ||
221 (this>best) ){
223 best=this;
224 besti=entryindex[i];
225 bestj=entryindex[j];
230 }else{
231 float *p=alloca(dim*sizeof(float));
232 float *q=alloca(dim*sizeof(float));
233 float best=0.f;
235 /* try COG/normal and furthest pairs */
236 /* meanpoint */
237 /* eventually, we want to select the closest entry and figure n/c
238 from p/q (because storing n/c is too large */
239 for(k=0;k<dim;k++){
240 spinnit(spinbuf,entries);
242 p[k]=0.f;
243 for(j=0;j<entries;j++)
244 p[k]+=b->valuelist[entryindex[j]*dim+k];
245 p[k]/=entries;
249 /* we go through the entries one by one, looking for the entry on
250 the other side closest to the point of reflection through the
251 center */
253 for(i=0;i<entries;i++){
254 float *ppi=_Nnow(entryindex[i]);
255 float ref_best=0.f;
256 float ref_j=-1;
257 float this;
258 spinnit(spinbuf,entries-i);
260 for(k=0;k<dim;k++)
261 q[k]=2*p[k]-ppi[k];
263 for(j=0;j<entries;j++){
264 if(j!=i){
265 float this=_Ndist(dim,q,_Nnow(entryindex[j]));
266 if(ref_j==-1 || this<=ref_best){ /* <=, not <; very important */
267 ref_best=this;
268 ref_j=entryindex[j];
273 vqsp_count(b->valuelist,pointlist,dim,
274 membership,reventry,
275 entryindex,entries,
276 pointindex,points,0,
277 entryA,entryB,
278 entryindex[i],ref_j,
279 &entriesA,&entriesB,&entriesC);
280 this=(entriesA-entriesC)*(entriesB-entriesC);
282 /* when choosing best, we also want some form of stability to
283 make sure more branches are pared later; secondary
284 weighting isn;t needed as the entry lists are in ascending
285 order, and we always try p/q in the same sequence */
287 if( (besti==-1) ||
288 (this>best) ){
290 best=this;
291 besti=entryindex[i];
292 bestj=ref_j;
296 if(besti>bestj){
297 long temp=besti;
298 besti=bestj;
299 bestj=temp;
304 /* find cells enclosing points */
305 /* count A/B points */
307 pointsA=vqsp_count(b->valuelist,pointlist,dim,
308 membership,reventry,
309 entryindex,entries,
310 pointindex,points,1,
311 entryA,entryB,
312 besti,bestj,
313 &entriesA,&entriesB,&entriesC);
315 /* fprintf(stderr,"split: total=%ld depth=%ld set A=%ld:%ld:%ld=B\n",
316 entries,depth,entriesA-entriesC,entriesC,entriesB-entriesC);*/
318 long thisaux=t->aux++;
319 if(t->aux>=t->alloc){
320 t->alloc*=2;
321 t->ptr0=_ogg_realloc(t->ptr0,sizeof(long)*t->alloc);
322 t->ptr1=_ogg_realloc(t->ptr1,sizeof(long)*t->alloc);
323 t->p=_ogg_realloc(t->p,sizeof(long)*t->alloc);
324 t->q=_ogg_realloc(t->q,sizeof(long)*t->alloc);
327 t->p[thisaux]=besti;
328 t->q[thisaux]=bestj;
330 if(entriesA==1){
331 ret=1;
332 t->ptr0[thisaux]=entryA[0];
333 *pointsofar+=pointsA;
334 }else{
335 t->ptr0[thisaux]= -t->aux;
336 ret=lp_split(pointlist,totalpoints,b,entryA,entriesA,pointindex,pointsA,
337 membership,reventry,depth+1,pointsofar);
339 if(entriesB==1){
340 ret++;
341 t->ptr1[thisaux]=entryB[0];
342 *pointsofar+=points-pointsA;
343 }else{
344 t->ptr1[thisaux]= -t->aux;
345 ret+=lp_split(pointlist,totalpoints,b,entryB,entriesB,pointindex+pointsA,
346 points-pointsA,membership,reventry,
347 depth+1,pointsofar);
350 free(entryA);
351 free(entryB);
352 return(ret);
355 static int _node_eq(encode_aux_nearestmatch *v, long a, long b){
356 long Aptr0=v->ptr0[a];
357 long Aptr1=v->ptr1[a];
358 long Bptr0=v->ptr0[b];
359 long Bptr1=v->ptr1[b];
361 /* the possibility of choosing the same p and q, but switched, can;t
362 happen because we always look for the best p/q in the same search
363 order and the search is stable */
365 if(Aptr0==Bptr0 && Aptr1==Bptr1)
366 return(1);
368 return(0);
371 void vqsp_book(vqgen *v, codebook *b, long *quantlist){
372 long i,j;
373 static_codebook *c=(static_codebook *)b->c;
374 encode_aux_nearestmatch *t;
376 memset(b,0,sizeof(codebook));
377 memset(c,0,sizeof(static_codebook));
378 b->c=c;
379 t=c->nearest_tree=_ogg_calloc(1,sizeof(encode_aux_nearestmatch));
380 c->maptype=2;
382 /* make sure there are no duplicate entries and that every
383 entry has points */
385 for(i=0;i<v->entries;){
386 /* duplicate? if so, eliminate */
387 for(j=0;j<i;j++){
388 if(_Ndist(v->elements,_now(v,i),_now(v,j))==0.f){
389 fprintf(stderr,"found a duplicate entry! removing...\n");
390 v->entries--;
391 memcpy(_now(v,i),_now(v,v->entries),sizeof(float)*v->elements);
392 memcpy(quantlist+i*v->elements,quantlist+v->entries*v->elements,
393 sizeof(long)*v->elements);
394 break;
397 if(j==i)i++;
401 v->assigned=_ogg_calloc(v->entries,sizeof(long));
402 for(i=0;i<v->points;i++){
403 float *ppt=_point(v,i);
404 float firstmetric=_Ndist(v->elements,_now(v,0),ppt);
405 long firstentry=0;
407 if(!(i&0xff))spinnit("checking... ",v->points-i);
409 for(j=0;j<v->entries;j++){
410 float thismetric=_Ndist(v->elements,_now(v,j),ppt);
411 if(thismetric<firstmetric){
412 firstmetric=thismetric;
413 firstentry=j;
417 v->assigned[firstentry]++;
420 for(j=0;j<v->entries;){
421 if(v->assigned[j]==0){
422 fprintf(stderr,"found an unused entry! removing...\n");
423 v->entries--;
424 memcpy(_now(v,j),_now(v,v->entries),sizeof(float)*v->elements);
425 v->assigned[j]=v->assigned[v->elements];
426 memcpy(quantlist+j*v->elements,quantlist+v->entries*v->elements,
427 sizeof(long)*v->elements);
428 continue;
430 j++;
434 fprintf(stderr,"Building a book with %ld unique entries...\n",v->entries);
437 long *entryindex=_ogg_malloc(v->entries*sizeof(long *));
438 long *pointindex=_ogg_malloc(v->points*sizeof(long));
439 long *membership=_ogg_malloc(v->points*sizeof(long));
440 long *reventry=_ogg_malloc(v->entries*sizeof(long));
441 long pointssofar=0;
443 for(i=0;i<v->entries;i++)entryindex[i]=i;
444 for(i=0;i<v->points;i++)pointindex[i]=i;
446 t->alloc=4096;
447 t->ptr0=_ogg_malloc(sizeof(long)*t->alloc);
448 t->ptr1=_ogg_malloc(sizeof(long)*t->alloc);
449 t->p=_ogg_malloc(sizeof(long)*t->alloc);
450 t->q=_ogg_malloc(sizeof(long)*t->alloc);
451 t->aux=0;
452 c->dim=v->elements;
453 c->entries=v->entries;
454 c->lengthlist=_ogg_calloc(c->entries,sizeof(long));
455 b->valuelist=v->entrylist; /* temporary; replaced later */
456 b->dim=c->dim;
457 b->entries=c->entries;
459 for(i=0;i<v->points;i++)membership[i]=-1;
460 for(i=0;i<v->points;i++){
461 float *ppt=_point(v,i);
462 long firstentry=0;
463 float firstmetric=_Ndist(v->elements,_now(v,0),ppt);
465 if(!(i&0xff))spinnit("assigning... ",v->points-i);
467 for(j=1;j<v->entries;j++){
468 if(v->assigned[j]!=-1){
469 float thismetric=_Ndist(v->elements,_now(v,j),ppt);
470 if(thismetric<=firstmetric){
471 firstmetric=thismetric;
472 firstentry=j;
477 membership[i]=firstentry;
480 fprintf(stderr,"Leaves added: %d \n",
481 lp_split(v->pointlist,v->points,
482 b,entryindex,v->entries,
483 pointindex,v->points,
484 membership,reventry,
485 0,&pointssofar));
487 free(pointindex);
488 free(membership);
489 free(reventry);
491 fprintf(stderr,"Paring/rerouting redundant branches... ");
493 /* The tree is likely big and redundant. Pare and reroute branches */
495 int changedflag=1;
497 while(changedflag){
498 changedflag=0;
500 /* span the tree node by node; list unique decision nodes and
501 short circuit redundant branches */
503 for(i=0;i<t->aux;){
504 int k;
506 /* check list of unique decisions */
507 for(j=0;j<i;j++)
508 if(_node_eq(t,i,j))break;
510 if(j<i){
511 /* a redundant entry; find all higher nodes referencing it and
512 short circuit them to the previously noted unique entry */
513 changedflag=1;
514 for(k=0;k<t->aux;k++){
515 if(t->ptr0[k]==-i)t->ptr0[k]=-j;
516 if(t->ptr1[k]==-i)t->ptr1[k]=-j;
519 /* Now, we need to fill in the hole from this redundant
520 entry in the listing. Insert the last entry in the list.
521 Fix the forward pointers to that last entry */
522 t->aux--;
523 t->ptr0[i]=t->ptr0[t->aux];
524 t->ptr1[i]=t->ptr1[t->aux];
525 t->p[i]=t->p[t->aux];
526 t->q[i]=t->q[t->aux];
527 for(k=0;k<t->aux;k++){
528 if(t->ptr0[k]==-t->aux)t->ptr0[k]=-i;
529 if(t->ptr1[k]==-t->aux)t->ptr1[k]=-i;
531 /* hole plugged */
533 }else
534 i++;
537 fprintf(stderr,"\rParing/rerouting redundant branches... "
538 "%ld remaining ",t->aux);
540 fprintf(stderr,"\n");
544 /* run all training points through the decision tree to get a final
545 probability count */
547 long *probability=_ogg_malloc(c->entries*sizeof(long));
548 for(i=0;i<c->entries;i++)probability[i]=1; /* trivial guard */
549 b->dim=c->dim;
551 /* sigh. A necessary hack */
552 for(i=0;i<t->aux;i++)t->p[i]*=c->dim;
553 for(i=0;i<t->aux;i++)t->q[i]*=c->dim;
555 for(i=0;i<v->points;i++){
556 /* we use the linear matcher regardless becuase the trainer
557 doesn't convert log to linear */
558 int ret=_best(b,v->pointlist+i*v->elements,1);
559 probability[ret]++;
560 if(!(i&0xff))spinnit("counting hits... ",v->points-i);
562 for(i=0;i<t->aux;i++)t->p[i]/=c->dim;
563 for(i=0;i<t->aux;i++)t->q[i]/=c->dim;
565 build_tree_from_lengths(c->entries,probability,c->lengthlist);
567 free(probability);
570 /* Sort the entries by codeword length, short to long (eases
571 assignment and packing to do it now) */
573 long *wordlen=c->lengthlist;
574 long *index=_ogg_malloc(c->entries*sizeof(long));
575 long *revindex=_ogg_malloc(c->entries*sizeof(long));
576 int k;
577 for(i=0;i<c->entries;i++)index[i]=i;
578 isortvals=c->lengthlist;
579 qsort(index,c->entries,sizeof(long),iascsort);
581 /* rearrange storage; ptr0/1 first as it needs a reverse index */
582 /* n and c stay unchanged */
583 for(i=0;i<c->entries;i++)revindex[index[i]]=i;
584 for(i=0;i<t->aux;i++){
585 if(!(i&0x3f))spinnit("sorting... ",t->aux-i);
587 if(t->ptr0[i]>=0)t->ptr0[i]=revindex[t->ptr0[i]];
588 if(t->ptr1[i]>=0)t->ptr1[i]=revindex[t->ptr1[i]];
589 t->p[i]=revindex[t->p[i]];
590 t->q[i]=revindex[t->q[i]];
592 free(revindex);
594 /* map lengthlist and vallist with index */
595 c->lengthlist=_ogg_calloc(c->entries,sizeof(long));
596 b->valuelist=_ogg_malloc(sizeof(float)*c->entries*c->dim);
597 c->quantlist=_ogg_malloc(sizeof(long)*c->entries*c->dim);
598 for(i=0;i<c->entries;i++){
599 long e=index[i];
600 for(k=0;k<c->dim;k++){
601 b->valuelist[i*c->dim+k]=v->entrylist[e*c->dim+k];
602 c->quantlist[i*c->dim+k]=quantlist[e*c->dim+k];
604 c->lengthlist[i]=wordlen[e];
607 free(wordlen);
610 fprintf(stderr,"Done. \n\n");