Incremental update
authorMonty <xiphmont@xiph.org>
Thu, 16 Dec 1999 09:24:54 +0000 (09:24 +0000)
committerMonty <xiphmont@xiph.org>
Thu, 16 Dec 1999 09:24:54 +0000 (09:24 +0000)
svn path=/trunk/vorbis/; revision=198

vq/lspdata.c [new file with mode: 0644]
vq/train.c
vq/vqext.h [new file with mode: 0644]
vq/vqgen.c
vq/vqgen.h

diff --git a/vq/lspdata.c b/vq/lspdata.c
new file mode 100644 (file)
index 0000000..6c24603
--- /dev/null
@@ -0,0 +1,117 @@
+/********************************************************************
+ *                                                                  *
+ * 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 <monty@xiph.org> and The XIPHOPHORUS Company       *
+ * http://www.xiph.org/                                             *
+ *                                                                  *
+ ********************************************************************
+
+ function: metrics and quantization code for LSP VQ codebooks
+ author: Monty <xiphmont@mit.edu>
+ modifications by: Monty
+ last modification date: Dec 15 1999
+
+ ********************************************************************/
+
+#include <math.h>
+#include <stdio.h>
+#include "vqgen.h"
+#include "vqext.h"
+
+char *vqext_booktype="LSPdata";
+
+/* LSP training metric.  We weight error proportional to distance
+   *between* LSP vector values */
+
+                            /* candidate,actual */
+double vqext_metric(vqgen *v,double *b, double *a){
+  int i;
+  int el=v->elements;
+  double acc=0.;
+  double lasta=0.;
+  /*double lastb=0.;*/
+  for(i=0;i<el;i++){
+    double actualdist=(a[i]-lasta);
+    /*double testdist=(b[i]-lastb);
+
+      double disterr=fabs(testdist-actualdist);*/
+    double poserr=fabs(a[i]-b[i]);
+    acc+=poserr/actualdist;
+
+    lasta=a[i];
+    /*lastb=b[i];*/
+  }
+  return acc;
+}
+
+/* LSP quantizes all absolute values, but the book encodes distance
+   between values (which has a smaller range).  Thus the desired
+   quantibits apply to the encoded (delta) values, not abs
+   positions. This requires minor additional trickery. */
+
+quant_return vqext_quantize(vqgen *v,int quantbits){
+  quant_return q;
+  double maxval=0.;
+  double maxdel;
+  double mindel;
+  double delta;
+  double fullrangevals;
+  double maxquant=((1<<quantbits)-1);
+  int j,k;
+
+  mindel=maxdel=_now(v,0)[0];
+  
+  for(j=0;j<v->entries;j++){
+    double last=0.;
+    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(maxval<_now(v,j)[k])maxval=_now(v,j)[k];
+      last=_now(v,j)[k];
+    }
+  }
+
+  q.minval=0.;
+  delta=(maxdel-mindel)/((1<<quantbits)-2);
+  fullrangevals=floor(maxval/delta);
+  q.delt=delta=maxval/fullrangevals;
+  q.addtoquant=floor(mindel/delta);
+
+  for(j=0;j<v->entries;j++){
+    double last=0.;
+    for(k=0;k<v->elements;k++){
+      double val=_now(v,j)[k];
+      double now=rint(val/delta);
+      double test=_now(v,j)[k]=now-last-q.addtoquant;
+
+      if(test<0){
+       fprintf(stderr,"fault; quantized value<0\n");
+       exit(1);
+      }
+
+      if(test>maxquant){
+       fprintf(stderr,"fault; quantized value>max\n");
+       exit(1);
+      }
+      last=now;
+    }
+  }
+  return(q);
+}
+
+/* much easier :-) */
+void vqext_unquantize(vqgen *v,quant_return *q){
+  long j,k;
+  for(j=0;j<v->entries;j++){
+    double last=0.;
+    for(k=0;k<v->elements;k++){
+      last=(_now(v,j)[k]+q->addtoquant)*q->delt+q->minval+last;
+      _now(v,j)[k]=last;
+    }
+  }
+}
index 4c0eddf..82a8faf 100644 (file)
@@ -14,7 +14,7 @@
  function: utility main for training codebooks
  author: Monty <xiphmont@mit.edu>
  modifications by: Monty
- last modification date: Dec 14 1999
+ last modification date: Dec 15 1999
 
  ********************************************************************/
 
 #include <errno.h>
 #include <signal.h>
 #include "vqgen.h"
-
-/* A metric for LSP codes */
-                            /* candidate,actual */
-static double _dist_and_pos(vqgen *v,double *b, double *a){
-  int i;
-  int el=v->elements;
-  double acc=0.;
-  double lastb=0.;
-  for(i=0;i<el;i++){
-    double actualdist=(a[i]-lastb);
-    double testdist=(b[i]-lastb);
-    if(actualdist>0 && testdist>0){
-      double val;
-      if(actualdist>testdist)
-       val=actualdist/testdist-1.;
-      else
-       val=testdist/actualdist-1.;
-      acc+=val;
-    }else{
-      acc+=999999.;
-    }
-    lastb=b[i];
-  }
-  return acc;
-}
-
-static void *set_metric(int m){
-  switch(m){
-  case 0:
-    return(NULL);
-  case 1:
-    return(_dist_and_pos);
-  default:
-    fprintf(stderr,"Invalid metric number\n");
-    exit(0);
-  }
-}
+#include "vqext.h"
 
 static int rline(FILE *in,FILE *out,char *line,int max,int pass){
   while(fgets(line,160,in)){
@@ -75,7 +39,7 @@ static int rline(FILE *in,FILE *out,char *line,int max,int pass){
 }
 
 /* command line:
-   trainvq [vq=file | [entries=n] [dim=n] [quant=n]] met=n in=file,firstcol 
+   trainvq [vq=file | [entries=n] [dim=n] [quant=n]] in=file,firstcol 
            [in=file,firstcol]
 */
 
@@ -87,10 +51,10 @@ void setexit(int dummy){
 
 int main(int argc,char *argv[]){
   vqgen v;
+  quant_return q;
+
   int entries=-1,dim=-1,quant=-1;
   FILE *out=NULL;
-  int met=0;
-  double (*metric)(vqgen *,double *, double *)=NULL;
   char line[1024];
   long i,j,k;
 
@@ -124,23 +88,37 @@ int main(int argc,char *argv[]){
        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(strlen(line)>0)line[strlen(line)-1]='\0';
+       if(strcmp(line,vqext_booktype)){
+         fprintf(stderr,"wrong book type; %s!=%s\n",line,vqext_booktype);
+         exit(1);
+       } 
            
        rline(in,out,line,160,1);
-       if(sscanf(line,"%d %d %d %d",&entries,&dim,&met,&quant)!=3){
+       if(sscanf(line,"%d %d",&entries,&dim)!=2){
          fprintf(stderr,"Syntax error reading book file\n");
          exit(1);
        }
+       
 
-       metric=set_metric(met);
-       vqgen_init(&v,dim,entries,metric,quant);
+       vqgen_init(&v,dim,entries,vqext_metric);
        init=1;
 
-       /* entries, bias, points */
+       /* quant setup */
+       rline(in,out,line,160,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);
+       }
+
+       /* entries */
        i=0;
        for(j=0;j<entries;j++){
          for(k=0;k<dim;k++){
@@ -149,7 +127,11 @@ int main(int argc,char *argv[]){
            v.entrylist[i++]=a;
          }
        }
+       
+       /* dequantize */
+       vqext_unquantize(&v,&q);
 
+       /* bias, points */
        i=0;
        for(j=0;j<entries;j++){
          rline(in,out,line,160,0);
@@ -183,17 +165,14 @@ int main(int argc,char *argv[]){
     if(!strncmp(*argv,"entries=",8)){
       sscanf(*argv,"entries=%d",&entries);
     }
-    if(!strncmp(*argv,"desired=",8)){
-      sscanf(*argv,"desired=%lf",&desired);
-    }
     if(!strncmp(*argv,"dim=",4)){
       sscanf(*argv,"dim=%d",&dim);
     }
-
-    /* which error metric (0==euclidian distance default) */
-    if(!strncmp(*argv,"met=",4)){
-      sscanf(*argv,"met=%d",&met);
-      metric=set_metric(met);
+    if(!strncmp(*argv,"desired=",8)){
+      sscanf(*argv,"desired=%lf",&desired);
+    }
+    if(!strncmp(*argv,"iter=",5)){
+      sscanf(*argv,"iter=%d",&iter);
     }
 
     if(!strncmp(*argv,"in=",3)){
@@ -212,7 +191,7 @@ int main(int argc,char *argv[]){
                  " first input file\n");
          exit(1);
        }
-       vqgen_init(&v,dim,entries,metric,quant);
+       vqgen_init(&v,dim,entries,vqext_metric);
        init=1;
       }
 
@@ -246,12 +225,19 @@ int main(int argc,char *argv[]){
   signal(SIGINT,setexit);
 
   for(i=0;i<iter && !exiting;i++){
-    if(vqgen_iterate(&v)<desired)break;
+    double result;
+    if(i!=0)vqext_unquantize(&v,&q);
+    result=vqgen_iterate(&v);
+    q=vqext_quantize(&v,quant);
+    if(result<desired)break;
   }
 
   /* save the book */
 
-  fprintf(out,"%d %d %d %d\n",entries,dim,met,quant);
+  fprintf(out,"# OggVorbis VQ codebook trainer, intermediate file\n");
+  fprintf(out,"%s\n",vqext_booktype);
+  fprintf(out,"%d %d\n",entries,dim);
+  fprintf(out,"%g %g %d %d\n",q.minval,q.delt,q.addtoquant,quant);
 
   i=0;
   for(j=0;j<entries;j++)
diff --git a/vq/vqext.h b/vq/vqext.h
new file mode 100644 (file)
index 0000000..6f414b2
--- /dev/null
@@ -0,0 +1,34 @@
+/********************************************************************
+ *                                                                  *
+ * 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 <monty@xiph.org> and The XIPHOPHORUS Company       *
+ * http://www.xiph.org/                                             *
+ *                                                                  *
+ ********************************************************************
+
+ function: prototypes for extermal metrics specific to data type
+
+ ********************************************************************/
+
+#ifndef _V_VQEXT_
+#define _V_VQEXT_
+
+#include "vqgen.h"
+
+extern char *vqext_booktype;
+typedef struct {
+  double minval;
+  double delt;
+  int    addtoquant;
+} quant_return;
+
+extern double vqext_metric(vqgen *v,double *b, double *a);
+extern quant_return vqext_quantize(vqgen *v,int quantbits);
+extern void vqext_unquantize(vqgen *v,quant_return *q);
+
+#endif
index 2b972b5..0c2f39f 100644 (file)
@@ -85,12 +85,10 @@ void _vqgen_seed(vqgen *v){
 /* External calls *******************************************************/
 
 void vqgen_init(vqgen *v,int elements,int entries,
-               double (*metric)(vqgen *,double *, double *),
-               int quant){
+               double (*metric)(vqgen *,double *, double *)){
   memset(v,0,sizeof(vqgen));
 
   v->elements=elements;
-  v->quantbits=quant;
   v->allocated=32768;
   v->pointlist=malloc(v->allocated*v->elements*sizeof(double));
 
@@ -251,29 +249,6 @@ double vqgen_iterate(vqgen *v){
 #endif
   }
 
-  {
-    /* midpoints must be quantized.  but we need to know the range in
-       order to do so */
-    double min,max;
-   
-    for(k=0;k<v->elements;k++){
-      double delta;
-      min=max=_now(v,0)[k];
-
-      for(j=1;j<v->entries;j++){
-       double val=_now(v,j)[k];
-       if(val<min)min=val;
-       if(val>max)max=val;
-      }
-    
-      delta=(max-min)/((1<<v->quantbits)-1);
-      for(j=0;j<v->entries;j++){
-       double val=_now(v,j)[k];
-       _now(v,j)[k]=min+delta*rint((val-min)/delta);
-      }
-    }
-  }
-
   asserror/=(v->entries*fdesired);
   fprintf(stderr,": dist %g(%g) metric error=%g \n",
          asserror,fdesired,meterror/v->points);
@@ -592,7 +567,7 @@ void vqgen_book(vqgen *v,vqbook *b){
   b->lengthlist=malloc(b->entries*sizeof(long));
   
   /* first, generate the encoding decision heirarchy */
-  fprintf(stderr,"Total leaves: %ld\n",
+  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
index 6fcc54d..3c20761 100644 (file)
@@ -18,7 +18,6 @@ typedef struct vqgen{
   int it;
 
   int    elements;
-  int    quantbits;
 
   /* point cache */
   double *pointlist; 
@@ -54,13 +53,13 @@ typedef struct vqbook{
 } vqbook;
 
 extern void vqgen_init(vqgen *v,int elements,int entries,
-                      double (*metric)(vqgen *,double *, double *),
-                      int quant);
+                      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 int vqenc_entry(vqbook *b,double *val);
 extern void vqgen_book(vqgen *v,vqbook *b);
+extern double *_now(vqgen *v,long ptr);
 
 #endif