IsoSpecPy 2.5.0__tar.gz → 2.6.0__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.
- {isospecpy-2.5.0 → isospecpy-2.6.0}/PKG-INFO +55 -6
- {isospecpy-2.5.0 → isospecpy-2.6.0}/README.md +54 -5
- isospecpy-2.6.0/VERSION +1 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/aligned_ptr.h +59 -9
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/allocator.h +8 -1
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/composition.h +9 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/cwrapper.cpp +84 -19
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/cwrapper.h +20 -1
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/dirtyAllocator.h +2 -1
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/fasta.cpp +28 -1
- isospecpy-2.6.0/src/IsoSpec++/fasta.h +120 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/fasta_mods.cpp +62 -30
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/fasta_mods.h +7 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/fixedEnvelopes.cpp +573 -216
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/fixedEnvelopes.h +24 -8
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/isa_dispatch.cpp +90 -32
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/isa_kernel_impl.h +17 -6
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/isa_kernels.h +11 -2
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/isoMath.cpp +71 -12
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/isoMath.h +72 -4
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/isoSpec++.cpp +192 -117
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/isoSpec++.h +221 -34
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/marginalTrek++.cpp +139 -45
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/marginalTrek++.h +25 -11
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/misc.cpp +2 -7
- isospecpy-2.6.0/src/IsoSpec++/operators.h +64 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/platform.h +14 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/unimod.cpp +24 -16
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/unimod.h +4 -5
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/unity-build.cpp +0 -1
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpecPy/IsoSpecPy.py +131 -51
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpecPy/isoFFI.py +13 -1
- isospecpy-2.5.0/VERSION +0 -1
- isospecpy-2.5.0/src/IsoSpec++/fasta.h +0 -70
- isospecpy-2.5.0/src/IsoSpec++/operators.cpp +0 -38
- isospecpy-2.5.0/src/IsoSpec++/operators.h +0 -150
- {isospecpy-2.5.0 → isospecpy-2.6.0}/LICENCE +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/pyproject.toml +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/skbuild/CMakeLists.txt +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/IsaDispatch.cmake +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/allocator.cpp +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/btrd.h +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/composition.cpp +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/conf.h +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/dirtyAllocator.cpp +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/element_lookup.cpp +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/element_lookup.h +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/element_tables.cpp +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/element_tables.h +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/isa_kernels_avx.cpp +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/isa_kernels_baseline.cpp +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/isa_kernels_v3.cpp +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/isa_kernels_v4.cpp +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/iso_simd.h +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/misc.h +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/mman.cpp +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/mman.h +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/platform_incl.h +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/pod_vector.h +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/python-build.cpp +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/summator.h +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/unimod_support.h +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpec++/unimod_table_data.h +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpecPy/Advanced.py +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpecPy/Distributions.py +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpecPy/Formulas.py +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpecPy/IsoSpecPyOld.py +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpecPy/PeriodicTbl.py +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpecPy/__init__.py +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpecPy/__main__.py +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpecPy/approximations.py +0 -0
- {isospecpy-2.5.0 → isospecpy-2.6.0}/src/IsoSpecPy/confs_passthrough.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: IsoSpecPy
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.6.0
|
|
4
4
|
Summary: IsoSpecPy is a Python library for computing isotopic distributions of molecules.
|
|
5
5
|
Keywords: isotopic distribution,mass spectrometry,chemistry,isotopic envelope,isotopologues
|
|
6
6
|
Author: Michał Startek, Mateusz Łącki
|
|
@@ -32,7 +32,7 @@ Description-Content-Type: text/markdown
|
|
|
32
32
|
|
|
33
33
|
IsoSpec is a fine-structure isotopic distribution calculator for chemical formulas — given a molecule, it computes the masses and probabilities of its isotopologues. It is fast enough to handle large molecules (proteins, oligonucleotides) where the full distribution has astronomically many configurations, and it returns provably-optimal subsets that cover a chosen fraction of the total probability mass.
|
|
34
34
|
|
|
35
|
-
IsoSpec is primarily used as a library by mass spectrometry software. It is implemented in C++ (`src/IsoSpec++/`) and shipped with first-class bindings for Python (`IsoSpecPy`, on PyPI)
|
|
35
|
+
IsoSpec is primarily used as a library by mass spectrometry software. It is implemented in C++ (`src/IsoSpec++/`) and shipped with first-class bindings for Python (`IsoSpecPy`, on PyPI), R (`IsoSpecR`, on CRAN) and Rust (`isospec`, the crate in `rust/`).
|
|
36
36
|
|
|
37
37
|
## Installation
|
|
38
38
|
|
|
@@ -54,6 +54,15 @@ install.packages("IsoSpecR")
|
|
|
54
54
|
|
|
55
55
|
From source: `cd src && R CMD build IsoSpecR && R CMD INSTALL IsoSpecR_*.tar.gz`.
|
|
56
56
|
|
|
57
|
+
### Rust
|
|
58
|
+
|
|
59
|
+
```toml
|
|
60
|
+
[dependencies]
|
|
61
|
+
isospec = "0.1"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The build script compiles the bundled C++ library; a C++20 compiler is all that is needed. See `rust/README.md`.
|
|
65
|
+
|
|
57
66
|
### C++ library
|
|
58
67
|
|
|
59
68
|
```bash
|
|
@@ -160,6 +169,27 @@ clang++ -std=c++20 water.cpp src/IsoSpec++/unity-build.cpp -o water
|
|
|
160
169
|
|
|
161
170
|
(`unity-build.cpp` is a single translation unit that `#include`s every source file — see `Examples/C++/COMPILING`.)
|
|
162
171
|
|
|
172
|
+
### Rust
|
|
173
|
+
|
|
174
|
+
```rust
|
|
175
|
+
use isospec::{Iso, PeptideOptions};
|
|
176
|
+
|
|
177
|
+
fn main() -> Result<(), isospec::Error> {
|
|
178
|
+
let iso = Iso::from_formula("H2O1")?;
|
|
179
|
+
for (mass, prob) in iso.envelope().total_prob(0.999)?.iter() {
|
|
180
|
+
println!("{mass}\t{prob}");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// A modified peptide; unlike Python's peptide_sequence=, the default
|
|
184
|
+
// here includes the terminal water.
|
|
185
|
+
let peptide = Iso::from_peptide("PEPTC[UNIMOD:4]DEK", &PeptideOptions::default())?;
|
|
186
|
+
println!("{}", peptide.monoisotopic_mass());
|
|
187
|
+
Ok(())
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
See `rust/examples/` for binned spectra, generators with configurations, and labelled elements.
|
|
192
|
+
|
|
163
193
|
### R
|
|
164
194
|
|
|
165
195
|
```r
|
|
@@ -179,7 +209,19 @@ IsoSpecify(molecule = composition, stopCondition = 0.999)
|
|
|
179
209
|
|
|
180
210
|
Like the Python `ParsePeptideSequence`, this returns the residue composition without a free peptide's terminal H2O -- add `c(H = 2, O = 1)` to it for the neutral molecule. A modification whose delta removes more atoms of an element than the bare sequence provides gives a negative count (`"G[UNIMOD:11]"` nets `H -1`, `S -1`); `IsoSpecify` rejects such a vector rather than quietly dropping those elements.
|
|
181
211
|
|
|
182
|
-
|
|
212
|
+
The rest of the API takes the same named vector, and treats an envelope as what `IsoSpecify` returns, a matrix with columns `mass` and `prob`:
|
|
213
|
+
|
|
214
|
+
```r
|
|
215
|
+
insulin <- c(C = 254, H = 377, N = 65, O = 75, S = 6)
|
|
216
|
+
IsoProperties(insulin)$averageMass # also mono/lightest/heaviest/mode peaks, variance
|
|
217
|
+
IsoBinned(insulin, binWidth = 1) # unit-resolution distribution, computed directly
|
|
218
|
+
IsoStochastic(insulin, ionicCurrent = 1e4, seed = 1) # simulated, reproducible measurement
|
|
219
|
+
wassersteinDistance(IsoSpecify(insulin, 0.999), IsoSpecify(c(C = 254, H = 377, N = 65, O = 74, S = 7), 0.999))
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
with `envelopeConvolve`, `envelopeLinearCombination`, `envelopeBin` and `envelopeResample` for envelope arithmetic, and `orientedWassersteinDistance`, `abyssalWassersteinDistance` and `wassersteinMatch` beside `wassersteinDistance`.
|
|
223
|
+
|
|
224
|
+
See `Examples/R/` for radiolabelling, full-spectrum extraction, Unimod-annotated sequences, and binned, simulated and compared envelopes.
|
|
183
225
|
|
|
184
226
|
## Advanced features
|
|
185
227
|
|
|
@@ -189,9 +231,11 @@ See `Examples/R/` for radiolabelling, full-spectrum extraction, and Unimod-annot
|
|
|
189
231
|
- `IsoBinned` — histogram-style envelope at a chosen bin width.
|
|
190
232
|
- **FASTA/peptide-sequence support** — build an `Iso` directly from an amino-acid sequence, with `[UNIMOD:<id>]` modification tags recognized inline; optionally include the N/C-terminal water.
|
|
191
233
|
- **Custom isotopic tables** — override natural abundances per element (e.g. for radio- or stable-isotope labelling). See `Examples/*/radiolabelling.*`.
|
|
192
|
-
- **Fixed-envelope arithmetic** — addition, normalization, convolution, Wasserstein
|
|
234
|
+
- **Fixed-envelope arithmetic** — addition, normalization, convolution, binning, resampling, Wasserstein distances.
|
|
235
|
+
- **Reproducible sampling** — stochastic envelopes and resampling take a seed (`seed=` in Python and R, `seeded_rng()` in C++, `with_seed` in Rust); a seed gives the same counts on every platform and in every binding.
|
|
193
236
|
- **Nominal-mass mode** — compute distributions over nucleon counts instead of real masses.
|
|
194
|
-
- **
|
|
237
|
+
- **Thread safety** — the library never parallelises its own work, but independent molecules and envelopes may be used from any number of threads, and a shared molecule or envelope may be read from several at once.
|
|
238
|
+
- **Streaming generators (for performance)** — the tabulated functions above materialize the full envelope into arrays. For large molecules where that uses too much memory, or for pipelines that consume one configuration at a time (e.g. binning on the fly), use the generator classes instead: `IsoThresholdGenerator`, `IsoLayeredGenerator`, `IsoOrderedGenerator`, `IsoStochasticGenerator`. They yield one isotopologue per call to `advanceToNextConfiguration()` without ever storing the full set. `IsoOrderedGenerator` additionally streams in strict order of decreasing probability. Generators are in C++, Python and Rust; R has the materialized functions only.
|
|
195
239
|
|
|
196
240
|
Algorithmic details are in the papers cited below; the Supporting Information of each is the better starting point for implementation specifics.
|
|
197
241
|
|
|
@@ -201,11 +245,16 @@ Algorithmic details are in the papers cited below; the Supporting Information of
|
|
|
201
245
|
src/IsoSpec++/ C++ core library (the algorithms live here)
|
|
202
246
|
src/IsoSpecPy/ Python binding, loaded via cffi
|
|
203
247
|
src/IsoSpecR/ R binding, via Rcpp
|
|
248
|
+
rust/ Rust crate (Cargo.toml at the repository root), via cxx
|
|
204
249
|
Examples/ Working examples in each language
|
|
205
|
-
tests/ C, C++, and Python test suites
|
|
250
|
+
tests/ C, C++, and Python test suites (R's are in src/IsoSpecR/tests, Rust's in rust/tests)
|
|
206
251
|
skbuild/ scikit-build-core entry point used when installing the Python wheel
|
|
207
252
|
```
|
|
208
253
|
|
|
254
|
+
## Changes
|
|
255
|
+
|
|
256
|
+
`CHANGELOG` lists the major changes in each release (the Rust crate keeps its own, `rust/CHANGELOG.md`).
|
|
257
|
+
|
|
209
258
|
## Citation
|
|
210
259
|
|
|
211
260
|
If IsoSpec is useful in your research, please cite:
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
IsoSpec is a fine-structure isotopic distribution calculator for chemical formulas — given a molecule, it computes the masses and probabilities of its isotopologues. It is fast enough to handle large molecules (proteins, oligonucleotides) where the full distribution has astronomically many configurations, and it returns provably-optimal subsets that cover a chosen fraction of the total probability mass.
|
|
4
4
|
|
|
5
|
-
IsoSpec is primarily used as a library by mass spectrometry software. It is implemented in C++ (`src/IsoSpec++/`) and shipped with first-class bindings for Python (`IsoSpecPy`, on PyPI)
|
|
5
|
+
IsoSpec is primarily used as a library by mass spectrometry software. It is implemented in C++ (`src/IsoSpec++/`) and shipped with first-class bindings for Python (`IsoSpecPy`, on PyPI), R (`IsoSpecR`, on CRAN) and Rust (`isospec`, the crate in `rust/`).
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -24,6 +24,15 @@ install.packages("IsoSpecR")
|
|
|
24
24
|
|
|
25
25
|
From source: `cd src && R CMD build IsoSpecR && R CMD INSTALL IsoSpecR_*.tar.gz`.
|
|
26
26
|
|
|
27
|
+
### Rust
|
|
28
|
+
|
|
29
|
+
```toml
|
|
30
|
+
[dependencies]
|
|
31
|
+
isospec = "0.1"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The build script compiles the bundled C++ library; a C++20 compiler is all that is needed. See `rust/README.md`.
|
|
35
|
+
|
|
27
36
|
### C++ library
|
|
28
37
|
|
|
29
38
|
```bash
|
|
@@ -130,6 +139,27 @@ clang++ -std=c++20 water.cpp src/IsoSpec++/unity-build.cpp -o water
|
|
|
130
139
|
|
|
131
140
|
(`unity-build.cpp` is a single translation unit that `#include`s every source file — see `Examples/C++/COMPILING`.)
|
|
132
141
|
|
|
142
|
+
### Rust
|
|
143
|
+
|
|
144
|
+
```rust
|
|
145
|
+
use isospec::{Iso, PeptideOptions};
|
|
146
|
+
|
|
147
|
+
fn main() -> Result<(), isospec::Error> {
|
|
148
|
+
let iso = Iso::from_formula("H2O1")?;
|
|
149
|
+
for (mass, prob) in iso.envelope().total_prob(0.999)?.iter() {
|
|
150
|
+
println!("{mass}\t{prob}");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// A modified peptide; unlike Python's peptide_sequence=, the default
|
|
154
|
+
// here includes the terminal water.
|
|
155
|
+
let peptide = Iso::from_peptide("PEPTC[UNIMOD:4]DEK", &PeptideOptions::default())?;
|
|
156
|
+
println!("{}", peptide.monoisotopic_mass());
|
|
157
|
+
Ok(())
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
See `rust/examples/` for binned spectra, generators with configurations, and labelled elements.
|
|
162
|
+
|
|
133
163
|
### R
|
|
134
164
|
|
|
135
165
|
```r
|
|
@@ -149,7 +179,19 @@ IsoSpecify(molecule = composition, stopCondition = 0.999)
|
|
|
149
179
|
|
|
150
180
|
Like the Python `ParsePeptideSequence`, this returns the residue composition without a free peptide's terminal H2O -- add `c(H = 2, O = 1)` to it for the neutral molecule. A modification whose delta removes more atoms of an element than the bare sequence provides gives a negative count (`"G[UNIMOD:11]"` nets `H -1`, `S -1`); `IsoSpecify` rejects such a vector rather than quietly dropping those elements.
|
|
151
181
|
|
|
152
|
-
|
|
182
|
+
The rest of the API takes the same named vector, and treats an envelope as what `IsoSpecify` returns, a matrix with columns `mass` and `prob`:
|
|
183
|
+
|
|
184
|
+
```r
|
|
185
|
+
insulin <- c(C = 254, H = 377, N = 65, O = 75, S = 6)
|
|
186
|
+
IsoProperties(insulin)$averageMass # also mono/lightest/heaviest/mode peaks, variance
|
|
187
|
+
IsoBinned(insulin, binWidth = 1) # unit-resolution distribution, computed directly
|
|
188
|
+
IsoStochastic(insulin, ionicCurrent = 1e4, seed = 1) # simulated, reproducible measurement
|
|
189
|
+
wassersteinDistance(IsoSpecify(insulin, 0.999), IsoSpecify(c(C = 254, H = 377, N = 65, O = 74, S = 7), 0.999))
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
with `envelopeConvolve`, `envelopeLinearCombination`, `envelopeBin` and `envelopeResample` for envelope arithmetic, and `orientedWassersteinDistance`, `abyssalWassersteinDistance` and `wassersteinMatch` beside `wassersteinDistance`.
|
|
193
|
+
|
|
194
|
+
See `Examples/R/` for radiolabelling, full-spectrum extraction, Unimod-annotated sequences, and binned, simulated and compared envelopes.
|
|
153
195
|
|
|
154
196
|
## Advanced features
|
|
155
197
|
|
|
@@ -159,9 +201,11 @@ See `Examples/R/` for radiolabelling, full-spectrum extraction, and Unimod-annot
|
|
|
159
201
|
- `IsoBinned` — histogram-style envelope at a chosen bin width.
|
|
160
202
|
- **FASTA/peptide-sequence support** — build an `Iso` directly from an amino-acid sequence, with `[UNIMOD:<id>]` modification tags recognized inline; optionally include the N/C-terminal water.
|
|
161
203
|
- **Custom isotopic tables** — override natural abundances per element (e.g. for radio- or stable-isotope labelling). See `Examples/*/radiolabelling.*`.
|
|
162
|
-
- **Fixed-envelope arithmetic** — addition, normalization, convolution, Wasserstein
|
|
204
|
+
- **Fixed-envelope arithmetic** — addition, normalization, convolution, binning, resampling, Wasserstein distances.
|
|
205
|
+
- **Reproducible sampling** — stochastic envelopes and resampling take a seed (`seed=` in Python and R, `seeded_rng()` in C++, `with_seed` in Rust); a seed gives the same counts on every platform and in every binding.
|
|
163
206
|
- **Nominal-mass mode** — compute distributions over nucleon counts instead of real masses.
|
|
164
|
-
- **
|
|
207
|
+
- **Thread safety** — the library never parallelises its own work, but independent molecules and envelopes may be used from any number of threads, and a shared molecule or envelope may be read from several at once.
|
|
208
|
+
- **Streaming generators (for performance)** — the tabulated functions above materialize the full envelope into arrays. For large molecules where that uses too much memory, or for pipelines that consume one configuration at a time (e.g. binning on the fly), use the generator classes instead: `IsoThresholdGenerator`, `IsoLayeredGenerator`, `IsoOrderedGenerator`, `IsoStochasticGenerator`. They yield one isotopologue per call to `advanceToNextConfiguration()` without ever storing the full set. `IsoOrderedGenerator` additionally streams in strict order of decreasing probability. Generators are in C++, Python and Rust; R has the materialized functions only.
|
|
165
209
|
|
|
166
210
|
Algorithmic details are in the papers cited below; the Supporting Information of each is the better starting point for implementation specifics.
|
|
167
211
|
|
|
@@ -171,11 +215,16 @@ Algorithmic details are in the papers cited below; the Supporting Information of
|
|
|
171
215
|
src/IsoSpec++/ C++ core library (the algorithms live here)
|
|
172
216
|
src/IsoSpecPy/ Python binding, loaded via cffi
|
|
173
217
|
src/IsoSpecR/ R binding, via Rcpp
|
|
218
|
+
rust/ Rust crate (Cargo.toml at the repository root), via cxx
|
|
174
219
|
Examples/ Working examples in each language
|
|
175
|
-
tests/ C, C++, and Python test suites
|
|
220
|
+
tests/ C, C++, and Python test suites (R's are in src/IsoSpecR/tests, Rust's in rust/tests)
|
|
176
221
|
skbuild/ scikit-build-core entry point used when installing the Python wheel
|
|
177
222
|
```
|
|
178
223
|
|
|
224
|
+
## Changes
|
|
225
|
+
|
|
226
|
+
`CHANGELOG` lists the major changes in each release (the Rust crate keeps its own, `rust/CHANGELOG.md`).
|
|
227
|
+
|
|
179
228
|
## Citation
|
|
180
229
|
|
|
181
230
|
If IsoSpec is useful in your research, please cite:
|
isospecpy-2.6.0/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.6.0
|
|
@@ -36,7 +36,9 @@
|
|
|
36
36
|
// elsewhere for plain huge-page mmap): that layer has no remap concept at
|
|
37
37
|
// all on Windows and no equivalent of mremap on Darwin, so each platform's
|
|
38
38
|
// real growth primitive is used directly instead:
|
|
39
|
-
// - Linux
|
|
39
|
+
// - Linux (any libc with mremap): mmap + mremap(MREMAP_MAYMOVE) + munmap.
|
|
40
|
+
// - Other UNIX (FreeBSD, ...: no mremap): growth maps a fresh region and
|
|
41
|
+
// copies, shrink unmaps the tail in place.
|
|
40
42
|
// - Apple: mmap/munmap for create/destroy (Darwin has no mremap); growth
|
|
41
43
|
// re-wires pages into a fresh mapping via mach_vm_remap instead of
|
|
42
44
|
// copying, shrink just munmaps the tail in place.
|
|
@@ -57,25 +59,41 @@
|
|
|
57
59
|
|
|
58
60
|
// The small-allocation backend needs an aligned allocator that can also be
|
|
59
61
|
// deallocated with a plain std::free() (release() promises exactly that).
|
|
60
|
-
// glibc/libc++'s std::aligned_alloc satisfies both at once.
|
|
62
|
+
// glibc/libc++'s std::aligned_alloc satisfies both at once. Windows' CRT
|
|
63
|
+
// (MSVC's, and the msvcrt/UCRT that MinGW, i.e. R's Rtools, links against) has
|
|
61
64
|
// no C11 aligned_alloc at all, only _aligned_malloc/_aligned_free -- and
|
|
62
65
|
// memory from those two is NOT free()-compatible (the CRT stores its own
|
|
63
66
|
// offset bookkeeping ahead of the returned pointer, which plain free() does
|
|
64
|
-
// not know how to unwind). So on
|
|
67
|
+
// not know how to unwind). So on Windows the small backend uses
|
|
65
68
|
// _aligned_malloc/_aligned_free for its own storage (still genuinely
|
|
66
69
|
// Alignment-aligned, as marginalTrek++.h's use of this class relies on),
|
|
67
70
|
// and release() falls back to materialising a fresh plain-malloc()'d copy
|
|
68
71
|
// to keep its free()-compatibility promise -- the same thing it already
|
|
69
72
|
// does to escape a VM-backed region.
|
|
70
|
-
#if defined(
|
|
73
|
+
#if defined(_WIN32)
|
|
71
74
|
#define ISOSPEC_ALIGNED_PTR_SMALL_BACKEND_FREE_COMPATIBLE 0
|
|
72
75
|
#else
|
|
73
76
|
#define ISOSPEC_ALIGNED_PTR_SMALL_BACKEND_FREE_COMPATIBLE 1
|
|
74
77
|
#endif
|
|
75
78
|
|
|
76
79
|
#if ISOSPEC_WE_ARE_ON_WINDOWS
|
|
80
|
+
// Without NOMINMAX, <windows.h> defines min and max as macros, which break
|
|
81
|
+
// every later std::min(...) and numeric_limits<T>::max() in the including
|
|
82
|
+
// translation unit. Defined only around this include, so that the macro
|
|
83
|
+
// itself does not leak into the caller's code (though a later <windows.h>
|
|
84
|
+
// there is then a no-op, without the macros); a caller who included
|
|
85
|
+
// <windows.h> first, macros and all, is covered by the parenthesised
|
|
86
|
+
// (std::min)(...) calls in the public headers.
|
|
87
|
+
#ifndef NOMINMAX
|
|
88
|
+
#define NOMINMAX
|
|
89
|
+
#define ISOSPEC_UNDEF_NOMINMAX
|
|
90
|
+
#endif
|
|
77
91
|
#include <windows.h>
|
|
78
|
-
#
|
|
92
|
+
#ifdef ISOSPEC_UNDEF_NOMINMAX
|
|
93
|
+
#undef NOMINMAX
|
|
94
|
+
#undef ISOSPEC_UNDEF_NOMINMAX
|
|
95
|
+
#endif
|
|
96
|
+
#if defined(_WIN32)
|
|
79
97
|
#include <malloc.h> // _aligned_malloc / _aligned_free
|
|
80
98
|
#endif
|
|
81
99
|
#elif ISOSPEC_WE_ARE_ON_UNIX_YAY
|
|
@@ -303,7 +321,26 @@ inline void vm_resize(vm_region& r, std::size_t new_bytes)
|
|
|
303
321
|
r.size = new_size;
|
|
304
322
|
}
|
|
305
323
|
|
|
306
|
-
#else //
|
|
324
|
+
#else // Other UNIX: Linux with mremap(), the rest (FreeBSD, ...) without
|
|
325
|
+
|
|
326
|
+
// ThreadSanitizer intercepts mmap() and munmap() but not mremap(), so a region
|
|
327
|
+
// that mremap() moves away from is freed behind its back and keeps its old
|
|
328
|
+
// shadow state. When another thread's mremap() later lands on those
|
|
329
|
+
// addresses, TSan reports its writes as racing with the previous owner's --
|
|
330
|
+
// pure address reuse, reproduced with two threads and nothing else. Under
|
|
331
|
+
// TSan, growth therefore goes through mmap + copy + munmap, which it does see.
|
|
332
|
+
#if defined(__SANITIZE_THREAD__)
|
|
333
|
+
#define ISOSPEC_ALIGNED_PTR_UNDER_TSAN 1
|
|
334
|
+
#elif defined(__has_feature)
|
|
335
|
+
#if __has_feature(thread_sanitizer)
|
|
336
|
+
#define ISOSPEC_ALIGNED_PTR_UNDER_TSAN 1
|
|
337
|
+
#endif
|
|
338
|
+
#endif
|
|
339
|
+
|
|
340
|
+
// mremap() is Linux's alone; MREMAP_MAYMOVE, from <sys/mman.h>, is the test.
|
|
341
|
+
#if defined(MREMAP_MAYMOVE) && !defined(ISOSPEC_ALIGNED_PTR_UNDER_TSAN)
|
|
342
|
+
#define ISOSPEC_ALIGNED_PTR_USE_MREMAP 1
|
|
343
|
+
#endif
|
|
307
344
|
|
|
308
345
|
inline void vm_resize(vm_region& r, std::size_t new_bytes)
|
|
309
346
|
{
|
|
@@ -311,11 +348,24 @@ inline void vm_resize(vm_region& r, std::size_t new_bytes)
|
|
|
311
348
|
if (new_size == r.size)
|
|
312
349
|
return;
|
|
313
350
|
|
|
351
|
+
#if !defined(ISOSPEC_ALIGNED_PTR_USE_MREMAP)
|
|
352
|
+
if (new_size < r.size) {
|
|
353
|
+
// Shrink in place: base address is untouched, just drop the tail.
|
|
354
|
+
::munmap(static_cast<char*>(r.base) + new_size, r.size - new_size);
|
|
355
|
+
r.size = new_size;
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
vm_region moved = vm_create(new_bytes);
|
|
359
|
+
std::memcpy(moved.base, r.base, (std::min)(r.size, moved.size));
|
|
360
|
+
vm_destroy(r);
|
|
361
|
+
r = moved;
|
|
362
|
+
#else
|
|
314
363
|
void* p = ::mremap(r.base, r.size, new_size, MREMAP_MAYMOVE);
|
|
315
364
|
if (p == MAP_FAILED)
|
|
316
365
|
throw std::bad_alloc();
|
|
317
366
|
r.base = p;
|
|
318
367
|
r.size = new_size;
|
|
368
|
+
#endif
|
|
319
369
|
}
|
|
320
370
|
|
|
321
371
|
#endif // __APPLE__
|
|
@@ -549,7 +599,7 @@ class aligned_unique_ptr {
|
|
|
549
599
|
// still has to copy -- there is nothing yet to remap.
|
|
550
600
|
aligned_ptr_detail::vm_region r = aligned_ptr_detail::vm_create(new_bytes);
|
|
551
601
|
if (ptr_) {
|
|
552
|
-
std::memcpy(r.base, ptr_, std::min(capacity_bytes_, new_bytes));
|
|
602
|
+
std::memcpy(r.base, ptr_, (std::min)(capacity_bytes_, new_bytes));
|
|
553
603
|
free_small(ptr_);
|
|
554
604
|
}
|
|
555
605
|
region_ = r;
|
|
@@ -562,7 +612,7 @@ class aligned_unique_ptr {
|
|
|
562
612
|
|
|
563
613
|
T* new_ptr = allocate_small(n);
|
|
564
614
|
if (ptr_) {
|
|
565
|
-
std::memcpy(new_ptr, ptr_, std::min(capacity_bytes_, new_bytes));
|
|
615
|
+
std::memcpy(new_ptr, ptr_, (std::min)(capacity_bytes_, new_bytes));
|
|
566
616
|
free_small(ptr_);
|
|
567
617
|
}
|
|
568
618
|
ptr_ = new_ptr;
|
|
@@ -573,7 +623,7 @@ class aligned_unique_ptr {
|
|
|
573
623
|
// bare std::free() / C free(), regardless of which backend produced it.
|
|
574
624
|
// Whenever the current backend isn't already free()-compatible on its
|
|
575
625
|
// own -- a VM-backed region always needs this, and so does the small
|
|
576
|
-
// backend on
|
|
626
|
+
// backend on Windows (see ISOSPEC_ALIGNED_PTR_SMALL_BACKEND_FREE_COMPATIBLE
|
|
577
627
|
// above) -- this materialises a fresh plain-malloc()'d copy instead.
|
|
578
628
|
// That copy is the whole cost of calling this in those cases;
|
|
579
629
|
// release_with_deleter() below avoids it when the caller can accept a
|
|
@@ -23,6 +23,13 @@
|
|
|
23
23
|
namespace IsoSpec
|
|
24
24
|
{
|
|
25
25
|
|
|
26
|
+
// Configurations per allocator slab. Small on purpose: with glibc, a slab of
|
|
27
|
+
// up to 1032 bytes (4 isotopes x 64 ints = 1024) is recycled through the
|
|
28
|
+
// per-thread tcache when the next molecule is built, so many small molecules
|
|
29
|
+
// in a row run 16-20% faster than with 1000 (2000 tryptic peptides, threshold
|
|
30
|
+
// generator, x86-64-v3 and v4). Single large calculations do not notice.
|
|
31
|
+
constexpr int default_tab_size = 64;
|
|
32
|
+
|
|
26
33
|
template <typename T> inline void copyConf(
|
|
27
34
|
const T* source, T* destination,
|
|
28
35
|
int dim
|
|
@@ -39,7 +46,7 @@ template <typename T> class Allocator
|
|
|
39
46
|
pod_vector<T*> prevTabs;
|
|
40
47
|
|
|
41
48
|
public:
|
|
42
|
-
explicit Allocator(const int dim, const int tabSize =
|
|
49
|
+
explicit Allocator(const int dim, const int tabSize = default_tab_size);
|
|
43
50
|
~Allocator();
|
|
44
51
|
|
|
45
52
|
Allocator(const Allocator& other) = delete;
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
#pragma once
|
|
29
29
|
|
|
30
|
+
#include <string_view>
|
|
30
31
|
#include <vector>
|
|
31
32
|
|
|
32
33
|
#include "isoSpec++.h"
|
|
@@ -87,6 +88,14 @@ struct ExpandedComposition {
|
|
|
87
88
|
}
|
|
88
89
|
};
|
|
89
90
|
|
|
91
|
+
//! A formula string read as a composition: each element once, in the order
|
|
92
|
+
//! written, counts signed ("H-2O-1" is accepted -- a composition may be a
|
|
93
|
+
//! delta; build_iso_from_composition rejects negatives when one becomes a
|
|
94
|
+
//! molecule). Throws std::invalid_argument for a malformed formula, an unknown
|
|
95
|
+
//! element or one written twice, std::out_of_range for a count past int. The
|
|
96
|
+
//! same tokenizer and checks as parse_formula, which goes through it.
|
|
97
|
+
ElementComposition parse_formula_composition(std::string_view formula);
|
|
98
|
+
|
|
90
99
|
//! Resolves each element of `composition` to its isotopes' masses and
|
|
91
100
|
//! probabilities from element_tables.h, filling a caller-owned `out`
|
|
92
101
|
//! (cleared first).
|
|
@@ -300,6 +300,43 @@ void* setupIsoStochasticGenerator(void* iso,
|
|
|
300
300
|
beta_bias);
|
|
301
301
|
});
|
|
302
302
|
}
|
|
303
|
+
|
|
304
|
+
namespace
|
|
305
|
+
{
|
|
306
|
+
// The random state a seeded generator draws from has to live as long as the
|
|
307
|
+
// generator and be built before it: a base class listed first is both.
|
|
308
|
+
struct OwnedRng
|
|
309
|
+
{
|
|
310
|
+
std::mt19937 owned_rng;
|
|
311
|
+
explicit OwnedRng(uint64_t seed) : owned_rng(seeded_rng(seed)) {}
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
class SeededIsoStochasticGenerator : private OwnedRng, public IsoStochasticGenerator
|
|
315
|
+
{
|
|
316
|
+
public:
|
|
317
|
+
SeededIsoStochasticGenerator(Iso&& iso, size_t no_molecules, double precision, double beta_bias, uint64_t seed) :
|
|
318
|
+
OwnedRng(seed),
|
|
319
|
+
IsoStochasticGenerator(std::move(iso), no_molecules, precision, beta_bias, owned_rng)
|
|
320
|
+
{}
|
|
321
|
+
};
|
|
322
|
+
} // namespace
|
|
323
|
+
|
|
324
|
+
void* setupIsoStochasticGeneratorSeeded(void* iso,
|
|
325
|
+
size_t no_molecules,
|
|
326
|
+
double precision,
|
|
327
|
+
double beta_bias,
|
|
328
|
+
uint64_t seed)
|
|
329
|
+
{
|
|
330
|
+
return c_guard([&]() -> void*
|
|
331
|
+
{
|
|
332
|
+
// Handed out as the base, like the unseeded generator, so every
|
|
333
|
+
// *IsoStochasticGenerator function (delete included, through the
|
|
334
|
+
// virtual destructor) works on it unchanged.
|
|
335
|
+
IsoStochasticGenerator* generator = new SeededIsoStochasticGenerator(
|
|
336
|
+
std::move(*reinterpret_cast<Iso*>(iso)), no_molecules, precision, beta_bias, seed);
|
|
337
|
+
return generator;
|
|
338
|
+
});
|
|
339
|
+
}
|
|
303
340
|
ISOSPEC_C_FN_CODES(IsoStochasticGenerator)
|
|
304
341
|
|
|
305
342
|
// ______________________________________________________ FixedEnvelopes
|
|
@@ -351,6 +388,26 @@ void* setupStochasticFixedEnvelope(void* iso,
|
|
|
351
388
|
});
|
|
352
389
|
}
|
|
353
390
|
|
|
391
|
+
void* setupStochasticFixedEnvelopeSeeded(void* iso,
|
|
392
|
+
size_t no_molecules,
|
|
393
|
+
double precision,
|
|
394
|
+
double beta_bias,
|
|
395
|
+
bool get_confs,
|
|
396
|
+
uint64_t seed)
|
|
397
|
+
{
|
|
398
|
+
return c_guard([&]() -> void*
|
|
399
|
+
{
|
|
400
|
+
std::mt19937 rng = seeded_rng(seed);
|
|
401
|
+
return new FixedEnvelope(
|
|
402
|
+
FixedEnvelope::FromStochastic(Iso(*reinterpret_cast<const Iso*>(iso), true),
|
|
403
|
+
no_molecules,
|
|
404
|
+
precision,
|
|
405
|
+
beta_bias,
|
|
406
|
+
get_confs,
|
|
407
|
+
rng));
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
354
411
|
|
|
355
412
|
void* setupBinnedFixedEnvelope(void* iso,
|
|
356
413
|
double target_total_prob,
|
|
@@ -542,6 +599,15 @@ void resampleEnvelope(void* envelope, size_t ionic_current, double beta_bias)
|
|
|
542
599
|
return c_guard([&]{ reinterpret_cast<FixedEnvelope*>(envelope)->resample(ionic_current, beta_bias); });
|
|
543
600
|
}
|
|
544
601
|
|
|
602
|
+
void resampleEnvelopeSeeded(void* envelope, size_t ionic_current, double beta_bias, uint64_t seed)
|
|
603
|
+
{
|
|
604
|
+
return c_guard([&]
|
|
605
|
+
{
|
|
606
|
+
std::mt19937 rng = seeded_rng(seed);
|
|
607
|
+
reinterpret_cast<FixedEnvelope*>(envelope)->resample(ionic_current, beta_bias, rng);
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
|
|
545
611
|
|
|
546
612
|
void* binnedEnvelope(void* envelope, double width, double middle)
|
|
547
613
|
{
|
|
@@ -614,27 +680,26 @@ void* parseFastaWithModsC(const char* sequence, const char* unimod_db_path)
|
|
|
614
680
|
{
|
|
615
681
|
return c_guard([&]() -> void*
|
|
616
682
|
{
|
|
617
|
-
//
|
|
618
|
-
//
|
|
619
|
-
//
|
|
620
|
-
//
|
|
621
|
-
//
|
|
622
|
-
//
|
|
623
|
-
//
|
|
624
|
-
//
|
|
625
|
-
//
|
|
626
|
-
//
|
|
627
|
-
//
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
parse_fasta_with_mods_into(sequence, scratch, resolve_unimod_table(unimod_db_path));
|
|
683
|
+
// A fresh composition per call, not a reused `static` one: a static
|
|
684
|
+
// shared by every thread is a data race, and `thread_local` is no way
|
|
685
|
+
// out -- its TLS teardown has crashed a dynamically-loaded Python/R
|
|
686
|
+
// extension module at interpreter shutdown (seen in CI on macOS).
|
|
687
|
+
// Reserving up front makes each vector one allocation rather than a
|
|
688
|
+
// doubling series, and `count` is moved into the handle rather than
|
|
689
|
+
// copied, so the net cost over the static is one malloc/free pair:
|
|
690
|
+
// measured at +7 ns per call (43 -> 50 ns) on unmodified peptides and
|
|
691
|
+
// +2.5% on modified ones, x86-64-v3, gcc -- small next to any
|
|
692
|
+
// binding's own per-call overhead. 16 covers an unmodified peptide
|
|
693
|
+
// (C, H, N, O, S, Se) with room for what a few modifications add.
|
|
694
|
+
ElementComposition composition;
|
|
695
|
+
composition.element_first_index.reserve(16);
|
|
696
|
+
composition.count.reserve(16);
|
|
697
|
+
parse_fasta_with_mods_into(sequence, composition, resolve_unimod_table(unimod_db_path));
|
|
633
698
|
std::unique_ptr<ElementCompositionHandle> handle(new ElementCompositionHandle());
|
|
634
|
-
handle->
|
|
635
|
-
|
|
636
|
-
for(int idx : scratch.element_first_index)
|
|
699
|
+
handle->symbols.reserve(composition.element_first_index.size());
|
|
700
|
+
for(int idx : composition.element_first_index)
|
|
637
701
|
handle->symbols.push_back(elem_table_symbol[idx]);
|
|
702
|
+
handle->counts = std::move(composition.count);
|
|
638
703
|
return handle.release();
|
|
639
704
|
});
|
|
640
705
|
}
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
|
|
17
17
|
#pragma once
|
|
18
18
|
|
|
19
|
+
#include <stddef.h>
|
|
20
|
+
#include <stdint.h>
|
|
21
|
+
|
|
19
22
|
#include "platform.h"
|
|
20
23
|
|
|
21
24
|
#define ISOSPEC_ALGO_LAYERED 0
|
|
@@ -117,6 +120,15 @@ ISOSPEC_C_API double probIsoStochasticGenerator(void* generator);
|
|
|
117
120
|
ISOSPEC_C_API void get_conf_signatureIsoStochasticGenerator(void* generator, int* space);
|
|
118
121
|
ISOSPEC_C_API bool advanceToNextConfigurationIsoStochasticGenerator(void* generator);
|
|
119
122
|
ISOSPEC_C_API void deleteIsoStochasticGenerator(void* generator);
|
|
123
|
+
// The *Seeded variants draw from a generator seeded with `seed`, so the same
|
|
124
|
+
// seed reproduces the same sample (also across bindings). The unseeded ones draw
|
|
125
|
+
// from a randomly seeded per-thread generator. A seeded stochastic generator
|
|
126
|
+
// owns its random state and is used and deleted like an unseeded one.
|
|
127
|
+
ISOSPEC_C_API void* setupIsoStochasticGeneratorSeeded(void* iso,
|
|
128
|
+
size_t no_molecules,
|
|
129
|
+
double precision,
|
|
130
|
+
double beta_bias,
|
|
131
|
+
uint64_t seed);
|
|
120
132
|
|
|
121
133
|
ISOSPEC_C_API void* setupThresholdFixedEnvelope(void* iso,
|
|
122
134
|
double threshold,
|
|
@@ -134,6 +146,13 @@ ISOSPEC_C_API void* setupStochasticFixedEnvelope(void* iso,
|
|
|
134
146
|
double beta_bias,
|
|
135
147
|
bool get_confs);
|
|
136
148
|
|
|
149
|
+
ISOSPEC_C_API void* setupStochasticFixedEnvelopeSeeded(void* iso,
|
|
150
|
+
size_t no_molecules,
|
|
151
|
+
double precision,
|
|
152
|
+
double beta_bias,
|
|
153
|
+
bool get_confs,
|
|
154
|
+
uint64_t seed);
|
|
155
|
+
|
|
137
156
|
ISOSPEC_C_API void* setupBinnedFixedEnvelope(void* iso,
|
|
138
157
|
double target_total_prob,
|
|
139
158
|
double bin_width,
|
|
@@ -185,7 +204,6 @@ ISOSPEC_C_API double empiricStddev(void* tabulator);
|
|
|
185
204
|
ISOSPEC_C_API double wassersteinDistance(void* tabulator1, void* tabulator2);
|
|
186
205
|
ISOSPEC_C_API double orientedWassersteinDistance(void* tabulator1, void* tabulator2);
|
|
187
206
|
ISOSPEC_C_API double abyssalWassersteinDistance(void* tabulator1, void* tabulator2, double abyss_depth, double other_scale);
|
|
188
|
-
// ISOSPEC_C_API double abyssalWassersteinDistanceGrad(void* const* envelopes, const double* scales, double* ret_gradient, size_t N, double abyss_depth_exp, double abyss_depth_the);
|
|
189
207
|
|
|
190
208
|
struct ws_match_res{
|
|
191
209
|
double res1;
|
|
@@ -203,6 +221,7 @@ ISOSPEC_C_API void scaleEnvelope(void* envelope, double factor);
|
|
|
203
221
|
ISOSPEC_C_API void normalizeEnvelope(void* envelope);
|
|
204
222
|
ISOSPEC_C_API void shiftMassEnvelope(void* envelope, double d_mass);
|
|
205
223
|
ISOSPEC_C_API void resampleEnvelope(void* envelope, size_t ionic_current, double beta_bias);
|
|
224
|
+
ISOSPEC_C_API void resampleEnvelopeSeeded(void* envelope, size_t ionic_current, double beta_bias, uint64_t seed);
|
|
206
225
|
ISOSPEC_C_API void* binnedEnvelope(void* envelope, double width, double middle);
|
|
207
226
|
ISOSPEC_C_API void* linearCombination(void* const * const envelopes, const double* intensities, size_t count);
|
|
208
227
|
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
#include <cstring>
|
|
20
20
|
#include "pod_vector.h"
|
|
21
|
+
#include "allocator.h"
|
|
21
22
|
|
|
22
23
|
namespace IsoSpec
|
|
23
24
|
{
|
|
@@ -33,7 +34,7 @@ class DirtyAllocator
|
|
|
33
34
|
pod_vector<void*> prevTabs;
|
|
34
35
|
|
|
35
36
|
public:
|
|
36
|
-
explicit DirtyAllocator(const int dim, const int tabSize =
|
|
37
|
+
explicit DirtyAllocator(const int dim, const int tabSize = default_tab_size);
|
|
37
38
|
~DirtyAllocator();
|
|
38
39
|
|
|
39
40
|
DirtyAllocator(const DirtyAllocator& other) = delete;
|
|
@@ -54,7 +54,7 @@ const double aa_elem_probabilities[19] = {
|
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
constexpr int aa_symbol_to_elem_counts[256*6] = {
|
|
58
58
|
/* Code: 0 unprintable */ 0, 0, 0, 0, 0, 0,
|
|
59
59
|
/* Code: 1 unprintable */ 0, 0, 0, 0, 0, 0,
|
|
60
60
|
/* Code: 2 unprintable */ 0, 0, 0, 0, 0, 0,
|
|
@@ -312,4 +312,31 @@ const int aa_symbol_to_elem_counts[256*6] = {
|
|
|
312
312
|
/* Code: 254 unprintable */ 0, 0, 0, 0, 0, 0
|
|
313
313
|
};
|
|
314
314
|
|
|
315
|
+
namespace {
|
|
316
|
+
|
|
317
|
+
constexpr PackedElemCounts pack_elem_counts()
|
|
318
|
+
{
|
|
319
|
+
PackedElemCounts ret{};
|
|
320
|
+
for(int c = 0; c < 256; c++)
|
|
321
|
+
for(int ii = 0; ii < 6; ii++)
|
|
322
|
+
ret.row[c] |= static_cast<std::uint64_t>(aa_symbol_to_elem_counts[c*6 + ii]) << (AA_PACKED_FIELD_BITS * ii);
|
|
323
|
+
return ret;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
constexpr bool packed_counts_cannot_overflow()
|
|
327
|
+
{
|
|
328
|
+
for(int ii = 0; ii < 256*6; ii++)
|
|
329
|
+
if(aa_symbol_to_elem_counts[ii] < 0 ||
|
|
330
|
+
aa_symbol_to_elem_counts[ii] * AA_PACKED_FLUSH_EVERY >= (1 << AA_PACKED_FIELD_BITS))
|
|
331
|
+
return false;
|
|
332
|
+
return 6 * AA_PACKED_FIELD_BITS <= 64;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
static_assert(packed_counts_cannot_overflow(),
|
|
336
|
+
"AA_PACKED_FLUSH_EVERY residues of the largest count must fit an AA_PACKED_FIELD_BITS field");
|
|
337
|
+
|
|
338
|
+
} // namespace
|
|
339
|
+
|
|
340
|
+
constexpr PackedElemCounts aa_symbol_to_packed_elem_counts = pack_elem_counts();
|
|
341
|
+
|
|
315
342
|
} // namespace IsoSpec
|