00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #ifndef OPENMS_CHEMISTRY_MASSDECOMPOSITION_IMS_INTEGERMASSDECOMPOSER_H
00037 #define OPENMS_CHEMISTRY_MASSDECOMPOSITION_IMS_INTEGERMASSDECOMPOSER_H
00038
00039 #include <vector>
00040 #include <utility>
00041
00042 #include <OpenMS/CHEMISTRY/MASSDECOMPOSITION/IMS/Weights.h>
00043 #include <OpenMS/CHEMISTRY/MASSDECOMPOSITION/IMS/MassDecomposer.h>
00044
00045 #include <OpenMS/MATH/MISC/MathFunctions.h>
00046
00047 namespace OpenMS
00048 {
00049
00050 namespace ims
00051 {
00052
00069 template <typename ValueType = long unsigned int,
00070 typename DecompositionValueType = unsigned int>
00071 class IntegerMassDecomposer :
00072 public MassDecomposer<ValueType, DecompositionValueType>
00073 {
00074 public:
00076 typedef typename MassDecomposer<ValueType, DecompositionValueType>::value_type value_type;
00077
00079 typedef typename MassDecomposer<ValueType, DecompositionValueType>::decomposition_value_type decomposition_value_type;
00080
00082 typedef typename MassDecomposer<ValueType, DecompositionValueType>::decomposition_type decomposition_type;
00083
00085 typedef typename MassDecomposer<ValueType, DecompositionValueType>::decompositions_type decompositions_type;
00086
00088 typedef typename decomposition_type::size_type size_type;
00089
00095 explicit IntegerMassDecomposer(const Weights & alphabet);
00096
00103 virtual bool exist(value_type mass);
00104
00111 virtual decomposition_type getDecomposition(value_type mass);
00112
00119 virtual decompositions_type getAllDecompositions(value_type mass);
00120
00129 virtual decomposition_value_type getNumberOfDecompositions(value_type mass);
00130
00131 private:
00132
00136 typedef std::vector<std::pair<size_type, decomposition_value_type> > witness_vector_type;
00137
00141 typedef std::vector<value_type> residues_table_row_type;
00142
00146 typedef std::vector<residues_table_row_type> residues_table_type;
00147
00151 Weights alphabet_;
00152
00158 residues_table_type ertable_;
00159
00164 residues_table_row_type lcms_;
00165
00171 residues_table_row_type mass_in_lcms_;
00172
00176 value_type infty_;
00177
00182 witness_vector_type witness_vector_;
00183
00187 void fillExtendedResidueTable_(const Weights & _alphabet, residues_table_row_type & _lcms,
00188 residues_table_row_type & _mass_in_lcms, const value_type _infty,
00189 witness_vector_type & _witness_vector, residues_table_type & _ertable);
00190
00199 void collectDecompositionsRecursively_(value_type mass, size_type alphabetMassIndex,
00200 decomposition_type decomposition, decompositions_type & decompositionsStore);
00201 };
00202
00203
00204 template <typename ValueType, typename DecompositionValueType>
00205 IntegerMassDecomposer<ValueType, DecompositionValueType>::IntegerMassDecomposer(
00206 const Weights & alphabet) :
00207 alphabet_(alphabet)
00208 {
00209
00210 lcms_.resize(alphabet.size());
00211 mass_in_lcms_.resize(alphabet.size());
00212
00213 infty_ = alphabet.getWeight(0) * alphabet.getWeight(alphabet.size() - 1);
00214
00215 fillExtendedResidueTable_(alphabet, lcms_, mass_in_lcms_, infty_, witness_vector_, ertable_);
00216
00217 }
00218
00219 template <typename ValueType, typename DecompositionValueType>
00220 void IntegerMassDecomposer<ValueType, DecompositionValueType>::fillExtendedResidueTable_(
00221 const Weights & _alphabet, residues_table_row_type & _lcms, residues_table_row_type & _mass_in_lcms,
00222 const value_type _infty, witness_vector_type & _witnessVector, residues_table_type & _ertable)
00223 {
00224
00225 if (_alphabet.size() < 2)
00226 {
00227 return;
00228 }
00229
00230 value_type smallestMass = _alphabet.getWeight(0), secondMass = _alphabet.getWeight(1);
00231
00232
00233 _ertable.reserve(_alphabet.size());
00234 _ertable.assign(_alphabet.size(), std::vector<value_type>(smallestMass, _infty));
00235
00236 for (size_type i = 0; i < _alphabet.size(); ++i)
00237 {
00238 _ertable[i][0] = 0;
00239 }
00240
00241
00242 _witnessVector.resize(smallestMass);
00243
00244
00245 size_type it_inc = secondMass % smallestMass, witness = 1;
00246
00247 value_type mass = secondMass;
00248
00249 decomposition_value_type counter = 0;
00250 size_type it_i = it_inc;
00251 while (it_i != 0)
00252 {
00253 _ertable[1][it_i] = mass;
00254 mass += secondMass;
00255 ++counter;
00256 _witnessVector[it_i] = std::make_pair(witness, counter);
00257
00258 it_i += it_inc;
00259 if (it_i >= _ertable[1].size())
00260 {
00261 it_i -= _ertable[1].size();
00262 }
00263 }
00264
00265 value_type d = Math::gcd(smallestMass, secondMass);
00266 _lcms[1] = secondMass * smallestMass / d;
00267 _mass_in_lcms[1] = smallestMass / d;
00268
00269
00270 for (size_type i = 2; i < _alphabet.size(); ++i)
00271 {
00272
00273 value_type currentMass = _alphabet.getWeight(i);
00274
00275 value_type d = Math::gcd(smallestMass, currentMass);
00276
00277
00278
00279 _lcms[i] = currentMass * smallestMass / d;
00280 _mass_in_lcms[i] = smallestMass / d;
00281
00282
00283 if (currentMass >= _ertable[i - 1][currentMass % smallestMass])
00284 {
00285 _ertable[i] = _ertable[i - 1];
00286 continue;
00287 }
00288
00289 const residues_table_row_type & prev_column = _ertable[i - 1];
00290 residues_table_row_type & cur_column = _ertable[i];
00291
00292 if (d == 1)
00293 {
00294
00295
00296
00297
00298 size_type p_inc = currentMass % smallestMass;
00299
00300
00301 value_type n = 0;
00302
00303 size_type p = 0;
00304
00305 decomposition_value_type counter = 0;
00306
00307 for (size_type m = smallestMass; m > 0; --m)
00308 {
00309 n += currentMass;
00310 p += p_inc;
00311 ++counter;
00312 if (p >= smallestMass)
00313 {
00314 p -= smallestMass;
00315 }
00316 if (n > prev_column[p])
00317 {
00318 n = prev_column[p];
00319 counter = 0;
00320 }
00321 else
00322 {
00323 _witnessVector[p] = std::make_pair(i, counter);
00324 }
00325 cur_column[p] = n;
00326 }
00327 }
00328 else
00329 {
00330
00331
00332
00333
00334
00335 size_type cur = currentMass % smallestMass;
00336 size_type prev = 0;
00337 size_type p_inc = cur - d;
00338
00339 std::vector<decomposition_value_type> counters(smallestMass);
00340
00341
00342 for (size_type j = 1; j < d; ++j)
00343 {
00344 cur_column[j] = prev_column[j];
00345 }
00346
00347
00348 for (size_type m = smallestMass / d; m > 1; m--)
00349 {
00350
00351 for (size_type r = 0; r < d; r++)
00352 {
00353
00354 ++counters[cur];
00355 if (cur_column[prev] + currentMass > prev_column[cur])
00356 {
00357 cur_column[cur] = prev_column[cur];
00358 counters[cur] = 0;
00359 }
00360 else
00361 {
00362 cur_column[cur] = cur_column[prev] + currentMass;
00363 _witnessVector[cur] = std::make_pair(i, counters[cur]);
00364 }
00365
00366 prev++;
00367 cur++;
00368 }
00369
00370 prev = cur - d;
00371
00372
00373 cur += p_inc;
00374 if (cur >= smallestMass)
00375 {
00376 cur -= smallestMass;
00377 }
00378 }
00379
00380
00381 bool cont = true;
00382 while (cont)
00383 {
00384 cont = false;
00385 prev++;
00386 cur++;
00387 ++counters[cur];
00388 for (size_type r = 1; r < d; ++r)
00389 {
00390 if (cur_column[prev] + currentMass < cur_column[cur])
00391 {
00392 cur_column[cur] = cur_column[prev] + currentMass;
00393 cont = true;
00394 _witnessVector[cur] = std::make_pair(i, counters[cur]);
00395 }
00396 else
00397 {
00398 counters[cur] = 0;
00399 }
00400 prev++;
00401 cur++;
00402 }
00403
00404 prev = cur - d;
00405
00406 cur += p_inc;
00407 if (cur >= smallestMass)
00408 {
00409 cur -= smallestMass;
00410 }
00411 }
00412 }
00413
00414 }
00415 }
00416
00417 template <typename ValueType, typename DecompositionValueType>
00418 bool IntegerMassDecomposer<ValueType, DecompositionValueType>::
00419 exist(value_type mass)
00420 {
00421
00422 value_type residue = ertable_.back().at(mass % alphabet_.getWeight(0));
00423 return residue != infty_ && mass >= residue;
00424 }
00425
00426 template <typename ValueType, typename DecompositionValueType>
00427 typename IntegerMassDecomposer<ValueType, DecompositionValueType>::decomposition_type
00428 IntegerMassDecomposer<ValueType, DecompositionValueType>::getDecomposition(value_type mass)
00429 {
00430
00431 decomposition_type decomposition;
00432 if (!this->exist(mass))
00433 {
00434 return decomposition;
00435 }
00436
00437 decomposition.reserve(alphabet_.size());
00438 decomposition.resize(alphabet_.size());
00439
00440
00441 value_type r = mass % alphabet_.getWeight(0);
00442 value_type m = ertable_.back().at(r);
00443
00444 decomposition.at(0) = static_cast<decomposition_value_type>
00445 ((mass - m) / alphabet_.getWeight(0));
00446
00447 while (m != 0)
00448 {
00449 size_type i = witness_vector_.at(r).first;
00450 decomposition_value_type j = witness_vector_.at(r).second;
00451 decomposition.at(i) += j;
00452 if (m < j * alphabet_.getWeight(i))
00453 {
00454 break;
00455 }
00456 m -= j * alphabet_.getWeight(i);
00457 r = m % alphabet_.getWeight(0);
00458 }
00459 return decomposition;
00460 }
00461
00462 template <typename ValueType, typename DecompositionValueType>
00463 typename IntegerMassDecomposer<ValueType, DecompositionValueType>::decompositions_type
00464 IntegerMassDecomposer<ValueType, DecompositionValueType>::getAllDecompositions(value_type mass)
00465 {
00466 decompositions_type decompositionsStore;
00467 decomposition_type decomposition(alphabet_.size());
00468 collectDecompositionsRecursively_(mass, alphabet_.size() - 1, decomposition, decompositionsStore);
00469 return decompositionsStore;
00470 }
00471
00472 template <typename ValueType, typename DecompositionValueType>
00473 void IntegerMassDecomposer<ValueType, DecompositionValueType>::
00474 collectDecompositionsRecursively_(value_type mass, size_type alphabetMassIndex,
00475 decomposition_type decomposition, decompositions_type & decompositionsStore)
00476 {
00477 if (alphabetMassIndex == 0)
00478 {
00479 value_type numberOfMasses0 = mass / alphabet_.getWeight(0);
00480 if (numberOfMasses0 * alphabet_.getWeight(0) == mass)
00481 {
00482 decomposition[0] = static_cast<decomposition_value_type>(numberOfMasses0);
00483 decompositionsStore.push_back(decomposition);
00484 }
00485 return;
00486 }
00487
00488
00489
00490 const value_type lcm = lcms_[alphabetMassIndex];
00491 const value_type mass_in_lcm = mass_in_lcms_[alphabetMassIndex];
00492
00493 value_type mass_mod_alphabet0 = mass % alphabet_.getWeight(0);
00494 const value_type mass_mod_decrement = alphabet_.getWeight(alphabetMassIndex) % alphabet_.getWeight(0);
00495
00496 for (value_type i = 0; i < mass_in_lcm; ++i)
00497 {
00498
00499 decomposition[alphabetMassIndex] = static_cast<decomposition_value_type>(i);
00500
00501
00502
00503 if (mass < i * alphabet_.getWeight(alphabetMassIndex))
00504 {
00505 break;
00506 }
00507
00508
00509 value_type r = ertable_[alphabetMassIndex - 1][mass_mod_alphabet0];
00510
00511
00512 if (r != infty_)
00513 {
00514 for (value_type m = mass - i * alphabet_.getWeight(alphabetMassIndex); m >= r; m -= lcm)
00515 {
00516
00517
00518
00519 collectDecompositionsRecursively_(m, alphabetMassIndex - 1, decomposition, decompositionsStore);
00520 decomposition[alphabetMassIndex] += mass_in_lcm;
00521
00522
00523 if (m < lcm)
00524 {
00525 break;
00526 }
00527 }
00528 }
00529
00530 if (mass_mod_alphabet0 < mass_mod_decrement)
00531 {
00532 mass_mod_alphabet0 += alphabet_.getWeight(0) - mass_mod_decrement;
00533 }
00534 else
00535 {
00536 mass_mod_alphabet0 -= mass_mod_decrement;
00537 }
00538 }
00539
00540 }
00541
00550 template <typename ValueType, typename DecompositionValueType>
00551 typename IntegerMassDecomposer<ValueType, DecompositionValueType>::decomposition_value_type IntegerMassDecomposer<ValueType,
00552 DecompositionValueType>::getNumberOfDecompositions(value_type mass)
00553 {
00554 return static_cast<typename IntegerMassDecomposer<ValueType, DecompositionValueType>::decomposition_value_type>(getAllDecompositions(mass).size());
00555 }
00556
00557 }
00558 }
00559
00560 #endif // OPENMS_CHEMISTRY_MASSDECOMPOSITION_IMS_INTEGERMASSDECOMPOSER_H