bqn-npy/npy.bqn
Dimitri Lozeve 9a1d251716 Fix issue with unsigned integers
Fixes https://github.com/dlozeve/bqn-npy/issues/1.

The spec says that •bit._cast should support 32-bit uints [1], but
CBQN does not [2].

To get around this, we just use signed integers, which works for
numbers smaller than 2^31. Above that, it will wrap around
and (probably) fail, but CBQN does not support them anyway (except by
converting them to doubles).

From Marshall:

> All of the provided functions at this time are identical on i32 and
> u32, because they work (mod 2^32) and the only difference between
> those formats is to add or subtract 2^32 from numbers outside the
> range [0,2^31).
> If you want to run on u32s stored directly as numbers in BQN (they
> won't fit in i32 and will be stored as double!) you can •bit._cast
> those into a signed format at the beginning and then back out at the
> end.

[1] https://mlochbaum.github.io/BQN/spec/system.html#bitwise-operations
[2] https://matrix.to/#/!EjsgbQQNuTfHXQoiax:matrix.org/$PL2AYNlLQuYhPftdt7yw7rW9heiVEEeATte2zOt2BYk
2024-11-11 22:58:04 +01:00

50 lines
2 KiB
BQN
Raw Blame History

This file contains ambiguous Unicode characters

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

SaveNpy,LoadNpy
lf@+10
magicString(@+147)"NUMPY"
# Type conversions
# CBQN does not support other widths than 1 for 'u'. However, signed
# and unsigned integers seem to have the same behavior for numbers
# below 2⋆31.
dtypesformats"<f8","<i4","<u4"64'f',32'i',1'u'
DtypeToFormat{(dtypes<𝕩)formats}
ArrayToBytes{DtypeToFormat 𝕨,8'c'•bit._cast 𝕩}
ArrayFromBytes{8'c',DtypeToFormat 𝕨•bit._cast 𝕩}
# Saving
To_i16le{@+256(|÷˜)𝕩}
FormatShape{'('(1','˘•Fmt¨𝕩)",)"}
BuildHeader{dtype 𝕊 data:
version10
# Hypothesis: BQN arrays are C-contiguous
headerData"{'descr':'"dtype"','fortran_order':False,'shape':"(FormatShape data)",}"
padding' '˜64-64|(magicString)+2+2+(headerData)+1
! 0=64|(magicString)+2+2+(padding)+(headerData)+1
headerDataPaddedheaderDatapaddinglf
magicString(@+version)(To_i16le headerDataPadded)headerDataPadded
}
DetectDtype{(´=¨𝕩)"<f8",(´0𝕩)"<i4""<u4"}
EncodeNpyDetectDtype(BuildHeaderArrayToBytes)
SaveNpy(•wdpath•file.At)•file.BytesEncodeNpy
# Loading
ParseHeader{𝕊𝕩:
"Not a valid NPY file"! magicString(magicString)𝕩
version@-˜(01+magicString)𝕩
headerlen+´1256×@-˜(23+magicString)𝕩
header(¬(' 'lf))/headerlen(4+magicString)𝕩
dtype3(´"<>") (("descr"header)1)header
("Unsupported dtype: "dtype) ! (<dtype)dtypes
shapestr(')') (1+'(') (("shape"header)1)header
shape•BQN¨','((-˜+`׬)=)shapestr
version,dtype,shape,headerlen+2+2+magicString
}
LoadNpy{𝕊𝕩:
bytes•file.Bytes 𝕩
versiondtypeshapedatastartParseHeader bytes
shapedtype ArrayFromBytes datastartbytes
}