bitvector - some bugfixes and further implementations
This commit is contained in:
parent
9bceebdd29
commit
e42987061f
182
bitvector.cc
182
bitvector.cc
@ -39,21 +39,48 @@ return s;
|
||||
}
|
||||
|
||||
|
||||
void bitvector::zero_padding() const
|
||||
{
|
||||
if(!modulo) return;
|
||||
bitvector *p = const_cast<bitvector *>(this);
|
||||
p->v[nn-1] &= (1ULL<<modulo)-1;
|
||||
}
|
||||
|
||||
|
||||
bitvector& bitvector::operator++()
|
||||
{
|
||||
copyonwrite();
|
||||
zero_padding();
|
||||
int i=0;
|
||||
while(i<nn) if(++v[i++]) break;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bitvector& bitvector::operator--()
|
||||
{
|
||||
copyonwrite();
|
||||
zero_padding();
|
||||
int i=0;
|
||||
while(i<nn) if(v[i++]--) break;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//implemented so that vectors of different length are considered different automatically
|
||||
bool bitvector::operator!=(const bitvector &rhs) const
|
||||
{
|
||||
if(nn!=rhs.nn || modulo!=rhs.modulo) return 1;
|
||||
if(v==rhs.v) return 0;
|
||||
if(!modulo) return memcmp(v,rhs.v,nn*sizeof(bitvector_block));
|
||||
if(memcmp(v,rhs.v,(nn-1)*sizeof(bitvector_block))) return 1;
|
||||
bitvector_block a=v[nn-1];
|
||||
bitvector_block b=rhs.v[nn-1];
|
||||
//zero out the irrelevant bits
|
||||
bitvector_block mask= ~((bitvector_block)0);
|
||||
mask <<=modulo;
|
||||
mask = ~mask;
|
||||
a&=mask; b&=mask;
|
||||
return a!=b;
|
||||
if(nn==rhs.nn && modulo==rhs.modulo && v==rhs.v) return false;
|
||||
zero_padding();
|
||||
rhs.zero_padding();
|
||||
int minnn=nn; if(rhs.nn<minnn) minnn=rhs.nn;
|
||||
int maxnn=nn; if(rhs.nn>maxnn) maxnn=rhs.nn;
|
||||
if(memcmp(v,rhs.v,minnn*sizeof(bitvector_block))) return true;
|
||||
if(minnn==maxnn) return false;
|
||||
if(nn==minnn) {for(int i=minnn; i<maxnn; ++i) if(rhs.v[i]) return true;}
|
||||
if(rhs.nn==minnn){for(int i=minnn; i<maxnn; ++i) if(v[i]) return true;}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -97,6 +124,7 @@ bitvector bitvector::operator~() const
|
||||
{
|
||||
bitvector r((*this).size());
|
||||
for(int i=0; i<nn; ++i) r.v[i] = ~v[i];
|
||||
r.zero_padding();
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -197,12 +225,7 @@ void bitvector::randomize()
|
||||
{
|
||||
copyonwrite();
|
||||
for(int i=0; i<nn; ++i) v[i]=RANDINT64();
|
||||
//zero the excess bits
|
||||
if(modulo)
|
||||
{
|
||||
bitvector_block mask = (1ULL<<modulo)-1;
|
||||
v[nn-1] &= mask;
|
||||
}
|
||||
zero_padding();
|
||||
}
|
||||
|
||||
|
||||
@ -322,6 +345,7 @@ bitvector r(size());
|
||||
r.clear();
|
||||
bitvector tmp(*this);
|
||||
tmp.resize(size()+1,true);
|
||||
tmp.copyonwrite();
|
||||
int rd=rhs.degree();
|
||||
for(int i=0; i<=rd; ++i) //avoid making a working copy of rhs and shifting it
|
||||
{
|
||||
@ -358,7 +382,7 @@ while(!newr.is_zero())
|
||||
t=newt; newt=remainder;
|
||||
}
|
||||
|
||||
if(r.degree()>0) laerror("field_inv: polynomial is not irreducible or input is its multiple");
|
||||
if(r.degree()>0) laerror("field_inv: polynomial is not irreducible or input is zero modulo the polynomial");
|
||||
if(!r[0]) laerror("zero in field_inv");
|
||||
|
||||
return t;
|
||||
@ -368,12 +392,13 @@ return t;
|
||||
|
||||
void bitvector::resize(const unsigned int n, bool preserve)
|
||||
{
|
||||
int old=size();
|
||||
if(preserve) zero_padding();
|
||||
int oldnn=nn;
|
||||
NRVec<bitvector_block>::resize((n+blockbits-1)/blockbits,preserve);
|
||||
modulo=n%blockbits;
|
||||
if(preserve) //clear newly allocated memory
|
||||
{
|
||||
for(int i=old; i<nn*blockbits; ++i) this->reset(i);
|
||||
for(int i=oldnn; i<nn; ++i) v[i]=0;
|
||||
}
|
||||
else clear();
|
||||
}
|
||||
@ -430,6 +455,7 @@ return big;
|
||||
|
||||
|
||||
//cf. Brent & Zimmermann ANZMC08t (2008) paper
|
||||
//
|
||||
bool bitvector::is_irreducible() const
|
||||
{
|
||||
bitvector tmp(size());
|
||||
@ -452,7 +478,8 @@ for(auto p=f.begin(); p!=f.end(); ++p)
|
||||
for(unsigned int j=0; j<dm; ++j) tmp = tmp.field_mult(tmp,*this);
|
||||
tmp.flip(1);
|
||||
bitvector g=tmp.gcd(*this);
|
||||
if(!g,is_one()) return false;
|
||||
//std::cout << "TEST tmp, ir, gcd, is_one "<<tmp<<" "<<*this<<" "<<g<<" : "<<g.is_one()<<std::endl;
|
||||
if(!g.is_one()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -508,6 +535,117 @@ if(dimensions)
|
||||
NRVec<bitvector_block>::put(fd,dimensions,transp);
|
||||
}
|
||||
|
||||
static bitvector *tryme;
|
||||
static bool irfound;
|
||||
static int mynth;
|
||||
|
||||
static void irfinder(int nones, int top)
|
||||
{
|
||||
if(irfound) return;
|
||||
if(nones==0) //terminate recursion
|
||||
{
|
||||
bool testit = tryme->is_irreducible();
|
||||
//std::cout <<"candidate = "<< *tryme<< " result = "<<testit<<std::endl;
|
||||
if(testit)
|
||||
{
|
||||
--mynth;
|
||||
if(!mynth) irfound=true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
for(int i=nones; i<=top; ++i)
|
||||
{
|
||||
tryme->set(i);
|
||||
irfinder(nones-1,i-1);
|
||||
if(irfound) break;
|
||||
else tryme->reset(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bitvector find_irreducible(int deg, int pop, int nth)
|
||||
{
|
||||
if(deg<=0) laerror("illegal degree in find_irreducible");
|
||||
if(deg==1) {bitvector r(2); r.set(1); r.reset(0); return r;}
|
||||
bitvector r(deg+1);
|
||||
if(pop== -1)
|
||||
{
|
||||
do {
|
||||
r.randomize();
|
||||
r.set(0);
|
||||
r.set(deg);
|
||||
if((r.population()&1)==0) r.flip(1+RANDINT32()%(deg-2));
|
||||
}
|
||||
while(!r.is_irreducible());
|
||||
return r;
|
||||
}
|
||||
if(pop<3 || (pop&1)==0) laerror("impossible population of irreducible polynomial requested");
|
||||
r.clear();
|
||||
r.set(0);
|
||||
r.set(deg);
|
||||
pop-=2;
|
||||
tryme= &r;
|
||||
irfound=false;
|
||||
mynth=nth;
|
||||
irfinder(pop,deg-1);
|
||||
if(!irfound) r.clear();
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bitvector bitvector::pow(unsigned int n) const
|
||||
{
|
||||
if(n==0) {bitvector r(size()); r.clear(); r.set(0); return r;}
|
||||
if(n==1) return *this;
|
||||
bitvector y,z;
|
||||
z= *this;
|
||||
while(!(n&1))
|
||||
{
|
||||
z = z*z;
|
||||
n >>= 1;
|
||||
}
|
||||
y=z;
|
||||
while((n >>= 1)/*!=0*/)
|
||||
{
|
||||
z = z*z;
|
||||
if(n&1) y *= z;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
bitvector bitvector::field_pow(unsigned int n, const bitvector &ir) const
|
||||
{
|
||||
if(n==0) {bitvector r(size()); r.clear(); r.set(0); return r;}
|
||||
if(n==1) return *this;
|
||||
bitvector y,z;
|
||||
z= *this;
|
||||
while(!(n&1))
|
||||
{
|
||||
z = z.field_mult(z,ir);
|
||||
n >>= 1;
|
||||
}
|
||||
y=z;
|
||||
while((n >>= 1)/*!=0*/)
|
||||
{
|
||||
z = z.field_mult(z,ir);
|
||||
if(n&1) y = y.field_mult(z,ir);
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
//sqrt(x) is x^(2^(d-1))
|
||||
bitvector bitvector::field_sqrt(const bitvector &ir) const
|
||||
{
|
||||
int d=ir.degree();
|
||||
bitvector r(*this);
|
||||
for(int i=0; i<d-1; ++i)
|
||||
{
|
||||
r= r.field_mult(r,ir);
|
||||
}
|
||||
r.resize(d+1,true);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
21
bitvector.h
21
bitvector.h
@ -43,7 +43,7 @@ private:
|
||||
unsigned int modulo;
|
||||
public:
|
||||
bitvector() : NRVec<bitvector_block>() {};
|
||||
explicit bitvector (const unsigned int n):NRVec<bitvector_block>((n+blockbits-1)/blockbits) {modulo=n%blockbits;};
|
||||
explicit bitvector (const unsigned int n):NRVec<bitvector_block>((n+blockbits-1)/blockbits) {modulo=n%blockbits; memset(v,0,nn*sizeof(bitvector_block));};
|
||||
bitvector (const bitvector_block a, const unsigned int n):NRVec<bitvector_block>(a,(n+blockbits-1)/blockbits) {modulo=n%blockbits;};
|
||||
bitvector(const bitvector &rhs) : NRVec<bitvector_block>(rhs) {modulo=rhs.modulo;};
|
||||
//operator= seems to be correctly synthetized by the compiler
|
||||
@ -63,10 +63,13 @@ public:
|
||||
const bool assign(const unsigned int i, const bool r) {if(r) set(i); else reset(i); return r;};
|
||||
void clear() {copyonwrite(true); memset(v,0,nn*sizeof(bitvector_block));};
|
||||
void fill() {memset(v,0xff,nn*sizeof(bitvector_block));};
|
||||
bool iszero() const {for(int i=0; i<nn; ++i) if(v[i]) return false; return true;};
|
||||
bool is_zero() const {return iszero();};
|
||||
bool is_one() const {if(v[0]!=1) return false; for(int i=1; i<nn; ++i) if(v[i]) return false; return true;};
|
||||
void zero_padding() const;
|
||||
bool is_zero() const {zero_padding(); for(int i=0; i<nn; ++i) if(v[i]) return false; return true;};
|
||||
bool is_one() const {zero_padding(); if(v[0]!=1) return false; for(int i=1; i<nn; ++i) if(v[i]) return false;return true;};
|
||||
bool iszero() const {return is_zero();};
|
||||
void randomize();
|
||||
bitvector& operator++();
|
||||
bitvector& operator--();
|
||||
bool operator!=(const bitvector &rhs) const;
|
||||
bool operator==(const bitvector &rhs) const {return !(*this != rhs);};
|
||||
bool operator>(const bitvector &rhs) const;
|
||||
@ -77,6 +80,9 @@ public:
|
||||
bitvector& operator&=(const bitvector &rhs);
|
||||
bitvector& operator|=(const bitvector &rhs);
|
||||
bitvector& operator^=(const bitvector &rhs);
|
||||
bitvector& operator&=(const bitvector_block rhs) {v[0]&=rhs; return *this;};
|
||||
bitvector& operator|=(const bitvector_block rhs) {v[0]|=rhs; return *this;};
|
||||
bitvector& operator^=(const bitvector_block rhs) {v[0]^=rhs; return *this;};
|
||||
bitvector& operator+=(const bitvector &rhs) {return (*this)^=rhs;}; //addition modulo 2
|
||||
bitvector& operator-=(const bitvector &rhs) {return (*this)^=rhs;}; //subtraction modulo 2
|
||||
bitvector operator&(const bitvector &rhs) const {return bitvector(*this) &= rhs;};
|
||||
@ -87,10 +93,13 @@ public:
|
||||
bitvector multiply(const bitvector &rhs, bool autoresize=true) const; //use autoresize=false only if you know it will not overflow!
|
||||
bitvector operator*(const bitvector &rhs) const {return multiply(rhs,true);} //multiplication of polynomials over GF(2) NOTE: naive algorithm, does not employ CLMUL nor fft-like approach, only for short vectors!!!
|
||||
bitvector& operator*=(const bitvector &rhs) {*this = (*this)*rhs; return *this;}
|
||||
bitvector pow(unsigned int n) const;
|
||||
bitvector field_mult(const bitvector &rhs, const bitvector &irpolynom) const; //multiplication in GF(2^n)
|
||||
bitvector field_inv(const bitvector &irpolynom) const; //multiplication in GF(2^n)
|
||||
bitvector field_div(const bitvector &rhs, const bitvector &irpolynom) const {return field_mult(rhs.field_inv(irpolynom),irpolynom);};
|
||||
bitvector field_composition(const bitvector &rhs, const bitvector &irpolynom) const;
|
||||
bitvector field_pow(unsigned int n, const bitvector &irpolynom) const;
|
||||
bitvector field_sqrt(const bitvector &irpolynom) const;
|
||||
bool is_irreducible() const; //test irreducibility of polynomial over GF2
|
||||
bitvector division(const bitvector &rhs, bitvector &remainder) const;
|
||||
bitvector operator/(const bitvector &rhs) const {bitvector rem(rhs.size()); return division(rhs,rem);};
|
||||
@ -99,7 +108,7 @@ public:
|
||||
bitvector lcm(const bitvector &rhs) const {return (*this)*rhs/this->gcd(rhs);};
|
||||
bitvector composition(const bitvector &rhs) const;
|
||||
unsigned int bitdiff(const bitvector &y) const; //number of differing bits (Hamming distance)
|
||||
unsigned int population(const unsigned int before=0) const; //number of 1's
|
||||
unsigned int population(const unsigned int before=0) const; //number of 1's (Hamming weight)
|
||||
unsigned int nlz() const; //number of leading zeroes
|
||||
unsigned int degree() const {if(iszero()) return 0; else return size()-nlz()-1;}; //interprested as a polynomial over GF(2)
|
||||
void truncate(int t=0) {int s=degree()+1; if(t>s) s=t; resize(s,true);};
|
||||
@ -117,6 +126,8 @@ public:
|
||||
void write(int fd, bool dimensions=1, bool transp=0);
|
||||
};
|
||||
|
||||
extern bitvector find_irreducible(int deg, int pop= -1, int nth=1); //degree and requested Hamming weight or -1 for random trial
|
||||
|
||||
//expand to separate bytes or ints
|
||||
template <typename T>
|
||||
void bitvector_expand(const bitvector &v, NRVec<T> &r)
|
||||
|
13
laerror.cc
13
laerror.cc
@ -205,4 +205,17 @@ extern "C" int cblas_errprn(int ierr, int info, char *form, ...) {
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int endianity()
|
||||
{
|
||||
static union {int i; char z[sizeof(int)];} u;
|
||||
static int jj= -1;
|
||||
if(jj<0) /* first call */
|
||||
{
|
||||
u.i=1;
|
||||
jj=0; while(!u.z[jj]) jj++;
|
||||
}
|
||||
return jj;
|
||||
}
|
||||
|
||||
}//namespace
|
||||
|
@ -53,6 +53,8 @@ s << x.msg;
|
||||
return s;
|
||||
}
|
||||
|
||||
extern int endianity();
|
||||
|
||||
}//namespace
|
||||
|
||||
#endif
|
||||
|
47
t.cc
47
t.cc
@ -2946,7 +2946,7 @@ cin >>n;
|
||||
cout <<factorization(n)<<" phi = "<<eulerphi(n)<<endl;
|
||||
}
|
||||
|
||||
if(1)
|
||||
if(0)
|
||||
{
|
||||
bitvector ir; cin >>ir;
|
||||
if(!ir.is_irreducible()) laerror("input must be an irreducible polynomial");
|
||||
@ -2961,8 +2961,49 @@ bitvector cc=a.field_composition(ai,ir);
|
||||
cout <<c<<endl;
|
||||
cout <<c%ir<<endl;
|
||||
cout <<cc<<endl;
|
||||
}
|
||||
|
||||
if(1)
|
||||
{
|
||||
int seed;
|
||||
int f=open("/dev/random",O_RDONLY);
|
||||
if(sizeof(int)!=read(f,&seed,sizeof(int))) laerror("cannot read /dev/random");
|
||||
close(f);
|
||||
srand(seed);
|
||||
|
||||
int d;
|
||||
cin >>d;
|
||||
bitvector ir=find_irreducible(d,3);
|
||||
if(ir.is_zero()) ir=find_irreducible(d,5);
|
||||
if(ir.is_zero()) ir=find_irreducible(d,7);
|
||||
if(ir.is_zero()) {cout<<"cannot find IR polynomial\n"; exit(1);}
|
||||
|
||||
|
||||
cout <<"IR = "<<ir<<endl;
|
||||
if(!ir.is_irreducible()) laerror("error in IR finder");
|
||||
else cout <<"IS irreducible\n";
|
||||
bitvector a(d);
|
||||
do { a.randomize(); }while(a.is_zero());
|
||||
cout <<"A = "<<a<<endl;
|
||||
bitvector aa=a;
|
||||
cout <<"A+1 = "<<++aa<<endl;
|
||||
cout <<"A+1-1 = "<<--aa<<endl;
|
||||
if(a!=aa) laerror("error in inc/dec");
|
||||
bitvector g=ir.gcd(a);
|
||||
cout<<"GCD A,IR = "<<g<<endl;
|
||||
if(!g.is_one() && !a.is_zero()) laerror("ERROR IN is_irreducible\n");
|
||||
bitvector ai = a.field_inv(ir);
|
||||
cout <<"I = "<<ai<<endl;
|
||||
bitvector check = a.field_mult(ai,ir);
|
||||
cout<<"check " <<check<<endl;
|
||||
if(!check.is_one()) laerror("error in GF(2^n) inversion");
|
||||
bitvector s=a.field_sqrt(ir);
|
||||
cout <<"test a "<<a<<endl;
|
||||
cout <<"tests2 "<<s.field_mult(s,ir)<<endl;
|
||||
cout <<"test s "<<s<<endl;
|
||||
bitvector dif=a - s.field_mult(s,ir);
|
||||
if(!dif.is_zero()) laerror("error in gf 2^n sqrt");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user