64-bit Mark Firsts (∊) hash table
This commit is contained in:
parent
dc7389a660
commit
37d7694c52
@ -17,6 +17,12 @@ static inline u32 hash32(u32 x) {
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
static inline u64 hash64(u64 x) {
|
||||
x ^= x >> 33; x *= 0xff51afd7ed558ccd;
|
||||
x ^= x >> 33; x *= 0xc4ceb9fe1a85ec53;
|
||||
x ^= x >> 33;
|
||||
return x;
|
||||
}
|
||||
|
||||
#define GRADE_UD(U,D) U
|
||||
#include "radix.h"
|
||||
@ -67,6 +73,20 @@ u8 radix_offsets_2_u32(usz* c0, u32* v0, usz n) {
|
||||
} \
|
||||
decG(x); TFREE(alloc);
|
||||
|
||||
static bool canCompare64_norm(B x, usz n) {
|
||||
u8 e = TI(x,elType);
|
||||
if (e == el_B) return 0;
|
||||
if (e == el_f64) {
|
||||
f64* p = f64any_ptr(x);
|
||||
for (usz i = 0; i < n; i++) {
|
||||
f64 v = p[i];
|
||||
if (v!=v) return 0;
|
||||
if (v==0) p[i]=0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
B memberOf_c1(B t, B x) {
|
||||
if (isAtm(x) || RNK(x)==0) thrM("∊: Argument cannot have rank 0");
|
||||
usz n = *SH(x);
|
||||
@ -103,64 +123,64 @@ B memberOf_c1(B t, B x) {
|
||||
if (lw == 3) { if (n<8) { BRUTE(8); } else { LOOKUP(8); } }
|
||||
if (lw == 4) { if (n<8) { BRUTE(16); } else { LOOKUP(16); } }
|
||||
#undef LOOKUP
|
||||
#define HASHTAB(T, W, RAD, STOP, THRESH) \
|
||||
T* xp = (T*)xv; \
|
||||
usz log = 64 - CLZ(n); \
|
||||
usz msl = (64 - CLZ(n+n/2)) + 1; if (RAD && msl>20) msl=20; \
|
||||
usz sh = W - (msl<14? msl : 12+(msl&1)); /* Shift to fit to table */ \
|
||||
usz sz = 1 << (W - sh); /* Initial size */ \
|
||||
usz msz = 1 << msl; /* Max sz */ \
|
||||
usz b = 64; /* Block size */ \
|
||||
/* Resize or abort if more than 1/2^thresh collisions/element */ \
|
||||
usz thresh = THRESH; \
|
||||
/* Filling e slots past the end requires e*(e+1)/2 collisions, so */ \
|
||||
/* n entries with <2 each can fill <sqrt(4*n) */ \
|
||||
usz ext = n<=b? n : b + (1 << (log/2 + 1)); \
|
||||
TALLOC(T, hash0, msz+ext); T* hash = hash0 + msz-sz; \
|
||||
T x0 = hash##W(xp[0]); rp[0] = 1; \
|
||||
for (u64 i = 0; i < sz+ext; i++) hash[i] = x0; \
|
||||
usz cc = 0; /* Collision counter */ \
|
||||
usz i=1; while (1) { \
|
||||
usz e = n-i>b? i+b : n; \
|
||||
for (; i < e; i++) { \
|
||||
T h = hash##W(xp[i]); T j0 = h>>sh, j = j0; T k; \
|
||||
while (k=hash[j], k!=h & k!=x0) j++; \
|
||||
cc += j-j0; \
|
||||
hash[j] = h; \
|
||||
rp[i] = k != h; \
|
||||
} \
|
||||
if (i == n) break; \
|
||||
i64 dc = (i64)cc - (i>>thresh); \
|
||||
if (dc >= 0) { \
|
||||
if (sz == msz || (RAD && i < n/2 && sz >= 1<<18)) break; /*Abort*/ \
|
||||
/* Avoid resizing if close to the end */ \
|
||||
if (cc<STOP && (n-i)*dc < (i*((i64)n+i))>>(5+log-(W-sh))) continue;\
|
||||
/* Resize hash, factor of 4 */ \
|
||||
usz m = 2; \
|
||||
usz dif = sz*((1<<m)-1); \
|
||||
sh -= m; sz <<= m; \
|
||||
hash -= dif; \
|
||||
usz j = 0; \
|
||||
cc = 0; \
|
||||
for (; j < dif; j++) hash[j] = x0; \
|
||||
for (; j < sz + ext; j++) { \
|
||||
T h = hash[j]; if (h==x0) continue; hash[j] = x0; \
|
||||
T k0 = h>>sh, k = k0; while (hash[k]!=x0) k++; \
|
||||
cc += k-k0; \
|
||||
hash[k] = h; \
|
||||
} \
|
||||
if (cc >= STOP) break; \
|
||||
thresh = THRESH; \
|
||||
} \
|
||||
} \
|
||||
TFREE(hash0); \
|
||||
if (i==n) { decG(x); return taga(cpyBitArr(r)); }
|
||||
if (lw == 5) {
|
||||
if (n<=12) { BRUTE(32); }
|
||||
|
||||
// Resizable hash table, fall back to radix lookup
|
||||
u32* xp = (u32*)xv;
|
||||
i8* rp; B r = m_i8arrv(&rp, n);
|
||||
usz log = 64 - CLZ(n);
|
||||
usz msl = (64 - CLZ(n+n/2)) + 1; if (msl>20) msl=20;
|
||||
usz sh = 32 - (msl<14? msl : 12+(msl&1)); // Shift to fit to table
|
||||
usz sz = 1 << (32 - sh); // Initial size
|
||||
usz msz = 1 << msl; // Max sz
|
||||
usz b = 64; // Block size
|
||||
// Resize or abort if more than 1/2^thresh collisions/element
|
||||
#define THRESH sz==msz? 1 : sz>=(1<<15)? 3 : 5
|
||||
usz thresh = THRESH;
|
||||
// Filling e slots past the end requires e*(e+1)/2 collisions, so
|
||||
// n entries with 1/2 each can fill <sqrt(n)
|
||||
usz ext = n<=b? n : b + (1 << (log/2));
|
||||
TALLOC(u32, hash0, msz+ext); u32* hash = hash0 + msz-sz;
|
||||
u32 x0 = hash32(xp[0]); rp[0] = 1;
|
||||
for (u64 i = 0; i < sz+ext; i++) hash[i] = x0;
|
||||
usz cc = 0; // Collision counter
|
||||
usz i=1; while (1) {
|
||||
usz e = n-i>b? i+b : n;
|
||||
for (; i < e; i++) {
|
||||
u32 h = hash32(xp[i]); u32 j0 = h>>sh, j = j0; u32 k;
|
||||
while (k=hash[j], k!=h & k!=x0) j++;
|
||||
cc += j-j0;
|
||||
hash[j] = h;
|
||||
rp[i] = k != h;
|
||||
}
|
||||
if (i == n) break;
|
||||
i64 dc = (i64)cc - (i>>thresh);
|
||||
if (dc >= 0) {
|
||||
if (sz == msz || (i < n/2 && sz >= 1<<18)) break; // Abort
|
||||
// Avoid resizing if close to the end
|
||||
if (cc<n/2 && (n-i)*dc < (i*((i64)n+i))>>(5+log-(32-sh))) continue;
|
||||
// Resize hash, factor of 4
|
||||
usz m = 2;
|
||||
usz dif = sz*((1<<m)-1);
|
||||
sh -= m; sz <<= m;
|
||||
hash -= dif;
|
||||
usz j = 0;
|
||||
cc = 0;
|
||||
for (; j < dif; j++) hash[j] = x0;
|
||||
for (; j < sz + ext; j++) {
|
||||
u32 h = hash[j]; if (h==x0) continue; hash[j] = x0;
|
||||
u32 k0 = h>>sh, k = k0; while (hash[k]!=x0) k++;
|
||||
cc += k-k0;
|
||||
hash[k] = h;
|
||||
}
|
||||
if (cc >= n/2) break;
|
||||
thresh = THRESH;
|
||||
}
|
||||
}
|
||||
#undef THRESH
|
||||
TFREE(hash0);
|
||||
if (i==n) { decG(x); return taga(cpyBitArr(r)); }
|
||||
HASHTAB(u32, 32, 1, n/2, sz==msz? 1 : sz>=(1<<15)? 3 : 5)
|
||||
|
||||
// Radix-assisted lookup
|
||||
usz rx = 256, tn = 1<<16; // Radix; table length
|
||||
@ -183,6 +203,13 @@ B memberOf_c1(B t, B x) {
|
||||
RADIX_LOOKUP_32(1, =0)
|
||||
return taga(cpyBitArr(r));
|
||||
}
|
||||
if (lw == 6 && canCompare64_norm(x, n)) {
|
||||
if (n<=12) { BRUTE(64); }
|
||||
i8* rp; B r = m_i8arrv(&rp, n);
|
||||
HASHTAB(u64, 64, 0, n, sz==msz? 0 : sz>=(1<<18)? 0 : sz>=(1<<14)? 3 : 5)
|
||||
decG(r); // Fall through
|
||||
}
|
||||
#undef HASHTAB
|
||||
#undef BRUTE
|
||||
|
||||
if (RNK(x)>1) x = toCells(x);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user