From: Monty Date: Fri, 17 Dec 1999 13:19:36 +0000 (+0000) Subject: The vq book builder is mostly running now, but does not produce output yet. X-Git-Tag: v1.3.3~1316 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=441cd3b28cf27e13c53d9ff1d3ead0a26dd9b313;p=platform%2Fupstream%2Flibvorbis.git The vq book builder is mostly running now, but does not produce output yet. svn path=/trunk/vorbis/; revision=202 --- diff --git a/vq/Makefile.in b/vq/Makefile.in index f41ebe1..137f8cd 100644 --- a/vq/Makefile.in +++ b/vq/Makefile.in @@ -1,4 +1,4 @@ -# $Id: Makefile.in,v 1.1 1999/12/17 07:21:26 xiphmont Exp $ +# $Id: Makefile.in,v 1.2 1999/12/17 13:19:30 xiphmont Exp $ ############################################################################### # # @@ -27,8 +27,8 @@ LIBS=@LIBS@ -lm HFILES = vqgen.h vqext.h -OFILES = vqgen.o train.o -ALLOFILES = $(OFILES) lspdata.o +OFILES = vqgen.o vqsplit.o +ALLOFILES = $(OFILES) lspdata.o train.o build.o all: $(MAKE) target CFLAGS="$(OPT)" @@ -39,9 +39,12 @@ debug: profile: $(MAKE) target CFLAGS="$(PROFILE)" -target: lspvqtrain +target: lspvqtrain vqbuild -lspvqtrain: $(OFILES) lspdata.o +lspvqtrain: $(OFILES) lspdata.o train.o + $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS) + +vqbuild: $(OFILES) build.o $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS) $(ALLOFILES): $(HFILES) @@ -50,5 +53,5 @@ $(ALLOFILES): $(HFILES) $(CC) $(CFLAGS) -c $< clean: - -rm -f *.o *.a test* *~ *.out *.m config.*\ + -rm -f *.o *.a test* *~ *.out *.m config.* \ lspvqtrain diff --git a/vq/build.c b/vq/build.c index 0eac602..ed5ca71 100644 --- a/vq/build.c +++ b/vq/build.c @@ -14,7 +14,7 @@ function: utility main for building codebooks from training sets author: Monty modifications by: Monty - last modification date: Dec 14 1999 + last modification date: Dec 15 1999 ********************************************************************/ @@ -23,209 +23,177 @@ #include #include #include -#include #include "vqgen.h" -static int rline(FILE *in,FILE *out,char *line,int max,int pass){ - while(fgets(line,160,in)){ - if(line[0]=='#'){ - if(pass)fprintf(out,"%s",line); +static char *linebuffer=NULL; +static int lbufsize=0; +static char *rline(FILE *in,FILE *out,int pass){ + long sofar=0; + if(feof(in))return NULL; + + while(1){ + int gotline=0; + + while(!gotline){ + if(sofar>=lbufsize){ + if(!lbufsize){ + lbufsize=1024; + linebuffer=malloc(lbufsize); + }else{ + lbufsize*=2; + linebuffer=realloc(linebuffer,lbufsize); + } + } + { + long c=fgetc(in); + switch(c){ + case '\n': + case EOF: + gotline=1; + break; + default: + linebuffer[sofar++]=c; + linebuffer[sofar]='\0'; + break; + } + } + } + + if(linebuffer[0]=='#'){ + if(pass)fprintf(out,"%s",linebuffer); + sofar=0; }else{ - return(1); + return(linebuffer); } } - return(0); } /* command line: - buildvq vq=file out=file quant=n + buildvq file */ -int exiting=0; -void setexit(int dummy){ - fprintf(stderr,"\nexiting... please wait to finish this iteration\n"); - exiting=1; -} - int main(int argc,char *argv[]){ vqgen v; - int entries=-1,dim=-1; - char line[1024]; + vqbook b; + quant_return q; + int *quantlist=NULL; + + int entries=-1,dim=-1,quant=-1; + FILE *out=NULL; + FILE *in=NULL; + char *line,*name; long i,j,k; - int init=0; - while(*argv){ - - /* load the trained data */ - if(!strncmp(*argv,"vq=",3)){ - FILE *in=NULL; - char filename[80],*ptr; - if(sscanf(*argv,"vq=%70s",filename)!=1){ - fprintf(stderr,"Syntax error in argument '%s'\n",*argv); - exit(1); - } - - in=fopen(filename,"r"); - ptr=strrchr(filename,'-'); - if(ptr){ - int num; - ptr++; - num=atoi(ptr); - sprintf(ptr,"%d.vqi",num+1); - }else - strcat(filename,"-0.vqi"); - - out=fopen(filename,"w"); - if(out==NULL){ - fprintf(stderr,"Unable to open %s for writing\n",filename); - exit(1); - } - fprintf(out,"# OggVorbis VQ codebook trainer, intermediate file\n"); - - if(in){ - /* we wish to suck in a preexisting book and continue to train it */ - double a; - - rline(in,out,line,160,1); - if(sscanf(line,"%d %d %d",&entries,&dim,&met)!=3){ - fprintf(stderr,"Syntax error reading book file\n"); - exit(1); - } - - metric=set_metric(met); - vqgen_init(&v,dim,entries,metric,0.); - init=1; - - /* entries, bias, points */ - i=0; - for(j=0;jn){ - fprintf(stderr,"ran out of columns reading %s\n",file); - exit(1); - } - vqgen_addpoint(&v,b+start); + /* read book type, but it doesn't matter */ + line=rline(in,out,1); + + line=rline(in,out,1); + if(sscanf(line,"%d %d",&entries,&dim)!=2){ + fprintf(stderr,"Syntax error reading book file\n"); + exit(1); + } + + /* just use it to allocate mem */ + vqgen_init(&v,dim,entries,NULL); + + /* quant */ + line=rline(in,out,1); + if(sscanf(line,"%lf %lf %d %d",&q.minval,&q.delt, + &q.addtoquant,&quant)!=4){ + fprintf(stderr,"Syntax error reading book file\n"); + exit(1); + } + + /* quantized entries */ + /* save quant data; we can't regen it because the quant details + are specific to the data type */ + i=0; + quantlist=malloc(sizeof(int)*v.elements*v.entries); + for(j=0;j0)line[strlen(line)-1]='\0'; if(strcmp(line,vqext_booktype)){ fprintf(stderr,"wrong book type; %s!=%s\n",line,vqext_booktype); exit(1); @@ -149,7 +149,12 @@ int main(int argc,char *argv[]){ exit(1); } - /* entries */ + /* quantized entries */ + for(j=0;jelements*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){ int i; @@ -265,342 +257,3 @@ double vqgen_iterate(vqgen *v){ return(asserror); } - -/* Building a codebook from trained set ********************************** - - The codebook in raw form is technically finished once it's trained. - However, we want to finalize the representative codebook values for - each entry and generate auxiliary information to optimize encoding. - We generate the auxiliary coding tree using collected data, - probably the same data as in the original training */ - -/* At each recursion, the data set is split in half. Cells with data - points on side A go into set A, same with set B. The sets may - overlap. If the cell overlaps the deviding line only very slightly - (provided parameter), we may choose to ignore the overlap in order - to pare the tree down */ - -double *sortvals; -int els; -int iascsort(const void *a,const void *b){ - double av=sortvals[*((long *)a) * els]; - double bv=sortvals[*((long *)b) * els]; - if(avelements;k++) - position+=ppt[k]*n[k]; - if(position>0.){ - entryA[firstentry]++; - }else{ - entryB[firstentry]++; - } - } - - /* look to see if entries are in the slack zone */ - /* The entry splitting isn't total, so that storage has to be - allocated for recursion. Reuse the entryA/entryB vectors */ - for(j=0;jelements;k++){ - double center=(p[k]+q[k])/2.; - n[k]=(center-q[k])*2.; - *c+=center*n[k]; - } -} - -void pq_center_out(vqgen *v,double *n,double *c,double *center,double *q){ - int k; - *c=0.; - for(k=0;kelements;k++){ - n[k]=(center[k]-q[k])*2.; - *c+=center[k]*n[k]; - } -} - -int lp_split(vqgen *v,vqbook *b, - long *entryindex,long entries, - long *pointindex,long points, - long depth,double slack){ - - /* The encoder, regardless of book, will be using a straight - euclidian distance-to-point metric to determine closest point. - Thus we split the cells using the same (we've already trained the - codebook set spacing and distribution using special metrics and - even a midpoint division won't disturb the basic properties) */ - - long ret; - double *p; - double *q; - double *n; - double c; - long *entryA=calloc(entries,sizeof(long)); - long *entryB=calloc(entries,sizeof(long)); - long entriesA=0; - long entriesB=0; - long entriesC=0; - long pointsA=0; - long i,j,k; - - p=alloca(sizeof(double)*v->elements); - q=alloca(sizeof(double)*v->elements); - n=alloca(sizeof(double)*v->elements); - memset(p,0,sizeof(double)*v->elements); - - /* We need to find the dividing hyperplane. find the median of each - axis as the centerpoint and the normal facing farthest point */ - - /* more than one way to do this part. For small sets, we can brute - force it. */ - - if(entries<32){ - /* try every pair possibility */ - double best=0; - long besti=0; - long bestj=0; - double this; - for(i=0;ibest){ - best=this; - besti=i; - bestj=j; - } - } - } - pq_in_out(v,n,&c,_now(v,entryindex[besti]),_now(v,entryindex[bestj])); - }else{ - double best=0.; - long bestj=0; - - /* try COG/normal and furthest pairs */ - /* medianpoint */ - for(k=0;kelements;k++){ - /* just sort the index array */ - sortvals=v->pointlist+k; - els=v->elements; - qsort(pointindex,points,sizeof(long),iascsort); - if(points&0x1){ - p[k]=v->pointlist[(pointindex[points/2])*v->elements+k]; - }else{ - p[k]=(v->pointlist[(pointindex[points/2])*v->elements+k]+ - v->pointlist[(pointindex[points/2-1])*v->elements+k])/2.; - } - } - - /* try every normal, but just for distance */ - for(j=0;jbest){ - best=this; - bestj=j; - } - } - - pq_center_out(v,n,&c,p,_point(v,pointindex[bestj])); - - - } - - /* find cells enclosing points */ - /* count A/B points */ - - lp_count(v,entryindex,entries, - pointindex,points, - entryA,entryB, - n, c, slack, - &entriesA,&entriesB,&entriesC); - - /* the point index is split evenly, so we do an Order n - rearrangement into A first/B last and just pass it on */ - { - long Aptr=0; - long Bptr=points-1; - while(Aptr<=Bptr){ - while(Aptr<=Bptr){ - double position=-c; - for(k=0;kelements;k++) - position+=_point(v,pointindex[Aptr])[k]*n[k]; - if(position<=0.)break; /* not in A */ - Aptr++; - } - while(Aptr<=Bptr){ - double position=-c; - for(k=0;kelements;k++) - position+=_point(v,pointindex[Bptr])[k]*n[k]; - if(position>0.)break; /* not in B */ - Bptr--; - } - if(Aptraux++; - if(b->aux>=b->alloc){ - b->alloc*=2; - b->ptr0=realloc(b->ptr0,sizeof(long)*b->alloc); - b->ptr1=realloc(b->ptr1,sizeof(long)*b->alloc); - b->n=realloc(b->n,sizeof(double)*b->elements*b->alloc); - b->c=realloc(b->c,sizeof(double)*b->alloc); - } - - memcpy(b->n+b->elements*thisaux,n,sizeof(double)*v->elements); - b->c[thisaux]=c; - - if(entriesA==1){ - ret=1; - b->ptr0[thisaux]=entryA[0]; - }else{ - b->ptr0[thisaux]= -b->aux; - ret=lp_split(v,b,entryA,entriesA,pointindex,pointsA,depth+1,slack); - } - if(entriesB==1){ - ret++; - b->ptr1[thisaux]=entryB[0]; - }else{ - b->ptr1[thisaux]= -b->aux; - ret+=lp_split(v,b,entryB,entriesB,pointindex+pointsA,points-pointsA, - depth+1,slack); - } - } - free(entryA); - free(entryB); - return(ret); -} - -int vqenc_entry(vqbook *b,double *val){ - int ptr=0,k; - while(1){ - double c= -b->c[ptr]; - double *nptr=b->n+b->elements*ptr; - for(k=0;kelements;k++) - c+=nptr[k]*val[k]; - if(c>0.) /* in A */ - ptr= -b->ptr0[ptr]; - else /* in B */ - ptr= -b->ptr1[ptr]; - if(ptr<=0)break; - } - return(-ptr); -} - -void vqgen_book(vqgen *v,vqbook *b){ - long i; - long *entryindex=malloc(sizeof(double)*v->entries); - long *pointindex=malloc(sizeof(double)*v->points); - - memset(b,0,sizeof(vqbook)); - for(i=0;ientries;i++)entryindex[i]=i; - for(i=0;ipoints;i++)pointindex[i]=i; - b->elements=v->elements; - b->entries=v->entries; - b->alloc=4096; - b->ptr0=malloc(sizeof(long)*b->alloc); - b->ptr1=malloc(sizeof(long)*b->alloc); - b->n=malloc(sizeof(double)*b->elements*b->alloc); - b->c=malloc(sizeof(double)*b->alloc); - - b->valuelist=malloc(sizeof(double)*b->elements*b->entries); - b->codelist=malloc(sizeof(long)*b->entries); - b->lengthlist=malloc(b->entries*sizeof(long)); - - /* first, generate the encoding decision heirarchy */ - fprintf(stderr,"Total leaves: %d\n", - lp_split(v,b,entryindex,v->entries, pointindex,v->points,0,0)); - - /* run all training points through the decision tree to get a final - probability count */ - { - long *probability=calloc(b->entries*2,sizeof(long)); - for(i=0;ipoints;i++){ - int ret=vqenc_entry(b,v->pointlist+i*v->elements); - probability[ret]++; - } - - for(i=0;ientries;i++){ - fprintf(stderr,"point %ld: %ld\n",i,probability[i]); - } - - } - - /* generate the codewords (short to long) */ - - free(entryindex); - free(pointindex); -} - - - - - - - - - - - - - - diff --git a/vq/vqgen.h b/vq/vqgen.h index 3c20761..a592f78 100644 --- a/vq/vqgen.h +++ b/vq/vqgen.h @@ -36,6 +36,7 @@ typedef struct vqgen{ typedef struct vqbook{ long elements; long entries; + double *valuelist; long *codelist; long *lengthlist; @@ -52,14 +53,28 @@ typedef struct vqbook{ } vqbook; +typedef struct { + double minval; + double delt; + int addtoquant; +} quant_return; + +static inline double *_point(vqgen *v,long ptr){ + return v->pointlist+(v->elements*ptr); +} + +static inline double *_now(vqgen *v,long ptr){ + return v->entrylist+(v->elements*ptr); +} + extern void vqgen_init(vqgen *v,int elements,int entries, double (*metric)(vqgen *,double *, double *)); extern void vqgen_addpoint(vqgen *v, double *p); extern double *vqgen_midpoint(vqgen *v); extern double vqgen_iterate(vqgen *v); + +extern void vqsp_book(vqgen *v,vqbook *b); extern int vqenc_entry(vqbook *b,double *val); -extern void vqgen_book(vqgen *v,vqbook *b); -extern double *_now(vqgen *v,long ptr); #endif diff --git a/vq/vqsplit.c b/vq/vqsplit.c new file mode 100644 index 0000000..f453d0c --- /dev/null +++ b/vq/vqsplit.c @@ -0,0 +1,432 @@ +/******************************************************************** + * * + * 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. * + * * + * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-1999 * + * by 1999 Monty and The XIPHOPHORUS Company * + * http://www.xiph.org/ * + * * + ******************************************************************** + + function: build a VQ codebook + author: Monty + modifications by: Monty + last modification date: Dec 10 1999 + + ********************************************************************/ + +/* This code is *not* part of libvorbis. It is used to generate + trained codebooks offline and then spit the results into a + 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 +#include +#include +#include +#include "vqgen.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 +*/ + +/* Building a codebook from trained set ********************************** + + The codebook in raw form is technically finished once it's trained. + However, we want to finalize the representative codebook values for + each entry and generate auxiliary information to optimize encoding. + We generate the auxiliary coding tree using collected data, + probably the same data as in the original training */ + +/* At each recursion, the data set is split in half. Cells with data + points on side A go into set A, same with set B. The sets may + overlap. If the cell overlaps the deviding line only very slightly + (provided parameter), we may choose to ignore the overlap in order + to pare the tree down */ + +double *sortvals; +int els; +int iascsort(const void *a,const void *b){ + double av=sortvals[*((long *)a) * els]; + double bv=sortvals[*((long *)b) * els]; + if(avelements;k++) + position+=ppt[k]*n[k]; + if(position>0.){ + entryA[firstentry]++; + }else{ + entryB[firstentry]++; + } + } + + /* look to see if entries are in the slack zone */ + /* The entry splitting isn't total, so that storage has to be + allocated for recursion. Reuse the entryA/entryB vectors */ + for(j=0;jelements;k++){ + double center=(p[k]+q[k])/2.; + n[k]=(center-q[k])*2.; + *c+=center*n[k]; + } +} + +void pq_center_out(vqgen *v,double *n,double *c,double *center,double *q){ + int k; + *c=0.; + for(k=0;kelements;k++){ + n[k]=(center[k]-q[k])*2.; + *c+=center[k]*n[k]; + } +} + +int lp_split(vqgen *v,vqbook *b, + long *entryindex,long entries, + long *pointindex,long points, + long depth,double slack){ + + /* The encoder, regardless of book, will be using a straight + euclidian distance-to-point metric to determine closest point. + Thus we split the cells using the same (we've already trained the + codebook set spacing and distribution using special metrics and + even a midpoint division won't disturb the basic properties) */ + + long ret; + double *p; + double *q; + double *n; + double c; + long *entryA=calloc(entries,sizeof(long)); + long *entryB=calloc(entries,sizeof(long)); + long entriesA=0; + long entriesB=0; + long entriesC=0; + long pointsA=0; + long i,j,k; + + p=alloca(sizeof(double)*v->elements); + q=alloca(sizeof(double)*v->elements); + n=alloca(sizeof(double)*v->elements); + memset(p,0,sizeof(double)*v->elements); + + /* We need to find the dividing hyperplane. find the median of each + axis as the centerpoint and the normal facing farthest point */ + + /* more than one way to do this part. For small sets, we can brute + force it. */ + + if(entries<32){ + /* try every pair possibility */ + double best=0; + long besti=0; + long bestj=0; + double this; + for(i=0;ibest){ + best=this; + besti=i; + bestj=j; + } + } + } + pq_in_out(v,n,&c,_now(v,entryindex[besti]),_now(v,entryindex[bestj])); + }else{ + double best=0.; + long bestj=0; + + /* try COG/normal and furthest pairs */ + /* medianpoint */ + for(k=0;kelements;k++){ + /* just sort the index array */ + sortvals=v->pointlist+k; + els=v->elements; + qsort(pointindex,points,sizeof(long),iascsort); + if(points&0x1){ + p[k]=v->pointlist[(pointindex[points/2])*v->elements+k]; + }else{ + p[k]=(v->pointlist[(pointindex[points/2])*v->elements+k]+ + v->pointlist[(pointindex[points/2-1])*v->elements+k])/2.; + } + } + + /* try every normal, but just for distance */ + for(j=0;jbest){ + best=this; + bestj=j; + } + } + + pq_center_out(v,n,&c,p,_point(v,pointindex[bestj])); + + + } + + /* find cells enclosing points */ + /* count A/B points */ + + vqsp_count(v,entryindex,entries, + pointindex,points, + entryA,entryB, + n, c, slack, + &entriesA,&entriesB,&entriesC); + + /* the point index is split evenly, so we do an Order n + rearrangement into A first/B last and just pass it on */ + { + long Aptr=0; + long Bptr=points-1; + while(Aptr<=Bptr){ + while(Aptr<=Bptr){ + double position=-c; + for(k=0;kelements;k++) + position+=_point(v,pointindex[Aptr])[k]*n[k]; + if(position<=0.)break; /* not in A */ + Aptr++; + } + while(Aptr<=Bptr){ + double position=-c; + for(k=0;kelements;k++) + position+=_point(v,pointindex[Bptr])[k]*n[k]; + if(position>0.)break; /* not in B */ + Bptr--; + } + if(Aptraux++; + if(b->aux>=b->alloc){ + b->alloc*=2; + b->ptr0=realloc(b->ptr0,sizeof(long)*b->alloc); + b->ptr1=realloc(b->ptr1,sizeof(long)*b->alloc); + b->n=realloc(b->n,sizeof(double)*b->elements*b->alloc); + b->c=realloc(b->c,sizeof(double)*b->alloc); + } + + memcpy(b->n+b->elements*thisaux,n,sizeof(double)*v->elements); + b->c[thisaux]=c; + + if(entriesA==1){ + ret=1; + b->ptr0[thisaux]=entryA[0]; + }else{ + b->ptr0[thisaux]= -b->aux; + ret=lp_split(v,b,entryA,entriesA,pointindex,pointsA,depth+1,slack); + } + if(entriesB==1){ + ret++; + b->ptr1[thisaux]=entryB[0]; + }else{ + b->ptr1[thisaux]= -b->aux; + ret+=lp_split(v,b,entryB,entriesB,pointindex+pointsA,points-pointsA, + depth+1,slack); + } + } + free(entryA); + free(entryB); + return(ret); +} + +void vqsp_book(vqgen *v, vqbook *b){ + long *entryindex=malloc(sizeof(double)*v->entries); + long *pointindex=malloc(sizeof(double)*v->points); + long i; + + memset(b,0,sizeof(vqbook)); + for(i=0;ientries;i++)entryindex[i]=i; + for(i=0;ipoints;i++)pointindex[i]=i; + + b->elements=v->elements; + b->entries=v->entries; + b->alloc=4096; + b->ptr0=malloc(sizeof(long)*b->alloc); + b->ptr1=malloc(sizeof(long)*b->alloc); + b->n=malloc(sizeof(double)*b->elements*b->alloc); + b->c=malloc(sizeof(double)*b->alloc); + + b->valuelist=v->entrylist; + b->codelist=malloc(sizeof(long)*b->entries); + b->lengthlist=calloc(b->entries,sizeof(long)); + + /* first, generate the encoding decision heirarchy */ + fprintf(stderr,"Total leaves: %d\n", + lp_split(v,b,entryindex,v->entries, pointindex,v->points,0,0)); + + /* run all training points through the decision tree to get a final + probability count */ + { + long *probability=calloc(b->entries,sizeof(long)); + long *membership=malloc(b->entries*sizeof(long)); + long j; + + for(i=0;ipoints;i++){ + int ret=vqenc_entry(b,v->pointlist+i*v->elements); + probability[ret]++; + } + for(i=0;ientries;i++)membership[i]=i; + + /* find codeword lengths */ + /* much more elegant means exist. Brute force n^2, minimum thought */ + for(i=v->entries;i>1;i--){ + int first=-1,second=-1; + long least=v->points+1; + + /* find the two nodes to join */ + for(j=0;jentries;j++) + if(probability[j]points+1; + for(j=0;jentries;j++) + if(probability[j]entries;j++) + if(membership[j]==first || membership[j]==second){ + membership[j]=first; + probability[j]=least; + b->lengthlist[j]++; + } + } + for(i=0;ientries-1;i++) + if(membership[i]!=membership[i+1]){ + fprintf(stderr,"huffman fault; failed to build single tree\n"); + exit(1); + } + + /* unneccessary metric */ + memset(probability,0,sizeof(long)*v->entries); + for(i=0;ipoints;i++){ + int ret=vqenc_entry(b,v->pointlist+i*v->elements); + probability[ret]++; + } + + /* print the results */ + for(i=0;ientries;i++) + fprintf(stderr,"%d: count=%ld codelength=%d\n",i,probability[i],b->lengthlist[i]); + + free(probability); + free(membership); + } + + /* rearrange, sort by codelength */ + + + /* generate the codewords (short to long) */ + + + free(entryindex); + free(pointindex); +} + +int vqenc_entry(vqbook *b,double *val){ + int ptr=0,k; + while(1){ + double c= -b->c[ptr]; + double *nptr=b->n+b->elements*ptr; + for(k=0;kelements;k++) + c+=nptr[k]*val[k]; + if(c>0.) /* in A */ + ptr= -b->ptr0[ptr]; + else /* in B */ + ptr= -b->ptr1[ptr]; + if(ptr<=0)break; + } + return(-ptr); +} + + + +