singeli num_squeeze
This commit is contained in:
parent
e31c574fd8
commit
75bfa5d905
2
makefile
2
makefile
@ -216,7 +216,7 @@ preSingeliBin:
|
||||
@${MAKE} i_singeli=0 singeli=0 force_build_dir=obj/presingeli f= lf= postmsg="singeli sources:" i_t=presingeli i_f='-O1 -DPRE_SINGELI' FFI=0 OUTPUT=obj/presingeli/BQN c
|
||||
|
||||
|
||||
build_singeli: ${addprefix src/singeli/gen/, cmp.c dyarith.c copy.c equal.c scan.c slash.c}
|
||||
build_singeli: ${addprefix src/singeli/gen/, cmp.c dyarith.c copy.c equal.c squeeze.c scan.c slash.c}
|
||||
@echo $(postmsg)
|
||||
src/singeli/gen/%.c: src/singeli/src/%.singeli preSingeliBin
|
||||
@echo $< | cut -c 17- | sed 's/^/ /'
|
||||
|
||||
@ -1,5 +1,14 @@
|
||||
#include "../core.h"
|
||||
|
||||
// #undef SINGELI
|
||||
|
||||
#if SINGELI
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#include "../singeli/gen/squeeze.c"
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
FORCE_INLINE B num_squeeze_choose(B x, u32 or) {
|
||||
if (or==0) goto r_bit;
|
||||
else if (or<=(u32)I8_MAX ) goto r_i8;
|
||||
@ -30,44 +39,61 @@ B num_squeeze(B x) {
|
||||
usz ia = a(x)->ia;
|
||||
u8 xe = TI(x,elType);
|
||||
|
||||
#if !SINGELI
|
||||
usz i = 0;
|
||||
#endif
|
||||
|
||||
u32 or = 0; // using bitwise or as an approximate ⌈´
|
||||
switch (xe) { default: UD;
|
||||
case el_bit: goto r_x;
|
||||
case el_i8: { i8* xp = i8any_ptr (x); for (; i < ia; i++) { i32 c = xp[i]; or|= (u8)c; } goto r_orI8; }
|
||||
case el_i16: { i16* xp = i16any_ptr(x); for (; i < ia; i++) { i32 c = xp[i]; or|= ((u32)c & ~1) ^ (u32)(c>>31); } goto r_or; }
|
||||
case el_i32: { i32* xp = i32any_ptr(x); for (; i < ia; i++) { i32 c = xp[i]; or|= ((u32)c & ~1) ^ (u32)(c>>31); } goto r_or; }
|
||||
case el_f64: {
|
||||
f64* xp = f64any_ptr(x);
|
||||
for (; i < ia; i++) {
|
||||
f64 cf = xp[i];
|
||||
i32 c = (i32)cf;
|
||||
if (c!=cf) goto r_x; // already f64
|
||||
or|= ((u32)c & ~1) ^ (u32)(c>>31);
|
||||
#if SINGELI
|
||||
case el_i8: { or = avx2_squeeze_i8 ((u8*)i8any_ptr (x), ia); goto r_orI8; }
|
||||
case el_i16: { or = avx2_squeeze_i16((u8*)i16any_ptr(x), ia); goto r_or; }
|
||||
case el_i32: { or = avx2_squeeze_i32((u8*)i32any_ptr(x), ia); goto r_or; }
|
||||
case el_f64: { or = avx2_squeeze_f64((u8*)f64any_ptr(x), ia); goto r_orF64; }
|
||||
#else
|
||||
case el_i8: { i8* xp = i8any_ptr (x); for (; i < ia; i++) { i32 c = xp[i]; or|= (u8)c; } goto r_orI8; }
|
||||
case el_i16: { i16* xp = i16any_ptr(x); for (; i < ia; i++) { i32 c = xp[i]; or|= ((u32)c & ~1) ^ (u32)(c>>31); } goto r_or; }
|
||||
case el_i32: { i32* xp = i32any_ptr(x); for (; i < ia; i++) { i32 c = xp[i]; or|= ((u32)c & ~1) ^ (u32)(c>>31); } goto r_or; }
|
||||
case el_f64: {
|
||||
f64* xp = f64any_ptr(x);
|
||||
for (; i < ia; i++) {
|
||||
f64 cf = xp[i];
|
||||
i32 c = (i32)cf;
|
||||
if (c!=cf) goto r_x; // already f64
|
||||
or|= ((u32)c & ~1) ^ (u32)(c>>31);
|
||||
}
|
||||
goto r_or;
|
||||
}
|
||||
goto r_or;
|
||||
}
|
||||
#endif
|
||||
case el_B: case el_c8: case el_c16: case el_c32:; /*fallthrough*/
|
||||
}
|
||||
|
||||
B* xp = arr_bptr(x);
|
||||
if (xp==NULL) return num_squeezeF(x, ia);
|
||||
for (; i < ia; i++) {
|
||||
if (RARE(!q_i32(xp[i]))) {
|
||||
while (i<ia) if (!isF64(xp[i++])) goto r_x;
|
||||
goto r_f64;
|
||||
|
||||
#if SINGELI
|
||||
or = avx2_squeeze_B((u8*)xp, ia);
|
||||
if (or==0xfffffffe) goto r_f64;
|
||||
goto r_orF64;
|
||||
r_orF64: if (or==0xffffffff) goto r_x; else goto r_or;
|
||||
#else
|
||||
for (; i < ia; i++) {
|
||||
if (RARE(!q_i32(xp[i]))) {
|
||||
while (i<ia) if (!isF64(xp[i++])) goto r_x;
|
||||
goto r_f64;
|
||||
}
|
||||
i32 c = o2iu(xp[i]);
|
||||
or|= ((u32)c & ~1) ^ (u32)(c>>31);
|
||||
}
|
||||
i32 c = o2iu(xp[i]);
|
||||
or|= ((u32)c & ~1) ^ (u32)(c>>31);
|
||||
}
|
||||
goto r_or;
|
||||
goto r_or;
|
||||
#endif
|
||||
|
||||
r_or : return num_squeeze_choose(x, or);
|
||||
r_x : return FL_SET(x, fl_squoze);
|
||||
r_f64 : return FL_SET(toF64Any(x), fl_squoze);
|
||||
r_orI8 : if (or>=2) goto r_x; else goto r_i8;
|
||||
r_i8 : return FL_SET(toI8Any (x), fl_squoze);
|
||||
r_orI8 : if (or>=2) goto r_x; else goto r_bit;
|
||||
r_bit : return FL_SET(taga(toBitArr(x)), fl_squoze);
|
||||
}
|
||||
B chr_squeeze(B x) {
|
||||
usz ia = a(x)->ia;
|
||||
|
||||
@ -60,10 +60,10 @@ def iota{T & w256{T,32}} = make{T,0,1,2,3,4,5,6,7}
|
||||
def iota{T & w256{T,16}} = make{T,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}
|
||||
def iota{T & w256{T,8}} = make{T,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31}
|
||||
|
||||
# bit arith
|
||||
def __xor{a:T, b:T & w256i{T}} = T ~~ emit{[8]f32, '_mm256_xor_ps', v2f{a}, v2f{b}}
|
||||
def __and{a:T, b:T & w256i{T}} = T ~~ emit{[8]f32, '_mm256_and_ps', v2f{a}, v2f{b}}
|
||||
def __or {a:T, b:T & w256i{T}} = T ~~ emit{[8]f32, '_mm256_or_ps', v2f{a}, v2f{b}}
|
||||
|
||||
def __not{a:T & w256u{T}} = a ^ broadcast{T, ~cast{eltype{T},0}}
|
||||
|
||||
# float comparison
|
||||
|
||||
@ -125,8 +125,8 @@ def shuf{I==[4]u32, x:T, n & w256{T} & knum{n}} = T ~~ emit{[8]i32, '_mm256_shuf
|
||||
def shuf{I==[4]u64, x:T, n & w256{T} & knum{n}} = T ~~ emit{[4]f64, '_mm256_permute4x64_pd', v2d{x}, n}
|
||||
def shufHalves{x:T, y:T, n & w256{T} & knum{n}} = T ~~ emit{[4]i64, '_mm256_permute2x128_si256', v2i{x}, v2i{y}, n}
|
||||
|
||||
def sel{I, x:T, i:[8]i32 & w256{I,32}} = T ~~ emit{[32]u8, '_mm256_permutevar8x32_epi32', v2i{x}, i}
|
||||
def sel{I, x:T, i:[32]i8 & w128{I, 8}} = T ~~ emit{[32]u8, '_mm256_shuffle_epi8', v2i{x}, i}
|
||||
def sel{I, x:T, i:[8]i32 & w256{T} & w256{I,32}} = T ~~ emit{[32]u8, '_mm256_permutevar8x32_epi32', v2i{x}, i}
|
||||
def sel{I, x:T, i:[32]i8 & w256{T} & w128{I, 8}} = T ~~ emit{[32]u8, '_mm256_shuffle_epi8', v2i{x}, i}
|
||||
|
||||
def extract{x:T, i & w256i{T,8 } & knum{i}} = emit{eltype{T}, '_mm256_extract_epi8', x, i}
|
||||
def extract{x:T, i & w256i{T,16} & knum{i}} = emit{eltype{T}, '_mm256_extract_epi16', x, i}
|
||||
@ -183,3 +183,7 @@ def ucvt{T, x:X & w256u{X,64} & T==u16} = to_el{T, sel{[16]i8, ucvt{u32,x}, make
|
||||
def ucvt{T, x:X & w256u{X,64} & T== u8} = to_el{T, sel{[16]i8, ucvt{u32,x}, make{[32]i8, 4*iota{32}}}}
|
||||
|
||||
def ucvt{T, x:X & w256{X} & width{T}==width{eltype{X}}} = to_el{T, x} # TODO check for not being f64/i64
|
||||
|
||||
|
||||
def cvt2{T, x:X & T==i32 & X==[4]f64} = emit{[4]i32, '_mm256_cvtpd_epi32', x}
|
||||
def cvt2{T, x:X & T==f64 & X==[4]i32} = emit{[4]f64, '_mm256_cvtepi32_pd', x}
|
||||
@ -102,9 +102,10 @@ def forNZ{vars,begin,end,block} = {
|
||||
}
|
||||
}
|
||||
|
||||
def maxvalue{T & T==u8 } = 0xff
|
||||
def maxvalue{T & T==u16} = 0xffff
|
||||
def maxvalue{T & T==u32} = 0xffffffff
|
||||
def minvalue{T & isunsigned{T}} = 0
|
||||
def maxvalue{T & isunsigned{T}} = (1<<width{T})-1
|
||||
def minvalue{T & issigned{T}} = - (1<<(width{T}-1))
|
||||
def maxvalue{T & issigned{T}} = (1<<(width{T}-1))-1
|
||||
|
||||
# tuple operations
|
||||
def broadcast{T, v & isprim{T}} = v
|
||||
|
||||
@ -49,10 +49,16 @@ def maskAfter{n} = {
|
||||
|
||||
# store low packed elements of x to P
|
||||
def storeLow{ptr:P, w, x:T & width{T}==w} = store{*T~~ptr, 0, x}
|
||||
|
||||
def storeLow{ptr:P, w, x:T & w128{T} & w==16} = emit{void, '_mm_storeu_si16', ptr, v2i{x}}
|
||||
def storeLow{ptr:P, w, x:T & w128{T} & w==32} = emit{void, '_mm_storeu_si32', ptr, v2i{x}}
|
||||
def storeLow{ptr:P, w, x:T & w128{T} & w==64} = emit{void, '_mm_storeu_si64', ptr, v2i{x}}
|
||||
|
||||
def storeLow{ptr:P, w, x:T & w256{T} & w==16} = storeLow{ptr, w, half{x, 0}}
|
||||
def storeLow{ptr:P, w, x:T & w256{T} & w==32} = storeLow{ptr, w, half{x, 0}}
|
||||
def storeLow{ptr:P, w, x:T & w256{T} & w==64} = storeLow{ptr, w, half{x, 0}}
|
||||
def storeLow{ptr:P, w, x:T & w256{T} & w==128} = store{*[128/width{eltype{T}}](eltype{T})~~ptr, 0, half{x, 0}}
|
||||
def storeLow{ptr:P, w, x:T & w256{T} & w==64} = emit{void, '_mm_storeu_si64', ptr, v2i{half{x, 0}}}
|
||||
def storeLow{ptr:P, w, x:T & w256{T} & w==32} = emit{void, '_mm_storeu_si32', ptr, v2i{half{x, 0}}}
|
||||
def storeLow{ptr:P, w, x:T & w256{T} & w==16} = emit{void, '_mm_storeu_si16', ptr, v2i{half{x, 0}}}
|
||||
|
||||
|
||||
def loadLow{ptr:P, w & w128{eltype{P}} & w==128} = eltype{P} ~~ load{*[16]u8 ~~ ptr}
|
||||
def loadLow{ptr:P, w & w128{eltype{P}} & w== 64} = eltype{P} ~~ emit{[16]u8, '_mm_loadu_si64', ptr}
|
||||
@ -82,10 +88,14 @@ def loadBatch{ptr:P, n, T} = {
|
||||
cvt{E0, T, loadLow{*to_el{E0, T} ~~ rpos, vcount{T}*width{E0}}}
|
||||
}
|
||||
|
||||
def maskedLoop{bulk, l, step} = { # TODO version assuming l!=0
|
||||
|
||||
|
||||
def maskedLoop{bulk, l, step} = maskedLoop{bulk, 0, l, step}
|
||||
|
||||
def maskedLoop{bulk, i0, l, step} = {
|
||||
m:u64 = l/bulk
|
||||
@for (i to m) step{i, maskNone}
|
||||
@for (i from i0 to m) step{i, maskNone}
|
||||
|
||||
left:= l & (bulk-1)
|
||||
if (left!=0) step{m, maskAfter{left}}
|
||||
}
|
||||
}
|
||||
90
src/singeli/src/squeeze.singeli
Normal file
90
src/singeli/src/squeeze.singeli
Normal file
@ -0,0 +1,90 @@
|
||||
include './base'
|
||||
include './sse3'
|
||||
include './avx'
|
||||
include './avx2'
|
||||
include './mask'
|
||||
include 'util/tup'
|
||||
|
||||
def preserve_negative_zero = 0
|
||||
|
||||
def inRangeLen{x:T, start, count & issigned{eltype{T}}} = {
|
||||
def TU = ty_u{T}
|
||||
(TU~~(x-broadcast{T,start})) < broadcast{TU,count}
|
||||
}
|
||||
def inRangeLen{x:T, start, count & isunsigned{eltype{T}}} = {
|
||||
def TS = ty_s{T}
|
||||
def h = 1 << (width{eltype{T}}-1)
|
||||
(TS~~x)-broadcast{TS,start-h} < broadcast{TS,count-h}
|
||||
}
|
||||
def inRangeIncl{x:T, start, end} = inRangeLen{x, start, end-start+1}
|
||||
def inRangeExcl{x:T, start, end} = inRangeLen{x, start, end-start}
|
||||
|
||||
def isSNaN{x:T & isunsigned{eltype{T}}} = inRangeLen{x<<1, (0xFFE<<52)+2, (1<<52)-2}
|
||||
|
||||
def fold{F, x:T} = {
|
||||
show{'WARNING: using fallback fold'}
|
||||
def E = eltype{T}
|
||||
r:E = 0
|
||||
each{{i} => { r = F{r, cast_i{E, extract{x, i}}, iota{vcount{T}}} }}
|
||||
promote{u32, r}
|
||||
}
|
||||
def fold{F, x:T & w128{T}} = {
|
||||
c:= x
|
||||
def EW = width{eltype{T}}
|
||||
if (EW<=64) c = F{c, shuf{[4]u32, c, 4b1032}}
|
||||
if (EW<=32) c = F{c, shuf{[4]u32, c, 4b2301}}
|
||||
if (EW<=16) c = F{c, sel{[16]u8, c, make{[16]i8, iota{16}^2}}}
|
||||
if (EW<=8) c = F{c, sel{[16]u8, c, make{[16]i8, iota{16}^1}}}
|
||||
extract{c, 0}
|
||||
}
|
||||
def fold{F, x:T & w256{T}} = fold{F, F{half{x, 0}, half{x, 1}}}
|
||||
|
||||
squeeze{vw, X0}(x0:*u8, len:Size) : u32 = {
|
||||
def X = tern{X0==u64, f64, X0}
|
||||
def bulk = vw / width{X}
|
||||
def XV = [bulk]X
|
||||
def E = tern{X==f64, u32, ty_u{X}}
|
||||
def EV = [bulk]E
|
||||
xp:= *X~~x0
|
||||
r1:= broadcast{EV, 0}
|
||||
if (X==i8) {
|
||||
maskedLoop{bulk, len, {i, M} => {
|
||||
v0:= loadBatch{xp, i, XV}
|
||||
if (anyne{broadcast{EV, 0xfe} & EV~~v0, broadcast{EV, 0}, M}) return{2}
|
||||
}}
|
||||
0
|
||||
} else {
|
||||
maskedLoop{bulk, len, {i, M} => {
|
||||
v0:= loadBatch{xp, i, XV}
|
||||
def toint{x:T & isint{eltype{T}}} = x
|
||||
def toint{flt:T & X==f64} = {
|
||||
int:= cvt2{i32, flt}
|
||||
|
||||
def conv{x} = tern{preserve_negative_zero, ty_u{x}, x}
|
||||
|
||||
if (anyne{conv{flt}, conv{cvt2{f64, int}}, M}) { # is any not an integer
|
||||
if (X0==f64) return{0xffff_ffff}
|
||||
|
||||
maskedLoop{bulk, i, len, {i, M} => {
|
||||
def XU = [bulk]u64
|
||||
v:= XU ~~ loadBatch{xp, i, XV}
|
||||
if (any{M{isSNaN{v}}}) return{0xffff_ffff} # is any not even a float
|
||||
}}
|
||||
return{0xffff_fffe}
|
||||
}
|
||||
int
|
||||
}
|
||||
v1:= toint{v0}
|
||||
r1|= M{(broadcast{EV, ~E~~1} & EV~~v1) ^ EV~~(v1 >> (width{X}-1))}
|
||||
}}
|
||||
promote{u32, fold{|, r1}}
|
||||
}
|
||||
}
|
||||
|
||||
'avx2_squeeze_i8' = squeeze{256, i8 }
|
||||
'avx2_squeeze_i16' = squeeze{256, i16}
|
||||
'avx2_squeeze_i32' = squeeze{256, i32}
|
||||
'avx2_squeeze_f64' = squeeze{256, f64}
|
||||
'avx2_squeeze_B' = squeeze{256, u64}
|
||||
#'avx2_squeeze_u16' = squeeze{256, u16}
|
||||
#'avx2_squeeze_u32' = squeeze{256, u32}
|
||||
@ -58,6 +58,12 @@ def iota{T & w128{T,32}} = make{T,0,1,2,3}
|
||||
def iota{T & w128{T,16}} = make{T,0,1,2,3,4,5,6,7}
|
||||
def iota{T & w128{T,8}} = make{T,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}
|
||||
|
||||
# bit arith
|
||||
def __xor{a:T, b:T & w128i{T}} = T ~~ emit{[4]f32, '_mm_xor_ps', v2f{a}, v2f{b}}
|
||||
def __and{a:T, b:T & w128i{T}} = T ~~ emit{[4]f32, '_mm_and_ps', v2f{a}, v2f{b}}
|
||||
def __or {a:T, b:T & w128i{T}} = T ~~ emit{[4]f32, '_mm_or_ps', v2f{a}, v2f{b}}
|
||||
def __not{a:T & w128u{T}} = a ^ broadcast{T, ~cast{eltype{T},0}}
|
||||
|
||||
# signed comparison
|
||||
def __eq{a:T,b:T & T==[16]i8 } = emit{[16]u8, '_mm_cmpeq_epi8', a, b}
|
||||
def __eq{a:T,b:T & T==[ 8]i16} = emit{[ 8]u16, '_mm_cmpeq_epi16', a, b}
|
||||
@ -79,10 +85,38 @@ def __gt{a:T,b:T & w128u{T}} = ~(a<=b)
|
||||
# rest of comparison
|
||||
def __ne{a:T,b:T & w128i{T}} = ~(b==a)
|
||||
|
||||
|
||||
# shift
|
||||
def __shl{a:T,b & w128i{T, 16} & knum{b}} = emit{T, '_mm_slli_epi16', a, b}
|
||||
def __shl{a:T,b & w128i{T, 32} & knum{b}} = emit{T, '_mm_slli_epi32', a, b}
|
||||
def __shl{a:T,b & w128i{T, 64} & knum{b}} = emit{T, '_mm_slli_epi64', a, b}
|
||||
def __shr{a:T,b & w128u{T, 16} & knum{b}} = emit{T, '_mm_srli_epi16', a, b}
|
||||
def __shr{a:T,b & w128u{T, 32} & knum{b}} = emit{T, '_mm_srli_epi32', a, b}
|
||||
def __shr{a:T,b & w128u{T, 64} & knum{b}} = emit{T, '_mm_srli_epi64', a, b}
|
||||
def __shr{a:T,b & w128s{T, 16} & knum{b}} = emit{T, '_mm_srai_epi16', a, b}
|
||||
def __shr{a:T,b & w128s{T, 32} & knum{b}} = emit{T, '_mm_srai_epi32', a, b}
|
||||
# no 64-bit arithmetic shift :/
|
||||
|
||||
def min{a:T,b:T & T==[ 8]i16} = emit{T, '_mm_min_epi16', a, b}; def max{a:T,b:T & T==[ 8]i16} = emit{T, '_mm_max_epi16', a, b}
|
||||
def min{a:T,b:T & T==[16]u8 } = emit{T, '_mm_min_epu8', a, b}; def max{a:T,b:T & T==[16]u8 } = emit{T, '_mm_max_epu8', a, b}
|
||||
|
||||
|
||||
# shuffle stuff
|
||||
def shuf{I==[4]u32, x:T, n & w128{T} & knum{n}} = T ~~ emit{[4]i32, '_mm_shuffle_epi32', v2i{x}, n}
|
||||
def sel{I, x:T, i:[16]i8 & w128{T} & w128{I, 8}} = T ~~ emit{[16]u8, '_mm_shuffle_epi8', v2i{x}, i}
|
||||
|
||||
# arith
|
||||
def __add{a:T,b:T & w128i{T, 8}} = emit{T, '_mm_add_epi8', a, b}
|
||||
def __add{a:T,b:T & w128i{T, 16}} = emit{T, '_mm_add_epi16', a, b}
|
||||
def __add{a:T,b:T & w128i{T, 32}} = emit{T, '_mm_add_epi32', a, b}
|
||||
def __add{a:T,b:T & w128i{T, 64}} = emit{T, '_mm_add_epi64', a, b}
|
||||
|
||||
def __sub{a:T,b:T & w128i{T, 8}} = emit{T, '_mm_sub_epi8', a, b}
|
||||
def __sub{a:T,b:T & w128i{T, 16}} = emit{T, '_mm_sub_epi16', a, b}
|
||||
def __sub{a:T,b:T & w128i{T, 32}} = emit{T, '_mm_sub_epi32', a, b}
|
||||
def __sub{a:T,b:T & w128i{T, 64}} = emit{T, '_mm_sub_epi64', a, b}
|
||||
|
||||
|
||||
# mask stuff
|
||||
def getmask{x:T & w128{T, 8}} = emit{u32, '_mm_movemask_epi8', x}
|
||||
def getmask{x:T & w128{T, 16}} = getmask{emit{[16]u8, '_mm_packs_epi16', x, broadcast{[8]u16, 0}}}
|
||||
|
||||
@ -10,7 +10,8 @@ test/moreCfgs.sh path/to/mlochbaum/BQN // run "2+2" in a bunch of configurations
|
||||
./BQN test/equal.bqn // fuzz-test 𝕨≡𝕩
|
||||
./BQN test/copy.bqn // fuzz-test creating new arrays with elements copied from another
|
||||
./BQN test/bitcpy.bqn // fuzz-test bit_cpy; requires a CBQN build with -DTEST_BITCPY
|
||||
./BQN test/squeeze.bqn // fuzz-test squeezing; requires a CBQN build with -DEEQUAL_NEGZERO
|
||||
./BQN test/squeezeValid.bqn // fuzz-test squeezing giving a correct result; requires a CBQN build with -DEEQUAL_NEGZERO
|
||||
./BQN test/squeezeExact.bqn // fuzz-test squeezing giving the exact smallest result; requires a CBQN build with -DEEQUAL_NEGZERO
|
||||
./BQN test/random.bqn // various random tests
|
||||
make -C test/ffi // test FFI functionality; expects both regular and shared library CBQN builds to already exist
|
||||
|
||||
|
||||
70
test/squeezeExact.bqn
Normal file
70
test/squeezeExact.bqn
Normal file
@ -0,0 +1,70 @@
|
||||
⟨EEqual, ClearRefs, Variation, Squeeze, Type⟩ ← •internal
|
||||
u ← ⌊100×(•UnixTime+1|100וMonoTime)@
|
||||
|
||||
r ← •MakeRand •Show u
|
||||
|
||||
ntn ← "bit"‿"i8"‿"i16"‿"i32"‿"f64"
|
||||
ntv ← "Ab"‿"Ai8"‿"Ai16"‿"Ai32"‿"Af64"
|
||||
nmin ← 0∾ -2⋆¯1+8×2⋆↕3
|
||||
nmax ← 1∾¯1+2⋆¯1+8×2⋆↕3
|
||||
int ← 1‿1‿1‿1‿0
|
||||
|
||||
ctn ← "c8"‿"c16"‿"c32"
|
||||
ctv ← "Ac8"‿"Ac16"‿"Ac32"
|
||||
cmax ← 1114112⌊2⋆8×2⋆↕3
|
||||
|
||||
⟨specF64⟩ ← ⟨r⟩ •Import "utils.bqn"
|
||||
spec ← specF64∾{⇐}∾"a⍉𝕨"∾<"foo"
|
||||
|
||||
# currently tests an array of 0s, with only one outstanding element
|
||||
Do ← { 𝕊:
|
||||
val ← {r.Range∘≠◶𝕩𝕩} ⟨
|
||||
{𝕊: r.Range∘≠⊸⊑ spec}
|
||||
{𝕊: (¯5+r.Range 10) + 2⋆r.Range 64}
|
||||
⟩
|
||||
base ← 0
|
||||
|
||||
len ← 1+r.Range 2⋆3+r.Range 7
|
||||
pos ← r.Range len
|
||||
arr ← "Ah" Variation val⌾(pos⊸⊑) len⥊<base
|
||||
|
||||
tOut‿tIn ← {
|
||||
1=•Type val?
|
||||
msk ← ((¬int) ∨ val≡⌊val) ∧ 1∾˜ (≥⟜nmin∧≤⟜nmax)val
|
||||
⟨1↑msk/ntn ⋄ "Ah"‿"Af"∾msk/ntv⟩;
|
||||
(2≡•Type val) ∧ 1≡len?
|
||||
msk ← {2≡•Type val? (1≡len) ∧ (val-@)<cmax; 0}
|
||||
⟨1↑msk/ctn ⋄ "Ah"‿"Af"∾msk/ctv⟩;
|
||||
# else
|
||||
⟨"h"‿"fill" ⋄ "Ah"‿"Af"⟩
|
||||
}
|
||||
tIn ↩ {'S'∾1↓𝕩}¨⊸∾ ∾⟜"Inc"¨⊸∾ tIn
|
||||
|
||||
{
|
||||
arrv ← 𝕩 Variation arr
|
||||
sq ← Squeeze arrv
|
||||
sqt ← Type sq
|
||||
sqt↩{
|
||||
"arr"≡¯3↑sqt? ¯3↓sqt;
|
||||
!"slice"≡¯5↑sqt ⋄ ¯5↓sqt
|
||||
}
|
||||
¬ (arrv EEqual arr) ∧ (arrv EEqual sq) ∧ (⊑(<sqt) ∊ tOut)?
|
||||
•Out "Fail:"
|
||||
•Show arrv
|
||||
•Show sq
|
||||
•Show Type sq
|
||||
•Show tOut‿𝕩
|
||||
•Exit 1
|
||||
;@
|
||||
}¨ tIn
|
||||
ClearRefs@
|
||||
}
|
||||
|
||||
n0a ← "Af64" Variation 1↓1‿1‿¯1×π‿0‿0
|
||||
n0b ← Squeeze n0a
|
||||
{
|
||||
n0a≡○÷n0b? •Out "Squeeze behavior on negative zero: keep";
|
||||
•Out "Squeeze behavior on negative zero: discard"
|
||||
}
|
||||
|
||||
Do¨ ↕100000
|
||||
Loading…
Reference in New Issue
Block a user