31 #include "../support/common.hpp"
32 #include "../util/Vector.hpp"
56 static const int log2_ones_per_inventory = 10;
57 static const int ones_per_inventory = 1 << log2_ones_per_inventory;
58 static const int ones_per_inventory_mask = ones_per_inventory - 1;
59 static const uint64_t log2_longwords_per_subinventory = 2;
60 static const int longwords_per_subinventory = 1 << log2_longwords_per_subinventory;
61 static const int log2_ones_per_sub64 = log2_ones_per_inventory - log2_longwords_per_subinventory;
62 static const int ones_per_sub64 = 1 << log2_ones_per_sub64;
63 static const uint64_t ones_per_sub64_mask = ones_per_sub64 - 1;
64 static const int log2_ones_per_sub16 = log2_ones_per_sub64 - 2;
65 static const int ones_per_sub16 = 1 << log2_ones_per_sub16;
66 static const uint64_t ones_per_sub16_mask = ones_per_sub16 - 1;
71 uint64_t num_words, inventory_size, num_ones;
83 num_words = (num_bits + 63) / 64;
87 for (uint64_t i = 0; i < num_words; i++) c += __builtin_popcountll(bits[i]);
90 assert(c <= num_bits);
92 inventory_size = (c + ones_per_inventory - 1) / ones_per_inventory;
95 printf(
"Number of bits: %" PRId64
" Number of ones: %" PRId64
" (%.2f%%)\n", num_bits, c, (c * 100.0) / num_bits);
97 printf(
"Ones per inventory: %d Ones per sub 64: %d sub 16: %d\n", ones_per_inventory, ones_per_sub64, ones_per_sub16);
100 inventory.
size(inventory_size * (longwords_per_subinventory + 1) + 1);
103 const uint64_t mask = ones_per_inventory - 1;
106 for (uint64_t i = 0; i < num_words; i++)
107 for (
int j = 0; j < 64; j++) {
108 if (i * 64 + j >= num_bits)
break;
109 if (bits[i] & 1ULL << j) {
110 if ((d & mask) == 0) inventory[(d >> log2_ones_per_inventory) * (longwords_per_subinventory + 1)] = i * 64 + j;
116 inventory[inventory_size * (longwords_per_subinventory + 1)] = num_bits;
119 printf(
"Inventory entries filled: %" PRId64
"\n", inventory_size + 1);
126 uint64_t exact = 0, start, span, inventory_index;
129 for (uint64_t i = 0; i < num_words; i++)
130 for (
int j = 0; j < 64; j++) {
131 if (i * 64 + j >= num_bits)
break;
132 if (bits[i] & 1ULL << j) {
133 if ((d & mask) == 0) {
134 inventory_index = (d >> log2_ones_per_inventory) * (longwords_per_subinventory + 1);
135 start = inventory[inventory_index];
136 span = inventory[inventory_index + longwords_per_subinventory + 1] - start;
137 if (span > (1 << 16)) inventory[inventory_index] = -inventory[inventory_index] - 1;
139 p64 = &inventory[inventory_index + 1];
140 p16 = (uint16_t *)p64;
143 if (span < (1 << 16)) {
144 assert(i * 64 + j - start <= (1 << 16));
145 if ((d & ones_per_sub16_mask) == 0) {
146 assert(offset < longwords_per_subinventory * 4);
147 p16[offset++] = i * 64 + j - start;
150 if ((d & ones_per_sub64_mask) == 0) {
151 assert(offset < longwords_per_subinventory);
152 p64[offset++] = i * 64 + j - start;
171 printf(
"Selecting %" PRId64
"\n...", rank);
173 assert(rank < num_ones);
175 const uint64_t inventory_index = rank >> log2_ones_per_inventory;
176 assert(inventory_index <= inventory_size);
177 const int64_t *inventory_start = &inventory + (inventory_index << log2_longwords_per_subinventory) + inventory_index;
179 const int64_t inventory_rank = *inventory_start;
180 const int subrank = rank & ones_per_inventory_mask;
182 printf(
"Rank: %" PRId64
" inventory index: %" PRId64
" inventory rank: %" PRId64
" subrank: %d\n", rank, inventory_index, inventory_rank, subrank);
188 if (inventory_rank >= 0) {
189 start = inventory_rank + ((uint16_t *)(inventory_start + 1))[subrank >> log2_ones_per_sub16];
190 residual = subrank & ones_per_sub16_mask;
192 assert((subrank >> log2_ones_per_sub64) < longwords_per_subinventory);
193 start = -inventory_rank - 1 + *(inventory_start + 1 + (subrank >> log2_ones_per_sub64));
194 residual = subrank & ones_per_sub64_mask;
198 printf(
"Differential; start: %" PRId64
" residual: %d\n", start, residual);
199 if (residual == 0) puts(
"No residual; returning start");
202 if (residual == 0)
return start;
204 uint64_t word_index = start / 64;
205 uint64_t word = bits[word_index] & -1ULL << start % 64;
208 const int bit_count = __builtin_popcountll(word);
209 if (residual < bit_count)
break;
210 word = bits[++word_index];
211 residual -= bit_count;
214 return word_index * 64 +
select64(word, residual);
217 uint64_t
select(
const uint64_t rank, uint64_t *
const next) {
218 const uint64_t s = select(rank);
221 uint64_t window = bits[curr] & -1ULL << s;
222 window &= window - 1;
224 while (window == 0) window = bits[++curr];
225 *next = curr * 64 + __builtin_ctzll(window);
231 size_t bitCount()
const {
return inventory.
bitCount() -
sizeof(inventory) * 8 +
sizeof(*
this) * 8; };