Merge pull request #43 from mlochbaum/cellwidth
Type-independent code, and Replicate improvements
This commit is contained in:
commit
741d7ca31d
2
makefile
2
makefile
@ -198,7 +198,7 @@ ${bd}/%.o: src/jit/%.c
|
||||
@echo $< | cut -c 5-
|
||||
@$(CC_INC) $@.d -o $@ -c $<
|
||||
|
||||
builtins: ${addprefix ${bd}/, arithm.o arithd.o cmp.o sfns.o squeeze.o select.o slash.o sort.o selfsearch.o md1.o md2.o fns.o sysfn.o internal.o inverse.o}
|
||||
builtins: ${addprefix ${bd}/, arithm.o arithd.o cmp.o sfns.o squeeze.o select.o slash.o group.o sort.o selfsearch.o md1.o md2.o fns.o sysfn.o internal.o inverse.o}
|
||||
${bd}/%.o: src/builtins/%.c
|
||||
@echo $< | cut -c 5-
|
||||
@$(CC_INC) $@.d -o $@ -c $<
|
||||
|
||||
@ -35,16 +35,13 @@
|
||||
TALLOC(usz, c0, C); usz *c0o=c0+C/2; \
|
||||
for (usz j=0; j<C; j++) c0[j]=0; \
|
||||
for (usz i=0; i<n; i++) c0o[xp[i]]++; \
|
||||
if (n <= C*8) { /* Sum-based */ \
|
||||
for (usz i=1; i<n; i++) rp[i]=0; \
|
||||
GRADE_UD( \
|
||||
rp[0]=-C/2; usz e=C-1; while (c0[e]==0) e--; \
|
||||
for (usz j=0 , i=0; j<e; j++) { i+=c0[j]; rp[i]++; } \
|
||||
, \
|
||||
rp[0]=C/2-1; usz e=0; while (c0[e]==0) e++; \
|
||||
for (usz j=C-1, i=0; j>e; j--) { i+=c0[j]; rp[i]--; } \
|
||||
) \
|
||||
for (usz i=1; i<n; i++) rp[i]+=rp[i-1]; \
|
||||
if (n/16 <= C) { /* Sum-based */ \
|
||||
for (usz i=0; i<n; i++) rp[i]=0; \
|
||||
usz j=GRADE_UD(0,C-1), i; \
|
||||
while ((i=c0[j])==0) GRADE_UD(j++,j--); \
|
||||
usz js = j - C/2; \
|
||||
while (i<n) { rp[i]++; i+=c0[GRADE_UD(++j,--j)]; } \
|
||||
for (usz i=0; i<n; i++) js=rp[i]+=js; \
|
||||
} else { /* Branchy */ \
|
||||
FOR(j,C) for (usz c=c0[j]; c--; ) *rp++ = j-C/2; \
|
||||
} \
|
||||
|
||||
255
src/builtins/group.c
Normal file
255
src/builtins/group.c
Normal file
@ -0,0 +1,255 @@
|
||||
#include "../core.h"
|
||||
#include "../utils/talloc.h"
|
||||
#include "../utils/mut.h"
|
||||
#include "../builtins.h"
|
||||
|
||||
extern B ud_c1(B, B);
|
||||
extern B ne_c2(B, B, B);
|
||||
extern B slash_c1(B, B);
|
||||
extern B slash_c2(B, B, B);
|
||||
extern B select_c2(B, B, B);
|
||||
extern B take_c2(B, B, B);
|
||||
extern B drop_c2(B, B, B);
|
||||
extern B join_c2(B, B, B);
|
||||
|
||||
static Arr* arr_shChangeLen(Arr* a, ur r, usz* xsh, usz len) {
|
||||
assert(r > 1);
|
||||
usz* sh = a->sh = m_shArr(r)->a;
|
||||
SPRNK(a,r);
|
||||
sh[0] = len;
|
||||
shcpy(sh+1, xsh+1, r-1);
|
||||
return a;
|
||||
}
|
||||
static B m_shChangeLen(u8 xt, ur xr, usz* xsh, usz l, usz cw, usz csz) {
|
||||
return taga(arr_shChangeLen(m_arr(offsetof(TyArr, a)+l*cw, xt, l*csz), xr, xsh, l));
|
||||
}
|
||||
static void allocGroups(B* rp, usz ria, B z, u8 xt, ur xr, usz* xsh, i32* len, usz width, usz csz) {
|
||||
if (xr==1) for (usz j = 0; j < ria; j++) { usz l=len[j]; if (!l) rp[j] = inc(z); else m_tyarrv(rp+j, width, l, xt); }
|
||||
else for (usz j = 0; j < ria; j++) { usz l=len[j]; rp[j] = !l ? inc(z) : m_shChangeLen(xt, xr, xsh, l, width, csz); }
|
||||
}
|
||||
|
||||
extern B rt_group;
|
||||
B group_c2(B t, B w, B x) {
|
||||
if (!isArr(x)) thrM("⊔: 𝕩 must be an array");
|
||||
ur xr = RNK(x);
|
||||
if (isArr(w) && RNK(w)==1 && xr>=1 && depth(w)==1) {
|
||||
usz wia = IA(w);
|
||||
usz* xsh = SH(x);
|
||||
usz xia = *xsh;
|
||||
if (wia-xia > 1) thrF("⊔: ≠𝕨 must be either ≠𝕩 or one bigger (%s≡≠𝕨, %s≡≠𝕩)", wia, xia);
|
||||
u8 we = TI(w,elType);
|
||||
if (elInt(we)) {
|
||||
if (we==el_bit) w = taga(cpyI8Arr(w));
|
||||
i64 ria = 0;
|
||||
bool bad = false, sort = true;
|
||||
usz neg = 0, change = 0;
|
||||
void *wp0 = tyany_ptr(w);
|
||||
#define CASE(T) case el_##T: { \
|
||||
T max = -1, prev = -1; \
|
||||
for (usz i = 0; i < xia; i++) { \
|
||||
T n = ((T*)wp0)[i]; \
|
||||
if (n>max) max = n; \
|
||||
bad |= n < -1; \
|
||||
neg += n == -1; \
|
||||
sort &= prev <= n; \
|
||||
change += prev != n; \
|
||||
prev = n; \
|
||||
} \
|
||||
if (wia>xia) { ria=((T*)wp0)[xia]; bad|=ria<-1; } \
|
||||
i64 m=(i64)max+1; if (m>ria) ria=m; \
|
||||
break; }
|
||||
switch (we) { default:UD; case el_bit: CASE(i8) CASE(i16) CASE(i32) }
|
||||
#undef CASE
|
||||
if (bad) thrM("⊔: 𝕨 can't contain elements less than ¯1");
|
||||
if (ria > (i64)(USZ_MAX)) thrOOM();
|
||||
|
||||
Arr* r = arr_shVec(m_fillarrp(ria)); fillarr_setFill(r, m_f64(0));
|
||||
B* rp = fillarr_ptr(r);
|
||||
for (usz i = 0; i < ria; i++) rp[i] = m_f64(0); // don't break if allocation errors
|
||||
B xf = getFillQ(x);
|
||||
|
||||
Arr* rf = m_fillarrp(0); if (xr==1) arr_shVec(rf); else arr_shChangeLen(rf, xr, xsh, 0);
|
||||
fillarr_setFill(rf, m_f64(0));
|
||||
B z = taga(rf);
|
||||
fillarr_setFill(r, z);
|
||||
|
||||
// Both cases needed to make sure wia>0 for ip[wia-1] below
|
||||
if (ria==0) goto setfill_dec_ret;
|
||||
if (neg==xia) {
|
||||
for (usz i = 0; i < ria; i++) rp[i] = inc(z);
|
||||
goto setfill_dec_ret;
|
||||
}
|
||||
TALLOC(i32, pos, 2*ria+1); i32* len = pos+ria+1;
|
||||
|
||||
bool notB = TI(x,elType) != el_B;
|
||||
u8 xt = arrNewType(TY(x));
|
||||
u8 xl = arrTypeBitsLog(TY(x));
|
||||
bool bits = xl == 0;
|
||||
u64 width = bits ? 1 : 1<<(xl-3); // cell width in bits if bits==1, bytes otherwise
|
||||
usz csz = 1;
|
||||
if (RARE(xr>1)) {
|
||||
width *= csz = arr_csz(x);
|
||||
xl += CTZ(csz);
|
||||
if (bits && xl>=3) { bits=0; width>>=3; }
|
||||
if ((csz & (csz-1)) || xl>7) xl = 7;
|
||||
}
|
||||
if (xia>64 && notB && !bits && change<(xia*width)/32) {
|
||||
#define C1(F,X ) F##_c1(m_f64(0),X )
|
||||
#define C2(F,X,W) F##_c2(m_f64(0),X,W)
|
||||
if (wia>xia) w = C2(take, m_f64(xia), w);
|
||||
B c = C2(ne, C2(drop, m_f64(-1), inc(w)),
|
||||
C2(drop, m_f64( 1), inc(w)));
|
||||
B ind = C1(slash, C2(join, m_f64(-1!=IGetU(w,0).f), c));
|
||||
w = C2(select, inc(ind), w);
|
||||
#undef C1
|
||||
#undef C2
|
||||
if (TI(ind,elType)!=el_i32) ind = taga(cpyI32Arr(ind));
|
||||
if (TI(w ,elType)!=el_i32) w = taga(cpyI32Arr(w ));
|
||||
wia = IA(ind);
|
||||
|
||||
i32* ip = i32any_ptr(ind);
|
||||
i32* wp = i32any_ptr(w);
|
||||
usz i0 = ip[0];
|
||||
for (usz i=0; i<wia-1; i++) ip[i] = ip[i+1]-ip[i];
|
||||
ip[wia-1] = xia-ip[wia-1];
|
||||
for (usz i = 0; i < ria; i++) len[i] = pos[i] = 0;
|
||||
for (usz i = 0; i < wia; i++) len[wp[i]]+=ip[i];
|
||||
|
||||
void* xp = tyany_ptr(x);
|
||||
|
||||
allocGroups(rp, ria, z, xt, xr, xsh, len, width, csz);
|
||||
for (u64 i=0, k=i0*width; i<wia; i++) {
|
||||
u64 k0 = k;
|
||||
u64 l = ip[i]*width; k += l;
|
||||
i32 n = wp[i]; if (n<0) continue;
|
||||
memcpy((u8*)tyarr_ptr(rp[n])+pos[n], (u8*)xp+k0, l);
|
||||
pos[n] += l;
|
||||
}
|
||||
decG(ind);
|
||||
} else {
|
||||
if (xia>32 && neg>xia/4+xia/8) {
|
||||
if (wia>xia) w = take_c2(m_f64(0), m_f64(xia), w);
|
||||
B m = ne_c2(m_f64(0), m_f64(-1), inc(w));
|
||||
w = slash_c2(m_f64(0), inc(m), w);
|
||||
x = slash_c2(m_f64(0), m, x); xia = IA(x);
|
||||
neg = 0;
|
||||
}
|
||||
if (TI(w,elType)!=el_i32) w = taga(cpyI32Arr(w));
|
||||
i32* wp = i32any_ptr(w);
|
||||
for (usz i = 0; i < ria; i++) len[i] = pos[i] = 0;
|
||||
for (usz i = 0; i < xia; i++) len[wp[i]]++; // overallocation makes this safe after n<-1 check
|
||||
|
||||
u8 xk = xl - 3;
|
||||
if (notB && !bits && sort) {
|
||||
void* xp = tyany_ptr(x);
|
||||
u64 i=neg*width;
|
||||
#define GROUP_SORT(ALLOC) \
|
||||
for (usz j=0; j<ria; j++) { \
|
||||
usz l = len[j]; \
|
||||
if (!l) { rp[j]=inc(z); continue; } \
|
||||
ALLOC; \
|
||||
u64 lw = l*width; \
|
||||
memcpy(tyarr_ptr(rp[j]), (u8*)xp+i, lw); \
|
||||
i += lw; \
|
||||
}
|
||||
if (xr==1) GROUP_SORT(m_tyarrv(rp+j, width, l, xt))
|
||||
else GROUP_SORT(rp[j] = m_shChangeLen(xt, xr, xsh, l, width, csz))
|
||||
#undef GROUP_SORT
|
||||
} else if (notB && xk <= 3) {
|
||||
void* xp = tyany_ptr(x);
|
||||
allocGroups(rp, ria, z, xt, xr, xsh, len, width, csz);
|
||||
switch(xk) { default: UD;
|
||||
case 0: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u8* )tyarr_ptr(rp[n]))[pos[n]++] = ((u8* )xp)[i]; } break;
|
||||
case 1: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u16*)tyarr_ptr(rp[n]))[pos[n]++] = ((u16*)xp)[i]; } break;
|
||||
case 2: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u32*)tyarr_ptr(rp[n]))[pos[n]++] = ((u32*)xp)[i]; } break;
|
||||
case 3: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u64*)tyarr_ptr(rp[n]))[pos[n]++] = ((u64*)xp)[i]; } break;
|
||||
}
|
||||
} else {
|
||||
for (usz i = 0; i < ria; i++) {
|
||||
usz l = len[i];
|
||||
Arr* c = m_fillarrp(l*csz);
|
||||
c->ia = 0;
|
||||
fillarr_setFill(c, inc(xf));
|
||||
if (xr==1) arr_shVec(c); else arr_shChangeLen(c, xr, xsh, l);
|
||||
rp[i] = taga(c);
|
||||
}
|
||||
SLOW2("𝕨⊔𝕩", w, x);
|
||||
SGet(x)
|
||||
if (csz == 1) {
|
||||
for (usz i = 0; i < xia; i++) {
|
||||
i32 n = wp[i];
|
||||
if (n>=0) fillarr_ptr(a(rp[n]))[pos[n]++] = Get(x, i);
|
||||
}
|
||||
} else {
|
||||
for (usz i = 0; i < xia; i++) {
|
||||
i32 n = wp[i];
|
||||
if (n<0) continue;
|
||||
usz p = (pos[n]++)*csz;
|
||||
B* rnp = fillarr_ptr(a(rp[n])) + p;
|
||||
for (usz j = 0; j < csz; j++) rnp[j] = Get(x, i*csz + j);
|
||||
}
|
||||
}
|
||||
for (usz i = 0; i < ria; i++) a(rp[i])->ia = len[i]*csz;
|
||||
}
|
||||
}
|
||||
TFREE(pos);
|
||||
setfill_dec_ret:
|
||||
fillarr_setFill(rf, xf);
|
||||
decG(w); decG(x);
|
||||
return taga(r);
|
||||
} else if (xr==1) {
|
||||
SLOW2("𝕨⊔𝕩", w, x);
|
||||
SGetU(w)
|
||||
i64 ria = wia==xia? 0 : o2i64(GetU(w, xia));
|
||||
if (ria<-1) thrM("⊔: 𝕨 can't contain elements less than ¯1");
|
||||
ria--;
|
||||
for (usz i = 0; i < xia; i++) {
|
||||
B cw = GetU(w, i);
|
||||
if (!q_i64(cw)) goto base;
|
||||
i64 c = o2i64G(cw);
|
||||
if (c>ria) ria = c;
|
||||
if (c<-1) thrM("⊔: 𝕨 can't contain elements less than ¯1");
|
||||
}
|
||||
if (ria > (i64)(USZ_MAX-1)) thrOOM();
|
||||
ria++;
|
||||
TALLOC(i32, lenO, ria+1); i32* len = lenO+1;
|
||||
TALLOC(i32, pos, ria);
|
||||
for (usz i = 0; i < ria; i++) len[i] = pos[i] = 0;
|
||||
for (usz i = 0; i < xia; i++) len[o2i64G(GetU(w, i))]++;
|
||||
|
||||
Arr* r = arr_shVec(m_fillarrp(ria)); fillarr_setFill(r, m_f64(0));
|
||||
B* rp = fillarr_ptr(r);
|
||||
for (usz i = 0; i < ria; i++) rp[i] = m_f64(0); // don't break if allocation errors
|
||||
B xf = getFillQ(x);
|
||||
|
||||
for (usz i = 0; i < ria; i++) {
|
||||
Arr* c = m_fillarrp(len[i]);
|
||||
c->ia = 0;
|
||||
fillarr_setFill(c, inc(xf));
|
||||
arr_shVec(c);
|
||||
rp[i] = taga(c);
|
||||
}
|
||||
Arr* rf = m_fillarrp(0); arr_shVec(rf);
|
||||
fillarr_setFill(rf, xf);
|
||||
fillarr_setFill(r, taga(rf));
|
||||
SGet(x)
|
||||
for (usz i = 0; i < xia; i++) {
|
||||
i64 n = o2i64G(GetU(w, i));
|
||||
if (n>=0) fillarr_ptr(a(rp[n]))[pos[n]++] = Get(x, i);
|
||||
}
|
||||
for (usz i = 0; i < ria; i++) a(rp[i])->ia = len[i];
|
||||
decG(w); decG(x); TFREE(lenO); TFREE(pos);
|
||||
return taga(r);
|
||||
}
|
||||
}
|
||||
base:
|
||||
return c2(rt_group, w, x);
|
||||
}
|
||||
B group_c1(B t, B x) {
|
||||
if (isArr(x) && RNK(x)==1 && TI(x,arrD1)) {
|
||||
usz ia = IA(x);
|
||||
B range = ud_c1(t, m_f64(ia));
|
||||
return group_c2(m_f64(0), x, range);
|
||||
}
|
||||
return c1(rt_group, x);
|
||||
}
|
||||
@ -6,13 +6,12 @@
|
||||
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);
|
||||
if (elChr(xe)) xe -= el_c8-el_i8;
|
||||
if (n<=1) { decG(x); return n ? taga(arr_shVec(allOnes(1))) : emptyIVec(); }
|
||||
|
||||
u8 lw = cellWidthLog(x);
|
||||
void* xv = tyany_ptr(x);
|
||||
#define BRUTE(T) \
|
||||
i##T* xp = tyany_ptr(x); \
|
||||
i##T* xp = xv; \
|
||||
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]; \
|
||||
@ -22,7 +21,7 @@ B memberOf_c1(B t, B x) {
|
||||
decG(x); return r;
|
||||
#define LOOKUP(T) \
|
||||
usz tn = 1<<T; \
|
||||
u##T* xp = (u##T*)tyany_ptr(x); \
|
||||
u##T* xp = (u##T*)xv; \
|
||||
i8* rp; B r = m_i8arrv(&rp, n); \
|
||||
TALLOC(u8, tab, tn); \
|
||||
if (T>8 && n<tn/64) for (usz i=0; i<n; i++) tab[xp[i]]=1; \
|
||||
@ -30,14 +29,14 @@ B memberOf_c1(B t, B x) {
|
||||
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<8) { BRUTE(16); } else { LOOKUP(16); } }
|
||||
if (lw == 3) { if (n<8) { BRUTE(8); } else { LOOKUP(8); } }
|
||||
if (lw == 4) { if (n<8) { BRUTE(16); } else { LOOKUP(16); } }
|
||||
#undef LOOKUP
|
||||
if (xe==el_i32) {
|
||||
if (lw == 5) {
|
||||
if (n<=32) { BRUTE(32); }
|
||||
// Radix-assisted lookup
|
||||
usz rx = 256, tn = 1<<16; // Radix; table length
|
||||
u32* v0 = (u32*)tyany_ptr(x);
|
||||
u32* v0 = (u32*)xv;
|
||||
i8* r0; B r = m_i8arrv(&r0, n);
|
||||
|
||||
TALLOC(u8, alloc, 6*n+(4+(tn>3*n?tn:3*n)+(2*rx+1)*sizeof(usz)));
|
||||
@ -81,6 +80,7 @@ B memberOf_c1(B t, B x) {
|
||||
}
|
||||
#undef BRUTE
|
||||
|
||||
if (RNK(x)>1) x = toCells(x);
|
||||
u64* rp; B r = m_bitarrv(&rp, n);
|
||||
H_Sb* set = m_Sb(64);
|
||||
SGetU(x)
|
||||
@ -92,14 +92,13 @@ B memberOf_c1(B t, B x) {
|
||||
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 (n<=1) { decG(x); return n ? taga(arr_shVec(allZeroes(1))) : emptyIVec(); }
|
||||
if (n>(usz)I32_MAX+1) thrM("⊒: Argument length >2⋆31 not supported");
|
||||
if (RNK(x)>1) x = toCells(x);
|
||||
u8 xe = TI(x,elType);
|
||||
if (elChr(xe)) xe -= el_c8-el_i8;
|
||||
|
||||
u8 lw = cellWidthLog(x);
|
||||
void* xv = tyany_ptr(x);
|
||||
#define BRUTE(T) \
|
||||
i##T* xp = tyany_ptr(x); \
|
||||
i##T* xp = xv; \
|
||||
i8* rp; B r = m_i8arrv(&rp, n); rp[0]=0; \
|
||||
for (usz i=1; i<n; i++) { \
|
||||
usz c=0; i##T xi=xp[i]; \
|
||||
@ -109,7 +108,7 @@ B count_c1(B t, B x) {
|
||||
decG(x); return r;
|
||||
#define LOOKUP(T) \
|
||||
usz tn = 1<<T; \
|
||||
u##T* xp = (u##T*)tyany_ptr(x); \
|
||||
u##T* xp = (u##T*)xv; \
|
||||
i32* rp; B r = m_i32arrv(&rp, n); \
|
||||
TALLOC(i32, tab, tn); \
|
||||
if (T>8 && n<tn/16) for (usz i=0; i<n; i++) tab[xp[i]]=0; \
|
||||
@ -117,14 +116,14 @@ B count_c1(B t, B x) {
|
||||
for (usz i=0; i<n; i++) rp[i]=tab[xp[i]]++; \
|
||||
decG(x); TFREE(tab); \
|
||||
return num_squeeze(r)
|
||||
if (xe==el_i8) { if (n<12) { BRUTE(8); } else { LOOKUP(8); } }
|
||||
if (xe==el_i16) { if (n<12) { BRUTE(16); } else { LOOKUP(16); } }
|
||||
if (lw==3) { if (n<12) { BRUTE(8); } else { LOOKUP(8); } }
|
||||
if (lw==4) { if (n<12) { BRUTE(16); } else { LOOKUP(16); } }
|
||||
#undef LOOKUP
|
||||
if (xe==el_i32) {
|
||||
if (lw==5) {
|
||||
if (n<=32) { BRUTE(32); }
|
||||
// Radix-assisted lookup
|
||||
usz rx = 256, tn = 1<<16; // Radix; table length
|
||||
u32* v0 = (u32*)tyany_ptr(x);
|
||||
u32* v0 = (u32*)xv;
|
||||
i32* r0; B r = m_i32arrv(&r0, n);
|
||||
|
||||
TALLOC(u8, alloc, 6*n+(4+4*(tn>n?tn:n)+(2*rx+1)*sizeof(usz)));
|
||||
@ -169,6 +168,7 @@ B count_c1(B t, B x) {
|
||||
}
|
||||
#undef BRUTE
|
||||
|
||||
if (RNK(x)>1) x = toCells(x);
|
||||
i32* rp; B r = m_i32arrv(&rp, n);
|
||||
H_b2i* map = m_b2i(64);
|
||||
SGetU(x)
|
||||
@ -184,14 +184,13 @@ 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 (n<=1) { decG(x); return n ? taga(arr_shVec(allZeroes(1))) : emptyIVec(); }
|
||||
if (n>(usz)I32_MAX+1) thrM("⊐: Argument length >2⋆31 not supported");
|
||||
if (RNK(x)>1) x = toCells(x);
|
||||
u8 xe = TI(x,elType);
|
||||
if (elChr(xe)) xe -= el_c8-el_i8;
|
||||
|
||||
u8 lw = cellWidthLog(x);
|
||||
void* xv = tyany_ptr(x);
|
||||
#define BRUTE(T) \
|
||||
i##T* xp = tyany_ptr(x); \
|
||||
i##T* xp = xv; \
|
||||
i8* rp; B r = m_i8arrv(&rp, n); rp[0]=0; \
|
||||
TALLOC(i##T, uniq, n); uniq[0]=xp[0]; \
|
||||
for (usz i=1, u=1; i<n; i++) { \
|
||||
@ -202,7 +201,7 @@ B indexOf_c1(B t, B x) {
|
||||
decG(x); TFREE(uniq); return r;
|
||||
#define LOOKUP(T) \
|
||||
usz tn = 1<<T; \
|
||||
u##T* xp = (u##T*)tyany_ptr(x); \
|
||||
u##T* xp = (u##T*)xv; \
|
||||
i32* rp; B r = m_i32arrv(&rp, n); \
|
||||
TALLOC(i32, tab, tn); \
|
||||
if (T>8 && n<tn/16) for (usz i=0; i<n; i++) tab[xp[i]]=n; \
|
||||
@ -214,11 +213,11 @@ B indexOf_c1(B t, B x) {
|
||||
} \
|
||||
decG(x); TFREE(tab); \
|
||||
return num_squeeze(r)
|
||||
if (xe==el_i8) { if (n<12) { BRUTE(8); } else { LOOKUP(8); } }
|
||||
if (xe==el_i16) { if (n<12) { BRUTE(16); } else { LOOKUP(16); } }
|
||||
if (lw==3) { if (n<12) { BRUTE(8); } else { LOOKUP(8); } }
|
||||
if (lw==4) { if (n<12) { BRUTE(16); } else { LOOKUP(16); } }
|
||||
#undef LOOKUP
|
||||
|
||||
if (xe==el_i32) {
|
||||
if (lw==5) {
|
||||
if (n<32) { BRUTE(32); }
|
||||
i32* xp = tyany_ptr(x);
|
||||
i32 min=I32_MAX, max=I32_MIN;
|
||||
@ -245,6 +244,7 @@ B indexOf_c1(B t, B x) {
|
||||
}
|
||||
#undef BRUTE
|
||||
|
||||
if (RNK(x)>1) x = toCells(x);
|
||||
i32* rp; B r = m_i32arrv(&rp, n);
|
||||
H_b2i* map = m_b2i(64);
|
||||
SGetU(x)
|
||||
|
||||
@ -811,241 +811,27 @@ B shifta_c2(B t, B w, B x) {
|
||||
return qWithFill(mut_fcd(r, x), f);
|
||||
}
|
||||
|
||||
extern B ne_c2(B, B, B);
|
||||
extern B slash_c1(B, B);
|
||||
extern B slash_c2(B, B, B);
|
||||
extern B select_c2(B, B, B);
|
||||
extern B rt_group;
|
||||
B group_c2(B t, B w, B x) {
|
||||
if (isArr(w)&isArr(x) && RNK(w)==1 && RNK(x)==1 && depth(w)==1) {
|
||||
usz wia = IA(w);
|
||||
usz xia = IA(x);
|
||||
if (wia-xia > 1) thrF("⊔: ≠𝕨 must be either ≠𝕩 or one bigger (%s≡≠𝕨, %s≡≠𝕩)", wia, xia);
|
||||
u8 we = TI(w,elType);
|
||||
if (elInt(we)) {
|
||||
if (we==el_bit) w = taga(cpyI8Arr(w));
|
||||
i64 ria = 0;
|
||||
bool bad = false, sort = true;
|
||||
usz neg = 0, change = 0;
|
||||
void *wp0 = tyany_ptr(w);
|
||||
#define CASE(T) case el_##T: { \
|
||||
T max = -1, prev = -1; \
|
||||
for (usz i = 0; i < xia; i++) { \
|
||||
T n = ((T*)wp0)[i]; \
|
||||
if (n>max) max = n; \
|
||||
bad |= n < -1; \
|
||||
neg += n == -1; \
|
||||
sort &= prev <= n; \
|
||||
change += prev != n; \
|
||||
prev = n; \
|
||||
} \
|
||||
if (wia>xia) { ria=((T*)wp0)[xia]; bad|=ria<-1; } \
|
||||
i64 m=(i64)max+1; if (m>ria) ria=m; \
|
||||
break; }
|
||||
switch (we) { default:UD; case el_bit: CASE(i8) CASE(i16) CASE(i32) }
|
||||
#undef CASE
|
||||
if (bad) thrM("⊔: 𝕨 can't contain elements less than ¯1");
|
||||
if (ria > (i64)(USZ_MAX)) thrOOM();
|
||||
|
||||
Arr* r = arr_shVec(m_fillarrp(ria)); fillarr_setFill(r, m_f64(0));
|
||||
B* rp = fillarr_ptr(r);
|
||||
for (usz i = 0; i < ria; i++) rp[i] = m_f64(0); // don't break if allocation errors
|
||||
B xf = getFillQ(x);
|
||||
|
||||
Arr* rf = arr_shVec(m_fillarrp(0)); fillarr_setFill(rf, m_f64(0));
|
||||
B z = taga(rf);
|
||||
fillarr_setFill(r, z);
|
||||
|
||||
TALLOC(i32, pos, 2*ria+1); i32* len = pos+ria+1;
|
||||
// Both cases needed to make sure wia>0 for ip[wia-1] below
|
||||
if (ria==0) goto intvec_ret;
|
||||
if (neg==xia) {
|
||||
for (usz i = 0; i < ria; i++) rp[i] = inc(z);
|
||||
goto intvec_ret;
|
||||
}
|
||||
|
||||
u8 xe = TI(x,elType);
|
||||
u8 width = elWidth(xe);
|
||||
u64 xw;
|
||||
if (xia>64 && (xw=(u64)xia*width)<=I32_MAX && change<xw/32 && xe!=el_bit && xe!=el_B) {
|
||||
#define C1(F,X ) F##_c1(m_f64(0),X )
|
||||
#define C2(F,X,W) F##_c2(m_f64(0),X,W)
|
||||
if (wia>xia) w = C2(take, m_f64(xia), w);
|
||||
B c = C2(ne, C2(drop, m_f64(-1), inc(w)),
|
||||
C2(drop, m_f64( 1), inc(w)));
|
||||
B ind = C1(slash, C2(join, m_f64(-1!=IGetU(w,0).f), c));
|
||||
w = C2(select, inc(ind), w);
|
||||
#undef C1
|
||||
#undef C2
|
||||
if (TI(ind,elType)!=el_i32) ind = taga(cpyI32Arr(ind));
|
||||
if (TI(w ,elType)!=el_i32) w = taga(cpyI32Arr(w ));
|
||||
wia = IA(ind);
|
||||
|
||||
i32* ip = i32any_ptr(ind);
|
||||
i32* wp = i32any_ptr(w);
|
||||
usz i0 = ip[0];
|
||||
for (usz i=0; i<wia-1; i++) ip[i] = ip[i+1]-ip[i];
|
||||
ip[wia-1] = xia-ip[wia-1];
|
||||
for (usz i = 0; i < ria; i++) len[i] = pos[i] = 0;
|
||||
for (usz i = 0; i < wia; i++) len[wp[i]]+=ip[i];
|
||||
|
||||
void* xp = tyany_ptr(x);
|
||||
u8 xt = el2t(xe);
|
||||
|
||||
for (usz j = 0; j < ria; j++) {
|
||||
usz l=len[j];
|
||||
if (!l) rp[j]=inc(z); else m_tyarrv(rp+j, width, l, xt);
|
||||
}
|
||||
for (usz i=0, k=i0*width; i<wia; i++) {
|
||||
usz k0 = k;
|
||||
usz l = ip[i]*width; k += l;
|
||||
i32 n = wp[i]; if (n<0) continue;
|
||||
memcpy((u8*)tyarr_ptr(rp[n])+pos[n], (u8*)xp+k0, l);
|
||||
pos[n] += l;
|
||||
}
|
||||
decG(ind); goto intvec_ret;
|
||||
}
|
||||
if (xia>32 && neg>xia/4+xia/8) {
|
||||
if (wia>xia) w = take_c2(m_f64(0), m_f64(xia), w);
|
||||
B m = ne_c2(m_f64(0), m_f64(-1), inc(w));
|
||||
w = slash_c2(m_f64(0), inc(m), w);
|
||||
x = slash_c2(m_f64(0), m, x); xia = IA(x);
|
||||
neg = 0;
|
||||
}
|
||||
if (TI(w,elType)!=el_i32) w = taga(cpyI32Arr(w));
|
||||
i32* wp = i32any_ptr(w);
|
||||
for (usz i = 0; i < ria; i++) len[i] = pos[i] = 0;
|
||||
for (usz i = 0; i < xia; i++) len[wp[i]]++; // overallocation makes this safe after n<-1 check
|
||||
|
||||
switch (xe) { default: UD;
|
||||
case el_i8: case el_c8:
|
||||
case el_i16: case el_c16:
|
||||
case el_i32: case el_c32: case el_f64: {
|
||||
void* xp = tyany_ptr(x);
|
||||
u8 xt = el2t(xe);
|
||||
if (sort) {
|
||||
for (usz j=0, i=neg*width; j<ria; j++) {
|
||||
usz l = len[j];
|
||||
if (!l) { rp[j]=inc(z); continue; }
|
||||
m_tyarrv(rp+j, width, l, xt);
|
||||
usz lw = l*width;
|
||||
memcpy(tyarr_ptr(rp[j]), (u8*)xp+i, lw);
|
||||
i += lw;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (usz j = 0; j < ria; j++) {
|
||||
usz l=len[j];
|
||||
if (!l) rp[j]=inc(z); else m_tyarrv(rp+j, width, l, xt);
|
||||
}
|
||||
switch(width) { default: UD;
|
||||
case 1: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u8* )tyarr_ptr(rp[n]))[pos[n]++] = ((u8* )xp)[i]; } break;
|
||||
case 2: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u16*)tyarr_ptr(rp[n]))[pos[n]++] = ((u16*)xp)[i]; } break;
|
||||
case 4: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((u32*)tyarr_ptr(rp[n]))[pos[n]++] = ((u32*)xp)[i]; } break;
|
||||
case 8: for (usz i = 0; i < xia; i++) { i32 n = wp[i]; if (n>=0) ((f64*)tyarr_ptr(rp[n]))[pos[n]++] = ((f64*)xp)[i]; } break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case el_bit: case el_B: {
|
||||
for (usz i = 0; i < ria; i++) {
|
||||
Arr* c = m_fillarrp(len[i]);
|
||||
c->ia = 0;
|
||||
fillarr_setFill(c, inc(xf));
|
||||
arr_shVec(c);
|
||||
rp[i] = taga(c);
|
||||
}
|
||||
SLOW2("𝕨⊔𝕩", w, x);
|
||||
SGet(x)
|
||||
for (usz i = 0; i < xia; i++) {
|
||||
i32 n = wp[i];
|
||||
if (n>=0) fillarr_ptr(a(rp[n]))[pos[n]++] = Get(x, i);
|
||||
}
|
||||
for (usz i = 0; i < ria; i++) a(rp[i])->ia = len[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
intvec_ret:
|
||||
fillarr_setFill(rf, xf);
|
||||
decG(w); decG(x); TFREE(pos);
|
||||
return taga(r);
|
||||
} else {
|
||||
SLOW2("𝕨⊔𝕩", w, x);
|
||||
SGetU(w)
|
||||
i64 ria = wia==xia? 0 : o2i64(GetU(w, xia));
|
||||
if (ria<-1) thrM("⊔: 𝕨 can't contain elements less than ¯1");
|
||||
ria--;
|
||||
for (usz i = 0; i < xia; i++) {
|
||||
B cw = GetU(w, i);
|
||||
if (!q_i64(cw)) goto base;
|
||||
i64 c = o2i64G(cw);
|
||||
if (c>ria) ria = c;
|
||||
if (c<-1) thrM("⊔: 𝕨 can't contain elements less than ¯1");
|
||||
}
|
||||
if (ria > (i64)(USZ_MAX-1)) thrOOM();
|
||||
ria++;
|
||||
TALLOC(i32, lenO, ria+1); i32* len = lenO+1;
|
||||
TALLOC(i32, pos, ria);
|
||||
for (usz i = 0; i < ria; i++) len[i] = pos[i] = 0;
|
||||
for (usz i = 0; i < xia; i++) len[o2i64G(GetU(w, i))]++;
|
||||
|
||||
Arr* r = arr_shVec(m_fillarrp(ria)); fillarr_setFill(r, m_f64(0));
|
||||
B* rp = fillarr_ptr(r);
|
||||
for (usz i = 0; i < ria; i++) rp[i] = m_f64(0); // don't break if allocation errors
|
||||
B xf = getFillQ(x);
|
||||
|
||||
for (usz i = 0; i < ria; i++) {
|
||||
Arr* c = m_fillarrp(len[i]);
|
||||
c->ia = 0;
|
||||
fillarr_setFill(c, inc(xf));
|
||||
arr_shVec(c);
|
||||
rp[i] = taga(c);
|
||||
}
|
||||
Arr* rf = m_fillarrp(0); arr_shVec(rf);
|
||||
fillarr_setFill(rf, xf);
|
||||
fillarr_setFill(r, taga(rf));
|
||||
SGet(x)
|
||||
for (usz i = 0; i < xia; i++) {
|
||||
i64 n = o2i64G(GetU(w, i));
|
||||
if (n>=0) fillarr_ptr(a(rp[n]))[pos[n]++] = Get(x, i);
|
||||
}
|
||||
for (usz i = 0; i < ria; i++) a(rp[i])->ia = len[i];
|
||||
decG(w); decG(x); TFREE(lenO); TFREE(pos);
|
||||
return taga(r);
|
||||
}
|
||||
}
|
||||
base:
|
||||
return c2(rt_group, w, x);
|
||||
}
|
||||
B ud_c1(B, B);
|
||||
B group_c1(B t, B x) {
|
||||
if (isArr(x) && RNK(x)==1 && TI(x,arrD1)) {
|
||||
usz ia = IA(x);
|
||||
B range = ud_c1(t, m_f64(ia));
|
||||
return group_c2(m_f64(0), x, range);
|
||||
}
|
||||
return c1(rt_group, x);
|
||||
}
|
||||
|
||||
extern B rt_reverse;
|
||||
B reverse_c1(B t, B x) {
|
||||
if (isAtm(x) || RNK(x)==0) thrM("⌽: Argument cannot be a unit");
|
||||
usz xia = IA(x);
|
||||
if (xia==0) return x;
|
||||
u8 xe = TI(x,elType);
|
||||
if (RNK(x)==1) {
|
||||
usz n = *SH(x);
|
||||
if (n==0) return x;
|
||||
u8 xl = cellWidthLog(x);
|
||||
u8 xt = arrNewType(TY(x));
|
||||
if (xl <= 6 && (xl >=3 || xl == 0)) {
|
||||
void* xv = tyany_ptr(x);
|
||||
B r;
|
||||
switch(xe) { default: UD;
|
||||
case el_bit: { u64* xp = bitarr_ptr(x); u64* rp; r = m_bitarrv(&rp, xia); for (usz i = 0; i < xia; i++) bitp_set(rp, i, bitp_get(xp, xia-i-1)); break; }
|
||||
case el_i8: case el_c8: { u8* xp = tyany_ptr(x); u8* rp = m_tyarrv(&r, 1, xia, el2t(xe)); for (usz i = 0; i < xia; i++) rp[i] = xp[xia-i-1]; break; }
|
||||
case el_i16:case el_c16: { u16* xp = tyany_ptr(x); u16* rp = m_tyarrv(&r, 2, xia, el2t(xe)); for (usz i = 0; i < xia; i++) rp[i] = xp[xia-i-1]; break; }
|
||||
case el_i32:case el_c32: { u32* xp = tyany_ptr(x); u32* rp = m_tyarrv(&r, 4, xia, el2t(xe)); for (usz i = 0; i < xia; i++) rp[i] = xp[xia-i-1]; break; }
|
||||
case el_f64: { f64* xp = f64any_ptr(x); f64* rp; r = m_f64arrv(&rp, xia); for (usz i = 0; i < xia; i++) rp[i] = xp[xia-i-1]; break; }
|
||||
case el_B: {
|
||||
switch(xl) { default: UD; break;
|
||||
case 0: { u64* xp = xv; u64* rp; r = m_bitarrc(&rp, x); for (usz i = 0; i < n; i++) bitp_set(rp, i, bitp_get(xp, n-i-1)); break; }
|
||||
case 3: { u8* xp = xv; u8* rp = m_tyarrc(&r, 1, x, xt); for (usz i = 0; i < n; i++) rp[i] = xp[n-i-1]; break; }
|
||||
case 4: { u16* xp = xv; u16* rp = m_tyarrc(&r, 2, x, xt); for (usz i = 0; i < n; i++) rp[i] = xp[n-i-1]; break; }
|
||||
case 5: { u32* xp = xv; u32* rp = m_tyarrc(&r, 4, x, xt); for (usz i = 0; i < n; i++) rp[i] = xp[n-i-1]; break; }
|
||||
case 6: if (TI(x,elType)!=el_B) { u64* xp = xv; u64* rp = m_tyarrc(&r, 8, x, xt); for (usz i = 0; i < n; i++) rp[i] = xp[n-i-1]; break; }
|
||||
else {
|
||||
HArr_p rp = m_harrUc(x);
|
||||
B* xp = arr_bptr(x);
|
||||
if (xp!=NULL) for (usz i = 0; i < xia; i++) rp.a[i] = inc(xp[xia-i-1]);
|
||||
else { SGet(x) for (usz i = 0; i < xia; i++) rp.a[i] = Get(x, xia-i-1); }
|
||||
if (xp!=NULL) for (usz i = 0; i < n; i++) rp.a[i] = inc(xp[n-i-1]);
|
||||
else { SGet(x) for (usz i = 0; i < n; i++) rp.a[i] = Get(x, n-i-1); }
|
||||
r = rp.b;
|
||||
B xf = getFillQ(x);
|
||||
decG(x);
|
||||
@ -1060,8 +846,8 @@ B reverse_c1(B t, B x) {
|
||||
usz csz = arr_csz(x);
|
||||
usz cam = SH(x)[0];
|
||||
usz rp = 0;
|
||||
usz ip = xia;
|
||||
MAKE_MUT(r, xia); mut_init(r, xe);
|
||||
usz ip = IA(x);
|
||||
MAKE_MUT(r, ip); mut_init(r, TI(x,elType));
|
||||
MUTG_INIT(r);
|
||||
for (usz i = 0; i < cam; i++) {
|
||||
ip-= csz;
|
||||
@ -1206,54 +992,6 @@ B pick_ucw(B t, B o, B w, B x) {
|
||||
return qWithFill(mut_fcd(r, x), xf);
|
||||
}
|
||||
|
||||
B slash_ucw(B t, B o, B w, B x) {
|
||||
if (isAtm(w) || isAtm(x) || RNK(w)!=1 || RNK(x)!=1 || IA(w)!=IA(x)) return def_fn_ucw(t, o, w, x);
|
||||
usz ia = IA(x);
|
||||
SGetU(w)
|
||||
if (!elInt(TI(w,elType))) for (usz i = 0; i < ia; i++) if (!q_i32(GetU(w,i))) return def_fn_ucw(t, o, w, x);
|
||||
B arg = slash_c2(t, inc(w), inc(x));
|
||||
usz argIA = IA(arg);
|
||||
B rep = c1(o, arg);
|
||||
if (isAtm(rep) || RNK(rep)!=1 || IA(rep) != argIA) thrF("𝔽⌾(a⊸/)𝕩: Result of 𝔽 must have the same shape as a/𝕩 (expected ⟨%s⟩, got %H)", argIA, rep);
|
||||
MAKE_MUT(r, ia); mut_init(r, el_or(TI(x,elType), TI(rep,elType)));
|
||||
SGet(x)
|
||||
SGet(rep)
|
||||
usz repI = 0;
|
||||
if (TY(w) == t_bitarr) {
|
||||
u64* d = bitarr_ptr(w);
|
||||
if (elInt(TI(x,elType)) && elInt(TI(rep,elType))) {
|
||||
if (r->fns->elType!=el_i32) mut_to(r, el_i32);
|
||||
i32* rp = r->ai32;
|
||||
x = toI32Any(x); i32* xp = i32any_ptr(x);
|
||||
rep = toI32Any(rep); i32* np = i32any_ptr(rep);
|
||||
for (usz i = 0; i < ia; i++) {
|
||||
bool v = bitp_get(d, i);
|
||||
i32 nc = np[repI];
|
||||
i32 xc = xp[i];
|
||||
rp[i] = v? nc : xc;
|
||||
repI+= v;
|
||||
}
|
||||
} else {
|
||||
MUTG_INIT(r);
|
||||
for (usz i = 0; i < ia; i++) mut_setG(r, i, bitp_get(d, i)? Get(rep,repI++) : Get(x,i));
|
||||
}
|
||||
} else {
|
||||
SGetU(rep)
|
||||
MUTG_INIT(r);
|
||||
for (usz i = 0; i < ia; i++) {
|
||||
i32 cw = o2iG(GetU(w, i));
|
||||
if (cw) {
|
||||
B cr = Get(rep,repI);
|
||||
if (CHECK_VALID) for (i32 j = 1; j < cw; j++) if (!equal(GetU(rep,repI+j), cr)) { mut_pfree(r,i); thrM("𝔽⌾(a⊸/): Incompatible result elements"); }
|
||||
mut_setG(r, i, cr);
|
||||
repI+= cw;
|
||||
} else mut_setG(r, i, Get(x,i));
|
||||
}
|
||||
}
|
||||
decG(w); decG(rep);
|
||||
return mut_fcd(r, x);
|
||||
}
|
||||
|
||||
static B takedrop_ucw(i64 wi, B o, u64 am, B x, size_t xr) {
|
||||
usz xia = IA(x);
|
||||
usz csz = arr_csz(x);
|
||||
@ -1339,7 +1077,6 @@ void sfns_init() {
|
||||
c(BFn,bi_pick)->uc1 = pick_uc1;
|
||||
c(BFn,bi_reverse)->uc1 = reverse_uc1;
|
||||
c(BFn,bi_pick)->ucw = pick_ucw;
|
||||
c(BFn,bi_slash)->ucw = slash_ucw;
|
||||
c(BFn,bi_select)->ucw = select_ucw; // TODO move to new init fn
|
||||
c(BFn,bi_shape)->uc1 = shape_uc1;
|
||||
c(BFn,bi_transp)->uc1 = transp_uc1;
|
||||
|
||||
@ -178,6 +178,58 @@ static void where_block_u16(u64* src, u16* dst, usz len, usz sum) {
|
||||
}
|
||||
}
|
||||
|
||||
static B compress_grouped(u64* wp, B x, usz wia, usz wsum, u8 xt) {
|
||||
B r;
|
||||
usz csz = arr_csz(x);
|
||||
u8 xl = arrTypeBitsLog(TY(x));
|
||||
#define COMPRESS_GROUP(CPY) \
|
||||
u64 ri = 0; \
|
||||
u64 wv = wp[0]; usz i = 0, wn = (wia-1)/64+1; \
|
||||
for (u64 e=wsum*width; ri < e; ) { \
|
||||
while (wv== 0) { wv=wp[++i]; } usz i0=64*i+CTZ( wv); wv|=wv-1; \
|
||||
while (wv==-(u64)1) { wv=++i<wn?wp[i]:0; } usz i1=64*i+CTZ(~wv); wv&=wv+1; \
|
||||
u64 l = (i1-i0) * width; \
|
||||
CPY(rp, ri, xp, i0*width, l); ri += l; \
|
||||
}
|
||||
if (xl>0 || csz%8==0) { // Full bytes
|
||||
u64 width = xl==0 ? csz/8 : csz << (xl-3);
|
||||
u8* xp; u8* rp;
|
||||
bool is_B = TI(x,elType) == el_B; HArr_p rh;
|
||||
if (!is_B) {
|
||||
xp = tyany_ptr(x);
|
||||
rp = m_tyarrv(&r,width,wsum,xt);
|
||||
} else {
|
||||
xp = (u8*)arr_bptr(x);
|
||||
usz ria = wsum*csz;
|
||||
if (xp != NULL) {
|
||||
rh = m_harrUv(ria);
|
||||
rp = (u8*)rh.a;
|
||||
} else {
|
||||
SLOW2("𝕨/𝕩", w, x);
|
||||
M_HARR(rp, ria) SGet(x)
|
||||
for (usz i = 0; i < wia; i++) if (bitp_get(wp,i)) {
|
||||
for (usz j = 0; j < csz; j++) HARR_ADDA(rp, Get(x,i*csz+j));
|
||||
}
|
||||
return withFill(HARR_FV(rp), getFillQ(x));
|
||||
}
|
||||
}
|
||||
#define MEM_CPY(R,RI,X,XI,L) memcpy(R+RI, X+XI, L)
|
||||
COMPRESS_GROUP(MEM_CPY)
|
||||
#undef MEM_CPY
|
||||
if (is_B) {
|
||||
for (usz i = 0; i < wsum*csz; i++) inc(((B*)rp)[i]);
|
||||
r = withFill(rh.b, getFillQ(x));
|
||||
IA(r) = wsum; // Shape-setting code at end of compress expects this
|
||||
}
|
||||
} else { // Bits
|
||||
usz width = csz;
|
||||
u64* xp = tyany_ptr(x);
|
||||
u64* rp; r = m_bitarrv(&rp,wsum*width); IA(r) = wsum;
|
||||
COMPRESS_GROUP(bit_cpy)
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static B where(B x, usz xia, u64 s) {
|
||||
B r;
|
||||
u64* xp = bitarr_ptr(x);
|
||||
@ -261,24 +313,45 @@ static B where(B x, usz xia, u64 s) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static B compress(B w, B x, usz wia, B xf) {
|
||||
// Is the number of values switches in w at most max?
|
||||
static bool groups_lt(u64* wp, usz len, usz max) {
|
||||
usz r = 0;
|
||||
u64 prev = 0;
|
||||
usz l = (len-1)/64+1; // assume trailing bits are zeroed out
|
||||
usz b = 1<<8;
|
||||
for (usz i = 0; i < l; ) {
|
||||
for (usz e = l-i<b?l:i+b; i < e; i++) {
|
||||
u64 v=wp[i]; r+= POPC(v ^ (v<<1 | prev)); prev = v>>63;
|
||||
}
|
||||
if (r > max) return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern B take_c2(B, B, B);
|
||||
static B compress(B w, B x, usz wia, u8 xl, u8 xt) {
|
||||
u64* wp = bitarr_ptr(w);
|
||||
u64 we = 0;
|
||||
usz ie = wia/64;
|
||||
usz q=wia%64; if (q) we = wp[ie] &= ((u64)1<<q) - 1;
|
||||
while (!we) {
|
||||
if (RARE(ie==0)) { return q_N(xf)? emptyHVec() : isF64(xf)? emptyIVec() : isC32(xf)? emptyCVec() : m_emptyFVec(xf); }
|
||||
if (RARE(ie==0)) {
|
||||
if (RNK(x)>1) return take_c2(m_f64(0), m_f64(0), inc(x));
|
||||
u8 xe = TI(x,elType);
|
||||
if (xe != el_B) return elNum(xe)? emptyIVec() : emptyCVec();
|
||||
B xf = getFillQ(x); return q_N(xf)? emptyHVec() : m_emptyFVec(xf);
|
||||
}
|
||||
we = wp[--ie];
|
||||
}
|
||||
usz wia0 = wia;
|
||||
wia = 64*(ie+1) - CLZ(we);
|
||||
usz wsum = bit_sum(wp, wia);
|
||||
if (wsum == wia0) { dec(xf); return inc(x); }
|
||||
|
||||
if (wsum == wia0) return inc(x);
|
||||
|
||||
B r;
|
||||
u8 xe = TI(x,elType);
|
||||
switch(xe) { default: UD;
|
||||
case el_bit: {
|
||||
switch(xl) {
|
||||
default: r = compress_grouped(wp, x, wia, wsum, xt); break;
|
||||
case 0: {
|
||||
u64* xp = bitarr_ptr(x); u64* rp;
|
||||
#if SINGELI && defined(__BMI2__)
|
||||
r = m_bitarrv(&rp,wsum+128); a(r)->ia = wsum;
|
||||
@ -317,36 +390,50 @@ static B compress(B w, B x, usz wia, B xf) {
|
||||
TFREE(buf)
|
||||
#define WITH_SPARSE(W, CUTOFF, DENSE) { \
|
||||
i##W *xp=tyany_ptr(x), *rp; \
|
||||
if (wsum>=wia/CUTOFF) { DENSE; } \
|
||||
else { rp=m_tyarrv(&r,W/8,wsum,el2t(xe)); COMPRESS_BLOCK(i##W); } \
|
||||
if (wsum<wia/CUTOFF) { rp=m_tyarrv(&r,W/8,wsum,xt); COMPRESS_BLOCK(i##W); } \
|
||||
else if (groups_lt(wp,wia, wia/128)) r = compress_grouped(wp, x, wia, wsum, xt); \
|
||||
else { DENSE; } \
|
||||
break; }
|
||||
#if SINGELI
|
||||
case el_i8: case el_c8: WITH_SPARSE( 8, 32, rp=m_tyarrvO(&r,1,wsum,el2t(xe), 8); bmipopc_2slash8 (wp, xp, rp, wia))
|
||||
case el_i16:case el_c16: WITH_SPARSE(16, 16, rp=m_tyarrvO(&r,2,wsum,el2t(xe), 16); bmipopc_2slash16(wp, xp, rp, wia))
|
||||
case 3: WITH_SPARSE( 8, 32, rp=m_tyarrvO(&r,1,wsum,xt, 8); bmipopc_2slash8 (wp, xp, rp, wia))
|
||||
case 4: WITH_SPARSE(16, 16, rp=m_tyarrvO(&r,2,wsum,xt, 16); bmipopc_2slash16(wp, xp, rp, wia))
|
||||
#else
|
||||
case el_i8: case el_c8: WITH_SPARSE( 8, 2, rp=m_tyarrv(&r,1,wsum,el2t(xe)); for (usz i=0; i<wia; i++) { *rp = xp[i]; rp+= bitp_get(wp,i); })
|
||||
case el_i16:case el_c16: WITH_SPARSE(16, 2, rp=m_tyarrv(&r,2,wsum,el2t(xe)); for (usz i=0; i<wia; i++) { *rp = xp[i]; rp+= bitp_get(wp,i); })
|
||||
case 3: WITH_SPARSE( 8, 2, rp=m_tyarrv(&r,1,wsum,xt); for (usz i=0; i<wia; i++) { *rp = xp[i]; rp+= bitp_get(wp,i); })
|
||||
case 4: WITH_SPARSE(16, 2, rp=m_tyarrv(&r,2,wsum,xt); for (usz i=0; i<wia; i++) { *rp = xp[i]; rp+= bitp_get(wp,i); })
|
||||
#endif
|
||||
#undef WITH_SPARSE
|
||||
case el_i32:case el_c32: { i32* xp= tyany_ptr(x); i32* rp=m_tyarrv(&r,4,wsum,el2t(xe)); COMPRESS_BLOCK(i32); break; }
|
||||
case el_f64: { f64* xp=f64any_ptr(x); f64* rp; r = m_f64arrv(&rp,wsum); COMPRESS_BLOCK(f64); break; }
|
||||
case el_B: {
|
||||
B* xp = arr_bptr(x);
|
||||
if (xp!=NULL) {
|
||||
HArr_p rh = m_harrUv(wsum);
|
||||
B *rp = rh.a; COMPRESS_BLOCK(B);
|
||||
for (usz i=0; i<wsum; i++) inc(rh.a[i]);
|
||||
r = withFill(rh.b, xf);
|
||||
} else {
|
||||
SLOW2("𝕨/𝕩", w, x);
|
||||
M_HARR(rp, wsum) SGet(x)
|
||||
for (usz i = 0; i < wia; i++) if (bitp_get(wp,i)) HARR_ADDA(rp, Get(x,i));
|
||||
r = withFill(HARR_FV(rp), xf);
|
||||
#define BLOCK_OR_GROUPED(T) \
|
||||
if (wsum>=wia/8 && groups_lt(wp,wia, wia/16)) r = compress_grouped(wp, x, wia, wsum, xt); \
|
||||
else { T* xp=tyany_ptr(x); T* rp=m_tyarrv(&r,sizeof(T),wsum,xt); COMPRESS_BLOCK(T); }
|
||||
case 5: BLOCK_OR_GROUPED(i32) break;
|
||||
case 6:
|
||||
if (TI(x,elType)!=el_B) { BLOCK_OR_GROUPED(u64) }
|
||||
else {
|
||||
B xf = getFillQ(x);
|
||||
B* xp = arr_bptr(x);
|
||||
if (xp!=NULL) {
|
||||
HArr_p rh = m_harrUv(wsum);
|
||||
B *rp = rh.a; COMPRESS_BLOCK(B);
|
||||
for (usz i=0; i<wsum; i++) inc(rh.a[i]);
|
||||
r = withFill(rh.b, xf);
|
||||
} else {
|
||||
SLOW2("𝕨/𝕩", w, x);
|
||||
M_HARR(rp, wsum) SGet(x)
|
||||
for (usz i = 0; i < wia; i++) if (bitp_get(wp,i)) HARR_ADDA(rp, Get(x,i));
|
||||
r = withFill(HARR_FV(rp), xf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#undef BLOCK_OR_GROUPED
|
||||
#undef COMPRESS_BLOCK
|
||||
}
|
||||
ur xr = RNK(x);
|
||||
if (xr > 1) {
|
||||
Arr* ra=a(r); SPRNK(ra,xr);
|
||||
usz* sh = PSH(ra) = m_shArr(xr)->a;
|
||||
sh[0] = PIA(ra); PIA(ra) *= arr_csz(x);
|
||||
shcpy(sh+1, SH(x)+1, xr-1);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -359,48 +446,55 @@ B slash_c1(B t, B x) {
|
||||
usz xia = IA(x);
|
||||
B r;
|
||||
u8 xe = TI(x,elType);
|
||||
if (xe!=el_bit && s<=xia) { x = num_squeeze(x); xe = TI(x,elType); }
|
||||
if (xe==el_bit) {
|
||||
r = where(x, xia, s);
|
||||
} else if (RARE(xia>=I32_MAX)) {
|
||||
} else if (RARE(xia > (usz)I32_MAX+1)) {
|
||||
SGetU(x)
|
||||
f64* rp; r = m_f64arrv(&rp, s); usz ri = 0;
|
||||
for (usz i = 0; i < xia; i++) {
|
||||
usz c = o2s(GetU(x, i));
|
||||
for (usz j = 0; j < c; j++) rp[ri++] = i;
|
||||
}
|
||||
} else {
|
||||
} else if (RARE(xe > el_i32)) {
|
||||
i32* rp; r = m_i32arrv(&rp, s);
|
||||
if (xe==el_i8) {
|
||||
i8* xp = i8any_ptr(x);
|
||||
while (xia>0 && !xp[xia-1]) xia--;
|
||||
for (u64 i = 0; i < xia; i++) {
|
||||
i32 c = xp[i];
|
||||
if (LIKELY(c==0 || c==1)) {
|
||||
*rp = i;
|
||||
rp+= c;
|
||||
} else {
|
||||
for (i32 j = 0; j < c; j++) *rp++ = i;
|
||||
SLOW1("/𝕩", x);
|
||||
SGetU(x)
|
||||
for (u64 i = 0; i < xia; i++) {
|
||||
usz c = o2s(GetU(x, i));
|
||||
for (u64 j = 0; j < c; j++) *rp++ = i;
|
||||
}
|
||||
} else {
|
||||
if (s/16 <= xia) { // Sparse case: type of x matters
|
||||
#define SPARSE_IND(T) \
|
||||
T* xp = T##any_ptr(x); \
|
||||
usz b = 1<<10; \
|
||||
for (usz k=0, j=0, js=0, ij=xp[0]; ; ) { \
|
||||
usz e = b<s-k? k+b : s; \
|
||||
for (usz i=k; i<e; i++) rp[i]=0; \
|
||||
while (ij<e) { rp[ij]++; ij+=xp[++j]; } \
|
||||
for (usz i=k; i<e; i++) js=rp[i]+=js; \
|
||||
if (e==s) {break;} k=e; \
|
||||
}
|
||||
}
|
||||
} else if (xe==el_i32) {
|
||||
i32* rp; r = m_i32arrv(&rp, s);
|
||||
if (xe == el_i8 ) { SPARSE_IND(i8 ); }
|
||||
else if (xe == el_i16) { SPARSE_IND(i16); }
|
||||
else { SPARSE_IND(i32); }
|
||||
#undef SPARSE_IND
|
||||
} else { // Dense case: only result type matters
|
||||
#define DENSE_IND(T) \
|
||||
T* rp; r = m_##T##arrv(&rp, s); \
|
||||
for (u64 i = 0; i < xia; i++) { \
|
||||
i32 c = xp[i]; \
|
||||
for (i32 j = 0; j < c; j++) *rp++ = i; \
|
||||
}
|
||||
if (xe < el_i32) x = taga(cpyI32Arr(x));
|
||||
i32* xp = i32any_ptr(x);
|
||||
while (xia>0 && !xp[xia-1]) xia--;
|
||||
for (u64 i = 0; i < xia; i++) {
|
||||
i32 c = xp[i];
|
||||
if (LIKELY(c==0 || c==1)) {
|
||||
*rp = i;
|
||||
rp+= c;
|
||||
} else {
|
||||
for (i32 j = 0; j < c; j++) *rp++ = i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SLOW1("/𝕩", x);
|
||||
SGetU(x)
|
||||
for (u64 i = 0; i < xia; i++) {
|
||||
usz c = o2s(GetU(x, i));
|
||||
for (u64 j = 0; j < c; j++) *rp++ = i;
|
||||
}
|
||||
if (xia <= 128) { DENSE_IND(i8 ); }
|
||||
else if (xia <= 32768) { DENSE_IND(i16); }
|
||||
else { DENSE_IND(i32); }
|
||||
#undef DENSE_IND
|
||||
}
|
||||
}
|
||||
decG(x);
|
||||
@ -408,85 +502,144 @@ B slash_c1(B t, B x) {
|
||||
}
|
||||
|
||||
B slash_c2(B t, B w, B x) {
|
||||
if (isArr(x) && RNK(x)==1 && isArr(w) && RNK(w)==1 && depth(w)==1) {
|
||||
B r;
|
||||
if (isArr(w) && RNK(w)==1 && depth(w)==1) {
|
||||
usz wia = IA(w);
|
||||
usz xia = IA(x);
|
||||
if (RARE(wia!=xia)) {
|
||||
if (wia==0) { decG(w); return x; }
|
||||
thrF("/: Lengths of components of 𝕨 must match 𝕩 (%s ≠ %s)", wia, xia);
|
||||
}
|
||||
B xf = getFillQ(x);
|
||||
if (wia==0) { decG(w); return isArr(x)? x : m_atomUnit(x); }
|
||||
if (isAtm(x) || RNK(x)==0) thrM("/: 𝕩 must have rank at least 1 for simple 𝕨");
|
||||
ur xr = RNK(x);
|
||||
usz xlen = *SH(x);
|
||||
if (RARE(wia!=xlen)) thrF("/: Lengths of components of 𝕨 must match 𝕩 (%s ≠ %s)", wia, xlen);
|
||||
|
||||
B r;
|
||||
if (TI(w,elType)==el_bit) {
|
||||
compress:
|
||||
r = compress(w, x, wia, xf);
|
||||
decWX_ret:
|
||||
decG(w); decG(x); return r;
|
||||
|
||||
to_compress:
|
||||
wia = xia;
|
||||
w = taga(cpyBitArr(w));
|
||||
goto compress;
|
||||
u8 xl = cellWidthLog(x);
|
||||
u8 xt = arrNewType(TY(x));
|
||||
|
||||
u8 we = TI(w,elType);
|
||||
if (!elInt(we)) {
|
||||
w=any_squeeze(w); we=TI(w,elType);
|
||||
if (!elInt(we)) goto slow;
|
||||
}
|
||||
#define CASE(WT,XT) if (TI(x,elType)==el_##XT) { \
|
||||
XT* xp = XT##any_ptr(x); \
|
||||
XT* rp; r = m_##XT##arrv(&rp, wsum); \
|
||||
for (usz i = 0; i < wia; i++) { \
|
||||
WT cw = wp[i]; XT cx = xp[i]; \
|
||||
for (i64 j = 0; j < cw; j++) *rp++ = cx; \
|
||||
} \
|
||||
goto decWX_ret; \
|
||||
if (we==el_bit) {
|
||||
wbool:
|
||||
r = compress(w, x, wia, xl, xt);
|
||||
goto decWX_ret;
|
||||
}
|
||||
if (xl>6 || (xl<3 && xl!=0)) goto base;
|
||||
u64 s = usum(w);
|
||||
if (s<=wia) {
|
||||
w=num_squeezeChk(w); we=TI(w,elType);
|
||||
if (we==el_bit) goto wbool;
|
||||
}
|
||||
|
||||
#define TYPED(WT,WTU,SIGN) { \
|
||||
WT* wp = WT##any_ptr(w); \
|
||||
while (wia>0 && !wp[wia-1]) wia--; \
|
||||
i64 wsum = 0; \
|
||||
WTU or = 0; \
|
||||
for (usz i = 0; i < wia; i++) { \
|
||||
wsum+= wp[i]; \
|
||||
or|= (WTU)wp[i]; \
|
||||
} \
|
||||
if (RARE(or>>SIGN)) thrM("/: 𝕨 must consist of natural numbers"); \
|
||||
if (RARE(or<2)) goto to_compress; \
|
||||
if (TI(x,elType)==el_bit) { \
|
||||
u64* xp = bitarr_ptr(x); u64 ri=0; \
|
||||
u64* rp; r = m_bitarrv(&rp, wsum); \
|
||||
for (usz i = 0; i < wia; i++) { \
|
||||
WT cw = wp[i]; bool cx = bitp_get(xp,i); \
|
||||
for (i64 j = 0; j < cw; j++) bitp_set(rp, ri++, cx); \
|
||||
} \
|
||||
decG(w); decG(x); return r; \
|
||||
} \
|
||||
CASE(WT,i8) CASE(WT,i16) CASE(WT,i32) CASE(WT,f64) \
|
||||
SLOW2("𝕨/𝕩", w, x); \
|
||||
M_HARR(r0, wsum) SGetU(x) \
|
||||
for (usz i = 0; i < wia; i++) { \
|
||||
i32 cw = wp[i]; if (cw==0) continue; \
|
||||
B cx = incBy(GetU(x, i), cw); \
|
||||
for (i64 j = 0; j < cw; j++) HARR_ADDA(r0, cx); \
|
||||
} \
|
||||
r = withFill(HARR_FV(r0), xf); goto decWX_ret; \
|
||||
if (RARE(TI(x,elType)==el_B)) { // Slow case
|
||||
slow:
|
||||
if (xr > 1) goto base;
|
||||
SLOW2("𝕨/𝕩", w, x);
|
||||
B xf = getFillQ(x);
|
||||
MAKE_MUT(r0, s) mut_init(r0, el_B); MUTG_INIT(r0);
|
||||
SGetU(w) SGetU(x)
|
||||
usz ri = 0;
|
||||
for (usz i = 0; i < wia; i++) {
|
||||
usz c = o2s(GetU(w, i));
|
||||
if (c) {
|
||||
mut_fillG(r0, ri, GetU(x, i), c);
|
||||
ri+= c;
|
||||
}
|
||||
}
|
||||
r = withFill(mut_fv(r0), xf);
|
||||
decWX_ret: decG(w);
|
||||
decX_ret: decG(x);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (TI(w,elType)==el_i8 ) TYPED(i8,u8,7);
|
||||
if (TI(w,elType)==el_i32) TYPED(i32,u32,31);
|
||||
#undef TYPED
|
||||
#undef CASE
|
||||
SLOW2("𝕨/𝕩", w, x);
|
||||
u64 ria = usum(w);
|
||||
if (ria>=USZ_MAX) thrOOM();
|
||||
M_HARR(r, ria) SGetU(w) SGetU(x)
|
||||
for (usz i = 0; i < wia; i++) {
|
||||
usz c = o2s(GetU(w, i));
|
||||
if (c) {
|
||||
B cx = incBy(GetU(x, i), c);
|
||||
for (usz j = 0; RARE(j < c); j++) HARR_ADDA(r, cx);
|
||||
// Make shape if needed; all cases below use it
|
||||
usz* rsh = NULL;
|
||||
if (xr > 1) {
|
||||
usz* sh = rsh = m_shArr(xr)->a;
|
||||
sh[0] = s;
|
||||
shcpy(sh+1, SH(x)+1, xr-1);
|
||||
}
|
||||
|
||||
if (xl == 0) {
|
||||
u64* xp = bitarr_ptr(x);
|
||||
u64* rp; r = m_bitarrv(&rp, s); if (rsh) { SPRNK(a(r),xr); SH(r) = rsh; }
|
||||
if (s/256 <= wia) {
|
||||
#define SPARSE_REP(T) \
|
||||
T* wp = T##any_ptr(w); \
|
||||
usz b = 1<<12; \
|
||||
u64 xx=xp[0], xs=xx>>63, js=-(xx&1); xx^=xx<<1; \
|
||||
for (usz k=0, j=0, ij=wp[0]; ; ) { \
|
||||
usz e = b<s-k? k+b : s; \
|
||||
usz eb = (e-1)/64+1; \
|
||||
for (usz i=k/64; i<eb; i++) rp[i]=0; \
|
||||
while (ij<e) { \
|
||||
xx>>=1; j++; if (j%64==0) { u64 v=xp[j/64]; xx=v^(v<<1)^xs; xs=v>>63; } \
|
||||
rp[ij/64]^=(-(xx&1))<<(ij%64); ij+=wp[j]; \
|
||||
} \
|
||||
for (usz i=k/64; i<eb; i++) js=-((rp[i]^=js)>>63); \
|
||||
if (e==s) {break;} k=e; \
|
||||
}
|
||||
if (we==el_i8 ) { SPARSE_REP(i8 ); }
|
||||
else if (we==el_i16) { SPARSE_REP(i16); }
|
||||
else { SPARSE_REP(i32); }
|
||||
#undef SPARSE_REP
|
||||
} else {
|
||||
if (we < el_i32) w = taga(cpyI32Arr(w));
|
||||
i32* wp = i32any_ptr(w);
|
||||
u64 ri=0, rc=0, xc=0; usz j=0;
|
||||
for (usz i = 0; i < wia; i++) {
|
||||
u64 v = -(u64)bitp_get(xp,i);
|
||||
rc ^= (v^xc) << (ri%64);
|
||||
xc = v;
|
||||
ri += wp[i]; usz e = ri/64;
|
||||
if (j < e) {
|
||||
rp[j++] = rc;
|
||||
while (j < e) rp[j++] = v;
|
||||
rc = v;
|
||||
}
|
||||
}
|
||||
if (ri%64) rp[j] = rc;
|
||||
}
|
||||
} else {
|
||||
u8 xk = xl-3;
|
||||
void* rv = m_tyarrv(&r, 1<<xk, s, xt);
|
||||
if (rsh) { Arr* ra=a(r); SPRNK(ra,xr); PSH(ra) = rsh; PIA(ra) = s*arr_csz(x); }
|
||||
void* xv = tyany_ptr(x);
|
||||
if (s/32 <= wia) { // Sparse case: use both types
|
||||
#define CASE(L,XT) case L: { \
|
||||
XT* xp = xv; XT* rp = rv; \
|
||||
usz b = 1<<10; \
|
||||
XT js=xp[0], px=js; \
|
||||
for (usz k=0, j=0, ij=wp[0]; ; ) { \
|
||||
usz e = b<s-k? k+b : s; \
|
||||
for (usz i=k; i<e; i++) rp[i]=0; \
|
||||
while (ij<e) { j++; XT sx=px; rp[ij]^=sx^(px=xp[j]); ij+=wp[j]; } \
|
||||
for (usz i=k; i<e; i++) js=rp[i]^=js; \
|
||||
if (e==s) {break;} k=e; \
|
||||
} break; }
|
||||
#define SPARSE_REP(WT) \
|
||||
WT* wp = WT##any_ptr(w); \
|
||||
switch (xk) { default: UD; CASE(0,u8) CASE(1,u16) CASE(2,u32) CASE(3,u64) }
|
||||
if (we == el_i8 ) { SPARSE_REP(i8 ); }
|
||||
else if (we == el_i16) { SPARSE_REP(i16); }
|
||||
else { SPARSE_REP(i32); }
|
||||
#undef SPARSE_REP
|
||||
#undef CASE
|
||||
} else { // Dense case: only type of x matters
|
||||
#define CASE(L,T) case L: { \
|
||||
T* xp = xv; T* rp = rv; \
|
||||
for (usz i = 0; i < wia; i++) { \
|
||||
i32 cw = wp[i]; T cx = xp[i]; \
|
||||
for (i64 j = 0; j < cw; j++) *rp++ = cx; \
|
||||
} break; }
|
||||
if (we < el_i32) w = taga(cpyI32Arr(w));
|
||||
i32* wp = i32any_ptr(w);
|
||||
while (wia>0 && !wp[wia-1]) wia--;
|
||||
switch (xk) { default: UD; CASE(0,u8) CASE(1,u16) CASE(2,u32) CASE(3,u64) }
|
||||
#undef CASE
|
||||
}
|
||||
}
|
||||
decG(w); decG(x);
|
||||
return withFill(HARR_FV(r), xf);
|
||||
goto decWX_ret;
|
||||
}
|
||||
if (isArr(x) && RNK(x)==1 && q_i32(w)) {
|
||||
usz xia = IA(x);
|
||||
@ -497,25 +650,25 @@ B slash_c2(B t, B w, B x) {
|
||||
}
|
||||
if (TI(x,elType)==el_i32) {
|
||||
i32* xp = i32any_ptr(x);
|
||||
i32* rp; B r = m_i32arrv(&rp, xia*wv);
|
||||
i32* rp; r = m_i32arrv(&rp, xia*wv);
|
||||
for (usz i = 0; i < xia; i++) {
|
||||
for (i64 j = 0; j < wv; j++) *rp++ = xp[i];
|
||||
}
|
||||
decG(x);
|
||||
return r;
|
||||
goto decX_ret;
|
||||
} else {
|
||||
SLOW2("𝕨/𝕩", w, x);
|
||||
B xf = getFillQ(x);
|
||||
HArr_p r = m_harrUv(xia*wv);
|
||||
HArr_p r0 = m_harrUv(xia*wv);
|
||||
SGetU(x)
|
||||
for (usz i = 0; i < xia; i++) {
|
||||
B cx = incBy(GetU(x, i), wv);
|
||||
for (i64 j = 0; j < wv; j++) *r.a++ = cx;
|
||||
for (i64 j = 0; j < wv; j++) *r0.a++ = cx;
|
||||
}
|
||||
decG(x);
|
||||
return withFill(r.b, xf);
|
||||
r = withFill(r0.b, xf);
|
||||
goto decX_ret;
|
||||
}
|
||||
}
|
||||
base:
|
||||
return c2(rt_slash, w, x);
|
||||
}
|
||||
|
||||
@ -621,6 +774,55 @@ B slash_im(B t, B x) {
|
||||
}
|
||||
}
|
||||
|
||||
B slash_ucw(B t, B o, B w, B x) {
|
||||
if (isAtm(w) || isAtm(x) || RNK(w)!=1 || RNK(x)!=1 || IA(w)!=IA(x)) return def_fn_ucw(t, o, w, x);
|
||||
usz ia = IA(x);
|
||||
SGetU(w)
|
||||
if (!elInt(TI(w,elType))) for (usz i = 0; i < ia; i++) if (!q_i32(GetU(w,i))) return def_fn_ucw(t, o, w, x);
|
||||
B arg = slash_c2(t, inc(w), inc(x));
|
||||
usz argIA = IA(arg);
|
||||
B rep = c1(o, arg);
|
||||
if (isAtm(rep) || RNK(rep)!=1 || IA(rep) != argIA) thrF("𝔽⌾(a⊸/)𝕩: Result of 𝔽 must have the same shape as a/𝕩 (expected ⟨%s⟩, got %H)", argIA, rep);
|
||||
MAKE_MUT(r, ia); mut_init(r, el_or(TI(x,elType), TI(rep,elType)));
|
||||
SGet(x)
|
||||
SGet(rep)
|
||||
usz repI = 0;
|
||||
if (TY(w) == t_bitarr) {
|
||||
u64* d = bitarr_ptr(w);
|
||||
if (elInt(TI(x,elType)) && elInt(TI(rep,elType))) {
|
||||
if (r->fns->elType!=el_i32) mut_to(r, el_i32);
|
||||
i32* rp = r->ai32;
|
||||
x = toI32Any(x); i32* xp = i32any_ptr(x);
|
||||
rep = toI32Any(rep); i32* np = i32any_ptr(rep);
|
||||
for (usz i = 0; i < ia; i++) {
|
||||
bool v = bitp_get(d, i);
|
||||
i32 nc = np[repI];
|
||||
i32 xc = xp[i];
|
||||
rp[i] = v? nc : xc;
|
||||
repI+= v;
|
||||
}
|
||||
} else {
|
||||
MUTG_INIT(r);
|
||||
for (usz i = 0; i < ia; i++) mut_setG(r, i, bitp_get(d, i)? Get(rep,repI++) : Get(x,i));
|
||||
}
|
||||
} else {
|
||||
SGetU(rep)
|
||||
MUTG_INIT(r);
|
||||
for (usz i = 0; i < ia; i++) {
|
||||
i32 cw = o2iG(GetU(w, i));
|
||||
if (cw) {
|
||||
B cr = Get(rep,repI);
|
||||
if (CHECK_VALID) for (i32 j = 1; j < cw; j++) if (!equal(GetU(rep,repI+j), cr)) { mut_pfree(r,i); thrM("𝔽⌾(a⊸/): Incompatible result elements"); }
|
||||
mut_setG(r, i, cr);
|
||||
repI+= cw;
|
||||
} else mut_setG(r, i, Get(x,i));
|
||||
}
|
||||
}
|
||||
decG(w); decG(rep);
|
||||
return mut_fcd(r, x);
|
||||
}
|
||||
|
||||
void slash_init() {
|
||||
c(BFn,bi_slash)->im = slash_im;
|
||||
}
|
||||
c(BFn,bi_slash)->ucw = slash_ucw;
|
||||
}
|
||||
|
||||
@ -54,4 +54,17 @@ extern u8 elType2type[];
|
||||
extern u8 elTypeWidth[];
|
||||
#define elWidth(X) elTypeWidth[X]
|
||||
extern u8 arrTypeWidthLog[];
|
||||
#define arrTypeWidthLog(X) arrTypeWidthLog[X]
|
||||
#define arrTypeWidthLog(X) arrTypeWidthLog[X]
|
||||
extern u8 arrTypeBitsLog[];
|
||||
#define arrTypeBitsLog(X) arrTypeBitsLog[X]
|
||||
#define arrNewType(X) el2t(TIi(X,elType))
|
||||
|
||||
// Log of width in bits: max of 7, and also return 7 if not power of 2
|
||||
static u8 cellWidthLog(B x) {
|
||||
assert(isArr(x) && RNK(x)>=1);
|
||||
u8 lw = arrTypeBitsLog(TY(x));
|
||||
if (LIKELY(RNK(x)==1)) return lw;
|
||||
usz csz = arr_csz(x);
|
||||
if (csz & (csz-1)) return 7; // Not power of 2
|
||||
return lw + CTZ(csz | 128>>lw); // Max of 7; also handle csz==0
|
||||
}
|
||||
|
||||
@ -88,40 +88,5 @@ static B toF64Any(B x) { u8 t=TY(x); return t==t_f64arr || t==t_f64slice? x : ta
|
||||
B m_cai32(usz ia, i32* a);
|
||||
B m_caf64(usz sz, f64* a);
|
||||
|
||||
static i64 bit_sum(u64* x, u64 am) {
|
||||
i64 r = 0;
|
||||
for (u64 i = 0; i < (am>>6); i++) r+= POPC(x[i]);
|
||||
if (am&63) r+= POPC(x[am>>6]<<(64-am & 63));
|
||||
return r;
|
||||
}
|
||||
|
||||
static u64 usum(B x) { // doesn't consume; may error
|
||||
assert(isArr(x));
|
||||
u64 r = 0;
|
||||
usz xia = IA(x);
|
||||
u8 xe = TI(x,elType);
|
||||
if (xe==el_bit) return bit_sum(bitarr_ptr(x), xia);
|
||||
else if (xe==el_i8 ) { i8* p = i8any_ptr (x); for (usz i = 0; i < xia; i++) { if (RARE(p[i]<0)) goto neg; r+= p[i]; } }
|
||||
else if (xe==el_i16) { i16* p = i16any_ptr(x); for (usz i = 0; i < xia; i++) { if (RARE(p[i]<0)) goto neg; if (addOn(r,p[i])) goto overflow; } }
|
||||
else if (xe==el_i32) { i32* p = i32any_ptr(x); for (usz i = 0; i < xia; i++) { if (RARE(p[i]<0)) goto neg; if (addOn(r,p[i])) goto overflow; } }
|
||||
else if (xe==el_f64) {
|
||||
f64* p = f64any_ptr(x);
|
||||
for (usz i = 0; i < xia; i++) {
|
||||
f64 c = p[i];
|
||||
u64 ci = (u64)c;
|
||||
if (c!=ci) thrM("Expected integer");
|
||||
if (ci<0) goto neg;
|
||||
if (addOn(r,ci)) goto overflow;
|
||||
}
|
||||
} else {
|
||||
SGetU(x)
|
||||
for (usz i = 0; i < xia; i++) {
|
||||
u64 c = o2u64(GetU(x,i));
|
||||
if (c<0) thrM("Didn't expect negative integer");
|
||||
if (addOn(r,c)) goto overflow;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
overflow: thrM("Sum too big");
|
||||
neg: thrM("Didn't expect negative integer");
|
||||
}
|
||||
i64 bit_sum(u64* x, u64 am);
|
||||
u64 usum(B x); // doesn't consume; error if not natural numbers or overflow
|
||||
|
||||
@ -565,6 +565,44 @@ bool eequal(B w, B x) { // doesn't consume
|
||||
return true;
|
||||
}
|
||||
|
||||
i64 bit_sum(u64* x, u64 am) {
|
||||
i64 r = 0;
|
||||
for (u64 i = 0; i < (am>>6); i++) r+= POPC(x[i]);
|
||||
if (am&63) r+= POPC(x[am>>6]<<(64-am & 63));
|
||||
return r;
|
||||
}
|
||||
|
||||
u64 usum(B x) { // doesn't consume; may error
|
||||
assert(isArr(x));
|
||||
u64 r = 0;
|
||||
usz xia = IA(x);
|
||||
u8 xe = TI(x,elType);
|
||||
if (xe==el_bit) return bit_sum(bitarr_ptr(x), xia);
|
||||
else if (xe==el_i8 ) { i8* p = i8any_ptr (x); i8 m=0; for (usz i = 0; i < xia; ) { usz b=1<< 8; i16 s=0; for (usz e = xia-i<b?xia:i+b; i < e; i++) { m|=p[i]; s+=p[i]; } if (m<0) goto neg; if (addOn(r,(u16)s)) goto overflow; } }
|
||||
else if (xe==el_i16) { i16* p = i16any_ptr(x); i16 m=0; for (usz i = 0; i < xia; ) { usz b=1<<16; i32 s=0; for (usz e = xia-i<b?xia:i+b; i < e; i++) { m|=p[i]; s+=p[i]; } if (m<0) goto neg; if (addOn(r,(u32)s)) goto overflow; } }
|
||||
else if (xe==el_i32) { i32* p = i32any_ptr(x); i32 m=0; for (usz i = 0; i < xia; i++) { m|=p[i]; if (addOn(r,p[i])) goto overflow; } if (m<0) goto neg; }
|
||||
else if (xe==el_f64) {
|
||||
f64* p = f64any_ptr(x);
|
||||
for (usz i = 0; i < xia; i++) {
|
||||
f64 c = p[i];
|
||||
u64 ci = (u64)c;
|
||||
if (c!=ci) thrM("Expected integer");
|
||||
if (ci<0) goto neg;
|
||||
if (addOn(r,ci)) goto overflow;
|
||||
}
|
||||
} else {
|
||||
SGetU(x)
|
||||
for (usz i = 0; i < xia; i++) {
|
||||
u64 c = o2u64(GetU(x,i));
|
||||
if (c<0) thrM("Didn't expect negative integer");
|
||||
if (addOn(r,c)) goto overflow;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
overflow: thrM("Sum too big");
|
||||
neg: thrM("Didn't expect negative integer");
|
||||
}
|
||||
|
||||
usz depthF(B x) { // doesn't consume
|
||||
u64 r = 0;
|
||||
usz ia = IA(x);
|
||||
|
||||
@ -20,6 +20,14 @@ u8 arrTypeWidthLog[] = {
|
||||
[t_i32arr]=2, [t_i32slice]=2, [t_c32arr]=2, [t_c32slice]=2,
|
||||
[t_f64arr]=3, [t_f64slice]=3
|
||||
};
|
||||
u8 arrTypeBitsLog[] = {
|
||||
[t_bitarr]=0,
|
||||
[t_i8arr ]=3, [t_i8slice ]=3, [t_c8arr ]=3, [t_c8slice ]=3,
|
||||
[t_i16arr]=4, [t_i16slice]=4, [t_c16arr]=4, [t_c16slice]=4,
|
||||
[t_i32arr]=5, [t_i32slice]=5, [t_c32arr]=5, [t_c32slice]=5,
|
||||
[t_f64arr]=6, [t_f64slice]=6,
|
||||
[t_harr ]=6, [t_hslice ]=6, [t_fillarr]=6,[t_fillslice]=6
|
||||
};
|
||||
|
||||
B m_i8(i8 x) { return m_i32(x); } B m_i16(i16 x) { return m_i32(x); }
|
||||
B m_c8(u8 x) { return m_c32(x); } B m_c16(u16 x) { return m_c32(x); }
|
||||
@ -87,4 +95,4 @@ void tyarr_init() {
|
||||
Arr* emptySVec = arr_shVec(m_fillarrp(0));
|
||||
fillarr_setFill(emptySVec, emptyCVec());
|
||||
bi_emptySVec = taga(emptySVec); gc_add(bi_emptySVec);
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
#include "../builtins/sfns.c"
|
||||
#include "../builtins/select.c"
|
||||
#include "../builtins/slash.c"
|
||||
#include "../builtins/group.c"
|
||||
#include "../builtins/sysfn.c"
|
||||
#include "../builtins/sort.c"
|
||||
#include "../builtins/selfsearch.c"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user