LA_library/bitvector.cc

264 lines
6.2 KiB
C++

/*
LA: linear algebra C++ interface library
Copyright (C) 2008 Jiri Pittner <jiri.pittner@jh-inst.cas.cz> or <jiri@pittnerovi.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "bitvector.h"
#include <unistd.h>
namespace LA {
//inefficient I/O operators
std::ostream & operator<<(std::ostream &s, const bitvector &x)
{
for(unsigned int i=0; i<x.size(); ++i) s<< x[i];
return s;
}
std::istream & operator>>(std::istream &s, bitvector &x)
{
std::string str;
s >> str;
x.resize(str.size());
for(unsigned int i=0; i<x.size(); ++i) {x.assign(i,str[i]!='0');}
return s;
}
//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;
}
bool bitvector::operator>(const bitvector &rhs) const
{
if(nn!=rhs.nn || modulo!=rhs.modulo) laerror("at the moment only bitvectors of the same length comparable");
if(v==rhs.v) return 0;
if(!modulo) return memcmp(v,rhs.v,nn*sizeof(bitvector_block)>0);
int r;
if((r=memcmp(v,rhs.v,(nn-1)*sizeof(bitvector_block)))) return r>0;
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;
}
bool bitvector::operator<(const bitvector &rhs) const
{
if(nn!=rhs.nn || modulo!=rhs.modulo) laerror("at the moment only bitvectors of the same length comparable");
if(v==rhs.v) return 0;
if(!modulo) return memcmp(v,rhs.v,nn*sizeof(bitvector_block)<0);
int r;
if((r=memcmp(v,rhs.v,(nn-1)*sizeof(bitvector_block)))) return r<0;
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;
}
bitvector bitvector::operator~() const
{
bitvector r((*this).size());
for(int i=0; i<nn; ++i) r.v[i] = ~v[i];
return r;
}
bitvector& bitvector::operator&=(const bitvector &rhs)
{
if(size()<rhs.size()) resize(rhs.size(),true);
copyonwrite();
for(int i=0; i<nn; ++i) v[i] &= rhs.v[i];
return *this;
}
bitvector& bitvector::operator|=(const bitvector &rhs)
{
if(size()<rhs.size()) resize(rhs.size(),true);
copyonwrite();
for(int i=0; i<nn; ++i) v[i] |= rhs.v[i];
return *this;
}
bitvector& bitvector::operator^=(const bitvector &rhs)
{
if(size()<rhs.size()) resize(rhs.size(),true);
copyonwrite();
for(int i=0; i<nn; ++i) v[i] ^= rhs.v[i];
return *this;
}
/*number of ones in a binary number, from "Hacker's delight" book*/
#ifdef LONG_IS_32
static unsigned int word_popul(unsigned long x)
{
x -= ((x>>1)&0x55555555);
x = (x&0x33333333) + ((x>>2)&0x33333333);
x=(x + (x>>4))&0x0f0f0f0f;
x+= (x>>8);
x+= (x>>16);
return x&0x3f;
}
#else
//@@@@ use an efficient trick
static unsigned int word_popul(unsigned long x)
{
unsigned int s=0;
for(int i=0; i<64; ++i)
{
if(x&1) ++s;
x>>=1;
}
return s;
}
#endif
bitvector& bitvector::operator>>=(unsigned int i)
{
if(i==0) return *this;
copyonwrite();
unsigned int imod = i%blockbits;
unsigned int ishift = i/blockbits;
for(int dest=0; dest<nn; ++dest)
{
int src=dest+ishift;
if(src>=nn) v[dest]=0;
else
{
v[dest] = v[src]>>imod;
if(imod && (src+1<nn)) v[dest] |= (v[src+1]&((1ULL<<imod)-1)) <<(blockbits-imod);
}
}
return *this;
}
bitvector& bitvector::leftshift(unsigned int i, bool autoresize)
{
if(i==0) return *this;
copyonwrite();
unsigned int imod = i%blockbits;
unsigned int ishift = i/blockbits;
if(autoresize) resize(size()+i,true);
for(int dest=nn-1; dest>=0; --dest)
{
int src=dest-ishift;
if(src<0) v[dest]=0;
else
{
v[dest] = v[src]<<imod;
if(imod && (src-1>=0)) v[dest] |= (v[src-1]& (((1ULL<<imod)-1) <<(blockbits-imod)))>>(blockbits-imod);
}
}
return *this;
}
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;
}
}
unsigned int bitvector::population(const unsigned int before) const
{
if(before) laerror("before parameter in population() not implemented yet");
int i;
unsigned int s=0;
for(i=0; i<nn-1; ++i) s+=word_popul(v[i]);
bitvector_block a=v[nn-1];
if(modulo)
{
bitvector_block mask= ~((bitvector_block)0);
mask <<=modulo;
a &= ~mask;
}
return s+word_popul(a);
}
unsigned int bitvector::operator%(const bitvector &y) const
{
if(nn!=y.nn) laerror("incompatible size in bitdifference");
unsigned int s=0;
for(int i=0; i<nn-1; ++i) s+=word_popul(v[i]^y.v[i]);
bitvector_block a=v[nn-1]^y.v[nn-1];
if(modulo)
{
bitvector_block mask= ~((bitvector_block)0);
mask <<=modulo;
a &= ~mask;
}
return s+word_popul(a);
}
void bitvector::read(int fd, bool dimensions, bool transp)
{
if(dimensions)
{
int r = ::read(fd,&modulo,sizeof(modulo));
if(r!=sizeof(modulo)) laerror("cannot read in bitvector");
}
NRVec<bitvector_block>::get(fd,dimensions,transp);
}
void bitvector::write(int fd, bool dimensions, bool transp)
{
if(dimensions)
{
int r = ::write(fd,&modulo,sizeof(modulo));
if(r!=sizeof(modulo)) laerror("cannot write in bitvector");
}
NRVec<bitvector_block>::put(fd,dimensions,transp);
}
}//namespace