3 // Implements operations over a bitmap
7 // In theory, we should have superblocks of size s=log^2 n divided into
8 // blocks of size b=(log n)/2. This takes
9 // O(n log n / log^2 n + n log log n / log n + log n sqrt n log log n) bits
10 // In practice, we can have any s and b, and the needed amount of bits is
11 // (n/s) log n + (n/b) log s + b 2^b log b bits
12 // Optimizing it turns out that s should be exactly s = b log n
13 // Optimizing b is more difficult but could be done numerically.
14 // However, the exponential table does no more than popcounting, so why not
15 // setting up a popcount algorithm tailored to the computer register size,
16 // defining that size as b, and proceeding.
18 const unsigned char popc[] =
20 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
21 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
22 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
23 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
24 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
25 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
26 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
27 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
30 uint popcount (register uint x)
32 return popc[x&0xFF] + popc[(x>>8)&0xFF] + popc[(x>>16)&0xFF] + popc[x>>24];
35 uint popcount8(register int x)
37 return popc[x & 0xff];
41 // creates a bitmap structure from a bitstring, which is shared
43 bitmap createBitmap (uint *string, uint n, bool isfullbmap)
46 uint i,j,pop,bpop,pos;
48 B = malloc (sizeof(struct sbitmap));
50 B->n = n; words = (n+W-1)/W;
51 ns = (n+256-1)/256; nb = 256/W; // adjustments
52 B->bdata = malloc (ns*nb*sizeof(byte));
53 B->sdata = malloc (ns*sizeof(int));
55 printf (" Bitmap over %i bits took %i bits\n", n,n+ns*nb*8+ns*32);
62 if (pos == words) break;
63 B->bdata[pos++] = bpop;
64 bpop += popcount(*string++);
68 if (isfullbmap) {// creates the data structure to solve select_0() queries
69 B->bdata_0 = malloc(ns*nb*sizeof(byte));
70 B->sdata_0 = malloc(ns*sizeof(int));
73 for (i = 0; i < ns; i++) {
76 for (j = 0; j < nb; j++) {
77 if (pos == words) break;
78 B->bdata_0[pos++] = bpop;
79 bpop += popcount(~(*string++));
84 else { B->bdata_0 = NULL; B->sdata_0 = NULL;}
88 // rank(i): how many 1's are there before position i, not included
90 uint rank (bitmap B, uint i)
92 return B->sdata[i>>8] + B->bdata[i>>5] +
93 popcount (B->data[i>>5] & ((1<<(i&0x1F))-1));
97 // select_1(x): returns the position i of the bitmap B such that
98 // the number of ones up to position i is x.
100 uint select_1(bitmap B, uint x)
103 uint l = 0, n = B->n, r = n/s,left;
106 uint rankmid = B->sdata[mid];
107 // first, binary search on the superblock array
114 rankmid = B->sdata[mid];
116 // sequential search using popcount over an int
124 if (left > (n+W-1)/W) return n;
128 // sequential search using popcount over a char
130 rankmid = popcount8(j);
135 rankmid = popcount8(j);
140 rankmid = popcount8(j);
148 // finally sequential search bit per bit
158 // select_0(x): returns the position i of the bitmap B such that
159 // the number of zeros up to position i is x.
161 uint select_0(bitmap B, uint x)
164 uint l = 0, n = B->n, r = n/s, left;
167 uint rankmid = B->sdata_0[mid];
168 // first, binary search on the superblock array
175 rankmid = B->sdata_0[mid];
177 // sequential search using popcount over an int
185 if (left > (n+W-1)/W) return n;
189 // sequential search using popcount over a char
191 rankmid = popcount8(~j);
196 rankmid = popcount8(~j);
201 rankmid = popcount8(~j);
209 // finally sequential search bit per bit
221 // destroys the bitmap, freeing the original bitstream
223 void destroyBitmap (bitmap B)
232 uint sizeofBitmap(bitmap B)
234 return sizeof(struct sbitmap) +
235 ((B->n+W-1)/W)*sizeof(uint) + // data
236 ((B->n+256-1)/256)*sizeof(int) + // sdata
237 ((B->n+256-1)/256)*(256/W)*sizeof(byte); // bdata
238 //((B->sdata_0)?((B->n+256-1)/256)*sizeof(int):0) +
239 //((B->bdata_0)?((B->n+256-1)/256)*(256/W)*sizeof(byte):0);