summaryrefslogtreecommitdiff
path: root/vq/latticehint.c
diff options
context:
space:
mode:
Diffstat (limited to 'vq/latticehint.c')
-rw-r--r--vq/latticehint.c430
1 files changed, 0 insertions, 430 deletions
diff --git a/vq/latticehint.c b/vq/latticehint.c
deleted file mode 100644
index d6ef8fe0..00000000
--- a/vq/latticehint.c
+++ /dev/null
@@ -1,430 +0,0 @@
-/********************************************************************
- * *
- * 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 OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 *
- * by the XIPHOPHORUS Company http://www.xiph.org/ *
- * *
- ********************************************************************
-
- function: utility main for building thresh/pigeonhole encode hints
- last mod: $Id: latticehint.c,v 1.12 2001/12/20 01:00:39 segher Exp $
-
- ********************************************************************/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <math.h>
-#include <string.h>
-#include <errno.h>
-#include "../lib/scales.h"
-#include "bookutil.h"
-#include "vqgen.h"
-#include "vqsplit.h"
-
-/* The purpose of this util is to build encode hints for lattice
- codebooks so that brute forcing each codebook entry isn't needed.
- Threshhold hints are for books in which each scalar in the vector
- is independant (eg, residue) and pigeonhole lookups provide a
- minimum error fit for words where the scalars are interdependant
- (each affecting the fit of the next in sequence) as in an LSP
- sequential book (or can be used along with a sparse threshhold map,
- like a splitting tree that need not be trained)
-
- If the input book is non-sequential, a threshhold hint is built.
- If the input book is sequential, a pigeonholing hist is built.
- If the book is sparse, a pigeonholing hint is built, possibly in addition
- to the threshhold hint
-
- command line:
- latticehint book.vqh [threshlist]
-
- latticehint produces book.vqh on stdout */
-
-static int longsort(const void *a, const void *b){
- return(**((long **)a)-**((long **)b));
-}
-
-static int addtosearch(int entry,long **tempstack,long *tempcount,int add){
- long *ptr=tempstack[entry];
- long i=tempcount[entry];
-
- if(ptr){
- while(i--)
- if(*ptr++==add)return(0);
- tempstack[entry]=_ogg_realloc(tempstack[entry],
- (tempcount[entry]+1)*sizeof(long));
- }else{
- tempstack[entry]=_ogg_malloc(sizeof(long));
- }
-
- tempstack[entry][tempcount[entry]++]=add;
- return(1);
-}
-
-static void setvals(int dim,encode_aux_pigeonhole *p,
- long *temptrack,float *tempmin,float *tempmax,
- int seqp){
- int i;
- float last=0.f;
- for(i=0;i<dim;i++){
- tempmin[i]=(temptrack[i])*p->del+p->min+last;
- tempmax[i]=tempmin[i]+p->del;
- if(seqp)last=tempmin[i];
- }
-}
-
-/* note that things are currently set up such that input fits that
- quantize outside the pigeonmap are dropped and brute-forced. So we
- can ignore the <0 and >=n boundary cases in min/max error */
-
-static float minerror(int dim,float *a,encode_aux_pigeonhole *p,
- long *temptrack,float *tempmin,float *tempmax){
- int i;
- float err=0.f;
- for(i=0;i<dim;i++){
- float eval=0.f;
- if(a[i]<tempmin[i]){
- eval=tempmin[i]-a[i];
- }else if(a[i]>tempmax[i]){
- eval=a[i]-tempmax[i];
- }
- err+=eval*eval;
- }
- return(err);
-}
-
-static float maxerror(int dim,float *a,encode_aux_pigeonhole *p,
- long *temptrack,float *tempmin,float *tempmax){
- int i;
- float err=0.f,eval;
- for(i=0;i<dim;i++){
- if(a[i]<tempmin[i]){
- eval=tempmax[i]-a[i];
- }else if(a[i]>tempmax[i]){
- eval=a[i]-tempmin[i];
- }else{
- float t1=a[i]-tempmin[i];
- eval=tempmax[i]-a[i];
- if(t1>eval)eval=t1;
- }
- err+=eval*eval;
- }
- return(err);
-}
-
-int main(int argc,char *argv[]){
- codebook *b;
- static_codebook *c;
- int entries=-1,dim=-1;
- float min,del;
- char *name;
- long i,j;
- float *suggestions;
- int suggcount=0;
-
- if(argv[1]==NULL){
- fprintf(stderr,"Need a lattice book on the command line.\n");
- exit(1);
- }
-
- {
- char *ptr;
- char *filename=strdup(argv[1]);
-
- b=codebook_load(filename);
- c=(static_codebook *)(b->c);
-
- ptr=strrchr(filename,'.');
- if(ptr){
- *ptr='\0';
- name=strdup(filename);
- }else{
- name=strdup(filename);
- }
- }
-
- if(c->maptype!=1){
- fprintf(stderr,"Provided book is not a latticebook.\n");
- exit(1);
- }
-
- entries=b->entries;
- dim=b->dim;
- min=_float32_unpack(c->q_min);
- del=_float32_unpack(c->q_delta);
-
- /* Do we want to gen a threshold hint? */
- if(c->q_sequencep==0){
- /* yes. Discard any preexisting threshhold hint */
- long quantvals=_book_maptype1_quantvals(c);
- long **quantsort=alloca(quantvals*sizeof(long *));
- encode_aux_threshmatch *t=_ogg_calloc(1,sizeof(encode_aux_threshmatch));
- c->thresh_tree=t;
-
- fprintf(stderr,"Adding threshold hint to %s...\n",name);
-
- /* partial/complete suggestions */
- if(argv[2]){
- char *ptr=strdup(argv[2]);
- suggestions=alloca(sizeof(float)*quantvals);
-
- for(suggcount=0;ptr && suggcount<quantvals;suggcount++){
- char *ptr2=strchr(ptr,',');
- if(ptr2)*ptr2++='\0';
- suggestions[suggcount]=atof(ptr);
- ptr=ptr2;
- }
- }
-
- /* simplest possible threshold hint only */
- t->quantthresh=_ogg_calloc(quantvals-1,sizeof(float));
- t->quantmap=_ogg_calloc(quantvals,sizeof(int));
- t->threshvals=quantvals;
- t->quantvals=quantvals;
-
- /* the quantvals may not be in order; sort em first */
- for(i=0;i<quantvals;i++)quantsort[i]=c->quantlist+i;
- qsort(quantsort,quantvals,sizeof(long *),longsort);
-
- /* ok, gen the map and thresholds */
- for(i=0;i<quantvals;i++)t->quantmap[i]=quantsort[i]-c->quantlist;
- for(i=0;i<quantvals-1;i++){
- float v1=*(quantsort[i])*del+min;
- float v2=*(quantsort[i+1])*del+min;
-
- for(j=0;j<suggcount;j++)
- if(v1<suggestions[j] && suggestions[j]<v2){
- t->quantthresh[i]=suggestions[j];
- break;
- }
-
- if(j==suggcount){
- t->quantthresh[i]=(v1+v2)*.5;
- }
- }
- }
-
- /* Do we want to gen a pigeonhole hint? */
-#if 0
- for(i=0;i<entries;i++)if(c->lengthlist[i]==0)break;
- if(c->q_sequencep || i<entries){
- long **tempstack;
- long *tempcount;
- long *temptrack;
- float *tempmin;
- float *tempmax;
- long totalstack=0;
- long pigeons;
- long subpigeons;
- long quantvals=_book_maptype1_quantvals(c);
- int changep=1,factor;
-
- encode_aux_pigeonhole *p=_ogg_calloc(1,sizeof(encode_aux_pigeonhole));
- c->pigeon_tree=p;
-
- fprintf(stderr,"Adding pigeonhole hint to %s...\n",name);
-
- /* the idea is that we quantize uniformly, even in a nonuniform
- lattice, so that quantization of one scalar has a predictable
- result on the next sequential scalar in a greedy matching
- algorithm. We generate a lookup based on the quantization of
- the vector (pigeonmap groups quantized entries together) and
- list the entries that could possible be the best fit for any
- given member of that pigeonhole. The encode process then has a
- much smaller list to brute force */
-
- /* find our pigeonhole-specific quantization values, fill in the
- quant value->pigeonhole map */
- factor=3;
- p->del=del;
- p->min=min;
- p->quantvals=quantvals;
- {
- int max=0;
- for(i=0;i<quantvals;i++)if(max<c->quantlist[i])max=c->quantlist[i];
- p->mapentries=max;
- }
- p->pigeonmap=_ogg_malloc(p->mapentries*sizeof(long));
- p->quantvals=(quantvals+factor-1)/factor;
-
- /* pigeonhole roughly on the boundaries of the quantvals; the
- exact pigeonhole grouping is an optimization issue, not a
- correctness issue */
- for(i=0;i<p->mapentries;i++){
- float thisval=del*i+min; /* middle of the quant zone */
- int quant=0;
- float err=fabs(c->quantlist[0]*del+min-thisval);
- for(j=1;j<quantvals;j++){
- float thiserr=fabs(c->quantlist[j]*del+min-thisval);
- if(thiserr<err){
- quant=j/factor;
- err=thiserr;
- }
- }
- p->pigeonmap[i]=quant;
- }
-
- /* pigeonmap complete. Now do the grungy business of finding the
- entries that could possibly be the best fit for a value appearing
- in the pigeonhole. The trick that allows the below to work is the
- uniform quantization; even though the scalars may be 'sequential'
- (each a delta from the last), the uniform quantization means that
- the error variance is *not* dependant. Given a pigeonhole and an
- entry, we can find the minimum and maximum possible errors
- (relative to the entry) for any point that could appear in the
- pigeonhole */
-
- /* must iterate over both pigeonholes and entries */
- /* temporarily (in order to avoid thinking hard), we grow each
- pigeonhole seperately, the build a stack of 'em later */
- pigeons=1;
- subpigeons=1;
- for(i=0;i<dim;i++)subpigeons*=p->mapentries;
- for(i=0;i<dim;i++)pigeons*=p->quantvals;
- temptrack=_ogg_calloc(dim,sizeof(long));
- tempmin=_ogg_calloc(dim,sizeof(float));
- tempmax=_ogg_calloc(dim,sizeof(float));
- tempstack=_ogg_calloc(pigeons,sizeof(long *));
- tempcount=_ogg_calloc(pigeons,sizeof(long));
-
- while(1){
- float errorpost=-1;
- char buffer[80];
-
- /* map our current pigeonhole to a 'big pigeonhole' so we know
- what list we're after */
- int entry=0;
- for(i=dim-1;i>=0;i--)entry=entry*p->quantvals+p->pigeonmap[temptrack[i]];
- setvals(dim,p,temptrack,tempmin,tempmax,c->q_sequencep);
- sprintf(buffer,"Building pigeonhole search list [%ld]...",totalstack);
-
-
- /* Search all entries to find the one with the minimum possible
- maximum error. Record that error */
- for(i=0;i<entries;i++){
- if(c->lengthlist[i]>0){
- float this=maxerror(dim,b->valuelist+i*dim,p,
- temptrack,tempmin,tempmax);
- if(errorpost==-1 || this<errorpost)errorpost=this;
- spinnit(buffer,subpigeons);
- }
- }
-
- /* Our search list will contain all entries with a minimum
- possible error <= our errorpost */
- for(i=0;i<entries;i++)
- if(c->lengthlist[i]>0){
- spinnit(buffer,subpigeons);
- if(minerror(dim,b->valuelist+i*dim,p,
- temptrack,tempmin,tempmax)<errorpost)
- totalstack+=addtosearch(entry,tempstack,tempcount,i);
- }
-
- for(i=0;i<dim;i++){
- temptrack[i]++;
- if(temptrack[i]<p->mapentries)break;
- temptrack[i]=0;
- }
- if(i==dim)break;
- subpigeons--;
- }
-
- fprintf(stderr,"\r "
- "\rTotal search list size (all entries): %ld\n",totalstack);
-
- /* pare the index of lists for improbable quantizations (where
- improbable is determined by c->lengthlist; we assume that
- pigeonholing is in sync with the codeword cells, which it is */
- /*for(i=0;i<entries;i++){
- float probability= 1.f/(1<<c->lengthlist[i]);
- if(c->lengthlist[i]==0 || probability*entries<cutoff){
- totalstack-=tempcount[i];
- tempcount[i]=0;
- }
- }*/
-
- /* pare the list of shortlists; merge contained and similar lists
- together */
- p->fitmap=_ogg_malloc(pigeons*sizeof(long));
- for(i=0;i<pigeons;i++)p->fitmap[i]=-1;
- while(changep){
- char buffer[80];
- changep=0;
-
- for(i=0;i<pigeons;i++){
- if(p->fitmap[i]<0 && tempcount[i]){
- for(j=i+1;j<pigeons;j++){
- if(p->fitmap[j]<0 && tempcount[j]){
- /* is one list a superset, or are they sufficiently similar? */
- int amiss=0,bmiss=0,ii,jj;
- for(ii=0;ii<tempcount[i];ii++){
- for(jj=0;jj<tempcount[j];jj++)
- if(tempstack[i][ii]==tempstack[j][jj])break;
- if(jj==tempcount[j])amiss++;
- }
- for(jj=0;jj<tempcount[j];jj++){
- for(ii=0;ii<tempcount[i];ii++)
- if(tempstack[i][ii]==tempstack[j][jj])break;
- if(ii==tempcount[i])bmiss++;
- }
- if(amiss==0 ||
- bmiss==0 ||
- (amiss*2<tempcount[i] && bmiss*2<tempcount[j] &&
- tempcount[i]+bmiss<entries/30)){
-
- /*superset/similar Add all of one to the other. */
- for(jj=0;jj<tempcount[j];jj++)
- totalstack+=addtosearch(i,tempstack,tempcount,
- tempstack[j][jj]);
- totalstack-=tempcount[j];
- p->fitmap[j]=i;
- changep=1;
- }
- }
- }
- sprintf(buffer,"Consolidating [%ld total, %s]... ",totalstack,
- changep?"reit":"nochange");
- spinnit(buffer,pigeons-i);
- }
- }
- }
-
- /* repack the temp stack in final form */
- fprintf(stderr,"\r "
- "\rFinal total list size: %ld\n",totalstack);
-
-
- p->fittotal=totalstack;
- p->fitlist=_ogg_malloc((totalstack+1)*sizeof(long));
- p->fitlength=_ogg_malloc(pigeons*sizeof(long));
- {
- long usage=0;
- for(i=0;i<pigeons;i++){
- if(p->fitmap[i]==-1){
- if(tempcount[i])
- memcpy(p->fitlist+usage,tempstack[i],tempcount[i]*sizeof(long));
- p->fitmap[i]=usage;
- p->fitlength[i]=tempcount[i];
- usage+=tempcount[i];
- if(usage>totalstack){
- fprintf(stderr,"Internal error; usage>totalstack\n");
- exit(1);
- }
- }else{
- p->fitlength[i]=p->fitlength[p->fitmap[i]];
- p->fitmap[i]=p->fitmap[p->fitmap[i]];
- }
- }
- }
- }
-#endif
-
- write_codebook(stdout,name,c);
- fprintf(stderr,"\r "
- "\nDone.\n");
- exit(0);
-}