Merge pull request #114 from mlochbaum/simplify

Miscellaneous strength reductions
This commit is contained in:
dzaima 2024-07-08 04:23:42 +03:00 committed by GitHub
commit c466db24bc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 384 additions and 130 deletions

View File

@ -7,10 +7,18 @@
B fne_c1(B, B);
B shape_c2(B, B, B);
B transp_c2(B, B, B);
B fold_rows(Md1D* d, B x); // from fold.c
B fold_rows_bit(Md1D* d, B x, usz n, usz m); // from fold.c
B take_c2(B, B, B);
B join_c2(B, B, B);
// from fold.c:
B fold_rows(Md1D* d, B x, usz n, usz m);
B fold_rows_bit(Md1D* d, B x, usz n, usz m);
B insert_cells_join(B x, usz* xsh, ur cr, ur k);
B insert_cells_identity(B x, B f, usz* xsh, ur xr, ur k, u8 rtid);
B scan_rows_bit(u8, B x, usz m); // from scan.c
B takedrop_highrank(bool take, B w, B x); // from sfns.c
B rotate_highrank(bool inv, B w, B x); // from sfns.c
B try_interleave_cells(B w, B x, ur xr, ur xk, usz* xsh); // from transpose.c
// X - variable name; XSH - its shape; K - number of leading axes that get iterated over; SLN - number of slices that will be made; DX - additional refcount count to add to x
@ -165,7 +173,7 @@ NOINLINE B leading_axis_arith(FC2 fc2, B w, B x, usz* wsh, usz* xsh, ur mr) { //
if (mr==wr) w=s; else x=s;
return fc2(m_f64(0), w, x);
} else {
M_APD_SH(r, mr, bsh);
M_APD_SH_N(r, mr, bsh, cam);
S_KSLICES(b, bsh, mr, cam, 1) usz bp=0;
if (mr==wr) { SGetU(w); for (usz i=0; i<cam; i++) APDD(r, fc2(m_f64(0), GetU(w,i), SLICEI(b))); }
else { SGetU(x); for (usz i=0; i<cam; i++) APDD(r, fc2(m_f64(0), SLICEI(b), GetU(x,i))); }
@ -178,52 +186,58 @@ NOINLINE B leading_axis_arith(FC2 fc2, B w, B x, usz* wsh, usz* xsh, ur mr) { //
// fast special-case implementations
extern void (*const si_select_cells_bit_lt64)(uint64_t*,uint64_t*,uint32_t,uint32_t,uint32_t); // from fold.c (fold.singeli)
static NOINLINE B select_cells(usz n, B x, usz cam, usz k, bool leaf) { // n {leaf? <∘⊑; ⊏}⎉¯k x; TODO probably can share some parts with takedrop_highrank and/or call ⊏?
static NOINLINE B select_cells(usz ind, B x, usz cam, usz k, bool leaf) { // ind {leaf? <∘⊑; ⊏}⎉¯k x; TODO probably can share some parts with takedrop_highrank and/or call ⊏?
ur xr = RNK(x);
assert(xr>1 && k<xr);
usz* xsh = SH(x);
usz csz = shProd(xsh, k+1, xr);
usz take = leaf? 1 : csz;
usz jump = xsh[k] * csz;
assert(cam*jump == IA(x));
usz l = xsh[k];
assert(0<=ind && ind<l);
assert(cam*l*csz == IA(x));
Arr* ra;
if (take==jump) {
usz take = leaf? 1 : csz;
if (l==1 && take==csz) {
ra = cpyWithShape(incG(x));
arr_shErase(ra, 1);
} else if (take==1) {
} else {
u8 xe = TI(x,elType);
if (xe==el_B) {
u8 ewl= elwBitLog(xe);
u8 xl = leaf? ewl : multWidthLog(csz, ewl);
usz ria = cam*take;
if (xl>=7 || (xl<3 && xl>0)) { // generic case
MAKE_MUT_INIT(rm, ria, TI(x,elType)); MUTG_INIT(rm);
usz jump = l * csz;
usz xi = take*ind;
usz ri = 0;
for (usz i = 0; i < cam; i++) {
mut_copyG(rm, ri, x, xi, take);
xi+= jump;
ri+= take;
}
ra = mut_fp(rm);
} else if (xe==el_B) {
assert(take == 1);
SGet(x)
HArr_p rp = m_harrUv(cam);
for (usz i = 0; i < cam; i++) rp.a[i] = Get(x, i*jump+n);
HArr_p rp = m_harrUv(ria);
for (usz i = 0; i < cam; i++) rp.a[i] = Get(x, i*l+ind);
NOGC_E; ra = (Arr*)rp.c;
} else {
void* rp = m_tyarrlbp(&ra, elwBitLog(xe), cam, el2t(xe));
void* rp = m_tyarrlbp(&ra, ewl, ria, el2t(xe));
void* xp = tyany_ptr(x);
switch(xe) {
case el_bit:
switch(xl) {
case 0:
#if SINGELI
if (jump < 64) si_select_cells_bit_lt64(xp, rp, cam, jump, n);
if (l < 64) si_select_cells_bit_lt64(xp, rp, cam, l, ind);
else
#endif
for (usz i=0; i<cam; i++) bitp_set(rp, i, bitp_get(xp, i*jump+n));
for (usz i=0; i<cam; i++) bitp_set(rp, i, bitp_get(xp, i*l+ind));
break;
case el_i8: case el_c8: PLAINLOOP for (usz i=0; i<cam; i++) ((u8* )rp)[i] = ((u8* )xp)[i*jump+n]; break;
case el_i16: case el_c16: PLAINLOOP for (usz i=0; i<cam; i++) ((u16*)rp)[i] = ((u16*)xp)[i*jump+n]; break;
case el_i32: case el_c32: PLAINLOOP for (usz i=0; i<cam; i++) ((u32*)rp)[i] = ((u32*)xp)[i*jump+n]; break;
case el_f64: PLAINLOOP for (usz i=0; i<cam; i++) ((f64*)rp)[i] = ((f64*)xp)[i*jump+n]; break;
case 3: PLAINLOOP for (usz i=0; i<cam; i++) ((u8* )rp)[i] = ((u8* )xp)[i*l+ind]; break;
case 4: PLAINLOOP for (usz i=0; i<cam; i++) ((u16*)rp)[i] = ((u16*)xp)[i*l+ind]; break;
case 5: PLAINLOOP for (usz i=0; i<cam; i++) ((u32*)rp)[i] = ((u32*)xp)[i*l+ind]; break;
case 6: PLAINLOOP for (usz i=0; i<cam; i++) ((f64*)rp)[i] = ((f64*)xp)[i*l+ind]; break;
}
}
} else {
MAKE_MUT_INIT(rm, cam*take, TI(x,elType)); MUTG_INIT(rm);
usz xi = take*n;
usz ri = 0;
for (usz i = 0; i < cam; i++) {
mut_copyG(rm, ri, x, xi, take);
xi+= jump;
ri+= take;
}
ra = mut_fp(rm);
}
usz* rsh = arr_shAlloc(ra, leaf? k : xr-1);
if (rsh) {
@ -444,8 +458,12 @@ B for_cells_c1(B f, u32 xr, u32 cr, u32 k, B x, u32 chr) { // F⎉cr x, with arr
return taga(arr_shReplace(r, k+1, rsh));
}
case n_shifta: case n_shiftb: {
if (IA(x)==0) goto noSpecial;
if (cr!=1) goto base;
if (IA(x)==0) return x;
if (cr!=1) {
if (cr==0) goto base;
if (!(xsh[k]==1 // handled by fill case
|| shProd(xsh, k+1, xr)==1)) goto base;
}
B xf = getFillR(x);
if (noFill(xf)) goto base;
return shift_cells(xf, x, cam, xsh[k], TI(x,elType), rtid);
@ -453,47 +471,74 @@ B for_cells_c1(B f, u32 xr, u32 cr, u32 k, B x, u32 chr) { // F⎉cr x, with arr
case n_transp: {
return cr<=1? x : transp_cells(xr-1, k, x);
}
// trivial cases for unhandled functions
case n_reverse: case n_and: case n_or: case n_find:
if (cr == 0) break;
if (xsh[k] <= 1) return x;
break;
case n_gradeUp: case n_gradeDown: case n_indexOf: case n_memberOf: case n_count: {
if (cr == 0) break;
usz l = xsh[k];
if (l <= 1) {
usz ia = l*cam;
Arr* r = rtid==n_memberOf? allOnes(ia) : allZeroes(ia);
usz* rsh = arr_shAlloc(r, k+1);
shcpy(rsh, xsh, k+1);
decG(x); return taga(r);
}
break;
}
}
if (TY(f) == t_md1D) {
Md1D* fd = c(Md1D,f);
u8 rtid = fd->m1->flags-1;
if (rtid==n_const) { f=fd->f; goto const_f; }
usz *sh = SH(x);
if (((rtid==n_fold && cr==1) || rtid==n_insert) && TI(x,elType)!=el_B
&& isFun(fd->f) && 1==shProd(sh, k+1, xr) && sh[k] > 0) {
usz m = sh[k];
u8 frtid = v(fd->f)->flags-1;
if (m==1 || frtid==n_ltack) return select_cells(0 , x, cam, k, false);
if ( frtid==n_rtack) return select_cells(m-1, x, cam, k, false);
if (isPervasiveDyExt(fd->f)) {
if (TI(x,elType)==el_bit) {
incG(x); // keep shape alive
B r = fold_rows_bit(fd, x, shProd(sh, 0, k), m);
if (!q_N(r)) {
if (xr > 2) {
usz* rsh = arr_shAlloc(a(r), xr-1);
shcpy(rsh, sh, k);
shcpy(rsh+k, sh+k+1, xr-1-k);
}
decG(x); return r;
switch(rtid) {
case n_const: f=fd->f; goto const_f;
case n_cell: cr-= cr>0; return for_cells_c1(fd->f, xr, cr, xr-cr, x, U'˘');
case n_fold: if (cr != 1) break; // else fall through
case n_insert: if (cr>0 && isFun(fd->f)) {
u8 frtid = v(fd->f)->flags-1;
if (frtid==n_join && rtid==n_insert) return insert_cells_join(x, xsh, cr, k);
usz m = xsh[k];
if (m==0) return insert_cells_identity(x, fd->f, xsh, xr, k, rtid);
if (TI(x,elType)==el_B) break;
if (m==1 || frtid==n_ltack) return select_cells(0 , x, cam, k, false);
if ( frtid==n_rtack) return select_cells(m-1, x, cam, k, false);
if (isPervasiveDyExt(fd->f) && 1==shProd(xsh, k+1, xr)) {
B r;
// special cases always return rank 1
// incG(x) preserves the shape to restore afterwards if needed
if (TI(x,elType)==el_bit) {
incG(x); r = fold_rows_bit(fd, x, cam, m);
if (q_N(r)) decG(x); // will try fold_rows
else goto finish_fold;
}
decG(x);
if (m<=64 && m<cam) {
incG(x); r = fold_rows (fd, x, cam, m);
}
else break;
finish_fold:
if (xr > 2) {
usz* rsh = arr_shAlloc(a(r), xr-1);
shcpy(rsh, xsh, k);
shcpy(rsh+k, xsh+k+1, xr-1-k);
}
decG(x); return r;
}
// TODO extend to any rank
if (xr==2 && k==1 && m<=64 && m<sh[0]) return fold_rows(fd, x);
}
}
if (rtid==n_scan) {
if (cr==0) goto noSpecial;
usz *sh = SH(x); usz m = sh[k];
if (m<=1 || IA(x)==0) return x;
if (!isFun(fd->f)) goto base;
u8 frtid = v(fd->f)->flags-1;
if (frtid==n_rtack) return x;
if (TI(x,elType)==el_bit && (isPervasiveDyExt(fd->f)||frtid==n_ltack)
&& 1==shProd(sh, k+1, xr)) {
B r = scan_rows_bit(frtid, x, m); if (!q_N(r)) return r;
} break;
case n_scan: {
if (cr==0) break;
usz m = xsh[k];
if (m<=1 || IA(x)==0) return x;
if (!isFun(fd->f)) break;
u8 frtid = v(fd->f)->flags-1;
if (frtid==n_rtack) return x;
if (TI(x,elType)==el_bit && (isPervasiveDyExt(fd->f)||frtid==n_ltack)
&& 1==shProd(xsh, k+1, xr)) {
B r = scan_rows_bit(frtid, x, m); if (!q_N(r)) return r;
}
break;
}
}
} else if (TY(f) == t_md2D) {
@ -531,7 +576,7 @@ B for_cells_c1(B f, u32 xr, u32 cr, u32 k, B x, u32 chr) { // F⎉cr x, with arr
base:;
M_APD_SH(r, k, xsh);
M_APD_SH_N(r, k, xsh, cam);
S_KSLICES(x, xsh, k, cam, 1); FC1 fc1 = c1fn(f);
for (usz i=0,xp=0; i<cam; i++) APDD(r, fc1(f, SLICEI(x)));
decG(x);
@ -608,7 +653,7 @@ NOINLINE B for_cells_AS(B f, B w, B x, ur wcr, ur wr, u32 chr) {
}
generic:;
S_KSLICES(w, wsh, wk, cam, 1) incBy(x, cam-1);
M_APD_SH(r, wk, wsh); FC2 fc2 = c2fn(f);
M_APD_SH_N(r, wk, wsh, cam); FC2 fc2 = c2fn(f);
for (usz i=0,wp=0; i<cam; i++) APDD(r, fc2(f, SLICEI(w), x));
decG(w); return taga(APD_SH_GET(r, chr));
}
@ -618,40 +663,79 @@ NOINLINE B for_cells_SA(B f, B w, B x, ur xcr, ur xr, u32 chr) {
usz* xsh=SH(x); usz cam=shProd(xsh,0,xk);
if (cam==0) return rank2_empty(f, w, 0, x, xk, chr);
if (isFun(f)) {
if (IA(x)==0) goto generic;
u8 rtid = v(f)->flags-1;
if (rtid==n_rtack) { dec(w); return x; }
if (rtid==n_ltack) return const_cells(x, xk, xsh, w, chr);
if (rtid==n_select && xk==1 && isF64(w) && xr==2) return select_cells(WRAP(o2i64(w), SH(x)[1], thrF("⊏: Indexing out-of-bounds (𝕨≡%R, %s≡≠𝕩)", w, cam)), x, cam, 1, false);
if (rtid==n_pick && xk==1 && TI(x,arrD1) && xr==2 && isF64(w)) return select_cells(WRAP(o2i64(w), SH(x)[1], thrF("⊑: Indexing out-of-bounds (𝕨≡%R, %s≡≠𝕩)", w, cam)), x, cam, 1, true);
if ((rtid==n_shifta || rtid==n_shiftb) && xk==1 && xr==2 && isAtm(w)) {
if (isArr(w)) { B w0=w; w = IGet(w,0); decG(w0); }
return shift_cells(w, x, SH(x)[0], SH(x)[1], el_or(TI(x,elType), selfElType(w)), rtid);
}
if (rtid==n_take || rtid==n_drop) {
if (xcr==0 || !isF64(w)) goto generic;
bool take = rtid==n_take;
f64* ap;
B a = m_f64arrv(&ap, xk+1);
if (!take) { FILL_TO(ap, el_f64, 0, m_f64(0), xk); }
else { usz* xsh=SH(x); PLAINLOOP for (usz i=0; i<xk; i++) ap[i] = xsh[i]; }
ap[xk] = o2fG(w);
return takedrop_highrank(take, a, x);
}
if (rtid==n_transp && q_usz(w)) { usz a=o2sG(w); if (a<xcr) return transp_cells(a+xk, xk, x); }
if (isPervasiveDy(f)) {
if (isAtm(w)) return c2(f, w, x);
if (RNK(w)!=xcr || !eqShPart(SH(w), xsh+xk, xcr)) goto generic;
if (TI(w,elType)==el_B || TI(x,elType)==el_B || (IA(w)>(2048*8)>>arrTypeBitsLog(TY(w)) && IA(w)!=IA(x))) goto generic;
return c2(f, C2(shape, C1(fne, incG(x)), w), x);
switch(rtid) {
case n_rtack: dec(w); return x;
case n_ltack: return const_cells(x, xk, xsh, w, chr);
case n_select: if (isF64(w) && xcr>=1) {
usz l = xsh[xk];
return select_cells(WRAP(o2i64(w), l, thrF("⊏: Indexing out-of-bounds (𝕨≡%R, %s≡≠𝕩)", w, l)), x, cam, xk, false);
} break;
case n_pick: if (isF64(w) && xcr==1 && TI(x,arrD1)) {
usz l = xsh[xk];
return select_cells(WRAP(o2i64(w), l, thrF("⊑: Indexing out-of-bounds (𝕨≡%R, %s≡≠𝕩)", w, l)), x, cam, xk, true);
} break;
case n_shifta: case n_shiftb: if (isAtm(w)) {
if (IA(x)==0) return x;
if (xcr!=1) {
if (xcr==0) break;
if (!(xsh[xk]==1 || shProd(xsh, xk+1, xr)==1)) break;
}
if (isArr(w)) { B w0=w; w = IGet(w,0); decG(w0); }
return shift_cells(w, x, cam, xsh[xk], el_or(TI(x,elType), selfElType(w)), rtid);
} break;
case n_take: case n_drop: {
bool take = rtid==n_take;
B a;
if (isF64(w)) {
if (xcr < 1) break;
f64* ap;
a = m_f64arrv(&ap, xk+1);
if (!take) { FILL_TO(ap, el_f64, 0, m_f64(0), xk); }
else { PLAINLOOP for (usz i=0; i<xk; i++) ap[i] = xsh[i]; }
ap[xk] = o2fG(w);
} else {
if (!isArr(w) || RNK(w)>1) break;
usz wia = IA(w);
if (xcr < wia) break; // needs rank extension in the middle of x's shape
if (!take) a = C2(take, m_f64(-(i32)(xk+wia)), w);
else a = C2(join, C2(take, m_f64(xk), C1(fne, incG(x))), w); // (k↑≢𝕩)∾𝕨
}
return takedrop_highrank(take, a, x);
} break;
case n_reverse: {
B a;
if (isF64(w)) {
if (xcr < 1) break;
f64* ap;
a = m_f64arrv(&ap, xk+1);
FILL_TO(ap, el_f64, 0, m_f64(0), xk);
ap[xk] = o2fG(w);
} else {
if (!isArr(w) || RNK(w)>1) break;
usz wia = IA(w);
if (xcr < wia) break;
a = C2(take, m_f64(-(i32)(xk+wia)), w);
}
return rotate_highrank(0, a, x);
}
case n_transp:
if (q_usz(w)) { usz a=o2sG(w); if (a<xcr) return transp_cells(a+xk, xk, x); }
break;
default: if (isPervasiveDy(f)) {
if (isAtm(w)) return c2(f, w, x);
if (IA(x)==0) break;
if (RNK(w)!=xcr || !eqShPart(SH(w), xsh+xk, xcr)) break;
if (TI(w,elType)==el_B || TI(x,elType)==el_B || (IA(w)>(2048*8)>>arrTypeBitsLog(TY(w)) && IA(w)!=IA(x))) break;
return c2(f, C2(shape, C1(fne, incG(x)), w), x);
}
}
} else if (!isMd(f)) {
dec(w);
return const_cells(x, xk, xsh, inc(f), chr);
}
generic:;
S_KSLICES(x, xsh, xk, cam, 1) incBy(w, cam-1);
M_APD_SH(r, xk, xsh); FC2 fc2 = c2fn(f);
M_APD_SH_N(r, xk, xsh, cam); FC2 fc2 = c2fn(f);
for (usz i=0,xp=0; i<cam; i++) APDD(r, fc2(f, w, SLICEI(x)));
decG(x); return taga(APD_SH_GET(r, chr));
}
@ -705,7 +789,7 @@ NOINLINE B for_cells_AA(B f, B w, B x, ur wcr, ur xcr, u32 chr) {
}
generic:;
M_APD_SH(r, zk, zsh);
M_APD_SH_N(r, zk, zsh, cam);
S_KSLICES(w, wsh, wk, xkM? cam0 : cam, 1) usz wp=0;
S_KSLICES(x, xsh, xk, xkM? cam : cam0, 1) usz xp=0;
FC2 fc2 = c2fn(f);

View File

@ -14,7 +14,8 @@
// Insert with rank (˝˘ or ˝⎉k), or fold on flat array
// SHOULD optimize dyadic insert with rank
// Length 1, ⊣⊢: implemented as ⊏˘
// SHOULD reshape identity for fast ˝˘ on empty rows
// ∾˝ with rank: reshape argument
// Arithmetic on empty: reshape identity
// Boolean operand, cell size 1:
// +: popcount
// Rows length ≤64: extract rows, popcount each
@ -375,28 +376,58 @@ u64 usum(B x) { // doesn't consume; will error on non-integers, or elements <0,
B select_c1(B, B);
B select_c2(B, B, B);
B shape_c1(B, B);
static B m1c1(B t, B f, B x) { // consumes x
B fn = m1_d(inc(t), inc(f));
B r = c1(fn, x);
decG(fn);
return r;
}
extern GLOBAL B rt_insert;
extern B insert_base(B f, B x, bool has_w, B w); // from cells.c
B insert_c1(Md1D* d, B x) { B f = d->f;
if (isAtm(x) || RNK(x)==0) thrM("˝: 𝕩 must have rank at least 1");
ur xr;
if (isAtm(x) || (xr=RNK(x))==0) thrM("˝: 𝕩 must have rank at least 1");
usz len = *SH(x);
if (len==0) { SLOW2("!𝕎˝𝕩", f, x); return m1c1(rt_insert, f, x); }
if (len==0) {
if (isFun(f)) {
B id = TI(f,identity)(f);
if (!q_N(id)) {
if (isArr(id)) { decG(x); return id; } // arithmetic with table
usz* xsh = SH(x);
Arr* r = reshape_one(shProd(xsh, 1, xr), id);
if (xr == 2) arr_shVec(r); else {
usz* rsh = arr_shAlloc(r, xr-1);
shcpy(rsh, xsh+1, xr-1);
}
decG(x); return taga(r);
} else if (v(f)->flags == n_join+1) {
if (xr <= 1) thrM("˝: Identity does not exist");
goto join;
}
}
thrM("˝: Identity not found");
}
if (len==1) return C1(select, x);
if (RARE(!isFun(f))) { decG(x); if (isMd(f)) thrM("Calling a modifier"); return inc(f); }
ur xr = RNK(x);
if (xr==1 && isPervasiveDyExt(f)) return m_unit(fold_c1(d, x));
if (isPervasiveDyExt(f)) {
if (xr==1) return m_unit(fold_c1(d, x));
if (len==IA(x)) {
B r = m_vec1(fold_c1(d, C1(shape, x)));
ur rr = xr - 1;
if (rr > 1) {
ShArr* rsh = m_shArr(rr);
PLAINLOOP for (ur i=0; i<rr; i++) rsh->a[i] = 1;
arr_shReplace(a(r), rr, rsh);
}
return r;
}
}
if (v(f)->flags) {
u8 rtid = v(f)->flags-1;
if (rtid==n_ltack) return C1(select, x);
if (rtid==n_rtack) return C2(select, m_f64(-1), x);
if (rtid==n_join) {
if (rtid==n_join) { join:;
if (xr==1) return x;
ShArr* rsh;
if (xr>2) {
@ -414,17 +445,32 @@ B insert_c1(Md1D* d, B x) { B f = d->f;
return insert_base(f, x, 0, m_f64(0));
}
B insert_c2(Md1D* d, B w, B x) { B f = d->f;
if (isAtm(x) || RNK(x)==0) thrM("˝: 𝕩 must have rank at least 1");
if (*SH(x)==0) { decG(x); return w; }
ur xr;
if (isAtm(x) || (xr=RNK(x))==0) thrM("˝: 𝕩 must have rank at least 1");
usz len = *SH(x);
if (len==0) { decG(x); return w; }
if (RARE(!isFun(f))) { dec(w); decG(x); if (isMd(f)) thrM("Calling a modifier"); return inc(f); }
if (RNK(x)==1 && isPervasiveDyExt(f)) {
if (isAtm(w)) {
to_fold: return m_unit(fold_c2(d, w, x));
}
if (RNK(w)==0) {
if (isPervasiveDyExt(f) && len==IA(x)) {
// 1-element arrays are always conformable
// final rank is higher of w, cell rank of x
ur rr = xr - 1;
if (isArr(w)) {
if (IA(w) != 1) goto skip;
ur wr = RNK(w); if (wr>rr) rr = wr;
B w0=w; w = IGet(w,0); decG(w0);
goto to_fold;
}
if (xr > 1) x = C1(shape, x);
B r = m_unit(fold_c2(d, w, x));
if (rr > 0) {
if (rr == 1) arr_shVec(a(r));
else {
ShArr* rsh = m_shArr(rr);
PLAINLOOP for (ur i=0; i<rr; i++) rsh->a[i] = 1;
arr_shReplace(a(r), rr, rsh);
}
}
return r;
skip:;
}
if (v(f)->flags) {
u8 rtid = v(f)->flags-1;
@ -434,19 +480,56 @@ B insert_c2(Md1D* d, B w, B x) { B f = d->f;
return insert_base(f, x, 1, w);
}
// Arithmetic fold/insert on rows of flat rank-2 array x
B insert_cells_join(B x, usz* xsh, ur cr, ur k) {
assert(k > 0);
if (cr <= 1) {
if (xsh[k]==0) thrM("˝: Identity does not exist");
return x;
}
ur rr = k+cr-1; // result rank (>1)
ShArr* rsh;
rsh = m_shArr(rr);
shcpy(rsh->a, xsh, k);
rsh->a[k] = xsh[k] * xsh[k+1];
shcpy(rsh->a+k+1, xsh+k+2, cr-2);
Arr* r = TI(x,slice)(x, 0, IA(x));
arr_shSetUG(r, rr, rsh);
decG(x); return taga(r);
}
B insert_cells_identity(B x, B f, usz* xsh, ur xr, ur k, u8 rtid) {
B id;
if (!isFun(f) || q_N(id = TI(f,identity)(f))) thrF("%c: Identity not found", rtid==n_fold? U'´' : U'˝');
bool cs = !isArr(id); // if x cell shape is used (not table)
usz ria = shProd(xsh, 0, k);
if (cs) ria*= shProd(xsh, k+1, xr);
Arr* r = reshape_one(ria, id);
ur rr = cs? xr-1 : k;
if (rr == 1) arr_shVec(r); else {
usz* rsh = arr_shAlloc(r, rr);
shcpy(rsh, xsh, k);
if (cs) shcpy(rsh+k, xsh+k+1, rr-k);
}
decG(x); return taga(r);
}
// Arithmetic fold/insert on -k-cells of flat array x
// Return a vector regardless of argument shape
B transp_c1(B, B);
B join_c2(B, B, B);
B fold_rows(Md1D* fd, B x) {
assert(isArr(x) && RNK(x)==2);
B fold_rows(Md1D* fd, B x, usz n, usz m) {
assert(isArr(x) && IA(x)==n*m);
// Target block size trying to avoid power-of-two lengths, from:
// {𝕩/˜⌊´⊸= +˝˘ +˝¬∨`2|>⌊∘÷⟜2⍟(↕12) ⌊0.5+32÷˜𝕩÷⌜1+↕64} +⟜↕2⋆16
u64 block = (116053*8) >> arrTypeBitsLog(TY(x));
if (TI(x,elType)==el_bit || IA(x)/2 <= block) {
if (RNK(x) > 2) {
Arr* xc = cpyWithShape(x);
ShArr* sh = m_shArr(2);
sh->a[0] = n; sh->a[1] = m;
x = taga(arr_shReplace(xc, 2, sh));
}
x = C1(transp, x);
return insert_c1(fd, x);
} else {
usz *sh = SH(x); usz n = sh[0]; usz m = sh[1];
usz b = (block + m - 1) / m; // Normal block length
usz b_max = b + b/4; // Last block max length
MAKE_MUT(r, n); MUT_APPEND_INIT(r);

View File

@ -998,7 +998,10 @@ B shiftb_c1(B t, B x) {
if (ia==0) return x;
B xf = getFillE(x);
usz csz = arr_csz(x);
if (ia==csz) { // length 1
Arr* r = arr_shCopy(reshape_one(ia, xf), x);
decG(x); return taga(r);
}
MAKE_MUT_INIT(r, ia, el_or(TI(x,elType), selfElType(xf))); MUTG_INIT(r);
mut_copyG(r, csz, x, 0, ia-csz);
mut_fillG(r, 0, xf, csz);
@ -1025,6 +1028,10 @@ B shifta_c1(B t, B x) {
if (ia==0) return x;
B xf = getFillE(x);
usz csz = arr_csz(x);
if (ia==csz) { // length 1
Arr* r = arr_shCopy(reshape_one(ia, xf), x);
decG(x); return taga(r);
}
MAKE_MUT_INIT(r, ia, el_or(TI(x,elType), selfElType(xf))); MUTG_INIT(r);
mut_copyG(r, 0, x, csz, ia-csz);
mut_fillG(r, ia-csz, xf, csz);
@ -1059,7 +1066,7 @@ static u64 bit_reverse(u64 x) {
B reverse_c1(B t, B x) {
if (isAtm(x) || RNK(x)==0) thrM("⌽: Argument cannot be a unit");
usz n = *SH(x);
if (n==0) return x;
if (n<=1) return x;
u8 xl = cellWidthLog(x);
u8 xt = arrNewType(TY(x));
if (xl<=6 && (xl>=3 || xl==0)) {
@ -1115,7 +1122,7 @@ B reverse_c1(B t, B x) {
B reverse_c2(B t, B w, B x);
#define WRAP_ROT(V, L) ({ i64 v_ = (V); usz l_ = (L); if ((u64)v_ >= (u64)l_) { v_%= (i64)l_; if(v_<0) v_+= l_; } v_; })
static NOINLINE B rotate_highrank(bool inv, B w, B x) {
NOINLINE B rotate_highrank(bool inv, B w, B x) {
#define INV (inv? "⁼" : "")
if (RNK(w)>1) thrF("⌽%U: 𝕨 must have rank at most 1 (%H ≡ ≢𝕨)", INV, w);
B r;

View File

@ -73,11 +73,15 @@ SHOULD_INLINE void arr_check_size(u64 sz, u8 type, usz ia) {
#endif
}
// Log of width in bits: max of 7, and also return 7 if not power of 2
SHOULD_INLINE u8 cellWidthLog(B x) {
SHOULD_INLINE u8 multWidthLog(usz n, u8 lw) { // Of n elements, 1<<lw bit
if (n & (n-1)) return 7; // Not power of 2
return lw + CTZ(n | 128>>lw); // Max of 7; also handle n==0
}
SHOULD_INLINE u8 kCellWidthLog(B x, ur k) {
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
ur xr = RNK(x);
if (LIKELY(xr <= k)) return lw;
return multWidthLog(shProd(SH(x), k, xr), lw);
}
SHOULD_INLINE u8 cellWidthLog(B x) { return kCellWidthLog(x, 1); }

View File

@ -460,7 +460,7 @@ B bqn_merge(B x, u32 type) {
return taga(r);
}
M_APD_SH(r, xr, SH(x));
M_APD_SH_N(r, xr, SH(x), xia);
SGetU(x)
for (usz i = 0; i < xia; i++) APD(r, GetU(x, i));
decG(x);

View File

@ -129,7 +129,7 @@ NOINLINE B load_fullpath(B path, B name) {
GLOBAL HArr* comps_curr;
GLOBAL B rt_undo, rt_select, rt_slash, rt_insert, rt_depth,
GLOBAL B rt_undo, rt_select, rt_slash, rt_depth,
rt_group, rt_under, rt_find;
Block* load_buildBlock(B x, B src, B path, B name, Scope* sc, i32 nsResult) { // consumes x,src
B fullpath = load_fullpath(path, name);
@ -500,7 +500,6 @@ void load_init() { // very last init function
gc_add(rt_under = Get(rtObjRaw, n_under ));
gc_add(rt_find = Get(rtObjRaw, n_find ));
gc_add(rt_depth = Get(rtObjRaw, n_depth ));
gc_add(rt_insert = Get(rtObjRaw, n_insert));
for (usz i = 0; i < RT_LEN; i++) {
#ifdef RT_WRAP
@ -542,7 +541,7 @@ void load_init() { // very last init function
load_rt = frtObj;
rt_select = rt_slash = rt_group = rt_find = bi_invalidFn;
rt_undo = rt_insert = bi_invalidMd1;
rt_undo = bi_invalidMd1;
rt_under = rt_depth = bi_invalidMd2;
rt_invFnRegFn = rt_invFnSwapFn = invalidFn_c1;

View File

@ -665,6 +665,37 @@ NOINLINE void apd_sh_init(ApdMut* m, B x) {
else m->apd(m, x);
if (xe==el_B) NOGC_E;
}
// used if this is the only append: only need to add leading 1s to shape
NOINLINE void apd_reshape(ApdMut* m, B x) {
ur rr0 = m->rr0; // need to be read before union fields are written
for (ur i=0; i<rr0; i++) assert(m->rsh0[i] == 1);
inc(x);
if (isAtm(x)) x = m_unit(x);
if (rr0 > 0) {
ur xr = RNK(x);
if (rr0 + xr > UR_MAX) {
m->failEl = x;
m->end = apd_rnk_err;
return;
}
ur rr = rr0 + xr;
Arr* r = cpyWithShape(x);
if (rr <= 1) {
arr_shErase(r, rr);
} else {
usz* xsh = PSH(r);
ShArr* rsh = m_shArr(rr);
PLAINLOOP for (ur i=0; i<rr0; i++) rsh->a[i] = 1;
shcpy(rsh->a + rr0, xsh, xr);
arr_shReplace(r, rr, rsh);
}
x = taga(r);
}
m->obj = a(x);
m->end = apd_ret_end;
}
NOINLINE void apd_widen(ApdMut* m, B x, ApdFn* const* fns) {
u8 xe = isArr(x)? TI(x,elType) : selfElType(x);

View File

@ -265,7 +265,7 @@ struct ApdMut {
};
};
ApdFn apd_tot_init, apd_sh_init;
ApdFn apd_tot_init, apd_sh_init, apd_reshape;
#if DEBUG
ApdFn apd_dbg_apd;
ApdEnd apd_dbg_end;
@ -275,6 +275,7 @@ ApdFn apd_tot_init, apd_sh_init;
#endif
#define M_APD_TOT(M, IA) M_APD_BASE(M) M.apd = apd_tot_init; M.ia0 = (IA); // end gives uninitialized shape
#define M_APD_SH(M, RR, RSH) M_APD_BASE(M) M.apd = apd_sh_init; M.rsh0 = (RSH); M.rr0 = (RR); // end gives full shape; will error on invalid at the end; rsh must be alive until at least the first APD call
#define M_APD_SH_N(M, RR, RSH, N) M_APD_BASE(M) M.apd = N==1? apd_reshape : apd_sh_init; M.rsh0 = (RSH); M.rr0 = (RR); // same, with known number of appends
#define M_APD_SH1(M, RIA) usz M##_sh0 = (RIA); M_APD_SH(M, 1, &M##_sh0);
#define APD(M, A) M.apd(&M, A) // doesn't consume A
#define APDD(M, A) ({ B av_ = (A); M.apd(&M, av_); dec(av_); }) // consumes A

View File

@ -21,6 +21,51 @@
!"˘: Argument frames don't agree (⟨3⟩ ≡ ≢𝕨, ⟨2⟩ ≡ ≢𝕩, common frame of 1 axes)" % "abc" ˘ "ab"
! ´{𝕊: ! ({𝕨𝕩}´) (<•rand.Range "ab",12,,0,"") ˜ (4•rand.Range) 1, {}, 'a', <'a', <{}, "ab", 0, ""}¨10000
# error cases that could be affected by special code
!"∧: Argument cannot have rank 0" % ˘2
!": Argument cannot have rank 0" % ˘"a"
!"Expected non-negative integer, got ¯3" % 2¯3/1 620
!"/: Lengths of components of 𝕨 must match 𝕩 (3 ≠ 4)" % 123/˘4567
!"/: Simple 𝕨 must have rank 0 or 1 (2≡=𝕨)" % (2314) /˘ 2
!"𝕨/𝕩: Length of compound 𝕨 must be at most rank of 𝕩" % (<0)/˘(5)<"ab"
!"⊏: Indexing out-of-bounds (24∊𝕨, 4≡≠𝕩)" % 124144
!"⊏: Indexing out-of-bounds (4∊𝕨, 4≡≠𝕩)" % 1˜6424
!"𝕨⊏𝕩: 𝕨 must be an array of numbers or list of such arrays" % 0@¯11 520.5
!"Expected integer, got ¯5.25" % ¯5.25˘424
!"⊏: Indexing out-of-bounds (1∊𝕨, 1≡≠𝕩)" % 001 ˘(˘) 10000×3
!"⊏: 𝕩 cannot be a unit" % 0˘5<"a"
!"⊏: 𝕩 cannot be a unit" % (30)˘3
!"Expected integer, got 0.1" % 0.1˘3515
!"⊑: 𝕩 must be a list when 𝕨 is a number (3‿4 ≡ ≢𝕩)" % 5˘234
!">: Result rank too large (80 ≡ =𝕩, 205 ≡ =⊑𝕩)" % >80 (2001)<(2051)1
!"⎉: Result rank too large (195 ≡ =𝕩, 210 ≡ =𝔽v)" % >5 (2001)<(2051)1
!"∾: Lengths not matchable (⟨6⟩ ≡ ≢𝕨, 1‿1 ≡ ≢𝕩)" % ("abc""def")˘(3/)"a"
!"∾: Argument ranks must differ by 1 or less (0≡=𝕨, 2≡=𝕩)" % 1˘333
!"∾: Lengths not matchable (4‿2 ≡ ≢𝕨, 3‿3 ≡ ≢𝕩)" % (3424)˘3335
!"≍: 𝕨 and 𝕩 must have equal shapes (3‿4 ≡ ≢𝕨, 3‿3 ≡ ≢𝕩)" % (34)2 23318
!"≍: Result rank too large (255≡=𝕩)" % 0˜2551
!"shift: Lengths not matchable (⟨6⟩ ≡ ≢𝕨, 1‿1 ≡ ≢𝕩)" % ("abc""def")«˘(3/)"a"
!"shift: =𝕨 must be =𝕩 or ¯1+=𝕩 (0≡=𝕨, 2≡=𝕩)" % 1«˘222
!"»: Argument cannot be a scalar" % »0 2316
!"⌽: Argument cannot be a unit" % ˘10
!"Expected integer, got 1.5" % 1.5˘232
!"↑: 𝕨 must have rank at most 1 (1‿2 ≡ ≢𝕨)" % (12)˘232
!"↓: 𝕨 must have rank at most 1 (4‿2 ≡ ≢𝕨)" % (428)˘@
!"Integer out of range: 1e20" % 1e20˘31010
!"Expected number" % 34@˘34
!"Expected integer, got 0.5" % 0.5˘4312
!"↑: Argument must have rank at least 1" % ˘2
!"↓: Argument must have rank at least 1" % 0 210
!"⊐: 𝕩 cannot have rank 0" % ˘"abcd"
!"⊒: Argument cannot have rank 0" % ˘"abcd"
!"∊: Argument cannot have rank 0" % ˘"abcd"
!"⍋: 𝕨 must be sorted" % 021˘ 3412
!"`: Shape of 𝕨 must match the cell of 𝕩 (⟨2⟩ ≡ ≢𝕨, 2‿3 ≡ ≢𝕩)" % (221)+`˘2230.4
!"`: Shape of 𝕨 must match the cell of 𝕩 (⟨⟩ ≡ ≢𝕨, 3‿3 ≡ ≢𝕩)" % 2+`˘333
!"´: Argument must be a list (3‿3 ≡ ≢𝕩)" % +´˘23318
!"´: 𝕩 must be a list (3‿3 ≡ ≢𝕩)" % 1+´˘23318
!"˝: 𝕩 must have rank at least 1" % +˝˘˘1010100
%USE tcc 2, 20, ¯2, ¯20, 0 {𝕨 _tcc 𝕩 𝕨 _tcc 𝕩} <4, 5, 4520, 456120
%USE tcc <, , , {𝕎 _tcc 𝕩} <4, 5, 4520, 456120, 2345120
%USE tcc <, , {𝕎 _tcc 𝕩} <4, 5, 4520, 456120, 2345120