17#include "fixedEnvelopes.h"
26_masses(array_copy<double>(other._masses, other._confs_no)),
27_probs(array_copy<double>(other._probs, other._confs_no)),
28_confs(array_copy_nptr<int>(other._confs, other._confs_no*other.allDim)),
29_confs_no(other._confs_no),
31sorted_by_mass(other.sorted_by_mass),
32sorted_by_prob(other.sorted_by_prob),
33total_prob(other.total_prob)
36FixedEnvelope::FixedEnvelope(FixedEnvelope&& other) :
37_masses(other._masses),
40_confs_no(other._confs_no),
42sorted_by_mass(other.sorted_by_mass),
43sorted_by_prob(other.sorted_by_prob),
44total_prob(other.total_prob)
46other._masses =
nullptr;
47other._probs =
nullptr;
48other._confs =
nullptr;
50other.total_prob = 0.0;
53FixedEnvelope::FixedEnvelope(
double* in_masses,
double* in_probs,
size_t in_confs_no,
bool masses_sorted,
bool probs_sorted,
double _total_prob) :
57_confs_no(in_confs_no),
59sorted_by_mass(masses_sorted),
60sorted_by_prob(probs_sorted),
61total_prob(_total_prob)
64FixedEnvelope FixedEnvelope::operator+(
const FixedEnvelope& other)
const
66 double* nprobs =
reinterpret_cast<double*
>(malloc(
sizeof(
double) * (_confs_no+other._confs_no)));
68 throw std::bad_alloc();
69 double* nmasses =
reinterpret_cast<double*
>(malloc(
sizeof(
double) * (_confs_no+other._confs_no)));
70 if(nmasses ==
nullptr)
73 throw std::bad_alloc();
76 memcpy(nprobs, _probs,
sizeof(
double) * _confs_no);
77 memcpy(nmasses, _masses,
sizeof(
double) * _confs_no);
79 memcpy(nprobs+_confs_no, other._probs,
sizeof(
double) * other._confs_no);
80 memcpy(nmasses+_confs_no, other._masses,
sizeof(
double) * other._confs_no);
82 return FixedEnvelope(nmasses, nprobs, _confs_no + other._confs_no);
85FixedEnvelope FixedEnvelope::operator*(
const FixedEnvelope& other)
const
87 double* nprobs =
reinterpret_cast<double*
>(malloc(
sizeof(
double) * _confs_no * other._confs_no));
89 throw std::bad_alloc();
92 double* nmasses =
reinterpret_cast<double*
>(malloc(
sizeof(
double) * _confs_no * other._confs_no));
93 if(nmasses ==
nullptr)
96 throw std::bad_alloc();
101 for(
size_t ii = 0; ii < _confs_no; ii++)
102 for(
size_t jj = 0; jj < other._confs_no; jj++)
104 nprobs[tgt_idx] = _probs[ii] * other._probs[jj];
105 nmasses[tgt_idx] = _masses[ii] + other._masses[jj];
109 return FixedEnvelope(nmasses, nprobs, tgt_idx);
112void FixedEnvelope::sort_by_mass()
119 sorted_by_mass =
true;
120 sorted_by_prob =
false;
124void FixedEnvelope::sort_by_prob()
131 sorted_by_prob =
true;
132 sorted_by_mass =
false;
135template<
typename T>
void reorder_array(T* arr,
size_t* order,
size_t size,
bool can_destroy =
false)
139 size_t* order_c =
new size_t[size];
140 memcpy(order_c, order,
sizeof(
size_t)*size);
144 for(
size_t ii = 0; ii < size; ii++)
145 while(order[ii] != ii)
147 std::swap(arr[ii], arr[order[ii]]);
148 std::swap(order[order[ii]], order[ii]);
155void FixedEnvelope::sort_by(
double* order)
160 size_t* indices =
new size_t[_confs_no];
162 for(
size_t ii = 0; ii < _confs_no; ii++)
165 std::sort<size_t*>(indices, indices + _confs_no, TableOrder<double>(order));
167 size_t* inverse =
new size_t[_confs_no];
169 for(
size_t ii = 0; ii < _confs_no; ii++)
170 inverse[indices[ii]] = ii;
174 reorder_array(_masses, inverse, _confs_no);
175 reorder_array(_probs, inverse, _confs_no, _confs ==
nullptr);
176 if(_confs !=
nullptr)
178 int* swapspace =
new int[allDim];
179 for(
size_t ii = 0; ii < _confs_no; ii++)
180 while(inverse[ii] != ii)
182 memcpy(swapspace, &_confs[ii*allDim], allDimSizeofInt);
183 memcpy(&_confs[ii*allDim], &_confs[inverse[ii]*allDim], allDimSizeofInt);
184 memcpy(&_confs[inverse[ii]*allDim], swapspace, allDimSizeofInt);
185 std::swap(inverse[inverse[ii]], inverse[ii]);
193double FixedEnvelope::get_total_prob()
195 if(std::isnan(total_prob))
198 for(
size_t ii = 0; ii < _confs_no; ii++)
199 total_prob += _probs[ii];
204void FixedEnvelope::scale(
double factor)
206 for(
size_t ii = 0; ii < _confs_no; ii++)
207 _probs[ii] *= factor;
208 total_prob *= factor;
211void FixedEnvelope::normalize()
213 double tp = get_total_prob();
221void FixedEnvelope::shift_mass(
double value)
223 for(
size_t ii = 0; ii < _confs_no; ii++)
224 _masses[ii] += value;
227void FixedEnvelope::resample(
size_t samples,
double beta_bias)
230 throw std::logic_error(
"Resample called on an empty spectrum");
236 _probs[_confs_no-1] = (std::numeric_limits<double>::max)();
240 pprob += _probs[++pidx];
242 double covered_part = (pprob - cprob) / (1.0 - cprob);
243 while(samples * covered_part < beta_bias && samples > 0)
245 cprob += rdvariate_beta_1_b(samples) * (1.0 - cprob);
248 pprob += _probs[++pidx];
253 covered_part = (pprob - cprob) / (1.0 - cprob);
257 size_t nrtaken = rdvariate_binom(samples, covered_part);
258 _probs[pidx] +=
static_cast<double>(nrtaken);
264 memset(_probs + pidx, 0,
sizeof(
double)*(_confs_no - pidx));
267FixedEnvelope FixedEnvelope::LinearCombination(
const std::vector<const FixedEnvelope*>& spectra,
const std::vector<double>& intensities)
269 return LinearCombination(spectra.data(), intensities.data(), spectra.size());
272FixedEnvelope FixedEnvelope::LinearCombination(
const FixedEnvelope*
const * spectra,
const double* intensities,
size_t size)
275 for(
size_t ii = 0; ii < size; ii++)
276 ret_size += spectra[ii]->_confs_no;
278 double* newprobs =
reinterpret_cast<double*
>(malloc(
sizeof(
double)*ret_size));
279 if(newprobs ==
nullptr)
280 throw std::bad_alloc();
281 double* newmasses =
reinterpret_cast<double*
>(malloc(
sizeof(
double)*ret_size));
282 if(newmasses ==
nullptr)
285 throw std::bad_alloc();
289 for(
size_t ii = 0; ii < size; ii++)
291 double mul = intensities[ii];
292 for(
size_t jj = 0; jj < spectra[ii]->_confs_no; jj++)
293 newprobs[jj+cntr] = spectra[ii]->_probs[jj] * mul;
294 memcpy(newmasses + cntr, spectra[ii]->_masses,
sizeof(
double) * spectra[ii]->_confs_no);
295 cntr += spectra[ii]->_confs_no;
297 return FixedEnvelope(newmasses, newprobs, cntr);
300double FixedEnvelope::WassersteinDistance(FixedEnvelope& other)
303 if((get_total_prob()*0.999 > other.get_total_prob()) || (other.get_total_prob() > get_total_prob()*1.001))
304 throw std::logic_error(
"Spectra must be normalized before computing Wasserstein Distance");
306 if(_confs_no == 0 || other._confs_no == 0)
310 other.sort_by_mass();
313 size_t idx_other = 0;
315 double acc_prob = 0.0;
316 double last_point = 0.0;
319 while(idx_this < _confs_no && idx_other < other._confs_no)
321 if(_masses[idx_this] < other._masses[idx_other])
323 ret += (_masses[idx_this] - last_point) * std::abs(acc_prob);
324 acc_prob += _probs[idx_this];
325 last_point = _masses[idx_this];
330 ret += (other._masses[idx_other] - last_point) * std::abs(acc_prob);
331 acc_prob -= other._probs[idx_other];
332 last_point = other._masses[idx_other];
337 acc_prob = std::abs(acc_prob);
339 while(idx_this < _confs_no)
341 ret += (_masses[idx_this] - last_point) * acc_prob;
342 acc_prob -= _probs[idx_this];
343 last_point = _masses[idx_this];
347 while(idx_other < other._confs_no)
349 ret += (other._masses[idx_other] - last_point) * acc_prob;
350 acc_prob -= other._probs[idx_other];
351 last_point = other._masses[idx_other];
359double FixedEnvelope::OrientedWassersteinDistance(FixedEnvelope& other)
362 if((get_total_prob()*0.999 > other.get_total_prob()) || (other.get_total_prob() > get_total_prob()*1.001))
363 throw std::logic_error(
"Spectra must be normalized before computing Wasserstein Distance");
365 if(_confs_no == 0 || other._confs_no == 0)
369 other.sort_by_mass();
372 size_t idx_other = 0;
374 double acc_prob = 0.0;
375 double last_point = 0.0;
378 while(idx_this < _confs_no && idx_other < other._confs_no)
380 if(_masses[idx_this] < other._masses[idx_other])
382 ret += (_masses[idx_this] - last_point) * acc_prob;
383 acc_prob += _probs[idx_this];
384 last_point = _masses[idx_this];
389 ret += (other._masses[idx_other] - last_point) * acc_prob;
390 acc_prob -= other._probs[idx_other];
391 last_point = other._masses[idx_other];
396 while(idx_this < _confs_no)
398 ret += (_masses[idx_this] - last_point) * acc_prob;
399 acc_prob -= _probs[idx_this];
400 last_point = _masses[idx_this];
404 while(idx_other < other._confs_no)
406 ret += (other._masses[idx_other] - last_point) * acc_prob;
407 acc_prob -= other._probs[idx_other];
408 last_point = other._masses[idx_other];
415double FixedEnvelope::AbyssalWassersteinDistance(FixedEnvelope& other,
double abyss_depth,
double other_scale)
418 other.sort_by_mass();
420 std::vector<std::pair<double, double>> carried;
423 size_t idx_other = 0;
427 auto finished = [&]() ->
bool {
return idx_this >= _confs_no && idx_other >= other._confs_no; };
428 auto next = [&]() -> std::pair<double, double> {
429 if(idx_this >= _confs_no || (idx_other < other._confs_no && _masses[idx_this] > other._masses[idx_other]))
431 std::pair<double, double> res = std::pair<double, double>(other._masses[idx_other], other._probs[idx_other]*other_scale);
437 std::pair<double, double> res = std::pair<double, double>(_masses[idx_this], -_probs[idx_this]);
443 double condemned = 0.0;
448 double m = pair.first;
449 double p = pair.second;
450 if(!carried.empty() && carried[0].second * p > 0.0)
452 carried.emplace_back(m, p);
456 while(!carried.empty())
458 double cm = carried.back().first;
459 double cp = carried.back().second;
460 if(m - cm >= abyss_depth)
462 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
463 condemned += fabs(it->second);
469 accd += fabs((m-cm)*cp);
475 accd += fabs((m-cm)*p);
482 carried.emplace_back(m, p);
486 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
487 condemned += fabs(it->second);
489 return accd + condemned * abyss_depth * 0.5;
493double FixedEnvelope::ScaledAbyssalWassersteinDistance(FixedEnvelope *
const * others,
double abyss_depth,
const double* other_scales,
const size_t N)
497 std::priority_queue<std::pair<double, size_t>> PQ;
498 std::unique_ptr<size_t[]> indices = std::make_unique<size_t[]>(N);
499 memset(indices.get(), 0,
sizeof(
size_t)*N);
501 for(
size_t ii=0; ii<N; ii++)
503 others[ii]->sort_by_mass();
504 if(others[ii]->_confs_no > 0)
505 PQ.emplace_back({others._probs[0], ii});
511 std::vector<std::pair<double, double>> carried;
514 size_t idx_other = 0;
518 auto finished = [&]() ->
bool {
return idx_this >= _confs_no && PQ.empty(); };
519 auto next = [&]() -> std::tuple<double, double, size_t> {
520 if(idx_this >= _confs_no || (idx_other < other._confs_no && _masses[idx_this] > other._masses[idx_other]))
522 std::pair<double, double> res = std::pair<double, double>(other._masses[idx_other], other._probs[idx_other]*other_scale);
528 std::pair<double, double> res = std::pair<double, double>(_masses[idx_this], -_probs[idx_this]);
534 double condemned = 0.0;
538 auto [m, p] = next();
539 if(!carried.empty() && carried[0].second * p > 0.0)
541 carried.emplace_back(m, p);
545 while(!carried.empty())
547 auto& [cm, cp] = carried.back();
548 if(m - cm >= abyss_depth)
550 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
551 condemned += fabs(it->second);
557 accd += fabs((m-cm)*cp);
563 accd += fabs((m-cm)*p);
570 carried.emplace_back(m, p);
574 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
575 condemned += fabs(it->second);
577 return accd + condemned * abyss_depth * 0.5;
583double AbyssalWassersteinDistanceGrad(FixedEnvelope*
const* envelopes,
const double* scales,
double* ret_gradient,
size_t N,
double abyss_depth_exp,
double abyss_depth_the)
586 std::unique_ptr<size_t[]> env_idx = std::make_unique<size_t[]>(N+1);
587 memset(env_idx.get(), 0, (N+1)*
sizeof(
size_t));
588 memset(ret_gradient, 0, (N+1)*
sizeof(
double));
590 auto pq_cmp = [](std::pair<double, size_t>& p1, std::pair<double, size_t>& p2) {
return p1.first > p2.first; };
591 std::priority_queue<std::pair<double, size_t>, std::vector<std::pair<double, size_t>>,
decltype(pq_cmp)> PQ(pq_cmp);
593 for(
size_t ii=0; ii<=N; ii++)
595 envelopes[ii]->sort_by_mass();
596 if(envelopes[ii]->_confs_no > 0)
598 std::cout <<
"Initial push: " << envelopes[ii]->_masses[0] <<
" " << ii <<
'\n';
599 PQ.push({envelopes[ii]->_masses[0], ii});
603 std::vector<std::tuple<double, double, size_t>> carried;
605 auto next = [&]() -> std::tuple<double, double, size_t> {
606 auto [mass, eidx] = PQ.top();
607 double prob = envelopes[eidx]->_probs[env_idx[eidx]];
612 prob = prob * scales[eidx];
613 std::cout <<
"Next: " << mass <<
" " << prob <<
" " << eidx <<
'\n';
615 if(env_idx[eidx] < envelopes[eidx]->_confs_no)
616 PQ.push({envelopes[eidx]->_masses[env_idx[eidx]], eidx});
618 return {mass, prob, eidx};
621 double condemned = 0.0;
623 const double max_flow_dist = abyss_depth_exp + abyss_depth_the;
624 max_flow_dist *= 2.0;
628 auto [m, p, eidx] = next();
629 if(!carried.empty() && std::get<1>(carried[0]) * p > 0.0)
631 carried.emplace_back(m, p, eidx);
635 while(!carried.empty())
637 auto& [cm, cp, ceidx] = carried.back();
638 if(m - cm >= max_flow_dist)
640 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
641 condemned += fabs(std::get<1>(*it));
645 std::cout <<
"accing\n";
648 accd += fabs((m-cm)*cp);
651 std::cout <<
"cprob:" << cp <<
'\n';
655 accd += fabs((m-cm)*p);
657 std::cout <<
"prob:" << p <<
'\n';
663 carried.emplace_back(m, p, eidx);
667 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
668 condemned += fabs(std::get<1>(*it));
670 std::cout <<
"ISO:" << accd <<
" " << condemned <<
'\n';
671 return accd + condemned * max_flow_dist * 0.5;
674 auto [m, p, eidx] = next();
675 if(!carried.empty() && (std::get<1>(carried[0]) * p > 0.0))
677 carried.emplace_back(m, p, eidx);
681 while(!carried.empty())
683 auto& [cm, cp, ceidx] = carried.back();
684 if(m - cm >= max_flow_dist)
686 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
688 flow = fabs(std::get<1>(*it));
689 const size_t target_idx = std::get<2>(*it);
690 flow *= target_idx == 0 ? abyss_depth_exp : abyss_depth_the;
691 ret_gradient[target_idx] += flow;
693 std::cout <<
"condemnin': " << m <<
" " << p <<
" " << eidx <<
" | " << cm <<
" " << cp <<
" " << ceidx <<
'\n';
700 flow = fabs((m-cm)*cp);
703 ret_gradient[ceidx] += flow;
708 flow = fabs((m-cm)*p);
711 ret_gradient[eidx] += flow;
717 carried.emplace_back(m, p, eidx);
721 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
722 condemned += fabs(std::get<1>(*it));
725 return accd + condemned * (abyss_depth_exp + abyss_depth_the) * 0.5;
730std::tuple<double, double, double> FixedEnvelope::WassersteinMatch(FixedEnvelope& other,
double flow_distance,
double other_scale)
733 return {0.0, other.get_total_prob() * other_scale, 0.0};
735 double unmatched1 = 0.0;
736 double unmatched2 = 0.0;
737 double massflow = 0.0;
740 other.sort_by_mass();
743 size_t idx_other = 0;
744 double used_prob_this = 0.0;
745 double used_prob_other = 0.0;
747 while(idx_this < _confs_no && idx_other < other._confs_no)
750 while(moved && idx_this < _confs_no && idx_other < other._confs_no)
753 if(_masses[idx_this] < other._masses[idx_other] - flow_distance)
755 unmatched1 += _probs[idx_this] - used_prob_this;
756 used_prob_this = 0.0;
760 if(other._masses[idx_other] < _masses[idx_this] - flow_distance)
762 unmatched2 += other._probs[idx_other]*other_scale - used_prob_other;
763 used_prob_other = 0.0;
768 if(idx_this < _confs_no && idx_other < other._confs_no)
770 assert(_probs[idx_this] - used_prob_this >= 0.0);
771 assert(other._probs[idx_other]*other_scale - used_prob_other >= 0.0);
773 if(_probs[idx_this] - used_prob_this < other._probs[idx_other]*other_scale - used_prob_other)
775 massflow += _probs[idx_this] - used_prob_this;
776 used_prob_other += _probs[idx_this] - used_prob_this;
777 assert(used_prob_other >= 0.0);
778 used_prob_this = 0.0;
783 massflow += other._probs[idx_other]*other_scale - used_prob_other;
784 used_prob_this += other._probs[idx_other]*other_scale - used_prob_other;
785 assert(used_prob_this >= 0.0);
786 used_prob_other = 0.0;
792 unmatched1 -= used_prob_this;
793 unmatched2 -= used_prob_other;
795 for(; idx_this < _confs_no; idx_this++)
796 unmatched1 += _probs[idx_this];
797 for(; idx_other < other._confs_no; idx_other++)
798 unmatched2 += other._probs[idx_other]*other_scale;
800 return {unmatched1, unmatched2, massflow};
803FixedEnvelope FixedEnvelope::bin(
double bin_width,
double middle)
812 ret.reallocate_memory<
false>(ISOSPEC_INIT_TABLE_SIZE);
816 double curr_mass = _masses[0];
817 double accd_prob = _probs[0];
818 for(
size_t ii = 1; ii<_confs_no; ii++)
820 if(curr_mass != _masses[ii])
822 ret.store_conf(curr_mass, accd_prob);
823 curr_mass = _masses[ii];
824 accd_prob = _probs[ii];
827 accd_prob += _probs[ii];
829 ret.store_conf(curr_mass, accd_prob);
835 double half_width = 0.5*bin_width;
836 double hwmm = half_width-middle;
838 while(ii < _confs_no)
840 double current_bin_middle = floor((_masses[ii]+hwmm)/bin_width)*bin_width + middle;
841 double current_bin_end = current_bin_middle + half_width;
842 double bin_prob = 0.0;
844 while(ii < _confs_no && _masses[ii] <= current_bin_end)
846 bin_prob += _probs[ii];
849 ret.store_conf(current_bin_middle, bin_prob);
855template<
bool tgetConfs>
void FixedEnvelope::reallocate_memory(
size_t new_size)
857 current_size = new_size;
859 _masses =
reinterpret_cast<double*
>(realloc(_masses, new_size *
sizeof(
double)));
860 if(_masses ==
nullptr)
861 throw std::bad_alloc();
862 tmasses = _masses + _confs_no;
864 _probs =
reinterpret_cast<double*
>(realloc(_probs, new_size *
sizeof(
double)));
865 if(_probs ==
nullptr)
866 throw std::bad_alloc();
867 tprobs = _probs + _confs_no;
869 constexpr_if(tgetConfs)
871 _confs =
reinterpret_cast<int*
>(realloc(_confs, new_size * allDimSizeofInt));
872 if(_confs ==
nullptr)
873 throw std::bad_alloc();
874 tconfs = _confs + (allDim * _confs_no);
878void FixedEnvelope::slow_reallocate_memory(
size_t new_size)
880 current_size = new_size;
882 _masses =
reinterpret_cast<double*
>(realloc(_masses, new_size *
sizeof(
double)));
883 if(_masses ==
nullptr)
884 throw std::bad_alloc();
885 tmasses = _masses + _confs_no;
887 _probs =
reinterpret_cast<double*
>(realloc(_probs, new_size *
sizeof(
double)));
888 if(_probs ==
nullptr)
889 throw std::bad_alloc();
890 tprobs = _probs + _confs_no;
892 if(_confs !=
nullptr)
894 _confs =
reinterpret_cast<int*
>(realloc(_confs, new_size * allDimSizeofInt));
895 if(_confs ==
nullptr)
896 throw std::bad_alloc();
897 tconfs = _confs + (allDim * _confs_no);
901template<
bool tgetConfs>
void FixedEnvelope::threshold_init(Iso&& iso,
double threshold,
bool absolute)
903 IsoThresholdGenerator generator(std::move(iso), threshold, absolute);
905 size_t tab_size = generator.count_confs();
906 this->allDim = generator.getAllDim();
907 this->allDimSizeofInt = this->allDim *
sizeof(int);
909 this->reallocate_memory<tgetConfs>(tab_size);
911 double* ttmasses = this->_masses;
912 double* ttprobs = this->_probs;
913 ISOSPEC_MAYBE_UNUSED
int* ttconfs;
914 constexpr_if(tgetConfs)
917 while(generator.advanceToNextConfiguration())
919 *ttmasses = generator.mass(); ttmasses++;
920 *ttprobs = generator.prob(); ttprobs++;
921 constexpr_if(tgetConfs) { generator.get_conf_signature(ttconfs); ttconfs += allDim; }
924 this->_confs_no = tab_size;
927template void FixedEnvelope::threshold_init<true>(Iso&& iso,
double threshold,
bool absolute);
928template void FixedEnvelope::threshold_init<false>(Iso&& iso,
double threshold,
bool absolute);
931template<
bool tgetConfs>
void FixedEnvelope::total_prob_init(Iso&& iso,
double target_total_prob,
bool optimize)
933 if(target_total_prob <= 0.0)
936 if(target_total_prob >= 1.0)
938 threshold_init<tgetConfs>(std::move(iso), 0.0,
true);
942 IsoLayeredGenerator generator(std::move(iso), 1000, 1000,
true, std::min<double>(target_total_prob, 0.9999));
944 this->allDim = generator.getAllDim();
945 this->allDimSizeofInt = this->allDim*
sizeof(int);
948 this->reallocate_memory<tgetConfs>(ISOSPEC_INIT_TABLE_SIZE);
950 size_t last_switch = 0;
951 double prob_at_last_switch = 0.0;
952 double prob_so_far = 0.0;
955 const double sum_above = log1p(-target_total_prob) - 2.3025850929940455;
960 while(generator.advanceToNextConfigurationWithinLayer())
962 this->
template addConfILG<tgetConfs>(generator);
963 prob_so_far += *(tprobs-1);
964 if(prob_so_far >= target_total_prob)
968 while(generator.advanceToNextConfigurationWithinLayer())
969 this->
template addConfILG<tgetConfs>(generator);
976 if(prob_so_far >= target_total_prob)
979 last_switch = this->_confs_no;
980 prob_at_last_switch = prob_so_far;
982 layer_delta = sum_above - log1p(-prob_so_far);
983 layer_delta = (std::max)((std::min)(layer_delta, -0.1), -5.0);
984 }
while(generator.nextLayer(layer_delta));
986 if(!optimize || prob_so_far <= target_total_prob)
995 int* conf_swapspace =
nullptr;
996 constexpr_if(tgetConfs)
997 conf_swapspace =
reinterpret_cast<int*
>(malloc(this->allDimSizeofInt));
999 size_t start = last_switch;
1000 size_t end = this->_confs_no;
1001 double sum_to_start = prob_at_last_switch;
1006 size_t len = end - start;
1007#if ISOSPEC_BUILDING_R
1008 size_t pivot = len/2 + start;
1010 size_t pivot = random_gen() % len + start;
1014 double pprob = this->_probs[pivot];
1015 swap<tgetConfs>(pivot, end-1, conf_swapspace);
1017 double new_csum = sum_to_start;
1019 size_t loweridx = start;
1020 for(
size_t ii = start; ii < end-1; ii++)
1021 if(this->_probs[ii] > pprob)
1023 swap<tgetConfs>(ii, loweridx, conf_swapspace);
1024 new_csum += this->_probs[loweridx];
1028 swap<tgetConfs>(end-1, loweridx, conf_swapspace);
1031 if(new_csum < target_total_prob)
1033 start = loweridx + 1;
1034 sum_to_start = new_csum + this->_probs[loweridx];
1040 constexpr_if(tgetConfs)
1041 free(conf_swapspace);
1043 if(end <= current_size/2)
1045 this->
template reallocate_memory<tgetConfs>(end);
1047 this->_confs_no = end;
1050template void FixedEnvelope::total_prob_init<true>(Iso&& iso,
double target_total_prob,
bool optimize);
1051template void FixedEnvelope::total_prob_init<false>(Iso&& iso,
double target_total_prob,
bool optimize);
1053template<
bool tgetConfs>
void FixedEnvelope::stochastic_init(Iso&& iso,
size_t _no_molecules,
double _precision,
double _beta_bias)
1055 IsoStochasticGenerator generator(std::move(iso), _no_molecules, _precision, _beta_bias);
1057 this->allDim = generator.getAllDim();
1058 this->allDimSizeofInt = this->allDim *
sizeof(int);
1060 this->reallocate_memory<tgetConfs>(ISOSPEC_INIT_TABLE_SIZE);
1062 while(generator.advanceToNextConfiguration())
1063 addConfILG<tgetConfs, IsoStochasticGenerator>(generator);
1066template void FixedEnvelope::stochastic_init<true>(Iso&& iso,
size_t _no_molecules,
double _precision,
double _beta_bias);
1067template void FixedEnvelope::stochastic_init<false>(Iso&& iso,
size_t _no_molecules,
double _precision,
double _beta_bias);
1069double FixedEnvelope::empiric_average_mass()
1072 for(
size_t ii = 0; ii < _confs_no; ii++)
1074 ret += _masses[ii] * _probs[ii];
1076 return ret / get_total_prob();
1079double FixedEnvelope::empiric_variance()
1082 double avg = empiric_average_mass();
1083 for(
size_t ii = 0; ii < _confs_no; ii++)
1085 double msq = _masses[ii] - avg;
1086 ret += msq * msq * _probs[ii];
1089 return ret / get_total_prob();
1092FixedEnvelope FixedEnvelope::Binned(Iso&& iso,
double target_total_prob,
double bin_width,
double bin_middle)
1096 double min_mass = iso.getLightestPeakMass();
1097 double range_len = iso.getHeaviestPeakMass() - min_mass;
1098 size_t no_bins =
static_cast<size_t>(range_len / bin_width) + 2;
1099 double half_width = 0.5*bin_width;
1100 double hwmm = half_width-bin_middle;
1101 size_t idx_min = floor((min_mass + hwmm) / bin_width);
1102 size_t idx_max = idx_min + no_bins;
1105# if ISOSPEC_GOT_MMAN
1106 acc =
reinterpret_cast<double*
>(mmap(
nullptr,
sizeof(
double)*no_bins, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
1109 acc =
reinterpret_cast<double*
>(calloc(no_bins,
sizeof(
double)));
1112 throw std::bad_alloc();
1116 IsoLayeredGenerator ITG(std::move(iso));
1120 while((non_empty = ITG.advanceToNextConfiguration()) && ITG.prob() == 0.0)
1125 double accum_prob = ITG.prob();
1126 size_t nonzero_idx = floor((ITG.mass() + hwmm)/bin_width);
1127 acc[nonzero_idx] = accum_prob;
1129 while(ITG.advanceToNextConfiguration() && accum_prob < target_total_prob)
1131 double prob = ITG.prob();
1133 size_t bin_idx = floor((ITG.mass() + hwmm)/bin_width);
1134 acc[bin_idx] += prob;
1139 size_t distance_10da =
static_cast<size_t>(10.0/bin_width) + 1;
1141 size_t empty_steps = 0;
1143 ret.reallocate_memory<
false>(ISOSPEC_INIT_TABLE_SIZE);
1145 for(
size_t ii = nonzero_idx; ii >= idx_min && empty_steps < distance_10da; ii--)
1150 ret.store_conf(
static_cast<double>(ii)*bin_width + bin_middle, acc[ii]);
1157 for(
size_t ii = nonzero_idx+1; ii < idx_max && empty_steps < distance_10da; ii++)
1162 ret.store_conf(
static_cast<double>(ii)*bin_width + bin_middle, acc[ii]);
1171# if ISOSPEC_GOT_MMAN
1172 munmap(acc,
sizeof(
double)*no_bins);