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,326 @@
1
+ """Enhanced end-to-end differentiable variant calling pipeline.
2
+
3
+ This module provides an enhanced variant calling pipeline that composes:
4
+ 1. Quality filtering (preprocessing) - Filter low-quality bases
5
+ 2. Pileup generation - Aggregate reads at each position
6
+ 3. CNN classification - DeepVariant-style variant classification
7
+ 4. Quality recalibration - VQSR-style variant quality filtering
8
+
9
+ The pipeline is fully differentiable, enabling gradient-based optimization
10
+ of all components jointly.
11
+ """
12
+
13
+ import logging
14
+ from dataclasses import dataclass
15
+ from typing import Any
16
+
17
+ import jax.numpy as jnp
18
+ from datarax.core.config import OperatorConfig
19
+ from datarax.core.operator import OperatorModule
20
+ from flax import nnx
21
+ from jaxtyping import Array
22
+
23
+ from diffbio.operators.quality_filter import (
24
+ DifferentiableQualityFilter,
25
+ QualityFilterConfig,
26
+ )
27
+ from diffbio.operators.variant import (
28
+ CNNVariantClassifier,
29
+ CNNVariantClassifierConfig,
30
+ DifferentiablePileup,
31
+ PileupConfig,
32
+ SoftVariantQualityFilter,
33
+ VariantQualityFilterConfig,
34
+ )
35
+ from diffbio.utils.nn_utils import extract_windows_1d
36
+
37
+ logger = logging.getLogger(__name__)
38
+
39
+
40
+ @dataclass(frozen=True)
41
+ class EnhancedVariantCallingPipelineConfig(OperatorConfig):
42
+ # pylint: disable=too-many-instance-attributes
43
+ """Configuration for the enhanced variant calling pipeline.
44
+
45
+ Attributes:
46
+ reference_length: Length of reference sequence.
47
+ num_classes: Number of variant classes (default: 3 for ref/snp/indel).
48
+ quality_threshold: Initial quality score threshold for filtering.
49
+ pileup_window_size: Window size for pileup context.
50
+ cnn_input_height: Height of pileup image for CNN (coverage depth).
51
+ cnn_hidden_channels: Hidden channels for CNN classifier.
52
+ cnn_fc_dims: Fully connected layer dimensions for CNN.
53
+ cnn_dropout_rate: Dropout rate for CNN classifier.
54
+ quality_recal_n_components: Number of GMM components for quality recalibration.
55
+ quality_recal_n_features: Number of features for quality recalibration.
56
+ quality_recal_threshold: Threshold for quality filtering.
57
+ enable_preprocessing: Whether to enable quality filtering preprocessing.
58
+ enable_quality_recalibration: Whether to enable quality recalibration.
59
+ """
60
+
61
+ reference_length: int = 1000
62
+ num_classes: int = 3
63
+ quality_threshold: float = 20.0
64
+ pileup_window_size: int = 11
65
+ cnn_input_height: int = 100
66
+ cnn_hidden_channels: tuple[int, ...] = (64, 128, 256)
67
+ cnn_fc_dims: tuple[int, ...] = (256, 128)
68
+ cnn_dropout_rate: float = 0.1
69
+ quality_recal_n_components: int = 3
70
+ quality_recal_n_features: int = 4
71
+ quality_recal_threshold: float = 0.5
72
+ enable_preprocessing: bool = True
73
+ enable_quality_recalibration: bool = True
74
+
75
+ def __post_init__(self) -> None:
76
+ """Set non-default stochastic fields."""
77
+ object.__setattr__(self, "stochastic", True)
78
+ if self.stream_name is None:
79
+ object.__setattr__(self, "stream_name", "sample")
80
+ super().__post_init__()
81
+
82
+
83
+ class EnhancedVariantCallingPipeline(OperatorModule):
84
+ """Enhanced end-to-end differentiable variant calling pipeline.
85
+
86
+ This pipeline processes sequencing reads to call variants using a
87
+ DeepVariant-style CNN classifier followed by VQSR-style quality
88
+ recalibration:
89
+
90
+ Input data structure:
91
+ - reads: Float[Array, "num_reads read_length 4"] - One-hot encoded reads
92
+ - positions: Int[Array, "num_reads"] - Read start positions on reference
93
+ - quality: Float[Array, "num_reads read_length"] - Base quality scores
94
+
95
+ Output data structure (adds):
96
+ - pileup: Float[Array, "reference_length 4"] - Aggregated base frequencies
97
+ - logits: Float[Array, "reference_length num_classes"] - Raw predictions
98
+ - probabilities: Float[Array, "reference_length num_classes"] - Class probs
99
+ - quality_scores: Float[Array, "reference_length"] - Recalibrated quality
100
+ - filter_weights: Float[Array, "reference_length"] - Soft filter weights
101
+
102
+ The pipeline is fully differentiable, supporting gradient-based training
103
+ to optimize all components jointly.
104
+
105
+ Example:
106
+ ```python
107
+ config = EnhancedVariantCallingPipelineConfig(reference_length=1000)
108
+ pipeline = EnhancedVariantCallingPipeline(config, rngs=nnx.Rngs(42))
109
+ result, state, meta = pipeline.apply(data, {}, None)
110
+ probs = result["probabilities"]
111
+ ```
112
+ """
113
+
114
+ def __init__(
115
+ self,
116
+ config: EnhancedVariantCallingPipelineConfig,
117
+ *,
118
+ rngs: nnx.Rngs,
119
+ name: str | None = None,
120
+ ):
121
+ """Initialize the enhanced variant calling pipeline.
122
+
123
+ Args:
124
+ config: Pipeline configuration.
125
+ rngs: Random number generators for parameter initialization.
126
+ name: Optional name for the pipeline.
127
+ """
128
+ super().__init__(config, rngs=rngs, name=name)
129
+
130
+ # 1. Quality filter for preprocessing (optional)
131
+ self.quality_filter = (
132
+ DifferentiableQualityFilter(
133
+ QualityFilterConfig(initial_threshold=config.quality_threshold),
134
+ rngs=rngs,
135
+ )
136
+ if config.enable_preprocessing
137
+ else None
138
+ )
139
+
140
+ # 2. Pileup generation
141
+ self.pileup = DifferentiablePileup(
142
+ PileupConfig(
143
+ reference_length=config.reference_length,
144
+ use_quality_weights=True,
145
+ ),
146
+ rngs=rngs,
147
+ )
148
+
149
+ # 3. CNN classifier (DeepVariant-style)
150
+ # Use 4 channels (A, C, G, T) from the pileup
151
+ self.cnn_classifier = CNNVariantClassifier(
152
+ CNNVariantClassifierConfig(
153
+ num_classes=config.num_classes,
154
+ input_height=config.cnn_input_height,
155
+ input_width=config.pileup_window_size,
156
+ num_channels=4, # A, C, G, T from pileup
157
+ hidden_channels=config.cnn_hidden_channels,
158
+ fc_dims=config.cnn_fc_dims,
159
+ dropout_rate=config.cnn_dropout_rate,
160
+ ),
161
+ rngs=rngs,
162
+ )
163
+
164
+ # 4. Quality recalibration (optional)
165
+ self.quality_recalibration = (
166
+ SoftVariantQualityFilter(
167
+ VariantQualityFilterConfig(
168
+ n_components=config.quality_recal_n_components,
169
+ n_features=config.quality_recal_n_features,
170
+ threshold=config.quality_recal_threshold,
171
+ ),
172
+ rngs=rngs,
173
+ )
174
+ if config.enable_quality_recalibration
175
+ else None
176
+ )
177
+
178
+ def apply(
179
+ self,
180
+ data: dict[str, Array],
181
+ state: dict[str, Any],
182
+ metadata: dict[str, Any] | None,
183
+ random_params: Any = None, # noqa: ARG002
184
+ stats: dict[str, Any] | None = None, # noqa: ARG002
185
+ ) -> tuple[dict[str, Array], dict[str, Any], dict[str, Any] | None]:
186
+ """Apply the enhanced variant calling pipeline.
187
+
188
+ Args:
189
+ data: Input data containing:
190
+ - reads: Float[Array, "num_reads read_length 4"]
191
+ - positions: Int[Array, "num_reads"]
192
+ - quality: Float[Array, "num_reads read_length"]
193
+ state: Element state (passed through).
194
+ metadata: Element metadata (passed through).
195
+ random_params: Random parameters for stochastic operations.
196
+ stats: Optional statistics dict.
197
+
198
+ Returns:
199
+ Tuple of (output_data, state, metadata) where output_data contains
200
+ all input keys plus variant calling outputs.
201
+ """
202
+ reads = data["reads"]
203
+ positions = data["positions"]
204
+ quality = data["quality"]
205
+
206
+ # Step 1: Quality filtering (optional)
207
+ if self.quality_filter is not None:
208
+ # Apply quality filter per-base
209
+ num_reads, read_length, _ = reads.shape
210
+ reads_flat = reads.reshape(-1, 4)
211
+ quality_flat = quality.reshape(-1)
212
+
213
+ filter_data = {"sequence": reads_flat, "quality_scores": quality_flat}
214
+ filter_result, _, _ = self.quality_filter.apply(filter_data, {}, None)
215
+
216
+ reads = filter_result["sequence"].reshape(num_reads, read_length, 4)
217
+ quality = filter_result["quality_scores"].reshape(num_reads, read_length)
218
+
219
+ # Step 2: Generate pileup
220
+ pileup_data = {
221
+ "reads": reads,
222
+ "positions": positions,
223
+ "quality": quality,
224
+ }
225
+ pileup_result, _, _ = self.pileup.apply(pileup_data, {}, None)
226
+ pileup = pileup_result["pileup"] # (reference_length, 4)
227
+
228
+ # Step 3: CNN classification
229
+ # Extract windows around each position for CNN input
230
+ # CNN expects (batch, height, width, channels)
231
+ ref_length = self.config.reference_length
232
+ window_size = self.config.pileup_window_size
233
+
234
+ # Extract windows: (ref_length, window_size, 4)
235
+ # extract_windows_1d handles padding internally
236
+ windows = extract_windows_1d(pileup, window_size)
237
+
238
+ # Add depth dimension for CNN: (ref_length, height, width, channels)
239
+ # Use pileup as a simple "pileup image" - repeat to create height
240
+ cnn_input_height = self.config.cnn_input_height
241
+ # Create a simplified pileup image by repeating the window pattern
242
+ pileup_images = jnp.broadcast_to(
243
+ windows[:, None, :, :], (ref_length, cnn_input_height, window_size, 4)
244
+ )
245
+
246
+ # Apply CNN classifier
247
+ cnn_data = {"pileup_image": pileup_images}
248
+ cnn_result, _, _ = self.cnn_classifier.apply(cnn_data, {}, None)
249
+
250
+ logits = cnn_result["logits"] # (ref_length, num_classes)
251
+ probabilities = cnn_result["class_probs"] # CNN outputs class_probs
252
+
253
+ # Build output
254
+ output_data = {
255
+ **data,
256
+ "pileup": pileup,
257
+ "logits": logits,
258
+ "probabilities": probabilities,
259
+ }
260
+
261
+ # Step 4: Quality recalibration (optional)
262
+ if self.quality_recalibration is not None:
263
+ # Compute variant features for quality recalibration
264
+ # Features: depth, max_prob, entropy, strand_balance
265
+ depth = pileup.sum(axis=-1) # Total coverage at each position
266
+ max_prob = probabilities.max(axis=-1) # Confidence of prediction
267
+ entropy = -jnp.sum(
268
+ probabilities * jnp.log(probabilities + 1e-10), axis=-1
269
+ ) # Prediction entropy
270
+ # Simple strand balance proxy (ratio of first two bases)
271
+ strand_balance = jnp.abs(pileup[:, 0] - pileup[:, 1]) / (depth + 1e-10)
272
+
273
+ variant_features = jnp.stack(
274
+ [depth, max_prob, entropy, strand_balance], axis=-1
275
+ ) # (ref_length, 4)
276
+
277
+ recal_data = {"variant_features": variant_features}
278
+ recal_result, _, _ = self.quality_recalibration.apply(recal_data, {}, None)
279
+
280
+ output_data["quality_scores"] = recal_result["quality_scores"]
281
+ output_data["filter_weights"] = recal_result["filter_weights"]
282
+
283
+ return output_data, state, metadata
284
+
285
+
286
+ def create_enhanced_variant_calling_pipeline(
287
+ reference_length: int = 1000,
288
+ num_classes: int = 3,
289
+ pileup_window_size: int = 11,
290
+ cnn_hidden_channels: tuple[int, ...] | None = None,
291
+ cnn_fc_dims: tuple[int, ...] | None = None,
292
+ enable_preprocessing: bool = True,
293
+ enable_quality_recalibration: bool = True,
294
+ seed: int = 42,
295
+ ) -> EnhancedVariantCallingPipeline:
296
+ """Factory function to create an enhanced variant calling pipeline.
297
+
298
+ Args:
299
+ reference_length: Length of reference sequence.
300
+ num_classes: Number of variant classes.
301
+ pileup_window_size: Window size for pileup context.
302
+ cnn_hidden_channels: Hidden channels for CNN classifier.
303
+ cnn_fc_dims: Fully connected dimensions for CNN.
304
+ enable_preprocessing: Whether to enable quality filtering.
305
+ enable_quality_recalibration: Whether to enable quality recalibration.
306
+ seed: Random seed.
307
+
308
+ Returns:
309
+ Configured EnhancedVariantCallingPipeline instance.
310
+ """
311
+ if cnn_hidden_channels is None:
312
+ cnn_hidden_channels = (64, 128, 256)
313
+ if cnn_fc_dims is None:
314
+ cnn_fc_dims = (256, 128)
315
+
316
+ config = EnhancedVariantCallingPipelineConfig(
317
+ reference_length=reference_length,
318
+ num_classes=num_classes,
319
+ pileup_window_size=pileup_window_size,
320
+ cnn_hidden_channels=cnn_hidden_channels,
321
+ cnn_fc_dims=cnn_fc_dims,
322
+ enable_preprocessing=enable_preprocessing,
323
+ enable_quality_recalibration=enable_quality_recalibration,
324
+ )
325
+ rngs = nnx.Rngs(seed)
326
+ return EnhancedVariantCallingPipeline(config, rngs=rngs)