CMS 3D CMS Logo

CombinatoricGenerator.h
Go to the documentation of this file.
1 #ifndef RecoTauTag_RecoTau_CombinatoricGenerator_h
2 #define RecoTauTag_RecoTau_CombinatoricGenerator_h
3 
4 #include <boost/iterator/iterator_facade.hpp>
5 #include <boost/iterator/filter_iterator.hpp>
6 #include <boost/iterator/transform_iterator.hpp>
7 #include <vector>
8 #include <set>
9 #include <memory>
10 #include <iostream>
11 
12 /*
13  * CombinatoricGenerator
14  *
15  * Author: Evan K. Friis (UC Davis)
16  *
17  * Generic classes to compute combinatoric subsets of collections.
18  *
19  * Example of use:
20  *
21  * vector<int> collection = [0, 1, 2, 3, 4, 5];
22  *
23  * typedef CombinatoricGenerator<std::vector<int> Generator;
24  *
25  * // Select three element combinations of collection
26  * Generator generator(collection.begin(), collection.end(), 3);
27  *
28  * for(Generator::iterator combo = generator.begin(); combo != generator.end(); ++combo)
29  * {
30  * for(Generator::combo_iterator element = combo->begin(); element != combo->end(); ++element)
31  * {
32  * cout << *element << " ";
33  * }
34  * cout << endl;
35  * }
36  *
37  * Outputs:
38  * 0 1 2
39  * 0 1 3
40  * 0 1 4
41  * ...
42  * 3 4 5
43  *
44  *
45  */
46 
47 namespace reco {
48  namespace tau {
49 
50  template <typename T>
51  class Combinatoric {
52  /* Combinatoric<T>
53  *
54  * Class that represents a subset of values from a collection of type T.
55  *
56  * The values belonging to the current combination subset can be accessed with the iterators
57  * combo_begin() and combo_end()
58  *
59  * The values in the collection not in the subset can be accessed with
60  * remainder_begin() and remainder_end()
61  *
62  */
63 
64  // Iterator over input collection
65  typedef typename T::const_iterator value_iter;
66  typedef typename T::value_type value_type;
67  typedef size_t index_type;
68  typedef typename std::vector<index_type> indices_collection;
69  typedef typename indices_collection::const_iterator index_iter;
70  typedef typename std::set<index_type> indices_set;
71 
72  class IndexInSet {
73  /* Determine if a given index is in a set of indices */
74  public:
75  IndexInSet(const indices_set& combo, bool negate) : combo_(combo), negate_(negate) {}
76  bool operator()(const index_type& index) const {
77  return (negate_) ? !combo_.count(index) : combo_.count(index);
78  }
79 
80  private:
82  bool negate_;
83  };
84 
85  class ValueAccessor {
86  /* Class to extract a value from a collection given the beginning of the collection
87  * and the index into the colleciton */
88  public:
89  ValueAccessor(const value_iter& begin) : begin_(begin) {}
90  const value_type& operator()(index_type const& index) const { return *(begin_ + index); }
91 
92  private:
94  };
95 
96  public:
97  Combinatoric(const value_iter& begin,
100  bool done)
101  : begin_(begin),
102  combo_(combo.begin(), combo.end()),
103  comboSet_(combo.begin(), combo.end()),
104  indices_(indices),
105  done_(done),
106  valueAccessor_(begin),
109 
110  typedef typename boost::filter_iterator<IndexInSet, index_iter> ComboIter;
111  typedef typename boost::transform_iterator<ValueAccessor, ComboIter> ValueIter;
112 
115  return ValueIter(ComboIter(inChoice_, indices_.begin(), indices_.end()), valueAccessor_);
116  }
120  }
121 
125  }
129  }
130 
133  //std::cout << "building next: " << std::endl;
134  //std::cout << "current " << std::endl;
135  //std::copy(combo_.begin(), combo_.end(), std::ostream_iterator<int>(std::cout, " "));
136  //std::cout << std::endl;
137 
138  indices_collection newCombo(combo_);
139 
140  // Find the first value that can be updated (starting from the back
141  // max value for index is (nElements-1) - (distance from end)
142  // Examples:
143  // 189 -> 289 (will be updated to 234)
144  // 179 -> 189
145  // 123 -> 124
146  size_t distanceFromEnd = 0;
147  size_t nElements = indices_.size();
148  indices_collection::reverse_iterator pos = newCombo.rbegin();
149  for (; pos != newCombo.rend(); ++pos, ++distanceFromEnd) {
150  // Check if we can update this element to the next value (without overflow)
151  // If so, increment it it, then quit
152  if (*pos < (nElements - 1 - distanceFromEnd)) {
153  (*pos)++;
154  break;
155  } else {
156  // Set to 'unset value' - we need to update it!
157  (*pos) = nElements;
158  }
159  }
160 
161  //std::cout << "after update " << std::endl;
162  //std::copy(newCombo.begin(), newCombo.end(), std::ostream_iterator<int>(std::cout, " "));
163  //std::cout << std::endl;
164 
165  // forward_pos points to the element *after* pos
166  indices_collection::iterator forward_pos = pos.base();
167  // Only do the updates if we have not reached all the way to the beginning!
168  // this indicates we are at the end of the iteration. We return a combo
169  // with all values at nElements to flag that we are at the end
170  bool done = true;
171  if (forward_pos != newCombo.begin()) {
172  // Everything after pos needs to be updated. i.e. 159 -> 167
173  index_type next_pos_value = (*pos) + 1;
174  //std::cout << "next pos: " << next_pos_value << std::endl;
175  done = false;
176  for (; forward_pos != newCombo.end(); ++forward_pos, ++next_pos_value) {
177  *forward_pos = next_pos_value;
178  }
179  }
180 
181  //std::cout << "final " << std::endl;
182  //std::copy(newCombo.begin(), newCombo.end(), std::ostream_iterator<int>(std::cout, " "));
183  //std::cout << std::endl;
184 
185  //return std::unique_ptr<Combinatoric<T> >(new Combinatoric<T>(begin_, indices_, newCombo));
186  return Combinatoric<T>(begin_, indices_, newCombo, done);
187  }
188 
189  // Check if iteration is done
190  bool done() const { return done_; }
191 
193  const indices_set& combo() const { return comboSet_; }
194 
196  bool operator==(const Combinatoric<T>& rhs) const {
197  return (this->combo() == rhs.combo() && this->done() == rhs.done());
198  }
199 
200  private:
201  // Beginning and ending of the vector of iterators that point to our
202  // input collection
207  bool done_;
211  };
212 
213  template <typename T>
215  : public boost::iterator_facade<CombinatoricIterator<T>, const Combinatoric<T>, boost::forward_traversal_tag> {
216  /* An iterator over Combinatorics */
217  public:
220 
221  private:
223 
224  bool equal(CombinatoricIterator const& other) const { return this->node_ == other.node_; }
225 
226  void increment() { node_ = node_.next(); }
227 
228  const Combinatoric<T>& dereference() const { return node_; }
229 
231  };
232 
233  template <typename T>
235  /* CombinatoricGenerator
236  *
237  * Generate combinatoric subsets of a collection of type T.
238  *
239  * This classes begin() and end() functions return iterators of size
240  * <choose> the first and last combinatoric subsets in the input collection
241  * range defined by <begin> and <end>.
242  */
243 
244  // Iterator over input collection
245  typedef typename T::const_iterator value_iter;
246  typedef typename T::value_type value_type;
247  typedef size_t index_type;
248  typedef typename std::vector<index_type> indices_collection;
249  typedef typename indices_collection::iterator index_iter;
250  typedef typename std::set<index_type> indices_set;
251 
252  public:
253  typedef std::unique_ptr<CombinatoricIterator<T> > CombIterPtr;
256 
257  explicit CombinatoricGenerator(const value_iter& begin, const value_iter& end, size_t choose) {
258  // Make beginning and ending index collections
259  indices_collection initialCombo(choose);
260  indices_collection finalCombo(choose);
261 
262  size_t totalElements = end - begin;
263 
264  if (choose <= totalElements) {
265  indices_collection allIndices(totalElements);
266  for (size_t i = 0; i < totalElements; ++i) {
267  allIndices[i] = i;
268  }
269 
270  for (size_t i = 0; i < choose; ++i) {
271  initialCombo[i] = i;
272  // End conditions each is set at nElements
273  finalCombo[i] = totalElements;
274  }
275 
276  beginning_ =
277  CombIterPtr(new CombinatoricIterator<T>(Combinatoric<T>(begin, allIndices, initialCombo, false)));
278 
279  ending_ = CombIterPtr(new CombinatoricIterator<T>(Combinatoric<T>(begin, allIndices, finalCombo, true)));
280  } else {
281  // We don't have enough in the collection to return [choose] items.
282  // Return an empty collection
285 
288  }
289  }
290 
292 
294 
295  private:
298  };
299 
300  } // namespace tau
301 } // namespace reco
302 #endif
CombinatoricIterator(const Combinatoric< T > &c)
CombinatoricIterator< T > end()
ValueIter combo_end() const
One past the last element in the selected subset.
std::vector< index_type > indices_collection
bool operator==(const Combinatoric< T > &rhs) const
Comparison to another combination.
indices_collection::const_iterator index_iter
ValueIter remainder_begin() const
One past the last element in the non-selected subset.
ValueIter combo_begin() const
The first element in the selected subset.
Combinatoric< T > next() const
Build the next cominatoric subset after the current one.
CombinatoricGenerator(const value_iter &begin, const value_iter &end, size_t choose)
const Combinatoric< T > & dereference() const
Combinatoric(const value_iter &begin, const indices_collection &indices, const indices_collection &combo, bool done)
const indices_set & combo() const
Return the set of selected indices.
bool equal(CombinatoricIterator const &other) const
boost::filter_iterator< IndexInSet, index_iter > ComboIter
bool operator()(const index_type &index) const
const value_type & operator()(index_type const &index) const
ValueIter remainder_end() const
The first element in the non-selected subset.
CombinatoricIterator< T > iterator
fixed size matrix
indices_collection::iterator index_iter
std::vector< index_type > indices_collection
std::unique_ptr< CombinatoricIterator< T > > CombIterPtr
boost::transform_iterator< ValueAccessor, ComboIter > ValueIter
std::set< index_type > indices_set
iterator::value_type::ValueIter combo_iterator
CombinatoricIterator< T > begin()
IndexInSet(const indices_set &combo, bool negate)