31 #include "../support/common.hpp"
32 #include "../util/Vector.hpp"
54 static const int max_zeros_per_inventory = 8192;
59 int log2_zeros_per_inventory, log2_zeros_per_sub16, log2_zeros_per_sub64, log2_longwords_per_subinventory, zeros_per_inventory, zeros_per_sub16, zeros_per_sub64, longwords_per_subinventory,
60 longwords_per_inventory, zeros_per_inventory_mask, zeros_per_sub16_mask, zeros_per_sub64_mask;
62 uint64_t num_words, inventory_size, exact_spill_size, num_zeros;
74 SimpleSelectZero(
const uint64_t *
const bits,
const uint64_t num_bits,
const int max_log2_longwords_per_subinventory) : bits(bits) {
75 num_words = (num_bits + 63) / 64;
79 for (uint64_t i = 0; i < num_words; i++) c += __builtin_popcountll(~bits[i]);
82 if (num_bits % 64 != 0) c -= 64 - num_bits % 64;
83 assert(c <= num_bits);
85 zeros_per_inventory = num_bits == 0 ? 0 : (c * max_zeros_per_inventory + num_bits - 1) / num_bits;
87 log2_zeros_per_inventory = max(0,
lambda_safe(zeros_per_inventory));
88 zeros_per_inventory = 1ULL << log2_zeros_per_inventory;
89 zeros_per_inventory_mask = zeros_per_inventory - 1;
90 inventory_size = (c + zeros_per_inventory - 1) / zeros_per_inventory;
92 log2_longwords_per_subinventory = min(max_log2_longwords_per_subinventory, max(0, log2_zeros_per_inventory - 2));
93 longwords_per_subinventory = 1 << log2_longwords_per_subinventory;
94 longwords_per_inventory = longwords_per_subinventory + 1;
95 log2_zeros_per_sub64 = max(0, log2_zeros_per_inventory - log2_longwords_per_subinventory);
96 log2_zeros_per_sub16 = max(0, log2_zeros_per_sub64 - 2);
97 zeros_per_sub64 = 1ULL << log2_zeros_per_sub64;
98 zeros_per_sub16 = 1ULL << log2_zeros_per_sub16;
99 zeros_per_sub64_mask = zeros_per_sub64 - 1;
100 zeros_per_sub16_mask = zeros_per_sub16 - 1;
103 printf(
"Number of zeros: %" PRId64
" Number of zeros per inventory item: %d\n", c, zeros_per_inventory);
104 printf(
"Longwords per subinventory: %d zeros per sub 64: %d sub 16: %d\n", longwords_per_subinventory, zeros_per_sub64, zeros_per_sub16);
107 inventory.
size(inventory_size * longwords_per_inventory + 1);
108 const int64_t *end_of_inventory = &inventory + inventory_size * longwords_per_inventory + 1;
113 for (uint64_t i = 0; i < num_words; i++)
114 for (
int j = 0; j < 64; j++) {
115 if (i * 64 + j >= num_bits)
break;
116 if (~bits[i] & 1ULL << j) {
117 if ((d & zeros_per_inventory_mask) == 0) inventory[(d >> log2_zeros_per_inventory) * longwords_per_inventory] = i * 64 + j;
123 inventory[inventory_size * longwords_per_inventory] = num_bits;
126 printf(
"Inventory entries filled: %" PRId64
"\n", inventory_size + 1);
129 if (zeros_per_inventory > 1) {
132 uint64_t spilled = 0, exact = 0, start, span, inventory_index;
134 for (uint64_t i = 0; i < num_words; i++)
136 for (
int j = 0; j < 64; j++) {
137 if (i * 64 + j >= num_bits)
break;
138 if (~bits[i] & 1ULL << j) {
139 if ((d & zeros_per_inventory_mask) == 0) {
140 inventory_index = d >> log2_zeros_per_inventory;
141 start = inventory[inventory_index * longwords_per_inventory];
142 span = inventory[(inventory_index + 1) * longwords_per_inventory] - start;
143 zeros = min(c - d, (uint64_t)zeros_per_inventory);
145 assert(start + span == num_bits || zeros == zeros_per_inventory);
148 if (span >= (1 << 16)) {
150 if (zeros_per_sub64 > 1) spilled += zeros;
158 printf(
"Spilled entries: %" PRId64
" exact: %" PRId64
"\n", spilled, exact);
161 exact_spill_size = spilled;
162 exact_spill.
size(exact_spill_size);
170 for (uint64_t i = 0; i < num_words; i++)
171 for (
int j = 0; j < 64; j++) {
172 if (i * 64 + j >= num_bits)
break;
173 if (~bits[i] & 1ULL << j) {
174 if ((d & zeros_per_inventory_mask) == 0) {
175 inventory_index = d >> log2_zeros_per_inventory;
176 start = inventory[inventory_index * longwords_per_inventory];
177 span = inventory[(inventory_index + 1) * longwords_per_inventory] - start;
178 p64 = &inventory[inventory_index * longwords_per_inventory + 1];
179 p16 = (uint16_t *)p64;
183 if (span < (1 << 16)) {
184 assert(i * 64 + j - start <= (1 << 16));
185 if ((d & zeros_per_sub16_mask) == 0) {
186 assert(offset < longwords_per_subinventory * 4);
187 assert(p16 + offset < (uint16_t *)end_of_inventory);
188 p16[offset++] = i * 64 + j - start;
191 if (zeros_per_sub64 == 1) {
192 assert(p64 + offset < end_of_inventory);
193 p64[offset++] = i * 64 + j;
195 assert(p64 < end_of_inventory);
196 if ((d & zeros_per_inventory_mask) == 0) {
197 inventory[inventory_index * longwords_per_inventory] |= 1ULL << 63;
200 assert(spilled < exact_spill_size);
201 exact_spill[spilled++] = i * 64 + j;
211 printf(
"First inventories: %" PRId64
" %" PRId64
" %" PRId64
" %" PRId64
"\n", inventory[0], inventory[1], inventory[2], inventory[3]);
215 if (exact_spill_size > 0) printf(
"First spilled entries: %016" PRIx64
" %016" PRIx64
" %016" PRIx64
" %016" PRIx64
"\n", exact_spill[0], exact_spill[1], exact_spill[2], exact_spill[3]);
221 printf(
"Selecting %" PRId64
"\n...", rank);
224 const uint64_t inventory_index = rank >> log2_zeros_per_inventory;
225 const int64_t *inventory_start = &inventory + (inventory_index << log2_longwords_per_subinventory) + inventory_index;
226 assert(inventory_index <= inventory_size);
228 const int64_t inventory_rank = *inventory_start;
229 const int subrank = rank & zeros_per_inventory_mask;
231 printf(
"Rank: %" PRId64
" inventory index: %" PRId64
" inventory rank: %" PRId64
" subrank: %d\n", rank, inventory_index, inventory_rank, subrank);
235 if (subrank == 0) puts(
"Exact hit (no subrank); returning inventory");
237 if (subrank == 0)
return inventory_rank & ~(1ULL << 63);
242 if (inventory_rank >= 0) {
243 start = inventory_rank + ((uint16_t *)(inventory_start + 1))[subrank >> log2_zeros_per_sub16];
244 residual = subrank & zeros_per_sub16_mask;
246 if (zeros_per_sub64 == 1)
return *(inventory_start + 1 + subrank);
247 assert(*(inventory_start + 1) + subrank < (int64_t)exact_spill_size);
248 return exact_spill[*(inventory_start + 1) + subrank];
252 printf(
"Differential; start: %" PRId64
" residual: %d\n", start, residual);
253 if (residual == 0) puts(
"No residual; returning start");
256 if (residual == 0)
return start;
258 uint64_t word_index = start / 64;
259 uint64_t word = ~bits[word_index] & -1ULL << start % 64;
262 const int bit_count = __builtin_popcountll(word);
263 if (residual < bit_count)
break;
264 word = ~bits[++word_index];
265 residual -= bit_count;
268 return word_index * 64 +
select64(word, residual);
272 size_t bitCount()
const {
return inventory.
bitCount() -
sizeof(inventory) * 8 + exact_spill.
bitCount() -
sizeof(exact_spill) * 8 +
sizeof(*
this) * 8; }