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,509 @@
|
|
|
1
|
+
"""Differentiable secondary structure prediction (PyDSSP-style).
|
|
2
|
+
|
|
3
|
+
This module implements a JAX/Flax NNX version of the DSSP algorithm for
|
|
4
|
+
assigning secondary structure to protein backbone atoms. The key innovation
|
|
5
|
+
is a continuous hydrogen bond matrix that enables gradient-based optimization.
|
|
6
|
+
|
|
7
|
+
The algorithm computes hydrogen bond energies using the Kabsch-Sander formula,
|
|
8
|
+
then applies a smooth transformation to create a differentiable H-bond matrix.
|
|
9
|
+
Secondary structure is assigned based on characteristic H-bond patterns.
|
|
10
|
+
|
|
11
|
+
Reference:
|
|
12
|
+
Kabsch & Sander (1983). Dictionary of protein secondary structure:
|
|
13
|
+
pattern recognition of hydrogen-bonded and geometrical features.
|
|
14
|
+
Biopolymers 22, 2577-2637.
|
|
15
|
+
|
|
16
|
+
Minami (2023). PyDSSP: A simplified implementation of DSSP algorithm
|
|
17
|
+
for PyTorch and NumPy. https://github.com/ShintaroMinami/PyDSSP
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import logging
|
|
21
|
+
from dataclasses import dataclass
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
import jax.numpy as jnp
|
|
25
|
+
from datarax.core.config import OperatorConfig
|
|
26
|
+
from datarax.core.operator import OperatorModule
|
|
27
|
+
from flax import nnx
|
|
28
|
+
from jaxtyping import Array, Float
|
|
29
|
+
|
|
30
|
+
from diffbio.core import soft_ops
|
|
31
|
+
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
# DSSP constants from Kabsch & Sander (1983)
|
|
35
|
+
CONST_Q1Q2 = 0.084 # Partial charges (e units)
|
|
36
|
+
CONST_F = 332.0 # Conversion factor to kcal/mol
|
|
37
|
+
DEFAULT_CUTOFF = -0.5 # H-bond energy threshold (kcal/mol)
|
|
38
|
+
DEFAULT_MARGIN = 1.0 # Smoothing margin for continuous H-bond map
|
|
39
|
+
|
|
40
|
+
# Atom indices in the coordinate array
|
|
41
|
+
ATOM_N = 0
|
|
42
|
+
ATOM_CA = 1
|
|
43
|
+
ATOM_C = 2
|
|
44
|
+
ATOM_O = 3
|
|
45
|
+
|
|
46
|
+
# Secondary structure class indices
|
|
47
|
+
SS_LOOP = 0 # '-' (coil/loop)
|
|
48
|
+
SS_HELIX = 1 # 'H' (alpha-helix)
|
|
49
|
+
SS_STRAND = 2 # 'E' (beta-strand)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dataclass(frozen=True)
|
|
53
|
+
class _SecondaryStructureCoreConfig:
|
|
54
|
+
"""Core DSSP thresholding configuration."""
|
|
55
|
+
|
|
56
|
+
margin: float = DEFAULT_MARGIN
|
|
57
|
+
cutoff: float = DEFAULT_CUTOFF
|
|
58
|
+
min_helix_length: int = 4
|
|
59
|
+
temperature: float = 1.0
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass(frozen=True)
|
|
63
|
+
class _SecondaryStructureConstraintConfig:
|
|
64
|
+
"""Optional geometric regularization configuration."""
|
|
65
|
+
|
|
66
|
+
use_bond_length_constraint: bool = False
|
|
67
|
+
use_bond_angle_constraint: bool = False
|
|
68
|
+
bond_length_weight: float = 0.1
|
|
69
|
+
bond_angle_weight: float = 0.1
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@dataclass(frozen=True)
|
|
73
|
+
class SecondaryStructureConfig(
|
|
74
|
+
_SecondaryStructureCoreConfig,
|
|
75
|
+
_SecondaryStructureConstraintConfig,
|
|
76
|
+
OperatorConfig,
|
|
77
|
+
):
|
|
78
|
+
"""Configuration for DifferentiableSecondaryStructure."""
|
|
79
|
+
|
|
80
|
+
def __post_init__(self) -> None:
|
|
81
|
+
"""Validate the secondary-structure configuration."""
|
|
82
|
+
super().__post_init__()
|
|
83
|
+
|
|
84
|
+
if self.margin <= 0.0:
|
|
85
|
+
raise ValueError("margin must be positive.")
|
|
86
|
+
if self.min_helix_length <= 0:
|
|
87
|
+
raise ValueError("min_helix_length must be positive.")
|
|
88
|
+
if self.temperature <= 0.0:
|
|
89
|
+
raise ValueError("temperature must be positive.")
|
|
90
|
+
if self.bond_length_weight < 0.0:
|
|
91
|
+
raise ValueError("bond_length_weight must be non-negative.")
|
|
92
|
+
if self.bond_angle_weight < 0.0:
|
|
93
|
+
raise ValueError("bond_angle_weight must be non-negative.")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def compute_hydrogen_position(
|
|
97
|
+
n_pos: Float[Array, "... 3"],
|
|
98
|
+
ca_pos: Float[Array, "... 3"],
|
|
99
|
+
c_prev_pos: Float[Array, "... 3"],
|
|
100
|
+
) -> Float[Array, "... 3"]:
|
|
101
|
+
"""Compute hydrogen atom position from backbone atoms.
|
|
102
|
+
|
|
103
|
+
The amide hydrogen is placed along the N-H bond direction, which is
|
|
104
|
+
approximately opposite to the bisector of CA-N and C_prev-N vectors.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
n_pos: Nitrogen atom positions.
|
|
108
|
+
ca_pos: Alpha carbon positions.
|
|
109
|
+
c_prev_pos: Carbonyl carbon from previous residue.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Estimated hydrogen atom positions.
|
|
113
|
+
"""
|
|
114
|
+
# Vectors from N to neighboring atoms
|
|
115
|
+
vec_n_ca = ca_pos - n_pos
|
|
116
|
+
vec_n_c = c_prev_pos - n_pos
|
|
117
|
+
|
|
118
|
+
# Normalize
|
|
119
|
+
vec_n_ca = vec_n_ca / (jnp.linalg.norm(vec_n_ca, axis=-1, keepdims=True) + 1e-8)
|
|
120
|
+
vec_n_c = vec_n_c / (jnp.linalg.norm(vec_n_c, axis=-1, keepdims=True) + 1e-8)
|
|
121
|
+
|
|
122
|
+
# H is opposite to the average direction (bisector)
|
|
123
|
+
h_direction = -(vec_n_ca + vec_n_c)
|
|
124
|
+
h_direction = h_direction / (jnp.linalg.norm(h_direction, axis=-1, keepdims=True) + 1e-8)
|
|
125
|
+
|
|
126
|
+
# Standard N-H bond length is ~1.0 Angstrom
|
|
127
|
+
h_pos = n_pos + h_direction * 1.0
|
|
128
|
+
|
|
129
|
+
return h_pos
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class DifferentiableSecondaryStructure(OperatorModule):
|
|
133
|
+
"""Differentiable secondary structure prediction using DSSP algorithm.
|
|
134
|
+
|
|
135
|
+
This operator computes secondary structure assignments for protein
|
|
136
|
+
backbone atoms using a differentiable version of the DSSP algorithm.
|
|
137
|
+
The key innovation is a continuous hydrogen bond matrix that enables
|
|
138
|
+
gradient flow through the secondary structure prediction.
|
|
139
|
+
|
|
140
|
+
The algorithm:
|
|
141
|
+
1. Compute hydrogen bond energies using Kabsch-Sander electrostatic formula
|
|
142
|
+
2. Apply smooth transformation to create continuous H-bond matrix in [0,1]
|
|
143
|
+
3. Detect helix patterns (i→i+4 H-bonds) and strand patterns
|
|
144
|
+
4. Output soft secondary structure assignments
|
|
145
|
+
|
|
146
|
+
Input data structure:
|
|
147
|
+
- coordinates: Float[Array, "batch length 4 3"] - Backbone atoms (N, CA, C, O)
|
|
148
|
+
|
|
149
|
+
Output data structure (adds):
|
|
150
|
+
- ss_onehot: Float[Array, "batch length 3"] - Soft SS probabilities
|
|
151
|
+
- hbond_map: Float[Array, "batch length length"] - Continuous H-bond matrix
|
|
152
|
+
- ss_indices: Int[Array, "batch length"] - Hard SS assignments (0=loop, 1=helix, 2=strand)
|
|
153
|
+
|
|
154
|
+
Example:
|
|
155
|
+
```python
|
|
156
|
+
config = SecondaryStructureConfig(margin=1.0, cutoff=-0.5)
|
|
157
|
+
predictor = DifferentiableSecondaryStructure(config, rngs=nnx.Rngs(42))
|
|
158
|
+
coords = jax.random.uniform(key, (1, 50, 4, 3)) * 10 # 50 residues
|
|
159
|
+
result, _, _ = predictor.apply({"coordinates": coords}, {}, None)
|
|
160
|
+
ss_probs = result["ss_onehot"] # (1, 50, 3)
|
|
161
|
+
```
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
def __init__(
|
|
165
|
+
self,
|
|
166
|
+
config: SecondaryStructureConfig,
|
|
167
|
+
*,
|
|
168
|
+
rngs: nnx.Rngs,
|
|
169
|
+
name: str | None = None,
|
|
170
|
+
):
|
|
171
|
+
"""Initialize the secondary structure predictor.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
config: Configuration with DSSP parameters.
|
|
175
|
+
rngs: Random number generators.
|
|
176
|
+
name: Optional name for the operator.
|
|
177
|
+
"""
|
|
178
|
+
super().__init__(config, rngs=rngs, name=name)
|
|
179
|
+
self.config: SecondaryStructureConfig = config
|
|
180
|
+
|
|
181
|
+
def compute_hbond_energy(
|
|
182
|
+
self,
|
|
183
|
+
coords: Float[Array, "batch length 4 3"],
|
|
184
|
+
) -> Float[Array, "batch length length"]:
|
|
185
|
+
"""Compute hydrogen bond energy matrix.
|
|
186
|
+
|
|
187
|
+
Uses the Kabsch-Sander electrostatic energy formula:
|
|
188
|
+
E = q1*q2 * f * (1/r_ON + 1/r_CH - 1/r_OH - 1/r_CN)
|
|
189
|
+
|
|
190
|
+
where r_XY is the distance between atoms X and Y.
|
|
191
|
+
|
|
192
|
+
Donor: N-H from residue i
|
|
193
|
+
Acceptor: C=O from residue j
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
coords: Backbone coordinates (batch, length, 4, 3).
|
|
197
|
+
Atom order: N, CA, C, O
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
Energy matrix (batch, length, length) in kcal/mol.
|
|
201
|
+
E[b, i, j] = energy of H-bond from donor i to acceptor j.
|
|
202
|
+
"""
|
|
203
|
+
batch, length, _, _ = coords.shape
|
|
204
|
+
|
|
205
|
+
# Extract atom positions
|
|
206
|
+
n_pos = coords[:, :, ATOM_N, :] # (batch, length, 3)
|
|
207
|
+
ca_pos = coords[:, :, ATOM_CA, :]
|
|
208
|
+
c_pos = coords[:, :, ATOM_C, :]
|
|
209
|
+
o_pos = coords[:, :, ATOM_O, :]
|
|
210
|
+
|
|
211
|
+
# Compute hydrogen positions (shifted by 1 for C from previous residue)
|
|
212
|
+
# For first residue, use self C as approximation
|
|
213
|
+
c_prev = jnp.concatenate([c_pos[:, :1, :], c_pos[:, :-1, :]], axis=1)
|
|
214
|
+
h_pos = compute_hydrogen_position(n_pos, ca_pos, c_prev)
|
|
215
|
+
|
|
216
|
+
# Expand for pairwise computation
|
|
217
|
+
# Donors: N, H from residue i
|
|
218
|
+
# Acceptors: C, O from residue j
|
|
219
|
+
n_i = n_pos[:, :, None, :] # (batch, length, 1, 3)
|
|
220
|
+
h_i = h_pos[:, :, None, :]
|
|
221
|
+
c_j = c_pos[:, None, :, :] # (batch, 1, length, 3)
|
|
222
|
+
o_j = o_pos[:, None, :, :]
|
|
223
|
+
|
|
224
|
+
# Compute distances with numerical stability
|
|
225
|
+
def safe_distance(pos1, pos2, min_dist=0.1):
|
|
226
|
+
diff = pos1 - pos2
|
|
227
|
+
dist = jnp.sqrt(jnp.sum(diff**2, axis=-1) + 1e-10)
|
|
228
|
+
return jnp.maximum(dist, min_dist)
|
|
229
|
+
|
|
230
|
+
d_on = safe_distance(o_j, n_i) # O(acceptor) to N(donor)
|
|
231
|
+
d_ch = safe_distance(c_j, h_i) # C(acceptor) to H(donor)
|
|
232
|
+
d_oh = safe_distance(o_j, h_i) # O(acceptor) to H(donor)
|
|
233
|
+
d_cn = safe_distance(c_j, n_i) # C(acceptor) to N(donor)
|
|
234
|
+
|
|
235
|
+
# Kabsch-Sander energy formula
|
|
236
|
+
energy = CONST_Q1Q2 * CONST_F * (1.0 / d_on + 1.0 / d_ch - 1.0 / d_oh - 1.0 / d_cn)
|
|
237
|
+
|
|
238
|
+
return energy
|
|
239
|
+
|
|
240
|
+
def compute_hbond_map(
|
|
241
|
+
self,
|
|
242
|
+
coords: Float[Array, "batch length 4 3"],
|
|
243
|
+
) -> Float[Array, "batch length length"]:
|
|
244
|
+
"""Compute continuous hydrogen bond matrix.
|
|
245
|
+
|
|
246
|
+
Transforms the energy matrix into a continuous [0,1] matrix using
|
|
247
|
+
a smooth sigmoid-like function based on sine:
|
|
248
|
+
HbondMat(i,j) = (1 + sin((cutoff - E - margin) / margin * pi/2)) / 2
|
|
249
|
+
|
|
250
|
+
This allows gradients to flow through the H-bond detection.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
coords: Backbone coordinates (batch, length, 4, 3).
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
Continuous H-bond matrix (batch, length, length) in [0, 1].
|
|
257
|
+
"""
|
|
258
|
+
energy = self.compute_hbond_energy(coords)
|
|
259
|
+
|
|
260
|
+
margin = self.config.margin
|
|
261
|
+
cutoff = self.config.cutoff
|
|
262
|
+
|
|
263
|
+
# Smooth transformation: maps energy to [0, 1]
|
|
264
|
+
# More negative energy (stronger H-bond) -> higher value
|
|
265
|
+
x = (cutoff - energy - margin) / margin
|
|
266
|
+
|
|
267
|
+
# Clamp to [-1, 1] for sin input to stay in valid range
|
|
268
|
+
x = jnp.clip(x, -1.0, 1.0)
|
|
269
|
+
|
|
270
|
+
# Sine-based sigmoid: smooth transition in [0, 1]
|
|
271
|
+
hbond_map = (1.0 + jnp.sin(x * jnp.pi / 2)) / 2.0
|
|
272
|
+
|
|
273
|
+
return hbond_map
|
|
274
|
+
|
|
275
|
+
def detect_helix_pattern(
|
|
276
|
+
self,
|
|
277
|
+
hbond_map: Float[Array, "batch length length"],
|
|
278
|
+
) -> Float[Array, "batch length"]:
|
|
279
|
+
"""Detect alpha-helix pattern (i→i+4 hydrogen bonds).
|
|
280
|
+
|
|
281
|
+
Alpha-helices are characterized by H-bonds from residue i (donor)
|
|
282
|
+
to residue i-4 (acceptor), creating i→i+4 backbone H-bonds.
|
|
283
|
+
|
|
284
|
+
Args:
|
|
285
|
+
hbond_map: Continuous H-bond matrix.
|
|
286
|
+
|
|
287
|
+
Returns:
|
|
288
|
+
Soft helix assignment for each residue.
|
|
289
|
+
"""
|
|
290
|
+
batch, length, _ = hbond_map.shape
|
|
291
|
+
|
|
292
|
+
# Extract i→i+4 diagonal (donor i to acceptor i-4)
|
|
293
|
+
# This means hbond_map[i, i-4] should be high
|
|
294
|
+
helix_score = jnp.zeros((batch, length))
|
|
295
|
+
|
|
296
|
+
# For residues 4 and beyond, check if they donate to i-4
|
|
297
|
+
# and residue i+4 donates to them
|
|
298
|
+
for offset in [3, 4]: # Check both i→i+3 (3-10 helix) and i→i+4 (alpha helix)
|
|
299
|
+
# Create shifted versions to extract diagonal
|
|
300
|
+
if offset < length:
|
|
301
|
+
# Score for being in a helix: both i→i-offset and i+offset→i should be H-bonded
|
|
302
|
+
# Simplified: just check i→i-offset pattern
|
|
303
|
+
indices = jnp.arange(length)
|
|
304
|
+
donor_indices = indices
|
|
305
|
+
acceptor_indices = indices - offset
|
|
306
|
+
|
|
307
|
+
# Mask for valid indices
|
|
308
|
+
valid_mask = acceptor_indices >= 0
|
|
309
|
+
|
|
310
|
+
# Get H-bond scores for valid pairs
|
|
311
|
+
scores = jnp.where(
|
|
312
|
+
valid_mask,
|
|
313
|
+
hbond_map[:, donor_indices, jnp.maximum(acceptor_indices, 0)],
|
|
314
|
+
0.0,
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
helix_score = helix_score + scores
|
|
318
|
+
|
|
319
|
+
# Normalize and apply temperature
|
|
320
|
+
helix_score = helix_score / 2.0 # Average of two patterns
|
|
321
|
+
helix_score = soft_ops.clip(helix_score, 0.0, 1.0, softness=0.1)
|
|
322
|
+
|
|
323
|
+
return helix_score
|
|
324
|
+
|
|
325
|
+
def detect_strand_pattern(
|
|
326
|
+
self,
|
|
327
|
+
hbond_map: Float[Array, "batch length length"],
|
|
328
|
+
) -> Float[Array, "batch length"]:
|
|
329
|
+
"""Detect beta-strand pattern (parallel/antiparallel H-bonds).
|
|
330
|
+
|
|
331
|
+
Beta-strands are characterized by H-bonds between distant residues
|
|
332
|
+
forming ladder-like patterns (parallel or antiparallel).
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
hbond_map: Continuous H-bond matrix.
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
Soft strand assignment for each residue.
|
|
339
|
+
"""
|
|
340
|
+
batch, length, _ = hbond_map.shape
|
|
341
|
+
|
|
342
|
+
# For strands, we look for H-bonds to non-local residues (|i-j| > 4)
|
|
343
|
+
# Create distance mask
|
|
344
|
+
i_idx = jnp.arange(length)[:, None]
|
|
345
|
+
j_idx = jnp.arange(length)[None, :]
|
|
346
|
+
distance_mask = jnp.abs(i_idx - j_idx) > 4
|
|
347
|
+
|
|
348
|
+
# Mask H-bond map to only consider non-local bonds
|
|
349
|
+
masked_hbond = hbond_map * distance_mask[None, :, :]
|
|
350
|
+
|
|
351
|
+
# Score for each residue: max of incoming and outgoing non-local H-bonds
|
|
352
|
+
incoming = soft_ops.max(masked_hbond, axis=1, softness=0.1)
|
|
353
|
+
outgoing = soft_ops.max(masked_hbond, axis=2, softness=0.1)
|
|
354
|
+
|
|
355
|
+
strand_score = jnp.maximum(incoming, outgoing)
|
|
356
|
+
|
|
357
|
+
return strand_score
|
|
358
|
+
|
|
359
|
+
def assign_secondary_structure(
|
|
360
|
+
self,
|
|
361
|
+
hbond_map: Float[Array, "batch length length"],
|
|
362
|
+
) -> Float[Array, "batch length 3"]:
|
|
363
|
+
"""Assign secondary structure based on H-bond patterns.
|
|
364
|
+
|
|
365
|
+
Combines helix and strand detection into soft assignments.
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
hbond_map: Continuous H-bond matrix.
|
|
369
|
+
|
|
370
|
+
Returns:
|
|
371
|
+
One-hot encoded SS assignments (batch, length, 3).
|
|
372
|
+
Classes: 0=loop, 1=helix, 2=strand
|
|
373
|
+
"""
|
|
374
|
+
helix_score = self.detect_helix_pattern(hbond_map)
|
|
375
|
+
strand_score = self.detect_strand_pattern(hbond_map)
|
|
376
|
+
|
|
377
|
+
# Stack scores: [loop, helix, strand]
|
|
378
|
+
# Loop score is complement of max(helix, strand)
|
|
379
|
+
loop_score = 1.0 - jnp.maximum(helix_score, strand_score)
|
|
380
|
+
|
|
381
|
+
scores = jnp.stack([loop_score, helix_score, strand_score], axis=-1)
|
|
382
|
+
|
|
383
|
+
# Apply softmax with temperature for soft assignments
|
|
384
|
+
temp = self.config.temperature
|
|
385
|
+
ss_probs = nnx.softmax(scores / temp, axis=-1)
|
|
386
|
+
|
|
387
|
+
return ss_probs
|
|
388
|
+
|
|
389
|
+
def apply(
|
|
390
|
+
self,
|
|
391
|
+
data: dict[str, Any],
|
|
392
|
+
state: dict[str, Any],
|
|
393
|
+
metadata: dict[str, Any] | None,
|
|
394
|
+
random_params: Any = None, # noqa: ARG002
|
|
395
|
+
stats: dict[str, Any] | None = None, # noqa: ARG002
|
|
396
|
+
) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any] | None]:
|
|
397
|
+
"""Apply secondary structure prediction.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
data: Input data containing:
|
|
401
|
+
- coordinates: Float[Array, "batch length 4 3"]
|
|
402
|
+
state: Element state (passed through).
|
|
403
|
+
metadata: Element metadata (passed through).
|
|
404
|
+
random_params: Random parameters (unused).
|
|
405
|
+
stats: Optional statistics (unused).
|
|
406
|
+
|
|
407
|
+
Returns:
|
|
408
|
+
Tuple of (output_data, state, metadata).
|
|
409
|
+
"""
|
|
410
|
+
coords = data["coordinates"]
|
|
411
|
+
|
|
412
|
+
# Compute H-bond matrix
|
|
413
|
+
hbond_map = self.compute_hbond_map(coords)
|
|
414
|
+
|
|
415
|
+
# Assign secondary structure
|
|
416
|
+
ss_onehot = self.assign_secondary_structure(hbond_map)
|
|
417
|
+
|
|
418
|
+
# Hard assignments for convenience
|
|
419
|
+
ss_indices = jnp.argmax(ss_onehot, axis=-1)
|
|
420
|
+
|
|
421
|
+
# Build output
|
|
422
|
+
output_data = {
|
|
423
|
+
**data,
|
|
424
|
+
"hbond_map": hbond_map,
|
|
425
|
+
"ss_onehot": ss_onehot,
|
|
426
|
+
"ss_indices": ss_indices,
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
# Optionally compute artifex backbone constraint losses
|
|
430
|
+
constraint_loss = _compute_backbone_constraints(coords, self.config)
|
|
431
|
+
if constraint_loss is not None:
|
|
432
|
+
output_data["backbone_constraint_loss"] = constraint_loss
|
|
433
|
+
|
|
434
|
+
return output_data, state, metadata
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def _compute_backbone_constraints(
|
|
438
|
+
coords: Float[Array, "batch length 4 3"],
|
|
439
|
+
config: SecondaryStructureConfig,
|
|
440
|
+
) -> Array | None:
|
|
441
|
+
"""Compute artifex backbone constraint losses if enabled.
|
|
442
|
+
|
|
443
|
+
Uses artifex BondLengthExtension and BondAngleExtension to compute
|
|
444
|
+
regularisation losses that penalise deviation from ideal protein
|
|
445
|
+
backbone geometry.
|
|
446
|
+
|
|
447
|
+
Args:
|
|
448
|
+
coords: Backbone coordinates (batch, length, 4, 3).
|
|
449
|
+
config: Config with constraint flags and weights.
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
Scalar constraint loss, or None if constraints are disabled.
|
|
453
|
+
"""
|
|
454
|
+
if not config.use_bond_length_constraint and not config.use_bond_angle_constraint:
|
|
455
|
+
return None
|
|
456
|
+
|
|
457
|
+
from artifex.generative_models.extensions.protein.backbone import ( # noqa: PLC0415
|
|
458
|
+
BondAngleExtension,
|
|
459
|
+
BondLengthExtension,
|
|
460
|
+
)
|
|
461
|
+
from artifex.generative_models.extensions.protein.backbone import ( # noqa: PLC0415
|
|
462
|
+
ProteinExtensionConfig,
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
batch_data = {"coordinates": coords}
|
|
466
|
+
total_loss = jnp.float32(0.0)
|
|
467
|
+
|
|
468
|
+
if config.use_bond_length_constraint:
|
|
469
|
+
ext_config = ProteinExtensionConfig()
|
|
470
|
+
ext = BondLengthExtension(ext_config, rngs=nnx.Rngs(0))
|
|
471
|
+
bl_loss = ext.loss_fn(batch_data, None)
|
|
472
|
+
total_loss = total_loss + config.bond_length_weight * bl_loss
|
|
473
|
+
|
|
474
|
+
if config.use_bond_angle_constraint:
|
|
475
|
+
ext_config = ProteinExtensionConfig()
|
|
476
|
+
ext = BondAngleExtension(ext_config, rngs=nnx.Rngs(0))
|
|
477
|
+
ba_loss = ext.loss_fn(batch_data, None)
|
|
478
|
+
total_loss = total_loss + config.bond_angle_weight * ba_loss
|
|
479
|
+
|
|
480
|
+
return total_loss
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
def create_secondary_structure_predictor(
|
|
484
|
+
margin: float = DEFAULT_MARGIN,
|
|
485
|
+
cutoff: float = DEFAULT_CUTOFF,
|
|
486
|
+
min_helix_length: int = 4,
|
|
487
|
+
temperature: float = 1.0,
|
|
488
|
+
seed: int = 42,
|
|
489
|
+
) -> DifferentiableSecondaryStructure:
|
|
490
|
+
"""Factory function to create a secondary structure predictor.
|
|
491
|
+
|
|
492
|
+
Args:
|
|
493
|
+
margin: Smoothing margin for H-bond matrix. Default 1.0.
|
|
494
|
+
cutoff: H-bond energy threshold in kcal/mol. Default -0.5.
|
|
495
|
+
min_helix_length: Minimum residues for helix. Default 4.
|
|
496
|
+
temperature: Softmax temperature. Default 1.0.
|
|
497
|
+
seed: Random seed. Default 42.
|
|
498
|
+
|
|
499
|
+
Returns:
|
|
500
|
+
Configured DifferentiableSecondaryStructure instance.
|
|
501
|
+
"""
|
|
502
|
+
config = SecondaryStructureConfig(
|
|
503
|
+
margin=margin,
|
|
504
|
+
cutoff=cutoff,
|
|
505
|
+
min_helix_length=min_helix_length,
|
|
506
|
+
temperature=temperature,
|
|
507
|
+
)
|
|
508
|
+
rngs = nnx.Rngs(seed)
|
|
509
|
+
return DifferentiableSecondaryStructure(config, rngs=rngs)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Differentiable quality filter operator for bioinformatics sequences.
|
|
2
|
+
|
|
3
|
+
This module provides a soft quality filtering operator that down-weights
|
|
4
|
+
low-quality positions in sequences using a differentiable sigmoid function.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from datarax.core.config import OperatorConfig
|
|
12
|
+
from datarax.core.operator import OperatorModule
|
|
13
|
+
from flax import nnx
|
|
14
|
+
from jaxtyping import PyTree
|
|
15
|
+
|
|
16
|
+
from diffbio.constants import PHRED_QUALITY_THRESHOLD
|
|
17
|
+
from diffbio.core import soft_ops
|
|
18
|
+
from diffbio.utils.nn_utils import init_learnable_param
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass(frozen=True)
|
|
24
|
+
class QualityFilterConfig(OperatorConfig):
|
|
25
|
+
"""Configuration for DifferentiableQualityFilter.
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
initial_threshold: Initial Phred quality score threshold.
|
|
29
|
+
Positions with quality below this are down-weighted.
|
|
30
|
+
Default is 20.0 (1% error rate).
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
initial_threshold: float = PHRED_QUALITY_THRESHOLD
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class DifferentiableQualityFilter(OperatorModule):
|
|
37
|
+
"""Differentiable quality filter for DNA/RNA sequences.
|
|
38
|
+
|
|
39
|
+
This operator applies soft quality filtering using a sigmoid function
|
|
40
|
+
to weight sequence positions by their quality scores. High-quality
|
|
41
|
+
positions (above threshold) pass through with high weight, while
|
|
42
|
+
low-quality positions are down-weighted.
|
|
43
|
+
|
|
44
|
+
The threshold is a learnable parameter that can be optimized
|
|
45
|
+
end-to-end with the rest of the pipeline.
|
|
46
|
+
|
|
47
|
+
Formula:
|
|
48
|
+
retention_weight = sigmoid(quality_score - threshold)
|
|
49
|
+
filtered_sequence = sequence * retention_weight
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
config: QualityFilterConfig with initial threshold
|
|
53
|
+
rngs: Flax NNX random number generators
|
|
54
|
+
|
|
55
|
+
Example:
|
|
56
|
+
```python
|
|
57
|
+
config = QualityFilterConfig(initial_threshold=20.0)
|
|
58
|
+
filter_op = DifferentiableQualityFilter(config, rngs=nnx.Rngs(42))
|
|
59
|
+
data = {"sequence": encoded_seq, "quality_scores": quality}
|
|
60
|
+
filtered_data, state, meta = filter_op.apply(data, {}, None, None)
|
|
61
|
+
```
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
def __init__(
|
|
65
|
+
self,
|
|
66
|
+
config: QualityFilterConfig,
|
|
67
|
+
*,
|
|
68
|
+
rngs: nnx.Rngs | None = None,
|
|
69
|
+
name: str | None = None,
|
|
70
|
+
):
|
|
71
|
+
"""Initialize the quality filter with learnable threshold.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
config: Quality filter configuration
|
|
75
|
+
rngs: Random number generators (optional for deterministic ops)
|
|
76
|
+
name: Optional operator name
|
|
77
|
+
"""
|
|
78
|
+
super().__init__(config, rngs=rngs, name=name)
|
|
79
|
+
|
|
80
|
+
# Learnable threshold parameter
|
|
81
|
+
self.threshold = init_learnable_param(config.initial_threshold)
|
|
82
|
+
|
|
83
|
+
def apply(
|
|
84
|
+
self,
|
|
85
|
+
data: PyTree,
|
|
86
|
+
state: PyTree,
|
|
87
|
+
metadata: dict[str, Any] | None,
|
|
88
|
+
random_params: Any = None,
|
|
89
|
+
stats: dict[str, Any] | None = None,
|
|
90
|
+
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
91
|
+
"""Apply soft quality filtering to sequence data.
|
|
92
|
+
|
|
93
|
+
This method applies a differentiable quality filter that weights
|
|
94
|
+
each position by sigmoid(quality - threshold). High quality
|
|
95
|
+
positions retain most of their value, while low quality positions
|
|
96
|
+
are down-weighted.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
data: Dictionary containing:
|
|
100
|
+
- "sequence": One-hot encoded sequence (length, alphabet_size)
|
|
101
|
+
- "quality_scores": Phred quality scores (length,)
|
|
102
|
+
state: Element state (passed through unchanged)
|
|
103
|
+
metadata: Element metadata (passed through unchanged)
|
|
104
|
+
random_params: Not used (deterministic operator)
|
|
105
|
+
stats: Not used
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Tuple of (transformed_data, state, metadata):
|
|
109
|
+
- transformed_data contains weighted sequence and original quality
|
|
110
|
+
- state is passed through unchanged
|
|
111
|
+
- metadata is passed through unchanged
|
|
112
|
+
"""
|
|
113
|
+
sequence = data["sequence"]
|
|
114
|
+
quality_scores = data["quality_scores"]
|
|
115
|
+
|
|
116
|
+
# Soft comparison: high quality -> weight ~1, low quality -> weight ~0
|
|
117
|
+
retention_weights = soft_ops.greater(quality_scores, self.threshold[...], softness=1.0)
|
|
118
|
+
|
|
119
|
+
# Apply weights to sequence (broadcast over alphabet dimension)
|
|
120
|
+
weighted_sequence = sequence * retention_weights[:, None]
|
|
121
|
+
|
|
122
|
+
# Build output data (preserve quality scores for downstream use)
|
|
123
|
+
transformed_data = {
|
|
124
|
+
"sequence": weighted_sequence,
|
|
125
|
+
"quality_scores": quality_scores,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return transformed_data, state, metadata
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""RNA secondary structure prediction operators for DiffBio.
|
|
2
|
+
|
|
3
|
+
This module provides differentiable operators for RNA secondary structure
|
|
4
|
+
prediction, following the McCaskill partition function algorithm for
|
|
5
|
+
computing base pair probabilities.
|
|
6
|
+
|
|
7
|
+
Operators:
|
|
8
|
+
DifferentiableRNAFold: McCaskill-style RNA folding with base pair probs
|
|
9
|
+
|
|
10
|
+
Factory Functions:
|
|
11
|
+
create_rna_fold_predictor: Create RNA fold predictor with defaults
|
|
12
|
+
|
|
13
|
+
References:
|
|
14
|
+
McCaskill (1990). The equilibrium partition function and base pair
|
|
15
|
+
binding probabilities for RNA secondary structure.
|
|
16
|
+
|
|
17
|
+
Matthies et al. (2024). Differentiable partition function calculation
|
|
18
|
+
for RNA. Nucleic Acids Research.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from diffbio.operators.rna_structure.rna_folding import (
|
|
22
|
+
DifferentiableRNAFold,
|
|
23
|
+
RNAFoldConfig,
|
|
24
|
+
compute_base_pair_probabilities,
|
|
25
|
+
compute_pair_energy_matrix,
|
|
26
|
+
create_rna_fold_predictor,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"DifferentiableRNAFold",
|
|
31
|
+
"RNAFoldConfig",
|
|
32
|
+
"create_rna_fold_predictor",
|
|
33
|
+
"compute_pair_energy_matrix",
|
|
34
|
+
"compute_base_pair_probabilities",
|
|
35
|
+
]
|