2008-02-26 14:55:23 +01:00
/*
LA : linear algebra C + + interface library
2023-12-28 23:48:05 +01:00
Copyright ( C ) 2008 - 2023 Jiri Pittner < jiri . pittner @ jh - inst . cas . cz > or < jiri @ pittnerovi . com >
2008-02-26 14:55:23 +01:00
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/>.
*/
2005-09-08 17:16:18 +02:00
# ifndef _BITVECTOR_H_
# define _BITVECTOR_H_
# include "vec.h"
2023-12-28 23:48:05 +01:00
# include "numbers.h"
2024-01-02 14:05:28 +01:00
# include "laerror.h"
2023-12-27 23:24:13 +01:00
# include <stdint.h>
2005-09-08 17:16:18 +02:00
2024-01-02 14:05:28 +01:00
//TODO: if efficiency is requires, make also a monic_bitvector, which will not store the leading 1 explicitly
//and then the field operations will be done without any resize
//To avoid confusion this class must NOT be derived from bitvector and have only explicit constructor conversion
2009-11-12 22:01:19 +01:00
2023-12-27 23:24:13 +01:00
namespace LA {
2005-09-08 17:16:18 +02:00
//compressed storage of large bit vectors
2023-12-28 17:06:07 +01:00
//let's now use 64-bit blocks exclusively for simplicity
2006-03-30 21:16:40 +02:00
2023-12-27 23:24:13 +01:00
typedef uint64_t bitvector_block ;
2006-03-30 21:16:40 +02:00
# define blockbits (8*sizeof(bitvector_block))
inline unsigned int bitvector_rounded ( unsigned int n )
{
return ( ( n + blockbits - 1 ) / blockbits ) * blockbits ;
}
class bitvector : public NRVec < bitvector_block >
2005-09-08 17:16:18 +02:00
{
private :
2006-03-30 21:16:40 +02:00
unsigned int modulo ;
2005-09-08 17:16:18 +02:00
public :
2006-03-30 21:16:40 +02:00
bitvector ( ) : NRVec < bitvector_block > ( ) { } ;
2024-01-01 21:26:35 +01:00
explicit bitvector ( const unsigned int n ) : NRVec < bitvector_block > ( ( n + blockbits - 1 ) / blockbits ) { modulo = n % blockbits ; memset ( v , 0 , nn * sizeof ( bitvector_block ) ) ; } ;
2006-03-30 21:16:40 +02:00
bitvector ( const bitvector_block a , const unsigned int n ) : NRVec < bitvector_block > ( a , ( n + blockbits - 1 ) / blockbits ) { modulo = n % blockbits ; } ;
2006-03-31 21:01:14 +02:00
bitvector ( const bitvector & rhs ) : NRVec < bitvector_block > ( rhs ) { modulo = rhs . modulo ; } ;
2024-01-02 14:05:28 +01:00
explicit bitvector ( const uint8_t * data , const unsigned int n ) : NRVec < bitvector_block > ( ( n + blockbits - 1 ) / blockbits )
{
modulo = n % blockbits ;
if ( endianity ( ) ) laerror ( " not portable to big endian " ) ;
else memcpy ( & v [ 0 ] , data , ( n + 7 ) / 8 ) ;
zero_padding ( ) ;
} ;
void getdata ( uint8_t * data )
{
if ( endianity ( ) ) laerror ( " not portable to big endian " ) ;
else memcpy ( data , & v [ 0 ] , ( size ( ) + 7 ) / 8 ) ;
}
2006-03-31 21:01:14 +02:00
//operator= seems to be correctly synthetized by the compiler
2006-03-30 21:16:40 +02:00
//override dereferencing to address single bits, is however possible
2005-09-08 17:16:18 +02:00
//only in the const context (otherwise we would have to define a type which, when assigned to, changes a single bit - possible but probably inefficient)
2023-12-28 17:06:07 +01:00
void resize ( const unsigned int n , bool preserve = false ) ; //preserve data or clear
2006-03-30 21:16:40 +02:00
unsigned int size ( ) const { return ( nn * blockbits ) - blockbits + ( modulo ? modulo : blockbits ) ; } ;
//arguments must be unsigned to keep the resulting assembly code simple and efficient
2023-12-28 17:06:07 +01:00
const bool operator [ ] ( const unsigned int i ) const { return ( v [ i / blockbits ] > > ( i % blockbits ) ) & 1ULL ; } ;
2023-12-27 23:24:13 +01:00
const bool get ( const unsigned int i ) const { return ( * this ) [ i ] ; } ;
2022-06-22 19:41:25 +02:00
bitvector_block getblock ( const unsigned int i ) const { return v [ i ] ; } ; //integer interpretation
void setblock ( const unsigned int i , const bitvector_block b ) { v [ i ] = b ; } ;
int getblocksize ( ) const { return 8 * sizeof ( bitvector_block ) ; } ;
2024-01-02 14:05:28 +01:00
void set ( const unsigned int i )
{
# ifdef DEBUG
if ( i > = size ( ) ) laerror ( " bitvector index out of range in " ) ;
# endif
v [ i / blockbits ] | = ( 1UL < < ( i % blockbits ) ) ;
} ;
void reset ( const unsigned int i )
{
# ifdef DEBUG
if ( i > = size ( ) ) laerror ( " bitvector index out of range in " ) ;
# endif
v [ i / blockbits ] & = ~ ( 1UL < < ( i % blockbits ) ) ;
} ;
void flip ( const unsigned int i )
{
# ifdef DEBUG
if ( i > = size ( ) ) laerror ( " bitvector index out of range in " ) ;
# endif
v [ i / blockbits ] ^ = ( 1UL < < ( i % blockbits ) ) ;
} ;
2006-03-30 21:16:40 +02:00
const bool assign ( const unsigned int i , const bool r ) { if ( r ) set ( i ) ; else reset ( i ) ; return r ; } ;
2013-11-04 15:56:39 +01:00
void clear ( ) { copyonwrite ( true ) ; memset ( v , 0 , nn * sizeof ( bitvector_block ) ) ; } ;
2006-03-30 21:16:40 +02:00
void fill ( ) { memset ( v , 0xff , nn * sizeof ( bitvector_block ) ) ; } ;
2024-01-01 21:26:35 +01:00
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 ( ) ; } ;
2023-12-27 23:24:13 +01:00
void randomize ( ) ;
2024-01-01 21:26:35 +01:00
bitvector & operator + + ( ) ;
bitvector & operator - - ( ) ;
2006-03-31 21:01:14 +02:00
bool operator ! = ( const bitvector & rhs ) const ;
bool operator = = ( const bitvector & rhs ) const { return ! ( * this ! = rhs ) ; } ;
bool operator > ( const bitvector & rhs ) const ;
bool operator < ( const bitvector & rhs ) const ;
bool operator > = ( const bitvector & rhs ) const { return ! ( * this < rhs ) ; } ;
bool operator < = ( const bitvector & rhs ) const { return ! ( * this > rhs ) ; } ;
bitvector operator ~ ( ) const ;
bitvector & operator & = ( const bitvector & rhs ) ;
bitvector & operator | = ( const bitvector & rhs ) ;
bitvector & operator ^ = ( const bitvector & rhs ) ;
2024-01-01 21:26:35 +01:00
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 ; } ;
2023-12-27 23:24:13 +01:00
bitvector & operator + = ( const bitvector & rhs ) { return ( * this ) ^ = rhs ; } ; //addition modulo 2
bitvector & operator - = ( const bitvector & rhs ) { return ( * this ) ^ = rhs ; } ; //subtraction modulo 2
2006-03-31 21:01:14 +02:00
bitvector operator & ( const bitvector & rhs ) const { return bitvector ( * this ) & = rhs ; } ;
bitvector operator | ( const bitvector & rhs ) const { return bitvector ( * this ) | = rhs ; } ;
bitvector operator ^ ( const bitvector & rhs ) const { return bitvector ( * this ) ^ = rhs ; } ;
2023-12-27 23:24:13 +01:00
bitvector operator + ( const bitvector & rhs ) const { return * this ^ rhs ; } ; //addition modulo 2
bitvector operator - ( const bitvector & rhs ) const { return * this ^ rhs ; } ; //subtraction modulo 2
2023-12-31 19:48:07 +01:00
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!!!
2024-01-01 10:58:30 +01:00
bitvector & operator * = ( const bitvector & rhs ) { * this = ( * this ) * rhs ; return * this ; }
2024-01-01 21:26:35 +01:00
bitvector pow ( unsigned int n ) const ;
2023-12-31 19:48:07 +01:00
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 ) ; } ;
2024-01-01 10:58:30 +01:00
bitvector field_composition ( const bitvector & rhs , const bitvector & irpolynom ) const ;
2024-01-01 21:26:35 +01:00
bitvector field_pow ( unsigned int n , const bitvector & irpolynom ) const ;
bitvector field_sqrt ( const bitvector & irpolynom ) const ;
2024-01-01 10:58:30 +01:00
bool is_irreducible ( ) const ; //test irreducibility of polynomial over GF2
2023-12-28 17:06:07 +01:00
bitvector division ( const bitvector & rhs , bitvector & remainder ) const ;
bitvector operator / ( const bitvector & rhs ) const { bitvector rem ( rhs . size ( ) ) ; return division ( rhs , rem ) ; } ;
bitvector operator % ( const bitvector & rhs ) const { bitvector rem ( rhs . size ( ) ) ; division ( rhs , rem ) ; return rem ; } ;
2023-12-31 19:48:07 +01:00
bitvector gcd ( const bitvector & rhs ) const ; //as a polynomial over GF2
2023-12-28 17:06:07 +01:00
bitvector lcm ( const bitvector & rhs ) const { return ( * this ) * rhs / this - > gcd ( rhs ) ; } ;
2024-01-01 10:58:30 +01:00
bitvector composition ( const bitvector & rhs ) const ;
2023-12-31 19:48:07 +01:00
unsigned int bitdiff ( const bitvector & y ) const ; //number of differing bits (Hamming distance)
2024-01-01 21:26:35 +01:00
unsigned int population ( const unsigned int before = 0 ) const ; //number of 1's (Hamming weight)
2023-12-28 17:06:07 +01:00
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)
2024-01-01 10:58:30 +01:00
void truncate ( int t = 0 ) { int s = degree ( ) + 1 ; if ( t > s ) s = t ; resize ( s , true ) ; } ;
2023-12-28 17:06:07 +01:00
unsigned int ntz ( ) const ; //number of trailing zeroes
2006-03-31 21:01:14 +02:00
//extended, truncated const i.e. not on *this but return new entity, take care of modulo's bits
2023-12-27 23:24:13 +01:00
//logical shifts
bitvector & operator > > = ( unsigned int i ) ;
bitvector & leftshift ( unsigned int i , bool autoresize = false ) ;
bitvector & operator < < = ( unsigned int i ) { return leftshift ( i , true ) ; } ;
2023-12-28 17:06:07 +01:00
bitvector operator > > ( unsigned int i ) const { bitvector r ( * this ) ; return r > > = i ; } ;
bitvector operator < < ( unsigned int i ) const { bitvector r ( * this ) ; return r < < = i ; } ;
2006-03-31 21:01:14 +02:00
//logical rotations not implemented yet
2021-04-21 15:04:37 +02:00
//unformatted file IO
void read ( int fd , bool dimensions = 1 , bool transp = 0 ) ;
void write ( int fd , bool dimensions = 1 , bool transp = 0 ) ;
2005-09-08 17:16:18 +02:00
} ;
2024-01-01 21:26:35 +01:00
extern bitvector find_irreducible ( int deg , int pop = - 1 , int nth = 1 ) ; //degree and requested Hamming weight or -1 for random trial
2022-06-22 19:41:25 +02:00
//expand to separate bytes or ints
template < typename T >
void bitvector_expand ( const bitvector & v , NRVec < T > & r )
{
int n = v . size ( ) ;
r . resize ( n ) ;
r . clear ( ) ;
for ( int i = 0 ; i < n ; + + i ) if ( v [ i ] ) r [ i ] = 1 ;
}
2022-06-24 06:42:32 +02:00
//mantissa of a floating number between 0 and 1
template < typename T >
2022-07-08 10:58:30 +02:00
bitvector mantissa ( T x , int nbits , int shift = 0 )
2022-06-24 06:42:32 +02:00
{
2022-07-08 10:58:30 +02:00
while ( shift > 0 ) { x + = x ; - - shift ; }
while ( shift < 0 ) { x * = .5 ; + + shift ; }
2022-06-24 06:42:32 +02:00
if ( x < 0 | | x > = 1 ) laerror ( " number not normalized in bitvector mantissa " ) ;
bitvector b ( nbits ) ;
b . clear ( ) ;
T y = x + x ;
2022-07-05 21:19:09 +02:00
for ( int i = 0 ; i < nbits - 1 ; + + i )
2022-06-24 06:42:32 +02:00
{
int n = ( int ) y ;
2022-07-05 21:19:09 +02:00
if ( n & 1 ) b . set ( i + 1 ) ;
2022-06-24 06:42:32 +02:00
y + = y ;
}
return b ;
}
2022-07-01 14:15:44 +02:00
template < typename T >
2022-07-08 10:58:30 +02:00
void bitvector_decimal ( T & x , const bitvector & b , int shift = 0 )
2022-07-01 14:15:44 +02:00
{
x = 0 ;
2022-07-08 10:58:30 +02:00
for ( int i = b . size ( ) - 1 ; i > = 0 ; - - i ) if ( b [ i ] ) x + = 1. / ( 1ULL < < i ) ;
while ( shift > 0 ) { x + = x ; - - shift ; }
while ( shift < 0 ) { x * = .5 ; + + shift ; }
2022-07-01 14:15:44 +02:00
}
2022-06-24 06:42:32 +02:00
2022-06-22 19:41:25 +02:00
template < typename T >
void bitvector_compress ( bitvector & r , const NRVec < T > & v )
{
int n = v . size ( ) ;
r . resize ( n ) ;
r . clear ( ) ;
for ( int i = 0 ; i < n ; + + i ) if ( v [ i ] ) r . set ( i ) ;
}
2009-11-12 22:01:19 +01:00
extern std : : ostream & operator < < ( std : : ostream & s , const bitvector & x ) ;
extern std : : istream & operator > > ( std : : istream & s , bitvector & x ) ;
2006-03-30 21:16:40 +02:00
2021-09-21 15:38:12 +02:00
class bitvector_from1 : public bitvector
{
public :
bitvector_from1 ( ) : bitvector ( ) { } ;
bitvector_from1 ( const bitvector & rhs ) : bitvector ( rhs ) { } ;
explicit bitvector_from1 ( const unsigned int n ) : bitvector ( n ) { } ;
const bool operator [ ] ( const unsigned int i ) { return bitvector : : operator [ ] ( i - 1 ) ; } ;
void set ( const unsigned int i ) { bitvector : : set ( i - 1 ) ; } ;
void reset ( const unsigned int i ) { bitvector : : reset ( i - 1 ) ; } ;
const bool get ( const unsigned int i ) { return bitvector : : get ( i - 1 ) ; } ;
const bool assign ( const unsigned int i , const bool r ) { return bitvector : : assign ( i - 1 , r ) ; } ;
unsigned int population ( const unsigned int before = 0 ) const { return bitvector : : population ( before ? before - 1 : 0 ) ; } ;
} ;
2009-11-12 22:01:19 +01:00
} //namespace
2005-09-08 17:16:18 +02:00
# endif