Blame vq/vqgen.c

Packit 06404a
/********************************************************************
Packit 06404a
 *                                                                  *
Packit 06404a
 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
Packit 06404a
 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
Packit 06404a
 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
Packit 06404a
 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
Packit 06404a
 *                                                                  *
Packit 06404a
 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001             *
Packit 06404a
 * by the Xiph.Org Foundation http://www.xiph.org/                  *
Packit 06404a
 *                                                                  *
Packit 06404a
 ********************************************************************
Packit 06404a
Packit 06404a
 function: train a VQ codebook 
Packit 06404a
 last mod: $Id: vqgen.c 16037 2009-05-26 21:10:58Z xiphmont $
Packit 06404a
Packit 06404a
 ********************************************************************/
Packit 06404a
Packit 06404a
/* This code is *not* part of libvorbis.  It is used to generate
Packit 06404a
   trained codebooks offline and then spit the results into a
Packit 06404a
   pregenerated codebook that is compiled into libvorbis.  It is an
Packit 06404a
   expensive (but good) algorithm.  Run it on big iron. */
Packit 06404a
Packit 06404a
/* There are so many optimizations to explore in *both* stages that
Packit 06404a
   considering the undertaking is almost withering.  For now, we brute
Packit 06404a
   force it all */
Packit 06404a
Packit 06404a
#include <stdlib.h>
Packit 06404a
#include <stdio.h>
Packit 06404a
#include <math.h>
Packit 06404a
#include <string.h>
Packit 06404a
Packit 06404a
#include "vqgen.h"
Packit 06404a
#include "bookutil.h"
Packit 06404a
Packit 06404a
/* Codebook generation happens in two steps: 
Packit 06404a
Packit 06404a
   1) Train the codebook with data collected from the encoder: We use
Packit 06404a
   one of a few error metrics (which represent the distance between a
Packit 06404a
   given data point and a candidate point in the training set) to
Packit 06404a
   divide the training set up into cells representing roughly equal
Packit 06404a
   probability of occurring. 
Packit 06404a
Packit 06404a
   2) Generate the codebook and auxiliary data from the trained data set
Packit 06404a
*/
Packit 06404a
Packit 06404a
/* Codebook training ****************************************************
Packit 06404a
 *
Packit 06404a
 * The basic idea here is that a VQ codebook is like an m-dimensional
Packit 06404a
 * foam with n bubbles.  The bubbles compete for space/volume and are
Packit 06404a
 * 'pressurized' [biased] according to some metric.  The basic alg
Packit 06404a
 * iterates through allowing the bubbles to compete for space until
Packit 06404a
 * they converge (if the damping is dome properly) on a steady-state
Packit 06404a
 * solution. Individual input points, collected from libvorbis, are
Packit 06404a
 * used to train the algorithm monte-carlo style.  */
Packit 06404a
Packit 06404a
/* internal helpers *****************************************************/
Packit 06404a
#define vN(data,i) (data+v->elements*i)
Packit 06404a
Packit 06404a
/* default metric; squared 'distance' from desired value. */
Packit 06404a
float _dist(vqgen *v,float *a, float *b){
Packit 06404a
  int i;
Packit 06404a
  int el=v->elements;
Packit 06404a
  float acc=0.f;
Packit 06404a
  for(i=0;i
Packit 06404a
    float val=(a[i]-b[i]);
Packit 06404a
    acc+=val*val;
Packit 06404a
  }
Packit 06404a
  return sqrt(acc);
Packit 06404a
}
Packit 06404a
Packit 06404a
float *_weight_null(vqgen *v,float *a){
Packit 06404a
  return a;
Packit 06404a
}
Packit 06404a
Packit 06404a
/* *must* be beefed up. */
Packit 06404a
void _vqgen_seed(vqgen *v){
Packit 06404a
  long i;
Packit 06404a
  for(i=0;i<v->entries;i++)
Packit 06404a
    memcpy(_now(v,i),_point(v,i),sizeof(float)*v->elements);
Packit 06404a
  v->seeded=1;
Packit 06404a
}
Packit 06404a
Packit 06404a
int directdsort(const void *a, const void *b){
Packit 06404a
  float av=*((float *)a);
Packit 06404a
  float bv=*((float *)b);
Packit 06404a
  return (av<bv)-(av>bv);
Packit 06404a
}
Packit 06404a
Packit 06404a
void vqgen_cellmetric(vqgen *v){
Packit 06404a
  int j,k;
Packit 06404a
  float min=-1.f,max=-1.f,mean=0.f,acc=0.f;
Packit 06404a
  long dup=0,unused=0;
Packit 06404a
 #ifdef NOISY
Packit 06404a
  int i;
Packit 06404a
   char buff[80];
Packit 06404a
   float spacings[v->entries];
Packit 06404a
   int count=0;
Packit 06404a
   FILE *cells;
Packit 06404a
   sprintf(buff,"cellspace%d.m",v->it);
Packit 06404a
   cells=fopen(buff,"w");
Packit 06404a
#endif
Packit 06404a
Packit 06404a
  /* minimum, maximum, cell spacing */
Packit 06404a
  for(j=0;j<v->entries;j++){
Packit 06404a
    float localmin=-1.;
Packit 06404a
Packit 06404a
    for(k=0;k<v->entries;k++){
Packit 06404a
      if(j!=k){
Packit 06404a
        float this=_dist(v,_now(v,j),_now(v,k));
Packit 06404a
        if(this>0){
Packit 06404a
          if(v->assigned[k] && (localmin==-1 || this
Packit 06404a
            localmin=this;
Packit 06404a
        }else{        
Packit 06404a
          if(k
Packit 06404a
            dup++;
Packit 06404a
            break;
Packit 06404a
          }
Packit 06404a
        }
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
    if(k<v->entries)continue;
Packit 06404a
Packit 06404a
    if(v->assigned[j]==0){
Packit 06404a
      unused++;
Packit 06404a
      continue;
Packit 06404a
    }
Packit 06404a
    
Packit 06404a
    localmin=v->max[j]+localmin/2; /* this gives us rough diameter */
Packit 06404a
    if(min==-1 || localmin
Packit 06404a
    if(max==-1 || localmin>max)max=localmin;
Packit 06404a
    mean+=localmin;
Packit 06404a
    acc++;
Packit 06404a
#ifdef NOISY
Packit 06404a
    spacings[count++]=localmin;
Packit 06404a
#endif
Packit 06404a
  }
Packit 06404a
Packit 06404a
  fprintf(stderr,"cell diameter: %.03g::%.03g::%.03g (%ld unused/%ld dup)\n",
Packit 06404a
          min,mean/acc,max,unused,dup);
Packit 06404a
Packit 06404a
#ifdef NOISY
Packit 06404a
  qsort(spacings,count,sizeof(float),directdsort);
Packit 06404a
  for(i=0;i
Packit 06404a
    fprintf(cells,"%g\n",spacings[i]);
Packit 06404a
  fclose(cells);
Packit 06404a
#endif            
Packit 06404a
Packit 06404a
}
Packit 06404a
Packit 06404a
/* External calls *******************************************************/
Packit 06404a
Packit 06404a
/* We have two forms of quantization; in the first, each vector
Packit 06404a
   element in the codebook entry is orthogonal.  Residues would use this
Packit 06404a
   quantization for example.
Packit 06404a
Packit 06404a
   In the second, we have a sequence of monotonically increasing
Packit 06404a
   values that we wish to quantize as deltas (to save space).  We
Packit 06404a
   still need to quantize so that absolute values are accurate. For
Packit 06404a
   example, LSP quantizes all absolute values, but the book encodes
Packit 06404a
   distance between values because each successive value is larger
Packit 06404a
   than the preceeding value.  Thus the desired quantibits apply to
Packit 06404a
   the encoded (delta) values, not abs positions. This requires minor
Packit 06404a
   additional encode-side trickery. */
Packit 06404a
Packit 06404a
void vqgen_quantize(vqgen *v,quant_meta *q){
Packit 06404a
Packit 06404a
  float maxdel;
Packit 06404a
  float mindel;
Packit 06404a
Packit 06404a
  float delta;
Packit 06404a
  float maxquant=((1<<q->quant)-1);
Packit 06404a
Packit 06404a
  int j,k;
Packit 06404a
Packit 06404a
  mindel=maxdel=_now(v,0)[0];
Packit 06404a
  
Packit 06404a
  for(j=0;j<v->entries;j++){
Packit 06404a
    float last=0.f;
Packit 06404a
    for(k=0;k<v->elements;k++){
Packit 06404a
      if(mindel>_now(v,j)[k]-last)mindel=_now(v,j)[k]-last;
Packit 06404a
      if(maxdel<_now(v,j)[k]-last)maxdel=_now(v,j)[k]-last;
Packit 06404a
      if(q->sequencep)last=_now(v,j)[k];
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
Packit 06404a
  /* first find the basic delta amount from the maximum span to be
Packit 06404a
     encoded.  Loosen the delta slightly to allow for additional error
Packit 06404a
     during sequence quantization */
Packit 06404a
Packit 06404a
  delta=(maxdel-mindel)/((1<<q->quant)-1.5f);
Packit 06404a
Packit 06404a
  q->min=_float32_pack(mindel);
Packit 06404a
  q->delta=_float32_pack(delta);
Packit 06404a
Packit 06404a
  mindel=_float32_unpack(q->min);
Packit 06404a
  delta=_float32_unpack(q->delta);
Packit 06404a
Packit 06404a
  for(j=0;j<v->entries;j++){
Packit 06404a
    float last=0;
Packit 06404a
    for(k=0;k<v->elements;k++){
Packit 06404a
      float val=_now(v,j)[k];
Packit 06404a
      float now=rint((val-last-mindel)/delta);
Packit 06404a
      
Packit 06404a
      _now(v,j)[k]=now;
Packit 06404a
      if(now<0){
Packit 06404a
        /* be paranoid; this should be impossible */
Packit 06404a
        fprintf(stderr,"fault; quantized value<0\n");
Packit 06404a
        exit(1);
Packit 06404a
      }
Packit 06404a
Packit 06404a
      if(now>maxquant){
Packit 06404a
        /* be paranoid; this should be impossible */
Packit 06404a
        fprintf(stderr,"fault; quantized value>max\n");
Packit 06404a
        exit(1);
Packit 06404a
      }
Packit 06404a
      if(q->sequencep)last=(now*delta)+mindel+last;
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
}
Packit 06404a
Packit 06404a
/* much easier :-).  Unlike in the codebook, we don't un-log log
Packit 06404a
   scales; we just make sure they're properly offset. */
Packit 06404a
void vqgen_unquantize(vqgen *v,quant_meta *q){
Packit 06404a
  long j,k;
Packit 06404a
  float mindel=_float32_unpack(q->min);
Packit 06404a
  float delta=_float32_unpack(q->delta);
Packit 06404a
Packit 06404a
  for(j=0;j<v->entries;j++){
Packit 06404a
    float last=0.f;
Packit 06404a
    for(k=0;k<v->elements;k++){
Packit 06404a
      float now=_now(v,j)[k];
Packit 06404a
      now=fabs(now)*delta+last+mindel;
Packit 06404a
      if(q->sequencep)last=now;
Packit 06404a
      _now(v,j)[k]=now;
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
}
Packit 06404a
Packit 06404a
void vqgen_init(vqgen *v,int elements,int aux,int entries,float mindist,
Packit 06404a
                float  (*metric)(vqgen *,float *, float *),
Packit 06404a
                float *(*weight)(vqgen *,float *),int centroid){
Packit 06404a
  memset(v,0,sizeof(vqgen));
Packit 06404a
Packit 06404a
  v->centroid=centroid;
Packit 06404a
  v->elements=elements;
Packit 06404a
  v->aux=aux;
Packit 06404a
  v->mindist=mindist;
Packit 06404a
  v->allocated=32768;
Packit 06404a
  v->pointlist=_ogg_malloc(v->allocated*(v->elements+v->aux)*sizeof(float));
Packit 06404a
Packit 06404a
  v->entries=entries;
Packit 06404a
  v->entrylist=_ogg_malloc(v->entries*v->elements*sizeof(float));
Packit 06404a
  v->assigned=_ogg_malloc(v->entries*sizeof(long));
Packit 06404a
  v->bias=_ogg_calloc(v->entries,sizeof(float));
Packit 06404a
  v->max=_ogg_calloc(v->entries,sizeof(float));
Packit 06404a
  if(metric)
Packit 06404a
    v->metric_func=metric;
Packit 06404a
  else
Packit 06404a
    v->metric_func=_dist;
Packit 06404a
  if(weight)
Packit 06404a
    v->weight_func=weight;
Packit 06404a
  else
Packit 06404a
    v->weight_func=_weight_null;
Packit 06404a
Packit 06404a
  v->asciipoints=tmpfile();
Packit 06404a
Packit 06404a
}
Packit 06404a
Packit 06404a
void vqgen_addpoint(vqgen *v, float *p,float *a){
Packit 06404a
  int k;
Packit 06404a
  for(k=0;k<v->elements;k++)
Packit 06404a
    fprintf(v->asciipoints,"%.12g\n",p[k]);
Packit 06404a
  for(k=0;k<v->aux;k++)
Packit 06404a
    fprintf(v->asciipoints,"%.12g\n",a[k]);
Packit 06404a
Packit 06404a
  if(v->points>=v->allocated){
Packit 06404a
    v->allocated*=2;
Packit 06404a
    v->pointlist=_ogg_realloc(v->pointlist,v->allocated*(v->elements+v->aux)*
Packit 06404a
                         sizeof(float));
Packit 06404a
  }
Packit 06404a
Packit 06404a
  memcpy(_point(v,v->points),p,sizeof(float)*v->elements);
Packit 06404a
  if(v->aux)memcpy(_point(v,v->points)+v->elements,a,sizeof(float)*v->aux);
Packit 06404a
 
Packit 06404a
  /* quantize to the density mesh if it's selected */
Packit 06404a
  if(v->mindist>0.f){
Packit 06404a
    /* quantize to the mesh */
Packit 06404a
    for(k=0;k<v->elements+v->aux;k++)
Packit 06404a
      _point(v,v->points)[k]=
Packit 06404a
        rint(_point(v,v->points)[k]/v->mindist)*v->mindist;
Packit 06404a
  }
Packit 06404a
  v->points++;
Packit 06404a
  if(!(v->points&0xff))spinnit("loading... ",v->points);
Packit 06404a
}
Packit 06404a
Packit 06404a
/* yes, not threadsafe.  These utils aren't */
Packit 06404a
static int sortit=0;
Packit 06404a
static int sortsize=0;
Packit 06404a
static int meshcomp(const void *a,const void *b){
Packit 06404a
  if(((sortit++)&0xfff)==0)spinnit("sorting mesh...",sortit);
Packit 06404a
  return(memcmp(a,b,sortsize));
Packit 06404a
}
Packit 06404a
Packit 06404a
void vqgen_sortmesh(vqgen *v){
Packit 06404a
  sortit=0;
Packit 06404a
  if(v->mindist>0.f){
Packit 06404a
    long i,march=1;
Packit 06404a
Packit 06404a
    /* sort to make uniqueness detection trivial */
Packit 06404a
    sortsize=(v->elements+v->aux)*sizeof(float);
Packit 06404a
    qsort(v->pointlist,v->points,sortsize,meshcomp);
Packit 06404a
Packit 06404a
    /* now march through and eliminate dupes */
Packit 06404a
    for(i=1;i<v->points;i++){
Packit 06404a
      if(memcmp(_point(v,i),_point(v,i-1),sortsize)){
Packit 06404a
        /* a new, unique entry.  march it down */
Packit 06404a
        if(i>march)memcpy(_point(v,march),_point(v,i),sortsize);
Packit 06404a
        march++;
Packit 06404a
      }
Packit 06404a
      spinnit("eliminating density... ",v->points-i);
Packit 06404a
    }
Packit 06404a
Packit 06404a
    /* we're done */
Packit 06404a
    fprintf(stderr,"\r%ld training points remining out of %ld"
Packit 06404a
            " after density mesh (%ld%%)\n",march,v->points,march*100/v->points);
Packit 06404a
    v->points=march;
Packit 06404a
Packit 06404a
  }
Packit 06404a
  v->sorted=1;
Packit 06404a
}
Packit 06404a
Packit 06404a
float vqgen_iterate(vqgen *v,int biasp){
Packit 06404a
  long   i,j,k;
Packit 06404a
Packit 06404a
  float fdesired;
Packit 06404a
  long  desired;
Packit 06404a
  long  desired2;
Packit 06404a
Packit 06404a
  float asserror=0.f;
Packit 06404a
  float meterror=0.f;
Packit 06404a
  float *new;
Packit 06404a
  float *new2;
Packit 06404a
  long   *nearcount;
Packit 06404a
  float *nearbias;
Packit 06404a
 #ifdef NOISY
Packit 06404a
   char buff[80];
Packit 06404a
   FILE *assig;
Packit 06404a
   FILE *bias;
Packit 06404a
   FILE *cells;
Packit 06404a
   sprintf(buff,"cells%d.m",v->it);
Packit 06404a
   cells=fopen(buff,"w");
Packit 06404a
   sprintf(buff,"assig%d.m",v->it);
Packit 06404a
   assig=fopen(buff,"w");
Packit 06404a
   sprintf(buff,"bias%d.m",v->it);
Packit 06404a
   bias=fopen(buff,"w");
Packit 06404a
 #endif
Packit 06404a
 
Packit 06404a
Packit 06404a
  if(v->entries<2){
Packit 06404a
    fprintf(stderr,"generation requires at least two entries\n");
Packit 06404a
    exit(1);
Packit 06404a
  }
Packit 06404a
Packit 06404a
  if(!v->sorted)vqgen_sortmesh(v);
Packit 06404a
  if(!v->seeded)_vqgen_seed(v);
Packit 06404a
Packit 06404a
  fdesired=(float)v->points/v->entries;
Packit 06404a
  desired=fdesired;
Packit 06404a
  desired2=desired*2;
Packit 06404a
  new=_ogg_malloc(sizeof(float)*v->entries*v->elements);
Packit 06404a
  new2=_ogg_malloc(sizeof(float)*v->entries*v->elements);
Packit 06404a
  nearcount=_ogg_malloc(v->entries*sizeof(long));
Packit 06404a
  nearbias=_ogg_malloc(v->entries*desired2*sizeof(float));
Packit 06404a
Packit 06404a
  /* fill in nearest points for entry biasing */
Packit 06404a
  /*memset(v->bias,0,sizeof(float)*v->entries);*/
Packit 06404a
  memset(nearcount,0,sizeof(long)*v->entries);
Packit 06404a
  memset(v->assigned,0,sizeof(long)*v->entries);
Packit 06404a
  if(biasp){
Packit 06404a
    for(i=0;i<v->points;i++){
Packit 06404a
      float *ppt=v->weight_func(v,_point(v,i));
Packit 06404a
      float firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
Packit 06404a
      float secondmetric=v->metric_func(v,_now(v,1),ppt)+v->bias[1];
Packit 06404a
      long   firstentry=0;
Packit 06404a
      long   secondentry=1;
Packit 06404a
      
Packit 06404a
      if(!(i&0xff))spinnit("biasing... ",v->points+v->points+v->entries-i);
Packit 06404a
      
Packit 06404a
      if(firstmetric>secondmetric){
Packit 06404a
        float temp=firstmetric;
Packit 06404a
        firstmetric=secondmetric;
Packit 06404a
        secondmetric=temp;
Packit 06404a
        firstentry=1;
Packit 06404a
        secondentry=0;
Packit 06404a
      }
Packit 06404a
      
Packit 06404a
      for(j=2;j<v->entries;j++){
Packit 06404a
        float thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j];
Packit 06404a
        if(thismetric
Packit 06404a
          if(thismetric
Packit 06404a
            secondmetric=firstmetric;
Packit 06404a
            secondentry=firstentry;
Packit 06404a
            firstmetric=thismetric;
Packit 06404a
            firstentry=j;
Packit 06404a
          }else{
Packit 06404a
            secondmetric=thismetric;
Packit 06404a
            secondentry=j;
Packit 06404a
          }
Packit 06404a
        }
Packit 06404a
      }
Packit 06404a
      
Packit 06404a
      j=firstentry;
Packit 06404a
      for(j=0;j<v->entries;j++){
Packit 06404a
        
Packit 06404a
        float thismetric,localmetric;
Packit 06404a
        float *nearbiasptr=nearbias+desired2*j;
Packit 06404a
        long k=nearcount[j];
Packit 06404a
        
Packit 06404a
        localmetric=v->metric_func(v,_now(v,j),ppt);
Packit 06404a
        /* 'thismetric' is to be the bias value necessary in the current
Packit 06404a
           arrangement for entry j to capture point i */
Packit 06404a
        if(firstentry==j){
Packit 06404a
          /* use the secondary entry as the threshhold */
Packit 06404a
          thismetric=secondmetric-localmetric;
Packit 06404a
        }else{
Packit 06404a
          /* use the primary entry as the threshhold */
Packit 06404a
          thismetric=firstmetric-localmetric;
Packit 06404a
        }
Packit 06404a
        
Packit 06404a
        /* support the idea of 'minimum distance'... if we want the
Packit 06404a
           cells in a codebook to be roughly some minimum size (as with
Packit 06404a
           the low resolution residue books) */
Packit 06404a
        
Packit 06404a
        /* a cute two-stage delayed sorting hack */
Packit 06404a
        if(k
Packit 06404a
          nearbiasptr[k]=thismetric;
Packit 06404a
          k++;
Packit 06404a
          if(k==desired){
Packit 06404a
            spinnit("biasing... ",v->points+v->points+v->entries-i);
Packit 06404a
            qsort(nearbiasptr,desired,sizeof(float),directdsort);
Packit 06404a
          }
Packit 06404a
          
Packit 06404a
        }else if(thismetric>nearbiasptr[desired-1]){
Packit 06404a
          nearbiasptr[k]=thismetric;
Packit 06404a
          k++;
Packit 06404a
          if(k==desired2){
Packit 06404a
            spinnit("biasing... ",v->points+v->points+v->entries-i);
Packit 06404a
            qsort(nearbiasptr,desired2,sizeof(float),directdsort);
Packit 06404a
            k=desired;
Packit 06404a
          }
Packit 06404a
        }
Packit 06404a
        nearcount[j]=k;
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
    
Packit 06404a
    /* inflate/deflate */
Packit 06404a
    
Packit 06404a
    for(i=0;i<v->entries;i++){
Packit 06404a
      float *nearbiasptr=nearbias+desired2*i;
Packit 06404a
      
Packit 06404a
      spinnit("biasing... ",v->points+v->entries-i);
Packit 06404a
      
Packit 06404a
      /* due to the delayed sorting, we likely need to finish it off....*/
Packit 06404a
      if(nearcount[i]>desired)
Packit 06404a
        qsort(nearbiasptr,nearcount[i],sizeof(float),directdsort);
Packit 06404a
Packit 06404a
      v->bias[i]=nearbiasptr[desired-1];
Packit 06404a
Packit 06404a
    }
Packit 06404a
  }else{ 
Packit 06404a
    memset(v->bias,0,v->entries*sizeof(float));
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* Now assign with new bias and find new midpoints */
Packit 06404a
  for(i=0;i<v->points;i++){
Packit 06404a
    float *ppt=v->weight_func(v,_point(v,i));
Packit 06404a
    float firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
Packit 06404a
    long   firstentry=0;
Packit 06404a
Packit 06404a
    if(!(i&0xff))spinnit("centering... ",v->points-i);
Packit 06404a
Packit 06404a
    for(j=0;j<v->entries;j++){
Packit 06404a
      float thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j];
Packit 06404a
      if(thismetric
Packit 06404a
        firstmetric=thismetric;
Packit 06404a
        firstentry=j;
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
Packit 06404a
    j=firstentry;
Packit 06404a
      
Packit 06404a
#ifdef NOISY
Packit 06404a
    fprintf(cells,"%g %g\n%g %g\n\n",
Packit 06404a
          _now(v,j)[0],_now(v,j)[1],
Packit 06404a
          ppt[0],ppt[1]);
Packit 06404a
#endif
Packit 06404a
Packit 06404a
    firstmetric-=v->bias[j];
Packit 06404a
    meterror+=firstmetric;
Packit 06404a
Packit 06404a
    if(v->centroid==0){
Packit 06404a
      /* set up midpoints for next iter */
Packit 06404a
      if(v->assigned[j]++){
Packit 06404a
        for(k=0;k<v->elements;k++)
Packit 06404a
          vN(new,j)[k]+=ppt[k];
Packit 06404a
        if(firstmetric>v->max[j])v->max[j]=firstmetric;
Packit 06404a
      }else{
Packit 06404a
        for(k=0;k<v->elements;k++)
Packit 06404a
          vN(new,j)[k]=ppt[k];
Packit 06404a
        v->max[j]=firstmetric;
Packit 06404a
      }
Packit 06404a
    }else{
Packit 06404a
      /* centroid */
Packit 06404a
      if(v->assigned[j]++){
Packit 06404a
        for(k=0;k<v->elements;k++){
Packit 06404a
          if(vN(new,j)[k]>ppt[k])vN(new,j)[k]=ppt[k];
Packit 06404a
          if(vN(new2,j)[k]
Packit 06404a
        }
Packit 06404a
        if(firstmetric>v->max[firstentry])v->max[j]=firstmetric;
Packit 06404a
      }else{
Packit 06404a
        for(k=0;k<v->elements;k++){
Packit 06404a
          vN(new,j)[k]=ppt[k];
Packit 06404a
          vN(new2,j)[k]=ppt[k];
Packit 06404a
        }
Packit 06404a
        v->max[firstentry]=firstmetric;
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  /* assign midpoints */
Packit 06404a
Packit 06404a
  for(j=0;j<v->entries;j++){
Packit 06404a
#ifdef NOISY
Packit 06404a
    fprintf(assig,"%ld\n",v->assigned[j]);
Packit 06404a
    fprintf(bias,"%g\n",v->bias[j]);
Packit 06404a
#endif
Packit 06404a
    asserror+=fabs(v->assigned[j]-fdesired);
Packit 06404a
    if(v->assigned[j]){
Packit 06404a
      if(v->centroid==0){
Packit 06404a
        for(k=0;k<v->elements;k++)
Packit 06404a
          _now(v,j)[k]=vN(new,j)[k]/v->assigned[j];
Packit 06404a
      }else{
Packit 06404a
        for(k=0;k<v->elements;k++)
Packit 06404a
          _now(v,j)[k]=(vN(new,j)[k]+vN(new2,j)[k])/2.f;
Packit 06404a
      }
Packit 06404a
    }
Packit 06404a
  }
Packit 06404a
Packit 06404a
  asserror/=(v->entries*fdesired);
Packit 06404a
Packit 06404a
  fprintf(stderr,"Pass #%d... ",v->it);
Packit 06404a
  fprintf(stderr,": dist %g(%g) metric error=%g \n",
Packit 06404a
          asserror,fdesired,meterror/v->points);
Packit 06404a
  v->it++;
Packit 06404a
  
Packit 06404a
  free(new);
Packit 06404a
  free(nearcount);
Packit 06404a
  free(nearbias);
Packit 06404a
#ifdef NOISY
Packit 06404a
  fclose(assig);
Packit 06404a
  fclose(bias);
Packit 06404a
  fclose(cells);
Packit 06404a
#endif
Packit 06404a
  return(asserror);
Packit 06404a
}
Packit 06404a