1 /********************************************************************
3 * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
5 * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
6 * PLEASE READ THESE TERMS DISTRIBUTING. *
8 * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-1999 *
9 * by 1999 Monty <monty@xiph.org> and The XIPHOPHORUS Company *
10 * http://www.xiph.org/ *
12 ********************************************************************
14 function: build a VQ codebook
15 author: Monty <xiphmont@mit.edu>
16 modifications by: Monty
17 last modification date: Nov 09 1999
19 ********************************************************************/
21 /* This code is *not* part of libvorbis. It is used to generate
22 trained codebooks offline and then spit the results into a
23 pregenerated codebook that is compiled into libvorbis. It is an
24 expensive (but good) algorithm. Run it on big iron. */
48 double (*error_func) (struct vqgen *v,double *a,double *b);
52 /*************************************************************************
53 * Vector quantization is a *bit* like an n-body problem in
54 * m-dimensional space implemented as a monte-carlo simulation. But
55 * not really. We're first-order only, and the 'forces' are
56 * attractive or repulsive. Think 'xspringies' but without velocity or
59 /* internal helpers *****************************************************/
60 double *_point(vqgen *v,long ptr){
61 return v->pointlist+(v->elements*ptr);
64 double *_now(vqgen *v,long ptr){
65 return v->entry_now+(v->elements*ptr);
68 double *_next(vqgen *v,long ptr){
69 return v->entry_next+(v->elements*ptr);
72 double _error_func(vqgen *v,double *a, double *b){
77 acc+=(a[i]-b[i])*(a[i]-b[i]);
81 void vqgen_init(vqgen *v,int elements,int entries){
82 memset(v,0,sizeof(vqgen));
86 v->pointlist=malloc(v->allocated*v->elements*sizeof(double));
89 v->entry_now=malloc(v->entries*v->elements*sizeof(double));
90 v->entry_next=malloc(v->entries*v->elements*sizeof(double));
91 v->assigned=malloc(v->entries*sizeof(long));
92 v->error=malloc(v->entries*sizeof(double));
93 v->bias=malloc(v->entries*sizeof(double));
96 for(i=0;i<v->entries;i++)
102 v->error_func=_error_func;
105 void _vqgen_seed(vqgen *v){
106 memcpy(v->entry_now,v->pointlist,sizeof(double)*v->entries*v->elements);
109 void vqgen_addpoint(vqgen *v, double *p){
110 if(v->points>=v->allocated){
112 v->pointlist=realloc(v->pointlist,v->allocated*v->elements*sizeof(double));
115 memcpy(_point(v,v->points),p,sizeof(double)*v->elements);
117 if(v->points==v->entries)_vqgen_seed(v);
120 void vqgen_iterate(vqgen *v){
121 static int iteration=0;
131 sprintf(name,"space%d.m",iteration);
132 graph=fopen(name,"w");
134 sprintf(name,"err%d.m",iteration);
137 sprintf(name,"bias%d.m",iteration);
138 bias=fopen(name,"w");
142 memset(v->entry_next,0,sizeof(double)*v->elements*v->entries);
143 memset(v->assigned,0,sizeof(long)*v->entries);
144 memset(v->error,0,sizeof(double)*v->entries);
146 /* assign all the points, accumulate error */
147 for(i=0;i<v->points;i++){
148 double besterror=v->error_func(v,_now(v,0),_point(v,i))*v->bias[0];
150 for(j=1;j<v->entries;j++){
151 double thiserror=v->error_func(v,_now(v,j),_point(v,i))*v->bias[j];
152 if(thiserror<besterror){
158 v->error[bestentry]+=v->error_func(v,_now(v,bestentry),_point(v,i));
159 v->assigned[bestentry]++;
161 double *n=_next(v,bestentry);
162 double *p=_point(v,i);
163 for(j=0;j<v->elements;j++)
168 double *n=_now(v,bestentry);
169 double *p=_point(v,i);
170 fprintf(graph,"%g %g\n%g %g\n\n",p[0],p[1],n[0],n[1]);
175 for(i=0;i<v->entries;i++){
176 double *next=_next(v,i);
177 double *now=_now(v,i);
179 for(j=0;j<v->elements;j++)
180 next[j]/=v->assigned[i];
182 for(j=0;j<v->elements;j++)
187 /* average global error */
188 for(i=0;i<v->entries;i++)
189 averror+=v->error[i];
193 /* positive/negative 'pressure' */
196 for(i=0;i<v->entries;i++){
199 bias=1.+ (averror-v->error[i])/v->error[i];
207 for(i=0;i<v->entries;i++)
211 /* dump state, report error */
212 for(i=0;i<v->entries;i++){
213 fprintf(err,"%g\n",v->error[i]);
214 fprintf(bias,"%g\n",v->bias[i]);
217 fprintf(stderr,"average error: %g\n",averror);
222 memcpy(v->entry_now,v->entry_next,sizeof(double)*v->entries*v->elements);
226 int main(int argc,char *argv[]){
227 FILE *in=fopen(argv[1],"r");
232 vqgen_init(&v,2,128);
234 while(fgets(buffer,80,in)){
236 if(sscanf(buffer,"%lf %lf",a,a+1)==2)
237 vqgen_addpoint(&v,a);