31 #include "../support/common.hpp"
32 #include "../util/Vector.hpp"
54 template <util::AllocType AT = util::AllocType::MALLOC>
class DoubleEF {
56 static constexpr uint64_t log2q =
LOG2Q;
57 static constexpr uint64_t q = 1 << log2q;
58 static constexpr uint64_t q_mask = q - 1;
59 static constexpr uint64_t super_q = 1 << 14;
60 static constexpr uint64_t super_q_mask = super_q - 1;
61 static constexpr uint64_t q_per_super_q = super_q / q;
62 static constexpr uint64_t super_q_size = 1 + q_per_super_q / 4;
64 uint64_t lower_bits_mask_cum_keys, lower_bits_mask_position;
66 uint64_t num_buckets, u_cum_keys, u_position;
67 uint64_t l_position, l_cum_keys;
68 int64_t cum_keys_min_delta, min_diff;
69 uint64_t bits_per_key_fixed_point;
74 const uint64_t mask = ((UINT64_C(1) << width) - 1) << start % 8;
76 memcpy(&t, (uint8_t *)&bits + start / 8, 8);
77 t = (t & ~mask) | value << start % 8;
78 memcpy((uint8_t *)&bits + start / 8, &t, 8);
81 __inline
size_t lower_bits_size_words()
const {
return ((num_buckets + 1) * (l_cum_keys + l_position) + 63) / 64 + 1; }
83 __inline
size_t cum_keys_size_words()
const {
return (num_buckets + 1 + (u_cum_keys >> l_cum_keys) + 63) / 64; }
85 __inline
size_t position_size_words()
const {
return (num_buckets + 1 + (u_position >> l_position) + 63) / 64; }
87 __inline
size_t jump_size_words()
const {
88 size_t size = (num_buckets / super_q) * super_q_size * 2;
89 if (num_buckets % super_q != 0) size += (1 + ((num_buckets % super_q + q - 1) / q + 3) / 4) * 2;
94 os.write((
char *)&ef.num_buckets,
sizeof(ef.num_buckets));
95 os.write((
char *)&ef.u_cum_keys,
sizeof(ef.u_cum_keys));
96 os.write((
char *)&ef.u_position,
sizeof(ef.u_position));
97 os.write((
char *)&ef.cum_keys_min_delta,
sizeof(ef.cum_keys_min_delta));
98 os.write((
char *)&ef.min_diff,
sizeof(ef.min_diff));
99 os.write((
char *)&ef.bits_per_key_fixed_point,
sizeof(ef.bits_per_key_fixed_point));
102 os << ef.upper_bits_cum_keys;
103 os << ef.upper_bits_position;
109 is.read((
char *)&ef.num_buckets,
sizeof(ef.num_buckets));
110 is.read((
char *)&ef.u_cum_keys,
sizeof(ef.u_cum_keys));
111 is.read((
char *)&ef.u_position,
sizeof(ef.u_position));
112 is.read((
char *)&ef.cum_keys_min_delta,
sizeof(ef.cum_keys_min_delta));
113 is.read((
char *)&ef.min_diff,
sizeof(ef.min_diff));
114 is.read((
char *)&ef.bits_per_key_fixed_point,
sizeof(ef.bits_per_key_fixed_point));
116 ef.l_position = ef.u_position / (ef.num_buckets + 1) == 0 ? 0 :
lambda(ef.u_position / (ef.num_buckets + 1));
117 ef.l_cum_keys = ef.u_cum_keys / (ef.num_buckets + 1) == 0 ? 0 :
lambda(ef.u_cum_keys / (ef.num_buckets + 1));
118 assert(ef.l_cum_keys * 2 + ef.l_position <= 56);
120 ef.lower_bits_mask_cum_keys = (UINT64_C(1) << ef.l_cum_keys) - 1;
121 ef.lower_bits_mask_position = (UINT64_C(1) << ef.l_position) - 1;
124 is >> ef.upper_bits_cum_keys;
125 is >> ef.upper_bits_position;
133 DoubleEF(
const std::vector<uint64_t> &cum_keys,
const std::vector<uint64_t> &position) {
134 assert(cum_keys.size() == position.size());
135 num_buckets = cum_keys.size() - 1;
137 bits_per_key_fixed_point = (uint64_t(1) << 20) * (position[num_buckets] / (
double)cum_keys[num_buckets]);
139 min_diff = std::numeric_limits<int64_t>::max() / 2;
140 cum_keys_min_delta = std::numeric_limits<int64_t>::max() / 2;
141 int64_t prev_bucket_bits = 0;
142 for (
size_t i = 1; i <= num_buckets; ++i) {
143 const int64_t nkeys_delta = cum_keys[i] - cum_keys[i - 1];
144 cum_keys_min_delta = min(cum_keys_min_delta, nkeys_delta);
145 const int64_t bucket_bits = int64_t(position[i]) - int64_t(bits_per_key_fixed_point * cum_keys[i] >> 20);
146 min_diff = min(min_diff, bucket_bits - prev_bucket_bits);
147 prev_bucket_bits = bucket_bits;
150 u_position = int64_t(position[num_buckets]) - int64_t(bits_per_key_fixed_point * cum_keys[num_buckets] >> 20) - int64_t(num_buckets * min_diff) + 1;
151 l_position = u_position / (num_buckets + 1) == 0 ? 0 :
lambda(u_position / (num_buckets + 1));
152 u_cum_keys = cum_keys[num_buckets] - num_buckets * cum_keys_min_delta + 1;
153 l_cum_keys = u_cum_keys / (num_buckets + 1) == 0 ? 0 :
lambda(u_cum_keys / (num_buckets + 1));
154 assert(l_cum_keys * 2 + l_position <= 56);
157 printf(
"Elias-Fano l (cumulative): %d\n", l_cum_keys);
158 printf(
"Elias-Fano l (positions): %d\n", l_position);
159 printf(
"Elias-Fano u (cumulative): %lld\n", u_cum_keys);
160 printf(
"Elias-Fano u (positions): %lld\n", u_position);
163 lower_bits_mask_cum_keys = (UINT64_C(1) << l_cum_keys) - 1;
164 lower_bits_mask_position = (UINT64_C(1) << l_position) - 1;
166 const uint64_t words_lower_bits = lower_bits_size_words();
167 lower_bits.
size(words_lower_bits);
168 const uint64_t words_cum_keys = cum_keys_size_words();
169 upper_bits_cum_keys.
size(words_cum_keys);
170 const uint64_t words_position = position_size_words();
171 upper_bits_position.
size(words_position);
173 for (uint64_t i = 0, cum_delta = 0, bit_delta = 0; i <= num_buckets; i++, cum_delta += cum_keys_min_delta, bit_delta += min_diff) {
174 if (l_cum_keys != 0) set_bits(lower_bits, i * (l_cum_keys + l_position), l_cum_keys, (cum_keys[i] - cum_delta) & lower_bits_mask_cum_keys);
175 set(upper_bits_cum_keys, ((cum_keys[i] - cum_delta) >> l_cum_keys) + i);
177 const auto pval = int64_t(position[i]) - int64_t(bits_per_key_fixed_point * cum_keys[i] >> 20);
178 if (l_position != 0) set_bits(lower_bits, i * (l_cum_keys + l_position) + l_cum_keys, l_position, (pval - bit_delta) & lower_bits_mask_position);
179 set(upper_bits_position, ((pval - bit_delta) >> l_position) + i);
182 const uint64_t jump_words = jump_size_words();
183 jump.
size(jump_words);
185 for (uint64_t i = 0, c = 0, last_super_q = 0; i < words_cum_keys; i++) {
186 for (
int b = 0; b < 64; b++) {
187 if (upper_bits_cum_keys[i] & UINT64_C(1) << b) {
188 if ((c & super_q_mask) == 0) jump[(c / super_q) * (super_q_size * 2)] = last_super_q = i * 64 + b;
189 if ((c & q_mask) == 0) {
190 const uint64_t offset = i * 64 + b - last_super_q;
191 if (offset >= (1 << 16)) abort();
192 ((uint16_t *)(&jump + (c / super_q) * (super_q_size * 2) + 2))[2 * ((c % super_q) / q)] = offset;
199 for (uint64_t i = 0, c = 0, last_super_q = 0; i < words_position; i++) {
200 for (
int b = 0; b < 64; b++) {
201 if (upper_bits_position[i] & UINT64_C(1) << b) {
202 if ((c & super_q_mask) == 0) jump[(c / super_q) * (super_q_size * 2) + 1] = last_super_q = i * 64 + b;
203 if ((c & q_mask) == 0) {
204 const uint64_t offset = i * 64 + b - last_super_q;
205 if (offset >= (1 << 16)) abort();
206 ((uint16_t *)(&jump + (c / super_q) * (super_q_size * 2) + 2))[2 * ((c % super_q) / q) + 1] = offset;
214 for (uint64_t i = 0; i < num_buckets; i++) {
218 assert(x == cum_keys[i]);
219 assert(x2 == cum_keys[i + 1]);
220 assert(y == position[i]);
223 assert(x == cum_keys[i]);
224 assert(y == position[i]);
229 void get(
const uint64_t i, uint64_t &cum_keys, uint64_t &cum_keys_next, uint64_t &position) {
230 const uint64_t pos_lower = i * (l_cum_keys + l_position);
232 memcpy(&lower, (uint8_t *)&lower_bits + pos_lower / 8, 8);
233 lower >>= pos_lower % 8;
235 const uint64_t jump_super_q = (i / super_q) * super_q_size * 2;
236 const uint64_t jump_inside_super_q = (i % super_q) / q;
237 const uint64_t jump_cum_keys = jump[jump_super_q] + ((uint16_t *)(&jump + jump_super_q + 2))[2 * jump_inside_super_q];
238 const uint64_t jump_position = jump[jump_super_q + 1] + ((uint16_t *)(&jump + jump_super_q + 2))[2 * jump_inside_super_q + 1];
240 uint64_t curr_word_cum_keys = jump_cum_keys / 64;
241 uint64_t curr_word_position = jump_position / 64;
242 uint64_t window_cum_keys = upper_bits_cum_keys[curr_word_cum_keys] & UINT64_C(-1) << jump_cum_keys % 64;
243 uint64_t window_position = upper_bits_position[curr_word_position] & UINT64_C(-1) << jump_position % 64;
244 uint64_t delta_cum_keys = i & q_mask;
245 uint64_t delta_position = i & q_mask;
247 for (uint64_t bit_count; (bit_count =
nu(window_cum_keys)) <= delta_cum_keys; delta_cum_keys -= bit_count) window_cum_keys = upper_bits_cum_keys[++curr_word_cum_keys];
248 for (uint64_t bit_count; (bit_count =
nu(window_position)) <= delta_position; delta_position -= bit_count) window_position = upper_bits_position[++curr_word_position];
250 const uint64_t select_cum_keys =
select64(window_cum_keys, delta_cum_keys);
251 const int64_t cum_delta = i * cum_keys_min_delta;
252 cum_keys = ((curr_word_cum_keys * 64 + select_cum_keys - i) << l_cum_keys | (lower & lower_bits_mask_cum_keys)) + cum_delta;
254 lower >>= l_cum_keys;
255 const int64_t bit_delta = i * min_diff;
256 position = ((curr_word_position * 64 +
select64(window_position, delta_position) - i) << l_position | (lower & lower_bits_mask_position)) + bit_delta +
257 int64_t(bits_per_key_fixed_point * cum_keys >> 20);
259 window_cum_keys &= (-1ULL << select_cum_keys) << 1;
260 while (window_cum_keys == 0) window_cum_keys = upper_bits_cum_keys[++curr_word_cum_keys];
262 lower >>= l_position;
263 cum_keys_next = ((curr_word_cum_keys * 64 +
rho(window_cum_keys) - i - 1) << l_cum_keys | (lower & lower_bits_mask_cum_keys)) + cum_delta + cum_keys_min_delta;
266 void get(
const uint64_t i, uint64_t &cum_keys, uint64_t &position) {
267 const uint64_t pos_lower = i * (l_cum_keys + l_position);
269 memcpy(&lower, (uint8_t *)&lower_bits + pos_lower / 8, 8);
270 lower >>= pos_lower % 8;
272 const uint64_t jump_super_q = (i / super_q) * super_q_size * 2;
273 const uint64_t jump_inside_super_q = (i % super_q) / q;
274 const uint64_t jump_cum_keys = jump[jump_super_q] + ((uint16_t *)(&jump + jump_super_q + 2))[2 * jump_inside_super_q];
275 const uint64_t jump_position = jump[jump_super_q + 1] + ((uint16_t *)(&jump + jump_super_q + 2))[2 * jump_inside_super_q + 1];
277 uint64_t curr_word_cum_keys = jump_cum_keys / 64;
278 uint64_t curr_word_position = jump_position / 64;
279 uint64_t window_cum_keys = upper_bits_cum_keys[curr_word_cum_keys] & UINT64_C(-1) << jump_cum_keys % 64;
280 uint64_t window_position = upper_bits_position[curr_word_position] & UINT64_C(-1) << jump_position % 64;
281 uint64_t delta_cum_keys = i & q_mask;
282 uint64_t delta_position = i & q_mask;
284 for (uint64_t bit_count; (bit_count =
nu(window_cum_keys)) <= delta_cum_keys; delta_cum_keys -= bit_count) window_cum_keys = upper_bits_cum_keys[++curr_word_cum_keys];
285 for (uint64_t bit_count; (bit_count =
nu(window_position)) <= delta_position; delta_position -= bit_count) window_position = upper_bits_position[++curr_word_position];
287 const uint64_t select_cum_keys =
select64(window_cum_keys, delta_cum_keys);
288 const size_t cum_delta = i * cum_keys_min_delta;
289 cum_keys = ((curr_word_cum_keys * 64 + select_cum_keys - i) << l_cum_keys | (lower & lower_bits_mask_cum_keys)) + cum_delta;
291 lower >>= l_cum_keys;
292 const int64_t bit_delta = i * min_diff;
293 position = ((curr_word_position * 64 +
select64(window_position, delta_position) - i) << l_position | (lower & lower_bits_mask_position)) + bit_delta +
294 int64_t(bits_per_key_fixed_point * cum_keys >> 20);
297 uint64_t
bitCountCumKeys() {
return (num_buckets + 1) * l_cum_keys + num_buckets + 1 + (u_cum_keys >> l_cum_keys) + jump_size_words() / 2; }
299 uint64_t
bitCountPosition() {
return (num_buckets + 1) * l_position + num_buckets + 1 + (u_position >> l_position) + jump_size_words() / 2; }