IsoSpecPy 2.3.4__tar.gz → 2.3.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.
- {isospecpy-2.3.4 → isospecpy-2.3.5}/PKG-INFO +1 -1
- {isospecpy-2.3.4 → isospecpy-2.3.5}/pyproject.toml +1 -1
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/cwrapper.cpp +4 -10
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/fixedEnvelopes.cpp +86 -257
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/fixedEnvelopes.h +3 -5
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpecPy/Distributions.py +0 -1
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpecPy/IsoSpecPy.py +27 -29
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpecPy/PeriodicTbl.py +1 -1
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpecPy/approximations.py +0 -9
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpecPy/isoFFI.py +2 -2
- {isospecpy-2.3.4 → isospecpy-2.3.5}/LICENCE +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/README.md +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/skbuild/CMakeLists.txt +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/allocator.cpp +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/allocator.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/btrd.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/conf.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/cwrapper.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/dirtyAllocator.cpp +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/dirtyAllocator.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/element_tables.cpp +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/element_tables.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/fasta.cpp +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/fasta.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/isoMath.cpp +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/isoMath.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/isoSpec++.cpp +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/isoSpec++.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/marginalTrek++.cpp +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/marginalTrek++.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/misc.cpp +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/misc.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/mman.cpp +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/mman.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/operators.cpp +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/operators.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/platform.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/platform_incl.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/pod_vector.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/python-build.cpp +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/summator.h +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpec++/unity-build.cpp +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpecPy/Advanced.py +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpecPy/Formulas.py +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpecPy/IsoSpecPyOld.py +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpecPy/__init__.py +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/src/IsoSpecPy/__main__.py +0 -0
- {isospecpy-2.3.4 → isospecpy-2.3.5}/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.
|
|
3
|
+
Version: 2.3.5
|
|
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
|
|
@@ -9,7 +9,7 @@ cmake.source-dir = "skbuild"
|
|
|
9
9
|
name = "IsoSpecPy"
|
|
10
10
|
dependencies = ["cffi"]
|
|
11
11
|
description = "IsoSpecPy is a Python library for computing isotopic distributions of molecules."
|
|
12
|
-
version = "2.3.
|
|
12
|
+
version = "2.3.5"
|
|
13
13
|
license = "BSD-2-Clause"
|
|
14
14
|
license-files = ["LICENCE"]
|
|
15
15
|
authors = [{name = "Michał Startek"}, {name = "Mateusz Łącki"}]
|
|
@@ -129,8 +129,9 @@ double* getMarginalLogSizeEstimates(void* iso, double target_total_prob)
|
|
|
129
129
|
{
|
|
130
130
|
Iso* i = reinterpret_cast<Iso*>(iso);
|
|
131
131
|
double* ret = reinterpret_cast<double*>(malloc(sizeof(double)*i->getDimNumber()));
|
|
132
|
-
if(ret
|
|
133
|
-
|
|
132
|
+
if(ret == nullptr)
|
|
133
|
+
throw std::bad_alloc();
|
|
134
|
+
i->saveMarginalLogSizeEstimates(ret, target_total_prob);
|
|
134
135
|
return ret;
|
|
135
136
|
}
|
|
136
137
|
|
|
@@ -383,13 +384,6 @@ double abyssalWassersteinDistance(void* tabulator1, void* tabulator2, double aby
|
|
|
383
384
|
return reinterpret_cast<FixedEnvelope*>(tabulator1)->AbyssalWassersteinDistance(*reinterpret_cast<FixedEnvelope*>(tabulator2), abyss_depth, other_scale);
|
|
384
385
|
}
|
|
385
386
|
|
|
386
|
-
#if 0
|
|
387
|
-
double abyssalWassersteinDistanceGrad(void* const* envelopes, const double* scales, double* ret_gradient, size_t N, double abyss_depth_exp, double abyss_depth_the)
|
|
388
|
-
{
|
|
389
|
-
return AbyssalWassersteinDistanceGrad(reinterpret_cast<FixedEnvelope* const*>(envelopes), scales, ret_gradient, N, abyss_depth_exp, abyss_depth_the);
|
|
390
|
-
}
|
|
391
|
-
#endif
|
|
392
|
-
|
|
393
387
|
struct ws_match_res wassersteinMatch(void* tabulator1, void* tabulator2, double flow_dist, double other_scale)
|
|
394
388
|
{
|
|
395
389
|
struct ws_match_res res;
|
|
@@ -483,7 +477,7 @@ void array_fma(double* array, size_t N, double mul, double add)
|
|
|
483
477
|
#if defined(FP_FAST_FMA)
|
|
484
478
|
array[ii] = std::fma(array[ii], mul, add);
|
|
485
479
|
#else
|
|
486
|
-
array[ii]
|
|
480
|
+
array[ii] = (array[ii] * mul) + add;
|
|
487
481
|
#endif
|
|
488
482
|
}
|
|
489
483
|
|
|
@@ -28,9 +28,11 @@ _probs(array_copy_malloc<double>(other._probs, other._confs_no)),
|
|
|
28
28
|
_confs(array_copy_nptr_malloc<int>(other._confs, other._confs_no*other.allDim)),
|
|
29
29
|
_confs_no(other._confs_no),
|
|
30
30
|
allDim(other.allDim),
|
|
31
|
+
allDimSizeofInt(other.allDimSizeofInt),
|
|
31
32
|
sorted_by_mass(other.sorted_by_mass),
|
|
32
33
|
sorted_by_prob(other.sorted_by_prob),
|
|
33
|
-
total_prob(other.total_prob)
|
|
34
|
+
total_prob(other.total_prob),
|
|
35
|
+
current_size(other._confs_no)
|
|
34
36
|
{}
|
|
35
37
|
|
|
36
38
|
FixedEnvelope::FixedEnvelope(FixedEnvelope&& other) :
|
|
@@ -39,15 +41,60 @@ _probs(other._probs),
|
|
|
39
41
|
_confs(other._confs),
|
|
40
42
|
_confs_no(other._confs_no),
|
|
41
43
|
allDim(other.allDim),
|
|
44
|
+
allDimSizeofInt(other.allDimSizeofInt),
|
|
42
45
|
sorted_by_mass(other.sorted_by_mass),
|
|
43
46
|
sorted_by_prob(other.sorted_by_prob),
|
|
44
|
-
total_prob(other.total_prob)
|
|
47
|
+
total_prob(other.total_prob),
|
|
48
|
+
current_size(other.current_size)
|
|
45
49
|
{
|
|
46
50
|
other._masses = nullptr;
|
|
47
51
|
other._probs = nullptr;
|
|
48
52
|
other._confs = nullptr;
|
|
49
53
|
other._confs_no = 0;
|
|
50
54
|
other.total_prob = 0.0;
|
|
55
|
+
other.current_size = 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
FixedEnvelope& FixedEnvelope::operator=(const FixedEnvelope& other)
|
|
59
|
+
{
|
|
60
|
+
if(this == &other)
|
|
61
|
+
return *this;
|
|
62
|
+
// Copy-and-swap: construct the copy first so that if any allocation inside
|
|
63
|
+
// the copy constructor throws, *this is left untouched. Only after tmp is
|
|
64
|
+
// fully built do we pilfer its pointers; tmp then destructs holding the old
|
|
65
|
+
// ones, which frees them without any possibility of failure.
|
|
66
|
+
FixedEnvelope tmp(other);
|
|
67
|
+
std::swap(_masses, tmp._masses);
|
|
68
|
+
std::swap(_probs, tmp._probs);
|
|
69
|
+
std::swap(_confs, tmp._confs);
|
|
70
|
+
_confs_no = tmp._confs_no;
|
|
71
|
+
allDim = tmp.allDim;
|
|
72
|
+
allDimSizeofInt = tmp.allDimSizeofInt;
|
|
73
|
+
sorted_by_mass = tmp.sorted_by_mass;
|
|
74
|
+
sorted_by_prob = tmp.sorted_by_prob;
|
|
75
|
+
total_prob = tmp.total_prob;
|
|
76
|
+
current_size = tmp.current_size;
|
|
77
|
+
return *this;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
FixedEnvelope& FixedEnvelope::operator=(FixedEnvelope&& other)
|
|
81
|
+
{
|
|
82
|
+
if(this == &other)
|
|
83
|
+
return *this;
|
|
84
|
+
free(_masses);
|
|
85
|
+
free(_probs);
|
|
86
|
+
free(_confs);
|
|
87
|
+
_masses = other._masses; other._masses = nullptr;
|
|
88
|
+
_probs = other._probs; other._probs = nullptr;
|
|
89
|
+
_confs = other._confs; other._confs = nullptr;
|
|
90
|
+
_confs_no = other._confs_no; other._confs_no = 0;
|
|
91
|
+
allDim = other.allDim;
|
|
92
|
+
allDimSizeofInt = other.allDimSizeofInt;
|
|
93
|
+
sorted_by_mass = other.sorted_by_mass;
|
|
94
|
+
sorted_by_prob = other.sorted_by_prob;
|
|
95
|
+
total_prob = other.total_prob; other.total_prob = 0.0;
|
|
96
|
+
current_size = other.current_size; other.current_size = 0;
|
|
97
|
+
return *this;
|
|
51
98
|
}
|
|
52
99
|
|
|
53
100
|
FixedEnvelope::FixedEnvelope(double* in_masses, double* in_probs, size_t in_confs_no, bool masses_sorted, bool probs_sorted, double _total_prob) :
|
|
@@ -246,6 +293,12 @@ void FixedEnvelope::resample(size_t samples, double beta_bias)
|
|
|
246
293
|
double cprob = 0.0;
|
|
247
294
|
size_t pidx = -1; // Overflows - but it doesn't matter.
|
|
248
295
|
|
|
296
|
+
// Sentinel: prevents the inner while(pprob < cprob) from walking off the end
|
|
297
|
+
// if floating-point rounding leaves the accumulated probability sum slightly
|
|
298
|
+
// below 1.0. Safe to overwrite in-place: rdvariate_binom guards succ_prob>=1.0
|
|
299
|
+
// so infinity is handled correctly, and the sentinel is always cleaned up before
|
|
300
|
+
// return — either by the loop zeroing the slot when it advances pidx to here,
|
|
301
|
+
// or by the memset below when the loop terminates earlier.
|
|
249
302
|
_probs[_confs_no-1] = (std::numeric_limits<double>::max)();
|
|
250
303
|
|
|
251
304
|
while(samples > 0)
|
|
@@ -502,244 +555,6 @@ double FixedEnvelope::AbyssalWassersteinDistance(FixedEnvelope& other, double ab
|
|
|
502
555
|
return accd + condemned * abyss_depth * 0.5;
|
|
503
556
|
}
|
|
504
557
|
|
|
505
|
-
#if 0
|
|
506
|
-
double FixedEnvelope::ScaledAbyssalWassersteinDistance(FixedEnvelope * const * others, double abyss_depth, const double* other_scales, const size_t N)
|
|
507
|
-
{
|
|
508
|
-
sort_by_mass();
|
|
509
|
-
|
|
510
|
-
std::priority_queue<std::pair<double, size_t>> PQ;
|
|
511
|
-
std::unique_ptr<size_t[]> indices = std::make_unique<size_t[]>(N);
|
|
512
|
-
memset(indices.get(), 0, sizeof(size_t)*N);
|
|
513
|
-
|
|
514
|
-
for(size_t ii=0; ii<N; ii++)
|
|
515
|
-
{
|
|
516
|
-
others[ii]->sort_by_mass();
|
|
517
|
-
if(others[ii]->_confs_no > 0)
|
|
518
|
-
PQ.emplace_back({others._probs[0], ii});
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
std::vector<std::pair<double, double>> carried;
|
|
525
|
-
|
|
526
|
-
size_t idx_this = 0;
|
|
527
|
-
size_t idx_other = 0;
|
|
528
|
-
|
|
529
|
-
//std::cout << "AAA" << std::endl;
|
|
530
|
-
|
|
531
|
-
auto finished = [&]() -> bool { return idx_this >= _confs_no && PQ.empty(); };
|
|
532
|
-
auto next = [&]() -> std::tuple<double, double, size_t> {
|
|
533
|
-
if(idx_this >= _confs_no || (idx_other < other._confs_no && _masses[idx_this] > other._masses[idx_other]))
|
|
534
|
-
{
|
|
535
|
-
std::pair<double, double> res = std::pair<double, double>(other._masses[idx_other], other._probs[idx_other]*other_scale);
|
|
536
|
-
idx_other++;
|
|
537
|
-
return res;
|
|
538
|
-
}
|
|
539
|
-
else
|
|
540
|
-
{
|
|
541
|
-
std::pair<double, double> res = std::pair<double, double>(_masses[idx_this], -_probs[idx_this]);
|
|
542
|
-
idx_this++;
|
|
543
|
-
return res;
|
|
544
|
-
}
|
|
545
|
-
};
|
|
546
|
-
double accd = 0.0;
|
|
547
|
-
double condemned = 0.0;
|
|
548
|
-
|
|
549
|
-
while(!finished())
|
|
550
|
-
{
|
|
551
|
-
auto [m, p] = next();
|
|
552
|
-
if(!carried.empty() && carried[0].second * p > 0.0)
|
|
553
|
-
{
|
|
554
|
-
carried.emplace_back(m, p);
|
|
555
|
-
continue;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
while(!carried.empty())
|
|
559
|
-
{
|
|
560
|
-
auto& [cm, cp] = carried.back();
|
|
561
|
-
if(m - cm >= abyss_depth)
|
|
562
|
-
{
|
|
563
|
-
for(auto it = carried.cbegin(); it != carried.cend(); it++)
|
|
564
|
-
condemned += fabs(it->second);
|
|
565
|
-
carried.clear();
|
|
566
|
-
break;
|
|
567
|
-
}
|
|
568
|
-
if((cp+p)*p > 0.0)
|
|
569
|
-
{
|
|
570
|
-
accd += fabs((m-cm)*cp);
|
|
571
|
-
p += cp;
|
|
572
|
-
carried.pop_back();
|
|
573
|
-
}
|
|
574
|
-
else
|
|
575
|
-
{
|
|
576
|
-
accd += fabs((m-cm)*p);
|
|
577
|
-
cp += p;
|
|
578
|
-
p = 0.0;
|
|
579
|
-
break;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
if(p != 0.0)
|
|
583
|
-
carried.emplace_back(m, p);
|
|
584
|
-
//std::cout << m << " " << p << std::endl;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
for(auto it = carried.cbegin(); it != carried.cend(); it++)
|
|
588
|
-
condemned += fabs(it->second);
|
|
589
|
-
|
|
590
|
-
return accd + condemned * abyss_depth * 0.5;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
#endif
|
|
594
|
-
|
|
595
|
-
#if 0
|
|
596
|
-
double AbyssalWassersteinDistanceGrad(FixedEnvelope* const* envelopes, const double* scales, double* ret_gradient, size_t N, double abyss_depth_exp, double abyss_depth_the)
|
|
597
|
-
{
|
|
598
|
-
return 0.0;
|
|
599
|
-
std::unique_ptr<size_t[]> env_idx = std::make_unique<size_t[]>(N+1);
|
|
600
|
-
memset(env_idx.get(), 0, (N+1)*sizeof(size_t));
|
|
601
|
-
memset(ret_gradient, 0, (N+1)*sizeof(double));
|
|
602
|
-
|
|
603
|
-
auto pq_cmp = [](std::pair<double, size_t>& p1, std::pair<double, size_t>& p2) { return p1.first > p2.first; };
|
|
604
|
-
std::priority_queue<std::pair<double, size_t>, std::vector<std::pair<double, size_t>>, decltype(pq_cmp)> PQ(pq_cmp);
|
|
605
|
-
|
|
606
|
-
for(size_t ii=0; ii<=N; ii++)
|
|
607
|
-
{
|
|
608
|
-
envelopes[ii]->sort_by_mass();
|
|
609
|
-
if(envelopes[ii]->_confs_no > 0)
|
|
610
|
-
{
|
|
611
|
-
std::cout << "Initial push: " << envelopes[ii]->_masses[0] << " " << ii << '\n';
|
|
612
|
-
PQ.push({envelopes[ii]->_masses[0], ii});
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
std::vector<std::tuple<double, double, size_t>> carried;
|
|
617
|
-
|
|
618
|
-
auto next = [&]() -> std::tuple<double, double, size_t> {
|
|
619
|
-
auto [mass, eidx] = PQ.top();
|
|
620
|
-
double prob = envelopes[eidx]->_probs[env_idx[eidx]];
|
|
621
|
-
PQ.pop();
|
|
622
|
-
if(eidx == 0)
|
|
623
|
-
prob = -prob;
|
|
624
|
-
else
|
|
625
|
-
prob = prob * scales[eidx];
|
|
626
|
-
std::cout << "Next: " << mass << " " << prob << " " << eidx << '\n';
|
|
627
|
-
env_idx[eidx]++;
|
|
628
|
-
if(env_idx[eidx] < envelopes[eidx]->_confs_no)
|
|
629
|
-
PQ.push({envelopes[eidx]->_masses[env_idx[eidx]], eidx});
|
|
630
|
-
|
|
631
|
-
return {mass, prob, eidx};
|
|
632
|
-
};
|
|
633
|
-
double accd = 0.0;
|
|
634
|
-
double condemned = 0.0;
|
|
635
|
-
//double flow;
|
|
636
|
-
const double max_flow_dist = abyss_depth_exp + abyss_depth_the;
|
|
637
|
-
max_flow_dist *= 2.0;
|
|
638
|
-
|
|
639
|
-
while(!PQ.empty())
|
|
640
|
-
{
|
|
641
|
-
auto [m, p, eidx] = next();
|
|
642
|
-
if(!carried.empty() && std::get<1>(carried[0]) * p > 0.0)
|
|
643
|
-
{
|
|
644
|
-
carried.emplace_back(m, p, eidx);
|
|
645
|
-
continue;
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
while(!carried.empty())
|
|
649
|
-
{
|
|
650
|
-
auto& [cm, cp, ceidx] = carried.back();
|
|
651
|
-
if(m - cm >= max_flow_dist)
|
|
652
|
-
{
|
|
653
|
-
for(auto it = carried.cbegin(); it != carried.cend(); it++)
|
|
654
|
-
condemned += fabs(std::get<1>(*it));
|
|
655
|
-
carried.clear();
|
|
656
|
-
break;
|
|
657
|
-
}
|
|
658
|
-
std::cout << "accing\n";
|
|
659
|
-
if((cp+p)*p > 0.0)
|
|
660
|
-
{
|
|
661
|
-
accd += fabs((m-cm)*cp);
|
|
662
|
-
p += cp;
|
|
663
|
-
carried.pop_back();
|
|
664
|
-
std::cout << "cprob:" << cp << '\n';
|
|
665
|
-
}
|
|
666
|
-
else
|
|
667
|
-
{
|
|
668
|
-
accd += fabs((m-cm)*p);
|
|
669
|
-
cp += p;
|
|
670
|
-
std::cout << "prob:" << p << '\n';
|
|
671
|
-
p = 0.0;
|
|
672
|
-
break;
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
if(p != 0.0)
|
|
676
|
-
carried.emplace_back(m, p, eidx);
|
|
677
|
-
//std::cout << m << " " << p << std::endl;
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
for(auto it = carried.cbegin(); it != carried.cend(); it++)
|
|
681
|
-
condemned += fabs(std::get<1>(*it));
|
|
682
|
-
|
|
683
|
-
std::cout << "ISO:" << accd << " " << condemned << '\n';
|
|
684
|
-
return accd + condemned * max_flow_dist * 0.5;
|
|
685
|
-
while(!PQ.empty())
|
|
686
|
-
{
|
|
687
|
-
auto [m, p, eidx] = next();
|
|
688
|
-
if(!carried.empty() && (std::get<1>(carried[0]) * p > 0.0))
|
|
689
|
-
{
|
|
690
|
-
carried.emplace_back(m, p, eidx);
|
|
691
|
-
continue;
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
while(!carried.empty())
|
|
695
|
-
{
|
|
696
|
-
auto& [cm, cp, ceidx] = carried.back();
|
|
697
|
-
if(m - cm >= max_flow_dist)
|
|
698
|
-
{
|
|
699
|
-
for(auto it = carried.cbegin(); it != carried.cend(); it++)
|
|
700
|
-
{
|
|
701
|
-
flow = fabs(std::get<1>(*it));
|
|
702
|
-
const size_t target_idx = std::get<2>(*it);
|
|
703
|
-
flow *= target_idx == 0 ? abyss_depth_exp : abyss_depth_the;
|
|
704
|
-
ret_gradient[target_idx] += flow;
|
|
705
|
-
condemned += flow;
|
|
706
|
-
std::cout << "condemnin': " << m << " " << p << " " << eidx << " | " << cm << " " << cp << " " << ceidx << '\n';
|
|
707
|
-
}
|
|
708
|
-
carried.clear();
|
|
709
|
-
break;
|
|
710
|
-
}
|
|
711
|
-
if((cp+p)*p > 0.0)
|
|
712
|
-
{
|
|
713
|
-
flow = fabs((m-cm)*cp);
|
|
714
|
-
accd += flow;
|
|
715
|
-
p += cp;
|
|
716
|
-
ret_gradient[ceidx] += flow;
|
|
717
|
-
carried.pop_back();
|
|
718
|
-
}
|
|
719
|
-
else
|
|
720
|
-
{
|
|
721
|
-
flow = fabs((m-cm)*p);
|
|
722
|
-
accd += flow;
|
|
723
|
-
cp += p;
|
|
724
|
-
ret_gradient[eidx] += flow;
|
|
725
|
-
p = 0.0;
|
|
726
|
-
break;
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
if(p != 0.0)
|
|
730
|
-
carried.emplace_back(m, p, eidx);
|
|
731
|
-
//std::cout << m << " " << p << std::endl;
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
for(auto it = carried.cbegin(); it != carried.cend(); it++)
|
|
735
|
-
condemned += fabs(std::get<1>(*it));
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
return accd + condemned * (abyss_depth_exp + abyss_depth_the) * 0.5;
|
|
739
|
-
}
|
|
740
|
-
#endif
|
|
741
|
-
|
|
742
|
-
|
|
743
558
|
std::tuple<double, double, double> FixedEnvelope::WassersteinMatch(FixedEnvelope& other, double flow_distance, double other_scale)
|
|
744
559
|
{
|
|
745
560
|
if(_confs_no == 0)
|
|
@@ -867,48 +682,60 @@ FixedEnvelope FixedEnvelope::bin(double bin_width, double middle)
|
|
|
867
682
|
|
|
868
683
|
template<bool tgetConfs> void FixedEnvelope::reallocate_memory(size_t new_size)
|
|
869
684
|
{
|
|
870
|
-
|
|
871
|
-
// FIXME: Handle overflow gracefully here. It definitely could happen for people still stuck on 32 bits...
|
|
872
|
-
_masses = reinterpret_cast<double*>(realloc(_masses, new_size * sizeof(double)));
|
|
873
|
-
if(_masses == nullptr)
|
|
685
|
+
if(new_size > SIZE_MAX / sizeof(double))
|
|
874
686
|
throw std::bad_alloc();
|
|
687
|
+
double* tmp_masses = reinterpret_cast<double*>(realloc(_masses, new_size * sizeof(double)));
|
|
688
|
+
if(tmp_masses == nullptr)
|
|
689
|
+
throw std::bad_alloc();
|
|
690
|
+
_masses = tmp_masses;
|
|
875
691
|
tmasses = _masses + _confs_no;
|
|
876
692
|
|
|
877
|
-
|
|
878
|
-
if(
|
|
693
|
+
double* tmp_probs = reinterpret_cast<double*>(realloc(_probs, new_size * sizeof(double)));
|
|
694
|
+
if(tmp_probs == nullptr)
|
|
879
695
|
throw std::bad_alloc();
|
|
696
|
+
_probs = tmp_probs;
|
|
880
697
|
tprobs = _probs + _confs_no;
|
|
881
698
|
|
|
882
699
|
constexpr_if(tgetConfs)
|
|
883
700
|
{
|
|
884
|
-
|
|
885
|
-
|
|
701
|
+
if(allDimSizeofInt > 0 && new_size > SIZE_MAX / static_cast<size_t>(allDimSizeofInt))
|
|
702
|
+
throw std::bad_alloc();
|
|
703
|
+
int* tmp_confs = reinterpret_cast<int*>(realloc(_confs, new_size * allDimSizeofInt));
|
|
704
|
+
if(tmp_confs == nullptr)
|
|
886
705
|
throw std::bad_alloc();
|
|
706
|
+
_confs = tmp_confs;
|
|
887
707
|
tconfs = _confs + (allDim * _confs_no);
|
|
888
708
|
}
|
|
709
|
+
current_size = new_size;
|
|
889
710
|
}
|
|
890
711
|
|
|
891
712
|
void FixedEnvelope::slow_reallocate_memory(size_t new_size)
|
|
892
713
|
{
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
if(
|
|
714
|
+
if(new_size > SIZE_MAX / sizeof(double))
|
|
715
|
+
throw std::bad_alloc();
|
|
716
|
+
double* tmp_masses = reinterpret_cast<double*>(realloc(_masses, new_size * sizeof(double)));
|
|
717
|
+
if(tmp_masses == nullptr)
|
|
897
718
|
throw std::bad_alloc();
|
|
719
|
+
_masses = tmp_masses;
|
|
898
720
|
tmasses = _masses + _confs_no;
|
|
899
721
|
|
|
900
|
-
|
|
901
|
-
if(
|
|
722
|
+
double* tmp_probs = reinterpret_cast<double*>(realloc(_probs, new_size * sizeof(double)));
|
|
723
|
+
if(tmp_probs == nullptr)
|
|
902
724
|
throw std::bad_alloc();
|
|
725
|
+
_probs = tmp_probs;
|
|
903
726
|
tprobs = _probs + _confs_no;
|
|
904
727
|
|
|
905
728
|
if(_confs != nullptr)
|
|
906
729
|
{
|
|
907
|
-
|
|
908
|
-
if(_confs == nullptr)
|
|
730
|
+
if(allDimSizeofInt > 0 && new_size > SIZE_MAX / static_cast<size_t>(allDimSizeofInt))
|
|
909
731
|
throw std::bad_alloc();
|
|
732
|
+
int* tmp_confs = reinterpret_cast<int*>(realloc(_confs, new_size * allDimSizeofInt));
|
|
733
|
+
if(tmp_confs == nullptr)
|
|
734
|
+
throw std::bad_alloc();
|
|
735
|
+
_confs = tmp_confs;
|
|
910
736
|
tconfs = _confs + (allDim * _confs_no);
|
|
911
737
|
}
|
|
738
|
+
current_size = new_size;
|
|
912
739
|
}
|
|
913
740
|
|
|
914
741
|
template<bool tgetConfs> void FixedEnvelope::threshold_init(Iso&& iso, double threshold, bool absolute)
|
|
@@ -1155,7 +982,7 @@ FixedEnvelope FixedEnvelope::Binned(Iso&& iso, double target_total_prob, double
|
|
|
1155
982
|
|
|
1156
983
|
ret.reallocate_memory<false>(ISOSPEC_INIT_TABLE_SIZE);
|
|
1157
984
|
|
|
1158
|
-
for(size_t ii = nonzero_idx;
|
|
985
|
+
for(size_t ii = nonzero_idx; empty_steps < distance_10da; )
|
|
1159
986
|
{
|
|
1160
987
|
if(acc[ii] > 0.0)
|
|
1161
988
|
{
|
|
@@ -1164,6 +991,8 @@ FixedEnvelope FixedEnvelope::Binned(Iso&& iso, double target_total_prob, double
|
|
|
1164
991
|
}
|
|
1165
992
|
else
|
|
1166
993
|
empty_steps++;
|
|
994
|
+
if(ii == idx_min) break;
|
|
995
|
+
ii--;
|
|
1167
996
|
}
|
|
1168
997
|
|
|
1169
998
|
empty_steps = 0;
|
|
@@ -34,9 +34,6 @@ namespace IsoSpec
|
|
|
34
34
|
|
|
35
35
|
class FixedEnvelope;
|
|
36
36
|
|
|
37
|
-
double AbyssalWassersteinDistanceGrad(FixedEnvelope* const* envelopes, const double* scales, double* ret_gradient, size_t N, double abyss_depth_exp, double abyss_depth_the);
|
|
38
|
-
|
|
39
|
-
|
|
40
37
|
class ISOSPEC_EXPORT_SYMBOL FixedEnvelope {
|
|
41
38
|
protected:
|
|
42
39
|
double* _masses;
|
|
@@ -61,7 +58,7 @@ class ISOSPEC_EXPORT_SYMBOL FixedEnvelope {
|
|
|
61
58
|
allDim(0),
|
|
62
59
|
sorted_by_mass(false),
|
|
63
60
|
sorted_by_prob(false),
|
|
64
|
-
total_prob(
|
|
61
|
+
total_prob(NAN),
|
|
65
62
|
current_size(0),
|
|
66
63
|
allDimSizeofInt(0)
|
|
67
64
|
// Deliberately not initializing tmasses, tprobs, tconfs
|
|
@@ -69,6 +66,8 @@ class ISOSPEC_EXPORT_SYMBOL FixedEnvelope {
|
|
|
69
66
|
|
|
70
67
|
FixedEnvelope(const FixedEnvelope& other);
|
|
71
68
|
FixedEnvelope(FixedEnvelope&& other);
|
|
69
|
+
FixedEnvelope& operator=(const FixedEnvelope& other);
|
|
70
|
+
FixedEnvelope& operator=(FixedEnvelope&& other);
|
|
72
71
|
|
|
73
72
|
FixedEnvelope(double* masses, double* probs, size_t confs_no, bool masses_sorted = false, bool probs_sorted = false, double _total_prob = NAN);
|
|
74
73
|
FixedEnvelope(double* masses, double* probs, int* confs, size_t confs_no, int _allDim, bool masses_sorted = false, bool probs_sorted = false, double _total_prob = NAN);
|
|
@@ -239,7 +238,6 @@ class ISOSPEC_EXPORT_SYMBOL FixedEnvelope {
|
|
|
239
238
|
return Binned(Iso(iso, false), target_total_prob, bin_width, bin_middle);
|
|
240
239
|
}
|
|
241
240
|
|
|
242
|
-
friend double AbyssalWassersteinDistanceGrad(FixedEnvelope* const* envelopes, const double* scales, double* ret_gradient, size_t N, double abyss_depth_exp, double abyss_depth_the);
|
|
243
241
|
};
|
|
244
242
|
|
|
245
243
|
} // namespace IsoSpec
|
|
@@ -62,11 +62,10 @@ def ParseFormula(formula):
|
|
|
62
62
|
|
|
63
63
|
return ret
|
|
64
64
|
|
|
65
|
-
fasta_parsing_space = isoFFI.ffi.new("int[6]")
|
|
66
|
-
|
|
67
65
|
def ParseFASTA(fasta):
|
|
68
66
|
if isinstance(fasta, str):
|
|
69
67
|
fasta = fasta.encode("ascii")
|
|
68
|
+
fasta_parsing_space = isoFFI.ffi.new("int[6]")
|
|
70
69
|
isoFFI.clib.parse_fasta_c(fasta, fasta_parsing_space)
|
|
71
70
|
elements = list("CHNOS")
|
|
72
71
|
if fasta_parsing_space[5] > 0:
|
|
@@ -183,8 +182,10 @@ class Iso(object):
|
|
|
183
182
|
raise ValueError("All isotope probabilities p must fulfill: 0.0 < p <= 1.0")
|
|
184
183
|
|
|
185
184
|
self.isotopeNumbers = tuple(map(len, self.isotopeMasses))
|
|
186
|
-
|
|
187
|
-
|
|
185
|
+
if self.isotopeNumbers != tuple(map(len, self.isotopeProbabilities)):
|
|
186
|
+
raise ValueError("isotopeMasses and isotopeProbabilities must have the same number of isotopes per element")
|
|
187
|
+
if len(self.atomCounts) != len(self.isotopeNumbers) or len(self.isotopeNumbers) != len(self.isotopeProbabilities):
|
|
188
|
+
raise ValueError("atomCounts, isotopeMasses, and isotopeProbabilities must all have the same length")
|
|
188
189
|
|
|
189
190
|
self.dimNumber = len(self.isotopeNumbers)
|
|
190
191
|
|
|
@@ -299,7 +300,7 @@ class IsoDistribution(object):
|
|
|
299
300
|
try:
|
|
300
301
|
import numpy as np
|
|
301
302
|
except ImportError as e:
|
|
302
|
-
raise Exception(e
|
|
303
|
+
raise Exception(str(e) + "\nThis requires numpy to be installed.")
|
|
303
304
|
return np.frombuffer(isoFFI.ffi.buffer(self.masses))
|
|
304
305
|
|
|
305
306
|
def np_probs(self):
|
|
@@ -307,7 +308,7 @@ class IsoDistribution(object):
|
|
|
307
308
|
try:
|
|
308
309
|
import numpy as np
|
|
309
310
|
except ImportError as e:
|
|
310
|
-
raise Exception(e
|
|
311
|
+
raise Exception(str(e) + "\nThis requires numpy to be installed.")
|
|
311
312
|
return np.frombuffer(isoFFI.ffi.buffer(self.probs))
|
|
312
313
|
|
|
313
314
|
def __iter__(self):
|
|
@@ -358,22 +359,16 @@ class IsoDistribution(object):
|
|
|
358
359
|
self.parse_conf = iso._get_parse_conf_fun()
|
|
359
360
|
|
|
360
361
|
elif probs is not None or masses is not None:
|
|
361
|
-
|
|
362
|
-
|
|
362
|
+
if probs is None or masses is None:
|
|
363
|
+
raise ValueError("masses and probs must both be provided together")
|
|
364
|
+
if len(probs) != len(masses):
|
|
365
|
+
raise ValueError("masses and probs must have the same length")
|
|
363
366
|
self.size = len(probs)
|
|
364
367
|
type_str = "double["+str(self.size)+"]"
|
|
365
368
|
self.probs = isoFFI.ffi.new(type_str, probs)
|
|
366
369
|
self.masses = isoFFI.ffi.new(type_str, masses)
|
|
367
|
-
elif cobject == probs == masses == get_confs == iso == None:
|
|
368
|
-
self.size = 0
|
|
369
|
-
type_str = "double["+str(self.size)+"]"
|
|
370
|
-
self.probs = isoFFI.ffi.new(type_str, [])
|
|
371
|
-
self.masses = isoFFI.ffi.new(type_str, [])
|
|
372
|
-
self._total_prob = 0.0
|
|
373
|
-
self.mass_sorted = True
|
|
374
|
-
self.prob_sorted = True
|
|
375
370
|
else:
|
|
376
|
-
raise
|
|
371
|
+
raise ValueError("IsoDistribution requires at least one of: cobject, or masses+probs")
|
|
377
372
|
|
|
378
373
|
def _get_cobject(self):
|
|
379
374
|
if hasattr(self, 'raw_confs') and self.raw_confs is not None:
|
|
@@ -666,13 +661,15 @@ def IsoStochastic(no_molecules,
|
|
|
666
661
|
beta_bias=5.0,
|
|
667
662
|
get_confs=False,
|
|
668
663
|
**kwargs):
|
|
669
|
-
"""Initialize the
|
|
664
|
+
"""Initialize the isotopic distribution by stochastic sampling, simulating a measured mass spectrum
|
|
665
|
+
with a given number of ions. Each configuration is drawn independently according to its isotopic
|
|
666
|
+
probability, producing integer ion counts rather than exact probabilities.
|
|
670
667
|
|
|
671
668
|
Args:
|
|
672
|
-
no_molecules (uint): ionic current
|
|
669
|
+
no_molecules (uint): number of ions to simulate (ionic current).
|
|
673
670
|
formula (str): a chemical formula, e.g. "C2H6O1" or "C2H6O".
|
|
674
|
-
precision (float):
|
|
675
|
-
beta_bias (float, nonnegative): fiddling with this parameter does not change the result, but might make computations slightly faster (or likely, much, much slower
|
|
671
|
+
precision (float): total probability of the envelope used for sampling. Between 0.0 and 1.0.
|
|
672
|
+
beta_bias (float, nonnegative): fiddling with this parameter does not change the result, but might make computations slightly faster (or likely, much, much slower if you screw it up...)
|
|
676
673
|
get_confs (boolean): should we report the counts of isotopologues?
|
|
677
674
|
**kwargs: named arguments to the superclass.
|
|
678
675
|
"""
|
|
@@ -688,14 +685,14 @@ def IsoBinned(bin_width,
|
|
|
688
685
|
target_total_prob=0.9999,
|
|
689
686
|
bin_middle=0.0,
|
|
690
687
|
**kwargs):
|
|
691
|
-
"""Initialize the
|
|
688
|
+
"""Initialize the isotopic distribution as a binned (histogram) envelope.
|
|
689
|
+
Configurations are grouped into bins of equal width and their probabilities summed.
|
|
692
690
|
|
|
693
691
|
Args:
|
|
694
|
-
|
|
692
|
+
bin_width (float): width of each bin in Da.
|
|
695
693
|
formula (str): a chemical formula, e.g. "C2H6O1" or "C2H6O".
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
get_confs (boolean): should we report the counts of isotopologues?
|
|
694
|
+
target_total_prob (float): total probability of configurations to include before binning. Between 0.0 and 1.0.
|
|
695
|
+
bin_middle (float): offset of bin centres from zero.
|
|
699
696
|
**kwargs: named arguments to the superclass.
|
|
700
697
|
"""
|
|
701
698
|
iso = Iso(formula=formula, get_confs=False, **kwargs)
|
|
@@ -781,12 +778,13 @@ class IsoThresholdGenerator(IsoGenerator):
|
|
|
781
778
|
class IsoLayeredGenerator(IsoGenerator):
|
|
782
779
|
"""Class alowing memory-efficient iteration over the isotopic distribution up till some joint probability of the reported peaks."""
|
|
783
780
|
def __init__(self, formula="", get_confs=False, reorder_marginals = True, t_prob_hint = 0.99, **kwargs):
|
|
784
|
-
"""Initialize
|
|
781
|
+
"""Initialize IsoLayeredGenerator.
|
|
785
782
|
|
|
786
783
|
Args:
|
|
787
784
|
formula (str): a chemical formula, e.g. "C2H6O1" or "C2H6O".
|
|
788
|
-
absolute (boolean): should we report peaks with probabilities above an absolute probability threshold, or above a relative threshold amounting to a given proportion of the most probable peak?
|
|
789
785
|
get_confs (boolean): should we report the counts of isotopologues?
|
|
786
|
+
reorder_marginals (boolean): should the marginal distributions be reordered for efficiency?
|
|
787
|
+
t_prob_hint (float): hint for the target total probability, used to size internal buffers.
|
|
790
788
|
**kwargs: named arguments to the superclass.
|
|
791
789
|
"""
|
|
792
790
|
super(IsoLayeredGenerator, self).__init__(formula=formula, get_confs=get_confs, **kwargs)
|
|
@@ -832,7 +830,7 @@ class IsoOrderedGenerator(IsoGenerator):
|
|
|
832
830
|
def __del__(self):
|
|
833
831
|
try:
|
|
834
832
|
if self.cgen is not None:
|
|
835
|
-
self.ffi.
|
|
833
|
+
self.ffi.deleteIsoOrderedGenerator(self.cgen)
|
|
836
834
|
self.cgen = None
|
|
837
835
|
except AttributeError:
|
|
838
836
|
pass
|
|
@@ -20,7 +20,7 @@ symbol_to_masses = dict(symbol_to_masses)
|
|
|
20
20
|
symbol_to_probs = dict(symbol_to_probs)
|
|
21
21
|
|
|
22
22
|
# Several derivative convenience dicts...
|
|
23
|
-
symbol_to_massprob = dict((key,
|
|
23
|
+
symbol_to_massprob = dict((key, list(zip(symbol_to_masses[key], symbol_to_probs[key]))) for key in symbol_to_probs.keys())
|
|
24
24
|
|
|
25
25
|
def crossprod(l1, l2):
|
|
26
26
|
return sum(x1*x2 for x1, x2 in zip(l1, l2))
|
|
@@ -24,15 +24,6 @@ def test_log_multinomial_confs_cnt():
|
|
|
24
24
|
assert abs(x - 4.189655) < 10**(-5)
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
def multinomial_confs_cnt(n, i):
|
|
28
|
-
"""Return the approximate number of configurations of the multinomial distribution.
|
|
29
|
-
|
|
30
|
-
Args:
|
|
31
|
-
n (int): The number of trials.
|
|
32
|
-
i (int): The number of possible outcomes.
|
|
33
|
-
"""
|
|
34
|
-
return exp(log_subiso_cnt_simplex(n, i))
|
|
35
|
-
|
|
36
27
|
|
|
37
28
|
def log_V_simplex(n, i):
|
|
38
29
|
"""Get the natural logarithm of the volume of a simplex {(x_1,..,x_{i-1}): \sum_{j=1}^i = n}.
|
|
@@ -184,7 +184,7 @@ sure you want to do that, edit the source and disable this check."""
|
|
|
184
184
|
extension = [".so", ".dylib", ".dll"]
|
|
185
185
|
try:
|
|
186
186
|
if platform.system() == "Linux":
|
|
187
|
-
extension = [".so", "pyd"]
|
|
187
|
+
extension = [".so", ".pyd"]
|
|
188
188
|
elif platform.system() == "Windows":
|
|
189
189
|
extension = [".dll", ".pyd"]
|
|
190
190
|
except:
|
|
@@ -236,7 +236,7 @@ sure you want to do that, edit the source and disable this check."""
|
|
|
236
236
|
except (IndexError, OSError) as e:
|
|
237
237
|
errmsg = (
|
|
238
238
|
"Load libIsoSpec++.so, tried: "
|
|
239
|
-
+ libpath
|
|
239
|
+
+ str(libpath)
|
|
240
240
|
+ "\n"
|
|
241
241
|
+ "Got error: "
|
|
242
242
|
+ str(type(e))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|