Medial Code Documentation
Loading...
Searching...
No Matches
MedSparseVec.h
1// MedSparseVec
2// ------------
3//
4// Dealing with the problem of efficiently holding, inserting and retrieving an element of type T given some unsigned int unique
5// key attached to it.
6//
7// Hence the problem is : given pairs (key_i, elem_i) , create a memory efficient and fast data structure V (mimicing a vector)
8// with the main API : V.get(key) -> returns the matching element
9// The problem is how to do this efficiently when key is very sparse.
10//
11// If the vector V is in the range [a,b] (b-a+1 length) we would like to be able to insert : v[key]=elem, and retrieve out_elem = V[given key]
12//
13// We would like our memory to be as low as possible.
14// This implementation will add 1.5bits for each possible range.
15// So if the range (always an unsigned int) of the min,max values of keys for V is [a,b], and N = b-a+1 ,
16// and there are actually only M<N T elements, we will use memory of size: 1.5N/8 + M*sizeof(T) bytes.
17//
18// since we want to save memory this is better than a simple array only if:
19// N*sizeof(T) > 1.5N/8 + M*sizeof(T)
20// or:
21// M < N - 1.5N/(8*sizeof(T)) =(for sizeof(T)=4) N - 1.5N/32 = 0.953N ,
22//
23// so...in practice even if we keep just an int of memory as an item, we start saving memory even if the table is 0.95 full !!!
24//
25// other options are to use map<int,T> but map is using lots of memory per key, something like 32 bytes....
26// hence map will be better only for much sparser cases:
27//
28// M*(sizeof(T)+32) < 1.5N/8 + M*sizeof(T)
29// or:
30// M < 1.5N/(8*32) = 3N/512 = 0.005N !!
31//
32// Another option to compare to is keep a vector of the the pair <uint, T> (maybe even sorted)
33// this costs M*(sizeof(T)+4) and is VERY slow in lookup
34// however even here we get
35// M*(sizeof(T)+4) < 1.5N/8 + M*sizeof(T)
36// or:
37// M < 1.5N/32 = 0.046N .... so in sparsness of the 5%-95% we will be better even than just KEEPING the data AS IS !!!!
38//
39// so for sparsness in the range of 0.5% to 95% this data structure will save memory.
40//
41// Another drawback on this data structure:
42// - in order to get a fast insert time, it is best to:
43// (1) set the range [a,b] in advance.
44// (2) insert the elements with the keys SORTED, such that if we enter V[i] after V[j] then i > j (or appeared before).
45// failing to do so will return an error (or a terrible insertion time).
46//
47// so the actual situation to start with when using this package is :
48// (1) have a vector of size M of keys K[i] , which are unsigned int and sorted.
49// (2) have a vector of size M of elements E[i] of type T, such that the key for E[i] is K[i].
50//
51// OR:
52// (1) make sure that whenever a new pair {k,e} is inserted then k is >= of all the keys that were before or appeared already (in which case we replace its
53// ... value with the new e.
54//
55//
56
57#ifndef __MED__SPARSE__VEC__
58#define __MED__SPARSE__VEC__
59
60#include <vector>
61#include <immintrin.h>
62#include <nmmintrin.h>
63#include <cstring>
64
65using namespace std;
66
67#define MED_SPARSE_VEC_MAGIC_NUM 0x0102030405060708
68
69template <class T> class MedSparseVec {
70
71 public:
72
73 unsigned int min_val;
74 unsigned int max_val;
75 int max_set;
76 unsigned int max_key;
77 T def_val;
78
79 vector<unsigned int> counts;
80 vector<unsigned long long> is_in_bit;
81 vector<T> data;
82
83 void set_min(int _min) { min_val= _min; }
84 void set_max(int _max) { max_val= _max; max_set = 1; }
85 MedSparseVec() { min_val = 0; max_val = 0; max_set = 0; max_key = 0; init(); }
86 MedSparseVec(int _min) { min_val = _min; max_val = 0; max_set = 0; max_key = 0; init(); }
87 MedSparseVec(int _min, int _max) { min_val = _min; max_set = 1; max_val = _max; max_key = 0; init(); }
88 void set_def(const T val) { def_val = val; data[0] = def_val; }
89
90 inline T operator[] (const unsigned int key) const { return (*get(key)); }
91
92 inline T &operator[] (const unsigned int key) { return (*get(key)); }
93
94 void reserve(unsigned int size) {data.reserve(size);}
95
96 //------------------------------------------------------
97 // init major arrays
98 //------------------------------------------------------
99 void init() {
100 counts.resize(2, 0);
101 is_in_bit.resize(1, 0);
102 data.clear();
103// def_val = (T)0;
104 def_val = 0;
105 data.push_back(def_val);
106 }
107
108
109 //------------------------------------------------------
110 // clear a used sparse vec, going back to all defaults
111 void clear() {
112 counts.assign(2, 0);
113 is_in_bit.assign(1, 0ULL);
114 data.clear();
115 //def_val = (T)0;
116 def_val = 0;
117 data.push_back(def_val);
118 min_val = 0; max_val = 0; max_set = 0; max_key = 0;
119 }
120
121 //------------------------------------------------------
122 // get index of a data item - 0 is not found
123 //------------------------------------------------------
124 inline unsigned int get_ind(const unsigned int key)
125 {
126
127 if (key < min_val || key > max_key || (max_set && key>max_val))
128 return 0; // not in range
129
130 unsigned int mkey = key - min_val;
131 unsigned int i_count = mkey >> 6;
132 unsigned int i_bit = 63 - (mkey & 0x3f);
133 unsigned long long kbits = is_in_bit[i_count]>>i_bit;
134 //unsigned long long i_mask = (((unsigned long long)1)<<(i_bit));
135
136 //fprintf(stderr, "key=%d mkey=%d i_count=%d %d i_bit=%d kbits=%d ind= %d\n", key, mkey, i_count, counts[i_count], i_bit, kbits, -1); fflush(stderr);
137 //if ((is_in_bit[i_count]&i_mask) == 0)
138 if ((kbits & 0x1) == 0)
139 return 0; // no value inserted
140
141// unsigned int ind = counts[i_count] + (int)_mm_popcnt_u64(is_in_bit[i_count]>>i_bit);
142 unsigned int ind = counts[i_count] + (int)_mm_popcnt_u64(kbits);
143
144 //fprintf(stderr, "key=%d mkey=%d i_count=%d %d i_bit=%d i_mask=%llx %llx pos = %d val = %d\n", key, mkey, i_count, counts[i_count], i_bit, i_mask, is_in_bit[i_count]>>i_bit, pos, data[pos]); fflush(stderr);
145
146 return ind;
147 }
148
149 //------------------------------------------------------
150 // insert a new element
151 //------------------------------------------------------
152 int insert(const unsigned int key, const T elem)
153 {
154 // first we check we are allowed to insert it
155 if (key<min_val || (max_set && key>max_val)) return -1;
156
157 // get the bit indexes of key
158 unsigned int mkey = key - min_val;
159 unsigned int i_count = mkey >> 6;
160 unsigned int i_bit = 63 - (mkey & 0x3f);
161 unsigned long long i_mask = (((unsigned long long)1)<<(i_bit));
162
163// fprintf(stderr, "key=%d mkey=%d i_count=%d i_bit=%d i_mask=%llx max_key=%d is_in_bit=%llx\n", key, mkey, i_count, i_bit, i_mask,max_key, is_in_bit[i_count]);
164 if (key <= max_key) {
165 if (is_in_bit[i_count]&i_mask) {
166 unsigned int pos = counts[i_count] + (int)_mm_popcnt_u64(is_in_bit[i_count]>>i_bit);
167 data[pos] = elem;
168 return 0;
169 }
170 else
171 if (key < max_key)
172 return -2; // elements were not inserted in the correct sorted order
173 // in key == max_key with bit 0 we simply have to insert the value
174 }
175
176 // new max key
177 unsigned int last_cnt = 0;
178 if (counts.size() > 0)
179 last_cnt = counts.back();
180 counts.resize(i_count+2, last_cnt);
181 is_in_bit.resize(i_count+1, 0);
182 is_in_bit[i_count] |= i_mask;
183 counts[i_count+1] = counts[i_count] + (int)_mm_popcnt_u64(is_in_bit[i_count]);
184 data.push_back(elem);
185 max_key = key;
186 return 0;
187 }
188
189 //---------------------------------------------------------------
190 // get - NULL is returned for a key not inside.
191 //----------------------------------------------------------------
192 inline T *get(unsigned int key) {
193 return &data[get_ind(key)];
194 }
195
196
197 //---------------------------------------------------------------
198 // get_all_keys
199 //---------------------------------------------------------------
200 int get_all_keys(vector<unsigned int> &keys) {
201
202 keys.resize(data.size()-1);
203 unsigned int j=0;
204
205 //unsigned int base = min_val;
206 //for (int i=0; i<counts.size(); i++) {
207 // unsigned long long bits = is_in_bit[i];
208 // if (bits != 0)
209 // for (int k=63; k>=0; k--) {
210 // unsigned long long kbits = bits>>k;
211 // if (kbits & 0x1) {
212 // keys[j++] = base + 63 - k;
213 // }
214 // }
215 // base += 64;
216 //}
217
218
219 for (unsigned int i=min_val; i<=max_key; i++)
220 if (get_ind(i) > 0)
221 keys[j++] = i;
222
223 return 0;
224 }
225
226 //---------------------------------------------------------------
227 // get_all_intersected key:
228 // gets a uniq list of in_keys
229 // outputs:
230 // keys - the keys in the list that are also in in_keys
231 // inds - the indexes for these keys (in a vector of the same size)
232 //---------------------------------------------------------------
233 int get_all_intersected_keys(const vector<int> &in_keys, vector<int> &keys, vector<int> &inds) {
234
235 keys.resize(in_keys.size());
236 inds.resize(in_keys.size());
237 int i_size = 0;
238
239 for (int i=0; i<in_keys.size(); i++) {
240 int ind = get_ind(in_keys[i]);
241 if (ind > 0) {
242 keys[i_size] = in_keys[i];
243 inds[i_size] = ind;
244 i_size++;
245 }
246 }
247/*
248 for (int i=0; i<in_keys.size(); i++) {
249 unsigned int curr_key = in_keys[i];
250 //fprintf(stderr, "working on curr_key %d ind %d min_val %d max_key %d\n", curr_key, get_ind(curr_key), min_val, max_key);
251 if (curr_key >= min_val && curr_key <= max_key) {
252 unsigned int mkey = curr_key - min_val;
253 int i_count = mkey>>6;
254 int k = 63 - (mkey & 0x3f);
255 unsigned long long bits = is_in_bit[i_count];
256 if (bits) {
257 unsigned long long kbits = bits >> k;
258 //fprintf(stderr, "mkey %d i_count %d k %d bits %d\n", mkey, i_count, k, bits);
259 if (kbits &0x1) {
260 keys[i_size] = curr_key;
261 inds[i_size] = counts[i_count] + (int)_mm_popcnt_u64(kbits);
262 i_size++;
263 }
264 }
265 }
266 }
267*/
268 keys.resize(i_size);
269 inds.resize(i_size);
270
271 //fprintf(stderr, "i_size = %d/%d %d %d \n", i_size, in_keys.size(), keys.size(), inds.size()); fflush(stderr);
272 return 0;
273 }
274 //---------------------------------------------------------------
275 // Serializations
276 //---------------------------------------------------------------
277 size_t get_size() {
278 size_t size = 0;
279
280 size += sizeof(unsigned long long); // len of serialization
281 size += sizeof(unsigned long long); // magic number recognizer
282 size += sizeof(unsigned int); // min_val
283 size += sizeof(unsigned int); // max_val
284 size += sizeof(int); // max_set
285 size += sizeof(unsigned int); // max_key
286 size += sizeof(T); // def_val
287 size += sizeof(unsigned int); // len counts
288 size += sizeof(unsigned int) * counts.size(); // counts vector
289 size += sizeof(unsigned int); // len is_in_bit
290 size += sizeof(unsigned long long) * is_in_bit.size(); // is_in_bit vector
291 size += sizeof(unsigned int); // len data
292 size += sizeof(T) * data.size();
293
294 return size;
295
296 }
297
298 //---------------------------------------------------------------
299 size_t serialize(unsigned char *blob) {
300
301 unsigned char *curr = blob;
302
303 curr += sizeof(unsigned long long); // bypassing len - will place it at the end.
304 ((unsigned long long *)curr)[0] = (unsigned long long)MED_SPARSE_VEC_MAGIC_NUM; curr+= sizeof(unsigned long long);
305 ((unsigned int *)curr)[0] = min_val; curr+= sizeof(unsigned int);
306 ((unsigned int *)curr)[0] = max_val; curr+= sizeof(unsigned int);
307 ((int *)curr)[0] = max_set; curr+= sizeof(int);
308 ((unsigned int *)curr)[0] = max_key; curr+= sizeof(unsigned int);
309 ((T *)curr)[0] = def_val; curr+= sizeof(T);
310 ((unsigned int *)curr)[0] = (unsigned int)counts.size(); curr+= sizeof(unsigned int);
311 for (int i=0; i<counts.size(); i++) {
312 ((unsigned int *)curr)[0] = counts[i]; curr+= sizeof(unsigned int);
313 }
314 ((unsigned int *)curr)[0] = (unsigned int)is_in_bit.size(); curr+= sizeof(unsigned int);
315 for (int i=0; i<is_in_bit.size(); i++) {
316 ((unsigned long long *)curr)[0] = is_in_bit[i]; curr+= sizeof(unsigned long long);
317 }
318 ((unsigned int *)curr)[0] = (unsigned int)data.size(); curr+= sizeof(unsigned int);
319 for (int i=0; i<data.size(); i++) {
320 ((T *)curr)[0] = data[i]; curr+= sizeof(T);
321 }
322 unsigned long long len = (unsigned long long)(curr-blob);
323 ((unsigned long long *)blob)[0] = len;
324 return len;
325
326 }
327
328 //---------------------------------------------------------------
329 size_t deserialize(unsigned char *blob) {
330
331 unsigned char *curr = blob;
332
333 counts.clear();
334 is_in_bit.clear();
335 data.clear();
336 unsigned long long serialize_len = ((unsigned long long *)curr)[0]; curr += sizeof(unsigned long long);
337 unsigned long long magic_num = ((unsigned long long *)curr)[0]; curr += sizeof(unsigned long long);
338 if (magic_num != (unsigned long long)MED_SPARSE_VEC_MAGIC_NUM) {
339 fprintf(stderr, "ERROR: Sparse Vec Magic Num wrong : can't deserialize() (%llx)\n", magic_num);
340 return 0;
341 }
342 min_val = ((unsigned int *)curr)[0]; curr += sizeof(unsigned int);
343 max_val = ((unsigned int *)curr)[0]; curr += sizeof(unsigned int);
344 max_set = ((int *)curr)[0]; curr += sizeof(int);
345 max_key = ((unsigned int *)curr)[0]; curr += sizeof(unsigned int);
346 def_val = ((T *)curr)[0]; curr += sizeof(T);
347 unsigned int len_counts = ((unsigned int *)curr)[0]; curr += sizeof(unsigned int);
348 counts.resize(len_counts);
349 memcpy(&counts[0], curr, len_counts*sizeof(unsigned int));
350 curr += sizeof(unsigned int) * len_counts;
351
352 unsigned int len_is_in_bit = ((unsigned int *)curr)[0]; curr += sizeof(unsigned int);
353 is_in_bit.resize(len_is_in_bit);
354 memcpy(&is_in_bit[0], curr, len_is_in_bit*sizeof(unsigned long long));
355 curr += sizeof(unsigned long long)*len_is_in_bit;
356
357 unsigned int len_data = ((unsigned int *)curr)[0]; curr += sizeof(unsigned int);
358 data.resize(len_data);
359 memcpy(&data[0], curr, len_data*sizeof(T));
360 curr += sizeof(T) * len_data;
361
362 size_t len = curr - blob;
363 if (len != serialize_len) {
364 fprintf(stderr, "ERROR: Sparse Vec serialize len not matching decalred one: %zu != %llu\n", len, serialize_len);
365 return 0;
366 }
367 return len;
368 }
369
370};
371
372#endif
Definition MedSparseVec.h:69
Definition StdDeque.h:58