Home  · Classes  · Annotated Classes  · Modules  · Members  · Namespaces  · Related Pages
IntegerMassDecomposer.h
Go to the documentation of this file.
1 // --------------------------------------------------------------------------
2 // OpenMS -- Open-Source Mass Spectrometry
3 // --------------------------------------------------------------------------
4 // Copyright The OpenMS Team -- Eberhard Karls University Tuebingen,
5 // ETH Zurich, and Freie Universitaet Berlin 2002-2017.
6 //
7 // This software is released under a three-clause BSD license:
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of any author or any participating institution
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 // For a full list of authors, refer to the file AUTHORS.
17 // --------------------------------------------------------------------------
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING
22 // INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // --------------------------------------------------------------------------
31 // $Maintainer: Timo Sachsenberg $
32 // $Authors: Anton Pervukhin <Anton.Pervukhin@CeBiTec.Uni-Bielefeld.DE> $
33 // --------------------------------------------------------------------------
34 //
35 
36 #ifndef OPENMS_CHEMISTRY_MASSDECOMPOSITION_IMS_INTEGERMASSDECOMPOSER_H
37 #define OPENMS_CHEMISTRY_MASSDECOMPOSITION_IMS_INTEGERMASSDECOMPOSER_H
38 
39 #include <vector>
40 #include <utility>
41 
44 
46 
47 namespace OpenMS
48 {
49 
50  namespace ims
51  {
52 
69  template <typename ValueType = long unsigned int,
70  typename DecompositionValueType = unsigned int>
72  public MassDecomposer<ValueType, DecompositionValueType>
73  {
74 public:
77 
80 
83 
86 
88  typedef typename decomposition_type::size_type size_type;
89 
95  explicit IntegerMassDecomposer(const Weights & alphabet);
96 
103  virtual bool exist(value_type mass);
104 
111  virtual decomposition_type getDecomposition(value_type mass);
112 
119  virtual decompositions_type getAllDecompositions(value_type mass);
120 
129  virtual decomposition_value_type getNumberOfDecompositions(value_type mass);
130 
131 private:
132 
136  typedef std::vector<std::pair<size_type, decomposition_value_type> > witness_vector_type;
137 
141  typedef std::vector<value_type> residues_table_row_type;
142 
146  typedef std::vector<residues_table_row_type> residues_table_type;
147 
152 
158  residues_table_type ertable_;
159 
164  residues_table_row_type lcms_;
165 
171  residues_table_row_type mass_in_lcms_;
172 
176  value_type infty_;
177 
182  witness_vector_type witness_vector_;
183 
187  void fillExtendedResidueTable_(const Weights & _alphabet, residues_table_row_type & _lcms,
188  residues_table_row_type & _mass_in_lcms, const value_type _infty,
189  witness_vector_type & _witness_vector, residues_table_type & _ertable);
190 
199  void collectDecompositionsRecursively_(value_type mass, size_type alphabetMassIndex,
200  decomposition_type decomposition, decompositions_type & decompositionsStore);
201  };
202 
203 
204  template <typename ValueType, typename DecompositionValueType>
206  const Weights & alphabet) :
207  alphabet_(alphabet)
208  {
209 
210  lcms_.resize(alphabet.size());
211  mass_in_lcms_.resize(alphabet.size());
212 
213  infty_ = alphabet.getWeight(0) * alphabet.getWeight(alphabet.size() - 1);
214 
216 
217  }
218 
219  template <typename ValueType, typename DecompositionValueType>
221  const Weights & _alphabet, residues_table_row_type & _lcms, residues_table_row_type & _mass_in_lcms,
222  const value_type _infty, witness_vector_type & _witnessVector, residues_table_type & _ertable)
223  {
224 
225  if (_alphabet.size() < 2)
226  {
227  return;
228  }
229  // caches the most often used mass - smallest mass
230  value_type smallestMass = _alphabet.getWeight(0), secondMass = _alphabet.getWeight(1);
231 
232  // initializes table: infinity everywhere except in the first field of every column
233  _ertable.reserve(_alphabet.size());
234  _ertable.assign(_alphabet.size(), std::vector<value_type>(smallestMass, _infty));
235 
236  for (size_type i = 0; i < _alphabet.size(); ++i)
237  {
238  _ertable[i][0] = 0;
239  }
240 
241  // initializes witness vector
242  _witnessVector.resize(smallestMass);
243 
244  // fills second column (the first one is already correct)
245  size_type it_inc = secondMass % smallestMass, witness = 1;
246  //typename residues_table_row_type::iterator it = _ertable[1].begin() + it_inc;
247  value_type mass = secondMass;
248  // initializes counter to create a witness vector
249  decomposition_value_type counter = 0;
250  size_type it_i = it_inc;
251  while (it_i != 0)
252  {
253  _ertable[1][it_i] = mass;
254  mass += secondMass;
255  ++counter;
256  _witnessVector[it_i] = std::make_pair(witness, counter);
257  //std::cerr << "BLA: " << counter << " " << &_ertable[1][0] << " " << it - _ertable[1].begin() << " " << _ertable[1].size() << std::endl;
258  it_i += it_inc;
259  if (it_i >= _ertable[1].size())
260  {
261  it_i -= _ertable[1].size();
262  }
263  }
264  // fills cache variables for i==1
265  value_type tmp_d = Math::gcd(smallestMass, secondMass);
266  _lcms[1] = secondMass * smallestMass / tmp_d;
267  _mass_in_lcms[1] = smallestMass / tmp_d;
268 
269  // fills remaining table. i is the column index.
270  for (size_type i = 2; i < _alphabet.size(); ++i)
271  {
272  // caches often used i-th alphabet mass
273  value_type currentMass = _alphabet.getWeight(i);
274 
275  value_type d = Math::gcd(smallestMass, currentMass);
276 
277  // fills cache for various variables.
278  // note that values for i==0 are never assigned since they're unused anyway.
279  _lcms[i] = currentMass * smallestMass / d;
280  _mass_in_lcms[i] = smallestMass / d;
281 
282  // Nijenhuis' improvement: Is currentMass composable with smaller alphabet?
283  if (currentMass >= _ertable[i - 1][currentMass % smallestMass])
284  {
285  _ertable[i] = _ertable[i - 1];
286  continue;
287  }
288 
289  const residues_table_row_type & prev_column = _ertable[i - 1];
290  residues_table_row_type & cur_column = _ertable[i];
291 
292  if (d == 1)
293  {
294  // This loop is for the case that the gcd is 1. The optimization used below
295  // is not applicable here.
296 
297  // p_inc is used to change residue (p) efficiently
298  size_type p_inc = currentMass % smallestMass;
299 
300  // n is the value that will be written into the table
301  value_type n = 0;
302  // current residue (in paper variable 'r' is used)
303  size_type p = 0;
304  // counter for creation of witness vector
305  decomposition_value_type local_counter = 0;
306 
307  for (size_type m = smallestMass; m > 0; --m)
308  {
309  n += currentMass;
310  p += p_inc;
311  ++local_counter;
312  if (p >= smallestMass)
313  {
314  p -= smallestMass;
315  }
316  if (n > prev_column[p])
317  {
318  n = prev_column[p];
319  local_counter = 0;
320  }
321  else
322  {
323  _witnessVector[p] = std::make_pair(i, local_counter);
324  }
325  cur_column[p] = n;
326  }
327  }
328  else
329  {
330  // If we're here, the gcd is not 1. We can use the following cache-optimized
331  // version of the algorithm. The trick is to put the iteration over all
332  // residue classes into the _inner_ loop.
333  //
334  // One could see it as going through one column in blocks which are gcd entries long.
335  size_type cur = currentMass % smallestMass;
336  size_type prev = 0;
337  size_type p_inc = cur - d;
338  // counters for creation of one witness vector
339  std::vector<decomposition_value_type> counters(smallestMass);
340 
341  // copies first block from prev_column to cur_column
342  for (size_type j = 1; j < d; ++j)
343  {
344  cur_column[j] = prev_column[j];
345  }
346 
347  // first loop: goes through all blocks, updating cur_column for the first time.
348  for (size_type m = smallestMass / d; m > 1; m--)
349  {
350  // r: current residue class
351  for (size_type r = 0; r < d; r++)
352  {
353 
354  ++counters[cur];
355  if (cur_column[prev] + currentMass > prev_column[cur])
356  {
357  cur_column[cur] = prev_column[cur];
358  counters[cur] = 0;
359  }
360  else
361  {
362  cur_column[cur] = cur_column[prev] + currentMass;
363  _witnessVector[cur] = std::make_pair(i, counters[cur]);
364  }
365 
366  prev++;
367  cur++;
368  }
369 
370  prev = cur - d;
371 
372  // this does: cur = (cur + currentMass) % smallestMass - d;
373  cur += p_inc;
374  if (cur >= smallestMass)
375  {
376  cur -= smallestMass;
377  }
378  }
379 
380  // second loop:
381  bool cont = true;
382  while (cont)
383  {
384  cont = false;
385  prev++;
386  cur++;
387  ++counters[cur];
388  for (size_type r = 1; r < d; ++r)
389  {
390  if (cur_column[prev] + currentMass < cur_column[cur])
391  {
392  cur_column[cur] = cur_column[prev] + currentMass;
393  cont = true;
394  _witnessVector[cur] = std::make_pair(i, counters[cur]);
395  }
396  else
397  {
398  counters[cur] = 0;
399  }
400  prev++;
401  cur++;
402  }
403 
404  prev = cur - d;
405 
406  cur += p_inc;
407  if (cur >= smallestMass)
408  {
409  cur -= smallestMass;
410  }
411  }
412  }
413 
414  }
415  }
416 
417  template <typename ValueType, typename DecompositionValueType>
420  {
421 
422  value_type residue = ertable_.back().at(mass % alphabet_.getWeight(0));
423  return residue != infty_ && mass >= residue;
424  }
425 
426  template <typename ValueType, typename DecompositionValueType>
429  {
430 
431  decomposition_type decomposition;
432  if (!this->exist(mass))
433  {
434  return decomposition;
435  }
436 
437  decomposition.reserve(alphabet_.size());
438  decomposition.resize(alphabet_.size());
439 
440  // initial mass residue: in FIND-ONE algorithm in paper corresponds variable "r"
441  value_type r = mass % alphabet_.getWeight(0);
442  value_type m = ertable_.back().at(r);
443 
444  decomposition.at(0) = static_cast<decomposition_value_type>
445  ((mass - m) / alphabet_.getWeight(0));
446 
447  while (m != 0)
448  {
449  size_type i = witness_vector_.at(r).first;
450  decomposition_value_type j = witness_vector_.at(r).second;
451  decomposition.at(i) += j;
452  if (m < j * alphabet_.getWeight(i))
453  {
454  break;
455  }
456  m -= j * alphabet_.getWeight(i);
457  r = m % alphabet_.getWeight(0);
458  }
459  return decomposition;
460  }
461 
462  template <typename ValueType, typename DecompositionValueType>
465  {
466  decompositions_type decompositionsStore;
467  decomposition_type decomposition(alphabet_.size());
468  collectDecompositionsRecursively_(mass, alphabet_.size() - 1, decomposition, decompositionsStore);
469  return decompositionsStore;
470  }
471 
472  template <typename ValueType, typename DecompositionValueType>
475  decomposition_type decomposition, decompositions_type & decompositionsStore)
476  {
477  if (alphabetMassIndex == 0)
478  {
479  value_type numberOfMasses0 = mass / alphabet_.getWeight(0);
480  if (numberOfMasses0 * alphabet_.getWeight(0) == mass)
481  {
482  decomposition[0] = static_cast<decomposition_value_type>(numberOfMasses0);
483  decompositionsStore.push_back(decomposition);
484  }
485  return;
486  }
487 
488  // tested: caching these values gives us 15% better performance, at least
489  // with aminoacid-mono.masses
490  const value_type lcm = lcms_[alphabetMassIndex];
491  const value_type mass_in_lcm = mass_in_lcms_[alphabetMassIndex]; // this is alphabet mass divided by gcd
492 
493  value_type mass_mod_alphabet0 = mass % alphabet_.getWeight(0); // trying to avoid modulo
494  const value_type mass_mod_decrement = alphabet_.getWeight(alphabetMassIndex) % alphabet_.getWeight(0);
495 
496  for (value_type i = 0; i < mass_in_lcm; ++i)
497  {
498  // here is the conversion from value_type to decomposition_value_type
499  decomposition[alphabetMassIndex] = static_cast<decomposition_value_type>(i);
500 
501  // this check is needed because mass could have unsigned type and after reduction on i*alphabetMass will be still be positive but huge
502  // and that will end up in infinite loop
503  if (mass < i * alphabet_.getWeight(alphabetMassIndex))
504  {
505  break;
506  }
507 
508  // r: current residue class. will stay the same in the following loop
509  value_type r = ertable_[alphabetMassIndex - 1][mass_mod_alphabet0];
510 
511  // TODO: if infty was std::numeric_limits<...>... the following 'if' would not be necessary
512  if (r != infty_)
513  {
514  for (value_type m = mass - i * alphabet_.getWeight(alphabetMassIndex); m >= r; m -= lcm)
515  {
516  // the condition of the 'for' loop (m >= r) and decrementing the mass
517  // in steps of the lcm ensures that m is decomposable. Therefore
518  // the recursion will result in at least one witness.
519  collectDecompositionsRecursively_(m, alphabetMassIndex - 1, decomposition, decompositionsStore);
520  decomposition[alphabetMassIndex] += mass_in_lcm;
521  // this check is needed because mass could have unsigned type and after reduction on i*alphabetMass will be still be positive but huge
522  // and that will end up in infinite loop
523  if (m < lcm)
524  {
525  break;
526  }
527  }
528  }
529  // subtle way of changing the modulo, instead of plain calculation it from (mass - i*currentAlphabetMass) % alphabetMass0 every time
530  if (mass_mod_alphabet0 < mass_mod_decrement)
531  {
532  mass_mod_alphabet0 += alphabet_.getWeight(0) - mass_mod_decrement;
533  }
534  else
535  {
536  mass_mod_alphabet0 -= mass_mod_decrement;
537  }
538  }
539 
540  }
541 
550  template <typename ValueType, typename DecompositionValueType>
552  DecompositionValueType>::getNumberOfDecompositions(value_type mass)
553  {
555  }
556 
557  } // namespace ims
558 } // namespace OpenMS
559 
560 #endif // OPENMS_CHEMISTRY_MASSDECOMPOSITION_IMS_INTEGERMASSDECOMPOSER_H
IntegerMassDecomposer(const Weights &alphabet)
Definition: IntegerMassDecomposer.h:205
std::vector< residues_table_row_type > residues_table_type
Definition: IntegerMassDecomposer.h:146
value_type infty_
Definition: IntegerMassDecomposer.h:176
ValueType value_type
Definition: MassDecomposer.h:74
Represents a set of weights (double values and scaled with a certain precision their integer counterp...
Definition: Weights.h:68
std::vector< decomposition_value_type > decomposition_type
Definition: MassDecomposer.h:84
residues_table_row_type lcms_
Definition: IntegerMassDecomposer.h:164
Main OpenMS namespace.
Definition: FeatureDeconvolution.h:47
std::vector< std::pair< size_type, decomposition_value_type > > witness_vector_type
Definition: IntegerMassDecomposer.h:136
Implements MassDecomposer interface using algorithm and data structures described in paper "Efficient...
Definition: IntegerMassDecomposer.h:71
virtual decomposition_value_type getNumberOfDecompositions(value_type mass)
Definition: IntegerMassDecomposer.h:552
decomposition_type::size_type size_type
Type of decomposition&#39;s size.
Definition: IntegerMassDecomposer.h:88
std::vector< decomposition_type > decompositions_type
Definition: MassDecomposer.h:89
void fillExtendedResidueTable_(const Weights &_alphabet, residues_table_row_type &_lcms, residues_table_row_type &_mass_in_lcms, const value_type _infty, witness_vector_type &_witness_vector, residues_table_type &_ertable)
Definition: IntegerMassDecomposer.h:220
MassDecomposer< ValueType, DecompositionValueType >::decomposition_value_type decomposition_value_type
Type of decomposition value.
Definition: IntegerMassDecomposer.h:79
weight_type getWeight(size_type i) const
Definition: Weights.h:136
T gcd(T a, T b)
Returns the greatest common divisor (gcd) of two numbers by applying the Euclidean algorithm...
Definition: MathFunctions.h:169
std::vector< value_type > residues_table_row_type
Definition: IntegerMassDecomposer.h:141
void collectDecompositionsRecursively_(value_type mass, size_type alphabetMassIndex, decomposition_type decomposition, decompositions_type &decompositionsStore)
Definition: IntegerMassDecomposer.h:474
virtual bool exist(value_type mass)
Definition: IntegerMassDecomposer.h:419
An interface to handle decomposing of integer values/masses over a set of integer weights (alphabet)...
Definition: MassDecomposer.h:68
residues_table_type ertable_
Definition: IntegerMassDecomposer.h:158
virtual decompositions_type getAllDecompositions(value_type mass)
Definition: IntegerMassDecomposer.h:464
residues_table_row_type mass_in_lcms_
Definition: IntegerMassDecomposer.h:171
virtual decomposition_type getDecomposition(value_type mass)
Definition: IntegerMassDecomposer.h:428
size_type size() const
Definition: Weights.h:125
DecompositionValueType decomposition_value_type
Definition: MassDecomposer.h:79
Weights alphabet_
Definition: IntegerMassDecomposer.h:151
MassDecomposer< ValueType, DecompositionValueType >::decomposition_type decomposition_type
Type of decomposition.
Definition: IntegerMassDecomposer.h:82
MassDecomposer< ValueType, DecompositionValueType >::decompositions_type decompositions_type
Type of container for many decompositions.
Definition: IntegerMassDecomposer.h:85
witness_vector_type witness_vector_
Definition: IntegerMassDecomposer.h:182
MassDecomposer< ValueType, DecompositionValueType >::value_type value_type
Type of value to be decomposed.
Definition: IntegerMassDecomposer.h:76

OpenMS / TOPP release 2.3.0 Documentation generated on Tue Jan 9 2018 18:22:01 using doxygen 1.8.13