diffbio 0.1.0__py3-none-any.whl

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.
Files changed (202) hide show
  1. diffbio/__init__.py +39 -0
  2. diffbio/configs.py +75 -0
  3. diffbio/constants.py +204 -0
  4. diffbio/core/__init__.py +127 -0
  5. diffbio/core/base_operators.py +612 -0
  6. diffbio/core/data_types.py +260 -0
  7. diffbio/core/gnn_components.py +629 -0
  8. diffbio/core/graph_utils.py +149 -0
  9. diffbio/core/neural_components.py +270 -0
  10. diffbio/core/optimal_transport.py +133 -0
  11. diffbio/core/soft_ops/__init__.py +216 -0
  12. diffbio/core/soft_ops/_projections_permutahedron.py +1864 -0
  13. diffbio/core/soft_ops/_projections_simplex.py +240 -0
  14. diffbio/core/soft_ops/_projections_transport.py +508 -0
  15. diffbio/core/soft_ops/_sorting_network.py +204 -0
  16. diffbio/core/soft_ops/_types.py +15 -0
  17. diffbio/core/soft_ops/_utils.py +342 -0
  18. diffbio/core/soft_ops/autograd_safe.py +120 -0
  19. diffbio/core/soft_ops/comparison.py +235 -0
  20. diffbio/core/soft_ops/elementwise.py +309 -0
  21. diffbio/core/soft_ops/logical.py +146 -0
  22. diffbio/core/soft_ops/quantile.py +376 -0
  23. diffbio/core/soft_ops/selection.py +236 -0
  24. diffbio/core/soft_ops/sorting.py +926 -0
  25. diffbio/core/soft_ops/straight_through.py +261 -0
  26. diffbio/core/uncertainty.py +279 -0
  27. diffbio/evaluation/__init__.py +42 -0
  28. diffbio/evaluation/adapters.py +409 -0
  29. diffbio/evaluation/graders.py +223 -0
  30. diffbio/evaluation/problem.py +157 -0
  31. diffbio/evaluation/runner.py +277 -0
  32. diffbio/losses/__init__.py +59 -0
  33. diffbio/losses/alignment_losses.py +222 -0
  34. diffbio/losses/biological_regularization.py +288 -0
  35. diffbio/losses/metric_losses.py +139 -0
  36. diffbio/losses/singlecell_losses.py +387 -0
  37. diffbio/losses/statistical_losses.py +345 -0
  38. diffbio/operators/__init__.py +60 -0
  39. diffbio/operators/_count_vae.py +197 -0
  40. diffbio/operators/_loss_balancing.py +65 -0
  41. diffbio/operators/_masked_gene_transformer.py +118 -0
  42. diffbio/operators/_transformer_validation.py +50 -0
  43. diffbio/operators/alignment/__init__.py +51 -0
  44. diffbio/operators/alignment/profile_hmm.py +350 -0
  45. diffbio/operators/alignment/scoring.py +127 -0
  46. diffbio/operators/alignment/smith_waterman.py +261 -0
  47. diffbio/operators/alignment/soft_msa.py +419 -0
  48. diffbio/operators/assembly/__init__.py +27 -0
  49. diffbio/operators/assembly/gnn_assembly.py +252 -0
  50. diffbio/operators/assembly/metagenomic_binning.py +296 -0
  51. diffbio/operators/crispr/__init__.py +17 -0
  52. diffbio/operators/crispr/guide_scoring.py +269 -0
  53. diffbio/operators/drug_discovery/__init__.py +133 -0
  54. diffbio/operators/drug_discovery/_graph_utils.py +142 -0
  55. diffbio/operators/drug_discovery/admet_predictor.py +285 -0
  56. diffbio/operators/drug_discovery/attentive_fp.py +411 -0
  57. diffbio/operators/drug_discovery/dti.py +261 -0
  58. diffbio/operators/drug_discovery/fingerprint.py +490 -0
  59. diffbio/operators/drug_discovery/maccs_keys.py +267 -0
  60. diffbio/operators/drug_discovery/message_passing.py +200 -0
  61. diffbio/operators/drug_discovery/primitives.py +242 -0
  62. diffbio/operators/drug_discovery/property_predictor.py +163 -0
  63. diffbio/operators/drug_discovery/similarity.py +193 -0
  64. diffbio/operators/epigenomics/__init__.py +35 -0
  65. diffbio/operators/epigenomics/chromatin_state.py +491 -0
  66. diffbio/operators/epigenomics/contextual.py +288 -0
  67. diffbio/operators/epigenomics/fno_peak_calling.py +153 -0
  68. diffbio/operators/epigenomics/peak_calling.py +555 -0
  69. diffbio/operators/foundation_models/__init__.py +119 -0
  70. diffbio/operators/foundation_models/adapters.py +114 -0
  71. diffbio/operators/foundation_models/contracts.py +245 -0
  72. diffbio/operators/foundation_models/embedding_probe.py +83 -0
  73. diffbio/operators/foundation_models/experimental.py +128 -0
  74. diffbio/operators/foundation_models/foundation_model.py +332 -0
  75. diffbio/operators/foundation_models/frozen.py +59 -0
  76. diffbio/operators/foundation_models/precomputed.py +270 -0
  77. diffbio/operators/foundation_models/transformer_encoder.py +564 -0
  78. diffbio/operators/mapping/__init__.py +17 -0
  79. diffbio/operators/mapping/neural_mapper.py +493 -0
  80. diffbio/operators/metabolomics/__init__.py +39 -0
  81. diffbio/operators/metabolomics/spectral_similarity.py +315 -0
  82. diffbio/operators/molecular_dynamics/__init__.py +51 -0
  83. diffbio/operators/molecular_dynamics/force_field.py +265 -0
  84. diffbio/operators/molecular_dynamics/integrator.py +304 -0
  85. diffbio/operators/molecular_dynamics/primitives.py +115 -0
  86. diffbio/operators/multiomics/__init__.py +38 -0
  87. diffbio/operators/multiomics/hic_contact.py +377 -0
  88. diffbio/operators/multiomics/multiomics_vae.py +325 -0
  89. diffbio/operators/multiomics/spatial_deconvolution.py +316 -0
  90. diffbio/operators/multiomics/spatial_gene_detection.py +493 -0
  91. diffbio/operators/normalization/__init__.py +42 -0
  92. diffbio/operators/normalization/embedding.py +222 -0
  93. diffbio/operators/normalization/phate.py +400 -0
  94. diffbio/operators/normalization/umap.py +261 -0
  95. diffbio/operators/normalization/vae_normalizer.py +258 -0
  96. diffbio/operators/population/__init__.py +17 -0
  97. diffbio/operators/population/ancestry_estimation.py +274 -0
  98. diffbio/operators/preprocessing/__init__.py +76 -0
  99. diffbio/operators/preprocessing/adapter_removal.py +311 -0
  100. diffbio/operators/preprocessing/duplicate_filter.py +317 -0
  101. diffbio/operators/preprocessing/error_correction.py +287 -0
  102. diffbio/operators/protein/__init__.py +31 -0
  103. diffbio/operators/protein/secondary_structure.py +509 -0
  104. diffbio/operators/quality_filter.py +128 -0
  105. diffbio/operators/rna_structure/__init__.py +35 -0
  106. diffbio/operators/rna_structure/rna_folding.py +509 -0
  107. diffbio/operators/rnaseq/__init__.py +23 -0
  108. diffbio/operators/rnaseq/motif_discovery.py +251 -0
  109. diffbio/operators/rnaseq/splicing_psi.py +216 -0
  110. diffbio/operators/singlecell/__init__.py +193 -0
  111. diffbio/operators/singlecell/ambient_removal.py +333 -0
  112. diffbio/operators/singlecell/archetypes.py +191 -0
  113. diffbio/operators/singlecell/batch_correction.py +288 -0
  114. diffbio/operators/singlecell/cell_annotation.py +519 -0
  115. diffbio/operators/singlecell/communication.py +704 -0
  116. diffbio/operators/singlecell/differential_distribution.py +243 -0
  117. diffbio/operators/singlecell/doublet_detection.py +657 -0
  118. diffbio/operators/singlecell/downsampling.py +166 -0
  119. diffbio/operators/singlecell/enhanced_batch_correction.py +519 -0
  120. diffbio/operators/singlecell/grn_inference.py +336 -0
  121. diffbio/operators/singlecell/imputation.py +429 -0
  122. diffbio/operators/singlecell/knockdown_filter.py +176 -0
  123. diffbio/operators/singlecell/ot_trajectory.py +277 -0
  124. diffbio/operators/singlecell/simulation.py +444 -0
  125. diffbio/operators/singlecell/sindy_grn.py +247 -0
  126. diffbio/operators/singlecell/soft_clustering.py +211 -0
  127. diffbio/operators/singlecell/spatial_domains.py +677 -0
  128. diffbio/operators/singlecell/switch_de.py +184 -0
  129. diffbio/operators/singlecell/trajectory.py +447 -0
  130. diffbio/operators/singlecell/velocity.py +361 -0
  131. diffbio/operators/statistical/__init__.py +35 -0
  132. diffbio/operators/statistical/em_quantification.py +260 -0
  133. diffbio/operators/statistical/hmm.py +234 -0
  134. diffbio/operators/statistical/nb_glm.py +272 -0
  135. diffbio/operators/variant/__init__.py +64 -0
  136. diffbio/operators/variant/classifier.py +333 -0
  137. diffbio/operators/variant/cnn_classifier.py +255 -0
  138. diffbio/operators/variant/cnv_segmentation.py +678 -0
  139. diffbio/operators/variant/deepvariant_pileup.py +426 -0
  140. diffbio/operators/variant/pileup.py +240 -0
  141. diffbio/operators/variant/quality_recalibration.py +274 -0
  142. diffbio/pipelines/__init__.py +65 -0
  143. diffbio/pipelines/differential_expression.py +279 -0
  144. diffbio/pipelines/enhanced_variant_calling.py +326 -0
  145. diffbio/pipelines/perturbation.py +407 -0
  146. diffbio/pipelines/preprocessing.py +267 -0
  147. diffbio/pipelines/single_cell.py +366 -0
  148. diffbio/pipelines/variant_calling.py +490 -0
  149. diffbio/samplers/__init__.py +9 -0
  150. diffbio/samplers/perturbation_sampler.py +142 -0
  151. diffbio/sequences/__init__.py +34 -0
  152. diffbio/sequences/dna.py +239 -0
  153. diffbio/sources/__init__.py +149 -0
  154. diffbio/sources/_anndata_shared.py +89 -0
  155. diffbio/sources/_batch_iteration.py +37 -0
  156. diffbio/sources/_benchmark_source.py +152 -0
  157. diffbio/sources/_indexed_batch_source.py +38 -0
  158. diffbio/sources/_utils.py +45 -0
  159. diffbio/sources/anndata_interop.py +387 -0
  160. diffbio/sources/anndata_source.py +361 -0
  161. diffbio/sources/archive_ii.py +174 -0
  162. diffbio/sources/balifam.py +207 -0
  163. diffbio/sources/bam.py +265 -0
  164. diffbio/sources/bengrn_ground_truth.py +306 -0
  165. diffbio/sources/contextual_epigenomics.py +242 -0
  166. diffbio/sources/dti.py +359 -0
  167. diffbio/sources/embeddings.py +203 -0
  168. diffbio/sources/encode_peaks.py +223 -0
  169. diffbio/sources/fasta.py +226 -0
  170. diffbio/sources/immune_human.py +172 -0
  171. diffbio/sources/indexed_embeddings.py +128 -0
  172. diffbio/sources/indexed_view.py +191 -0
  173. diffbio/sources/molnet.py +493 -0
  174. diffbio/sources/multiomics.py +279 -0
  175. diffbio/sources/pancreas.py +108 -0
  176. diffbio/sources/perturbation/__init__.py +69 -0
  177. diffbio/sources/perturbation/_types.py +51 -0
  178. diffbio/sources/perturbation/_utils.py +125 -0
  179. diffbio/sources/perturbation/concat_source.py +115 -0
  180. diffbio/sources/perturbation/control_mapping.py +215 -0
  181. diffbio/sources/perturbation/experiment_config.py +261 -0
  182. diffbio/sources/perturbation/h5_metadata_cache.py +218 -0
  183. diffbio/sources/perturbation/output_space.py +52 -0
  184. diffbio/sources/perturbation/perturbation_source.py +513 -0
  185. diffbio/sources/seqfish.py +145 -0
  186. diffbio/sources/sequence_foundation.py +68 -0
  187. diffbio/sources/singlecell_foundation.py +68 -0
  188. diffbio/splitters/__init__.py +63 -0
  189. diffbio/splitters/base.py +251 -0
  190. diffbio/splitters/molecular.py +330 -0
  191. diffbio/splitters/perturbation.py +199 -0
  192. diffbio/splitters/random.py +217 -0
  193. diffbio/splitters/sequence.py +201 -0
  194. diffbio/utils/__init__.py +55 -0
  195. diffbio/utils/dependency_runtime.py +115 -0
  196. diffbio/utils/nn_utils.py +157 -0
  197. diffbio/utils/quality.py +45 -0
  198. diffbio/utils/training.py +585 -0
  199. diffbio-0.1.0.dist-info/METADATA +480 -0
  200. diffbio-0.1.0.dist-info/RECORD +202 -0
  201. diffbio-0.1.0.dist-info/WHEEL +4 -0
  202. diffbio-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,218 @@
1
+ """Singleton H5 metadata cache for fast categorical lookups.
2
+
3
+ Reads perturbation, cell type, and batch metadata directly from H5/H5AD files
4
+ via h5py, avoiding the overhead of loading the full AnnData object. Caches
5
+ results in a process-global singleton keyed by file path.
6
+
7
+ References:
8
+ - cell-load/src/cell_load/utils/data_utils.py (H5MetadataCache,
9
+ GlobalH5MetadataCache)
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import logging
15
+ import threading
16
+ from dataclasses import dataclass
17
+ from typing import Any
18
+
19
+ import numpy as np
20
+
21
+ from diffbio.sources.perturbation._utils import safe_decode_array
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ @dataclass(frozen=True, slots=True)
27
+ class _CategoricalEncoding:
28
+ """Decoded categorical labels plus per-row integer codes."""
29
+
30
+ categories: np.ndarray
31
+ codes: np.ndarray
32
+
33
+
34
+ def _require_h5py() -> Any:
35
+ """Import h5py, raising a clear error if not installed."""
36
+ try:
37
+ import h5py # noqa: PLC0415
38
+
39
+ return h5py
40
+ except ImportError as err:
41
+ raise ImportError(
42
+ "h5py is required for H5MetadataCache. Install with: uv pip install h5py"
43
+ ) from err
44
+
45
+
46
+ def _read_categorical_encoding(obs: Any, column: str) -> _CategoricalEncoding:
47
+ """Load decoded categories and integer codes for one obs column."""
48
+ dataset = obs[column]
49
+ if "categories" in dataset:
50
+ categories = safe_decode_array(dataset["categories"][:])
51
+ codes = dataset["codes"][:].astype(np.int32)
52
+ return _CategoricalEncoding(categories=categories, codes=codes)
53
+
54
+ raw = dataset[:]
55
+ unique_values, inverse_indices = np.unique(raw, return_inverse=True)
56
+ return _CategoricalEncoding(
57
+ categories=unique_values.astype(str),
58
+ codes=inverse_indices.astype(np.int32),
59
+ )
60
+
61
+
62
+ class H5MetadataCache:
63
+ """Cache for H5 file metadata to avoid repeated disk reads.
64
+
65
+ Extracts and caches categorical encodings (categories + integer codes) for
66
+ perturbation, cell type, and batch columns directly from the H5 file's
67
+ ``obs`` group. Also computes a boolean control mask.
68
+
69
+ Public properties:
70
+ pert_categories: Unique perturbation labels (string array).
71
+ pert_codes: Per-cell perturbation integer codes.
72
+ cell_type_categories: Unique cell type labels.
73
+ cell_type_codes: Per-cell cell type integer codes.
74
+ batch_categories: Unique batch labels.
75
+ batch_codes: Per-cell batch integer codes.
76
+ control_mask: Boolean mask, True for control cells.
77
+ control_pert_code: Integer code of the control perturbation.
78
+ n_cells: Total number of cells in the file.
79
+
80
+ Args:
81
+ h5_path: Path to the .h5ad or .h5 file.
82
+ pert_col: Obs column name for perturbation identity.
83
+ cell_type_key: Obs column name for cell type.
84
+ control_pert: Label identifying control cells.
85
+ batch_col: Obs column name for batch/plate.
86
+
87
+ Raises:
88
+ ValueError: If ``control_pert`` is not found in the perturbation categories.
89
+ """
90
+
91
+ __slots__ = (
92
+ "h5_path",
93
+ "_perturbation",
94
+ "_cell_type",
95
+ "_batch",
96
+ "control_mask",
97
+ "control_pert_code",
98
+ )
99
+
100
+ def __init__(
101
+ self,
102
+ h5_path: str,
103
+ pert_col: str = "perturbation",
104
+ cell_type_key: str = "cell_type",
105
+ control_pert: str = "non-targeting",
106
+ batch_col: str = "batch",
107
+ ) -> None:
108
+ h5py = _require_h5py()
109
+ self.h5_path = h5_path
110
+
111
+ with h5py.File(h5_path, "r") as f:
112
+ obs = f["obs"]
113
+ self._perturbation = _read_categorical_encoding(obs, pert_col)
114
+ self._cell_type = _read_categorical_encoding(obs, cell_type_key)
115
+ self._batch = _read_categorical_encoding(obs, batch_col)
116
+
117
+ # -- Control mask --
118
+ idx = np.where(self.pert_categories == control_pert)[0]
119
+ if idx.size == 0:
120
+ raise ValueError(
121
+ f"control_pert='{control_pert}' not found in {pert_col} "
122
+ f"categories: {list(self.pert_categories)}"
123
+ )
124
+ self.control_pert_code: int = int(idx[0])
125
+ self.control_mask: np.ndarray = self.pert_codes == self.control_pert_code
126
+
127
+ @property
128
+ def pert_categories(self) -> np.ndarray:
129
+ """Return unique perturbation labels."""
130
+ return self._perturbation.categories
131
+
132
+ @property
133
+ def pert_codes(self) -> np.ndarray:
134
+ """Return per-cell perturbation integer codes."""
135
+ return self._perturbation.codes
136
+
137
+ @property
138
+ def cell_type_categories(self) -> np.ndarray:
139
+ """Return unique cell type labels."""
140
+ return self._cell_type.categories
141
+
142
+ @property
143
+ def cell_type_codes(self) -> np.ndarray:
144
+ """Return per-cell integer cell type codes."""
145
+ return self._cell_type.codes
146
+
147
+ @property
148
+ def batch_categories(self) -> np.ndarray:
149
+ """Return unique batch labels."""
150
+ return self._batch.categories
151
+
152
+ @property
153
+ def batch_codes(self) -> np.ndarray:
154
+ """Return per-cell integer batch codes."""
155
+ return self._batch.codes
156
+
157
+ @property
158
+ def n_cells(self) -> int:
159
+ """Return total number of cells represented by the cached metadata."""
160
+ return int(self.pert_codes.shape[0])
161
+
162
+ def get_pert_names(self, codes: np.ndarray) -> np.ndarray:
163
+ """Return perturbation labels for the given integer codes."""
164
+ return self.pert_categories[codes]
165
+
166
+ def get_cell_type_names(self, codes: np.ndarray) -> np.ndarray:
167
+ """Return cell type labels for the given integer codes."""
168
+ return self.cell_type_categories[codes]
169
+
170
+ def get_batch_names(self, codes: np.ndarray) -> np.ndarray:
171
+ """Return batch labels for the given integer codes."""
172
+ return self.batch_categories[codes]
173
+
174
+
175
+ class GlobalH5MetadataCache:
176
+ """Singleton managing a shared dict of H5MetadataCache instances.
177
+
178
+ Thread-safe via a lock. Keyed by file path only; the first caller's
179
+ column parameters win for a given path.
180
+ """
181
+
182
+ _instance: GlobalH5MetadataCache | None = None
183
+ _lock = threading.Lock()
184
+ _cache: dict[str, H5MetadataCache]
185
+
186
+ def __new__(cls) -> GlobalH5MetadataCache:
187
+ """Return the singleton instance, creating it if necessary."""
188
+ with cls._lock:
189
+ if cls._instance is None:
190
+ cls._instance = super().__new__(cls)
191
+ cls._instance._cache = {}
192
+ return cls._instance
193
+
194
+ def get_cache(
195
+ self,
196
+ h5_path: str,
197
+ pert_col: str = "perturbation",
198
+ cell_type_key: str = "cell_type",
199
+ control_pert: str = "non-targeting",
200
+ batch_col: str = "batch",
201
+ ) -> H5MetadataCache:
202
+ """Get or create a metadata cache for the given file.
203
+
204
+ Args:
205
+ h5_path: Path to the H5/H5AD file.
206
+ pert_col: Perturbation column name.
207
+ cell_type_key: Cell type column name.
208
+ control_pert: Control perturbation label.
209
+ batch_col: Batch column name.
210
+
211
+ Returns:
212
+ Cached H5MetadataCache instance.
213
+ """
214
+ if h5_path not in self._cache:
215
+ self._cache[h5_path] = H5MetadataCache(
216
+ h5_path, pert_col, cell_type_key, control_pert, batch_col
217
+ )
218
+ return self._cache[h5_path]
@@ -0,0 +1,52 @@
1
+ """Output space management utilities for perturbation data.
2
+
3
+ Provides functions to select count representations based on the output space
4
+ mode.
5
+
6
+ References:
7
+ - cell-load/src/cell_load/dataset/_perturbation.py (output space logic)
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import jax.numpy as jnp
13
+ import numpy as np
14
+
15
+ from diffbio.sources.perturbation._types import OutputSpaceMode
16
+
17
+
18
+ def select_output_counts(
19
+ counts: jnp.ndarray,
20
+ hvg_indices: np.ndarray | None,
21
+ mode: OutputSpaceMode | str,
22
+ ) -> jnp.ndarray:
23
+ """Select count representation based on output space mode.
24
+
25
+ Args:
26
+ counts: Full count matrix of shape ``(n_cells, n_genes)``.
27
+ hvg_indices: Integer indices of highly variable genes. Required
28
+ when ``mode`` is ``OutputSpaceMode.GENE``.
29
+ mode: Output space mode (``"gene"``, ``"all"``, or ``"embedding"``).
30
+
31
+ Returns:
32
+ Subset or full count matrix. For embedding mode, returns an empty
33
+ array of shape ``(n_cells, 0)`` since counts are not used.
34
+
35
+ Raises:
36
+ ValueError: If mode is ``"gene"`` but ``hvg_indices`` is None.
37
+ """
38
+ mode = OutputSpaceMode(mode)
39
+
40
+ if mode == OutputSpaceMode.ALL:
41
+ return counts
42
+
43
+ if mode == OutputSpaceMode.GENE:
44
+ if hvg_indices is None:
45
+ raise ValueError(
46
+ "hvg_indices must be provided when output_space='gene'. "
47
+ "Set hvg_col in config to specify which var column marks HVGs."
48
+ )
49
+ return counts[:, hvg_indices]
50
+
51
+ # EMBEDDING mode: counts are not used
52
+ return jnp.empty((counts.shape[0], 0), dtype=counts.dtype)