zipoop 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
zipoop-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 zatumout
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
zipoop-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,51 @@
1
+ Metadata-Version: 2.4
2
+ Name: zipoop
3
+ Version: 0.1.0
4
+ Summary: Decoder and reader for Zipoop teacher shards (per-window neural compression of ENCODE signal tracks)
5
+ Author: zatumout
6
+ License-Expression: MIT
7
+ Project-URL: Dataset, https://huggingface.co/datasets/zatumout/zipoop-teacher-shards
8
+ Keywords: genomics,ENCODE,neural compression,distillation
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
11
+ Requires-Python: >=3.11
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: numpy>=1.26
15
+ Requires-Dist: torch>=2.2
16
+ Provides-Extra: test
17
+ Requires-Dist: pytest>=8; extra == "test"
18
+ Dynamic: license-file
19
+
20
+ # zipoop
21
+
22
+ Decoder and reader for the Zipoop teacher shards (dataset: https://huggingface.co/datasets/zatumout/zipoop-teacher-shards): 89,438 windows of 32 kb, 1,885 ENCODE tracks, stored as one `<chrom>.npz` per chromosome (`weights_npz`, with `MANIFEST.tsv`).
23
+
24
+ ## Data layout
25
+
26
+ `<root>/<chrom>.npz` (25 files) plus `MANIFEST.tsv` (chrom, windows, members, bytes, sha256). Each file is a deflate zip with members `<window>/<key>.npy` (161 arrays per window), windows in genome order. Window names are `<chrom>_<start>_<end>`.
27
+
28
+ ## Usage
29
+
30
+ ```python
31
+ from zipoop import Dataset
32
+ with Dataset("/path/to/weights_npz") as ds:
33
+ w = ds.load_window(ds.windows("chr21")[0]) # TeacherWindow: key, dna (L,), signal (L, T), valid (L, T)
34
+ ```
35
+
36
+ ```
37
+ zipoop verify /path/to/weights_npz # size + sha256 against MANIFEST.tsv
38
+ zipoop show /path/to/weights_npz chr21_10027008_10059776
39
+ ```
40
+
41
+ Lower level: `Dataset.read(window)` gives the parsed `Shard`, `Decoder(shard).decode(start, end, tracks)` decodes any slice or track subset. Evaluation helpers (`window_pearson`, `summarize`, `calibrate`, `restore_real`) are in `zipoop.evaluation`.
42
+
43
+ Rules baked into `load_window` (see `zipoop/teacher.py`): RNA-seq tracks are 0 and valid where unrecorded; other tracks stay missing there. Opening a chromosome file parses its whole zip directory (chr1 about 3.6 s and 0.9 GB), so keep the `Dataset` open; forked DataLoader workers reopen their own handles.
44
+
45
+ Only the shard variant in this dataset is supported (hybrid `pooper-dna-v3`, max-pool, sinusoidal positions, mask `track-rle-lzma-v2`); other variants raise a clear error.
46
+
47
+ Tests: `ZIPOOP_DATA=<weights_npz> pytest tests` (the pooper-equivalence test also needs the original shards and the pooper package).
48
+
49
+ ## License and data terms
50
+
51
+ The code is MIT-licensed (see `LICENSE`; keep the copyright notice "zatumout"). The shard dataset is released separately under CC BY 4.0 (credit: zatumout), commercial use and model distillation allowed. The shards and `zipoop/data/encode-panel_1885.json` are derived from public ENCODE tracks: when you use them, also cite and acknowledge the ENCODE Consortium as described at https://www.encodeproject.org/help/citing-encode.
zipoop-0.1.0/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # zipoop
2
+
3
+ Decoder and reader for the Zipoop teacher shards (dataset: https://huggingface.co/datasets/zatumout/zipoop-teacher-shards): 89,438 windows of 32 kb, 1,885 ENCODE tracks, stored as one `<chrom>.npz` per chromosome (`weights_npz`, with `MANIFEST.tsv`).
4
+
5
+ ## Data layout
6
+
7
+ `<root>/<chrom>.npz` (25 files) plus `MANIFEST.tsv` (chrom, windows, members, bytes, sha256). Each file is a deflate zip with members `<window>/<key>.npy` (161 arrays per window), windows in genome order. Window names are `<chrom>_<start>_<end>`.
8
+
9
+ ## Usage
10
+
11
+ ```python
12
+ from zipoop import Dataset
13
+ with Dataset("/path/to/weights_npz") as ds:
14
+ w = ds.load_window(ds.windows("chr21")[0]) # TeacherWindow: key, dna (L,), signal (L, T), valid (L, T)
15
+ ```
16
+
17
+ ```
18
+ zipoop verify /path/to/weights_npz # size + sha256 against MANIFEST.tsv
19
+ zipoop show /path/to/weights_npz chr21_10027008_10059776
20
+ ```
21
+
22
+ Lower level: `Dataset.read(window)` gives the parsed `Shard`, `Decoder(shard).decode(start, end, tracks)` decodes any slice or track subset. Evaluation helpers (`window_pearson`, `summarize`, `calibrate`, `restore_real`) are in `zipoop.evaluation`.
23
+
24
+ Rules baked into `load_window` (see `zipoop/teacher.py`): RNA-seq tracks are 0 and valid where unrecorded; other tracks stay missing there. Opening a chromosome file parses its whole zip directory (chr1 about 3.6 s and 0.9 GB), so keep the `Dataset` open; forked DataLoader workers reopen their own handles.
25
+
26
+ Only the shard variant in this dataset is supported (hybrid `pooper-dna-v3`, max-pool, sinusoidal positions, mask `track-rle-lzma-v2`); other variants raise a clear error.
27
+
28
+ Tests: `ZIPOOP_DATA=<weights_npz> pytest tests` (the pooper-equivalence test also needs the original shards and the pooper package).
29
+
30
+ ## License and data terms
31
+
32
+ The code is MIT-licensed (see `LICENSE`; keep the copyright notice "zatumout"). The shard dataset is released separately under CC BY 4.0 (credit: zatumout), commercial use and model distillation allowed. The shards and `zipoop/data/encode-panel_1885.json` are derived from public ENCODE tracks: when you use them, also cite and acknowledge the ENCODE Consortium as described at https://www.encodeproject.org/help/citing-encode.
@@ -0,0 +1,35 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "zipoop"
7
+ version = "0.1.0"
8
+ description = "Decoder and reader for Zipoop teacher shards (per-window neural compression of ENCODE signal tracks)"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{name = "zatumout"}]
14
+ keywords = ["genomics", "ENCODE", "neural compression", "distillation"]
15
+ classifiers = ["Programming Language :: Python :: 3", "Topic :: Scientific/Engineering :: Bio-Informatics"]
16
+ dependencies = ["numpy>=1.26", "torch>=2.2"]
17
+
18
+ [project.optional-dependencies]
19
+ test = ["pytest>=8"]
20
+
21
+ [project.urls]
22
+ Dataset = "https://huggingface.co/datasets/zatumout/zipoop-teacher-shards"
23
+
24
+ [project.scripts]
25
+ zipoop = "zipoop.cli:main"
26
+
27
+ [tool.setuptools.packages.find]
28
+ include = ["zipoop*"]
29
+
30
+ [tool.setuptools.package-data]
31
+ zipoop = ["data/*.json"]
32
+
33
+ [tool.pytest.ini_options]
34
+ testpaths = ["tests"]
35
+ addopts = "-q"
zipoop-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,123 @@
1
+ """Needs the real dataset: set ZIPOOP_DATA to the merged weights_npz directory (tests skip otherwise).
2
+ The equivalence tests additionally need the original per-window shards (ZIPOOP_SINGLE, default
3
+ /mnt/e/zipoop/weights) and the pooper package on the path."""
4
+ import os
5
+ import random
6
+ from pathlib import Path
7
+
8
+ import numpy as np
9
+ import pytest
10
+ import torch
11
+
12
+ import zipoop
13
+ from zipoop.masks import decode_mask
14
+ from zipoop.network import ModelConfig
15
+
16
+ DATA = os.environ.get("ZIPOOP_DATA")
17
+ SINGLE = Path(os.environ.get("ZIPOOP_SINGLE", "/mnt/e/zipoop/weights"))
18
+ needs_data = pytest.mark.skipif(not DATA, reason="ZIPOOP_DATA not set")
19
+
20
+
21
+ @pytest.fixture(scope="module")
22
+ def ds():
23
+ with zipoop.Dataset(DATA) as d:
24
+ yield d
25
+
26
+
27
+ @pytest.fixture(scope="module")
28
+ def windows(ds):
29
+ ws = ds.windows("chr21")
30
+ return random.Random(0).sample(ws, 3)
31
+
32
+
33
+ @needs_data
34
+ def test_manifest_verifies_small_chromosomes():
35
+ assert zipoop.verify(DATA, {"chrM", "chr22"}) == []
36
+
37
+
38
+ @needs_data
39
+ def test_window_listing_is_genome_ordered(ds):
40
+ starts = [int(w.split("_")[1]) for w in ds.windows("chr21")]
41
+ assert starts == sorted(starts)
42
+
43
+
44
+ @needs_data
45
+ def test_load_window_shapes_and_rna_rule(ds, windows):
46
+ w = ds.load_window(windows[0])
47
+ L, T = w.signal.shape
48
+ assert (L, T) == (32768, 1885) and w.dna.shape == (L,) and w.valid.shape == (L, T)
49
+ zero = torch.from_numpy(zipoop.zero_tracks())
50
+ assert w.valid[:, zero].all()
51
+ assert torch.isfinite(w.signal).all()
52
+
53
+
54
+ @needs_data
55
+ def test_slice_and_track_subset_match_full_decode(ds, windows):
56
+ dec = zipoop.Decoder(ds.read(windows[0]))
57
+ full = dec.decode()
58
+ part = dec.decode(1000, 5000, tracks=[3, 1884, 7])
59
+ expected = full[1000:5000][:, [3, 1884, 7]]
60
+ assert torch.allclose(part, expected, atol=1e-5, equal_nan=True)
61
+
62
+
63
+ @needs_data
64
+ def test_region_is_concatenation(ds):
65
+ ws = ds.windows("chr22")[:2]
66
+ r = ds.load_region(ws)
67
+ assert r.signal.shape[0] == 2 * 32768 and r.key == "+".join(ws)
68
+
69
+
70
+ @needs_data
71
+ def test_unknown_window_and_chrom(ds):
72
+ with pytest.raises(KeyError):
73
+ ds.read("chr21_1_2")
74
+ with pytest.raises(FileNotFoundError):
75
+ ds.windows("chrZ")
76
+
77
+
78
+ @needs_data
79
+ def test_bitwise_identical_to_pooper(ds, windows):
80
+ ref = pytest.importorskip("pooper.teacher_io")
81
+ from pooper.hybrid import archive_decoder
82
+ for w in windows:
83
+ path = SINGLE / "chr21" / f"{w}.npz"
84
+ if not path.exists():
85
+ pytest.skip("original shards not available")
86
+ a, b = ds.load_window(w), ref.load_window(path)
87
+ assert a.key == b.key
88
+ for name in ("dna", "signal", "valid"):
89
+ assert torch.equal(getattr(a, name), getattr(b, name)), name
90
+ old = archive_decoder(str(SINGLE / "chr21" / f"{windows[0]}.npz"))
91
+ new = zipoop.Decoder(ds.read(windows[0]))
92
+ for args in ({}, {"start": 4096, "end": 9000, "tracks": [0, 5, 1884]}, {"missing_nan": False}):
93
+ x, y = new.decode(**args), old.decode(**args)
94
+ assert torch.equal(torch.isnan(x), torch.isnan(y))
95
+ assert torch.equal(x.nan_to_num(), y.nan_to_num())
96
+
97
+
98
+ def test_model_config_rejects_unsupported_variants():
99
+ ok = {"width": 48, "rank": 48, "transformer_layers": 2, "attention_heads": 4, "downsample_levels": 7,
100
+ "pooling": "max", "position_encoding": "sinusoidal", "pair_channels": 0, "head_nonlinear_rank": 0}
101
+ assert ModelConfig.from_json(ok).width == 48
102
+ for bad in ({"pooling": "avg"}, {"position_encoding": "rope"}, {"pair_channels": 4}, {"head_nonlinear_rank": 8}):
103
+ with pytest.raises(ValueError):
104
+ ModelConfig.from_json({**ok, **bad})
105
+ legacy = {k: v for k, v in ok.items() if k != "pooling"}
106
+ with pytest.raises(ValueError):
107
+ ModelConfig.from_json(legacy)
108
+ with pytest.raises(ValueError):
109
+ ModelConfig.from_json({**ok, "width": 50})
110
+
111
+
112
+ def test_decode_mask_rejects_garbage():
113
+ with pytest.raises(ValueError):
114
+ decode_mask(b"\x05\x00", (10, 3))
115
+ with pytest.raises(ValueError):
116
+ decode_mask(b"\x80", (10, 1))
117
+
118
+
119
+ @needs_data
120
+ def test_dataset_is_picklable_for_spawn_workers(ds):
121
+ import pickle
122
+ clone = pickle.loads(pickle.dumps(ds))
123
+ assert clone.chroms() == ds.chroms()
@@ -0,0 +1,11 @@
1
+ """Zipoop: decoder and reader for the per-window teacher shards (merged per-chromosome npz)."""
2
+ from .dataset import Dataset, verify
3
+ from .decoder import Decoder
4
+ from .evaluation import calibrate, restore_real, summarize, window_pearson
5
+ from .panel import panel_tracks, zero_tracks
6
+ from .shard import Shard, read_shard
7
+ from .teacher import TeacherWindow, load_window
8
+
9
+ __version__ = "0.1.0"
10
+ __all__ = ["Dataset", "verify", "Decoder", "Shard", "read_shard", "TeacherWindow", "load_window",
11
+ "panel_tracks", "zero_tracks", "calibrate", "restore_real", "summarize", "window_pearson"]
@@ -0,0 +1,30 @@
1
+ import argparse
2
+ import sys
3
+
4
+ from .dataset import Dataset, verify
5
+
6
+
7
+ def main(argv=None):
8
+ parser = argparse.ArgumentParser(prog="zipoop", description="Zipoop teacher-shard dataset tools")
9
+ sub = parser.add_subparsers(dest="cmd", required=True)
10
+ v = sub.add_parser("verify", help="check <root>/*.npz against MANIFEST.tsv (size + sha256)")
11
+ v.add_argument("root")
12
+ v.add_argument("--chroms", default="", help="comma-separated subset")
13
+ v.add_argument("--workers", type=int, default=4, help="files hashed in parallel")
14
+ s = sub.add_parser("show", help="decode one window and print its shapes")
15
+ s.add_argument("root")
16
+ s.add_argument("window")
17
+ args = parser.parse_args(argv)
18
+ if args.cmd == "verify":
19
+ chroms = set(args.chroms.split(",")) if args.chroms else None
20
+ bad = verify(args.root, chroms, workers=args.workers, progress=lambda c, problem: print(f"{c}: {problem or 'ok'}", flush=True))
21
+ print(f"{len(bad)} problem(s)" if bad else "all files verified")
22
+ return 1 if bad else 0
23
+ with Dataset(args.root) as ds:
24
+ w = ds.load_window(args.window)
25
+ print(f"{w.key}: dna {tuple(w.dna.shape)}, signal {tuple(w.signal.shape)}, valid fraction {w.valid.float().mean():.4f}")
26
+ return 0
27
+
28
+
29
+ if __name__ == "__main__":
30
+ sys.exit(main())