annotate src/libvorbis-1.3.3/vq/vqgen.c @ 104:19297782190a

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