diffbio 0.1.3__tar.gz → 0.1.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {diffbio-0.1.3 → diffbio-0.1.5}/PKG-INFO +8 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/benchmarks/README.md +4 -4
- {diffbio-0.1.3 → diffbio-0.1.5}/pyproject.toml +10 -6
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/base_operators.py +12 -6
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/data_types.py +3 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/__init__.py +4 -0
- diffbio-0.1.5/src/diffbio/core/soft_ops/normalization.py +174 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/uncertainty.py +4 -4
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/evaluation/adapters.py +7 -7
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/_masked_gene_transformer.py +16 -20
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/alignment/profile_hmm.py +2 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/alignment/smith_waterman.py +2 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/alignment/soft_msa.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/assembly/gnn_assembly.py +3 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/assembly/metagenomic_binning.py +5 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/crispr/guide_scoring.py +3 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/drug_discovery/_graph_utils.py +1 -7
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/drug_discovery/admet_predictor.py +4 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/drug_discovery/attentive_fp.py +3 -6
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/drug_discovery/dti.py +3 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/drug_discovery/fingerprint.py +5 -6
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/drug_discovery/maccs_keys.py +4 -5
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/drug_discovery/property_predictor.py +3 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/drug_discovery/similarity.py +3 -6
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/epigenomics/chromatin_state.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/epigenomics/contextual.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/epigenomics/fno_peak_calling.py +3 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/epigenomics/peak_calling.py +6 -6
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/foundation_models/embedding_probe.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/foundation_models/foundation_model.py +6 -6
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/foundation_models/transformer_encoder.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/mapping/neural_mapper.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/metabolomics/isotope_envelope.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/metabolomics/soft_centroiding.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/metabolomics/spectral_similarity.py +3 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/molecular_dynamics/force_field.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/molecular_dynamics/integrator.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/multiomics/hic_contact.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/multiomics/multiomics_vae.py +4 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/multiomics/spatial_deconvolution.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/multiomics/spatial_gene_detection.py +1 -1
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/normalization/arcsinh_cofactor.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/normalization/differentiable_pca.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/normalization/embedding.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/normalization/learnable_normalization.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/normalization/learnable_orthogonal_projection.py +4 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/normalization/learnable_projection.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/normalization/matrix_free_pca.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/normalization/phate.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/normalization/scaling.py +4 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/normalization/soft_pca.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/normalization/umap.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/normalization/vae_normalizer.py +4 -5
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/population/ancestry_estimation.py +3 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/preprocessing/__init__.py +10 -5
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/preprocessing/adapter_removal.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/preprocessing/duplicate_filter.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/preprocessing/error_correction.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/protein/secondary_structure.py +3 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/quality_filter.py +3 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/rna_structure/rna_folding.py +3 -4
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/rnaseq/motif_discovery.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/rnaseq/splicing_psi.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/ambient_removal.py +4 -4
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/archetypes.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/batch_correction.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/cell_annotation.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/communication.py +4 -4
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/differential_distribution.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/doublet_detection.py +14 -53
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/downsampling.py +6 -11
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/enhanced_batch_correction.py +4 -4
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/grn_inference.py +3 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/imputation.py +8 -8
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/ot_trajectory.py +3 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/simulation.py +14 -34
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/sindy_grn.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/soft_clustering.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/soft_hvg.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/spatial_domains.py +4 -4
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/stochastic_gate_selector.py +6 -9
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/switch_de.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/trajectory.py +5 -4
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/velocity.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/statistical/em_quantification.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/statistical/hmm.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/statistical/nb_glm.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/variant/classifier.py +4 -4
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/variant/cnn_classifier.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/variant/cnv_segmentation.py +4 -4
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/variant/deepvariant_pileup.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/variant/pileup.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/variant/quality_recalibration.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/pipelines/adapters.py +4 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/pipelines/differential_expression.py +3 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/pipelines/enhanced_variant_calling.py +13 -7
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/pipelines/joint_preprocessing.py +4 -3
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/pipelines/preprocessing.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/pipelines/single_cell.py +19 -11
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/pipelines/variant_calling.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/anndata_source.py +1 -1
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/archive_ii.py +1 -1
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/balifam.py +1 -1
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/bengrn_ground_truth.py +2 -2
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/encode_peaks.py +1 -1
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/immune_human.py +1 -1
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/pancreas.py +1 -1
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/seqfish.py +1 -1
- {diffbio-0.1.3 → diffbio-0.1.5}/.gitignore +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/LICENSE +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/README.md +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/benchmarks/crossmodality/README.md +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/examples/README.md +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/configs.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/constants.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/gnn_components.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/graph_utils.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/neural_components.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/optimal_transport.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/_projections_permutahedron.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/_projections_simplex.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/_projections_transport.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/_sorting_network.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/_types.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/_utils.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/autograd_safe.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/comparison.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/elementwise.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/logical.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/quantile.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/selection.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/sorting.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/core/soft_ops/straight_through.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/evaluation/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/evaluation/graders.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/evaluation/problem.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/evaluation/runner.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/losses/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/losses/alignment_losses.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/losses/biological_regularization.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/losses/metric_losses.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/losses/self_supervised_losses.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/losses/singlecell_losses.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/losses/statistical_losses.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/_count_vae.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/_loss_balancing.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/_transformer_validation.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/alignment/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/alignment/scoring.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/assembly/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/crispr/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/drug_discovery/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/drug_discovery/message_passing.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/drug_discovery/primitives.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/epigenomics/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/foundation_models/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/foundation_models/adapters.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/foundation_models/contracts.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/foundation_models/experimental.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/foundation_models/frozen.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/foundation_models/precomputed.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/mapping/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/metabolomics/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/molecular_dynamics/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/molecular_dynamics/primitives.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/multiomics/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/normalization/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/population/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/protein/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/rna_structure/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/rnaseq/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/singlecell/knockdown_filter.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/statistical/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/variant/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/operators/variant/learnable_pileup.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/pipelines/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/pipelines/joint_training.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/pipelines/minibatch_training.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/pipelines/perturbation.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/reductions/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/reductions/base.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/reductions/pca_reduction.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/reductions/tfidf_reduction.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/samplers/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/samplers/perturbation_sampler.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sequences/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sequences/dna.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sequences/kmer.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/_anndata_shared.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/_batch_iteration.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/_benchmark_source.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/_indexed_batch_source.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/_utils.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/anndata_interop.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/bam.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/contextual_epigenomics.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/dti.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/embeddings.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/fasta.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/indexed_embeddings.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/indexed_view.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/molnet.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/multiomics.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/perturbation/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/perturbation/_types.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/perturbation/_utils.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/perturbation/concat_source.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/perturbation/control_mapping.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/perturbation/experiment_config.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/perturbation/h5_metadata_cache.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/perturbation/output_space.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/perturbation/perturbation_source.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/sequence_foundation.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/sources/singlecell_foundation.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/splitters/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/splitters/base.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/splitters/molecular.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/splitters/perturbation.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/splitters/random.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/splitters/sequence.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/utils/__init__.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/utils/dependency_runtime.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/utils/nn_utils.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/utils/quality.py +0 -0
- {diffbio-0.1.3 → diffbio-0.1.5}/src/diffbio/utils/training.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: diffbio
|
|
3
|
-
Version: 0.1.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 0.1.5
|
|
4
|
+
Summary: End-to-end differentiable bioinformatics for JAX/Flax NNX: alignment, mapping, assembly, variant calling, RNA-seq, single-cell, epigenomics, CRISPR, metabolomics, multi-omics, protein and RNA structure, molecular dynamics and drug-discovery operators composed into trainable pipelines on datarax, artifex, opifex and calibrax
|
|
5
5
|
Project-URL: Bug Tracker, https://github.com/avitai/DiffBio/issues
|
|
6
6
|
Project-URL: Documentation, https://diffbio.readthedocs.io
|
|
7
7
|
Project-URL: Source, https://github.com/avitai/DiffBio
|
|
@@ -50,7 +50,7 @@ Requires-Dist: beartype>=0.14.1
|
|
|
50
50
|
Requires-Dist: biopython>=1.81
|
|
51
51
|
Requires-Dist: calibrax>=0.1.5
|
|
52
52
|
Requires-Dist: chex>=0.1.7
|
|
53
|
-
Requires-Dist: datarax>=0.1.
|
|
53
|
+
Requires-Dist: datarax>=0.1.10
|
|
54
54
|
Requires-Dist: flax>=0.12.9
|
|
55
55
|
Requires-Dist: h5py>=3.7
|
|
56
56
|
Requires-Dist: jax-md>=0.2.27
|
|
@@ -74,6 +74,7 @@ Requires-Dist: griffe>=1.7.3; extra == 'all'
|
|
|
74
74
|
Requires-Dist: import-linter>=2.5; extra == 'all'
|
|
75
75
|
Requires-Dist: interrogate>=1.7.0; extra == 'all'
|
|
76
76
|
Requires-Dist: ipykernel>=6.29.5; extra == 'all'
|
|
77
|
+
Requires-Dist: jax-metal>=0.1.0; (sys_platform == 'darwin' and platform_machine == 'arm64') and extra == 'all'
|
|
77
78
|
Requires-Dist: jax[cuda12]>=0.11.1; extra == 'all'
|
|
78
79
|
Requires-Dist: lineax>=0.0.8; extra == 'all'
|
|
79
80
|
Requires-Dist: matplotlib>=3.7; extra == 'all'
|
|
@@ -101,6 +102,7 @@ Requires-Dist: pytest-timeout>=2.1; extra == 'all'
|
|
|
101
102
|
Requires-Dist: pytest-xdist>=3.6; extra == 'all'
|
|
102
103
|
Requires-Dist: pytest>=8.3.5; extra == 'all'
|
|
103
104
|
Requires-Dist: python-dotenv>=1; extra == 'all'
|
|
105
|
+
Requires-Dist: pyyaml>=6; extra == 'all'
|
|
104
106
|
Requires-Dist: radon>=6.0.1; extra == 'all'
|
|
105
107
|
Requires-Dist: rdkit>=2025.9.3; extra == 'all'
|
|
106
108
|
Requires-Dist: ruff>=0.1.5; extra == 'all'
|
|
@@ -185,6 +187,8 @@ Requires-Dist: pymdown-extensions>=10.14.3; extra == 'docs'
|
|
|
185
187
|
Provides-Extra: genomics
|
|
186
188
|
Requires-Dist: pyfaidx>=0.8.0; extra == 'genomics'
|
|
187
189
|
Requires-Dist: pysam>=0.22.0; extra == 'genomics'
|
|
190
|
+
Provides-Extra: metal
|
|
191
|
+
Requires-Dist: jax-metal>=0.1.0; (sys_platform == 'darwin' and platform_machine == 'arm64') and extra == 'metal'
|
|
188
192
|
Provides-Extra: soft-ops-advanced
|
|
189
193
|
Requires-Dist: lineax>=0.0.8; extra == 'soft-ops-advanced'
|
|
190
194
|
Requires-Dist: optimistix>=0.0.9; extra == 'soft-ops-advanced'
|
|
@@ -203,6 +207,7 @@ Requires-Dist: pytest-randomly>=3.16.0; extra == 'test'
|
|
|
203
207
|
Requires-Dist: pytest-timeout>=2.1; extra == 'test'
|
|
204
208
|
Requires-Dist: pytest-xdist>=3.6; extra == 'test'
|
|
205
209
|
Requires-Dist: pytest>=8.3.5; extra == 'test'
|
|
210
|
+
Requires-Dist: pyyaml>=6; extra == 'test'
|
|
206
211
|
Provides-Extra: torch-io
|
|
207
212
|
Requires-Dist: torch>=1.13.0; extra == 'torch-io'
|
|
208
213
|
Description-Content-Type: text/markdown
|
|
@@ -90,13 +90,13 @@ Download datasets before running:
|
|
|
90
90
|
|
|
91
91
|
```bash
|
|
92
92
|
# Single-cell (immune_human, 2GB)
|
|
93
|
-
mkdir -p /
|
|
94
|
-
wget -O /
|
|
93
|
+
mkdir -p /mnt/ssd2/Data/scib
|
|
94
|
+
wget -O /mnt/ssd2/Data/scib/Immune_ALL_human.h5ad \
|
|
95
95
|
"https://ndownloader.figshare.com/files/25717328"
|
|
96
96
|
|
|
97
97
|
# Trajectory (pancreas, 51MB)
|
|
98
|
-
mkdir -p /
|
|
99
|
-
wget -O /
|
|
98
|
+
mkdir -p /mnt/ssd2/Data/scvelo
|
|
99
|
+
wget -O /mnt/ssd2/Data/scvelo/endocrinogenesis_day15.h5ad \
|
|
100
100
|
"https://github.com/theislab/scvelo_notebooks/raw/master/data/Pancreas/endocrinogenesis_day15.h5ad"
|
|
101
101
|
```
|
|
102
102
|
|
|
@@ -37,7 +37,7 @@ classifiers = [
|
|
|
37
37
|
]
|
|
38
38
|
dependencies = [
|
|
39
39
|
# Datarax - operator, source, and pipeline contracts
|
|
40
|
-
"datarax>=0.1.
|
|
40
|
+
"datarax>=0.1.10",
|
|
41
41
|
# Artifex - modeling, modality, and transformer substrate
|
|
42
42
|
"avitai-artifex>=0.1.5",
|
|
43
43
|
# Opifex - scientific ML, operator learning, and advanced optimization
|
|
@@ -64,16 +64,16 @@ dependencies = [
|
|
|
64
64
|
"h5py>=3.7",
|
|
65
65
|
"jax-md>=0.2.27"
|
|
66
66
|
]
|
|
67
|
-
description = "
|
|
67
|
+
description = "End-to-end differentiable bioinformatics for JAX/Flax NNX: alignment, mapping, assembly, variant calling, RNA-seq, single-cell, epigenomics, CRISPR, metabolomics, multi-omics, protein and RNA structure, molecular dynamics and drug-discovery operators composed into trainable pipelines on datarax, artifex, opifex and calibrax"
|
|
68
68
|
keywords = ["jax", "flax", "bioinformatics", "differentiable", "variant-calling", "alignment", "machine-learning"]
|
|
69
69
|
license = {file = "LICENSE"}
|
|
70
70
|
name = "diffbio"
|
|
71
71
|
readme = "README.md"
|
|
72
72
|
requires-python = ">=3.12,<3.14"
|
|
73
|
-
version = "0.1.
|
|
73
|
+
version = "0.1.5"
|
|
74
74
|
|
|
75
75
|
[project.optional-dependencies]
|
|
76
|
-
all = ["diffbio[benchmark,chem,cuda12,dev,docs,genomics,soft-ops-advanced,soft-ops-ot,test,torch-io]"]
|
|
76
|
+
all = ["diffbio[benchmark,chem,cuda12,dev,docs,genomics,metal,soft-ops-advanced,soft-ops-ot,test,torch-io]"]
|
|
77
77
|
benchmark = [
|
|
78
78
|
# benchmarks/crossmodality/*.py call datasets.load_dataset. It used to arrive
|
|
79
79
|
# transitively through the sibling packages; they now declare their heavy
|
|
@@ -131,6 +131,8 @@ docs = [
|
|
|
131
131
|
"pymdown-extensions>=10.14.3"
|
|
132
132
|
]
|
|
133
133
|
genomics = ["pysam>=0.22.0", "pyfaidx>=0.8.0"]
|
|
134
|
+
# Apple Silicon GPU backend; setup.sh selects it on arm64 macOS.
|
|
135
|
+
metal = ["jax-metal>=0.1.0; sys_platform == 'darwin' and platform_machine == 'arm64'"]
|
|
134
136
|
soft-ops-advanced = ["optimistix>=0.0.9", "lineax>=0.0.8"]
|
|
135
137
|
soft-ops-ot = ["diffbio[soft-ops-advanced]", "ott-jax>=0.5.0"]
|
|
136
138
|
test = [
|
|
@@ -143,7 +145,9 @@ test = [
|
|
|
143
145
|
"pytest-env>=1.0.1",
|
|
144
146
|
"pytest-randomly>=3.16.0",
|
|
145
147
|
"pytest-timeout>=2.1",
|
|
146
|
-
"pytest-xdist>=3.6"
|
|
148
|
+
"pytest-xdist>=3.6",
|
|
149
|
+
# tests/test_ci_shards.py reads the CI workflow.
|
|
150
|
+
"pyyaml>=6"
|
|
147
151
|
]
|
|
148
152
|
torch-io = ["torch>=1.13.0"]
|
|
149
153
|
|
|
@@ -341,7 +345,7 @@ save_data = true
|
|
|
341
345
|
warmup = true
|
|
342
346
|
warmup_iterations = 3
|
|
343
347
|
|
|
344
|
-
[tool.
|
|
348
|
+
[tool.pytest_env]
|
|
345
349
|
JAX_ENABLE_X64 = "0"
|
|
346
350
|
JAX_SKIP_CUDA_CONSTRAINTS_CHECK = "1"
|
|
347
351
|
LD_LIBRARY_PATH = "/usr/local/cuda/lib64"
|
|
@@ -139,7 +139,7 @@ class TemperatureOperator(OperatorModule):
|
|
|
139
139
|
data: PyTree,
|
|
140
140
|
state: PyTree,
|
|
141
141
|
metadata: dict[str, Any] | None,
|
|
142
|
-
|
|
142
|
+
key: jax.Array | None = None,
|
|
143
143
|
stats: dict[str, Any] | None = None,
|
|
144
144
|
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
145
145
|
"""Base apply method - should be overridden by subclasses."""
|
|
@@ -233,7 +233,7 @@ class SequenceOperator(OperatorModule):
|
|
|
233
233
|
data: PyTree,
|
|
234
234
|
state: PyTree,
|
|
235
235
|
metadata: dict[str, Any] | None,
|
|
236
|
-
|
|
236
|
+
key: jax.Array | None = None,
|
|
237
237
|
stats: dict[str, Any] | None = None,
|
|
238
238
|
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
239
239
|
"""Base apply method - should be overridden by subclasses."""
|
|
@@ -278,6 +278,7 @@ class EncoderDecoderOperator(OperatorModule):
|
|
|
278
278
|
self,
|
|
279
279
|
mean: Float[Array, "... latent_dim"],
|
|
280
280
|
log_var: Float[Array, "... latent_dim"],
|
|
281
|
+
key: jax.Array | None = None,
|
|
281
282
|
) -> Float[Array, "... latent_dim"]:
|
|
282
283
|
"""Sample from latent distribution using reparameterization trick.
|
|
283
284
|
|
|
@@ -288,11 +289,16 @@ class EncoderDecoderOperator(OperatorModule):
|
|
|
288
289
|
Args:
|
|
289
290
|
mean: Mean of the latent distribution.
|
|
290
291
|
log_var: Log variance of the latent distribution.
|
|
292
|
+
key: The key to draw epsilon from. ``apply`` passes the record's key, so a
|
|
293
|
+
record's sample follows the record; a training loss such as
|
|
294
|
+
``compute_elbo_loss`` passes none and draws from the operator's ``sample``
|
|
295
|
+
stream, which advances on every call.
|
|
291
296
|
|
|
292
297
|
Returns:
|
|
293
298
|
Sampled latent representation.
|
|
294
299
|
"""
|
|
295
|
-
key
|
|
300
|
+
if key is None:
|
|
301
|
+
key = get_rng_key(self.rngs, "sample", fallback_seed=0)
|
|
296
302
|
std = jnp.exp(0.5 * log_var)
|
|
297
303
|
epsilon = jax.random.normal(key, mean.shape)
|
|
298
304
|
return mean + std * epsilon
|
|
@@ -345,7 +351,7 @@ class EncoderDecoderOperator(OperatorModule):
|
|
|
345
351
|
data: PyTree,
|
|
346
352
|
state: PyTree,
|
|
347
353
|
metadata: dict[str, Any] | None,
|
|
348
|
-
|
|
354
|
+
key: jax.Array | None = None,
|
|
349
355
|
stats: dict[str, Any] | None = None,
|
|
350
356
|
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
351
357
|
"""Base apply method - should be overridden by subclasses."""
|
|
@@ -442,7 +448,7 @@ class GraphOperator(OperatorModule):
|
|
|
442
448
|
data: PyTree,
|
|
443
449
|
state: PyTree,
|
|
444
450
|
metadata: dict[str, Any] | None,
|
|
445
|
-
|
|
451
|
+
key: jax.Array | None = None,
|
|
446
452
|
stats: dict[str, Any] | None = None,
|
|
447
453
|
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
448
454
|
"""Base apply method - should be overridden by subclasses."""
|
|
@@ -593,7 +599,7 @@ class HMMOperator(OperatorModule):
|
|
|
593
599
|
data: PyTree,
|
|
594
600
|
state: PyTree,
|
|
595
601
|
metadata: dict[str, Any] | None,
|
|
596
|
-
|
|
602
|
+
key: jax.Array | None = None,
|
|
597
603
|
stats: dict[str, Any] | None = None,
|
|
598
604
|
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
599
605
|
"""Base apply method - should be overridden by subclasses."""
|
|
@@ -6,6 +6,7 @@ the expected interfaces and data structures across the DiffBio codebase.
|
|
|
6
6
|
|
|
7
7
|
from typing import Any, Protocol, TypedDict, runtime_checkable
|
|
8
8
|
|
|
9
|
+
import jax
|
|
9
10
|
from jaxtyping import Array, Float
|
|
10
11
|
|
|
11
12
|
# =============================================================================
|
|
@@ -166,7 +167,7 @@ class DifferentiableOperator(Protocol):
|
|
|
166
167
|
data: dict[str, Any],
|
|
167
168
|
state: StateDict,
|
|
168
169
|
metadata: MetadataDict,
|
|
169
|
-
|
|
170
|
+
key: jax.Array | None = None,
|
|
170
171
|
stats: dict[str, Any] | None = None,
|
|
171
172
|
) -> OperatorOutput:
|
|
172
173
|
"""Apply the operator to input data.
|
|
@@ -175,7 +176,7 @@ class DifferentiableOperator(Protocol):
|
|
|
175
176
|
data: Input data dictionary.
|
|
176
177
|
state: Element state.
|
|
177
178
|
metadata: Element metadata.
|
|
178
|
-
|
|
179
|
+
key: The record's PRNG key; a stochastic operator draws from it.
|
|
179
180
|
stats: Statistics dictionary.
|
|
180
181
|
|
|
181
182
|
Returns:
|
|
@@ -81,6 +81,9 @@ from diffbio.core.soft_ops.sorting import (
|
|
|
81
81
|
top_k_mask,
|
|
82
82
|
)
|
|
83
83
|
|
|
84
|
+
# --- Range-aware normalization ---
|
|
85
|
+
from diffbio.core.soft_ops.normalization import temperature_softmax
|
|
86
|
+
|
|
84
87
|
# --- Quantile ---
|
|
85
88
|
from diffbio.core.soft_ops.quantile import (
|
|
86
89
|
argmedian,
|
|
@@ -126,6 +129,7 @@ from diffbio.core.soft_ops.straight_through import (
|
|
|
126
129
|
)
|
|
127
130
|
|
|
128
131
|
__all__ = [
|
|
132
|
+
"temperature_softmax",
|
|
129
133
|
# Types
|
|
130
134
|
"SoftBool",
|
|
131
135
|
"SoftIndex",
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"""Temperature softmax with jointly evaluated derivative coefficients.
|
|
2
|
+
|
|
3
|
+
Ordinary division AD forms ``T**-2`` before multiplying the softmax tail.
|
|
4
|
+
The product can be finite even when that reciprocal overflows or the tail
|
|
5
|
+
underflows. Evaluate probability products, score gaps and reciprocal powers
|
|
6
|
+
together in log space. A recursive coefficient JVP preserves mixed derivatives
|
|
7
|
+
at zero gaps; differentiating an outer zero selection would lose them.
|
|
8
|
+
|
|
9
|
+
This requires representable coefficient sums, not merely a representable final
|
|
10
|
+
contraction. Work grows with donor count and derivative order: the first JVP
|
|
11
|
+
has quadratic donor work. It is intended for small donor panels.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from functools import partial
|
|
15
|
+
|
|
16
|
+
import jax
|
|
17
|
+
import jax.numpy as jnp
|
|
18
|
+
from jax import Array
|
|
19
|
+
|
|
20
|
+
from diffbio.core.soft_ops._utils import canonicalize_axis
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
type _Specification = tuple[tuple[int, ...], tuple[tuple[int, int], ...], int]
|
|
24
|
+
type _Inputs = tuple[Array, Array, Array]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _logits(scores: Array, temperature: Array, covered: Array) -> Array:
|
|
28
|
+
"""Shift over covered donors before division, guarding excluded operands."""
|
|
29
|
+
maximum = jnp.max(jnp.where(covered, scores, -jnp.inf), axis=0, keepdims=True)
|
|
30
|
+
shifted = jnp.where(covered, scores - maximum, 0.0)
|
|
31
|
+
return jnp.where(covered, shifted / temperature, -jnp.inf)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _coefficient_value(
|
|
35
|
+
scores: Array, temperature: Array, covered: Array, specification: _Specification
|
|
36
|
+
) -> Array:
|
|
37
|
+
"""Evaluate a probability/gap monomial divided by a temperature power."""
|
|
38
|
+
indices, gaps, power = specification
|
|
39
|
+
log_weights = jax.nn.log_softmax(_logits(scores, temperature, covered), axis=0)
|
|
40
|
+
magnitude = sum(log_weights[index] for index in indices) - power * jnp.log(temperature)
|
|
41
|
+
sign = jnp.ones_like(magnitude)
|
|
42
|
+
nonzero = jnp.ones_like(magnitude, dtype=jnp.bool_)
|
|
43
|
+
for left, right in gaps:
|
|
44
|
+
gap = scores[left] - scores[right]
|
|
45
|
+
nonzero = nonzero & (gap != 0)
|
|
46
|
+
magnitude = magnitude + jnp.log(jnp.where(gap != 0, jnp.abs(gap), 1.0))
|
|
47
|
+
sign = sign * jnp.sign(gap)
|
|
48
|
+
# Guard the exponential too: a zero gap must not create 0 * inf.
|
|
49
|
+
value = sign * jnp.exp(jnp.where(nonzero, magnitude, 0.0))
|
|
50
|
+
return jnp.where(nonzero, value, 0.0)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
_coefficient = jax.custom_jvp(_coefficient_value, nondiff_argnums=(3,))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _coefficient_jvp(
|
|
57
|
+
specification: _Specification, primals: _Inputs, tangents: _Inputs
|
|
58
|
+
) -> tuple[Array, Array]:
|
|
59
|
+
"""Differentiate complete coefficients, including zero-gap extensions."""
|
|
60
|
+
scores, _, _ = primals
|
|
61
|
+
score_dot, temperature_dot, _ = tangents
|
|
62
|
+
indices, gaps, power = specification
|
|
63
|
+
value = _coefficient(*primals, specification)
|
|
64
|
+
derivative = jnp.zeros_like(value)
|
|
65
|
+
thermal = jnp.zeros_like(value)
|
|
66
|
+
for index in indices:
|
|
67
|
+
for other in range(scores.shape[0]):
|
|
68
|
+
if other != index:
|
|
69
|
+
extended = (*indices, other)
|
|
70
|
+
coefficient = _coefficient(*primals, (extended, gaps, power + 1))
|
|
71
|
+
derivative = derivative + coefficient * (score_dot[index] - score_dot[other])
|
|
72
|
+
thermal = thermal + _coefficient(
|
|
73
|
+
*primals, (extended, (*gaps, (other, index)), power + 2)
|
|
74
|
+
)
|
|
75
|
+
for position, (left, right) in enumerate(gaps):
|
|
76
|
+
remaining = gaps[:position] + gaps[position + 1 :]
|
|
77
|
+
derivative = derivative + _coefficient(*primals, (indices, remaining, power)) * (
|
|
78
|
+
score_dot[left] - score_dot[right]
|
|
79
|
+
)
|
|
80
|
+
if power:
|
|
81
|
+
thermal = thermal - power * _coefficient(*primals, (indices, gaps, power + 1))
|
|
82
|
+
return value, derivative + thermal * temperature_dot
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
_coefficient.defjvp(_coefficient_jvp)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@jax.custom_jvp
|
|
89
|
+
def _weights(scores: Array, temperature: Array, covered: Array) -> Array:
|
|
90
|
+
"""Keep the native shifted forward softmax arithmetic."""
|
|
91
|
+
return jax.nn.softmax(_logits(scores, temperature, covered), axis=0)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _weights_jvp(primals: _Inputs, tangents: _Inputs) -> tuple[Array, Array]:
|
|
95
|
+
"""Contract pairwise sensitivities without rounding either probability first."""
|
|
96
|
+
scores, _, _ = primals
|
|
97
|
+
score_dot, temperature_dot, _ = tangents
|
|
98
|
+
value = _weights(*primals)
|
|
99
|
+
rows = []
|
|
100
|
+
for index in range(scores.shape[0]):
|
|
101
|
+
derivative = jnp.zeros_like(value[index])
|
|
102
|
+
for other in range(scores.shape[0]):
|
|
103
|
+
if other != index:
|
|
104
|
+
probability = (index, other)
|
|
105
|
+
spatial = _coefficient(*primals, (probability, (), 1))
|
|
106
|
+
thermal = _coefficient(*primals, (probability, ((other, index),), 2))
|
|
107
|
+
derivative = derivative + spatial * (score_dot[index] - score_dot[other])
|
|
108
|
+
derivative = derivative + thermal * temperature_dot
|
|
109
|
+
rows.append(derivative)
|
|
110
|
+
return value, jnp.stack(rows)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
_weights.defjvp(_weights_jvp)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@partial(jax.jit, static_argnames=("axis",))
|
|
117
|
+
def temperature_softmax(
|
|
118
|
+
scores: Array,
|
|
119
|
+
temperature: float | Array = 1.0,
|
|
120
|
+
*,
|
|
121
|
+
axis: int = -1,
|
|
122
|
+
where: Array | None = None,
|
|
123
|
+
) -> Array:
|
|
124
|
+
"""Normalize small score axes with range-aware temperature derivatives.
|
|
125
|
+
|
|
126
|
+
Equivalent to masked ``jax.nn.softmax(scores / temperature, axis=axis)``
|
|
127
|
+
for valid inputs. Shift before division and evaluate complete derivative
|
|
128
|
+
coefficients in signed log space, preserving sensitivities even when a
|
|
129
|
+
probability rounds to zero or one. Supports JVP, VJP and higher derivatives.
|
|
130
|
+
|
|
131
|
+
This is an opt-in operation for small axes, not the default sorting kernel:
|
|
132
|
+
first derivatives require quadratic axis work and higher orders cost more.
|
|
133
|
+
Coefficients, score differences and their necessary sums must be representable;
|
|
134
|
+
a representable final contraction alone does not guarantee a finite derivative.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
scores: Real floating array. Included scores and their pairwise differences
|
|
138
|
+
must be finite. Excluded scores are ignored, including NaN/infinity.
|
|
139
|
+
temperature: Positive finite real scalar. Callers own runtime validation;
|
|
140
|
+
nonpositive/nonfinite values are outside this numerical contract.
|
|
141
|
+
axis: Static reduction axis. Must be nonempty.
|
|
142
|
+
where: Boolean mask broadcastable to the score shape. Empty slices return
|
|
143
|
+
zero weights and zero derivatives, matching native masked softmax.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
Weights with the score shape and standard floating dtype promotion.
|
|
147
|
+
|
|
148
|
+
Raises:
|
|
149
|
+
TypeError: Scores are not floating, temperature is complex, or mask is not boolean.
|
|
150
|
+
ValueError: Temperature is not scalar, the axis is invalid/empty, or mask cannot broadcast.
|
|
151
|
+
"""
|
|
152
|
+
scores = jnp.asarray(scores)
|
|
153
|
+
temperature = jnp.asarray(temperature)
|
|
154
|
+
if not jnp.issubdtype(scores.dtype, jnp.floating):
|
|
155
|
+
raise TypeError("scores must have a real floating dtype")
|
|
156
|
+
if jnp.issubdtype(temperature.dtype, jnp.complexfloating):
|
|
157
|
+
raise TypeError("temperature must be real")
|
|
158
|
+
if temperature.ndim != 0:
|
|
159
|
+
raise ValueError("temperature must be scalar")
|
|
160
|
+
temperature = temperature.astype(jnp.result_type(scores, temperature))
|
|
161
|
+
axis = canonicalize_axis(axis, scores.ndim)
|
|
162
|
+
if scores.shape[axis] == 0:
|
|
163
|
+
raise ValueError("the normalization axis must be nonempty")
|
|
164
|
+
covered = jnp.ones_like(scores, dtype=jnp.bool_) if where is None else jnp.asarray(where)
|
|
165
|
+
if covered.dtype != jnp.bool_:
|
|
166
|
+
raise TypeError("where must have boolean dtype")
|
|
167
|
+
covered = jnp.broadcast_to(covered, scores.shape)
|
|
168
|
+
scores, covered = jnp.moveaxis(scores, axis, 0), jnp.moveaxis(covered, axis, 0)
|
|
169
|
+
scores = jnp.where(covered, scores, 0.0)
|
|
170
|
+
populated = jnp.any(covered, axis=0, keepdims=True)
|
|
171
|
+
first = (jnp.arange(scores.shape[0]) == 0).reshape((-1,) + (1,) * (scores.ndim - 1))
|
|
172
|
+
safe_coverage = covered | (first & ~populated)
|
|
173
|
+
value = _weights(scores, temperature, safe_coverage)
|
|
174
|
+
return jnp.moveaxis(jnp.where(populated, value, 0.0), 0, axis)
|
|
@@ -161,7 +161,7 @@ class EnsembleUQOperator(OperatorModule):
|
|
|
161
161
|
data: PyTree,
|
|
162
162
|
state: PyTree,
|
|
163
163
|
metadata: dict[str, Any] | None,
|
|
164
|
-
|
|
164
|
+
key: jax.Array | None = None, # noqa: ARG002
|
|
165
165
|
stats: dict[str, Any] | None = None, # noqa: ARG002
|
|
166
166
|
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
167
167
|
"""Run ensemble forward passes and aggregate with uncertainty.
|
|
@@ -170,7 +170,7 @@ class EnsembleUQOperator(OperatorModule):
|
|
|
170
170
|
data: Input data dict for the base operator.
|
|
171
171
|
state: Element state (passed through).
|
|
172
172
|
metadata: Element metadata (passed through).
|
|
173
|
-
|
|
173
|
+
key: Unused.
|
|
174
174
|
stats: Unused.
|
|
175
175
|
|
|
176
176
|
Returns:
|
|
@@ -241,7 +241,7 @@ class MCSamplingUQOperator(OperatorModule):
|
|
|
241
241
|
data: PyTree,
|
|
242
242
|
state: PyTree,
|
|
243
243
|
metadata: dict[str, Any] | None,
|
|
244
|
-
|
|
244
|
+
key: jax.Array | None = None, # noqa: ARG002
|
|
245
245
|
stats: dict[str, Any] | None = None, # noqa: ARG002
|
|
246
246
|
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
247
247
|
"""Run Monte Carlo sampling to estimate empirical intervals.
|
|
@@ -250,7 +250,7 @@ class MCSamplingUQOperator(OperatorModule):
|
|
|
250
250
|
data: Input data dict for the base operator.
|
|
251
251
|
state: Element state (passed through).
|
|
252
252
|
metadata: Element metadata (passed through).
|
|
253
|
-
|
|
253
|
+
key: Unused.
|
|
254
254
|
stats: Unused.
|
|
255
255
|
|
|
256
256
|
Returns:
|
|
@@ -135,7 +135,7 @@ class TaskAdapter:
|
|
|
135
135
|
else:
|
|
136
136
|
adapted = data_dict
|
|
137
137
|
|
|
138
|
-
result, _, _ = operator.apply(adapted, {}, None)
|
|
138
|
+
result, _, _ = operator.apply(adapted, {}, None, jax.random.key(self._seed))
|
|
139
139
|
# Propagate retention info
|
|
140
140
|
if "retention_weights" not in result and "quality_scores" in adapted:
|
|
141
141
|
quality = adapted["quality_scores"]
|
|
@@ -160,7 +160,7 @@ class TaskAdapter:
|
|
|
160
160
|
temperature=temperature,
|
|
161
161
|
)
|
|
162
162
|
operator = SoftKMeansClustering(op_config, rngs=nnx.Rngs(self._seed))
|
|
163
|
-
result, _, _ = operator.apply(data_dict, {}, None)
|
|
163
|
+
result, _, _ = operator.apply(data_dict, {}, None, jax.random.key(self._seed))
|
|
164
164
|
return result
|
|
165
165
|
|
|
166
166
|
def _run_de(self, data_dict: dict[str, Any], config: dict[str, Any]) -> dict[str, Any]:
|
|
@@ -178,7 +178,7 @@ class TaskAdapter:
|
|
|
178
178
|
n_conditions=n_conditions,
|
|
179
179
|
)
|
|
180
180
|
pipeline = DifferentialExpressionPipeline(op_config, rngs=nnx.Rngs(self._seed))
|
|
181
|
-
result, _, _ = pipeline.apply(data_dict, {}, None)
|
|
181
|
+
result, _, _ = pipeline.apply(data_dict, {}, None, jax.random.key(self._seed))
|
|
182
182
|
|
|
183
183
|
# Add gene names for grader extraction
|
|
184
184
|
if "gene_names" not in result:
|
|
@@ -202,7 +202,7 @@ class TaskAdapter:
|
|
|
202
202
|
n_clusters=n_clusters,
|
|
203
203
|
)
|
|
204
204
|
operator = DifferentiableHarmony(op_config, rngs=nnx.Rngs(self._seed))
|
|
205
|
-
result, _, _ = operator.apply(data_dict, {}, None)
|
|
205
|
+
result, _, _ = operator.apply(data_dict, {}, None, jax.random.key(self._seed))
|
|
206
206
|
return result
|
|
207
207
|
|
|
208
208
|
def _run_normalization(
|
|
@@ -222,7 +222,7 @@ class TaskAdapter:
|
|
|
222
222
|
latent_dim=latent_dim,
|
|
223
223
|
)
|
|
224
224
|
operator = VAENormalizer(op_config, rngs=nnx.Rngs(self._seed))
|
|
225
|
-
result, _, _ = operator.apply(data_dict, {}, None)
|
|
225
|
+
result, _, _ = operator.apply(data_dict, {}, None, jax.random.key(self._seed))
|
|
226
226
|
return result
|
|
227
227
|
|
|
228
228
|
def _run_trajectory(self, data_dict: dict[str, Any], config: dict[str, Any]) -> dict[str, Any]:
|
|
@@ -240,7 +240,7 @@ class TaskAdapter:
|
|
|
240
240
|
n_diffusion_components=n_diffusion_components,
|
|
241
241
|
)
|
|
242
242
|
operator = DifferentiablePseudotime(op_config, rngs=nnx.Rngs(self._seed))
|
|
243
|
-
result, _, _ = operator.apply(data_dict, {}, None)
|
|
243
|
+
result, _, _ = operator.apply(data_dict, {}, None, jax.random.key(self._seed))
|
|
244
244
|
return result
|
|
245
245
|
|
|
246
246
|
def _run_spatial_analysis(
|
|
@@ -260,7 +260,7 @@ class TaskAdapter:
|
|
|
260
260
|
n_domains=n_domains,
|
|
261
261
|
)
|
|
262
262
|
operator = DifferentiableSpatialDomain(op_config, rngs=nnx.Rngs(self._seed))
|
|
263
|
-
result, _, _ = operator.apply(data_dict, {}, None)
|
|
263
|
+
result, _, _ = operator.apply(data_dict, {}, None, jax.random.key(self._seed))
|
|
264
264
|
return result
|
|
265
265
|
|
|
266
266
|
def _run_cell_annotation(
|
|
@@ -8,7 +8,6 @@ construction and one mask/input preparation flow.
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
from dataclasses import dataclass
|
|
11
|
-
from typing import Any
|
|
12
11
|
|
|
13
12
|
import jax
|
|
14
13
|
import jax.numpy as jnp
|
|
@@ -63,28 +62,34 @@ def build_masked_gene_transformer_encoder(
|
|
|
63
62
|
|
|
64
63
|
def build_masked_gene_mask(
|
|
65
64
|
*,
|
|
66
|
-
|
|
65
|
+
key: jax.Array | None,
|
|
67
66
|
mask_ratio: float,
|
|
68
67
|
n_genes: int,
|
|
69
68
|
) -> Array:
|
|
70
|
-
"""Build a per-gene binary mask for masked-gene transformer operators.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
69
|
+
"""Build a per-gene binary mask for masked-gene transformer operators.
|
|
70
|
+
|
|
71
|
+
With ``mask_ratio == 0`` nothing is masked and no key is needed; otherwise the mask is
|
|
72
|
+
drawn from ``key``, which must be given.
|
|
73
|
+
"""
|
|
74
|
+
if mask_ratio <= 0:
|
|
75
|
+
return jnp.zeros(n_genes, dtype=jnp.float32)
|
|
76
|
+
if key is None:
|
|
77
|
+
raise ValueError("masking genes needs the record's PRNG key")
|
|
78
|
+
noise = jax.random.uniform(key, (n_genes,))
|
|
79
|
+
return (noise < mask_ratio).astype(jnp.float32)
|
|
75
80
|
|
|
76
81
|
|
|
77
82
|
def prepare_masked_gene_batch(
|
|
78
83
|
data: PyTree,
|
|
79
84
|
*,
|
|
80
|
-
|
|
85
|
+
key: jax.Array | None,
|
|
81
86
|
mask_ratio: float,
|
|
82
87
|
) -> tuple[Array, Array, Array]:
|
|
83
88
|
"""Extract counts, int32 gene IDs, and the shared masking vector."""
|
|
84
89
|
counts = data["counts"]
|
|
85
90
|
gene_ids = jnp.asarray(data["gene_ids"], dtype=jnp.int32)
|
|
86
91
|
mask = build_masked_gene_mask(
|
|
87
|
-
|
|
92
|
+
key=key,
|
|
88
93
|
mask_ratio=mask_ratio,
|
|
89
94
|
n_genes=int(counts.shape[1]),
|
|
90
95
|
)
|
|
@@ -96,23 +101,14 @@ class MaskedGeneTransformerOperatorMixin:
|
|
|
96
101
|
|
|
97
102
|
config: MaskedGeneTransformerConfigBase
|
|
98
103
|
|
|
99
|
-
def generate_random_params(
|
|
100
|
-
self,
|
|
101
|
-
rng: jax.Array,
|
|
102
|
-
data_shapes: PyTree,
|
|
103
|
-
) -> jax.Array:
|
|
104
|
-
"""Return the RNG key used for reproducible masking inside apply."""
|
|
105
|
-
del data_shapes
|
|
106
|
-
return rng
|
|
107
|
-
|
|
108
104
|
def prepare_masked_gene_batch(
|
|
109
105
|
self,
|
|
110
106
|
data: PyTree,
|
|
111
|
-
|
|
107
|
+
key: jax.Array | None,
|
|
112
108
|
) -> tuple[Array, Array, Array]:
|
|
113
109
|
"""Prepare shared masked-gene inputs for per-cell `vmap` execution."""
|
|
114
110
|
return prepare_masked_gene_batch(
|
|
115
111
|
data,
|
|
116
|
-
|
|
112
|
+
key=key,
|
|
117
113
|
mask_ratio=self.config.mask_ratio,
|
|
118
114
|
)
|
|
@@ -41,7 +41,6 @@ class ProfileHMMConfig(OperatorConfig):
|
|
|
41
41
|
learnable_profile: Whether profile parameters are learnable.
|
|
42
42
|
"""
|
|
43
43
|
|
|
44
|
-
cacheable: bool = True
|
|
45
44
|
profile_length: int = 100
|
|
46
45
|
alphabet_size: int = 20 # Amino acids by default
|
|
47
46
|
temperature: float = 1.0
|
|
@@ -309,7 +308,7 @@ class ProfileHMMSearch(TemperatureOperator):
|
|
|
309
308
|
data: PyTree,
|
|
310
309
|
state: PyTree,
|
|
311
310
|
metadata: dict[str, Any] | None,
|
|
312
|
-
|
|
311
|
+
key: jax.Array | None = None,
|
|
313
312
|
stats: dict[str, Any] | None = None,
|
|
314
313
|
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
315
314
|
"""Apply profile HMM search to sequence.
|
|
@@ -319,7 +318,7 @@ class ProfileHMMSearch(TemperatureOperator):
|
|
|
319
318
|
- "sequence": One-hot encoded sequence (seq_len, alphabet_size)
|
|
320
319
|
state: Element state (passed through unchanged)
|
|
321
320
|
metadata: Element metadata (passed through unchanged)
|
|
322
|
-
|
|
321
|
+
key: Unused.
|
|
323
322
|
stats: Not used
|
|
324
323
|
|
|
325
324
|
Returns:
|
|
@@ -39,7 +39,6 @@ class SmithWatermanConfig(TemperatureConfig):
|
|
|
39
39
|
gap_extend: Penalty for extending a gap.
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
|
-
cacheable: bool = True
|
|
43
42
|
gap_open: float = DEFAULT_GAP_OPEN
|
|
44
43
|
gap_extend: float = DEFAULT_GAP_EXTEND
|
|
45
44
|
|
|
@@ -216,7 +215,7 @@ class SmoothSmithWaterman(TemperatureOperator):
|
|
|
216
215
|
data: PyTree,
|
|
217
216
|
state: PyTree,
|
|
218
217
|
metadata: dict[str, Any] | None,
|
|
219
|
-
|
|
218
|
+
key: jax.Array | None = None,
|
|
220
219
|
stats: dict[str, Any] | None = None,
|
|
221
220
|
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
222
221
|
"""Apply alignment to sequence pair data.
|
|
@@ -233,7 +232,7 @@ class SmoothSmithWaterman(TemperatureOperator):
|
|
|
233
232
|
- "seq2": Second sequence, one-hot encoded (len2, alphabet_size)
|
|
234
233
|
state: Element state (passed through unchanged)
|
|
235
234
|
metadata: Element metadata (passed through unchanged)
|
|
236
|
-
|
|
235
|
+
key: Unused.
|
|
237
236
|
stats: Not used
|
|
238
237
|
|
|
239
238
|
Returns:
|
|
@@ -339,7 +339,7 @@ class SoftProgressiveMSA(TemperatureOperator):
|
|
|
339
339
|
data: PyTree,
|
|
340
340
|
state: PyTree,
|
|
341
341
|
metadata: dict[str, Any] | None,
|
|
342
|
-
|
|
342
|
+
key: jax.Array | None = None,
|
|
343
343
|
stats: dict[str, Any] | None = None,
|
|
344
344
|
) -> tuple[PyTree, PyTree, dict[str, Any] | None]:
|
|
345
345
|
"""Apply soft progressive MSA.
|
|
@@ -349,7 +349,7 @@ class SoftProgressiveMSA(TemperatureOperator):
|
|
|
349
349
|
- "sequences": Input sequences (n_seqs, seq_len, alphabet_size)
|
|
350
350
|
state: Element state (passed through unchanged)
|
|
351
351
|
metadata: Element metadata (passed through unchanged)
|
|
352
|
-
|
|
352
|
+
key: Unused.
|
|
353
353
|
stats: Not used
|
|
354
354
|
|
|
355
355
|
Returns:
|