vqgen.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /********************************************************************
  2. * *
  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. *
  7. * *
  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/ *
  11. * *
  12. ********************************************************************
  13. function: train a VQ codebook
  14. last mod: $Id: vqgen.c,v 1.30.4.4 2000/05/06 05:41:14 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. double _dist(vqgen *v,double *a, double *b){
  51. int i;
  52. int el=v->elements;
  53. double acc=0.;
  54. for(i=0;i<el;i++){
  55. double val=(a[i]-b[i]);
  56. acc+=val*val;
  57. }
  58. return sqrt(acc);
  59. }
  60. double *_weight_null(vqgen *v,double *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(double)*v->elements);
  68. }
  69. int directdsort(const void *a, const void *b){
  70. double av=*((double *)a);
  71. double bv=*((double *)b);
  72. if(av>bv)return(-1);
  73. return(1);
  74. }
  75. void vqgen_cellmetric(vqgen *v){
  76. int j,k;
  77. double min=-1.,max=-1.,mean=0.,acc=0.;
  78. long dup=0,unused=0;
  79. #ifdef NOISY
  80. int i;
  81. char buff[80];
  82. double spacings[v->entries];
  83. int count=0;
  84. FILE *cells;
  85. sprintf(buff,"cellspace%d.m",v->it);
  86. cells=fopen(buff,"w");
  87. #endif
  88. /* minimum, maximum, cell spacing */
  89. for(j=0;j<v->entries;j++){
  90. double localmin=-1.;
  91. for(k=0;k<v->entries;k++){
  92. if(j!=k){
  93. double this=_dist(v,_now(v,j),_now(v,k));
  94. if(this>0){
  95. if(v->assigned[k] && (localmin==-1 || this<localmin))
  96. localmin=this;
  97. }else{
  98. if(k<j){
  99. dup++;
  100. break;
  101. }
  102. }
  103. }
  104. }
  105. if(k<v->entries)continue;
  106. if(v->assigned[j]==0){
  107. unused++;
  108. continue;
  109. }
  110. localmin=v->max[j]+localmin/2; /* this gives us rough diameter */
  111. if(min==-1 || localmin<min)min=localmin;
  112. if(max==-1 || localmin>max)max=localmin;
  113. mean+=localmin;
  114. acc++;
  115. #ifdef NOISY
  116. spacings[count++]=localmin;
  117. #endif
  118. }
  119. fprintf(stderr,"cell diameter: %.03g::%.03g::%.03g (%ld unused/%ld dup)\n",
  120. min,mean/acc,max,unused,dup);
  121. #ifdef NOISY
  122. qsort(spacings,count,sizeof(double),directdsort);
  123. for(i=0;i<count;i++)
  124. fprintf(cells,"%g\n",spacings[i]);
  125. fclose(cells);
  126. #endif
  127. }
  128. /* External calls *******************************************************/
  129. /* We have two forms of quantization; in the first, each vector
  130. element in the codebook entry is orthogonal. Residues would use this
  131. quantization for example.
  132. In the second, we have a sequence of monotonically increasing
  133. values that we wish to quantize as deltas (to save space). We
  134. still need to quantize so that absolute values are accurate. For
  135. example, LSP quantizes all absolute values, but the book encodes
  136. distance between values because each successive value is larger
  137. than the preceeding value. Thus the desired quantibits apply to
  138. the encoded (delta) values, not abs positions. This requires minor
  139. additional encode-side trickery. */
  140. void vqgen_quantize(vqgen *v,quant_meta *q){
  141. double maxdel;
  142. double mindel;
  143. double delta;
  144. double maxquant=((1<<q->quant)-1);
  145. int j,k;
  146. mindel=maxdel=_now(v,0)[0];
  147. for(j=0;j<v->entries;j++){
  148. double last=0.;
  149. for(k=0;k<v->elements;k++){
  150. if(mindel>_now(v,j)[k]-last)mindel=_now(v,j)[k]-last;
  151. if(maxdel<_now(v,j)[k]-last)maxdel=_now(v,j)[k]-last;
  152. if(q->sequencep)last=_now(v,j)[k];
  153. }
  154. }
  155. /* first find the basic delta amount from the maximum span to be
  156. encoded. Loosen the delta slightly to allow for additional error
  157. during sequence quantization */
  158. delta=(maxdel-mindel)/((1<<q->quant)-1.5);
  159. q->min=_float32_pack(mindel);
  160. q->delta=_float32_pack(delta);
  161. mindel=_float32_unpack(q->min);
  162. delta=_float32_unpack(q->delta);
  163. for(j=0;j<v->entries;j++){
  164. double last=0;
  165. for(k=0;k<v->elements;k++){
  166. double val=_now(v,j)[k];
  167. double now=rint((val-last-mindel)/delta);
  168. _now(v,j)[k]=now;
  169. if(now<0){
  170. /* be paranoid; this should be impossible */
  171. fprintf(stderr,"fault; quantized value<0\n");
  172. exit(1);
  173. }
  174. if(now>maxquant){
  175. /* be paranoid; this should be impossible */
  176. fprintf(stderr,"fault; quantized value>max\n");
  177. exit(1);
  178. }
  179. if(q->sequencep)last=(now*delta)+mindel+last;
  180. }
  181. }
  182. }
  183. /* much easier :-). Unlike in the codebook, we don't un-log log
  184. scales; we just make sure they're properly offset. */
  185. void vqgen_unquantize(vqgen *v,quant_meta *q){
  186. long j,k;
  187. double mindel=_float32_unpack(q->min);
  188. double delta=_float32_unpack(q->delta);
  189. for(j=0;j<v->entries;j++){
  190. double last=0.;
  191. for(k=0;k<v->elements;k++){
  192. double now=_now(v,j)[k];
  193. now=fabs(now)*delta+last+mindel;
  194. if(q->sequencep)last=now;
  195. _now(v,j)[k]=now;
  196. }
  197. }
  198. }
  199. void vqgen_init(vqgen *v,int elements,int aux,int entries,double mindist,
  200. double (*metric)(vqgen *,double *, double *),
  201. double *(*weight)(vqgen *,double *)){
  202. memset(v,0,sizeof(vqgen));
  203. v->elements=elements;
  204. v->aux=aux;
  205. v->mindist=mindist;
  206. v->allocated=32768;
  207. v->pointlist=malloc(v->allocated*(v->elements+v->aux)*sizeof(double));
  208. v->entries=entries;
  209. v->entrylist=malloc(v->entries*v->elements*sizeof(double));
  210. v->assigned=malloc(v->entries*sizeof(long));
  211. v->bias=calloc(v->entries,sizeof(double));
  212. v->max=calloc(v->entries,sizeof(double));
  213. if(metric)
  214. v->metric_func=metric;
  215. else
  216. v->metric_func=_dist;
  217. if(weight)
  218. v->weight_func=weight;
  219. else
  220. v->weight_func=_weight_null;
  221. }
  222. void vqgen_addpoint(vqgen *v, double *p,double *a){
  223. if(v->points>=v->allocated){
  224. v->allocated*=2;
  225. v->pointlist=realloc(v->pointlist,v->allocated*(v->elements+v->aux)*
  226. sizeof(double));
  227. }
  228. memcpy(_point(v,v->points),p,sizeof(double)*v->elements);
  229. if(v->aux)memcpy(_point(v,v->points)+v->elements,a,sizeof(double)*v->aux);
  230. v->points++;
  231. if(v->points==v->entries)_vqgen_seed(v);
  232. if(!(v->points&0xff))spinnit("loading... ",v->points);
  233. }
  234. double vqgen_iterate(vqgen *v,int biasp){
  235. long i,j,k;
  236. long biasable;
  237. double fdesired=(double)v->points/v->entries;
  238. long desired=fdesired;
  239. long desired2=desired*2;
  240. double asserror=0.;
  241. double meterror=0.;
  242. double *new=malloc(sizeof(double)*v->entries*v->elements);
  243. long *nearcount=malloc(v->entries*sizeof(long));
  244. double *nearbias=malloc(v->entries*desired2*sizeof(double));
  245. #ifdef NOISY
  246. char buff[80];
  247. FILE *assig;
  248. FILE *bias;
  249. FILE *cells;
  250. sprintf(buff,"cells%d.m",v->it);
  251. cells=fopen(buff,"w");
  252. sprintf(buff,"assig%d.m",v->it);
  253. assig=fopen(buff,"w");
  254. sprintf(buff,"bias%d.m",v->it);
  255. bias=fopen(buff,"w");
  256. #endif
  257. if(v->entries<2){
  258. fprintf(stderr,"generation requires at least two entries\n");
  259. exit(1);
  260. }
  261. /* fill in nearest points for entry biasing */
  262. /*memset(v->bias,0,sizeof(double)*v->entries);*/
  263. memset(nearcount,0,sizeof(long)*v->entries);
  264. memset(v->assigned,0,sizeof(long)*v->entries);
  265. biasable=0;
  266. if(biasp){
  267. for(i=0;i<v->points;i++){
  268. double *ppt=v->weight_func(v,_point(v,i));
  269. double firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
  270. double secondmetric=v->metric_func(v,_now(v,1),ppt)+v->bias[1];
  271. long firstentry=0;
  272. long secondentry=1;
  273. int biasflag=1;
  274. if(!(i&0xff))spinnit("biasing... ",v->points+v->points+v->entries-i);
  275. if(firstmetric>secondmetric){
  276. double temp=firstmetric;
  277. firstmetric=secondmetric;
  278. secondmetric=temp;
  279. firstentry=1;
  280. secondentry=0;
  281. }
  282. for(j=2;j<v->entries;j++){
  283. double thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j];
  284. if(thismetric<secondmetric){
  285. if(thismetric<firstmetric){
  286. secondmetric=firstmetric;
  287. secondentry=firstentry;
  288. firstmetric=thismetric;
  289. firstentry=j;
  290. }else{
  291. secondmetric=thismetric;
  292. secondentry=j;
  293. }
  294. }
  295. }
  296. j=firstentry;
  297. for(j=0;j<v->entries;j++){
  298. double thismetric,localmetric;
  299. double *nearbiasptr=nearbias+desired2*j;
  300. long k=nearcount[j];
  301. localmetric=v->metric_func(v,_now(v,j),ppt);
  302. /* 'thismetric' is to be the bias value necessary in the current
  303. arrangement for entry j to capture point i */
  304. if(firstentry==j){
  305. /* use the secondary entry as the threshhold */
  306. thismetric=secondmetric-localmetric;
  307. }else{
  308. /* use the primary entry as the threshhold */
  309. thismetric=firstmetric-localmetric;
  310. }
  311. /* support the idea of 'minimum distance'... if we want the
  312. cells in a codebook to be roughly some minimum size (as with
  313. the low resolution residue books) */
  314. if(localmetric>=v->mindist){
  315. /* a cute two-stage delayed sorting hack */
  316. if(k<desired){
  317. nearbiasptr[k]=thismetric;
  318. k++;
  319. if(k==desired){
  320. spinnit("biasing... ",v->points+v->points+v->entries-i);
  321. qsort(nearbiasptr,desired,sizeof(double),directdsort);
  322. }
  323. }else if(thismetric>nearbiasptr[desired-1]){
  324. nearbiasptr[k]=thismetric;
  325. k++;
  326. if(k==desired2){
  327. spinnit("biasing... ",v->points+v->points+v->entries-i);
  328. qsort(nearbiasptr,desired2,sizeof(double),directdsort);
  329. k=desired;
  330. }
  331. }
  332. nearcount[j]=k;
  333. }else
  334. biasflag=0;
  335. }
  336. biasable+=biasflag;
  337. }
  338. /* inflate/deflate */
  339. for(i=0;i<v->entries;i++){
  340. double *nearbiasptr=nearbias+desired2*i;
  341. spinnit("biasing... ",v->points+v->entries-i);
  342. /* due to the delayed sorting, we likely need to finish it off....*/
  343. if(nearcount[i]>desired)
  344. qsort(nearbiasptr,nearcount[i],sizeof(double),directdsort);
  345. /* desired is the *maximum* bias queue size. If we're using
  346. minimum distance, we're not interested in the max size... we're
  347. interested in the biasable number of points */
  348. {
  349. long localdesired=(double)biasable/v->entries;
  350. if(localdesired)
  351. v->bias[i]=nearbiasptr[localdesired-1];
  352. else
  353. v->bias[i]=nearbiasptr[0];
  354. }
  355. }
  356. }else{
  357. memset(v->bias,0,v->entries*sizeof(double));
  358. }
  359. /* Now assign with new bias and find new midpoints */
  360. for(i=0;i<v->points;i++){
  361. double *ppt=v->weight_func(v,_point(v,i));
  362. double firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
  363. long firstentry=0;
  364. if(!(i&0xff))spinnit("centering... ",v->points-i);
  365. for(j=0;j<v->entries;j++){
  366. double thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j];
  367. if(thismetric<firstmetric){
  368. firstmetric=thismetric;
  369. firstentry=j;
  370. }
  371. }
  372. j=firstentry;
  373. #ifdef NOISY
  374. fprintf(cells,"%g %g\n%g %g\n\n",
  375. _now(v,j)[0],_now(v,j)[1],
  376. ppt[0],ppt[1]);
  377. #endif
  378. firstmetric-=v->bias[firstentry];
  379. meterror+=firstmetric;
  380. /* set up midpoints for next iter */
  381. if(v->assigned[j]++){
  382. for(k=0;k<v->elements;k++)
  383. vN(new,j)[k]+=ppt[k];
  384. if(firstmetric>v->max[firstentry])v->max[firstentry]=firstmetric;
  385. }else{
  386. for(k=0;k<v->elements;k++)
  387. vN(new,j)[k]=ppt[k];
  388. v->max[firstentry]=firstmetric;
  389. }
  390. }
  391. /* assign midpoints */
  392. for(j=0;j<v->entries;j++){
  393. #ifdef NOISY
  394. fprintf(assig,"%ld\n",v->assigned[j]);
  395. fprintf(bias,"%g\n",v->bias[j]);
  396. #endif
  397. asserror+=fabs(v->assigned[j]-fdesired);
  398. if(v->assigned[j])
  399. for(k=0;k<v->elements;k++)
  400. _now(v,j)[k]=vN(new,j)[k]/v->assigned[j];
  401. }
  402. asserror/=(v->entries*fdesired);
  403. fprintf(stderr,"Pass #%d... ",v->it);
  404. fprintf(stderr,": dist %g(%g) metric error=%g \n",
  405. asserror,fdesired,meterror/v->points);
  406. v->it++;
  407. free(new);
  408. free(nearcount);
  409. free(nearbias);
  410. #ifdef NOISY
  411. fclose(assig);
  412. fclose(bias);
  413. fclose(cells);
  414. #endif
  415. return(asserror);
  416. }