annotate src/libvorbis-1.3.3/vq/vqgen.c @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
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