dnakit 0.1.0.dev0__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.
- dnakit/__init__.py +108 -0
- dnakit/_version.py +5 -0
- dnakit/alignment/__init__.py +6 -0
- dnakit/alignment/pairwise.py +512 -0
- dnakit/alignment/results.py +188 -0
- dnakit/backends/__init__.py +80 -0
- dnakit/backends/external.py +517 -0
- dnakit/backends/registry.py +207 -0
- dnakit/batch.py +452 -0
- dnakit/cache/__init__.py +5 -0
- dnakit/cache/store.py +424 -0
- dnakit/chunking.py +920 -0
- dnakit/cli/__init__.py +5 -0
- dnakit/cli/__main__.py +6 -0
- dnakit/cli/app.py +814 -0
- dnakit/cli/workflow.py +94 -0
- dnakit/config/__init__.py +5 -0
- dnakit/config/loader.py +381 -0
- dnakit/core/__init__.py +80 -0
- dnakit/core/_json.py +206 -0
- dnakit/core/backend_info.py +70 -0
- dnakit/core/collection.py +163 -0
- dnakit/core/coordinates.py +295 -0
- dnakit/core/enums.py +95 -0
- dnakit/core/facade.py +719 -0
- dnakit/core/feature.py +90 -0
- dnakit/core/gap.py +82 -0
- dnakit/core/issues.py +62 -0
- dnakit/core/provenance.py +305 -0
- dnakit/core/record.py +161 -0
- dnakit/core/results.py +134 -0
- dnakit/core/sequence.py +327 -0
- dnakit/datasets/__init__.py +100 -0
- dnakit/datasets/_advanced_shared.py +198 -0
- dnakit/datasets/_metadata.py +33 -0
- dnakit/datasets/advanced_deduplicate.py +183 -0
- dnakit/datasets/advanced_split.py +302 -0
- dnakit/datasets/clustering.py +286 -0
- dnakit/datasets/config.py +531 -0
- dnakit/datasets/deduplicate.py +303 -0
- dnakit/datasets/evaluation.py +244 -0
- dnakit/datasets/filter.py +135 -0
- dnakit/datasets/neural_clustering.py +221 -0
- dnakit/datasets/results.py +520 -0
- dnakit/datasets/split.py +450 -0
- dnakit/descriptors/__init__.py +102 -0
- dnakit/descriptors/_dinucleotide.py +345 -0
- dnakit/descriptors/_shared.py +180 -0
- dnakit/descriptors/all.py +917 -0
- dnakit/descriptors/basic.py +193 -0
- dnakit/descriptors/codon.py +195 -0
- dnakit/descriptors/complexity.py +201 -0
- dnakit/descriptors/entropy.py +101 -0
- dnakit/descriptors/homopolymer.py +105 -0
- dnakit/descriptors/kmer.py +88 -0
- dnakit/descriptors/results.py +286 -0
- dnakit/descriptors/schema.py +414 -0
- dnakit/descriptors/window.py +203 -0
- dnakit/download/__init__.py +54 -0
- dnakit/download/catalogs.py +166 -0
- dnakit/download/ena.py +131 -0
- dnakit/download/encode.py +103 -0
- dnakit/download/files.py +469 -0
- dnakit/download/indexes.py +233 -0
- dnakit/download/metadata.py +164 -0
- dnakit/download/models.py +227 -0
- dnakit/download/ncbi.py +333 -0
- dnakit/download/sequence.py +133 -0
- dnakit/download/ucsc.py +99 -0
- dnakit/evaluation/__init__.py +81 -0
- dnakit/evaluation/_shared.py +288 -0
- dnakit/evaluation/collection.py +270 -0
- dnakit/evaluation/config.py +591 -0
- dnakit/evaluation/distribution.py +287 -0
- dnakit/evaluation/frechet.py +223 -0
- dnakit/evaluation/generative.py +381 -0
- dnakit/evaluation/reference.py +409 -0
- dnakit/evaluation/results.py +137 -0
- dnakit/evaluation/scorecard.py +211 -0
- dnakit/evaluation/sequence.py +403 -0
- dnakit/evaluation/synthesis.py +249 -0
- dnakit/exceptions.py +189 -0
- dnakit/fingerprints/__init__.py +109 -0
- dnakit/fingerprints/_shared.py +116 -0
- dnakit/fingerprints/advanced.py +829 -0
- dnakit/fingerprints/bit.py +229 -0
- dnakit/fingerprints/encoding.py +351 -0
- dnakit/fingerprints/kmer.py +170 -0
- dnakit/fingerprints/results.py +531 -0
- dnakit/fingerprints/sketch.py +246 -0
- dnakit/io/__init__.py +112 -0
- dnakit/io/_advanced_common.py +105 -0
- dnakit/io/_formats.py +994 -0
- dnakit/io/annotations.py +1179 -0
- dnakit/io/api.py +759 -0
- dnakit/io/config.py +315 -0
- dnakit/io/genbank.py +523 -0
- dnakit/io/indexed.py +1146 -0
- dnakit/io/metadata.py +452 -0
- dnakit/io/parquet.py +56 -0
- dnakit/io/results.py +131 -0
- dnakit/io/source.py +138 -0
- dnakit/io/tables.py +1237 -0
- dnakit/molbio/__init__.py +101 -0
- dnakit/molbio/_shared.py +266 -0
- dnakit/molbio/assembly.py +279 -0
- dnakit/molbio/crispr.py +181 -0
- dnakit/molbio/optimization.py +897 -0
- dnakit/molbio/primer3_design.py +667 -0
- dnakit/molbio/primers.py +899 -0
- dnakit/molbio/restriction.py +573 -0
- dnakit/molbio/results.py +583 -0
- dnakit/ops/__init__.py +588 -0
- dnakit/ops/_common.py +201 -0
- dnakit/ops/circular.py +193 -0
- dnakit/ops/concat.py +204 -0
- dnakit/ops/direction.py +27 -0
- dnakit/ops/edit.py +443 -0
- dnakit/ops/evolution.py +991 -0
- dnakit/ops/mutation.py +151 -0
- dnakit/ops/records.py +1012 -0
- dnakit/ops/translation.py +257 -0
- dnakit/patterns/__init__.py +81 -0
- dnakit/patterns/_shared.py +282 -0
- dnakit/patterns/coding.py +360 -0
- dnakit/patterns/crispr.py +337 -0
- dnakit/patterns/motif.py +721 -0
- dnakit/patterns/regions.py +341 -0
- dnakit/patterns/repeats.py +480 -0
- dnakit/patterns/restriction.py +281 -0
- dnakit/patterns/results.py +411 -0
- dnakit/py.typed +1 -0
- dnakit/references/__init__.py +27 -0
- dnakit/references/models.py +155 -0
- dnakit/references/ncbi.py +785 -0
- dnakit/representations/__init__.py +29 -0
- dnakit/representations/backends.py +928 -0
- dnakit/representations/checkpoints.py +356 -0
- dnakit/representations/extraction.py +220 -0
- dnakit/representations/models.py +395 -0
- dnakit/representations/results.py +79 -0
- dnakit/search/__init__.py +132 -0
- dnakit/search/_http.py +271 -0
- dnakit/search/_shared.py +108 -0
- dnakit/search/blast.py +516 -0
- dnakit/search/ena.py +245 -0
- dnakit/search/encode.py +102 -0
- dnakit/search/ensembl.py +874 -0
- dnakit/search/models.py +159 -0
- dnakit/search/ncbi.py +756 -0
- dnakit/search/ucsc.py +388 -0
- dnakit/secondary_structure/__init__.py +38 -0
- dnakit/secondary_structure/dotbracket.py +410 -0
- dnakit/secondary_structure/nupack.py +589 -0
- dnakit/secondary_structure/results.py +142 -0
- dnakit/similarity/__init__.py +125 -0
- dnakit/similarity/_shared.py +152 -0
- dnakit/similarity/approximate.py +258 -0
- dnakit/similarity/compare.py +162 -0
- dnakit/similarity/dashing.py +936 -0
- dnakit/similarity/distance.py +279 -0
- dnakit/similarity/index.py +365 -0
- dnakit/similarity/matrix.py +254 -0
- dnakit/similarity/results.py +676 -0
- dnakit/similarity/search.py +286 -0
- dnakit/similarity/sketch.py +96 -0
- dnakit/similarity/vector.py +662 -0
- dnakit/standardize/__init__.py +77 -0
- dnakit/standardize/_shared.py +100 -0
- dnakit/standardize/config.py +411 -0
- dnakit/standardize/gaps.py +1060 -0
- dnakit/standardize/normalize.py +565 -0
- dnakit/standardize/results.py +247 -0
- dnakit/standardize/validate.py +487 -0
- dnakit/structure3d/__init__.py +47 -0
- dnakit/structure3d/_shared.py +47 -0
- dnakit/structure3d/geometry.py +773 -0
- dnakit/structure3d/pdb.py +253 -0
- dnakit/structure3d/results.py +233 -0
- dnakit/structure3d/threedna.py +174 -0
- dnakit/thermodynamics/__init__.py +112 -0
- dnakit/thermodynamics/_shared.py +92 -0
- dnakit/thermodynamics/backends.py +653 -0
- dnakit/thermodynamics/calculations.py +837 -0
- dnakit/thermodynamics/config.py +175 -0
- dnakit/thermodynamics/equilibrium.py +340 -0
- dnakit/thermodynamics/optics.py +385 -0
- dnakit/thermodynamics/parameters.py +79 -0
- dnakit/thermodynamics/results.py +445 -0
- dnakit/visualization/__init__.py +43 -0
- dnakit/visualization/_svg.py +185 -0
- dnakit/visualization/advanced.py +314 -0
- dnakit/visualization/config.py +255 -0
- dnakit/visualization/export.py +349 -0
- dnakit/visualization/matrix.py +279 -0
- dnakit/visualization/report.py +431 -0
- dnakit/visualization/results.py +236 -0
- dnakit/visualization/sequence.py +459 -0
- dnakit/workflows/__init__.py +45 -0
- dnakit/workflows/manifest.py +365 -0
- dnakit/workflows/runner.py +1548 -0
- dnakit/workflows/schema.py +898 -0
- dnakit-0.1.0.dev0.dist-info/METADATA +126 -0
- dnakit-0.1.0.dev0.dist-info/RECORD +210 -0
- dnakit-0.1.0.dev0.dist-info/WHEEL +5 -0
- dnakit-0.1.0.dev0.dist-info/entry_points.txt +2 -0
- dnakit-0.1.0.dev0.dist-info/licenses/DISCLAIMER.md +26 -0
- dnakit-0.1.0.dev0.dist-info/licenses/LICENSE +21 -0
- dnakit-0.1.0.dev0.dist-info/licenses/THIRD_PARTY_NOTICES.md +73 -0
- dnakit-0.1.0.dev0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"""Bounded dense pairwise similarity and distance matrices."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterable, Mapping
|
|
6
|
+
from itertools import islice
|
|
7
|
+
from typing import TypeAlias
|
|
8
|
+
|
|
9
|
+
from dnakit.core import DNA, DNARecord, DNASequence
|
|
10
|
+
from dnakit.core._json import FrozenDict
|
|
11
|
+
from dnakit.exceptions import ConfigurationError
|
|
12
|
+
from dnakit.fingerprints import BitFingerprintResult, FingerprintResult
|
|
13
|
+
from dnakit.similarity._shared import validate_positive_int
|
|
14
|
+
from dnakit.similarity.compare import ComparisonInput, compare
|
|
15
|
+
from dnakit.similarity.results import DistanceResult, SimilarityMatrixResult, SimilarityResult
|
|
16
|
+
from dnakit.similarity.vector import KmerMode, WeightInput, ZeroVectorPolicy
|
|
17
|
+
|
|
18
|
+
DEFAULT_MAX_MATRIX_ITEMS = 1_000
|
|
19
|
+
_SUPPORTED_METHODS = frozenset(
|
|
20
|
+
{
|
|
21
|
+
"exact",
|
|
22
|
+
"hamming",
|
|
23
|
+
"edit",
|
|
24
|
+
"kmer_jaccard",
|
|
25
|
+
"kmer_containment",
|
|
26
|
+
"kmer_cosine",
|
|
27
|
+
"tanimoto",
|
|
28
|
+
"jaccard",
|
|
29
|
+
"cosine",
|
|
30
|
+
"euclidean",
|
|
31
|
+
"manhattan",
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
_WEIGHTED_METHODS = frozenset({"tanimoto", "jaccard", "cosine", "euclidean", "manhattan"})
|
|
35
|
+
_ResolvedMatrixWeights: TypeAlias = tuple[float, ...] | dict[str, float]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _label(value: ComparisonInput, index: int) -> str:
|
|
39
|
+
if isinstance(value, DNA):
|
|
40
|
+
return value.id
|
|
41
|
+
if isinstance(value, DNARecord):
|
|
42
|
+
return value.id
|
|
43
|
+
if (
|
|
44
|
+
isinstance(value, (FingerprintResult, BitFingerprintResult))
|
|
45
|
+
and value.sequence_id is not None
|
|
46
|
+
):
|
|
47
|
+
return value.sequence_id
|
|
48
|
+
return f"item_{index}"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _matrix_kind(method: str) -> str:
|
|
52
|
+
return "distance" if method in ("hamming", "edit", "euclidean", "manhattan") else "similarity"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _merge_resolved_weights(
|
|
56
|
+
current: _ResolvedMatrixWeights | None,
|
|
57
|
+
candidate: object,
|
|
58
|
+
) -> _ResolvedMatrixWeights:
|
|
59
|
+
"""Merge one scalar result's applied weights into matrix-level audit data."""
|
|
60
|
+
|
|
61
|
+
if isinstance(candidate, Mapping):
|
|
62
|
+
if current is not None and not isinstance(current, dict):
|
|
63
|
+
raise ConfigurationError(
|
|
64
|
+
"Matrix comparisons resolved incompatible weight forms.",
|
|
65
|
+
code="INCONSISTENT_MATRIX_WEIGHTS",
|
|
66
|
+
)
|
|
67
|
+
merged = {} if current is None else dict(current)
|
|
68
|
+
for feature, value in candidate.items():
|
|
69
|
+
if (
|
|
70
|
+
not isinstance(feature, str)
|
|
71
|
+
or isinstance(value, bool)
|
|
72
|
+
or not isinstance(value, (int, float))
|
|
73
|
+
):
|
|
74
|
+
raise ConfigurationError(
|
|
75
|
+
"Matrix comparison returned invalid resolved weights.",
|
|
76
|
+
code="INVALID_RESOLVED_MATRIX_WEIGHTS",
|
|
77
|
+
)
|
|
78
|
+
number = float(value)
|
|
79
|
+
if feature in merged and merged[feature] != number:
|
|
80
|
+
raise ConfigurationError(
|
|
81
|
+
"Matrix comparisons resolved conflicting feature weights.",
|
|
82
|
+
code="INCONSISTENT_MATRIX_WEIGHTS",
|
|
83
|
+
context={"feature": feature},
|
|
84
|
+
)
|
|
85
|
+
merged[feature] = number
|
|
86
|
+
return merged
|
|
87
|
+
if isinstance(candidate, tuple) and all(
|
|
88
|
+
not isinstance(value, bool) and isinstance(value, (int, float)) for value in candidate
|
|
89
|
+
):
|
|
90
|
+
positional = tuple(float(value) for value in candidate)
|
|
91
|
+
if current is not None and current != positional:
|
|
92
|
+
raise ConfigurationError(
|
|
93
|
+
"Matrix comparisons resolved conflicting positional weights.",
|
|
94
|
+
code="INCONSISTENT_MATRIX_WEIGHTS",
|
|
95
|
+
)
|
|
96
|
+
return positional
|
|
97
|
+
raise ConfigurationError(
|
|
98
|
+
"Matrix comparison returned invalid resolved weights.",
|
|
99
|
+
code="INVALID_RESOLVED_MATRIX_WEIGHTS",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _finalize_resolved_weights(
|
|
104
|
+
weights: _ResolvedMatrixWeights | None,
|
|
105
|
+
) -> tuple[float, ...] | FrozenDict | None:
|
|
106
|
+
if isinstance(weights, dict):
|
|
107
|
+
return FrozenDict({feature: weights[feature] for feature in sorted(weights)})
|
|
108
|
+
return weights
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def similarity_matrix(
|
|
112
|
+
items: Iterable[ComparisonInput],
|
|
113
|
+
*,
|
|
114
|
+
method: str,
|
|
115
|
+
k: int | None = None,
|
|
116
|
+
mode: KmerMode = "set",
|
|
117
|
+
canonical: bool = False,
|
|
118
|
+
overlapping: bool = True,
|
|
119
|
+
reverse_complement: bool = False,
|
|
120
|
+
weights: WeightInput | None = None,
|
|
121
|
+
zero_vector_policy: ZeroVectorPolicy = "identity",
|
|
122
|
+
max_items: int = DEFAULT_MAX_MATRIX_ITEMS,
|
|
123
|
+
) -> SimilarityMatrixResult:
|
|
124
|
+
"""Materialize a bounded full pairwise matrix in input order.
|
|
125
|
+
|
|
126
|
+
The function intentionally refuses more than ``max_items`` inputs because
|
|
127
|
+
the output itself is quadratic. K-mer containment is directional and
|
|
128
|
+
therefore returns an asymmetric matrix; all other MVP methods are treated
|
|
129
|
+
as symmetric.
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
validate_positive_int(max_items, "max_items")
|
|
133
|
+
if method not in _SUPPORTED_METHODS:
|
|
134
|
+
raise ConfigurationError(
|
|
135
|
+
"Unknown pairwise matrix method.",
|
|
136
|
+
code="INVALID_COMPARISON_METHOD",
|
|
137
|
+
context={"method": method},
|
|
138
|
+
)
|
|
139
|
+
if weights is not None and method not in _WEIGHTED_METHODS:
|
|
140
|
+
raise ConfigurationError(
|
|
141
|
+
"weights are supported only for numeric fingerprint/vector matrix methods.",
|
|
142
|
+
code="UNSUPPORTED_MATRIX_WEIGHTS",
|
|
143
|
+
context={"method": method},
|
|
144
|
+
)
|
|
145
|
+
if isinstance(
|
|
146
|
+
items,
|
|
147
|
+
(str, bytes, DNASequence, DNARecord, FingerprintResult, BitFingerprintResult),
|
|
148
|
+
):
|
|
149
|
+
raise ConfigurationError(
|
|
150
|
+
"similarity_matrix items must be an iterable of comparison inputs.",
|
|
151
|
+
code="INVALID_MATRIX_ITEMS",
|
|
152
|
+
)
|
|
153
|
+
try:
|
|
154
|
+
iterator = iter(items)
|
|
155
|
+
except TypeError as exc:
|
|
156
|
+
raise ConfigurationError(
|
|
157
|
+
"similarity_matrix items must be iterable.",
|
|
158
|
+
code="INVALID_MATRIX_ITEMS",
|
|
159
|
+
) from exc
|
|
160
|
+
values = tuple(islice(iterator, max_items + 1))
|
|
161
|
+
if len(values) > max_items:
|
|
162
|
+
raise ConfigurationError(
|
|
163
|
+
"Pairwise matrix input exceeds max_items.",
|
|
164
|
+
code="SIMILARITY_MATRIX_SIZE_LIMIT",
|
|
165
|
+
context={
|
|
166
|
+
"item_count": len(values),
|
|
167
|
+
"item_count_is_lower_bound": True,
|
|
168
|
+
"max_items": max_items,
|
|
169
|
+
},
|
|
170
|
+
hint="Reduce the input or use a future Top-k/indexed search API.",
|
|
171
|
+
)
|
|
172
|
+
if any(
|
|
173
|
+
not isinstance(
|
|
174
|
+
value,
|
|
175
|
+
(
|
|
176
|
+
DNASequence,
|
|
177
|
+
DNARecord,
|
|
178
|
+
FingerprintResult,
|
|
179
|
+
BitFingerprintResult,
|
|
180
|
+
tuple,
|
|
181
|
+
list,
|
|
182
|
+
dict,
|
|
183
|
+
),
|
|
184
|
+
)
|
|
185
|
+
for value in values
|
|
186
|
+
):
|
|
187
|
+
raise ConfigurationError(
|
|
188
|
+
"Matrix contains an unsupported comparison input.",
|
|
189
|
+
code="INVALID_MATRIX_ITEM",
|
|
190
|
+
)
|
|
191
|
+
if weights is not None and not values:
|
|
192
|
+
raise ConfigurationError(
|
|
193
|
+
"A weighted matrix requires at least one item to resolve weight dimensions or keys.",
|
|
194
|
+
code="EMPTY_WEIGHTED_MATRIX",
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
symmetric = method != "kmer_containment"
|
|
198
|
+
size = len(values)
|
|
199
|
+
rows = [[0.0] * size for _ in range(size)]
|
|
200
|
+
resolved_matrix_weights: _ResolvedMatrixWeights | None = None
|
|
201
|
+
for row in range(size):
|
|
202
|
+
column_start = row if symmetric else 0
|
|
203
|
+
for column in range(column_start, size):
|
|
204
|
+
result = compare(
|
|
205
|
+
values[row],
|
|
206
|
+
values[column],
|
|
207
|
+
method=method,
|
|
208
|
+
k=k,
|
|
209
|
+
mode=mode,
|
|
210
|
+
canonical=canonical,
|
|
211
|
+
overlapping=overlapping,
|
|
212
|
+
reverse_complement=reverse_complement,
|
|
213
|
+
weights=weights,
|
|
214
|
+
zero_vector_policy=zero_vector_policy,
|
|
215
|
+
)
|
|
216
|
+
scalar = result.distance if isinstance(result, DistanceResult) else result.value
|
|
217
|
+
if weights is not None and isinstance(result, SimilarityResult):
|
|
218
|
+
candidate_weights = result.parameters.get("weights")
|
|
219
|
+
if candidate_weights is not None:
|
|
220
|
+
resolved_matrix_weights = _merge_resolved_weights(
|
|
221
|
+
resolved_matrix_weights,
|
|
222
|
+
candidate_weights,
|
|
223
|
+
)
|
|
224
|
+
rows[row][column] = scalar
|
|
225
|
+
if symmetric:
|
|
226
|
+
rows[column][row] = scalar
|
|
227
|
+
kind = _matrix_kind(method)
|
|
228
|
+
return SimilarityMatrixResult(
|
|
229
|
+
name="similarity_matrix" if kind == "similarity" else "distance_matrix",
|
|
230
|
+
method=method,
|
|
231
|
+
value_kind=kind, # type: ignore[arg-type]
|
|
232
|
+
labels=tuple(_label(value, index) for index, value in enumerate(values)),
|
|
233
|
+
values=tuple(tuple(row) for row in rows),
|
|
234
|
+
symmetric=symmetric,
|
|
235
|
+
max_items=max_items,
|
|
236
|
+
parameters=FrozenDict(
|
|
237
|
+
{
|
|
238
|
+
"k": k,
|
|
239
|
+
"mode": mode,
|
|
240
|
+
"canonical": canonical,
|
|
241
|
+
"overlapping": overlapping,
|
|
242
|
+
"reverse_complement": reverse_complement,
|
|
243
|
+
"weighted": weights is not None,
|
|
244
|
+
"weights": _finalize_resolved_weights(resolved_matrix_weights),
|
|
245
|
+
"zero_vector_policy": zero_vector_policy,
|
|
246
|
+
}
|
|
247
|
+
),
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
pairwise_matrix = similarity_matrix
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
__all__ = ["DEFAULT_MAX_MATRIX_ITEMS", "pairwise_matrix", "similarity_matrix"]
|