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  *
45  */
46 
47 namespace reco { namespace tau {
48 
49 template <typename T>
51  {
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):
76  combo_(combo),negate_(negate){}
77  bool operator()(const index_type& index) const {
78  return (negate_) ? !combo_.count(index) : combo_.count(index);
79  }
80  private:
82  bool negate_;
83  };
84 
85  class ValueAccessor : public std::unary_function<index_type const&, const value_type&>
86  {
87  /* Class to extract a value from a collection given the beginning of the collection
88  * and the index into the colleciton */
89  public:
91  begin_(begin){}
92  const value_type& operator()(index_type const & index) const {
93  return *(begin_+index);
94  }
95  private:
97  };
98 
99  public:
100 
102  const indices_collection& combo, bool done):
103  begin_(begin), combo_(combo.begin(), combo.end()),
104  comboSet_(combo.begin(), combo.end()),
105  indices_(indices),
106  done_(done),
109 
110  typedef typename boost::filter_iterator<IndexInSet, index_iter> ComboIter;
111  typedef typename boost::transform_iterator<ValueAccessor, ComboIter> ValueIter;
112 
117 
122 
125  {
126  //std::cout << "building next: " << std::endl;
127  //std::cout << "current " << std::endl;
128  //std::copy(combo_.begin(), combo_.end(), std::ostream_iterator<int>(std::cout, " "));
129  //std::cout << std::endl;
130 
131  indices_collection newCombo(combo_);
132 
133  // Find the first value that can be updated (starting from the back
134  // max value for index is (nElements-1) - (distance from end)
135  // Examples:
136  // 189 -> 289 (will be updated to 234)
137  // 179 -> 189
138  // 123 -> 124
139  size_t distanceFromEnd = 0;
140  size_t nElements = indices_.size();
141  indices_collection::reverse_iterator pos = newCombo.rbegin();
142  for(; pos != newCombo.rend(); ++pos, ++distanceFromEnd)
143  {
144  // Check if we can update this element to the next value (without overflow)
145  // If so, increment it it, then quit
146  if( *pos < (nElements - 1 - distanceFromEnd) )
147  {
148  (*pos)++;
149  break;
150  } else {
151  // Set to 'unset value' - we need to update it!
152  (*pos) = nElements;
153  }
154  }
155 
156  //std::cout << "after update " << std::endl;
157  //std::copy(newCombo.begin(), newCombo.end(), std::ostream_iterator<int>(std::cout, " "));
158  //std::cout << std::endl;
159 
160  // forward_pos points to the element *after* pos
161  indices_collection::iterator forward_pos = pos.base();
162  // Only do the updates if we have not reached all the way to the beginning!
163  // this indicates we are at the end of the iteration. We return a combo
164  // with all values at nElements to flag that we are at the end
165  bool done = true;
166  if (forward_pos != newCombo.begin()) {
167  // Everything after pos needs to be updated. i.e. 159 -> 167
168  index_type next_pos_value = (*pos)+1;
169  //std::cout << "next pos: " << next_pos_value << std::endl;
170  done = false;
171  for (; forward_pos != newCombo.end(); ++forward_pos, ++next_pos_value) {
172  *forward_pos = next_pos_value;
173  }
174  }
175 
176  //std::cout << "final " << std::endl;
177  //std::copy(newCombo.begin(), newCombo.end(), std::ostream_iterator<int>(std::cout, " "));
178  //std::cout << std::endl;
179 
180  //return std::auto_ptr<Combinatoric<T> >(new Combinatoric<T>(begin_, indices_, newCombo));
181  return Combinatoric<T>(begin_, indices_, newCombo, done);
182  }
183 
184  // Check if iteration is done
185  bool done() const { return done_; }
186 
188  const indices_set& combo() const { return comboSet_; }
189 
191  bool operator==(const Combinatoric<T>& rhs) const
192  {
193  return (this->combo() == rhs.combo() && this->done() == rhs.done());
194  }
195 
196  private:
197  // Beginning and ending of the vector of iterators that point to our
198  // input collection
203  bool done_;
207  };
208 
209 template<typename T>
210  class CombinatoricIterator : public boost::iterator_facade<
211  CombinatoricIterator<T>,
212  const Combinatoric<T>,
213  boost::forward_traversal_tag>
214 {
215  /* An iterator over Combinatorics */
216  public:
219 
220  private:
222 
223  bool equal(CombinatoricIterator const& other) const {
224  return this->node_ == other.node_;
225  }
226 
227  void increment() {
228  node_ = node_.next();
229  }
230 
231  const Combinatoric<T>& dereference() const {
232  return node_;
233  }
234 
236 };
237 
238 template<typename T>
240  {
241  /* CombinatoricGenerator
242  *
243  * Generate combinatoric subsets of a collection of type T.
244  *
245  * This classes begin() and end() functions return iterators of size
246  * <choose> the first and last combinatoric subsets in the input collection
247  * range defined by <begin> and <end>.
248  */
249 
250  // Iterator over input collection
251  typedef typename T::const_iterator value_iter;
252  typedef typename T::value_type value_type;
253  typedef size_t index_type;
254  typedef typename std::vector<index_type> indices_collection;
255  typedef typename indices_collection::iterator index_iter;
256  typedef typename std::set<index_type> indices_set;
257 
258  public:
259 
260  typedef std::auto_ptr<CombinatoricIterator<T> > CombIterPtr;
263 
264  explicit CombinatoricGenerator(const value_iter& begin, const value_iter& end, size_t choose)
265  {
266  // Make beginning and ending index collections
267  indices_collection initialCombo(choose);
268  indices_collection finalCombo(choose);
269 
270  size_t totalElements = end-begin;
271 
272  if (choose <= totalElements) {
273  indices_collection allIndices(totalElements);
274  for(size_t i=0; i < totalElements; ++i)
275  {
276  allIndices[i] = i;
277  }
278 
279  for(size_t i=0; i < choose; ++i)
280  {
281  initialCombo[i] = i;
282  // End conditions each is set at nElements
283  finalCombo[i] = totalElements;
284  }
285 
287  begin, allIndices, initialCombo, false)));
288 
290  begin, allIndices, finalCombo, true)));
291  } else {
292  // We don't have enough in the collection to return [choose] items.
293  // Return an empty collection
295  begin, indices_collection(), indices_collection(), true)));
296 
298  begin, indices_collection(), indices_collection(), true)));
299  }
300  }
301 
303  return *beginning_;
304  }
305 
307  return *ending_;
308  }
309 
310  private:
313  };
314 
315 } } // end namespace reco::tau
316 #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)
Combinatoric(const value_iter &begin, const indices_collection &indices, const indices_collection &combo, bool done)
std::auto_ptr< CombinatoricIterator< T > > CombIterPtr
bool equal(CombinatoricIterator const &other) const
#define end
Definition: vmac.h:37
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.
CombinatoricIterator< T > iterator
#define begin
Definition: vmac.h:30
indices_collection::iterator index_iter
std::vector< index_type > indices_collection
boost::transform_iterator< ValueAccessor, ComboIter > ValueIter
volatile std::atomic< bool > shutdown_flag false
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)