perf(svar2): consume genoray's sparse range stream in the writer - #416
Merged
Merged
Conversation
`_write_from_svar2` built its region-CSR cache by materializing genoray's dense `(samples, ploidy, regions, 2)` chunk and then discarding it: at the All of Us chr22 grid only 0.45% of `(region, sample, ploid)` windows hold a variant, the dense intermediate is ~128 GB per contig, and the `np.nonzero` scan that recovered the useful cells was 71% of the per-chunk kernel. genoray 4.1.0 emits those cells directly (d-laub/genoray#206), so the scan and the intermediate both go away. `nonempty_entries` collapses into a CSR expansion plus four column assignments and is deleted. The on-disk cache is unchanged, byte for byte. genoray filters on the same predicate (`end > start` in either channel), emits the same absolute `slot * ploidy + ploid` cell ids in the same region-major order, and carries the same raw start with length 0 for a cell non-empty in only one channel. The nine `_core.run_conversion_pipeline` fixtures move to genoray's keyword-only, struct-grouped signature (d-laub/genoray#153), which the same version bump requires. `nonempty_entries`'s shape check went with it. It guarded a transpose that no longer exists — the chunk arrives region-major — so the axis order it defended is now unrepresentable rather than validated. Its int32 cell-id overflow guard is already enforced by `_SparseWriter`'s `span >= 2**31` check. Refs #405. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`_write_from_svar2` now calls `SparseVar2._find_ranges_chunked_sparse` and the test fixtures call the keyword-only `_core.run_conversion_pipeline`. Neither exists before 4.1.0. `pixi.lock` is deliberately not regenerated and the `pixi-lock` / `pyrefly` hooks are skipped for this commit: 4.1.0 is not on PyPI yet, so pixi cannot resolve this range at all. Run `pixi lock` and re-run the hooks once the release lands. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… entry points genoray 5.0.0 is out, carrying both changes this branch needs: the sparse range emission from d-laub/genoray#206 and the keyword-only, grouped-argument pipeline entry points from d-laub/genoray#200. The previous pin (`>=4.1.0,<5`) anticipated a 4.1.0 that was never cut, so it excludes the release it was waiting for. Bump the pin in `pyproject.toml` and `pixi.toml` to `>=5,<6`, relock, and move both `Cargo.toml` git deps (`svar2-codec`, `genoray_core`) to the 5.0.0 tag commit 714f876. 5.0.0's breaking changes -- the `GENORAY_*` environment variables, the `reader_workers=` parameter and `resolve_log_level` -- all land on APIs genvarloader never calls, so nothing here needed rewriting for them. What did need rewriting: #200 made the `_core` pipeline entry points keyword-only and grouped their arguments into `RegionSpec` / `FieldSpec` / `PlanSettings`. The twelve test call sites that build svar2 fixtures now pass keywords and those dataclasses instead of a positional argument list. Re-checked the empty-cell contract at the new rev, as the comment in `Cargo.toml` asks: `gather_haps_readbound_impl` still consumes every range purely as a slice bound, so a `len == 0` range's `start` is never dereferenced. Full suite against the real 5.0.0 wheel: 1315 passed, 43 skipped, 4 xfailed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #405.
What
_write_from_svar2built its region-CSR range cache by materializing genoray's dense(samples, ploidy, regions, 2)chunk and then throwing almost all of it away. At the All of Us chr22 grid only 0.45% of(region, sample, ploid)windows hold a variant, the dense intermediate is ~128 GB per contig, and thenp.nonzeroscan that recovered the useful cells was 71% of the per-chunk write kernel.genoray now emits exactly those cells (d-laub/genoray#206), so the writer consumes
SparseVar2._find_ranges_chunked_sparse. The scan and the intermediate both disappear;nonempty_entriescollapses into a CSR expansion plus four column assignments and is deleted.The output does not change
Byte for byte. The two paths already agreed on every convention:
nonempty_entriesend > startper channel, OR'dcell_idslot * ploidy + ploid, selection-absolutelen = 0(not zeroed)cell_idascendingtest_write_svar2_chunked_matches_unchunkedcompares the on-disk table across chunk boundaries and still passes, with its spy now confirming the sparse stream is the one being driven.Also in here: the fixtures move to genoray's grouped pipeline args
The same version bump carries genoray's #153/#200 refactor, which made the
_corepipeline entry points keyword-only withRegionSpec/FieldSpec/PlanSettings. GVL called them positionally at 12 sites across 9 test files, so all 12 are ported.One guard intentionally removed
nonempty_entries's shape check defended against a mis-transpose. There is no transpose left — the chunk arrives region-major — so that axis order is now unrepresentable rather than validated. Its int32 cell-id overflow guard is already enforced by_SparseWriter'sspan >= 2**31check.Pinned to genoray 5.0.0
The release landed as 5.0.0, not the 4.1.0 this branch first anticipated, so the original
>=4.1.0,<5pin excluded the very release it was waiting for. Now pinned>=5,<6inpyproject.tomlandpixi.toml, relocked, and bothCargo.tomlgit deps (svar2-codec,genoray_core) moved to the 5.0.0 tag commit714f876.5.0.0's breaking changes — the
GENORAY_*environment variables, thereader_workers=parameter, andresolve_log_level— all land on APIs genvarloader never calls, so none of them required a change here.Re-checked the empty-cell contract at the new rev, as the
Cargo.tomlcomment asks:gather_haps_readbound_impl(genoray:src/query/gather.rs:869at 5.0.0) still consumes every range purely as a slice bound (d_snp_pos[ss..se],snp_positions[vs..ve]), so alen == 0range yields an empty slice and itsstartis never dereferenced.Testing
Against the real genoray 5.0.0 wheel, full suite (after
pixi run gen):1315 passed, 43 skipped, 4 xfailed, 0 failed —
pytest tests -p no:randomly --ignore=tests/benchmarks, 3m06s.cargo check --all-targetsis clean at the new rev, and all prek hooks (ruff check/format, pyrefly, pixi lock, commitizen) pass.Unblocks d-laub/genoray#204 (deleting genoray's dense chunk path).
🤖 Generated with Claude Code