uCBQN/src/builtins/selfsearch.c

252 lines
8.4 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "../core.h"
#include "../utils/hash.h"
#include "../utils/mut.h"
#include "../utils/talloc.h"
B memberOf_c1(B t, B x) {
if (isAtm(x) || RNK(x)==0) thrM("∊: Argument cannot have rank 0");
usz n = *SH(x);
if (n==0) { decG(x); return emptyIVec(); }
if (RNK(x)>1) x = toCells(x);
u8 xe = TI(x,elType);
#define BRUTE(T) \
i##T* xp = i##T##any_ptr(x); \
u64* rp; B r = m_bitarrv(&rp, n); bitp_set(rp, 0, 1); \
for (usz i=1; i<n; i++) { \
bool c=1; i##T xi=xp[i]; \
for (usz j=0; j<i; j++) c &= xi!=xp[j]; \
bitp_set(rp, i, c); \
} \
decG(x); return r;
#define LOOKUP(T) \
usz tn = 1<<T; \
u##T* xp = (u##T*)i##T##any_ptr(x); \
i8* rp; B r = m_i8arrv(&rp, n); \
TALLOC(u8, tab, tn); \
for (usz j=0; j<tn; j++) tab[j]=1; \
for (usz i=0; i<n; i++) { u##T j=xp[i]; rp[i]=tab[j]; tab[j]=0; } \
decG(x); TFREE(tab); \
return num_squeeze(r)
if (xe==el_i8) { if (n<8) { BRUTE(8); } else { LOOKUP(8); } }
if (xe==el_i16) {
if (n<16) { BRUTE(16); }
if (n>=256) { LOOKUP(16); }
// Radix-assisted lookup
usz rx = 256, tn = 256; // Radix; table length
u16* v0 = (u16*)i16any_ptr(x);
i8* r0; B r = m_i8arrv(&r0, n);
TALLOC(u8, alloc, 4*n+(tn+rx));
u8 *c0 = alloc;
u8 *k0 = c0+rx;
u16 *v1 = (u16*)(k0+n);
u8 *r1 = (u8*)(v1+n);
u8 *tab= r1+n;
// Count keys
for (usz j=0; j<rx; j++) c0[j] = 0;
for (usz i=0; i<n; i++) c0[(u8)(v0[i]>>8)]++;
// Exclusive prefix sum
usz s=0; for (usz j=0; j<rx; j++) { usz p=s; s+=c0[j]; c0[j]=p; }
// Radix move
for (usz i=0; i<n; i++) { u16 v=v0[i]; u8 k=k0[i]=(u8)(v>>8); usz c=c0[k]++; v1[c]=v; }
// Table lookup
for (usz j=0; j<tn; j++) tab[j]=1;
u8 t0=v1[0]>>8;
for (usz i=0, e=0; i<n; i++) {
u16 v=v1[i]; u8 tv=v>>8;
if (tv!=t0) { for (; e<i; e++) tab[(u8)v1[e]]=1; t0=tv; }
usz j=(u8)v; r1[i]=tab[j]; tab[j]=0;
}
// Radix unmove
memmove(c0+1, c0, rx-1); c0[0]=0;
for (usz i=0; i<n; i++) { r0[i]=r1[c0[k0[i]]++]; }
decG(x); TFREE(alloc);
return num_squeeze(r);
}
#undef LOOKUP
// Radix-assisted lookup
if (n<=32 && xe==el_i32) { BRUTE(32); }
if (n>=256 && xe==el_i32) {
usz rx = 256, tn = 1<<16; // Radix; table length
u32* v0 = (u32*)i32any_ptr(x);
i8* r0; B r = m_i8arrv(&r0, n);
TALLOC(u8, alloc, 9*n+(tn+2*rx*sizeof(usz)));
// Allocations count radix hash deradix
usz *c0 = (usz*)(alloc); // rx X-----------------X
usz *c1 = (usz*)(c0+rx); // rx X-----------------X
u8 *k0 = (u8 *)(c1+rx); // n X-----------------X
u8 *k1 = (u8 *)(k0+n); // --/----------X
u32 *v1 = (u32*)(k1); // n X-X
u32 *v2 = (u32*)(v1+n); // n X----------X
u8 *r2 = (u8 *)(k1+n);
u8 *r1 = (u8 *)(r2+n);
u8 *tab= (u8 *)(v2+n); // tn
// Count keys
for (usz j=0; j<2*rx; j++) c0[j] = 0;
for (usz i=0; i<n; i++) { u32 v=v0[i]; c0[(u8)(v>>24)]++; c1[(u8)(v>>16)]++; }
// Exclusive prefix sum
usz s0=0, s1=0;
for (usz j=0; j<rx; j++) {
usz p0 = s0, p1 = s1;
s0 += c0[j]; s1 += c1[j];
c0[j] = p0; c1[j] = p1;
}
// Radix moves
for (usz i=0; i<n; i++) { u32 v=v0[i]; u8 k=k0[i]=(u8)(v>>24); usz c=c0[k]++; v1[c]=v; }
for (usz i=0; i<n; i++) { u32 v=v1[i]; u8 k=k1[i]=(u8)(v>>16); usz c=c1[k]++; v2[c]=v; }
// Table lookup
for (usz j=0; j<tn; j++) tab[j]=1;
u32 t0=v2[0]>>16; usz e=0;
for (usz i=0; i<n; i++) {
u32 v=v2[i], tv=v>>16;
// Clear table when top bytes change
if (RARE(tv!=t0)) { for (; e<i; e++) tab[(u16)v2[e]]=1; t0=tv; }
u32 j=(u16)v; r2[i]=tab[j]; tab[j]=0;
}
// Radix unmoves
memmove(c0+1, c0, (2*rx-1)*sizeof(usz)); c0[0]=c1[0]=0;
for (usz i=0; i<n; i++) { r1[i]=r2[c1[k1[i]]++]; }
for (usz i=0; i<n; i++) { r0[i]=r1[c0[k0[i]]++]; }
decG(x); TFREE(alloc);
return num_squeeze(r);
}
#undef BRUTE
u64* rp; B r = m_bitarrv(&rp, n);
H_Sb* set = m_Sb(64);
SGetU(x)
for (usz i = 0; i < n; i++) bitp_set(rp, i, !ins_Sb(&set, GetU(x,i)));
free_Sb(set); decG(x);
return r;
}
B count_c1(B t, B x) {
if (isAtm(x) || RNK(x)==0) thrM("⊒: Argument cannot have rank 0");
usz n = *SH(x);
if (n==0) { decG(x); return emptyIVec(); }
if (RNK(x)>1) x = toCells(x);
u8 xe = TI(x,elType);
#define LOOKUP(T) \
usz tn = 1<<T; \
u##T* xp = (u##T*)i##T##any_ptr(x); \
i32* rp; B r = m_i32arrv(&rp, n); \
TALLOC(i32, tab, tn); \
for (usz j=0; j<tn; j++) tab[j]=0; \
for (usz i=0; i<n; i++) rp[i]=tab[xp[i]]++; \
decG(x); TFREE(tab); \
return num_squeeze(r)
if (n>=16 && xe==el_i8 && n<=(usz)I32_MAX+1) { LOOKUP(8); }
if (n>=256 && xe==el_i16 && n<=(usz)I32_MAX+1) { LOOKUP(16); }
#undef LOOKUP
i32* rp; B r = m_i32arrv(&rp, n);
H_b2i* map = m_b2i(64);
SGetU(x)
for (usz i = 0; i < n; i++) {
bool had; u64 p = mk_b2i(&map, GetU(x,i), &had);
rp[i] = had? ++map->a[p].val : (map->a[p].val = 0);
}
decG(x); free_b2i(map);
return r;
}
extern B rt_indexOf;
B indexOf_c1(B t, B x) {
if (isAtm(x) || RNK(x)==0) thrM("⊐: 𝕩 cannot have rank 0");
usz n = *SH(x);
if (n==0) { decG(x); return emptyIVec(); }
if (RNK(x)>1) x = toCells(x);
u8 xe = TI(x,elType);
#define LOOKUP(T) \
usz tn = 1<<T; \
u##T* xp = (u##T*)i##T##any_ptr(x); \
i32* rp; B r = m_i32arrv(&rp, n); \
TALLOC(i32, tab, tn); \
for (usz j=0; j<tn; j++) tab[j]=n; \
i32 u=0; \
for (usz i=0; i<n; i++) { \
u##T j=xp[i]; i32 t=tab[j]; \
if (t==n) rp[i]=tab[j]=u++; else rp[i]=t; \
} \
decG(x); TFREE(tab); \
return num_squeeze(r)
if (n>=16 && xe==el_i8 && n<=(usz)I32_MAX+1) { LOOKUP(8); }
if (n>=256 && xe==el_i16 && n<=(usz)I32_MAX+1) { LOOKUP(16); }
#undef LOOKUP
if (xe==el_i32) {
i32* xp = i32any_ptr(x);
i32 min=I32_MAX, max=I32_MIN;
for (usz i = 0; i < n; i++) {
i32 c = xp[i];
if (c<min) min = c;
if (c>max) max = c;
}
i64 dst = 1 + (max-(i64)min);
if ((dst<n*5 || dst<50) && min!=I32_MIN) {
i32* rp; B r = m_i32arrv(&rp, n);
TALLOC(i32, tmp, dst);
for (i64 i = 0; i < dst; i++) tmp[i] = I32_MIN;
i32* tc = tmp-min;
i32 ctr = 0;
for (usz i = 0; i < n; i++) {
i32 c = xp[i];
if (tc[c]==I32_MIN) tc[c] = ctr++;
rp[i] = tc[c];
}
decG(x); TFREE(tmp);
return r;
}
}
// // relies on equal hashes implying equal objects, which has like a 2⋆¯64 chance of being false per item
// i32* rp; B r = m_i32arrv(&rp, n);
// u64 size = n*2;
// wyhashmap_t idx[size];
// i32 val[size];
// for (i64 i = 0; i < size; i++) { idx[i] = 0; val[i] = -1; }
// SGet(x)
// i32 ctr = 0;
// for (usz i = 0; i < n; i++) {
// u64 hash = bqn_hash(Get(x,i), wy_secret);
// u64 p = wyhashmap(idx, size, &hash, 8, true, wy_secret);
// if (val[p]==-1) val[p] = ctr++;
// rp[i] = val[p];
// }
// dec(x);
// return r;
i32* rp; B r = m_i32arrv(&rp, n);
H_b2i* map = m_b2i(64);
SGetU(x)
i32 ctr = 0;
for (usz i = 0; i < n; i++) {
bool had; u64 p = mk_b2i(&map, GetU(x,i), &had);
if (had) rp[i] = map->a[p].val;
else rp[i] = map->a[p].val = ctr++;
}
free_b2i(map); decG(x);
return r;
}
extern B rt_find;
B find_c1(B t, B x) {
if (isAtm(x) || RNK(x)==0) thrM("⍷: Argument cannot have rank 0");
usz n = *SH(x);
if (n<=1) return x;
if (RNK(x)>1) return c1(rt_find, x);
B xf = getFillQ(x);
B r = emptyHVec();
H_Sb* set = m_Sb(64);
SGetU(x)
for (usz i = 0; i < n; i++) {
B c = GetU(x,i);
if (!ins_Sb(&set, c)) r = vec_add(r, inc(c));
}
free_Sb(set); decG(x);
return withFill(r, xf);
}