vqgen.c 15 KB

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