package it.unimi.dsi.bits;
import it.unimi.dsi.bits.BitVector;
import it.unimi.dsi.bits.BooleanListBitVector;
import it.unimi.dsi.bits.LongArrayBitVector;
import it.unimi.dsi.fastutil.io.BinIO;
import it.unimi.dsi.fastutil.longs.LongBidirectionalIterator;
import it.unimi.dsi.fastutil.longs.LongListIterator;
import it.unimi.dsi.fastutil.longs.LongSortedSet;
import it.unimi.dsi.util.LongBigList;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import junit.framework.TestCase;
public abstract class BitVectorTestCase extends TestCase {
public static void testSetClearFlip( final BitVector v ) {
final int size = v.size();
for( int i = size; i-- != 0; ) {
v.set( i );
assertTrue( v.getBoolean( i ) );
}
for( int i = size; i-- != 0; ) {
v.clear( i );
assertFalse( v.getBoolean( i ) );
}
for( int i = size; i-- != 0; ) {
v.set( i );
v.flip( i );
assertFalse( v.getBoolean( i ) );
v.flip( i );
assertTrue( v.getBoolean( i ) );
}
}
public static void testRemove( final BitVector v ) {
v.clear();
v.size( 100 );
v.set( 0, true );
assertTrue( v.removeBoolean( 0 ) );
assertFalse( v.getBoolean( 0 ) );
v.clear();
v.size( 100 );
v.set( 63, true );
v.set( 64, true );
assertTrue( v.removeBoolean( 63 ) );
assertTrue( v.getBoolean( 63 ) );
assertFalse( v.getBoolean( 64 ) );
assertFalse( v.getBoolean( 0 ) );
}
public static void testAdd( final BitVector v ) {
v.clear();
v.size( 100 );
v.add( 0, true );
assertTrue( v.getBoolean( 0 ) );
v.add( 0, true );
assertTrue( v.getBoolean( 0 ) );
assertTrue( v.getBoolean( 1 ) );
v.add( false );
assertTrue( v.getBoolean( 0 ) );
assertTrue( v.getBoolean( 1 ) );
assertFalse( v.getBoolean( 2 ) );
v.set( 1, false );
assertTrue( v.getBoolean( 0 ) );
assertFalse( v.getBoolean( 1 ) );
assertFalse( v.getBoolean( 2 ) );
v.set( 1, true );
assertTrue( v.getBoolean( 0 ) );
assertTrue( v.getBoolean( 1 ) );
assertFalse( v.getBoolean( 2 ) );
v.clear();
v.size( 100 );
v.add( 0, 1 );
assertEquals( 1, v.getInt( 0 ) );
v.add( 0, 2 );
assertEquals( 1, v.getInt( 0 ) );
assertEquals( 1, v.getInt( 1 ) );
v.add( 0, 0 );
assertEquals( 0, v.getInt( 0 ) );
assertEquals( 1, v.getInt( 1 ) );
assertEquals( 1, v.getInt( 2 ) );
v.add( 0 );
assertEquals( 0, v.getInt( 0 ) );
assertEquals( 1, v.getInt( 1 ) );
assertEquals( 1, v.getInt( 2 ) );
assertEquals( 0, v.getInt( 3 ) );
v.set( 1, 0 );
assertEquals( 0, v.getInt( 0 ) );
assertEquals( 0, v.getInt( 1 ) );
assertEquals( 1, v.getInt( 2 ) );
assertEquals( 0, v.getInt( 3 ) );
v.set( 1, 1 );
assertEquals( 0, v.getInt( 0 ) );
assertEquals( 1, v.getInt( 1 ) );
assertEquals( 1, v.getInt( 2 ) );
assertEquals( 0, v.getInt( 3 ) );
v.clear();
v.append( 1, 2 );
v.append( 1, 2 );
v.append( 3, 2 );
assertEquals( LongArrayBitVector.of( 1, 0, 1, 0, 1, 1 ), v );
v.clear();
for( int i = 0; i < 80; i++ ) v.add( 0, true );
for( int i = 0; i < 80; i++ ) assertTrue( v.getBoolean( i ) );
v.clear();
for( int i = 0; i < 80; i++ ) v.add( 0, false );
for( int i = 0; i < 80; i++ ) assertFalse( v.getBoolean( i ) );
}
public static void testFillFlip( final BitVector v ) {
v.clear();
v.size( 100 );
v.fill( true );
for( int i = v.size(); i-- != 0; ) assertTrue( v.getBoolean( i ) );
v.fill( false );
for( int i = v.size(); i-- != 0; ) assertFalse( v.getBoolean( i ) );
v.flip();
for( int i = v.size(); i-- != 0; ) assertTrue( v.getBoolean( i ) );
v.clear();
v.size( 100 );
v.fill( 1 );
for( int i = v.size(); i-- != 0; ) assertTrue( v.getBoolean( i ) );
v.fill( 0 );
for( int i = v.size(); i-- != 0; ) assertFalse( v.getBoolean( i ) );
v.clear();
v.size( 100 );
v.fill( 5, 70, true );
for( int i = v.size(); i-- != 0; ) assertEquals( Integer.toString( i ), i >= 5 && i < 70, v.getBoolean( i ) );
v.fill( true );
v.fill( 5, 70, false );
for( int i = v.size(); i-- != 0; ) assertEquals( Integer.toString( i ), i < 5 || i >= 70, v.getBoolean( i ) );
v.clear();
v.size( 100 );
v.fill( 5, 70, 1 );
for( int i = v.size(); i-- != 0; ) assertEquals( Integer.toString( i ), i >= 5 && i < 70, v.getBoolean( i ) );
v.fill( true );
v.fill( 5, 70, 0 );
for( int i = v.size(); i-- != 0; ) assertEquals( i < 5 || i >= 70, v.getBoolean( i ) );
v.clear();
v.size( 100 );
v.flip( 5, 70 );
for( int i = v.size(); i-- != 0; ) assertEquals( Integer.toString( i ), i >= 5 && i < 70, v.getBoolean( i ) );
v.fill( true );
v.flip( 5, 70 );
for( int i = v.size(); i-- != 0; ) assertEquals( i < 5 || i >= 70, v.getBoolean( i ) );
}
public static void testCopy( final BitVector v ) {
v.clear();
v.size( 100 );
v.fill( 5, 80, true );
BitVector w = v.copy( 0, 85 );
assertEquals( w, v.subVector( 0, 85 ).copy() );
for( int i = w.size(); i-- != 0; ) assertEquals( i >= 5 && i < 80, w.getBoolean( i ) );
w = v.copy( 5, 85 );
assertEquals( w, v.subVector( 5, 85 ).copy() );
for( int i = w.size(); i-- != 0; ) assertEquals( i < 75, w.getBoolean( i ) );
v.clear();
int[] bits = { 0,0,0,0,1,1,1,0,0,0,0,1,1,0,0 };
for( int i = 0; i < bits.length; i++ ) v.add( bits[ i ] );
LongArrayBitVector c = LongArrayBitVector.getInstance();
for( int i = 5; i < bits.length; i++ ) c.add( bits[ i ] );
assertEquals( c, v.copy( 5, 15 ) );
assertEquals( c, v.subVector( 5, 15 ).copy() );
v.clear();
bits = new int[] { 0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0 };
for( int i = 0; i < bits.length; i++ ) v.add( bits[ i ] );
c = LongArrayBitVector.getInstance();
for( int i = 5; i < bits.length - 2; i++ ) c.add( bits[ i ] );
assertEquals( c, v.copy( 5, bits.length - 2 ) );
assertEquals( v, v.copy() );
long[] words = new long[] { 0xDEADBEEFDEADF00DL, 0xDEADBEEFDEADF00DL, 0xDEADBEEFDEADF00DL, };
long[] copyWords16 = new long[] { 0xF00DDEADBEEFDEADL, 0xF00DDEADBEEFDEADL, 0xBEEFDEADL };
long[] copyWords32 = new long[] { 0xDEADF00DDEADBEEFL, 0xDEADF00DDEADBEEFL };
LongArrayBitVector.wrap( copyWords16, 64 * 2 + 32 ).equals( LongArrayBitVector.wrap( words, 64 * 3 ).copy( 16, 16 + 64 * 2 + 32 ) );
assertEquals( LongArrayBitVector.wrap( copyWords16, 64 * 2 + 32 ), LongArrayBitVector.wrap( words, 64 * 3 ).copy( 16, 16 + 64 * 2 + 32 ) );
copyWords16[ 2 ] &= 0xFFFF;
assertEquals( LongArrayBitVector.wrap( copyWords16, 64 * 2 + 16 ), LongArrayBitVector.wrap( words, 64 * 3 ).copy( 16, 16 + 64 * 2 + 16 ) );
copyWords16[ 2 ] &= 0xFF;
assertEquals( LongArrayBitVector.wrap( copyWords16, 64 * 2 + 8 ), LongArrayBitVector.wrap( words, 64 * 3 ).copy( 16, 16 + 64 * 2 + 8 ) );
copyWords16[ 2 ] &= 0x1F;
assertEquals( LongArrayBitVector.wrap( copyWords16, 64 * 2 + 5 ), LongArrayBitVector.wrap( words, 64 * 3 ).copy( 16, 16 + 64 * 2 + 5 ) );
copyWords16[ 2 ] &= 0x1;
assertEquals( LongArrayBitVector.wrap( copyWords16, 64 * 2 + 1 ), LongArrayBitVector.wrap( words, 64 * 3 ).copy( 16, 16 + 64 * 2 + 1 ) );
copyWords32[ 1 ] &= 0xFFFFFFFFFFFFL;
assertEquals( LongArrayBitVector.wrap( copyWords32, 64 * 1 + 32 + 16 ), LongArrayBitVector.wrap( words, 64 * 3 ).copy( 32, 32 + 64 + 32 + 16 ) );
copyWords32[ 1 ] &= 0xFFFFFFFFFFL;
assertEquals( LongArrayBitVector.wrap( copyWords32, 64 * 1 + 32 + 8 ), LongArrayBitVector.wrap( words, 64 * 3 ).copy( 32, 32 + 64 + 32 + 8 ) );
copyWords32[ 1 ] &= 0x1FFFFFFFFFL;
assertEquals( LongArrayBitVector.wrap( copyWords32, 64 * 1 + 32 + 5 ), LongArrayBitVector.wrap( words, 64 * 3 ).copy( 32, 32 + 64 + 32 + 5 ) );
copyWords32[ 1 ] &= 0x1FFFFFFFFL;
assertEquals( LongArrayBitVector.wrap( copyWords32, 64 * 1 + 32 + 1 ), LongArrayBitVector.wrap( words, 64 * 3 ).copy( 32, 32 + 64 + 32 + 1 ) );
}
public static void its( BitVector b ) {
for( int i = 0; i < 100; i++ ) b.add( i % 2 );
assertTrue( LongArrayBitVector.wrap( b.bits(), b.length() ).toString(), Arrays.equals( new long[] { 0xAAAAAAAAAAAAAAAAL, 0x0000000AAAAAAAAAL }, b.bits() ) );
}
public static void testLongBigListView( BitVector b ) {
LongBigList list = b.asLongBigList( 10 );
for( int i = 0; i < 100; i++ ) list.add( i );
for( int i = 0; i < 100; i++ ) assertEquals( i, list.getLong( i ) );
assertTrue( b.getBoolean( 10 ) );
assertTrue( b.getBoolean( 21 ) );
for( int i = 0; i < 100; i++ ) list.add( i );
for( int i = 0; i < 100; i++ ) {
assertEquals( i, list.set( i, i + 1 ) );
for( int j = i + 1; j < 100; j++ ) assertEquals( "" + i , j, list.getLong( j ) );
}
for( int i = 0; i < 100; i++ ) assertEquals( i + 1, list.getLong( i ) );
assertTrue( b.getBoolean( 0 ) );
assertTrue( b.getBoolean( 11 ) );
list.size( 100 );
int k = 0;
LongListIterator i = list.listIterator();
while( i.hasNext() ) {
assertEquals( k, i.nextIndex() );
assertEquals( ++k, i.nextLong() );
}
while( i.hasPrevious() ) {
assertEquals( k - 1, i.previousIndex() );
assertEquals( k--, i.previousLong() );
}
}
public static void testLongSetView( BitVector b ) {
LongSortedSet s = b.asLongSet();
assertNull( s.comparator() );
for( int i = 0; i < 100; i++ ) s.add( i * 2 );
for( int i = 0; i < 100; i++ ) assertTrue( s.contains( i * 2 ) );
for( int i = 0; i < 100; i++ ) assertFalse( s.contains( i * 2 + 1 ) );
LongBidirectionalIterator iterator = s.iterator();
for( int i = 0; i < 100; i++ ) assertEquals( i * 2, iterator.nextLong() );
assertFalse( iterator.hasNext() );
for( int i = 100; i-- != 0; ) assertEquals( i * 2, iterator.previousLong() );
assertFalse( iterator.hasPrevious() );
assertEquals( 100, s.size() );
assertEquals( false, s.remove( 1 ) );
assertEquals( 100, s.size() );
assertEquals( true, s.remove( 0 ) );
assertEquals( 99, s.size() );
assertEquals( true, s.remove( 60 ) );
assertEquals( 98, s.size() );
assertEquals( false, s.remove( 1000 ) );
assertEquals( 98, s.size() );
assertEquals( false, s.add( 2 ) );
assertEquals( 98, s.size() );
assertEquals( 2, s.firstLong() );
assertEquals( 198, s.lastLong() );
assertEquals( 18, s.subSet( 3, 40 ).size());
assertEquals( 19, s.headSet( 40 ).size());
assertEquals( 5, s.tailSet( 190 ).size());
iterator = s.iterator();
assertEquals( 2, iterator.nextLong() );
iterator.remove();
assertFalse( s.contains( 2 ) );
s.clear();
assertNull( s.comparator() );
for( int i = 0; i < 100; i++ ) s.add( i );
for( int i = 0; i < 100; i++ ) assertTrue( s.contains( i ) );
iterator = s.iterator();
for( int i = 0; i < 100; i++ ) assertEquals( i, iterator.nextLong() );
assertFalse( iterator.hasNext() );
for( int i = 100; i-- != 0; ) assertEquals( i, iterator.previousLong() );
assertFalse( iterator.hasPrevious() );
}
public static void testFirstLastPrefix( BitVector b ) {
b.clear();
b.length( 60 );
assertEquals( -1, b.firstOne() );
assertEquals( -1, b.lastOne() );
b.flip();
assertEquals( -1, b.firstZero() );
assertEquals( -1, b.lastZero() );
b.flip();
b.set( 4, true );
assertEquals( 4, b.firstOne() );
assertEquals( 4, b.lastOne() );
b.flip();
assertEquals( 4, b.firstZero() );
assertEquals( 4, b.lastZero() );
b.flip();
b.set( 50, true );
assertEquals( 4, b.firstOne() );
assertEquals( 50, b.nextOne( 5 ) );
assertEquals( 50, b.lastOne() );
assertEquals( 4, b.previousOne( 50 ) );
b.flip();
assertEquals( 4, b.firstZero() );
assertEquals( 50, b.nextZero( 5 ) );
assertEquals( 50, b.lastZero() );
assertEquals( 4, b.previousZero( 50 ) );
b.flip();
b.set( 20, true );
assertEquals( 4, b.firstOne() );
assertEquals( 20, b.nextOne( 5 ) );
assertEquals( 50, b.nextOne( 21 ) );
assertEquals( 50, b.lastOne() );
assertEquals( 20, b.previousOne( 50 ) );
assertEquals( 4, b.previousOne( 20 ) );
b.flip();
assertEquals( 4, b.firstZero() );
assertEquals( 20, b.nextZero( 5 ) );
assertEquals( 50, b.nextZero( 21 ) );
assertEquals( 50, b.lastZero() );
assertEquals( 20, b.previousZero( 50 ) );
assertEquals( 4, b.previousZero( 20 ) );
b.flip();
b.length( 100 );
b.set( 90, true );
assertEquals( 4, b.firstOne() );
assertEquals( 90, b.lastOne() );
b.flip();
assertEquals( 4, b.firstZero() );
assertEquals( 90, b.lastZero() );
b.flip();
b.clear();
b.length( 100 );
assertEquals( -1, b.firstOne() );
assertEquals( -1, b.lastOne() );
b.flip();
assertEquals( -1, b.firstZero() );
assertEquals( -1, b.lastZero() );
b.flip();
b.set( 4, true );
assertEquals( 4, b.firstOne() );
assertEquals( 4, b.lastOne() );
b.flip();
assertEquals( 4, b.firstZero() );
assertEquals( 4, b.lastZero() );
b.flip();
b.set( 90, true );
assertEquals( 4, b.firstOne() );
assertEquals( 90, b.lastOne() );
b.flip();
assertEquals( 4, b.firstZero() );
assertEquals( 90, b.lastZero() );
b.flip();
b.length( 60 );
BitVector c = b.copy();
c.length( 40 );
assertEquals( c.length(), b.longestCommonPrefixLength( c ) );
c.flip( 20 );
assertEquals( 20, b.longestCommonPrefixLength( c ) );
c.flip( 0 );
assertEquals( 0, b.longestCommonPrefixLength( c ) );
b.length( 128 ).fill( false );
b.set( 127 );
c.length( 65 ).fill( false );
assertEquals( 65, b.longestCommonPrefixLength( c ) );
b.length( 100 );
c = b.copy();
c.length( 80 );
assertEquals( c.length(), b.longestCommonPrefixLength( c ) );
assertEquals( c.length(), b.longestCommonPrefixLength( BooleanListBitVector.wrap( c ) ) );
c.flip( 20 );
assertEquals( 20, b.longestCommonPrefixLength( c ) );
assertEquals( 20, b.longestCommonPrefixLength( BooleanListBitVector.wrap( c ) ) );
c.flip( 0 );
assertEquals( 0, b.longestCommonPrefixLength( c ) );
assertEquals( 0, b.longestCommonPrefixLength( BooleanListBitVector.wrap( c ) ) );
c.clear();
c.length( 2 );
c.set( 0, 0 );
assertFalse( c.getBoolean( 0 ) );
c.set( 0, 1 );
assertTrue( c.getBoolean( 0 ) );
c.set( 0, 2 );
assertTrue( c.getBoolean( 0 ) );
c.set( 0, 0 );
assertFalse( c.getBoolean( 0 ) );
c.add( 0, 0 );
assertFalse( c.getBoolean( 0 ) );
c.add( 0, 1 );
assertTrue( c.getBoolean( 0 ) );
}
public static void testLogicOperators( BitVector b ) {
b.clear();
b.length( 100 );
BitVector c = b.copy();
for( int i = 0; i < 50; i++ ) b.set( 2 * i );
for( int i = 0; i < 50; i++ ) c.set( 2 * i + 1 );
BitVector r;
r = b.copy().and( c );
for( int i = 0; i < 100; i++ ) assertFalse( r.getBoolean( i ) );
r = b.copy().or( c );
for( int i = 0; i < 100; i++ ) assertTrue( r.getBoolean( i ) );
r = b.copy().xor( c );
for( int i = 0; i < 100; i++ ) assertTrue( r.getBoolean( i ) );
r.xor( r );
for( int i = 0; i < 100; i++ ) assertFalse( r.getBoolean( i ) );
r = b.copy().and( BooleanListBitVector.wrap( c ) );
for( int i = 0; i < 100; i++ ) assertFalse( r.getBoolean( i ) );
r = b.copy().or( BooleanListBitVector.wrap( c ) );
for( int i = 0; i < 100; i++ ) assertTrue( r.getBoolean( i ) );
r = b.copy().xor( BooleanListBitVector.wrap( c ) );
for( int i = 0; i < 100; i++ ) assertTrue( r.getBoolean( i ) );
r.xor( BooleanListBitVector.wrap( r ) );
for( int i = 0; i < 100; i++ ) assertFalse( r.getBoolean( i ) );
}
public static void testCount( BitVector b ) {
b.clear();
b.length( 100 );
for( int i = 0; i < 50; i++ ) b.set( i * 2 );
assertEquals( 50, b.count() );
}
public static void testSerialisation( BitVector b ) throws IOException, ClassNotFoundException {
final File file = File.createTempFile( BitVectorTestCase.class.getSimpleName(), "test" );
file.deleteOnExit();
b.clear();
BinIO.storeObject( b, file );
assertEquals( b, BinIO.loadObject( file ) );
b.length( 1000 );
BinIO.storeObject( b, file );
assertEquals( b, BinIO.loadObject( file ) );
b.fill( true );
BinIO.storeObject( b, file );
assertEquals( b, BinIO.loadObject( file ) );
}
public static void testReplace( BitVector b ) {
Random r = new Random( 1 );
LongArrayBitVector bv = LongArrayBitVector.getInstance( 200 );
for( int i = 0; i < 100; i++ ) bv.add( r.nextBoolean() );
assertEquals( b.replace( bv ), bv );
bv = LongArrayBitVector.getInstance( 256 );
for( int i = 0; i < 256; i++ ) bv.add( r.nextBoolean() );
assertEquals( b.replace( bv ), bv );
bv = LongArrayBitVector.getInstance( 10 );
for( int i = 0; i < 10; i++ ) bv.add( r.nextBoolean() );
assertEquals( b.replace( bv ), bv );
}
public static void testAppend( BitVector b ) {
b.clear();
LongArrayBitVector v = LongArrayBitVector.ofLength( 200 );
for( int i = 0; i < 60; i++ ) v.set( i * 3 );
b.append( v );
assertEquals( b, v );
b.clear();
b.add( true );
b.append( v );
LongArrayBitVector w = LongArrayBitVector.ofLength( 201 );
for( int i = 0; i < 60; i++ ) w.set( i * 3 + 1 );
w.set( 0 );
assertEquals( w, b );
}
}