annotate src/libvorbis-1.3.3/vq/vqgen.c @ 40:1df64224f5ac

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