00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <stdlib.h>
00028 #include <stdio.h>
00029 #include <math.h>
00030 #include <string.h>
00031
00032 #include "vqgen.h"
00033 #include "bookutil.h"
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 #define vN(data,i) (data+v->elements*i)
00058
00059
00060 float _dist(vqgen *v,float *a, float *b){
00061 int i;
00062 int el=v->elements;
00063 float acc=0.f;
00064 for(i=0;i<el;i++){
00065 float val=(a[i]-b[i]);
00066 acc+=val*val;
00067 }
00068 return sqrt(acc);
00069 }
00070
00071 float *_weight_null(vqgen *v,float *a){
00072 return a;
00073 }
00074
00075
00076 void _vqgen_seed(vqgen *v){
00077 long i;
00078 for(i=0;i<v->entries;i++)
00079 memcpy(_now(v,i),_point(v,i),sizeof(float)*v->elements);
00080 v->seeded=1;
00081 }
00082
00083 int directdsort(const void *a, const void *b){
00084 float av=*((float *)a);
00085 float bv=*((float *)b);
00086 return (av<bv)-(av>bv);
00087 }
00088
00089 void vqgen_cellmetric(vqgen *v){
00090 int j,k;
00091 float min=-1.f,max=-1.f,mean=0.f,acc=0.f;
00092 long dup=0,unused=0;
00093 #ifdef NOISY
00094 int i;
00095 char buff[80];
00096 float spacings[v->entries];
00097 int count=0;
00098 FILE *cells;
00099 sprintf(buff,"cellspace%d.m",v->it);
00100 cells=fopen(buff,"w");
00101 #endif
00102
00103
00104 for(j=0;j<v->entries;j++){
00105 float localmin=-1.;
00106
00107 for(k=0;k<v->entries;k++){
00108 if(j!=k){
00109 float this=_dist(v,_now(v,j),_now(v,k));
00110 if(this>0){
00111 if(v->assigned[k] && (localmin==-1 || this<localmin))
00112 localmin=this;
00113 }else{
00114 if(k<j){
00115 dup++;
00116 break;
00117 }
00118 }
00119 }
00120 }
00121 if(k<v->entries)continue;
00122
00123 if(v->assigned[j]==0){
00124 unused++;
00125 continue;
00126 }
00127
00128 localmin=v->max[j]+localmin/2;
00129 if(min==-1 || localmin<min)min=localmin;
00130 if(max==-1 || localmin>max)max=localmin;
00131 mean+=localmin;
00132 acc++;
00133 #ifdef NOISY
00134 spacings[count++]=localmin;
00135 #endif
00136 }
00137
00138 fprintf(stderr,"cell diameter: %.03g::%.03g::%.03g (%ld unused/%ld dup)\n",
00139 min,mean/acc,max,unused,dup);
00140
00141 #ifdef NOISY
00142 qsort(spacings,count,sizeof(float),directdsort);
00143 for(i=0;i<count;i++)
00144 fprintf(cells,"%g\n",spacings[i]);
00145 fclose(cells);
00146 #endif
00147
00148 }
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 void vqgen_quantize(vqgen *v,quant_meta *q){
00166
00167 float maxdel;
00168 float mindel;
00169
00170 float delta;
00171 float maxquant=((1<<q->quant)-1);
00172
00173 int j,k;
00174
00175 mindel=maxdel=_now(v,0)[0];
00176
00177 for(j=0;j<v->entries;j++){
00178 float last=0.f;
00179 for(k=0;k<v->elements;k++){
00180 if(mindel>_now(v,j)[k]-last)mindel=_now(v,j)[k]-last;
00181 if(maxdel<_now(v,j)[k]-last)maxdel=_now(v,j)[k]-last;
00182 if(q->sequencep)last=_now(v,j)[k];
00183 }
00184 }
00185
00186
00187
00188
00189
00190
00191 delta=(maxdel-mindel)/((1<<q->quant)-1.5f);
00192
00193 q->min=_float32_pack(mindel);
00194 q->delta=_float32_pack(delta);
00195
00196 mindel=_float32_unpack(q->min);
00197 delta=_float32_unpack(q->delta);
00198
00199 for(j=0;j<v->entries;j++){
00200 float last=0;
00201 for(k=0;k<v->elements;k++){
00202 float val=_now(v,j)[k];
00203 float now=rint((val-last-mindel)/delta);
00204
00205 _now(v,j)[k]=now;
00206 if(now<0){
00207
00208 fprintf(stderr,"fault; quantized value<0\n");
00209 exit(1);
00210 }
00211
00212 if(now>maxquant){
00213
00214 fprintf(stderr,"fault; quantized value>max\n");
00215 exit(1);
00216 }
00217 if(q->sequencep)last=(now*delta)+mindel+last;
00218 }
00219 }
00220 }
00221
00222
00223
00224 void vqgen_unquantize(vqgen *v,quant_meta *q){
00225 long j,k;
00226 float mindel=_float32_unpack(q->min);
00227 float delta=_float32_unpack(q->delta);
00228
00229 for(j=0;j<v->entries;j++){
00230 float last=0.f;
00231 for(k=0;k<v->elements;k++){
00232 float now=_now(v,j)[k];
00233 now=fabs(now)*delta+last+mindel;
00234 if(q->sequencep)last=now;
00235 _now(v,j)[k]=now;
00236 }
00237 }
00238 }
00239
00240 void vqgen_init(vqgen *v,int elements,int aux,int entries,float mindist,
00241 float (*metric)(vqgen *,float *, float *),
00242 float *(*weight)(vqgen *,float *),int centroid){
00243 memset(v,0,sizeof(vqgen));
00244
00245 v->centroid=centroid;
00246 v->elements=elements;
00247 v->aux=aux;
00248 v->mindist=mindist;
00249 v->allocated=32768;
00250 v->pointlist=_ogg_malloc(v->allocated*(v->elements+v->aux)*sizeof(float));
00251
00252 v->entries=entries;
00253 v->entrylist=_ogg_malloc(v->entries*v->elements*sizeof(float));
00254 v->assigned=_ogg_malloc(v->entries*sizeof(long));
00255 v->bias=_ogg_calloc(v->entries,sizeof(float));
00256 v->max=_ogg_calloc(v->entries,sizeof(float));
00257 if(metric)
00258 v->metric_func=metric;
00259 else
00260 v->metric_func=_dist;
00261 if(weight)
00262 v->weight_func=weight;
00263 else
00264 v->weight_func=_weight_null;
00265
00266 v->asciipoints=tmpfile();
00267
00268 }
00269
00270 void vqgen_addpoint(vqgen *v, float *p,float *a){
00271 int k;
00272 for(k=0;k<v->elements;k++)
00273 fprintf(v->asciipoints,"%.12g\n",p[k]);
00274 for(k=0;k<v->aux;k++)
00275 fprintf(v->asciipoints,"%.12g\n",a[k]);
00276
00277 if(v->points>=v->allocated){
00278 v->allocated*=2;
00279 v->pointlist=_ogg_realloc(v->pointlist,v->allocated*(v->elements+v->aux)*
00280 sizeof(float));
00281 }
00282
00283 memcpy(_point(v,v->points),p,sizeof(float)*v->elements);
00284 if(v->aux)memcpy(_point(v,v->points)+v->elements,a,sizeof(float)*v->aux);
00285
00286
00287 if(v->mindist>0.f){
00288
00289 for(k=0;k<v->elements+v->aux;k++)
00290 _point(v,v->points)[k]=
00291 rint(_point(v,v->points)[k]/v->mindist)*v->mindist;
00292 }
00293 v->points++;
00294 if(!(v->points&0xff))spinnit("loading... ",v->points);
00295 }
00296
00297
00298 static int sortit=0;
00299 static int sortsize=0;
00300 static int meshcomp(const void *a,const void *b){
00301 if(((sortit++)&0xfff)==0)spinnit("sorting mesh...",sortit);
00302 return(memcmp(a,b,sortsize));
00303 }
00304
00305 void vqgen_sortmesh(vqgen *v){
00306 sortit=0;
00307 if(v->mindist>0.f){
00308 long i,march=1;
00309
00310
00311 sortsize=(v->elements+v->aux)*sizeof(float);
00312 qsort(v->pointlist,v->points,sortsize,meshcomp);
00313
00314
00315 for(i=1;i<v->points;i++){
00316 if(memcmp(_point(v,i),_point(v,i-1),sortsize)){
00317
00318 if(i>march)memcpy(_point(v,march),_point(v,i),sortsize);
00319 march++;
00320 }
00321 spinnit("eliminating density... ",v->points-i);
00322 }
00323
00324
00325 fprintf(stderr,"\r%ld training points remining out of %ld"
00326 " after density mesh (%ld%%)\n",march,v->points,march*100/v->points);
00327 v->points=march;
00328
00329 }
00330 v->sorted=1;
00331 }
00332
00333 float vqgen_iterate(vqgen *v,int biasp){
00334 long i,j,k;
00335
00336 float fdesired;
00337 long desired;
00338 long desired2;
00339
00340 float asserror=0.f;
00341 float meterror=0.f;
00342 float *new;
00343 float *new2;
00344 long *nearcount;
00345 float *nearbias;
00346 #ifdef NOISY
00347 char buff[80];
00348 FILE *assig;
00349 FILE *bias;
00350 FILE *cells;
00351 sprintf(buff,"cells%d.m",v->it);
00352 cells=fopen(buff,"w");
00353 sprintf(buff,"assig%d.m",v->it);
00354 assig=fopen(buff,"w");
00355 sprintf(buff,"bias%d.m",v->it);
00356 bias=fopen(buff,"w");
00357 #endif
00358
00359
00360 if(v->entries<2){
00361 fprintf(stderr,"generation requires at least two entries\n");
00362 exit(1);
00363 }
00364
00365 if(!v->sorted)vqgen_sortmesh(v);
00366 if(!v->seeded)_vqgen_seed(v);
00367
00368 fdesired=(float)v->points/v->entries;
00369 desired=fdesired;
00370 desired2=desired*2;
00371 new=_ogg_malloc(sizeof(float)*v->entries*v->elements);
00372 new2=_ogg_malloc(sizeof(float)*v->entries*v->elements);
00373 nearcount=_ogg_malloc(v->entries*sizeof(long));
00374 nearbias=_ogg_malloc(v->entries*desired2*sizeof(float));
00375
00376
00377
00378 memset(nearcount,0,sizeof(long)*v->entries);
00379 memset(v->assigned,0,sizeof(long)*v->entries);
00380 if(biasp){
00381 for(i=0;i<v->points;i++){
00382 float *ppt=v->weight_func(v,_point(v,i));
00383 float firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
00384 float secondmetric=v->metric_func(v,_now(v,1),ppt)+v->bias[1];
00385 long firstentry=0;
00386 long secondentry=1;
00387
00388 if(!(i&0xff))spinnit("biasing... ",v->points+v->points+v->entries-i);
00389
00390 if(firstmetric>secondmetric){
00391 float temp=firstmetric;
00392 firstmetric=secondmetric;
00393 secondmetric=temp;
00394 firstentry=1;
00395 secondentry=0;
00396 }
00397
00398 for(j=2;j<v->entries;j++){
00399 float thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j];
00400 if(thismetric<secondmetric){
00401 if(thismetric<firstmetric){
00402 secondmetric=firstmetric;
00403 secondentry=firstentry;
00404 firstmetric=thismetric;
00405 firstentry=j;
00406 }else{
00407 secondmetric=thismetric;
00408 secondentry=j;
00409 }
00410 }
00411 }
00412
00413 j=firstentry;
00414 for(j=0;j<v->entries;j++){
00415
00416 float thismetric,localmetric;
00417 float *nearbiasptr=nearbias+desired2*j;
00418 long k=nearcount[j];
00419
00420 localmetric=v->metric_func(v,_now(v,j),ppt);
00421
00422
00423 if(firstentry==j){
00424
00425 thismetric=secondmetric-localmetric;
00426 }else{
00427
00428 thismetric=firstmetric-localmetric;
00429 }
00430
00431
00432
00433
00434
00435
00436 if(k<desired){
00437 nearbiasptr[k]=thismetric;
00438 k++;
00439 if(k==desired){
00440 spinnit("biasing... ",v->points+v->points+v->entries-i);
00441 qsort(nearbiasptr,desired,sizeof(float),directdsort);
00442 }
00443
00444 }else if(thismetric>nearbiasptr[desired-1]){
00445 nearbiasptr[k]=thismetric;
00446 k++;
00447 if(k==desired2){
00448 spinnit("biasing... ",v->points+v->points+v->entries-i);
00449 qsort(nearbiasptr,desired2,sizeof(float),directdsort);
00450 k=desired;
00451 }
00452 }
00453 nearcount[j]=k;
00454 }
00455 }
00456
00457
00458
00459 for(i=0;i<v->entries;i++){
00460 float *nearbiasptr=nearbias+desired2*i;
00461
00462 spinnit("biasing... ",v->points+v->entries-i);
00463
00464
00465 if(nearcount[i]>desired)
00466 qsort(nearbiasptr,nearcount[i],sizeof(float),directdsort);
00467
00468 v->bias[i]=nearbiasptr[desired-1];
00469
00470 }
00471 }else{
00472 memset(v->bias,0,v->entries*sizeof(float));
00473 }
00474
00475
00476 for(i=0;i<v->points;i++){
00477 float *ppt=v->weight_func(v,_point(v,i));
00478 float firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
00479 long firstentry=0;
00480
00481 if(!(i&0xff))spinnit("centering... ",v->points-i);
00482
00483 for(j=0;j<v->entries;j++){
00484 float thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j];
00485 if(thismetric<firstmetric){
00486 firstmetric=thismetric;
00487 firstentry=j;
00488 }
00489 }
00490
00491 j=firstentry;
00492
00493 #ifdef NOISY
00494 fprintf(cells,"%g %g\n%g %g\n\n",
00495 _now(v,j)[0],_now(v,j)[1],
00496 ppt[0],ppt[1]);
00497 #endif
00498
00499 firstmetric-=v->bias[j];
00500 meterror+=firstmetric;
00501
00502 if(v->centroid==0){
00503
00504 if(v->assigned[j]++){
00505 for(k=0;k<v->elements;k++)
00506 vN(new,j)[k]+=ppt[k];
00507 if(firstmetric>v->max[j])v->max[j]=firstmetric;
00508 }else{
00509 for(k=0;k<v->elements;k++)
00510 vN(new,j)[k]=ppt[k];
00511 v->max[j]=firstmetric;
00512 }
00513 }else{
00514
00515 if(v->assigned[j]++){
00516 for(k=0;k<v->elements;k++){
00517 if(vN(new,j)[k]>ppt[k])vN(new,j)[k]=ppt[k];
00518 if(vN(new2,j)[k]<ppt[k])vN(new2,j)[k]=ppt[k];
00519 }
00520 if(firstmetric>v->max[firstentry])v->max[j]=firstmetric;
00521 }else{
00522 for(k=0;k<v->elements;k++){
00523 vN(new,j)[k]=ppt[k];
00524 vN(new2,j)[k]=ppt[k];
00525 }
00526 v->max[firstentry]=firstmetric;
00527 }
00528 }
00529 }
00530
00531
00532
00533 for(j=0;j<v->entries;j++){
00534 #ifdef NOISY
00535 fprintf(assig,"%ld\n",v->assigned[j]);
00536 fprintf(bias,"%g\n",v->bias[j]);
00537 #endif
00538 asserror+=fabs(v->assigned[j]-fdesired);
00539 if(v->assigned[j]){
00540 if(v->centroid==0){
00541 for(k=0;k<v->elements;k++)
00542 _now(v,j)[k]=vN(new,j)[k]/v->assigned[j];
00543 }else{
00544 for(k=0;k<v->elements;k++)
00545 _now(v,j)[k]=(vN(new,j)[k]+vN(new2,j)[k])/2.f;
00546 }
00547 }
00548 }
00549
00550 asserror/=(v->entries*fdesired);
00551
00552 fprintf(stderr,"Pass #%d... ",v->it);
00553 fprintf(stderr,": dist %g(%g) metric error=%g \n",
00554 asserror,fdesired,meterror/v->points);
00555 v->it++;
00556
00557 free(new);
00558 free(nearcount);
00559 free(nearbias);
00560 #ifdef NOISY
00561 fclose(assig);
00562 fclose(bias);
00563 fclose(cells);
00564 #endif
00565 return(asserror);
00566 }
00567