Eliminate some unreachable cases from the cwrs code and fixup the

asserts to reflect the actual limits. Update the cwrs test to cover
the complete n,k range used by opus/opus_custom.
This commit is contained in:
Gregory Maxwell 2011-08-12 12:05:16 -04:00
parent 6854556556
commit da752d1883
3 changed files with 51 additions and 124 deletions

View file

@ -94,29 +94,12 @@ static const opus_uint32 INV_TABLE[64]={
0xD8FD8FD9,0x8D28AC43,0xDA6C0965,0xDB195E8F, 0xD8FD8FD9,0x8D28AC43,0xDA6C0965,0xDB195E8F,
0x0FDBC091,0x61F2A4BB,0xDCFDCFDD,0x46FDD947, 0x0FDBC091,0x61F2A4BB,0xDCFDCFDD,0x46FDD947,
0x56BE69C9,0xEB2FDEB3,0x26E978D5,0xEFDFBF7F, 0x56BE69C9,0xEB2FDEB3,0x26E978D5,0xEFDFBF7F,
/*
0x0FE03F81,0xC9484E2B,0xE133F84D,0xE1A8C537,
0x077975B9,0x70586723,0xCD29C245,0xFAA11E6F,
0x0FE3C071,0x08B51D9B,0x8CE2CABD,0xBF937F27,
0xA8FE53A9,0x592FE593,0x2C0685B5,0x2EB11B5F,
0xFCD1E361,0x451AB30B,0x72CFE72D,0xDB35A717,
0xFB74A399,0xE80BFA03,0x0D516325,0x1BCB564F,
0xE02E4851,0xD962AE7B,0x10F8ED9D,0x95AEDD07,
0xE9DC0589,0xA18A4473,0xEA53FA95,0xEE936F3F,
0x90948F41,0xEAFEAFEB,0x3D137E0D,0xEF46C0F7,
0x028C1979,0x791064E3,0xC04FEC05,0xE115062F,
0x32385831,0x6E68575B,0xA10D387D,0x6FECF2E7,
0x3FB47F69,0xED4BFB53,0x74FED775,0xDB43BB1F,
0x87654321,0x9BA144CB,0x478BBCED,0xBFB912D7,
0x1FDCD759,0x14B2A7C3,0xCB125CE5,0x437B2E0F,
0x10FEF011,0xD2B3183B,0x386CAB5D,0xEF6AC0C7,
0x0E64C149,0x9A020A33,0xE6B41C55,0xFEFEFEFF*/
}; };
/*Computes (_a*_b-_c)/(2*_d+1) when the quotient is known to be exact. /*Computes (_a*_b-_c)/(2*_d+1) when the quotient is known to be exact.
_a, _b, _c, and _d may be arbitrary so long as the arbitrary precision result _a, _b, _c, and _d may be arbitrary so long as the arbitrary precision result
fits in 32 bits, but currently the table for multiplicative inverses is only fits in 32 bits, but currently the table for multiplicative inverses is only
valid for _d<128.*/ valid for _d<64.*/
static inline opus_uint32 imusdiv32odd(opus_uint32 _a,opus_uint32 _b, static inline opus_uint32 imusdiv32odd(opus_uint32 _a,opus_uint32 _b,
opus_uint32 _c,int _d){ opus_uint32 _c,int _d){
return (_a*_b-_c)*INV_TABLE[_d]&MASK32; return (_a*_b-_c)*INV_TABLE[_d]&MASK32;
@ -126,7 +109,7 @@ static inline opus_uint32 imusdiv32odd(opus_uint32 _a,opus_uint32 _b,
_d does not actually have to be even, but imusdiv32odd will be faster when _d does not actually have to be even, but imusdiv32odd will be faster when
it's odd, so you should use that instead. it's odd, so you should use that instead.
_a and _d are assumed to be small (e.g., _a*_d fits in 32 bits; currently the _a and _d are assumed to be small (e.g., _a*_d fits in 32 bits; currently the
table for multiplicative inverses is only valid for _d<=256). table for multiplicative inverses is only valid for _d<=127).
_b and _c may be arbitrary so long as the arbitrary precision reuslt fits in _b and _c may be arbitrary so long as the arbitrary precision reuslt fits in
32 bits.*/ 32 bits.*/
static inline opus_uint32 imusdiv32even(opus_uint32 _a,opus_uint32 _b, static inline opus_uint32 imusdiv32even(opus_uint32 _a,opus_uint32 _b,
@ -137,7 +120,7 @@ static inline opus_uint32 imusdiv32even(opus_uint32 _a,opus_uint32 _b,
int one; int one;
celt_assert(_d>0); celt_assert(_d>0);
shift=EC_ILOG(_d^_d-1); shift=EC_ILOG(_d^_d-1);
celt_assert(_d<=256); celt_assert(_d<=127);
inv=INV_TABLE[_d-1>>shift]; inv=INV_TABLE[_d-1>>shift];
shift--; shift--;
one=1<<shift; one=1<<shift;
@ -268,7 +251,6 @@ static inline opus_uint32 imusdiv32even(opus_uint32 _a,opus_uint32 _b,
}*/ }*/
#ifndef SMALL_FOOTPRINT #ifndef SMALL_FOOTPRINT
/*Compute V(1,_k).*/ /*Compute V(1,_k).*/
static inline unsigned ncwrs1(int _k){ static inline unsigned ncwrs1(int _k){
return _k?2:1; return _k?2:1;
@ -362,7 +344,7 @@ static opus_uint32 ncwrs_urow(unsigned _n,unsigned _k,opus_uint32 *_u){
_u[0]=0; _u[0]=0;
_u[1]=um2=1; _u[1]=um2=1;
#ifndef SMALL_FOOTPRINT #ifndef SMALL_FOOTPRINT
if(_n<=6 || _k>255) if(_n<=6 || _k>127)
#endif #endif
{ {
/*If _n==0, _u[0] should be 1 and the rest should be 0.*/ /*If _n==0, _u[0] should be 1 and the rest should be 0.*/
@ -391,6 +373,8 @@ static opus_uint32 ncwrs_urow(unsigned _n,unsigned _k,opus_uint32 *_u){
return _u[_k]+_u[_k+1]; return _u[_k]+_u[_k+1];
} }
#ifndef SMALL_FOOTPRINT
/*Returns the _i'th combination of _k elements (at most 32767) chosen from a /*Returns the _i'th combination of _k elements (at most 32767) chosen from a
set of size 1 with associated sign bits. set of size 1 with associated sign bits.
_y: Returns the vector of pulses.*/ _y: Returns the vector of pulses.*/
@ -400,8 +384,6 @@ static inline void cwrsi1(int _k,opus_uint32 _i,int *_y){
_y[0]=_k+s^s; _y[0]=_k+s^s;
} }
#ifndef SMALL_FOOTPRINT
/*Returns the _i'th combination of _k elements (at most 32767) chosen from a /*Returns the _i'th combination of _k elements (at most 32767) chosen from a
set of size 2 with associated sign bits. set of size 2 with associated sign bits.
_y: Returns the vector of pulses.*/ _y: Returns the vector of pulses.*/
@ -476,37 +458,6 @@ static void cwrsi4(int _k,opus_uint32 _i,int *_y){
cwrsi3(_k,_i,_y+1); cwrsi3(_k,_i,_y+1);
} }
/*Returns the _i'th combination of _k elements (at most 238) chosen from a set
of size 5 with associated sign bits.
_y: Returns the vector of pulses.*/
static void cwrsi5(int _k,opus_uint32 _i,int *_y){
opus_uint32 p;
int s;
int yj;
p=ucwrs5(_k+1);
s=-(_i>=p);
_i-=p&s;
yj=_k;
/* A binary search on U(5,K) avoids the need for 64-bit arithmetic */
{
int kl=0;
int kr=_k;
for(;;){
_k=kl+kr>>1;
p=ucwrs5(_k);
if(p<_i){
if(_k>=kr)break;
kl=_k+1;
}
else if(p>_i)kr=_k-1;
else break;
}
}
_i-=p;
yj-=_k;
_y[0]=yj+s^s;
cwrsi4(_k,_i,_y+1);
}
#endif /* SMALL_FOOTPRINT */ #endif /* SMALL_FOOTPRINT */
/*Returns the _i'th combination of _k elements chosen from a set of size _n /*Returns the _i'th combination of _k elements chosen from a set of size _n
@ -661,15 +612,8 @@ void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){
void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){ void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){
opus_uint32 i; opus_uint32 i;
if (_k==0)
return;
switch(_n){
case 1:{
i=icwrs1(_y,&_k);
celt_assert(ncwrs1(_k)==2);
ec_enc_bits(_enc,i,1);
}break;
#ifndef SMALL_FOOTPRINT #ifndef SMALL_FOOTPRINT
switch(_n){
case 2:{ case 2:{
i=icwrs2(_y,&_k); i=icwrs2(_y,&_k);
ec_enc_uint(_enc,i,ncwrs2(_k)); ec_enc_uint(_enc,i,ncwrs2(_k));
@ -682,13 +626,9 @@ void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){
i=icwrs4(_y,&_k); i=icwrs4(_y,&_k);
ec_enc_uint(_enc,i,ncwrs4(_k)); ec_enc_uint(_enc,i,ncwrs4(_k));
}break; }break;
case 5:{
i=icwrs5(_y,&_k);
ec_enc_uint(_enc,i,ncwrs5(_k));
}break;
#endif
default: default:
{ {
#endif
VARDECL(opus_uint32,u); VARDECL(opus_uint32,u);
opus_uint32 nc; opus_uint32 nc;
SAVE_STACK; SAVE_STACK;
@ -696,37 +636,29 @@ void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){
i=icwrs(_n,_k,&nc,_y,u); i=icwrs(_n,_k,&nc,_y,u);
ec_enc_uint(_enc,i,nc); ec_enc_uint(_enc,i,nc);
RESTORE_STACK; RESTORE_STACK;
#ifndef SMALL_FOOTPRINT
}; };
} }
#endif
} }
void decode_pulses(int *_y,int _n,int _k,ec_dec *_dec) void decode_pulses(int *_y,int _n,int _k,ec_dec *_dec)
{ {
if (_k==0) {
int i;
for (i=0;i<_n;i++)
_y[i] = 0;
return;
}
switch(_n){
case 1:{
celt_assert(ncwrs1(_k)==2);
cwrsi1(_k,ec_dec_bits(_dec,1),_y);
}break;
#ifndef SMALL_FOOTPRINT #ifndef SMALL_FOOTPRINT
switch(_n){
case 2:cwrsi2(_k,ec_dec_uint(_dec,ncwrs2(_k)),_y);break; case 2:cwrsi2(_k,ec_dec_uint(_dec,ncwrs2(_k)),_y);break;
case 3:cwrsi3(_k,ec_dec_uint(_dec,ncwrs3(_k)),_y);break; case 3:cwrsi3(_k,ec_dec_uint(_dec,ncwrs3(_k)),_y);break;
case 4:cwrsi4(_k,ec_dec_uint(_dec,ncwrs4(_k)),_y);break; case 4:cwrsi4(_k,ec_dec_uint(_dec,ncwrs4(_k)),_y);break;
case 5:cwrsi5(_k,ec_dec_uint(_dec,ncwrs5(_k)),_y);break;
#endif
default: default:
{ {
#endif
VARDECL(opus_uint32,u); VARDECL(opus_uint32,u);
SAVE_STACK; SAVE_STACK;
ALLOC(u,_k+2U,opus_uint32); ALLOC(u,_k+2U,opus_uint32);
cwrsi(_n,_k,ec_dec_uint(_dec,ncwrs_urow(_n,_k,u)),_y,u); cwrsi(_n,_k,ec_dec_uint(_dec,ncwrs_urow(_n,_k,u)),_y,u);
RESTORE_STACK; RESTORE_STACK;
#ifndef SMALL_FOOTPRINT
} }
} }
#endif
} }

View file

@ -12,31 +12,43 @@
#include "../libcelt/entcode.c" #include "../libcelt/entcode.c"
#include "../libcelt/cwrs.c" #include "../libcelt/cwrs.c"
#include "../libcelt/mathops.c" #include "../libcelt/mathops.c"
#include "../libcelt/rate.h"
#define NMAX (14) #define NMAX (208)
#define KMAX (32767) #define KMAX (128)
static const int kmax[15]={ static const int pn[40]={
32767,32767,32767,32767, 1172, 2, 3, 4, 5, 6, 7, 8, 9, 10,
238, 95, 53, 36, 27, 11, 12, 13, 14, 16, 18, 20, 22, 24,
22, 18, 16, 15, 13 26, 28, 32, 36, 40, 44, 48, 52, 56,
64, 72, 80, 88, 96, 104, 112, 128, 144,
160, 176, 192, 208
}; };
static const int pkmax[40]={
128, 128, 128, 128, 88, 52, 36, 26, 22,
18, 16, 15, 13, 12, 11, 10, 9, 9,
8, 8, 7, 7, 7, 6, 6, 6, 6,
5, 5, 5, 5, 5, 5, 4, 4, 4,
4, 4, 4, 4
};
int main(int _argc,char **_argv){ int main(int _argc,char **_argv){
int t;
int n; int n;
ALLOC_STACK; ALLOC_STACK;
for(n=2;n<=NMAX;n++){ for(t=0;t<40;t++){
int dk; int pseudo;
int k; n=pn[t];
dk=kmax[n]>7?kmax[n]/7:1; for(pseudo=1;pseudo<41;pseudo++)
k=1-dk; {
do{ int k;
opus_uint32 uu[KMAX+2U]; opus_uint32 uu[KMAX+2U];
opus_uint32 inc; opus_uint32 inc;
opus_uint32 nc; opus_uint32 nc;
opus_uint32 i; opus_uint32 i;
k=kmax[n]-dk<k?kmax[n]:k+dk; k=get_pulses(pseudo);
if (k>pkmax[t])break;
printf("Testing CWRS with N=%i, K=%i...\n",n,k); printf("Testing CWRS with N=%i, K=%i...\n",n,k);
nc=ncwrs_urow(n,k,uu); nc=ncwrs_urow(n,k,uu);
inc=nc/10000; inc=nc/10000;
@ -44,6 +56,7 @@ int main(int _argc,char **_argv){
for(i=0;i<nc;i+=inc){ for(i=0;i<nc;i+=inc){
opus_uint32 u[KMAX+2U]; opus_uint32 u[KMAX+2U];
int y[NMAX]; int y[NMAX];
int sy;
int yy[5]; int yy[5];
opus_uint32 v; opus_uint32 v;
opus_uint32 ii; opus_uint32 ii;
@ -51,6 +64,13 @@ int main(int _argc,char **_argv){
int j; int j;
memcpy(u,uu,(k+2U)*sizeof(*u)); memcpy(u,uu,(k+2U)*sizeof(*u));
cwrsi(n,k,i,y,u); cwrsi(n,k,i,y,u);
sy=0;
for(j=0;j<n;j++)sy+=ABS(y[j]);
if(sy!=k){
fprintf(stderr,"N=%d Pulse count mismatch in cwrsi (%d!=%d).\n",
n,sy,k);
return 99;
}
/*printf("%6u of %u:",i,nc); /*printf("%6u of %u:",i,nc);
for(j=0;j<n;j++)printf(" %+3i",y[j]); for(j=0;j<n;j++)printf(" %+3i",y[j]);
printf(" ->");*/ printf(" ->");*/
@ -139,38 +159,11 @@ int main(int _argc,char **_argv){
return 14; return 14;
} }
} }
else if(n==5){
cwrsi5(k,i,yy);
for(j=0;j<5;j++)if(yy[j]!=y[j]){
fprintf(stderr,"N=5 pulse vector mismatch "
"({%i,%i,%i,%i,%i}!={%i,%i,%i,%i,%i}).\n",
yy[0],yy[1],yy[2],yy[3],yy[4],y[0],y[1],y[2],y[3],y[4]);
return 15;
}
ii=icwrs5(yy,&kk);
if(ii!=i){
fprintf(stderr,"N=5 combination-index mismatch (%lu!=%lu).\n",
(long)ii,(long)i);
return 16;
}
if(kk!=k){
fprintf(stderr,"N=5 pulse count mismatch (%i!=%i).\n",kk,k);
return 17;
}
v=ncwrs5(k);
if(v!=nc){
fprintf(stderr,"N=5 combination count mismatch (%lu!=%lu).\n",
(long)v,(long)nc);
return 18;
}
}
#endif /* SMALL_FOOTPRINT */ #endif /* SMALL_FOOTPRINT */
/*printf(" %6u\n",i);*/ /*printf(" %6u\n",i);*/
} }
/*printf("\n");*/ /*printf("\n");*/
} }
while(k<kmax[n]);
} }
return 0; return 0;
} }

View file

@ -181,7 +181,8 @@ unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B,
unsigned collapse_mask; unsigned collapse_mask;
SAVE_STACK; SAVE_STACK;
celt_assert2(K!=0, "alg_quant() needs at least one pulse"); celt_assert2(K>0, "alg_quant() needs at least one pulse");
celt_assert2(N>1, "alg_quant() needs at least two dimensions");
ALLOC(y, N, celt_norm); ALLOC(y, N, celt_norm);
ALLOC(iy, N, int); ALLOC(iy, N, int);
@ -340,7 +341,8 @@ unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B,
VARDECL(int, iy); VARDECL(int, iy);
SAVE_STACK; SAVE_STACK;
celt_assert2(K!=0, "alg_unquant() needs at least one pulse"); celt_assert2(K>0, "alg_unquant() needs at least one pulse");
celt_assert2(N>1, "alg_unquant() needs at least two dimensions");
ALLOC(iy, N, int); ALLOC(iy, N, int);
decode_pulses(iy, N, K, dec); decode_pulses(iy, N, K, dec);
Ryy = 0; Ryy = 0;