Register vlen-ndarray data type and codec - #71
Conversation
|
Some broader background on this: we're encoding photon fluxes. First consumer is NASA Sliderule and the ICESat-2 mission; raw photons vary, and we encode them as 'digests' on a grid with fixed attribute width, but variable column length per cell. (Hoping to have an example zarr store that can opened publicly for California sometime next week). We'll be using the same data type / codec for laser waveforms from the GEDI mission as well. |
|
Just reading your description (I haven't looked at the spec), but my first thought is why not generalise to arbitrary shaped ndarrays? Also I see potential variants data types that could be encoded differently:
|
|
It sounds like the codec is designed to exactly match data that has already been written using vlen-bytes. The representation isn't ideal but defining a codec for that purpose seems reasonable. However I think you could avoid having a separate vlen-ndarray dtype specifically for this codec, and instead just have an ndarray data type. Then the vlen-ndarray codec would just impose extra constraints. You could also have an array-to-array codec that converts the ndarray dtype to bytes dtype, and then use vlen-bytes as the array-to-bytes codec. |
|
Thanks — these both seem to push in the same direction and I think you're right: the dtype should be general and the codec should carry the constraints. @jbms — agreed on the split. I'll restructure this PR to register a @LDeakin — fair question. With the trailing shape fixed in configuration,
I'll note that mapping in the data-type text — as compatible-codec notes, not registrations — so the grammar's generality is on record without claiming codecs nobody is building. I'd like to keep the dtype registration minimal (the shape grammar plus this one codec) rather than grow it into a full ndarray design effort in this PR — but you two are the most likely implementors, so if the general dtype needs more decided up front to be implementable in tensorstore/zarrs — tell me what you need and I'll extend it. |
|
ok, I've updated both this PR and https://github.com/espg/zarr-vlen-ndarray — restructured per the dtype/codec split, details in the diffs. One correction from my earlier comment: any single variable dimension is length-inferable regardless of position — the leading restriction is this codec's design choice, and the text now says so. One thing that strikes me as a long time numpy user is the collision users have reading a data type that's |
I'm not sure if the data type should specify shape constraints --- or if that should be a part of the codec. In any case it seems reasonable to allow any single dimension to be variable-length under this design.
The data type specifies the type of an individual element within the array. Therefore, a regular array has a scalar type as its element, while in this case we are talking about an array where the element type is itself an array. Therefore, Another thing to consider is to specify the codec chain of |
This PR registers
vlen-ndarray, a data type for arrays whose elements are variable-length ndarrays — each element has shape(n, *inner_shape)withnvarying per element and the trailinginner_shapeplus the scalardtypefixed in the configuration — together with its paired parameter-freearray -> bytescodec:{ "data_type": { "name": "vlen-ndarray", "configuration": {"dtype": "float32", "inner_shape": [2]} }, "codecs": [{"name": "vlen-ndarray"}] }Wire format. The codec serializes each element as its raw little-endian C-order bytes and frames chunks exactly as the registered
vlen-bytescodec (u32le count; per element u32le length + payload). Encoded chunks are therefore byte-identical tobytes+vlen-byteschunks holding each element's raw bytes: existing stores using that common ragged-data convention upgrade to the typed form with a metadata-only rewrite, and implementations withoutvlen-ndarraysupport can read the data asbytes+vlen-bytesafter metadata substitution.Relation to existing discussions. This is a concrete, fixed-inner-shape point in the "generic container data types" design space discussed in #57, scoped to fixed-size numeric/boolean core scalar types so every element has a well-defined item size (element length is implied by encoded byte length — no per-element shape storage). It does not preclude a more general
variable_length[<base>]family later.Implementation. A working implementation (zarr-python >= 3.1, registered via
zarr.data_type/zarr.codecsentry points) with round-trip, sharding, and byte-identity tests: https://github.com/espg/zarr-vlen-ndarrayMotivating use. The zagg aggregation pipeline (and its
moczarrreader) stores per-cell t-digest centroid sets ((n, 2)float32) and location lists ((n,)uint64) on HEALPix grids; the store spec's/2revision cites this name (englacial/zagg#340, englacial/zagg#210).