ATLAS Offline Software
BuildCombinations.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 namespace DerivationFramework { namespace TriggerMatchingUtils {
6 
7  template <typename T>
8  bool insertIntoSortedVector(std::vector<T>& vec, const T& ele)
9  {
10  auto itr = std::lower_bound(vec.begin(), vec.end(), ele);
11  // if no lower bound is found or the found element doesn't equal ele then
12  // insert ele at this point
13  if (itr == vec.end() || *itr != ele) {
14  vec.insert(itr, ele);
15  return true;
16  }
17  else
18  return false;
19  }
20 
21  template <typename T>
22  std::vector<typename T::value_type> sorted(T begin, T end)
23  {
24  std::vector<typename T::value_type> output(begin, end);
25  std::sort(output.begin(), output.end() );
26  return output;
27  }
28 
29 
30  template <typename T>
31  std::vector<std::vector<T>> getAllDistinctCombinations(
32  std::vector<RangedItr<typename std::vector<T>::const_iterator>>& inputs)
33  {
34  // This is where the output will go
35  std::vector<std::vector<T>> output;
36 
37  // If inputs is empty or if any of the ranges within inputs are empty then
38  // no combinations will be found!
39  if (inputs.empty() || std::any_of(inputs.begin(), inputs.end(),
40  [] (const auto& rangedItr) { return rangedItr.exhausted(); }) )
41  return output;
42 
43  // This is the current output combination being built
44  std::vector<T> currentCombination;
45 
46  // This iterator points to where in the vector of ranged iterators we are
47  // looking. This can therefore often be acting as an iterator to and
48  // iterator! *itr is an iterator, **itr is a const T&!
49  // To disambiguate I will refer to itr as the outer iterator and *itr as the
50  // inner iterator.
51  auto itr = inputs.begin();
52  while (true) {
53  // Have we exhausted our current inner iterator?
54  if (itr == inputs.end() || itr->exhausted() ) {
55  // If the outer iterator has returned to the beginning then we're done
56  // and every combination has been checked.
57  if (itr == inputs.begin() )
58  break;
59  // otherwise we need to continue. To do this we
60  // - reset the current inner iterator. This is so that the next time we
61  // return to it we look through all the elements again
62  // - step the outer iterator back
63  // - remove the last element of the current combination. That
64  // element will be replaced by the next valid one from the list *now*
65  // pointed to by the outer iterator.
66  if (itr != inputs.end() )
67  itr->restart();
68  --itr;
69  currentCombination.pop_back();
70  } //> end if inner iterator is exhausted
71  else {
72  // Check if the pointed-to element is already in the current combination
73  const T& currentCandidate = **itr;
74  // Now that we've accessed this value, step past it
75  ++*itr;
76  if (std::find(
77  currentCombination.begin(),
78  currentCombination.end(),
79  currentCandidate) == currentCombination.end() ) {
80  // If it isn't, then add it.
81  currentCombination.push_back(currentCandidate);
82  // Step the outer iterator forwards so we're looking at the next list
83  ++itr;
84  if (itr == inputs.end() ) {
85  // If we're at the end then this is a complete combination, add it
86  // to the output.
87  insertIntoSortedVector(output, sorted(
88  currentCombination.begin(),
89  currentCombination.end() ) );
90  }
91  } //> end if currentCandidate is in currentCombination
92  } //> end else (if inner iterator is exhausted)
93  } //> end while loop
94  return output;
95  } //> end function getAllDistinctCombinations
96 
97 }} //> end namespace DerivationFramework::TriggerMatchingUtils