CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
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  * $Id $
45  *
46  */
47 
48 namespace reco { namespace tau {
49 
50 template <typename T>
52  {
53  /* Combinatoric<T>
54  *
55  * Class that represents a subset of values from a collection of type T.
56  *
57  * The values belonging to the current combination subset can be accessed with the iterators
58  * combo_begin() and combo_end()
59  *
60  * The values in the collection not in the subset can be accessed with
61  * remainder_begin() and remainder_end()
62  *
63  */
64 
65  // Iterator over input collection
66  typedef typename T::const_iterator value_iter;
67  typedef typename T::value_type value_type;
68  typedef size_t index_type;
69  typedef typename std::vector<index_type> indices_collection;
70  typedef typename indices_collection::const_iterator index_iter;
71  typedef typename std::set<index_type> indices_set;
72 
73  class IndexInSet {
74  /* Determine if a given index is in a set of indices */
75  public:
76  IndexInSet(const indices_set& combo, bool negate):
77  combo_(combo),negate_(negate){}
78  bool operator()(const index_type& index) const {
79  return (negate_) ? !combo_.count(index) : combo_.count(index);
80  }
81  private:
83  bool negate_;
84  };
85 
86  class ValueAccessor : public std::unary_function<index_type const&, const value_type&>
87  {
88  /* Class to extract a value from a collection given the beginning of the collection
89  * and the index into the colleciton */
90  public:
92  begin_(begin){}
93  const value_type& operator()(index_type const & index) const {
94  return *(begin_+index);
95  }
96  private:
98  };
99 
100  public:
101 
104  begin_(begin), combo_(combo.begin(), combo.end()),
105  comboSet_(combo.begin(), combo.end()),
106  indices_(indices),
107  done_(done),
110 
111  typedef typename boost::filter_iterator<IndexInSet, index_iter> ComboIter;
112  typedef typename boost::transform_iterator<ValueAccessor, ComboIter> ValueIter;
113 
118 
123 
126  {
127  //std::cout << "building next: " << std::endl;
128  //std::cout << "current " << std::endl;
129  //std::copy(combo_.begin(), combo_.end(), std::ostream_iterator<int>(std::cout, " "));
130  //std::cout << std::endl;
131 
132  indices_collection newCombo(combo_);
133 
134  // Find the first value that can be updated (starting from the back
135  // max value for index is (nElements-1) - (distance from end)
136  // Examples:
137  // 189 -> 289 (will be updated to 234)
138  // 179 -> 189
139  // 123 -> 124
140  size_t distanceFromEnd = 0;
141  size_t nElements = indices_.size();
142  indices_collection::reverse_iterator pos = newCombo.rbegin();
143  for(; pos != newCombo.rend(); ++pos, ++distanceFromEnd)
144  {
145  // Check if we can update this element to the next value (without overflow)
146  // If so, increment it it, then quit
147  if( *pos < (nElements - 1 - distanceFromEnd) )
148  {
149  (*pos)++;
150  break;
151  } else {
152  // Set to 'unset value' - we need to update it!
153  (*pos) = nElements;
154  }
155  }
156 
157  //std::cout << "after update " << std::endl;
158  //std::copy(newCombo.begin(), newCombo.end(), std::ostream_iterator<int>(std::cout, " "));
159  //std::cout << std::endl;
160 
161  // forward_pos points to the element *after* pos
162  indices_collection::iterator forward_pos = pos.base();
163  // Only do the updates if we have not reached all the way to the beginning!
164  // this indicates we are at the end of the iteration. We return a combo
165  // with all values at nElements to flag that we are at the end
166  bool done = true;
167  if (forward_pos != newCombo.begin()) {
168  // Everything after pos needs to be updated. i.e. 159 -> 167
169  index_type next_pos_value = (*pos)+1;
170  //std::cout << "next pos: " << next_pos_value << std::endl;
171  done = false;
172  for (; forward_pos != newCombo.end(); ++forward_pos, ++next_pos_value) {
173  *forward_pos = next_pos_value;
174  }
175  }
176 
177  //std::cout << "final " << std::endl;
178  //std::copy(newCombo.begin(), newCombo.end(), std::ostream_iterator<int>(std::cout, " "));
179  //std::cout << std::endl;
180 
181  //return std::auto_ptr<Combinatoric<T> >(new Combinatoric<T>(begin_, indices_, newCombo));
182  return Combinatoric<T>(begin_, indices_, newCombo, done);
183  }
184 
185  // Check if iteration is done
186  bool done() const { return done_; }
187 
189  const indices_set& combo() const { return comboSet_; }
190 
192  bool operator==(const Combinatoric<T>& rhs) const
193  {
194  return (this->combo() == rhs.combo() && this->done() == rhs.done());
195  }
196 
197  private:
198  // Beginning and ending of the vector of iterators that point to our
199  // input collection
204  bool done_;
208  };
209 
210 template<typename T>
211  class CombinatoricIterator : public boost::iterator_facade<
212  CombinatoricIterator<T>,
213  const Combinatoric<T>,
214  boost::forward_traversal_tag>
215 {
216  /* An iterator over Combinatorics */
217  public:
220 
221  private:
223 
224  bool equal(CombinatoricIterator const& other) const {
225  return this->node_ == other.node_;
226  }
227 
228  void increment() {
229  node_ = node_.next();
230  }
231 
232  const Combinatoric<T>& dereference() const {
233  return node_;
234  }
235 
237 };
238 
239 template<typename T>
241  {
242  /* CombinatoricGenerator
243  *
244  * Generate combinatoric subsets of a collection of type T.
245  *
246  * This classes begin() and end() functions return iterators of size
247  * <choose> the first and last combinatoric subsets in the input collection
248  * range defined by <begin> and <end>.
249  */
250 
251  // Iterator over input collection
252  typedef typename T::const_iterator value_iter;
253  typedef typename T::value_type value_type;
254  typedef size_t index_type;
255  typedef typename std::vector<index_type> indices_collection;
256  typedef typename indices_collection::iterator index_iter;
257  typedef typename std::set<index_type> indices_set;
258 
259  public:
260 
261  typedef std::auto_ptr<CombinatoricIterator<T> > CombIterPtr;
264 
265  explicit CombinatoricGenerator(const value_iter& begin, const value_iter& end, size_t choose)
266  {
267  // Make beginning and ending index collections
268  indices_collection initialCombo(choose);
269  indices_collection finalCombo(choose);
270 
271  size_t totalElements = end-begin;
272 
273  if (choose <= totalElements) {
274  indices_collection allIndices(totalElements);
275  for(size_t i=0; i < totalElements; ++i)
276  {
277  allIndices[i] = i;
278  }
279 
280  for(size_t i=0; i < choose; ++i)
281  {
282  initialCombo[i] = i;
283  // End conditions each is set at nElements
284  finalCombo[i] = totalElements;
285  }
286 
288  begin, allIndices, initialCombo, false)));
289 
291  begin, allIndices, finalCombo, true)));
292  } else {
293  // We don't have enough in the collection to return [choose] items.
294  // Return an empty collection
296  begin, indices_collection(), indices_collection(), true)));
297 
299  begin, indices_collection(), indices_collection(), true)));
300  }
301  }
302 
304  return *beginning_;
305  }
306 
308  return *ending_;
309  }
310 
311  private:
314  };
315 
316 } } // end namespace reco::tau
317 #endif
CombinatoricIterator(const Combinatoric< T > &c)
int i
Definition: DBlmapReader.cc:9
CombinatoricIterator< T > end()
std::vector< index_type > indices_collection
indices_collection::const_iterator index_iter
const Combinatoric< T > & dereference() const
ValueIter combo_end() const
One past the last element in the selected subset.
CombinatoricGenerator(const value_iter &begin, const value_iter &end, size_t choose)
std::auto_ptr< CombinatoricIterator< T > > CombIterPtr
bool equal(CombinatoricIterator const &other) const
#define end
Definition: vmac.h:38
Container::value_type value_type
boost::filter_iterator< IndexInSet, index_iter > ComboIter
ValueIter remainder_begin() const
One past the last element in the non-selected subset.
bool operator()(const index_type &index) const
ValueIter remainder_end() const
The first 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.
const indices_set & combo() const
Return the set of selected indices.
Combinatoric(const value_iter &begin, const indices_collection &indices, indices_collection combo, bool done)
CombinatoricIterator< T > iterator
#define begin
Definition: vmac.h:31
indices_collection::iterator index_iter
std::vector< index_type > indices_collection
boost::transform_iterator< ValueAccessor, ComboIter > ValueIter
bool operator==(const Combinatoric< T > &rhs) const
Comparison to another combination.
std::set< index_type > indices_set
const value_type & operator()(index_type const &index) const
iterator::value_type::ValueIter combo_iterator
CombinatoricIterator< T > begin()
IndexInSet(const indices_set &combo, bool negate)