17#include "fixedEnvelopes.h"
24FixedEnvelope::FixedEnvelope(
const FixedEnvelope& other) :
25_masses(array_copy<double>(other._masses, other._confs_no)),
26_probs(array_copy<double>(other._probs, other._confs_no)),
27_confs(array_copy_nptr<int>(other._confs, other._confs_no*other.allDim)),
28_confs_no(other._confs_no),
30sorted_by_mass(other.sorted_by_mass),
31sorted_by_prob(other.sorted_by_prob),
32total_prob(other.total_prob)
35FixedEnvelope::FixedEnvelope(FixedEnvelope&& other) :
36_masses(other._masses),
39_confs_no(other._confs_no),
41sorted_by_mass(other.sorted_by_mass),
42sorted_by_prob(other.sorted_by_prob),
43total_prob(other.total_prob)
45other._masses =
nullptr;
46other._probs =
nullptr;
47other._confs =
nullptr;
49other.total_prob = 0.0;
52FixedEnvelope::FixedEnvelope(
double* in_masses,
double* in_probs,
size_t in_confs_no,
bool masses_sorted,
bool probs_sorted,
double _total_prob) :
56_confs_no(in_confs_no),
58sorted_by_mass(masses_sorted),
59sorted_by_prob(probs_sorted),
60total_prob(_total_prob)
63FixedEnvelope FixedEnvelope::operator+(
const FixedEnvelope& other)
const
65 double* nprobs =
reinterpret_cast<double*
>(malloc(
sizeof(
double) * (_confs_no+other._confs_no)));
67 throw std::bad_alloc();
68 double* nmasses =
reinterpret_cast<double*
>(malloc(
sizeof(
double) * (_confs_no+other._confs_no)));
69 if(nmasses ==
nullptr)
72 throw std::bad_alloc();
75 memcpy(nprobs, _probs,
sizeof(
double) * _confs_no);
76 memcpy(nmasses, _masses,
sizeof(
double) * _confs_no);
78 memcpy(nprobs+_confs_no, other._probs,
sizeof(
double) * other._confs_no);
79 memcpy(nmasses+_confs_no, other._masses,
sizeof(
double) * other._confs_no);
81 return FixedEnvelope(nmasses, nprobs, _confs_no + other._confs_no);
84FixedEnvelope FixedEnvelope::operator*(
const FixedEnvelope& other)
const
86 double* nprobs =
reinterpret_cast<double*
>(malloc(
sizeof(
double) * _confs_no * other._confs_no));
88 throw std::bad_alloc();
91 double* nmasses =
reinterpret_cast<double*
>(malloc(
sizeof(
double) * _confs_no * other._confs_no));
92 if(nmasses ==
nullptr)
95 throw std::bad_alloc();
100 for(
size_t ii = 0; ii < _confs_no; ii++)
101 for(
size_t jj = 0; jj < other._confs_no; jj++)
103 nprobs[tgt_idx] = _probs[ii] * other._probs[jj];
104 nmasses[tgt_idx] = _masses[ii] + other._masses[jj];
108 return FixedEnvelope(nmasses, nprobs, tgt_idx);
111void FixedEnvelope::sort_by_mass()
118 sorted_by_mass =
true;
119 sorted_by_prob =
false;
123void FixedEnvelope::sort_by_prob()
130 sorted_by_prob =
true;
131 sorted_by_mass =
false;
134template<
typename T>
void reorder_array(T* arr,
size_t* order,
size_t size,
bool can_destroy =
false)
138 size_t* order_c =
new size_t[size];
139 memcpy(order_c, order,
sizeof(
size_t)*size);
143 for(
size_t ii = 0; ii < size; ii++)
144 while(order[ii] != ii)
146 std::swap(arr[ii], arr[order[ii]]);
147 std::swap(order[order[ii]], order[ii]);
154void FixedEnvelope::sort_by(
double* order)
159 size_t* indices =
new size_t[_confs_no];
161 for(
size_t ii = 0; ii < _confs_no; ii++)
164 std::sort<size_t*>(indices, indices + _confs_no, TableOrder<double>(order));
166 size_t* inverse =
new size_t[_confs_no];
168 for(
size_t ii = 0; ii < _confs_no; ii++)
169 inverse[indices[ii]] = ii;
173 reorder_array(_masses, inverse, _confs_no);
174 reorder_array(_probs, inverse, _confs_no, _confs ==
nullptr);
175 if(_confs !=
nullptr)
177 int* swapspace =
new int[allDim];
178 for(
size_t ii = 0; ii < _confs_no; ii++)
179 while(inverse[ii] != ii)
181 memcpy(swapspace, &_confs[ii*allDim], allDimSizeofInt);
182 memcpy(&_confs[ii*allDim], &_confs[inverse[ii]*allDim], allDimSizeofInt);
183 memcpy(&_confs[inverse[ii]*allDim], swapspace, allDimSizeofInt);
184 std::swap(inverse[inverse[ii]], inverse[ii]);
192double FixedEnvelope::get_total_prob()
194 if(std::isnan(total_prob))
197 for(
size_t ii = 0; ii < _confs_no; ii++)
198 total_prob += _probs[ii];
203void FixedEnvelope::scale(
double factor)
205 for(
size_t ii = 0; ii < _confs_no; ii++)
206 _probs[ii] *= factor;
207 total_prob *= factor;
210void FixedEnvelope::normalize()
212 double tp = get_total_prob();
220void FixedEnvelope::shift_mass(
double value)
222 for(
size_t ii = 0; ii < _confs_no; ii++)
223 _masses[ii] += value;
226void FixedEnvelope::resample(
size_t samples,
double beta_bias)
229 throw std::logic_error(
"Resample called on an empty spectrum");
235 _probs[_confs_no-1] = (std::numeric_limits<double>::max)();
239 pprob += _probs[++pidx];
241 double covered_part = (pprob - cprob) / (1.0 - cprob);
242 while(samples * covered_part < beta_bias && samples > 0)
244 cprob += rdvariate_beta_1_b(samples) * (1.0 - cprob);
247 pprob += _probs[++pidx];
252 covered_part = (pprob - cprob) / (1.0 - cprob);
256 size_t nrtaken = rdvariate_binom(samples, covered_part);
257 _probs[pidx] +=
static_cast<double>(nrtaken);
263 memset(_probs + pidx, 0,
sizeof(
double)*(_confs_no - pidx));
266FixedEnvelope FixedEnvelope::LinearCombination(
const std::vector<const FixedEnvelope*>& spectra,
const std::vector<double>& intensities)
268 return LinearCombination(spectra.data(), intensities.data(), spectra.size());
271FixedEnvelope FixedEnvelope::LinearCombination(
const FixedEnvelope*
const * spectra,
const double* intensities,
size_t size)
274 for(
size_t ii = 0; ii < size; ii++)
275 ret_size += spectra[ii]->_confs_no;
277 double* newprobs =
reinterpret_cast<double*
>(malloc(
sizeof(
double)*ret_size));
278 if(newprobs ==
nullptr)
279 throw std::bad_alloc();
280 double* newmasses =
reinterpret_cast<double*
>(malloc(
sizeof(
double)*ret_size));
281 if(newmasses ==
nullptr)
284 throw std::bad_alloc();
288 for(
size_t ii = 0; ii < size; ii++)
290 double mul = intensities[ii];
291 for(
size_t jj = 0; jj < spectra[ii]->_confs_no; jj++)
292 newprobs[jj+cntr] = spectra[ii]->_probs[jj] * mul;
293 memcpy(newmasses + cntr, spectra[ii]->_masses,
sizeof(
double) * spectra[ii]->_confs_no);
294 cntr += spectra[ii]->_confs_no;
296 return FixedEnvelope(newmasses, newprobs, cntr);
299double FixedEnvelope::WassersteinDistance(FixedEnvelope& other)
302 if((get_total_prob()*0.999 > other.get_total_prob()) || (other.get_total_prob() > get_total_prob()*1.001))
303 throw std::logic_error(
"Spectra must be normalized before computing Wasserstein Distance");
305 if(_confs_no == 0 || other._confs_no == 0)
309 other.sort_by_mass();
312 size_t idx_other = 0;
314 double acc_prob = 0.0;
315 double last_point = 0.0;
318 while(idx_this < _confs_no && idx_other < other._confs_no)
320 if(_masses[idx_this] < other._masses[idx_other])
322 ret += (_masses[idx_this] - last_point) * std::abs(acc_prob);
323 acc_prob += _probs[idx_this];
324 last_point = _masses[idx_this];
329 ret += (other._masses[idx_other] - last_point) * std::abs(acc_prob);
330 acc_prob -= other._probs[idx_other];
331 last_point = other._masses[idx_other];
336 acc_prob = std::abs(acc_prob);
338 while(idx_this < _confs_no)
340 ret += (_masses[idx_this] - last_point) * acc_prob;
341 acc_prob -= _probs[idx_this];
342 last_point = _masses[idx_this];
346 while(idx_other < other._confs_no)
348 ret += (other._masses[idx_other] - last_point) * acc_prob;
349 acc_prob -= other._probs[idx_other];
350 last_point = other._masses[idx_other];
358double FixedEnvelope::OrientedWassersteinDistance(FixedEnvelope& other)
361 if((get_total_prob()*0.999 > other.get_total_prob()) || (other.get_total_prob() > get_total_prob()*1.001))
362 throw std::logic_error(
"Spectra must be normalized before computing Wasserstein Distance");
364 if(_confs_no == 0 || other._confs_no == 0)
368 other.sort_by_mass();
371 size_t idx_other = 0;
373 double acc_prob = 0.0;
374 double last_point = 0.0;
377 while(idx_this < _confs_no && idx_other < other._confs_no)
379 if(_masses[idx_this] < other._masses[idx_other])
381 ret += (_masses[idx_this] - last_point) * acc_prob;
382 acc_prob += _probs[idx_this];
383 last_point = _masses[idx_this];
388 ret += (other._masses[idx_other] - last_point) * acc_prob;
389 acc_prob -= other._probs[idx_other];
390 last_point = other._masses[idx_other];
395 while(idx_this < _confs_no)
397 ret += (_masses[idx_this] - last_point) * acc_prob;
398 acc_prob -= _probs[idx_this];
399 last_point = _masses[idx_this];
403 while(idx_other < other._confs_no)
405 ret += (other._masses[idx_other] - last_point) * acc_prob;
406 acc_prob -= other._probs[idx_other];
407 last_point = other._masses[idx_other];
414double FixedEnvelope::AbyssalWassersteinDistance(FixedEnvelope& other,
double abyss_depth,
double other_scale)
417 other.sort_by_mass();
419 std::vector<std::pair<double, double>> carried;
422 size_t idx_other = 0;
426 auto finished = [&]() ->
bool {
return idx_this >= _confs_no && idx_other >= other._confs_no; };
427 auto next = [&]() -> std::pair<double, double> {
428 if(idx_this >= _confs_no || (idx_other < other._confs_no && _masses[idx_this] > other._masses[idx_other]))
430 std::pair<double, double> res = std::pair<double, double>(other._masses[idx_other], other._probs[idx_other]*other_scale);
436 std::pair<double, double> res = std::pair<double, double>(_masses[idx_this], -_probs[idx_this]);
442 double condemned = 0.0;
447 double m = pair.first;
448 double p = pair.second;
449 if(!carried.empty() && carried[0].second * p > 0.0)
451 carried.emplace_back(m, p);
455 while(!carried.empty())
457 double cm = carried.back().first;
458 double cp = carried.back().second;
459 if(m - cm >= abyss_depth)
461 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
462 condemned += fabs(it->second);
468 accd += fabs((m-cm)*cp);
474 accd += fabs((m-cm)*p);
481 carried.emplace_back(m, p);
485 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
486 condemned += fabs(it->second);
488 return accd + condemned * abyss_depth * 0.5;
492double FixedEnvelope::ScaledAbyssalWassersteinDistance(FixedEnvelope *
const * others,
double abyss_depth,
const double* other_scales,
const size_t N)
496 std::priority_queue<std::pair<double, size_t>> PQ;
497 std::unique_ptr<size_t[]> indices = std::make_unique<size_t[]>(N);
498 memset(indices.get(), 0,
sizeof(
size_t)*N);
500 for(
size_t ii=0; ii<N; ii++)
502 others[ii]->sort_by_mass();
503 if(others[ii]->_confs_no > 0)
504 PQ.emplace_back({others._probs[0], ii});
510 std::vector<std::pair<double, double>> carried;
513 size_t idx_other = 0;
517 auto finished = [&]() ->
bool {
return idx_this >= _confs_no && PQ.empty(); };
518 auto next = [&]() -> std::tuple<double, double, size_t> {
519 if(idx_this >= _confs_no || (idx_other < other._confs_no && _masses[idx_this] > other._masses[idx_other]))
521 std::pair<double, double> res = std::pair<double, double>(other._masses[idx_other], other._probs[idx_other]*other_scale);
527 std::pair<double, double> res = std::pair<double, double>(_masses[idx_this], -_probs[idx_this]);
533 double condemned = 0.0;
537 auto [m, p] = next();
538 if(!carried.empty() && carried[0].second * p > 0.0)
540 carried.emplace_back(m, p);
544 while(!carried.empty())
546 auto& [cm, cp] = carried.back();
547 if(m - cm >= abyss_depth)
549 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
550 condemned += fabs(it->second);
556 accd += fabs((m-cm)*cp);
562 accd += fabs((m-cm)*p);
569 carried.emplace_back(m, p);
573 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
574 condemned += fabs(it->second);
576 return accd + condemned * abyss_depth * 0.5;
582double AbyssalWassersteinDistanceGrad(FixedEnvelope*
const* envelopes,
const double* scales,
double* ret_gradient,
size_t N,
double abyss_depth_exp,
double abyss_depth_the)
585 std::unique_ptr<size_t[]> env_idx = std::make_unique<size_t[]>(N+1);
586 memset(env_idx.get(), 0, (N+1)*
sizeof(
size_t));
587 memset(ret_gradient, 0, (N+1)*
sizeof(
double));
589 auto pq_cmp = [](std::pair<double, size_t>& p1, std::pair<double, size_t>& p2) {
return p1.first > p2.first; };
590 std::priority_queue<std::pair<double, size_t>, std::vector<std::pair<double, size_t>>,
decltype(pq_cmp)> PQ(pq_cmp);
592 for(
size_t ii=0; ii<=N; ii++)
594 envelopes[ii]->sort_by_mass();
595 if(envelopes[ii]->_confs_no > 0)
597 std::cout <<
"Initial push: " << envelopes[ii]->_masses[0] <<
" " << ii <<
'\n';
598 PQ.push({envelopes[ii]->_masses[0], ii});
602 std::vector<std::tuple<double, double, size_t>> carried;
604 auto next = [&]() -> std::tuple<double, double, size_t> {
605 auto [mass, eidx] = PQ.top();
606 double prob = envelopes[eidx]->_probs[env_idx[eidx]];
611 prob = prob * scales[eidx];
612 std::cout <<
"Next: " << mass <<
" " << prob <<
" " << eidx <<
'\n';
614 if(env_idx[eidx] < envelopes[eidx]->_confs_no)
615 PQ.push({envelopes[eidx]->_masses[env_idx[eidx]], eidx});
617 return {mass, prob, eidx};
620 double condemned = 0.0;
622 const double max_flow_dist = abyss_depth_exp + abyss_depth_the;
623 max_flow_dist *= 2.0;
627 auto [m, p, eidx] = next();
628 if(!carried.empty() && std::get<1>(carried[0]) * p > 0.0)
630 carried.emplace_back(m, p, eidx);
634 while(!carried.empty())
636 auto& [cm, cp, ceidx] = carried.back();
637 if(m - cm >= max_flow_dist)
639 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
640 condemned += fabs(std::get<1>(*it));
644 std::cout <<
"accing\n";
647 accd += fabs((m-cm)*cp);
650 std::cout <<
"cprob:" << cp <<
'\n';
654 accd += fabs((m-cm)*p);
656 std::cout <<
"prob:" << p <<
'\n';
662 carried.emplace_back(m, p, eidx);
666 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
667 condemned += fabs(std::get<1>(*it));
669 std::cout <<
"ISO:" << accd <<
" " << condemned <<
'\n';
670 return accd + condemned * max_flow_dist * 0.5;
673 auto [m, p, eidx] = next();
674 if(!carried.empty() && (std::get<1>(carried[0]) * p > 0.0))
676 carried.emplace_back(m, p, eidx);
680 while(!carried.empty())
682 auto& [cm, cp, ceidx] = carried.back();
683 if(m - cm >= max_flow_dist)
685 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
687 flow = fabs(std::get<1>(*it));
688 const size_t target_idx = std::get<2>(*it);
689 flow *= target_idx == 0 ? abyss_depth_exp : abyss_depth_the;
690 ret_gradient[target_idx] += flow;
692 std::cout <<
"condemnin': " << m <<
" " << p <<
" " << eidx <<
" | " << cm <<
" " << cp <<
" " << ceidx <<
'\n';
699 flow = fabs((m-cm)*cp);
702 ret_gradient[ceidx] += flow;
707 flow = fabs((m-cm)*p);
710 ret_gradient[eidx] += flow;
716 carried.emplace_back(m, p, eidx);
720 for(
auto it = carried.cbegin(); it != carried.cend(); it++)
721 condemned += fabs(std::get<1>(*it));
724 return accd + condemned * (abyss_depth_exp + abyss_depth_the) * 0.5;
729std::tuple<double, double, double> FixedEnvelope::WassersteinMatch(FixedEnvelope& other,
double flow_distance,
double other_scale)
732 return {0.0, other.get_total_prob() * other_scale, 0.0};
734 double unmatched1 = 0.0;
735 double unmatched2 = 0.0;
736 double massflow = 0.0;
739 other.sort_by_mass();
742 size_t idx_other = 0;
743 double used_prob_this = 0.0;
744 double used_prob_other = 0.0;
746 while(idx_this < _confs_no && idx_other < other._confs_no)
749 while(moved && idx_this < _confs_no && idx_other < other._confs_no)
752 if(_masses[idx_this] < other._masses[idx_other] - flow_distance)
754 unmatched1 += _probs[idx_this] - used_prob_this;
755 used_prob_this = 0.0;
759 if(other._masses[idx_other] < _masses[idx_this] - flow_distance)
761 unmatched2 += other._probs[idx_other]*other_scale - used_prob_other;
762 used_prob_other = 0.0;
767 if(idx_this < _confs_no && idx_other < other._confs_no)
769 assert(_probs[idx_this] - used_prob_this >= 0.0);
770 assert(other._probs[idx_other]*other_scale - used_prob_other >= 0.0);
772 if(_probs[idx_this] - used_prob_this < other._probs[idx_other]*other_scale - used_prob_other)
774 massflow += _probs[idx_this] - used_prob_this;
775 used_prob_other += _probs[idx_this] - used_prob_this;
776 assert(used_prob_other >= 0.0);
777 used_prob_this = 0.0;
782 massflow += other._probs[idx_other]*other_scale - used_prob_other;
783 used_prob_this += other._probs[idx_other]*other_scale - used_prob_other;
784 assert(used_prob_this >= 0.0);
785 used_prob_other = 0.0;
791 unmatched1 -= used_prob_this;
792 unmatched2 -= used_prob_other;
794 for(; idx_this < _confs_no; idx_this++)
795 unmatched1 += _probs[idx_this];
796 for(; idx_other < other._confs_no; idx_other++)
797 unmatched2 += other._probs[idx_other]*other_scale;
799 return {unmatched1, unmatched2, massflow};
802FixedEnvelope FixedEnvelope::bin(
double bin_width,
double middle)
811 ret.reallocate_memory<
false>(ISOSPEC_INIT_TABLE_SIZE);
815 double curr_mass = _masses[0];
816 double accd_prob = _probs[0];
817 for(
size_t ii = 1; ii<_confs_no; ii++)
819 if(curr_mass != _masses[ii])
821 ret.store_conf(curr_mass, accd_prob);
822 curr_mass = _masses[ii];
823 accd_prob = _probs[ii];
826 accd_prob += _probs[ii];
828 ret.store_conf(curr_mass, accd_prob);
834 double half_width = 0.5*bin_width;
835 double hwmm = half_width-middle;
837 while(ii < _confs_no)
839 double current_bin_middle = floor((_masses[ii]+hwmm)/bin_width)*bin_width + middle;
840 double current_bin_end = current_bin_middle + half_width;
841 double bin_prob = 0.0;
843 while(ii < _confs_no && _masses[ii] <= current_bin_end)
845 bin_prob += _probs[ii];
848 ret.store_conf(current_bin_middle, bin_prob);
854template<
bool tgetConfs>
void FixedEnvelope::reallocate_memory(
size_t new_size)
856 current_size = new_size;
858 _masses =
reinterpret_cast<double*
>(realloc(_masses, new_size *
sizeof(
double)));
859 if(_masses ==
nullptr)
860 throw std::bad_alloc();
861 tmasses = _masses + _confs_no;
863 _probs =
reinterpret_cast<double*
>(realloc(_probs, new_size *
sizeof(
double)));
864 if(_probs ==
nullptr)
865 throw std::bad_alloc();
866 tprobs = _probs + _confs_no;
868 constexpr_if(tgetConfs)
870 _confs =
reinterpret_cast<int*
>(realloc(_confs, new_size * allDimSizeofInt));
871 if(_confs ==
nullptr)
872 throw std::bad_alloc();
873 tconfs = _confs + (allDim * _confs_no);
877void FixedEnvelope::slow_reallocate_memory(
size_t new_size)
879 current_size = new_size;
881 _masses =
reinterpret_cast<double*
>(realloc(_masses, new_size *
sizeof(
double)));
882 if(_masses ==
nullptr)
883 throw std::bad_alloc();
884 tmasses = _masses + _confs_no;
886 _probs =
reinterpret_cast<double*
>(realloc(_probs, new_size *
sizeof(
double)));
887 if(_probs ==
nullptr)
888 throw std::bad_alloc();
889 tprobs = _probs + _confs_no;
891 if(_confs !=
nullptr)
893 _confs =
reinterpret_cast<int*
>(realloc(_confs, new_size * allDimSizeofInt));
894 if(_confs ==
nullptr)
895 throw std::bad_alloc();
896 tconfs = _confs + (allDim * _confs_no);
900template<
bool tgetConfs>
void FixedEnvelope::threshold_init(Iso&& iso,
double threshold,
bool absolute)
902 IsoThresholdGenerator generator(std::move(iso), threshold, absolute);
904 size_t tab_size = generator.count_confs();
905 this->allDim = generator.getAllDim();
906 this->allDimSizeofInt = this->allDim *
sizeof(int);
908 this->reallocate_memory<tgetConfs>(tab_size);
910 double* ttmasses = this->_masses;
911 double* ttprobs = this->_probs;
912 ISOSPEC_MAYBE_UNUSED
int* ttconfs;
913 constexpr_if(tgetConfs)
916 while(generator.advanceToNextConfiguration())
918 *ttmasses = generator.mass(); ttmasses++;
919 *ttprobs = generator.prob(); ttprobs++;
920 constexpr_if(tgetConfs) { generator.get_conf_signature(ttconfs); ttconfs += allDim; }
923 this->_confs_no = tab_size;
926template void FixedEnvelope::threshold_init<true>(Iso&& iso,
double threshold,
bool absolute);
927template void FixedEnvelope::threshold_init<false>(Iso&& iso,
double threshold,
bool absolute);
930template<
bool tgetConfs>
void FixedEnvelope::total_prob_init(Iso&& iso,
double target_total_prob,
bool optimize)
932 if(target_total_prob <= 0.0)
935 if(target_total_prob >= 1.0)
937 threshold_init<tgetConfs>(std::move(iso), 0.0,
true);
941 IsoLayeredGenerator generator(std::move(iso), 1000, 1000,
true, std::min<double>(target_total_prob, 0.9999));
943 this->allDim = generator.getAllDim();
944 this->allDimSizeofInt = this->allDim*
sizeof(int);
947 this->reallocate_memory<tgetConfs>(ISOSPEC_INIT_TABLE_SIZE);
949 size_t last_switch = 0;
950 double prob_at_last_switch = 0.0;
951 double prob_so_far = 0.0;
954 const double sum_above = log1p(-target_total_prob) - 2.3025850929940455;
959 while(generator.advanceToNextConfigurationWithinLayer())
961 this->
template addConfILG<tgetConfs>(generator);
962 prob_so_far += *(tprobs-1);
963 if(prob_so_far >= target_total_prob)
967 while(generator.advanceToNextConfigurationWithinLayer())
968 this->
template addConfILG<tgetConfs>(generator);
975 if(prob_so_far >= target_total_prob)
978 last_switch = this->_confs_no;
979 prob_at_last_switch = prob_so_far;
981 layer_delta = sum_above - log1p(-prob_so_far);
982 layer_delta = (std::max)((std::min)(layer_delta, -0.1), -5.0);
983 }
while(generator.nextLayer(layer_delta));
985 if(!optimize || prob_so_far <= target_total_prob)
994 int* conf_swapspace =
nullptr;
995 constexpr_if(tgetConfs)
996 conf_swapspace =
reinterpret_cast<int*
>(malloc(this->allDimSizeofInt));
998 size_t start = last_switch;
999 size_t end = this->_confs_no;
1000 double sum_to_start = prob_at_last_switch;
1005 size_t len = end - start;
1006#if ISOSPEC_BUILDING_R
1007 size_t pivot = len/2 + start;
1009 size_t pivot = random_gen() % len + start;
1013 double pprob = this->_probs[pivot];
1014 swap<tgetConfs>(pivot, end-1, conf_swapspace);
1016 double new_csum = sum_to_start;
1018 size_t loweridx = start;
1019 for(
size_t ii = start; ii < end-1; ii++)
1020 if(this->_probs[ii] > pprob)
1022 swap<tgetConfs>(ii, loweridx, conf_swapspace);
1023 new_csum += this->_probs[loweridx];
1027 swap<tgetConfs>(end-1, loweridx, conf_swapspace);
1030 if(new_csum < target_total_prob)
1032 start = loweridx + 1;
1033 sum_to_start = new_csum + this->_probs[loweridx];
1039 constexpr_if(tgetConfs)
1040 free(conf_swapspace);
1042 if(end <= current_size/2)
1044 this->
template reallocate_memory<tgetConfs>(end);
1046 this->_confs_no = end;
1049template void FixedEnvelope::total_prob_init<true>(Iso&& iso,
double target_total_prob,
bool optimize);
1050template void FixedEnvelope::total_prob_init<false>(Iso&& iso,
double target_total_prob,
bool optimize);
1052template<
bool tgetConfs>
void FixedEnvelope::stochastic_init(Iso&& iso,
size_t _no_molecules,
double _precision,
double _beta_bias)
1054 IsoStochasticGenerator generator(std::move(iso), _no_molecules, _precision, _beta_bias);
1056 this->allDim = generator.getAllDim();
1057 this->allDimSizeofInt = this->allDim *
sizeof(int);
1059 this->reallocate_memory<tgetConfs>(ISOSPEC_INIT_TABLE_SIZE);
1061 while(generator.advanceToNextConfiguration())
1062 addConfILG<tgetConfs, IsoStochasticGenerator>(generator);
1065template void FixedEnvelope::stochastic_init<true>(Iso&& iso,
size_t _no_molecules,
double _precision,
double _beta_bias);
1066template void FixedEnvelope::stochastic_init<false>(Iso&& iso,
size_t _no_molecules,
double _precision,
double _beta_bias);
1068double FixedEnvelope::empiric_average_mass()
1071 for(
size_t ii = 0; ii < _confs_no; ii++)
1073 ret += _masses[ii] * _probs[ii];
1075 return ret / get_total_prob();
1078double FixedEnvelope::empiric_variance()
1081 double avg = empiric_average_mass();
1082 for(
size_t ii = 0; ii < _confs_no; ii++)
1084 double msq = _masses[ii] - avg;
1085 ret += msq * msq * _probs[ii];
1088 return ret / get_total_prob();
1091FixedEnvelope FixedEnvelope::Binned(Iso&& iso,
double target_total_prob,
double bin_width,
double bin_middle)
1095 double min_mass = iso.getLightestPeakMass();
1096 double range_len = iso.getHeaviestPeakMass() - min_mass;
1097 size_t no_bins =
static_cast<size_t>(range_len / bin_width) + 2;
1098 double half_width = 0.5*bin_width;
1099 double hwmm = half_width-bin_middle;
1100 size_t idx_min = floor((min_mass + hwmm) / bin_width);
1101 size_t idx_max = idx_min + no_bins;
1104# if ISOSPEC_GOT_MMAN
1105 acc =
reinterpret_cast<double*
>(mmap(
nullptr,
sizeof(
double)*no_bins, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
1108 acc =
reinterpret_cast<double*
>(calloc(no_bins,
sizeof(
double)));
1111 throw std::bad_alloc();
1115 IsoLayeredGenerator ITG(std::move(iso));
1119 while((non_empty = ITG.advanceToNextConfiguration()) && ITG.prob() == 0.0)
1124 double accum_prob = ITG.prob();
1125 size_t nonzero_idx = floor((ITG.mass() + hwmm)/bin_width);
1126 acc[nonzero_idx] = accum_prob;
1128 while(ITG.advanceToNextConfiguration() && accum_prob < target_total_prob)
1130 double prob = ITG.prob();
1132 size_t bin_idx = floor((ITG.mass() + hwmm)/bin_width);
1133 acc[bin_idx] += prob;
1138 size_t distance_10da =
static_cast<size_t>(10.0/bin_width) + 1;
1140 size_t empty_steps = 0;
1142 ret.reallocate_memory<
false>(ISOSPEC_INIT_TABLE_SIZE);
1144 for(
size_t ii = nonzero_idx; ii >= idx_min && empty_steps < distance_10da; ii--)
1149 ret.store_conf(
static_cast<double>(ii)*bin_width + bin_middle, acc[ii]);
1156 for(
size_t ii = nonzero_idx+1; ii < idx_max && empty_steps < distance_10da; ii++)
1161 ret.store_conf(
static_cast<double>(ii)*bin_width + bin_middle, acc[ii]);
1170# if ISOSPEC_GOT_MMAN
1171 munmap(acc,
sizeof(
double)*no_bins);