Repository navigation
Add Array.prepend, bounds in the array metadata, and the offset chunk grid - #4516
rhoadesScholar wants to merge 1 commit into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #4516 +/- ##
==========================================
+ Coverage 94.90% 94.92% +0.02%
==========================================
Files 96 96
Lines 14048 14226 +178
==========================================
+ Hits 13332 13504 +172
- Misses 716 722 +6
🚀 New features to boost your workflow:
|
|
Ready for review; the registry entry is zarr-developers/zarr-extensions#80. cc @d-v-b |
|
thanks for this PR! I really want to see this feature added to |
|
Converting to draft while the design is worked out in zarr-developers/zarr-extensions#79. This branch is a prototype and will be reworked to match. |
fb48e95 to
4f7091d
Compare
|
The metadata form is being settled in ZEP 12 (zarr-developers/zeps#72, spec text zarr-developers/zarr-specs#400). This PR stays on the |
… grid Prototype for ZEP 12 and the `offset` chunk grid of the extensions registry. `Array.prepend(data, axis)` adds data before index 0 of an axis without touching an existing chunk. The array's lower bound is read from and written to the `bounds` metadata member (`inclusive_min` / `exclusive_max`, in place of `shape`); `ArrayV3Metadata` keeps `inclusive_min` beside the derived `shape`, and `bounded` records which form the stored document uses so later updates keep it. Grid indices on a `regular` grid can be negative, chunk keys carry them, and `-0` components are rejected. `OffsetChunkGridMetadata` wraps a `regular` grid so that its chunk 0 begins at a chosen coordinate. A regular dimension gains the position of the first element inside its first chunk, applied where array positions become chunk-local ones, so a partly filled first chunk is handled like a partly filled last chunk. `Array.domain` reports the coordinate range of each dimension.
4f7091d to
5d88716
Compare
Prototype for ZEP 12 (zarr-developers/zeps#72, spec text zarr-developers/zarr-specs#400) and the
offsetchunk grid of zarr-developers/zarr-extensions#81.Array.prepend(data, axis)adds data before index 0 of an axis, the wayappendadds it after the end. It grows by any number of elements and never touches an existing chunk:The first prepend switches the written metadata from
shapetobounds({"inclusive_min": [-3, 0], "exclusive_max": [6, 4]}); the chunk grid staysregular, and chunk grid indices below 0 come out by floor division. Readers that do not implementboundsrefuse the array, sinceshapeis absent, rather than misread it. Indexing stays zero-based: indexiis coordinateinclusive_min + i, andArray.domainreports the coordinate range. Theoffsetchunk grid (offset+base_chunk_grid, aregularbase only) is read and written; it places chunk 0 at a chosen coordinate and is not needed to prepend.To try it:
pip install "zarr @ git+https://github.com/zarr-developers/zarr-python@refs/pull/4516/head"What growing in front costs. Two chunk rows in front of an array of 64³ uint8 chunks, one machine (NVMe), wall seconds:
prepend's metadata stepScript: https://github.com/rhoadesScholar/zarr-chunk-offset/tree/main/bench
How it works
ArrayV3Metadatareads exactly one ofshapeandboundsand keepsinclusive_minbeside the derivedshape;to_dictwritesboundswhen some lower bound is non-zero or the stored document already usedbounds, so a resize or attribute update keeps the form it found. Entries and lengths are checked against the signed 64-bit range.OffsetChunkGridMetadatawraps aRegularChunkGridMetadata; the metadata derives the grid index of the first chunk and the first element's position inside it frominclusive_min, the grid origin andchunk_shape.shift, the position of the first element inside the first chunk, and abuffer_offset(chunk)that is 0 except for a partly filled first chunk. The indexers add it at the six places they convert array positions to chunk-local ones, so a partly filled first chunk is handled like a partly filled last chunk, write path included.-0.Tests. A
boundsstore and anoffset-grid store written by tensorstore (google/tensorstore#296) read back here with the same domain, grid origin, keys and values, and a write through this branch keeps theirboundsform. Every selection type is read and written against NumPy on an array whose first chunk is partly filled, and on the registry README's offset-grid example (keysc/-1/0,c/-1/1,c/0/0,c/0/1). Also covered: prepending by part of a chunk, whole chunks, part of a shard, and on an array already on anoffsetgrid; repeated prepends followed byresize; reopening;boundsandoffsetvalidation and refusals. mypy and ruff are clean.Not covered here: rectilinear grids (a non-zero lower bound is refused for them), Zarr v2 arrays, and switching an array to
boundswithout prepending.History: the first version of this PR used an
offsetchunk key encoding, the second aregular_boundedchunk grid; both were replaced on review in zarr-developers/zarr-extensions#79 and zarr-developers/zeps#72.Refs zarr-developers/zarr-specs#9, zarr-developers/zarr-extensions#30.