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.
- diffbio/__init__.py +39 -0
- diffbio/configs.py +75 -0
- diffbio/constants.py +204 -0
- diffbio/core/__init__.py +127 -0
- diffbio/core/base_operators.py +612 -0
- diffbio/core/data_types.py +260 -0
- diffbio/core/gnn_components.py +629 -0
- diffbio/core/graph_utils.py +149 -0
- diffbio/core/neural_components.py +270 -0
- diffbio/core/optimal_transport.py +133 -0
- diffbio/core/soft_ops/__init__.py +216 -0
- diffbio/core/soft_ops/_projections_permutahedron.py +1864 -0
- diffbio/core/soft_ops/_projections_simplex.py +240 -0
- diffbio/core/soft_ops/_projections_transport.py +508 -0
- diffbio/core/soft_ops/_sorting_network.py +204 -0
- diffbio/core/soft_ops/_types.py +15 -0
- diffbio/core/soft_ops/_utils.py +342 -0
- diffbio/core/soft_ops/autograd_safe.py +120 -0
- diffbio/core/soft_ops/comparison.py +235 -0
- diffbio/core/soft_ops/elementwise.py +309 -0
- diffbio/core/soft_ops/logical.py +146 -0
- diffbio/core/soft_ops/quantile.py +376 -0
- diffbio/core/soft_ops/selection.py +236 -0
- diffbio/core/soft_ops/sorting.py +926 -0
- diffbio/core/soft_ops/straight_through.py +261 -0
- diffbio/core/uncertainty.py +279 -0
- diffbio/evaluation/__init__.py +42 -0
- diffbio/evaluation/adapters.py +409 -0
- diffbio/evaluation/graders.py +223 -0
- diffbio/evaluation/problem.py +157 -0
- diffbio/evaluation/runner.py +277 -0
- diffbio/losses/__init__.py +59 -0
- diffbio/losses/alignment_losses.py +222 -0
- diffbio/losses/biological_regularization.py +288 -0
- diffbio/losses/metric_losses.py +139 -0
- diffbio/losses/singlecell_losses.py +387 -0
- diffbio/losses/statistical_losses.py +345 -0
- diffbio/operators/__init__.py +60 -0
- diffbio/operators/_count_vae.py +197 -0
- diffbio/operators/_loss_balancing.py +65 -0
- diffbio/operators/_masked_gene_transformer.py +118 -0
- diffbio/operators/_transformer_validation.py +50 -0
- diffbio/operators/alignment/__init__.py +51 -0
- diffbio/operators/alignment/profile_hmm.py +350 -0
- diffbio/operators/alignment/scoring.py +127 -0
- diffbio/operators/alignment/smith_waterman.py +261 -0
- diffbio/operators/alignment/soft_msa.py +419 -0
- diffbio/operators/assembly/__init__.py +27 -0
- diffbio/operators/assembly/gnn_assembly.py +252 -0
- diffbio/operators/assembly/metagenomic_binning.py +296 -0
- diffbio/operators/crispr/__init__.py +17 -0
- diffbio/operators/crispr/guide_scoring.py +269 -0
- diffbio/operators/drug_discovery/__init__.py +133 -0
- diffbio/operators/drug_discovery/_graph_utils.py +142 -0
- diffbio/operators/drug_discovery/admet_predictor.py +285 -0
- diffbio/operators/drug_discovery/attentive_fp.py +411 -0
- diffbio/operators/drug_discovery/dti.py +261 -0
- diffbio/operators/drug_discovery/fingerprint.py +490 -0
- diffbio/operators/drug_discovery/maccs_keys.py +267 -0
- diffbio/operators/drug_discovery/message_passing.py +200 -0
- diffbio/operators/drug_discovery/primitives.py +242 -0
- diffbio/operators/drug_discovery/property_predictor.py +163 -0
- diffbio/operators/drug_discovery/similarity.py +193 -0
- diffbio/operators/epigenomics/__init__.py +35 -0
- diffbio/operators/epigenomics/chromatin_state.py +491 -0
- diffbio/operators/epigenomics/contextual.py +288 -0
- diffbio/operators/epigenomics/fno_peak_calling.py +153 -0
- diffbio/operators/epigenomics/peak_calling.py +555 -0
- diffbio/operators/foundation_models/__init__.py +119 -0
- diffbio/operators/foundation_models/adapters.py +114 -0
- diffbio/operators/foundation_models/contracts.py +245 -0
- diffbio/operators/foundation_models/embedding_probe.py +83 -0
- diffbio/operators/foundation_models/experimental.py +128 -0
- diffbio/operators/foundation_models/foundation_model.py +332 -0
- diffbio/operators/foundation_models/frozen.py +59 -0
- diffbio/operators/foundation_models/precomputed.py +270 -0
- diffbio/operators/foundation_models/transformer_encoder.py +564 -0
- diffbio/operators/mapping/__init__.py +17 -0
- diffbio/operators/mapping/neural_mapper.py +493 -0
- diffbio/operators/metabolomics/__init__.py +39 -0
- diffbio/operators/metabolomics/spectral_similarity.py +315 -0
- diffbio/operators/molecular_dynamics/__init__.py +51 -0
- diffbio/operators/molecular_dynamics/force_field.py +265 -0
- diffbio/operators/molecular_dynamics/integrator.py +304 -0
- diffbio/operators/molecular_dynamics/primitives.py +115 -0
- diffbio/operators/multiomics/__init__.py +38 -0
- diffbio/operators/multiomics/hic_contact.py +377 -0
- diffbio/operators/multiomics/multiomics_vae.py +325 -0
- diffbio/operators/multiomics/spatial_deconvolution.py +316 -0
- diffbio/operators/multiomics/spatial_gene_detection.py +493 -0
- diffbio/operators/normalization/__init__.py +42 -0
- diffbio/operators/normalization/embedding.py +222 -0
- diffbio/operators/normalization/phate.py +400 -0
- diffbio/operators/normalization/umap.py +261 -0
- diffbio/operators/normalization/vae_normalizer.py +258 -0
- diffbio/operators/population/__init__.py +17 -0
- diffbio/operators/population/ancestry_estimation.py +274 -0
- diffbio/operators/preprocessing/__init__.py +76 -0
- diffbio/operators/preprocessing/adapter_removal.py +311 -0
- diffbio/operators/preprocessing/duplicate_filter.py +317 -0
- diffbio/operators/preprocessing/error_correction.py +287 -0
- diffbio/operators/protein/__init__.py +31 -0
- diffbio/operators/protein/secondary_structure.py +509 -0
- diffbio/operators/quality_filter.py +128 -0
- diffbio/operators/rna_structure/__init__.py +35 -0
- diffbio/operators/rna_structure/rna_folding.py +509 -0
- diffbio/operators/rnaseq/__init__.py +23 -0
- diffbio/operators/rnaseq/motif_discovery.py +251 -0
- diffbio/operators/rnaseq/splicing_psi.py +216 -0
- diffbio/operators/singlecell/__init__.py +193 -0
- diffbio/operators/singlecell/ambient_removal.py +333 -0
- diffbio/operators/singlecell/archetypes.py +191 -0
- diffbio/operators/singlecell/batch_correction.py +288 -0
- diffbio/operators/singlecell/cell_annotation.py +519 -0
- diffbio/operators/singlecell/communication.py +704 -0
- diffbio/operators/singlecell/differential_distribution.py +243 -0
- diffbio/operators/singlecell/doublet_detection.py +657 -0
- diffbio/operators/singlecell/downsampling.py +166 -0
- diffbio/operators/singlecell/enhanced_batch_correction.py +519 -0
- diffbio/operators/singlecell/grn_inference.py +336 -0
- diffbio/operators/singlecell/imputation.py +429 -0
- diffbio/operators/singlecell/knockdown_filter.py +176 -0
- diffbio/operators/singlecell/ot_trajectory.py +277 -0
- diffbio/operators/singlecell/simulation.py +444 -0
- diffbio/operators/singlecell/sindy_grn.py +247 -0
- diffbio/operators/singlecell/soft_clustering.py +211 -0
- diffbio/operators/singlecell/spatial_domains.py +677 -0
- diffbio/operators/singlecell/switch_de.py +184 -0
- diffbio/operators/singlecell/trajectory.py +447 -0
- diffbio/operators/singlecell/velocity.py +361 -0
- diffbio/operators/statistical/__init__.py +35 -0
- diffbio/operators/statistical/em_quantification.py +260 -0
- diffbio/operators/statistical/hmm.py +234 -0
- diffbio/operators/statistical/nb_glm.py +272 -0
- diffbio/operators/variant/__init__.py +64 -0
- diffbio/operators/variant/classifier.py +333 -0
- diffbio/operators/variant/cnn_classifier.py +255 -0
- diffbio/operators/variant/cnv_segmentation.py +678 -0
- diffbio/operators/variant/deepvariant_pileup.py +426 -0
- diffbio/operators/variant/pileup.py +240 -0
- diffbio/operators/variant/quality_recalibration.py +274 -0
- diffbio/pipelines/__init__.py +65 -0
- diffbio/pipelines/differential_expression.py +279 -0
- diffbio/pipelines/enhanced_variant_calling.py +326 -0
- diffbio/pipelines/perturbation.py +407 -0
- diffbio/pipelines/preprocessing.py +267 -0
- diffbio/pipelines/single_cell.py +366 -0
- diffbio/pipelines/variant_calling.py +490 -0
- diffbio/samplers/__init__.py +9 -0
- diffbio/samplers/perturbation_sampler.py +142 -0
- diffbio/sequences/__init__.py +34 -0
- diffbio/sequences/dna.py +239 -0
- diffbio/sources/__init__.py +149 -0
- diffbio/sources/_anndata_shared.py +89 -0
- diffbio/sources/_batch_iteration.py +37 -0
- diffbio/sources/_benchmark_source.py +152 -0
- diffbio/sources/_indexed_batch_source.py +38 -0
- diffbio/sources/_utils.py +45 -0
- diffbio/sources/anndata_interop.py +387 -0
- diffbio/sources/anndata_source.py +361 -0
- diffbio/sources/archive_ii.py +174 -0
- diffbio/sources/balifam.py +207 -0
- diffbio/sources/bam.py +265 -0
- diffbio/sources/bengrn_ground_truth.py +306 -0
- diffbio/sources/contextual_epigenomics.py +242 -0
- diffbio/sources/dti.py +359 -0
- diffbio/sources/embeddings.py +203 -0
- diffbio/sources/encode_peaks.py +223 -0
- diffbio/sources/fasta.py +226 -0
- diffbio/sources/immune_human.py +172 -0
- diffbio/sources/indexed_embeddings.py +128 -0
- diffbio/sources/indexed_view.py +191 -0
- diffbio/sources/molnet.py +493 -0
- diffbio/sources/multiomics.py +279 -0
- diffbio/sources/pancreas.py +108 -0
- diffbio/sources/perturbation/__init__.py +69 -0
- diffbio/sources/perturbation/_types.py +51 -0
- diffbio/sources/perturbation/_utils.py +125 -0
- diffbio/sources/perturbation/concat_source.py +115 -0
- diffbio/sources/perturbation/control_mapping.py +215 -0
- diffbio/sources/perturbation/experiment_config.py +261 -0
- diffbio/sources/perturbation/h5_metadata_cache.py +218 -0
- diffbio/sources/perturbation/output_space.py +52 -0
- diffbio/sources/perturbation/perturbation_source.py +513 -0
- diffbio/sources/seqfish.py +145 -0
- diffbio/sources/sequence_foundation.py +68 -0
- diffbio/sources/singlecell_foundation.py +68 -0
- diffbio/splitters/__init__.py +63 -0
- diffbio/splitters/base.py +251 -0
- diffbio/splitters/molecular.py +330 -0
- diffbio/splitters/perturbation.py +199 -0
- diffbio/splitters/random.py +217 -0
- diffbio/splitters/sequence.py +201 -0
- diffbio/utils/__init__.py +55 -0
- diffbio/utils/dependency_runtime.py +115 -0
- diffbio/utils/nn_utils.py +157 -0
- diffbio/utils/quality.py +45 -0
- diffbio/utils/training.py +585 -0
- diffbio-0.1.0.dist-info/METADATA +480 -0
- diffbio-0.1.0.dist-info/RECORD +202 -0
- diffbio-0.1.0.dist-info/WHEEL +4 -0
- diffbio-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"""Smooth Smith-Waterman alignment operator.
|
|
2
|
+
|
|
3
|
+
This module provides a differentiable implementation of the Smith-Waterman
|
|
4
|
+
local alignment algorithm using the logsumexp relaxation (SMURF-style).
|
|
5
|
+
|
|
6
|
+
Key technique: Replace max with logsumexp and argmax with softmax
|
|
7
|
+
to enable gradient flow through the alignment computation.
|
|
8
|
+
|
|
9
|
+
Reference:
|
|
10
|
+
Petti et al. "End-to-end learning of multiple sequence alignments with
|
|
11
|
+
differentiable Smith-Waterman." Bioinformatics 39(1):btac724, 2023.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import logging
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
from typing import Any, NamedTuple
|
|
17
|
+
|
|
18
|
+
import jax
|
|
19
|
+
import jax.numpy as jnp
|
|
20
|
+
from flax import nnx
|
|
21
|
+
from jaxtyping import Array, Float, PyTree
|
|
22
|
+
|
|
23
|
+
from diffbio.configs import TemperatureConfig
|
|
24
|
+
from diffbio.constants import DEFAULT_GAP_EXTEND, DEFAULT_GAP_OPEN
|
|
25
|
+
from diffbio.core.base_operators import TemperatureOperator
|
|
26
|
+
from diffbio.utils.nn_utils import init_learnable_param
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(frozen=True)
|
|
32
|
+
class SmithWatermanConfig(TemperatureConfig):
|
|
33
|
+
"""Configuration for SmoothSmithWaterman.
|
|
34
|
+
|
|
35
|
+
Attributes:
|
|
36
|
+
temperature: Temperature for logsumexp smoothing.
|
|
37
|
+
Lower = sharper (closer to hard max), Higher = smoother.
|
|
38
|
+
gap_open: Penalty for opening a gap.
|
|
39
|
+
gap_extend: Penalty for extending a gap.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
cacheable: bool = True
|
|
43
|
+
gap_open: float = DEFAULT_GAP_OPEN
|
|
44
|
+
gap_extend: float = DEFAULT_GAP_EXTEND
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class AlignmentResult(NamedTuple):
|
|
48
|
+
"""Result of a smooth alignment.
|
|
49
|
+
|
|
50
|
+
Attributes:
|
|
51
|
+
score: The soft alignment score.
|
|
52
|
+
alignment_matrix: The DP matrix H[i,j] of shape (len1+1, len2+1).
|
|
53
|
+
soft_alignment: Soft alignment matrix showing position correspondences.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
score: Float[Array, ""]
|
|
57
|
+
alignment_matrix: Float[Array, "len1_plus1 len2_plus1"]
|
|
58
|
+
soft_alignment: Float[Array, "len1 len2"]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class SmoothSmithWaterman(TemperatureOperator):
|
|
62
|
+
"""Differentiable Smith-Waterman local alignment.
|
|
63
|
+
|
|
64
|
+
This operator implements a smooth version of the Smith-Waterman algorithm
|
|
65
|
+
where max operations are replaced with logsumexp, enabling gradient flow
|
|
66
|
+
through the alignment computation.
|
|
67
|
+
|
|
68
|
+
The smoothness is controlled by the temperature parameter:
|
|
69
|
+
- temperature -> 0: Approaches hard max (standard Smith-Waterman)
|
|
70
|
+
- temperature -> inf: Uniform averaging
|
|
71
|
+
|
|
72
|
+
Inherits from TemperatureOperator to get:
|
|
73
|
+
|
|
74
|
+
- Learnable temperature parameter management
|
|
75
|
+
- soft_max() method using logsumexp relaxation
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
config: SmithWatermanConfig with alignment parameters.
|
|
79
|
+
scoring_matrix: Scoring matrix for matches/mismatches.
|
|
80
|
+
rngs: Flax NNX random number generators (optional).
|
|
81
|
+
name: Optional operator name.
|
|
82
|
+
|
|
83
|
+
Example:
|
|
84
|
+
```python
|
|
85
|
+
config = SmithWatermanConfig(temperature=1.0)
|
|
86
|
+
scoring = create_dna_scoring_matrix(match=2.0, mismatch=-1.0)
|
|
87
|
+
aligner = SmoothSmithWaterman(config, scoring_matrix=scoring)
|
|
88
|
+
result = aligner.align(seq1, seq2)
|
|
89
|
+
print(result.score)
|
|
90
|
+
```
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
def __init__(
|
|
94
|
+
self,
|
|
95
|
+
config: SmithWatermanConfig,
|
|
96
|
+
scoring_matrix: Array,
|
|
97
|
+
*,
|
|
98
|
+
rngs: nnx.Rngs | None = None,
|
|
99
|
+
name: str | None = None,
|
|
100
|
+
):
|
|
101
|
+
"""Initialize the smooth Smith-Waterman aligner.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
config: Alignment configuration.
|
|
105
|
+
scoring_matrix: Scoring matrix (alphabet_size, alphabet_size).
|
|
106
|
+
rngs: Random number generators (optional).
|
|
107
|
+
name: Optional operator name.
|
|
108
|
+
"""
|
|
109
|
+
super().__init__(config, rngs=rngs, name=name)
|
|
110
|
+
|
|
111
|
+
# Domain-specific learnable parameters (temperature managed by base class)
|
|
112
|
+
self.scoring_matrix = nnx.Param(scoring_matrix)
|
|
113
|
+
self.gap_open = init_learnable_param(config.gap_open)
|
|
114
|
+
self.gap_extend = init_learnable_param(config.gap_extend)
|
|
115
|
+
|
|
116
|
+
def _compute_score_matrix(
|
|
117
|
+
self,
|
|
118
|
+
seq1: Float[Array, "len1 alphabet"],
|
|
119
|
+
seq2: Float[Array, "len2 alphabet"],
|
|
120
|
+
) -> Float[Array, "len1 len2"]:
|
|
121
|
+
"""Compute pairwise scoring matrix between sequences.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
seq1: First sequence, one-hot encoded (len1, alphabet_size).
|
|
125
|
+
seq2: Second sequence, one-hot encoded (len2, alphabet_size).
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
Score matrix of shape (len1, len2).
|
|
129
|
+
"""
|
|
130
|
+
# S[i,j] = seq1[i] @ scoring_matrix @ seq2[j].T
|
|
131
|
+
# Using einsum for clarity
|
|
132
|
+
scoring = self.scoring_matrix[...]
|
|
133
|
+
return jnp.einsum("ia,ab,jb->ij", seq1, scoring, seq2)
|
|
134
|
+
|
|
135
|
+
def align(
|
|
136
|
+
self,
|
|
137
|
+
seq1: Float[Array, "len1 alphabet"],
|
|
138
|
+
seq2: Float[Array, "len2 alphabet"],
|
|
139
|
+
) -> AlignmentResult:
|
|
140
|
+
"""Perform smooth Smith-Waterman local alignment.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
seq1: First sequence, one-hot encoded (len1, alphabet_size).
|
|
144
|
+
seq2: Second sequence, one-hot encoded (len2, alphabet_size).
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
AlignmentResult with score, alignment matrix, and soft alignment.
|
|
148
|
+
"""
|
|
149
|
+
len1, len2 = seq1.shape[0], seq2.shape[0]
|
|
150
|
+
|
|
151
|
+
# Compute pairwise scores
|
|
152
|
+
score_matrix = self._compute_score_matrix(seq1, seq2)
|
|
153
|
+
|
|
154
|
+
# Gap penalties
|
|
155
|
+
gap_open = self.gap_open[...]
|
|
156
|
+
gap_extend = self.gap_extend[...]
|
|
157
|
+
# Simplified: use linear gap penalty (gap_open + gap_extend per position)
|
|
158
|
+
gap_penalty = gap_open + gap_extend
|
|
159
|
+
|
|
160
|
+
# Initialize DP matrices
|
|
161
|
+
# H[i,j] = alignment score ending at seq1[i-1], seq2[j-1]
|
|
162
|
+
# Using scan for efficient JAX computation
|
|
163
|
+
|
|
164
|
+
# Initialize H matrix with zeros
|
|
165
|
+
H = jnp.zeros((len1 + 1, len2 + 1))
|
|
166
|
+
|
|
167
|
+
# Fill the DP matrix row by row
|
|
168
|
+
# Note: fori_loop body signature is (i, carry) -> carry
|
|
169
|
+
def fill_row(i, H):
|
|
170
|
+
"""Fill row i+1 of the DP matrix."""
|
|
171
|
+
|
|
172
|
+
def cell_update(H_prev_col, j_idx):
|
|
173
|
+
"""Update single cell H[i+1, j+1]."""
|
|
174
|
+
j = j_idx.astype(jnp.int32)
|
|
175
|
+
s = score_matrix[i, j]
|
|
176
|
+
diag = H[i, j] + s
|
|
177
|
+
up = H[i, j + 1] + gap_penalty
|
|
178
|
+
left = H_prev_col + gap_penalty
|
|
179
|
+
|
|
180
|
+
# Use inherited soft_max from TemperatureOperator
|
|
181
|
+
candidates = jnp.stack([jnp.array(0.0), diag, up, left], axis=-1)
|
|
182
|
+
h_new = self.soft_max(candidates, axis=-1)
|
|
183
|
+
return h_new, h_new
|
|
184
|
+
|
|
185
|
+
# Scan across columns
|
|
186
|
+
_, new_row = jax.lax.scan(
|
|
187
|
+
cell_update, jnp.array(0.0), jnp.arange(len2, dtype=jnp.int32)
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Update H matrix
|
|
191
|
+
H = H.at[i + 1, 1:].set(new_row)
|
|
192
|
+
return H
|
|
193
|
+
|
|
194
|
+
# Fill all rows using fori_loop for efficiency
|
|
195
|
+
H = jax.lax.fori_loop(0, len1, fill_row, H)
|
|
196
|
+
|
|
197
|
+
# Compute final score as smooth max over all positions
|
|
198
|
+
# (local alignment can end anywhere)
|
|
199
|
+
final_candidates = jnp.stack([jnp.array(0.0), jnp.max(H)], axis=-1)
|
|
200
|
+
final_score = self.soft_max(final_candidates, axis=-1)
|
|
201
|
+
|
|
202
|
+
# Compute soft alignment (position correspondence probabilities)
|
|
203
|
+
# This is the softmax of the DP matrix (excluding borders)
|
|
204
|
+
H_inner = H[1:, 1:] # (len1, len2)
|
|
205
|
+
temp = self._temperature # Use property from TemperatureOperator
|
|
206
|
+
soft_alignment = jax.nn.softmax(H_inner.flatten() / temp).reshape(len1, len2)
|
|
207
|
+
|
|
208
|
+
return AlignmentResult(
|
|
209
|
+
score=final_score,
|
|
210
|
+
alignment_matrix=H,
|
|
211
|
+
soft_alignment=soft_alignment,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
def apply(
|
|
215
|
+
self,
|
|
216
|
+
data: PyTree,
|
|
217
|
+
state: PyTree,
|
|
218
|
+
metadata: dict[str, Any] | None,
|
|
219
|
+
random_params: Any = None,
|
|
220
|
+
stats: dict[str, Any] | None = None,
|
|
221
|
+
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
222
|
+
"""Apply alignment to sequence pair data.
|
|
223
|
+
|
|
224
|
+
This method implements the OperatorModule interface for batch processing.
|
|
225
|
+
It expects data containing two sequences and returns alignment results.
|
|
226
|
+
|
|
227
|
+
Note: Output preserves input keys for Datarax vmap compatibility,
|
|
228
|
+
while adding alignment result keys.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
data: Dictionary containing:
|
|
232
|
+
- "seq1": First sequence, one-hot encoded (len1, alphabet_size)
|
|
233
|
+
- "seq2": Second sequence, one-hot encoded (len2, alphabet_size)
|
|
234
|
+
state: Element state (passed through unchanged)
|
|
235
|
+
metadata: Element metadata (passed through unchanged)
|
|
236
|
+
random_params: Not used (deterministic operator)
|
|
237
|
+
stats: Not used
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
Tuple of (transformed_data, state, metadata):
|
|
241
|
+
- transformed_data contains input sequences plus alignment results
|
|
242
|
+
(score, alignment_matrix, soft_alignment)
|
|
243
|
+
- state is passed through unchanged
|
|
244
|
+
- metadata is passed through unchanged
|
|
245
|
+
"""
|
|
246
|
+
seq1 = data["seq1"]
|
|
247
|
+
seq2 = data["seq2"]
|
|
248
|
+
|
|
249
|
+
# Perform alignment
|
|
250
|
+
result = self.align(seq1, seq2)
|
|
251
|
+
|
|
252
|
+
# Build output data - preserve input keys for Datarax vmap compatibility
|
|
253
|
+
transformed_data = {
|
|
254
|
+
"seq1": seq1,
|
|
255
|
+
"seq2": seq2,
|
|
256
|
+
"score": result.score,
|
|
257
|
+
"alignment_matrix": result.alignment_matrix,
|
|
258
|
+
"soft_alignment": result.soft_alignment,
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return transformed_data, state, metadata
|
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
"""Soft progressive multiple sequence alignment operator.
|
|
2
|
+
|
|
3
|
+
This module provides differentiable multiple sequence alignment using
|
|
4
|
+
soft operations throughout the alignment process.
|
|
5
|
+
|
|
6
|
+
Key technique: Uses neural network sequence encoders to compute pairwise
|
|
7
|
+
similarities, builds a soft guide tree, and performs progressive profile
|
|
8
|
+
alignment with soft gap handling.
|
|
9
|
+
|
|
10
|
+
Applications: Multiple sequence alignment for homology detection, phylogenetic
|
|
11
|
+
analysis, and protein family characterization.
|
|
12
|
+
|
|
13
|
+
Inherits from TemperatureOperator to get:
|
|
14
|
+
|
|
15
|
+
- _temperature property for temperature-controlled smoothing
|
|
16
|
+
- soft_max() for logsumexp-based smooth maximum
|
|
17
|
+
- soft_argmax() for soft position selection
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import logging
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
import jax
|
|
25
|
+
import jax.numpy as jnp
|
|
26
|
+
from artifex.generative_models.core.base import MLP
|
|
27
|
+
from datarax.core.config import OperatorConfig
|
|
28
|
+
from flax import nnx
|
|
29
|
+
from jaxtyping import Array, Float, PyTree
|
|
30
|
+
|
|
31
|
+
from diffbio.core.base_operators import TemperatureOperator
|
|
32
|
+
from diffbio.utils.nn_utils import (
|
|
33
|
+
ARTIFEX_GELU_MLP_KWARGS,
|
|
34
|
+
ARTIFEX_GELU_NO_OUTPUT_MLP_KWARGS,
|
|
35
|
+
ensure_rngs,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
logger = logging.getLogger(__name__)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass(frozen=True)
|
|
42
|
+
class SoftProgressiveMSAConfig(OperatorConfig):
|
|
43
|
+
"""Configuration for SoftProgressiveMSA.
|
|
44
|
+
|
|
45
|
+
Attributes:
|
|
46
|
+
max_seq_length: Maximum sequence length.
|
|
47
|
+
hidden_dim: Hidden dimension for neural networks.
|
|
48
|
+
num_layers: Number of encoder layers.
|
|
49
|
+
alphabet_size: Size of sequence alphabet (4 for DNA, 20 for protein).
|
|
50
|
+
temperature: Temperature for softmax operations.
|
|
51
|
+
gap_open_penalty: Gap opening penalty.
|
|
52
|
+
gap_extend_penalty: Gap extension penalty.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
max_seq_length: int = 100
|
|
56
|
+
hidden_dim: int = 64
|
|
57
|
+
num_layers: int = 2
|
|
58
|
+
alphabet_size: int = 4
|
|
59
|
+
temperature: float = 1.0
|
|
60
|
+
gap_open_penalty: float = -10.0
|
|
61
|
+
gap_extend_penalty: float = -1.0
|
|
62
|
+
|
|
63
|
+
def __post_init__(self) -> None:
|
|
64
|
+
"""Validate soft MSA configuration."""
|
|
65
|
+
super().__post_init__()
|
|
66
|
+
if self.num_layers < 1:
|
|
67
|
+
raise ValueError("SoftProgressiveMSAConfig.num_layers must be at least 1.")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class SequenceEncoder(nnx.Module):
|
|
71
|
+
"""Encoder for biological sequences."""
|
|
72
|
+
|
|
73
|
+
def __init__(
|
|
74
|
+
self,
|
|
75
|
+
alphabet_size: int,
|
|
76
|
+
hidden_dim: int,
|
|
77
|
+
num_layers: int,
|
|
78
|
+
*,
|
|
79
|
+
rngs: nnx.Rngs,
|
|
80
|
+
):
|
|
81
|
+
"""Initialize the sequence encoder.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
alphabet_size: Size of input alphabet.
|
|
85
|
+
hidden_dim: Hidden dimension.
|
|
86
|
+
num_layers: Number of layers.
|
|
87
|
+
rngs: Random number generators.
|
|
88
|
+
"""
|
|
89
|
+
super().__init__()
|
|
90
|
+
self.backbone = MLP(
|
|
91
|
+
hidden_dims=[hidden_dim] * num_layers,
|
|
92
|
+
in_features=alphabet_size,
|
|
93
|
+
rngs=rngs,
|
|
94
|
+
**ARTIFEX_GELU_MLP_KWARGS,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Output projection for sequence embedding
|
|
98
|
+
self.output_proj = nnx.Linear(
|
|
99
|
+
in_features=hidden_dim,
|
|
100
|
+
out_features=hidden_dim,
|
|
101
|
+
rngs=rngs,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
def __call__(
|
|
105
|
+
self,
|
|
106
|
+
sequence: Float[Array, "seq_len alphabet_size"],
|
|
107
|
+
) -> Float[Array, "hidden_dim"]:
|
|
108
|
+
"""Encode a sequence to a fixed-size embedding.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
sequence: One-hot encoded sequence.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Sequence embedding vector.
|
|
115
|
+
"""
|
|
116
|
+
backbone_output = self.backbone(sequence)
|
|
117
|
+
if isinstance(backbone_output, tuple):
|
|
118
|
+
raise TypeError("Soft MSA sequence backbone must return a single tensor.")
|
|
119
|
+
|
|
120
|
+
# Global average pooling to get fixed-size embedding
|
|
121
|
+
embedding = jnp.mean(backbone_output, axis=0) # (hidden_dim,)
|
|
122
|
+
embedding = self.output_proj(embedding)
|
|
123
|
+
|
|
124
|
+
return embedding
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class ProfileBuilder(nnx.Module):
|
|
128
|
+
"""Builds alignment profiles from sequences."""
|
|
129
|
+
|
|
130
|
+
def __init__(
|
|
131
|
+
self,
|
|
132
|
+
hidden_dim: int,
|
|
133
|
+
alphabet_size: int,
|
|
134
|
+
*,
|
|
135
|
+
rngs: nnx.Rngs,
|
|
136
|
+
):
|
|
137
|
+
"""Initialize the profile builder.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
hidden_dim: Hidden dimension.
|
|
141
|
+
alphabet_size: Alphabet size.
|
|
142
|
+
rngs: Random number generators.
|
|
143
|
+
"""
|
|
144
|
+
super().__init__()
|
|
145
|
+
|
|
146
|
+
self.hidden_dim = hidden_dim
|
|
147
|
+
self.alphabet_size = alphabet_size
|
|
148
|
+
|
|
149
|
+
self.backbone = MLP(
|
|
150
|
+
hidden_dims=[hidden_dim, alphabet_size],
|
|
151
|
+
in_features=alphabet_size,
|
|
152
|
+
rngs=rngs,
|
|
153
|
+
**ARTIFEX_GELU_NO_OUTPUT_MLP_KWARGS,
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
def __call__(
|
|
157
|
+
self,
|
|
158
|
+
sequences: Float[Array, "n_seqs seq_len alphabet_size"],
|
|
159
|
+
weights: Float[Array, "n_seqs"],
|
|
160
|
+
) -> Float[Array, "seq_len alphabet_size"]:
|
|
161
|
+
"""Build a profile from weighted sequences.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
sequences: Stack of aligned sequences.
|
|
165
|
+
weights: Weights for each sequence.
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Profile (position-specific scoring matrix).
|
|
169
|
+
"""
|
|
170
|
+
# Weighted average of sequences
|
|
171
|
+
weights = weights / (jnp.sum(weights) + 1e-8)
|
|
172
|
+
profile = jnp.einsum("n,nla->la", weights, sequences)
|
|
173
|
+
|
|
174
|
+
# Refine profile
|
|
175
|
+
refinement = self.backbone(profile)
|
|
176
|
+
if isinstance(refinement, tuple):
|
|
177
|
+
raise TypeError("Soft MSA profile backbone must return a single tensor.")
|
|
178
|
+
profile = profile + 0.1 * refinement # Small residual update
|
|
179
|
+
|
|
180
|
+
# Normalize to valid probability distribution
|
|
181
|
+
profile = jax.nn.softmax(profile, axis=-1)
|
|
182
|
+
|
|
183
|
+
return profile
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class SoftProgressiveMSA(TemperatureOperator):
|
|
187
|
+
"""Differentiable progressive multiple sequence alignment.
|
|
188
|
+
|
|
189
|
+
This operator performs multiple sequence alignment using soft
|
|
190
|
+
operations that maintain gradient flow throughout the process.
|
|
191
|
+
|
|
192
|
+
Algorithm:
|
|
193
|
+
1. Encode each sequence to get embeddings
|
|
194
|
+
2. Compute pairwise distances from embeddings
|
|
195
|
+
3. Build soft guide tree from distances
|
|
196
|
+
4. Progressive alignment following guide tree order
|
|
197
|
+
5. Build consensus profile
|
|
198
|
+
|
|
199
|
+
Inherits from TemperatureOperator to get:
|
|
200
|
+
|
|
201
|
+
- _temperature property for temperature-controlled smoothing
|
|
202
|
+
- soft_max() for logsumexp-based smooth maximum
|
|
203
|
+
- soft_argmax() for soft position selection
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
config: SoftProgressiveMSAConfig with model parameters.
|
|
207
|
+
rngs: Flax NNX random number generators.
|
|
208
|
+
name: Optional operator name.
|
|
209
|
+
|
|
210
|
+
Example:
|
|
211
|
+
```python
|
|
212
|
+
config = SoftProgressiveMSAConfig(max_seq_length=100)
|
|
213
|
+
msa = SoftProgressiveMSA(config, rngs=nnx.Rngs(42))
|
|
214
|
+
data = {"sequences": seqs} # (n_seqs, seq_len, alphabet_size)
|
|
215
|
+
result, state, meta = msa.apply(data, {}, None)
|
|
216
|
+
```
|
|
217
|
+
"""
|
|
218
|
+
|
|
219
|
+
def __init__(
|
|
220
|
+
self,
|
|
221
|
+
config: SoftProgressiveMSAConfig,
|
|
222
|
+
*,
|
|
223
|
+
rngs: nnx.Rngs | None = None,
|
|
224
|
+
name: str | None = None,
|
|
225
|
+
):
|
|
226
|
+
"""Initialize the soft progressive MSA operator.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
config: MSA configuration.
|
|
230
|
+
rngs: Random number generators for initialization.
|
|
231
|
+
name: Optional operator name.
|
|
232
|
+
"""
|
|
233
|
+
super().__init__(config, rngs=rngs, name=name)
|
|
234
|
+
|
|
235
|
+
rngs = ensure_rngs(rngs)
|
|
236
|
+
|
|
237
|
+
self.hidden_dim = config.hidden_dim
|
|
238
|
+
# Temperature is now managed by TemperatureOperator via self._temperature
|
|
239
|
+
self.alphabet_size = config.alphabet_size
|
|
240
|
+
|
|
241
|
+
# Sequence encoder for computing pairwise similarities
|
|
242
|
+
self.seq_encoder = SequenceEncoder(
|
|
243
|
+
alphabet_size=config.alphabet_size,
|
|
244
|
+
hidden_dim=config.hidden_dim,
|
|
245
|
+
num_layers=config.num_layers,
|
|
246
|
+
rngs=rngs,
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
# Profile builder for progressive alignment
|
|
250
|
+
self.profile_builder = ProfileBuilder(
|
|
251
|
+
hidden_dim=config.hidden_dim,
|
|
252
|
+
alphabet_size=config.alphabet_size,
|
|
253
|
+
rngs=rngs,
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
# Alignment scoring
|
|
257
|
+
self.align_score = nnx.Linear(
|
|
258
|
+
in_features=config.alphabet_size * 2,
|
|
259
|
+
out_features=1,
|
|
260
|
+
rngs=rngs,
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
def _compute_pairwise_distances(
|
|
264
|
+
self,
|
|
265
|
+
sequences: Float[Array, "n_seqs seq_len alphabet_size"],
|
|
266
|
+
) -> Float[Array, "n_seqs n_seqs"]:
|
|
267
|
+
"""Compute pairwise distances between sequences.
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
sequences: Input sequences.
|
|
271
|
+
|
|
272
|
+
Returns:
|
|
273
|
+
Pairwise distance matrix.
|
|
274
|
+
"""
|
|
275
|
+
n_seqs = sequences.shape[0]
|
|
276
|
+
|
|
277
|
+
# Encode all sequences
|
|
278
|
+
embeddings = jax.vmap(self.seq_encoder)(sequences) # (n_seqs, hidden_dim)
|
|
279
|
+
|
|
280
|
+
# Compute pairwise distances (negative cosine similarity)
|
|
281
|
+
norms = jnp.linalg.norm(embeddings, axis=-1, keepdims=True) + 1e-8
|
|
282
|
+
normalized = embeddings / norms
|
|
283
|
+
|
|
284
|
+
# Cosine similarity -> distance
|
|
285
|
+
similarities = jnp.einsum("ih,jh->ij", normalized, normalized)
|
|
286
|
+
distances = 1.0 - similarities
|
|
287
|
+
|
|
288
|
+
# Zero diagonal
|
|
289
|
+
distances = distances * (1.0 - jnp.eye(n_seqs))
|
|
290
|
+
|
|
291
|
+
return distances
|
|
292
|
+
|
|
293
|
+
def _soft_align_pair(
|
|
294
|
+
self,
|
|
295
|
+
seq1: Float[Array, "len1 alphabet_size"],
|
|
296
|
+
seq2: Float[Array, "len2 alphabet_size"],
|
|
297
|
+
) -> tuple[
|
|
298
|
+
Float[Array, "max_len alphabet_size"],
|
|
299
|
+
Float[Array, "max_len alphabet_size"],
|
|
300
|
+
Float[Array, ""],
|
|
301
|
+
]:
|
|
302
|
+
"""Perform soft pairwise alignment.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
seq1: First sequence.
|
|
306
|
+
seq2: Second sequence.
|
|
307
|
+
|
|
308
|
+
Returns:
|
|
309
|
+
Tuple of (aligned_seq1, aligned_seq2, alignment_score).
|
|
310
|
+
"""
|
|
311
|
+
len1, len2 = seq1.shape[0], seq2.shape[0]
|
|
312
|
+
max_len = max(len1, len2)
|
|
313
|
+
|
|
314
|
+
# Compute position-wise similarity scores
|
|
315
|
+
# (len1, alphabet) x (len2, alphabet) -> (len1, len2)
|
|
316
|
+
match_scores = jnp.einsum("ia,ja->ij", seq1, seq2)
|
|
317
|
+
|
|
318
|
+
# Soft alignment via attention
|
|
319
|
+
# Each position in seq1 attends to positions in seq2
|
|
320
|
+
# Use inherited _temperature property from TemperatureOperator
|
|
321
|
+
attn_weights = jax.nn.softmax(match_scores / self._temperature, axis=-1)
|
|
322
|
+
|
|
323
|
+
# Soft-aligned seq2 based on seq1 positions
|
|
324
|
+
aligned_seq2_to_seq1 = jnp.einsum("ij,ja->ia", attn_weights, seq2)
|
|
325
|
+
|
|
326
|
+
# Pad to max_len
|
|
327
|
+
pad1 = max_len - len1
|
|
328
|
+
|
|
329
|
+
aligned1 = jnp.pad(seq1, ((0, pad1), (0, 0)))
|
|
330
|
+
aligned2 = jnp.pad(aligned_seq2_to_seq1, ((0, pad1), (0, 0)))
|
|
331
|
+
|
|
332
|
+
# Compute alignment score
|
|
333
|
+
alignment_score = jnp.mean(match_scores * attn_weights)
|
|
334
|
+
|
|
335
|
+
return aligned1, aligned2, alignment_score
|
|
336
|
+
|
|
337
|
+
def apply(
|
|
338
|
+
self,
|
|
339
|
+
data: PyTree,
|
|
340
|
+
state: PyTree,
|
|
341
|
+
metadata: dict[str, Any] | None,
|
|
342
|
+
random_params: Any = None,
|
|
343
|
+
stats: dict[str, Any] | None = None,
|
|
344
|
+
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
345
|
+
"""Apply soft progressive MSA.
|
|
346
|
+
|
|
347
|
+
Args:
|
|
348
|
+
data: Dictionary containing:
|
|
349
|
+
- "sequences": Input sequences (n_seqs, seq_len, alphabet_size)
|
|
350
|
+
state: Element state (passed through unchanged)
|
|
351
|
+
metadata: Element metadata (passed through unchanged)
|
|
352
|
+
random_params: Not used
|
|
353
|
+
stats: Not used
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
Tuple of (transformed_data, state, metadata):
|
|
357
|
+
- transformed_data contains:
|
|
358
|
+
|
|
359
|
+
- "sequences": Original sequences
|
|
360
|
+
- "aligned_sequences": Soft-aligned sequences
|
|
361
|
+
- "pairwise_distances": Guide tree distances
|
|
362
|
+
- "alignment_scores": Pairwise alignment scores
|
|
363
|
+
- "consensus_profile": Consensus profile
|
|
364
|
+
- state is passed through unchanged
|
|
365
|
+
- metadata is passed through unchanged
|
|
366
|
+
"""
|
|
367
|
+
sequences = data["sequences"]
|
|
368
|
+
n_seqs = sequences.shape[0]
|
|
369
|
+
|
|
370
|
+
# Step 1: Compute pairwise distances for guide tree
|
|
371
|
+
pairwise_distances = self._compute_pairwise_distances(sequences)
|
|
372
|
+
|
|
373
|
+
# Step 2: Progressive alignment
|
|
374
|
+
# For simplicity, align all sequences to the first one
|
|
375
|
+
# (full progressive alignment would follow guide tree)
|
|
376
|
+
aligned_sequences = []
|
|
377
|
+
alignment_scores = []
|
|
378
|
+
|
|
379
|
+
# Use first sequence as anchor
|
|
380
|
+
anchor = sequences[0]
|
|
381
|
+
aligned_sequences.append(anchor)
|
|
382
|
+
|
|
383
|
+
for i in range(1, n_seqs):
|
|
384
|
+
aligned1, aligned2, score = self._soft_align_pair(anchor, sequences[i])
|
|
385
|
+
# Keep the aligned version of sequences[i]
|
|
386
|
+
aligned_sequences.append(aligned2[: sequences[i].shape[0]])
|
|
387
|
+
alignment_scores.append(score)
|
|
388
|
+
|
|
389
|
+
# Stack aligned sequences (pad to same length)
|
|
390
|
+
max_len = max(s.shape[0] for s in aligned_sequences)
|
|
391
|
+
padded_aligned = []
|
|
392
|
+
for seq in aligned_sequences:
|
|
393
|
+
pad_len = max_len - seq.shape[0]
|
|
394
|
+
padded = jnp.pad(seq, ((0, pad_len), (0, 0)))
|
|
395
|
+
padded_aligned.append(padded)
|
|
396
|
+
|
|
397
|
+
aligned_stack = jnp.stack(padded_aligned, axis=0)
|
|
398
|
+
|
|
399
|
+
# Step 3: Build consensus profile
|
|
400
|
+
uniform_weights = jnp.ones(n_seqs) / n_seqs
|
|
401
|
+
consensus = self.profile_builder(aligned_stack, uniform_weights)
|
|
402
|
+
|
|
403
|
+
# Alignment scores matrix
|
|
404
|
+
scores_matrix = jnp.zeros((n_seqs, n_seqs))
|
|
405
|
+
if alignment_scores:
|
|
406
|
+
scores_array = jnp.array(alignment_scores)
|
|
407
|
+
# Fill first row/column with computed scores
|
|
408
|
+
scores_matrix = scores_matrix.at[0, 1:].set(scores_array)
|
|
409
|
+
scores_matrix = scores_matrix.at[1:, 0].set(scores_array)
|
|
410
|
+
|
|
411
|
+
transformed_data = {
|
|
412
|
+
"sequences": sequences,
|
|
413
|
+
"aligned_sequences": aligned_stack,
|
|
414
|
+
"pairwise_distances": pairwise_distances,
|
|
415
|
+
"alignment_scores": scores_matrix,
|
|
416
|
+
"consensus_profile": consensus,
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
return transformed_data, state, metadata
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Assembly operators for differentiable genome assembly.
|
|
2
|
+
|
|
3
|
+
This module provides graph neural network-based approaches to
|
|
4
|
+
assembly graph traversal that enable gradient flow through the
|
|
5
|
+
assembly process.
|
|
6
|
+
|
|
7
|
+
- GNNAssemblyNavigator: Message passing GNN for soft edge selection
|
|
8
|
+
- DifferentiableMetagenomicBinner: VAMB-style VAE for metagenomic binning
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from diffbio.operators.assembly.gnn_assembly import (
|
|
12
|
+
GNNAssemblyNavigator,
|
|
13
|
+
GNNAssemblyNavigatorConfig,
|
|
14
|
+
)
|
|
15
|
+
from diffbio.operators.assembly.metagenomic_binning import (
|
|
16
|
+
DifferentiableMetagenomicBinner,
|
|
17
|
+
MetagenomicBinnerConfig,
|
|
18
|
+
create_metagenomic_binner,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"GNNAssemblyNavigator",
|
|
23
|
+
"GNNAssemblyNavigatorConfig",
|
|
24
|
+
"DifferentiableMetagenomicBinner",
|
|
25
|
+
"MetagenomicBinnerConfig",
|
|
26
|
+
"create_metagenomic_binner",
|
|
27
|
+
]
|