/********************************************************************
* *
- * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
- * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
- * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
- * PLEASE READ THESE TERMS DISTRIBUTING. *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
- * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-1999 *
- * by 1999 Monty <monty@xiph.org> and The XIPHOPHORUS Company *
- * http://www.xiph.org/ *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************
- function: build a VQ codebook
- author: Monty <xiphmont@mit.edu>
- modifications by: Monty
- last modification date: Oct 04 1999
+ function: train a VQ codebook
********************************************************************/
pregenerated codebook that is compiled into libvorbis. It is an
expensive (but good) algorithm. Run it on big iron. */
+/* There are so many optimizations to explore in *both* stages that
+ considering the undertaking is almost withering. For now, we brute
+ force it all */
+
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
-#include "minit.h"
-/************************************************************************
+#include "vqgen.h"
+#include "bookutil.h"
+
+/* Codebook generation happens in two steps:
+
+ 1) Train the codebook with data collected from the encoder: We use
+ one of a few error metrics (which represent the distance between a
+ given data point and a candidate point in the training set) to
+ divide the training set up into cells representing roughly equal
+ probability of occurring.
+
+ 2) Generate the codebook and auxiliary data from the trained data set
+*/
+
+/* Codebook training ****************************************************
+ *
* The basic idea here is that a VQ codebook is like an m-dimensional
* foam with n bubbles. The bubbles compete for space/volume and are
* 'pressurized' [biased] according to some metric. The basic alg
* solution. Individual input points, collected from libvorbis, are
* used to train the algorithm monte-carlo style. */
-typedef struct vqgen{
- int elements;
- double errspread;
-
- /* point cache */
- double *pointlist;
- long *first;
- long *second;
- long points;
- long allocated;
-
- /* entries */
- double *entrylist;
- long *assigned;
- double *bias;
- long entries;
-
- double (*metric_func) (struct vqgen *v,double *a,double *b);
-} vqgen;
-
-typedef struct vqbook{
-
-
-
-} vqbook;
-
/* internal helpers *****************************************************/
#define vN(data,i) (data+v->elements*i)
-double *_point(vqgen *v,long ptr){
- return v->pointlist+(v->elements*ptr);
-}
-
-double *_now(vqgen *v,long ptr){
- return v->entrylist+(v->elements*ptr);
-}
-
/* default metric; squared 'distance' from desired value. */
-double _dist_sq(vqgen *v,double *a, double *b){
+float _dist(vqgen *v,float *a, float *b){
int i;
int el=v->elements;
- double acc=0.;
+ float acc=0.f;
for(i=0;i<el;i++){
- double val=(a[i]-b[i]);
+ float val=(a[i]-b[i]);
acc+=val*val;
}
- return acc;
+ return sqrt(acc);
}
-/* *must* be beefed up. Perhaps a Floyd-Steinberg like scattering? */
+float *_weight_null(vqgen *v,float *a){
+ return a;
+}
+
+/* *must* be beefed up. */
void _vqgen_seed(vqgen *v){
- memcpy(v->entrylist,v->pointlist,sizeof(double)*v->entries*v->elements);
+ long i;
+ for(i=0;i<v->entries;i++)
+ memcpy(_now(v,i),_point(v,i),sizeof(float)*v->elements);
+ v->seeded=1;
+}
+
+int directdsort(const void *a, const void *b){
+ float av=*((float *)a);
+ float bv=*((float *)b);
+ return (av<bv)-(av>bv);
}
-void _limited_sort(double *vals,long *index,long total,int desired){
- if(total>1){
- long bisect=total>>1;
- if(bisect>1)_limited_sort(vals,index,bisect,desired);
- if(total-bisect>1)_limited_sort(vals,index+bisect,total-bisect,
- desired);
- if(desired>total)desired=total;
-
- {
- int i;
- long ptra=0;
- long ptrb=bisect;
- long *temp=alloca(desired*sizeof(long));
-
- for(i=0;i<desired;i++){
- if(vals[index[ptra]]>vals[index[ptrb]]){
- temp[i]=index[ptra++];
- }else{
- temp[i]=index[ptrb++];
- }
- if(ptra==bisect)
- for(i++;i<desired;i++)temp[i]=index[ptrb++];
- else
- if(ptrb==total)
- for(i++;i<desired;i++)temp[i]=index[ptra++];
-
+void vqgen_cellmetric(vqgen *v){
+ int j,k;
+ float min=-1.f,max=-1.f,mean=0.f,acc=0.f;
+ long dup=0,unused=0;
+ #ifdef NOISY
+ int i;
+ char buff[80];
+ float spacings[v->entries];
+ int count=0;
+ FILE *cells;
+ sprintf(buff,"cellspace%d.m",v->it);
+ cells=fopen(buff,"w");
+#endif
+
+ /* minimum, maximum, cell spacing */
+ for(j=0;j<v->entries;j++){
+ float localmin=-1.;
+
+ for(k=0;k<v->entries;k++){
+ if(j!=k){
+ float this=_dist(v,_now(v,j),_now(v,k));
+ if(this>0){
+ if(v->assigned[k] && (localmin==-1 || this<localmin))
+ localmin=this;
+ }else{
+ if(k<j){
+ dup++;
+ break;
+ }
+ }
}
+ }
+ if(k<v->entries)continue;
- memcpy(index,temp,desired*sizeof(long));
+ if(v->assigned[j]==0){
+ unused++;
+ continue;
}
+
+ localmin=v->max[j]+localmin/2; /* this gives us rough diameter */
+ if(min==-1 || localmin<min)min=localmin;
+ if(max==-1 || localmin>max)max=localmin;
+ mean+=localmin;
+ acc++;
+#ifdef NOISY
+ spacings[count++]=localmin;
+#endif
}
-}
-/* External calls *******************************************************/
+ fprintf(stderr,"cell diameter: %.03g::%.03g::%.03g (%ld unused/%ld dup)\n",
+ min,mean/acc,max,unused,dup);
-void vqgen_init(vqgen *v,int elements,int entries,
- double (*metric)(vqgen *,double *, double *),
- double spread){
- memset(v,0,sizeof(vqgen));
+#ifdef NOISY
+ qsort(spacings,count,sizeof(float),directdsort);
+ for(i=0;i<count;i++)
+ fprintf(cells,"%g\n",spacings[i]);
+ fclose(cells);
+#endif
- v->elements=elements;
- v->errspread=spread;
- v->allocated=32768;
- v->pointlist=malloc(v->allocated*v->elements*sizeof(double));
- v->first=malloc(v->allocated*sizeof(long));
- v->second=malloc(v->allocated*sizeof(long));
-
- v->entries=entries;
- v->entrylist=malloc(v->entries*v->elements*sizeof(double));
- v->assigned=malloc(v->entries*sizeof(long));
- v->bias=calloc(v->entries,sizeof(double));
- if(metric)
- v->metric_func=metric;
- else
- v->metric_func=_dist_sq;
}
-void vqgen_addpoint(vqgen *v, double *p){
- if(v->points>=v->allocated){
- v->allocated*=2;
- v->pointlist=realloc(v->pointlist,v->allocated*v->elements*sizeof(double));
- v->first=realloc(v->first,v->allocated*sizeof(long));
- v->second=realloc(v->second,v->allocated*sizeof(long));
- }
-
- memcpy(_point(v,v->points),p,sizeof(double)*v->elements);
- v->points++;
- if(v->points==v->entries)_vqgen_seed(v);
-}
+/* External calls *******************************************************/
-void vqgen_recenter(vqgen *v){
- long i,j,k;
- double fdesired=(double)v->points/v->entries;
- double asserror=0.;
- double meterror=0.;
+/* We have two forms of quantization; in the first, each vector
+ element in the codebook entry is orthogonal. Residues would use this
+ quantization for example.
- if(v->entries<2)exit(1);
+ In the second, we have a sequence of monotonically increasing
+ values that we wish to quantize as deltas (to save space). We
+ still need to quantize so that absolute values are accurate. For
+ example, LSP quantizes all absolute values, but the book encodes
+ distance between values because each successive value is larger
+ than the preceeding value. Thus the desired quantibits apply to
+ the encoded (delta) values, not abs positions. This requires minor
+ additional encode-side trickery. */
- /* first round: new midpoints */
- {
- double *newlo=malloc(sizeof(double)*v->entries*v->elements);
- double *newhi=malloc(sizeof(double)*v->entries*v->elements);
+void vqgen_quantize(vqgen *v,quant_meta *q){
- memset(v->assigned,0,sizeof(long)*v->entries);
+ float maxdel;
+ float mindel;
- for(i=0;i<v->points;i++){
- double firstmetric=v->metric_func(v,_now(v,0),_point(v,i))+v->bias[0];
- long firstentry=0;
-
- for(j=1;j<v->entries;j++){
- double thismetric=v->metric_func(v,_now(v,j),_point(v,i))+v->bias[j];
- if(thismetric<firstmetric){
- firstmetric=thismetric;
- firstentry=j;
- }
- }
+ float delta;
+ float maxquant=((1<<q->quant)-1);
- j=firstentry;
- meterror+=firstmetric-v->bias[firstentry];
- if(v->assigned[j]++){
- for(k=0;k<v->elements;k++){
- if(_point(v,i)[k]<vN(newlo,j)[k])vN(newlo,j)[k]=_point(v,i)[k];
- if(_point(v,i)[k]>vN(newhi,j)[k])vN(newhi,j)[k]=_point(v,i)[k];
- }
- }else{
- for(k=0;k<v->elements;k++){
- vN(newlo,j)[k]=_point(v,i)[k];
- vN(newhi,j)[k]=_point(v,i)[k];
- }
- }
- }
+ int j,k;
- for(j=0;j<v->entries;j++){
- if(v->assigned[j]){
- for(k=0;k<v->elements;k++)
- _now(v,j)[k]=(vN(newlo,j)[k]+vN(newhi,j)[k])/2.;
- }
+ mindel=maxdel=_now(v,0)[0];
+
+ for(j=0;j<v->entries;j++){
+ float last=0.f;
+ for(k=0;k<v->elements;k++){
+ if(mindel>_now(v,j)[k]-last)mindel=_now(v,j)[k]-last;
+ if(maxdel<_now(v,j)[k]-last)maxdel=_now(v,j)[k]-last;
+ if(q->sequencep)last=_now(v,j)[k];
}
- free(newlo);
- free(newhi);
}
- for(i=0;i<v->entries;i++){
- asserror+=fabs(fdesired-v->assigned[i]);
- }
- fprintf(stderr,"recenter: dist error=%g(%g) metric error=%g\n",
- asserror/v->entries,fdesired,meterror/v->points);
-
- memset(v->bias,0,sizeof(double)*v->entries);
-}
+ /* first find the basic delta amount from the maximum span to be
+ encoded. Loosen the delta slightly to allow for additional error
+ during sequence quantization */
-void vqgen_rebias(vqgen *v){
- long i,j,k;
- double fdesired=(float)v->points/v->entries;
- long desired=(v->points+v->entries-1)/v->entries;
+ delta=(maxdel-mindel)/((1<<q->quant)-1.5f);
- double asserror=0.;
- double meterror=0.;
- long *nearcount=calloc(v->entries,sizeof(long));
- double *nearbias=malloc(v->entries*desired*sizeof(double));
+ q->min=_float32_pack(mindel);
+ q->delta=_float32_pack(delta);
- if(v->entries<2)exit(1);
+ mindel=_float32_unpack(q->min);
+ delta=_float32_unpack(q->delta);
- /* second round: fill in nearest points for entries */
+ for(j=0;j<v->entries;j++){
+ float last=0;
+ for(k=0;k<v->elements;k++){
+ float val=_now(v,j)[k];
+ float now=rint((val-last-mindel)/delta);
- memset(v->assigned,0,sizeof(long)*v->entries);
- for(i=0;i<v->points;i++){
- /* not clear this should be biased */
- double firstmetric=v->metric_func(v,_now(v,0),_point(v,i));
- double secondmetric=v->metric_func(v,_now(v,1),_point(v,i));
- long firstentry=0;
- long secondentry=1;
- if(firstmetric>secondmetric){
- double temp=firstmetric;
- firstmetric=secondmetric;
- secondmetric=temp;
- firstentry=1;
- secondentry=0;
- }
-
- for(j=2;j<v->entries;j++){
- double thismetric=v->metric_func(v,_now(v,j),_point(v,i));
- if(thismetric<secondmetric){
- if(thismetric<firstmetric){
- secondmetric=firstmetric;
- secondentry=firstentry;
- firstmetric=thismetric;
- firstentry=j;
- }else{
- secondmetric=thismetric;
- secondentry=j;
- }
- }
- }
- v->assigned[firstentry]++;
- meterror+=firstmetric;
-
- for(j=0;j<v->entries;j++){
-
- double thismetric;
- double *nearbiasptr=nearbias+desired*j;
- long k=nearcount[j]-1;
-
- /* 'thismetric' is to be the bias value necessary in the current
- arrangement for entry j to capture point i */
- if(firstentry==j){
- /* use the secondary entry as the threshhold */
- thismetric=secondmetric-v->metric_func(v,_now(v,j),_point(v,i));
- }else{
- /* use the primary entry as the threshhold */
- thismetric=firstmetric-v->metric_func(v,_now(v,j),_point(v,i));
+ _now(v,j)[k]=now;
+ if(now<0){
+ /* be paranoid; this should be impossible */
+ fprintf(stderr,"fault; quantized value<0\n");
+ exit(1);
}
- if(k>=0 && thismetric>nearbiasptr[k]){
-
- /* start at the end and search backward for where this entry
- belongs */
-
- for(;k>0;k--) if(nearbiasptr[k-1]>=thismetric)break;
-
- /* insert at k. Shift and inject. */
- memmove(nearbiasptr+k+1,nearbiasptr+k,(desired-k-1)*sizeof(double));
- nearbiasptr[k]=thismetric;
-
- if(nearcount[j]<desired)nearcount[j]++;
-
- }else{
- if(nearcount[j]<desired){
- /* we checked the thresh earlier. We know this is the
- last entry */
- nearbiasptr[nearcount[j]++]=thismetric;
- }
+ if(now>maxquant){
+ /* be paranoid; this should be impossible */
+ fprintf(stderr,"fault; quantized value>max\n");
+ exit(1);
}
+ if(q->sequencep)last=(now*delta)+mindel+last;
}
}
-
- /* third round: inflate/deflate */
- {
- for(i=0;i<v->entries;i++){
- v->bias[i]=nearbias[(i+1)*desired-1];
+}
+
+/* much easier :-). Unlike in the codebook, we don't un-log log
+ scales; we just make sure they're properly offset. */
+void vqgen_unquantize(vqgen *v,quant_meta *q){
+ long j,k;
+ float mindel=_float32_unpack(q->min);
+ float delta=_float32_unpack(q->delta);
+
+ for(j=0;j<v->entries;j++){
+ float last=0.f;
+ for(k=0;k<v->elements;k++){
+ float now=_now(v,j)[k];
+ now=fabs(now)*delta+last+mindel;
+ if(q->sequencep)last=now;
+ _now(v,j)[k]=now;
}
}
+}
- for(i=0;i<v->entries;i++){
- asserror+=fabs(fdesired-v->assigned[i]);
- }
+void vqgen_init(vqgen *v,int elements,int aux,int entries,float mindist,
+ float (*metric)(vqgen *,float *, float *),
+ float *(*weight)(vqgen *,float *),int centroid){
+ memset(v,0,sizeof(vqgen));
+
+ v->centroid=centroid;
+ v->elements=elements;
+ v->aux=aux;
+ v->mindist=mindist;
+ v->allocated=32768;
+ v->pointlist=_ogg_malloc(v->allocated*(v->elements+v->aux)*sizeof(float));
+
+ v->entries=entries;
+ v->entrylist=_ogg_malloc(v->entries*v->elements*sizeof(float));
+ v->assigned=_ogg_malloc(v->entries*sizeof(long));
+ v->bias=_ogg_calloc(v->entries,sizeof(float));
+ v->max=_ogg_calloc(v->entries,sizeof(float));
+ if(metric)
+ v->metric_func=metric;
+ else
+ v->metric_func=_dist;
+ if(weight)
+ v->weight_func=weight;
+ else
+ v->weight_func=_weight_null;
+
+ v->asciipoints=tmpfile();
- fprintf(stderr,"rebias: dist error=%g(%g) metric error=%g\n",
- asserror/v->entries,fdesired,meterror/v->points);
-
- free(nearcount);
- free(nearbias);
}
-/* the additional fields are the hyperplanes we've already used to
- split the set. The additional hyperplanes are necessary to bound
- later splits. One per depth */
-
-int lp_split(vqgen *v,long *index,long points,
- double *additional_a, double *additional_b, long depth){
- static int frameno=0;
- long A[points];
- long B[points];
- long ap=0;
- long bp=0;
- long cp=0;
- long i,j,k;
- long leaves=0;
-
- double best=0.;
- long besti=-1;
- long bestj=-1;
-
- if(depth>7){
- printf("leaf: points %ld, depth %ld\n",points,depth);
- return(1);
+void vqgen_addpoint(vqgen *v, float *p,float *a){
+ int k;
+ for(k=0;k<v->elements;k++)
+ fprintf(v->asciipoints,"%.12g\n",p[k]);
+ for(k=0;k<v->aux;k++)
+ fprintf(v->asciipoints,"%.12g\n",a[k]);
+
+ if(v->points>=v->allocated){
+ v->allocated*=2;
+ v->pointlist=_ogg_realloc(v->pointlist,v->allocated*(v->elements+v->aux)*
+ sizeof(float));
}
- if(points==1){
- printf("leaf: point %ld, depth %ld\n",index[0],depth);
- return(1);
+ memcpy(_point(v,v->points),p,sizeof(float)*v->elements);
+ if(v->aux)memcpy(_point(v,v->points)+v->elements,a,sizeof(float)*v->aux);
+
+ /* quantize to the density mesh if it's selected */
+ if(v->mindist>0.f){
+ /* quantize to the mesh */
+ for(k=0;k<v->elements+v->aux;k++)
+ _point(v,v->points)[k]=
+ rint(_point(v,v->points)[k]/v->mindist)*v->mindist;
}
+ v->points++;
+ if(!(v->points&0xff))spinnit("loading... ",v->points);
+}
- if(points==2){
- /* The result must be an even split */
- B[bp++]=index[0];
- A[ap++]=index[1];
- printf("even split: depth %ld\n",depth);
- return(2);
- }else{
- /* We need to find the best split */
- for(i=0;i<points-1;i++){
- for(j=i+1;j<points;j++){
- if(_dist_sq(v,_now(v,index[i]),_now(v,index[j]))>best){
- besti=i;
- bestj=j;
- best=_dist_sq(v,_now(v,index[i]),_now(v,index[j]));
- }
+/* yes, not threadsafe. These utils aren't */
+static int sortit=0;
+static int sortsize=0;
+static int meshcomp(const void *a,const void *b){
+ if(((sortit++)&0xfff)==0)spinnit("sorting mesh...",sortit);
+ return(memcmp(a,b,sortsize));
+}
+
+void vqgen_sortmesh(vqgen *v){
+ sortit=0;
+ if(v->mindist>0.f){
+ long i,march=1;
+
+ /* sort to make uniqueness detection trivial */
+ sortsize=(v->elements+v->aux)*sizeof(float);
+ qsort(v->pointlist,v->points,sortsize,meshcomp);
+
+ /* now march through and eliminate dupes */
+ for(i=1;i<v->points;i++){
+ if(memcmp(_point(v,i),_point(v,i-1),sortsize)){
+ /* a new, unique entry. march it down */
+ if(i>march)memcpy(_point(v,march),_point(v,i),sortsize);
+ march++;
}
+ spinnit("eliminating density... ",v->points-i);
}
- /* We have our endpoints. initial divvy */
- {
- double *cA=malloc(v->elements*sizeof(double));
- double *cB=malloc(v->elements*sizeof(double));
- double **a=malloc((points+depth)*sizeof(double *));
- double *b=malloc((points+depth)*sizeof(double));
- double *aa=malloc((points+depth)*v->elements*sizeof(double));
- double dA=0.,dB=0.;
- minit l;
-
- minit_init(&l,v->elements,points+depth-1,0);
-
- /* divisor hyperplane */
- for(i=0;i<v->elements;i++){
- double m=(_now(v,index[besti])[i]+_now(v,index[bestj])[i])/2;
- cA[i]=_now(v,index[besti])[i]-_now(v,index[bestj])[i];
- cB[i]=-cA[i];
- dA+=cA[i]*m;
- dB-=cA[i]*m;
- }
-
- for(i=0;i<points+depth;i++)
- a[i]=aa+i*v->elements;
-
- /* check each bubble to see if it intersects the divisor hyperplane */
- for(j=0;j<points;j++){
- long count=0,m=0;
- double d1=0.,d2=0.;
- int ret;
-
- if(j==besti){
- B[bp++]=index[j];
- }else if (j==bestj){
- A[ap++]=index[j];
- }else{
-
- for(i=0;i<points;i++){
- if(i!=j){
- b[count]=0.;
- for(k=0;k<v->elements;k++){
- double m=(_now(v,index[i])[k]+_now(v,index[j])[k])/2;
- a[count][k]=_now(v,index[i])[k]-_now(v,index[j])[k];
- b[count]+=a[count][k]*m;
- }
- count++;
- }
- }
-
- /* additional bounding hyperplanes from previous splits */
- for(i=0;i<depth;i++){
- b[count]=0.;
- for(k=0;k<v->elements;k++)
- a[count][k]=additional_a[m++];
- b[count++]=additional_b[i];
- }
-
- /* on what side of the dividing hyperplane is the current test
- point? */
- for(i=0;i<v->elements;i++)
- d1+=_now(v,index[j])[i]*cA[i];
-
-
- if(d1<dA){
- fprintf(stderr,"+");
- ret=minit_solve(&l,a,b,cA,1e-6,NULL,NULL,&d2);
- }else{
- fprintf(stderr,"-");
- ret=minit_solve(&l,a,b,cB,1e-6,NULL,NULL,&d2);
- d2= -d2;
- }
-
- switch(ret){
- case 0:
- /* bounded solution */
- if(d1<dA){
- A[ap++]=index[j];
- if(d2>dA){cp++;B[bp++]=index[j];}
- }else{
- B[bp++]=index[j];
- if(d2<dA){cp++;A[ap++]=index[j];}
- }
- break;
- default:
- /* unbounded solution or no solution; we're in both sets */
- B[bp++]=index[j];
- A[ap++]=index[j];
- cp++;
- break;
- }
- }
- }
+ /* we're done */
+ fprintf(stderr,"\r%ld training points remining out of %ld"
+ " after density mesh (%ld%%)\n",march,v->points,march*100/v->points);
+ v->points=march;
- /*{
- char buffer[80];
- FILE *o;
- int i;
-
- sprintf(buffer,"set%d.m",frameno);
- o=fopen(buffer,"w");
- for(i=0;i<points;i++)
- fprintf(o,"%g %g\n\n",_now(v,index[i])[0],_now(v,index[i])[1]);
- fclose(o);
-
- sprintf(buffer,"setA%d.m",frameno);
- o=fopen(buffer,"w");
- for(i=0;i<ap;i++)
- fprintf(o,"%g %g\n\n",_now(v,A[i])[0],_now(v,A[i])[1]);
- fclose(o);
-
- sprintf(buffer,"setB%d.m",frameno);
- o=fopen(buffer,"w");
- for(i=0;i<bp;i++)
- fprintf(o,"%g %g\n\n",_now(v,B[i])[0],_now(v,B[i])[1]);
- fclose(o);
-
- sprintf(buffer,"div%d.m",frameno);
- o=fopen(buffer,"w");
- fprintf(o,"%g %g\n%g %g\n\n",
- _now(v,index[besti])[0],
- (dA-cA[0]*_now(v,index[besti])[0])/cA[1],
- _now(v,index[bestj])[0],
- (dA-cA[0]*_now(v,index[bestj])[0])/cA[1]);
- fclose(o);
-
- sprintf(buffer,"bound%d.m",frameno);
- o=fopen(buffer,"w");
- for(i=0;i<depth;i++)
- fprintf(o,"%g %g\n%g %g\n\n",
- _now(v,index[besti])[0],
- (additional_b[i]-
- additional_a[i*2]*_now(v,index[besti])[0])/
- additional_a[i*2+1],
- _now(v,index[bestj])[0],
- (additional_b[i]-
- additional_a[i*2]*_now(v,index[bestj])[0])/
- additional_a[i*2+1]);
- fclose(o);
- frameno++;
- }*/
-
-
- minit_clear(&l);
- free(a);
- free(b);
- free(aa);
-
- fprintf(stderr,"split: total=%ld depth=%ld set A=%ld:%ld:%ld=B\n",
- points,depth,ap-cp,cp,bp-cp);
-
- /* handle adding this divisor hyperplane to the additional
- constraints. The 'inside' side is different for A and B */
-
- {
- /* marginally wasteful */
- double *newadd_a=alloca(sizeof(double)*v->elements*(depth+1));
- double *newadd_b=alloca(sizeof(double)*(depth+1));
- if(additional_a){
- memcpy(newadd_a,additional_a,sizeof(double)*v->elements*depth);
- memcpy(newadd_b,additional_b,sizeof(double)*depth);
- }
-
- memcpy(newadd_a+v->elements*depth,cA,sizeof(double)*v->elements);
- newadd_b[depth]=dA;
- leaves=lp_split(v,A,ap,newadd_a,newadd_b,depth+1);
-
- memcpy(newadd_a+v->elements*depth,cB,sizeof(double)*v->elements);
- newadd_b[depth]=dB;
- leaves+=lp_split(v,B,bp,newadd_a,newadd_b,depth+1);
-
- }
- free(cA);
- free(cB);
- return(leaves);
- }
}
+ v->sorted=1;
}
-void vqgen_book(vqgen *v){
+float vqgen_iterate(vqgen *v,int biasp){
+ long i,j,k;
+ float fdesired;
+ long desired;
+ long desired2;
+
+ float asserror=0.f;
+ float meterror=0.f;
+ float *new;
+ float *new2;
+ long *nearcount;
+ float *nearbias;
+ #ifdef NOISY
+ char buff[80];
+ FILE *assig;
+ FILE *bias;
+ FILE *cells;
+ sprintf(buff,"cells%d.m",v->it);
+ cells=fopen(buff,"w");
+ sprintf(buff,"assig%d.m",v->it);
+ assig=fopen(buff,"w");
+ sprintf(buff,"bias%d.m",v->it);
+ bias=fopen(buff,"w");
+ #endif
+
+
+ if(v->entries<2){
+ fprintf(stderr,"generation requires at least two entries\n");
+ exit(1);
+ }
+ if(!v->sorted)vqgen_sortmesh(v);
+ if(!v->seeded)_vqgen_seed(v);
+ fdesired=(float)v->points/v->entries;
+ desired=fdesired;
+ desired2=desired*2;
+ new=_ogg_malloc(sizeof(float)*v->entries*v->elements);
+ new2=_ogg_malloc(sizeof(float)*v->entries*v->elements);
+ nearcount=_ogg_malloc(v->entries*sizeof(long));
+ nearbias=_ogg_malloc(v->entries*desired2*sizeof(float));
-}
+ /* fill in nearest points for entry biasing */
+ /*memset(v->bias,0,sizeof(float)*v->entries);*/
+ memset(nearcount,0,sizeof(long)*v->entries);
+ memset(v->assigned,0,sizeof(long)*v->entries);
+ if(biasp){
+ for(i=0;i<v->points;i++){
+ float *ppt=v->weight_func(v,_point(v,i));
+ float firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
+ float secondmetric=v->metric_func(v,_now(v,1),ppt)+v->bias[1];
+ long firstentry=0;
+ long secondentry=1;
-static double testset24[48]={
-1.047758,1.245406,
-1.007972,1.150078,
-1.064390,1.146266,
-0.761842,0.826055,
-0.862073,1.243707,
-0.746351,1.055368,
-0.956844,1.048223,
-0.877782,1.111871,
-0.964564,1.309219,
-0.920062,1.168658,
-0.787654,0.895163,
-0.974003,1.200115,
-0.788360,1.142671,
-0.978414,1.122249,
-0.869938,0.954436,
-1.131220,1.348747,
-0.934630,1.108564,
-0.896666,1.045772,
-0.707360,0.920954,
-0.788914,0.970626,
-0.828682,1.043673,
-1.042016,1.190406,
-1.031643,1.068194,
-1.120824,1.220326,
-};
-
-static double testset256[1024]={
-1.047758,1.245406,1.007972,1.150078,
-1.064390,1.146266,0.761842,0.826055,
-0.862073,1.243707,0.746351,1.055368,
-0.956844,1.048223,0.877782,1.111871,
-0.964564,1.309219,0.920062,1.168658,
-0.787654,0.895163,0.974003,1.200115,
-0.788360,1.142671,0.978414,1.122249,
-0.869938,0.954436,1.131220,1.348747,
-0.934630,1.108564,0.896666,1.045772,
-0.707360,0.920954,0.788914,0.970626,
-0.828682,1.043673,1.042016,1.190406,
-1.031643,1.068194,1.120824,1.220326,
-0.747084,0.888176,1.051535,1.221335,
-0.980283,1.087708,1.311154,1.445530,
-0.927548,1.107237,1.296902,1.480610,
-0.804415,0.921948,1.029952,1.231078,
-0.923413,1.064919,1.143109,1.242755,
-0.826403,1.010624,1.353139,1.455870,
-0.837930,1.073739,1.251770,1.405370,
-0.704437,0.890366,1.016676,1.136689,
-0.840924,1.151858,1.369346,1.558572,
-0.835229,1.095713,1.165585,1.311155,
-0.763157,1.000718,1.168780,1.345318,
-0.912852,1.040279,1.260220,1.468606,
-0.680839,0.920854,1.056199,1.214924,
-0.993572,1.124795,1.220880,1.416346,
-0.766878,0.994942,1.170035,1.432164,
-1.006875,1.069566,1.283594,1.531742,
-1.029033,1.188357,1.330626,1.519446,
-0.915581,1.121514,1.193260,1.431981,
-0.950939,1.117674,1.280092,1.487413,
-0.783569,0.863166,1.198348,1.309199,
-0.845209,0.949087,1.133299,1.253263,
-0.836299,1.050413,1.263712,1.482634,
-1.049458,1.194466,1.332964,1.485894,
-0.921516,1.086016,1.244810,1.349821,
-0.888983,1.111494,1.313032,1.351122,
-1.015785,1.142849,1.292746,1.463028,
-0.860002,1.249262,1.354167,1.534761,
-0.942136,1.053546,1.120840,1.373279,
-0.846661,1.059871,1.294814,1.504904,
-0.796592,1.061316,1.349680,1.494821,
-0.880504,1.033570,1.314379,1.484966,
-0.770438,1.039993,1.238670,1.412317,
-1.036503,1.068649,1.202522,1.487553,
-0.942615,1.056630,1.344355,1.562161,
-0.963759,1.096427,1.324085,1.497266,
-0.899956,1.206083,1.349655,1.572202,
-0.977023,1.132722,1.338437,1.488086,
-1.096643,1.242143,1.357079,1.513244,
-0.795193,1.011915,1.312761,1.419554,
-1.021869,1.075269,1.265230,1.475986,
-1.019546,1.186088,1.347798,1.567607,
-1.051191,1.172904,1.381952,1.511843,
-0.924332,1.192953,1.385378,1.420727,
-0.869539,0.962051,1.400803,1.539414,
-0.949875,1.053939,1.305695,1.422764,
-0.962223,1.085902,1.247702,1.462327,
-0.991777,1.182062,1.287421,1.508453,
-0.918274,1.107269,1.325467,1.454377,
-0.993589,1.184665,1.352294,1.475413,
-0.804960,1.011490,1.259031,1.462335,
-0.845949,1.173858,1.389681,1.441148,
-0.858168,1.019930,1.232463,1.440218,
-0.884411,1.206226,1.318968,1.457990,
-0.893469,1.074271,1.274410,1.433475,
-1.039654,1.061160,1.122426,1.189133,
-1.062243,1.177357,1.344765,1.542071,
-0.900964,1.116803,1.380397,1.419108,
-0.969535,1.216066,1.383582,1.435924,
-1.017913,1.330986,1.403452,1.450709,
-0.771534,0.973324,1.171604,1.236873,
-0.955683,1.029609,1.309284,1.498449,
-0.892165,1.192347,1.322444,1.356025,
-0.890209,1.023145,1.326649,1.431669,
-1.038788,1.188891,1.330844,1.436180,
-1.050355,1.177363,1.283447,1.479040,
-0.825367,0.960892,1.179047,1.381923,
-0.978931,1.122163,1.304581,1.532161,
-0.970750,1.149650,1.390225,1.547422,
-0.805416,0.945116,1.118815,1.343870,
-1.004106,1.185996,1.304086,1.464108,
-0.771591,1.055865,1.150908,1.228683,
-0.950175,1.104237,1.203437,1.387264,
-0.923504,1.122814,1.173989,1.318650,
-0.960635,1.042342,1.196995,1.395394,
-1.035111,1.064804,1.134387,1.341424,
-0.815182,1.083612,1.159518,1.255777,
-0.784079,0.830594,1.056005,1.289902,
-0.737774,0.994134,1.115470,1.264879,
-0.820162,1.105657,1.182947,1.423629,
-1.067552,1.142869,1.191626,1.387014,
-0.752416,0.918026,1.124637,1.414500,
-0.767963,0.840069,0.997625,1.325653,
-0.787595,0.865440,1.090071,1.227348,
-0.798877,1.105239,1.331379,1.440643,
-0.829079,1.133632,1.280774,1.470690,
-1.009195,1.132959,1.284044,1.500589,
-0.698569,0.824611,1.236682,1.462088,
-0.817460,0.985767,1.081910,1.257751,
-0.784033,0.882552,1.149678,1.326920,
-1.039403,1.085310,1.211033,1.558635,
-0.966795,1.168857,1.309960,1.497788,
-0.906244,1.027050,1.198846,1.323671,
-0.776495,1.185285,1.309167,1.380683,
-0.799628,0.927976,1.048238,1.299045,
-0.779808,0.881990,1.167898,1.220314,
-0.770446,0.918281,1.049189,1.179393,
-0.768416,1.037558,1.165760,1.302606,
-0.743121,0.814671,0.990501,1.224236,
-1.037050,1.068240,1.159690,1.426280,
-0.978810,1.214329,1.253336,1.324395,
-0.984003,1.121443,1.376382,1.510519,
-1.146510,1.229726,1.417616,1.781032,
-0.897163,1.147910,1.221186,1.371815,
-1.068525,1.211553,1.343551,1.506743,
-0.762313,1.091082,1.253251,1.472381,
-0.960562,1.041965,1.247053,1.399214,
-0.864482,1.123473,1.163412,1.238620,
-0.963484,1.132803,1.164992,1.250389,
-1.009456,1.139510,1.251339,1.449078,
-0.851837,1.113642,1.170290,1.362806,
-0.857073,0.962039,1.127381,1.471682,
-1.047754,1.213381,1.388899,1.492383,
-0.938921,1.267308,1.337076,1.478427,
-0.790388,0.912816,1.159450,1.273259,
-0.832690,0.997776,1.156639,1.302621,
-0.783009,0.975374,1.080630,1.311112,
-0.819784,1.145093,1.326949,1.525480,
-0.806394,1.089564,1.329564,1.550362,
-0.958608,1.036364,1.379118,1.443043,
-0.753680,0.941781,1.147749,1.297211,
-0.883974,1.091394,1.315093,1.480307,
-1.239591,1.417601,1.495843,1.641941,
-0.881068,0.973780,1.278918,1.429384,
-0.869052,0.977661,1.280744,1.551295,
-1.022685,1.052986,1.105046,1.168670,
-0.981698,1.131448,1.197781,1.467704,
-0.945034,1.163410,1.250872,1.428793,
-1.092055,1.139380,1.187113,1.264586,
-0.788897,0.953764,1.232844,1.506461,
-0.885206,0.978419,1.209467,1.387569,
-0.762835,0.964279,1.064844,1.243153,
-0.974906,1.134763,1.283544,1.460386,
-1.081114,1.169260,1.290987,1.535452,
-0.880531,1.075660,1.378980,1.522978,
-1.039431,1.083792,1.350481,1.588522,
-0.922449,1.060622,1.152309,1.467930,
-0.918935,1.073732,1.283243,1.479567,
-0.992722,1.145398,1.239500,1.509004,
-0.903405,1.243062,1.421386,1.572148,
-0.912531,1.100239,1.310219,1.521424,
-0.875168,0.912787,1.123618,1.363635,
-0.732241,1.108317,1.323119,1.515675,
-0.951518,1.141874,1.341623,1.533409,
-0.992099,1.215801,1.477413,1.734691,
-1.005267,1.122655,1.356975,1.436445,
-0.740659,0.807749,1.167728,1.380618,
-1.078727,1.214706,1.328173,1.556699,
-1.026027,1.168906,1.313249,1.486078,
-0.914877,1.147150,1.389489,1.523984,
-1.062339,1.120684,1.160024,1.234794,
-1.129141,1.197655,1.374217,1.547755,
-1.070011,1.255271,1.360225,1.467869,
-0.779980,0.871696,1.098031,1.284490,
-1.062409,1.177542,1.314581,1.696662,
-0.702935,1.229873,1.370813,1.479500,
-1.029357,1.225167,1.341607,1.478163,
-1.025666,1.141749,1.185959,1.332892,
-0.799462,0.951470,1.214070,1.305787,
-0.740521,0.805457,1.107504,1.317258,
-0.784194,0.838683,1.055934,1.242692,
-0.839416,1.048060,1.391801,1.623786,
-0.692627,0.907677,1.060843,1.341002,
-0.823625,1.244497,1.396901,1.586243,
-0.942859,1.232978,1.348170,1.536735,
-0.894882,1.131376,1.292892,1.462724,
-0.776974,0.904449,1.325557,1.451968,
-1.066188,1.218328,1.376282,1.545381,
-0.990053,1.124279,1.340534,1.559666,
-0.776321,0.935169,1.191081,1.372326,
-0.949935,1.115929,1.397704,1.442549,
-0.936357,1.126885,1.356247,1.579931,
-1.045433,1.274605,1.366947,1.590215,
-1.063890,1.138062,1.220645,1.460005,
-0.751448,0.811338,1.078027,1.403146,
-0.935678,1.102858,1.356557,1.515948,
-1.026417,1.143843,1.299309,1.413976,
-0.821475,1.000237,1.105073,1.379882,
-0.960249,1.031602,1.250804,1.462620,
-0.661745,1.106452,1.291188,1.439529,
-0.691661,0.947241,1.261183,1.457391,
-0.839024,0.914750,1.040695,1.375853,
-1.029401,1.065349,1.121370,1.270670,
-0.888316,1.003349,1.103749,1.341290,
-0.766328,0.879083,1.217779,1.419868,
-0.811672,1.049673,1.186460,1.375742,
-0.969585,1.170126,1.259338,1.595070,
-1.016617,1.145706,1.335413,1.503064,
-0.980227,1.295316,1.417964,1.478684,
-0.885701,1.248099,1.416821,1.465338,
-0.953583,1.266596,1.325829,1.372230,
-1.038619,1.225860,1.351664,1.527048,
-1.104724,1.215839,1.250491,1.335237,
-1.124449,1.269485,1.420756,1.677260,
-0.881337,1.352259,1.433218,1.492756,
-1.023097,1.059205,1.110249,1.212976,
-1.135632,1.282243,1.415540,1.566039,
-1.063524,1.252342,1.399082,1.518433,
-0.790658,0.856337,1.154909,1.274963,
-1.119059,1.382625,1.423651,1.492741,
-1.030526,1.296610,1.330511,1.396550,
-0.947952,1.065235,1.225274,1.554455,
-0.960669,1.282313,1.370362,1.572736,
-0.996042,1.208193,1.385036,1.534877,
-1.003206,1.377432,1.431110,1.497189,
-1.088166,1.227944,1.508129,1.740407,
-0.996566,1.162407,1.347665,1.524235,
-0.944606,1.287026,1.400822,1.437156,
-1.066144,1.238314,1.454451,1.616016,
-1.121065,1.200875,1.316542,1.459583,
-1.158944,1.271448,1.356823,1.450510,
-0.811670,1.278011,1.361550,1.440647,
-0.875620,1.103051,1.230854,1.483429,
-0.959882,1.180685,1.381224,1.572807,
-1.049222,1.186513,1.387883,1.567423,
-1.049920,1.293154,1.507194,1.678371,
-0.872138,1.193727,1.455817,1.665837,
-0.738018,0.946583,1.335543,1.552061,
-1.072856,1.151838,1.321877,1.486028,
-1.026909,1.153575,1.306700,1.550408,
-0.940629,1.121943,1.303228,1.409285,
-1.023544,1.269480,1.316695,1.508732,
-0.924872,1.119626,1.479602,1.698360,
-0.793358,1.160361,1.381276,1.636124,
-0.892504,1.248046,1.320256,1.367114,
-1.165222,1.230265,1.507234,1.820748,
-0.711084,0.876165,1.145850,1.493303,
-0.776482,0.869670,1.124462,1.370831,
-0.785085,0.912534,1.099328,1.281523,
-0.947788,1.168239,1.407409,1.473592,
-0.913992,1.316132,1.619366,1.865030,
-1.024592,1.151907,1.383557,1.545112,
-0.987748,1.168194,1.415323,1.639563,
-0.725008,1.037088,1.306659,1.474607,
-0.965243,1.263523,1.454521,1.638929,
-1.035169,1.219404,1.427315,1.578414,
-0.787215,0.960639,1.245517,1.423549,
-0.902895,1.153039,1.412772,1.613360,
-0.983205,1.338886,1.493960,1.619623,
-0.822576,1.010524,1.232397,1.359007,
-0.773450,1.090005,1.170248,1.369534,
-1.117781,1.354485,1.662228,1.829565,
-1.104316,1.324945,1.525085,1.741040,
-1.135275,1.371208,1.537082,1.673949,
-0.889899,1.195451,1.242648,1.291881,
-
-};
-
-int main(int argc,char *argv[]){
- FILE *in=fopen(argv[1],"r");
- vqgen v;
- char buffer[160];
- int i,j;
-
- vqgen_init(&v,4,256,_dist_sq,0.);
-
- while(fgets(buffer,160,in)){
- double a[8];
- if(sscanf(buffer,"%lf %lf %lf %lf",
- a,a+1,a+2,a+3)==4)
- vqgen_addpoint(&v,a);
- }
- fclose(in);
-
- for(i=0;i<10;i++)
- vqgen_recenter(&v);
-
- for(i=0;i<100;i++){
- vqgen_rebias(&v);
- vqgen_recenter(&v);
- fprintf(stderr,"%d ",i);
- }
+ if(!(i&0xff))spinnit("biasing... ",v->points+v->points+v->entries-i);
- vqgen_recenter(&v);
+ if(firstmetric>secondmetric){
+ float temp=firstmetric;
+ firstmetric=secondmetric;
+ secondmetric=temp;
+ firstentry=1;
+ secondentry=0;
+ }
- exit(0);
+ for(j=2;j<v->entries;j++){
+ float thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j];
+ if(thismetric<secondmetric){
+ if(thismetric<firstmetric){
+ secondmetric=firstmetric;
+ secondentry=firstentry;
+ firstmetric=thismetric;
+ firstentry=j;
+ }else{
+ secondmetric=thismetric;
+ secondentry=j;
+ }
+ }
+ }
- memcpy(v.entrylist,testset256,sizeof(testset256));
+ j=firstentry;
+ for(j=0;j<v->entries;j++){
+
+ float thismetric,localmetric;
+ float *nearbiasptr=nearbias+desired2*j;
+ long k=nearcount[j];
+
+ localmetric=v->metric_func(v,_now(v,j),ppt);
+ /* 'thismetric' is to be the bias value necessary in the current
+ arrangement for entry j to capture point i */
+ if(firstentry==j){
+ /* use the secondary entry as the threshhold */
+ thismetric=secondmetric-localmetric;
+ }else{
+ /* use the primary entry as the threshhold */
+ thismetric=firstmetric-localmetric;
+ }
+
+ /* support the idea of 'minimum distance'... if we want the
+ cells in a codebook to be roughly some minimum size (as with
+ the low resolution residue books) */
+
+ /* a cute two-stage delayed sorting hack */
+ if(k<desired){
+ nearbiasptr[k]=thismetric;
+ k++;
+ if(k==desired){
+ spinnit("biasing... ",v->points+v->points+v->entries-i);
+ qsort(nearbiasptr,desired,sizeof(float),directdsort);
+ }
+
+ }else if(thismetric>nearbiasptr[desired-1]){
+ nearbiasptr[k]=thismetric;
+ k++;
+ if(k==desired2){
+ spinnit("biasing... ",v->points+v->points+v->entries-i);
+ qsort(nearbiasptr,desired2,sizeof(float),directdsort);
+ k=desired;
+ }
+ }
+ nearcount[j]=k;
+ }
+ }
- for(i=0;i<v.entries;i++){
- printf("\n");
- for(j=0;j<v.elements;j++)
- printf("%f,",_now(&v,i)[j]);
- }
- printf("\n");
-
-
- /* try recursively splitting the space using LP
- {
- long index[v.entries];
- for(i=0;i<v.entries;i++)index[i]=i;
- fprintf(stderr,"\n\nleaves=%d\n",
- lp_split(&v,index,v.entries,NULL,NULL,0));
- }*/
-
- return(0);
-}
+ /* inflate/deflate */
+ for(i=0;i<v->entries;i++){
+ float *nearbiasptr=nearbias+desired2*i;
+ spinnit("biasing... ",v->points+v->entries-i);
+ /* due to the delayed sorting, we likely need to finish it off....*/
+ if(nearcount[i]>desired)
+ qsort(nearbiasptr,nearcount[i],sizeof(float),directdsort);
+ v->bias[i]=nearbiasptr[desired-1];
+ }
+ }else{
+ memset(v->bias,0,v->entries*sizeof(float));
+ }
+
+ /* Now assign with new bias and find new midpoints */
+ for(i=0;i<v->points;i++){
+ float *ppt=v->weight_func(v,_point(v,i));
+ float firstmetric=v->metric_func(v,_now(v,0),ppt)+v->bias[0];
+ long firstentry=0;
+
+ if(!(i&0xff))spinnit("centering... ",v->points-i);
+
+ for(j=0;j<v->entries;j++){
+ float thismetric=v->metric_func(v,_now(v,j),ppt)+v->bias[j];
+ if(thismetric<firstmetric){
+ firstmetric=thismetric;
+ firstentry=j;
+ }
+ }
+ j=firstentry;
+#ifdef NOISY
+ fprintf(cells,"%g %g\n%g %g\n\n",
+ _now(v,j)[0],_now(v,j)[1],
+ ppt[0],ppt[1]);
+#endif
+ firstmetric-=v->bias[j];
+ meterror+=firstmetric;
+ if(v->centroid==0){
+ /* set up midpoints for next iter */
+ if(v->assigned[j]++){
+ for(k=0;k<v->elements;k++)
+ vN(new,j)[k]+=ppt[k];
+ if(firstmetric>v->max[j])v->max[j]=firstmetric;
+ }else{
+ for(k=0;k<v->elements;k++)
+ vN(new,j)[k]=ppt[k];
+ v->max[j]=firstmetric;
+ }
+ }else{
+ /* centroid */
+ if(v->assigned[j]++){
+ for(k=0;k<v->elements;k++){
+ if(vN(new,j)[k]>ppt[k])vN(new,j)[k]=ppt[k];
+ if(vN(new2,j)[k]<ppt[k])vN(new2,j)[k]=ppt[k];
+ }
+ if(firstmetric>v->max[firstentry])v->max[j]=firstmetric;
+ }else{
+ for(k=0;k<v->elements;k++){
+ vN(new,j)[k]=ppt[k];
+ vN(new2,j)[k]=ppt[k];
+ }
+ v->max[firstentry]=firstmetric;
+ }
+ }
+ }
+ /* assign midpoints */
+
+ for(j=0;j<v->entries;j++){
+#ifdef NOISY
+ fprintf(assig,"%ld\n",v->assigned[j]);
+ fprintf(bias,"%g\n",v->bias[j]);
+#endif
+ asserror+=fabs(v->assigned[j]-fdesired);
+ if(v->assigned[j]){
+ if(v->centroid==0){
+ for(k=0;k<v->elements;k++)
+ _now(v,j)[k]=vN(new,j)[k]/v->assigned[j];
+ }else{
+ for(k=0;k<v->elements;k++)
+ _now(v,j)[k]=(vN(new,j)[k]+vN(new2,j)[k])/2.f;
+ }
+ }
+ }
+ asserror/=(v->entries*fdesired);
+ fprintf(stderr,"Pass #%d... ",v->it);
+ fprintf(stderr,": dist %g(%g) metric error=%g \n",
+ asserror,fdesired,meterror/v->points);
+ v->it++;
+ free(new);
+ free(nearcount);
+ free(nearbias);
+#ifdef NOISY
+ fclose(assig);
+ fclose(bias);
+ fclose(cells);
+#endif
+ return(asserror);
+}