CMS 3D CMS Logo

/data/doxygen/doxygen-1.7.3/gen/CMSSW_4_2_8/src/RecoTauTag/RecoTau/interface/CombinatoricGenerator.h

Go to the documentation of this file.
00001 #ifndef RecoTauTag_RecoTau_CombinatoricGenerator_h
00002 #define RecoTauTag_RecoTau_CombinatoricGenerator_h
00003 
00004 #include <boost/iterator/iterator_facade.hpp>
00005 #include <boost/iterator/filter_iterator.hpp>
00006 #include <boost/iterator/transform_iterator.hpp>
00007 #include <vector>
00008 #include <set>
00009 #include <memory>
00010 
00011 /*
00012  * CombinatoricGenerator
00013  *
00014  * Author: Evan K. Friis (UC Davis)
00015  *
00016  * Generic classes to compute combinatoric subsets of collections.
00017  *
00018  * Example of use:
00019  *
00020  * vector<int> collection = [0, 1, 2, 3, 4, 5];
00021  *
00022  * typedef CombinatoricGenerator<std::vector<int> Generator; 
00023  * 
00024  * // Select three element combinations of collection
00025  * Generator generator(collection.begin(), collection.end(), 3);
00026  *
00027  * for(Generator::iterator combo = generator.begin(); combo != generator.end(); ++combo)
00028  * {
00029  *     for(Generator::combo_iterator element = combo->begin(); element != combo->end(); ++element)
00030  *     {
00031  *         cout << *element << " ";
00032  *     }
00033  *     cout << endl;
00034  * }
00035  *
00036  * Outputs:
00037  * 0 1 2
00038  * 0 1 3
00039  * 0 1 4
00040  * ...
00041  * 3 4 5
00042  *
00043  * $Id $
00044  *
00045  */
00046 
00047 namespace reco { namespace tau {
00048 
00049 template <typename T>
00050   class Combinatoric 
00051   {
00052     /* Combinatoric<T>
00053      *
00054      * Class that represents a subset of values from a collection of type T.
00055      *
00056      * The values belonging to the current combination subset can be accessed with the iterators
00057      * combo_begin() and combo_end()
00058      *
00059      * The values in the collection not in the subset can be accessed with 
00060      * remainder_begin() and remainder_end()
00061      *
00062      */
00063 
00064     // Iterator over input collection
00065     typedef typename T::const_iterator value_iter;
00066     typedef typename T::value_type value_type;
00067     typedef size_t index_type;
00068     typedef typename std::vector<index_type> indices_collection;
00069     typedef typename indices_collection::const_iterator index_iter;
00070     typedef typename std::set<index_type> indices_set;
00071 
00072     class IndexInSet {
00073       /* Determine if a given index is in a set of indices */
00074       public:
00075         IndexInSet(const indices_set& combo, bool negate):
00076           combo_(combo),negate_(negate){}
00077         bool operator()(const index_type& index) const { 
00078           return (negate_) ? !combo_.count(index) : combo_.count(index); 
00079         } 
00080       private:
00081         indices_set combo_;
00082         bool negate_;
00083     };
00084 
00085     class ValueAccessor : public std::unary_function<index_type const&, const value_type&> 
00086     {
00087       /* Class to extract a value from a collection given the beginning of the collection
00088        * and the index into the colleciton */
00089       public:
00090         ValueAccessor(const value_iter& begin):
00091           begin_(begin){}
00092         const value_type& operator()(index_type const & index) const {
00093           return *(begin_+index);
00094         }
00095       private:
00096         value_iter begin_;
00097     };
00098 
00099     public:
00100 
00101     Combinatoric(const value_iter& begin, const indices_collection& indices, 
00102         indices_collection combo, bool done):
00103       begin_(begin), combo_(combo.begin(), combo.end()),
00104       comboSet_(combo.begin(), combo.end()), 
00105       indices_(indices),
00106       done_(done),
00107       valueAccessor_(begin), inChoice_(comboSet_, false),
00108       notInChoice_(comboSet_, true) {}
00109 
00110     typedef typename boost::filter_iterator<IndexInSet, index_iter> ComboIter; 
00111     typedef typename boost::transform_iterator<ValueAccessor, ComboIter> ValueIter; 
00112 
00114     ValueIter combo_begin() const { return ValueIter(ComboIter(inChoice_, indices_.begin(), indices_.end()), valueAccessor_); }
00116     ValueIter combo_end() const { return ValueIter(ComboIter(inChoice_, indices_.end(), indices_.end()), valueAccessor_); }
00117 
00119     ValueIter remainder_end() const { return ValueIter(ComboIter(notInChoice_, indices_.end(), indices_.end()), valueAccessor_); }
00121     ValueIter remainder_begin() const { return ValueIter(ComboIter(notInChoice_, indices_.begin(), indices_.end()), valueAccessor_); }
00122 
00124     Combinatoric<T> next() const
00125     {
00126       //std::cout << "building next: " << std::endl;
00127       //std::cout << "current " << std::endl;
00128       //std::copy(combo_.begin(), combo_.end(), std::ostream_iterator<int>(std::cout, " "));
00129       //std::cout << std::endl;
00130 
00131       indices_collection newCombo(combo_);
00132 
00133       // Find the first value that can be updated (starting from the back
00134       // max value for index is (nElements-1) - (distance from end)
00135       // Examples:
00136       //    189 -> 289 (will be updated to 234)
00137       //    179 -> 189 
00138       //    123 -> 124
00139       size_t distanceFromEnd = 0;
00140       size_t nElements = indices_.size();
00141       indices_collection::reverse_iterator pos = newCombo.rbegin();
00142       for(; pos != newCombo.rend(); ++pos, ++distanceFromEnd) 
00143       {
00144         // Check if we can update this element to the next value (without overflow)
00145         // If so, increment it it, then quit
00146         if( *pos < (nElements - 1 - distanceFromEnd) )
00147         {
00148           (*pos)++;
00149           break;
00150         } else {
00151           // Set to 'unset value' - we need to update it!
00152           (*pos) = nElements;
00153         }
00154       }
00155 
00156       //std::cout << "after update " << std::endl;
00157       //std::copy(newCombo.begin(), newCombo.end(), std::ostream_iterator<int>(std::cout, " "));
00158       //std::cout << std::endl;
00159 
00160       // Everything after pos needs to be updated.  i.e. 159 -> 167
00161       index_type next_pos_value = (*pos)+1;
00162       // forward_pos points to the element *after* pos
00163       indices_collection::iterator forward_pos = pos.base();
00164       // Only do the updates if we have not reached all the way to the beginning!
00165       // this indicates we are at the end of the iteration.  We return a combo
00166       // with all values at nElements to flag that we are at the end
00167       bool done = true;
00168       if (forward_pos != newCombo.begin()) {
00169         done = false;
00170         for (; forward_pos != newCombo.end(); ++forward_pos, ++next_pos_value) {
00171           *forward_pos = next_pos_value;
00172         }
00173       }
00174 
00175       //std::cout << "final " << std::endl;
00176       //std::copy(newCombo.begin(), newCombo.end(), std::ostream_iterator<int>(std::cout, " "));
00177       //std::cout << std::endl;
00178 
00179       //return std::auto_ptr<Combinatoric<T> >(new Combinatoric<T>(begin_, indices_, newCombo));
00180       return Combinatoric<T>(begin_, indices_, newCombo, done);
00181     }
00182 
00183     // Check if iteration is done
00184     bool done() const { return done_; }
00185 
00187     const indices_set& combo() const { return comboSet_; }
00188 
00190     bool operator==(const Combinatoric<T>& rhs) const
00191     {
00192       return (this->combo() == rhs.combo() && this->done() == rhs.done());
00193     }
00194 
00195     private:
00196     // Beginning and ending of the vector of iterators that point to our
00197     // input collection
00198     value_iter begin_;
00199     indices_collection combo_;
00200     indices_set comboSet_;
00201     indices_collection indices_;
00202     bool done_;
00203     ValueAccessor valueAccessor_;
00204     IndexInSet inChoice_;
00205     IndexInSet notInChoice_;
00206   };
00207 
00208 template<typename T>
00209   class CombinatoricIterator : public boost::iterator_facade<
00210                                CombinatoricIterator<T>,
00211                                const Combinatoric<T>,
00212                                boost::forward_traversal_tag>
00213 {
00214   /* An iterator over Combinatorics */
00215   public:
00216     typedef Combinatoric<T> value_type;
00217     explicit CombinatoricIterator(const Combinatoric<T>& c):node_(c) {}
00218 
00219   private:
00220     friend class boost::iterator_core_access;
00221 
00222     bool equal(CombinatoricIterator const& other) const {
00223       return this->node_ == other.node_;
00224     }
00225 
00226     void increment() {
00227       node_ = node_.next(); 
00228     } 
00229 
00230     const Combinatoric<T>& dereference() const {
00231       return node_;
00232     }
00233 
00234     Combinatoric<T> node_;
00235 };
00236 
00237 template<typename T>
00238   class CombinatoricGenerator 
00239   {
00240     /* CombinatoricGenerator
00241      *
00242      * Generate combinatoric subsets of a collection of type T.
00243      *
00244      * This classes begin() and end() functions return iterators of size
00245      * <choose> the first and last combinatoric subsets in the input collection
00246      * range defined by <begin> and <end>.
00247      */
00248 
00249     // Iterator over input collection
00250     typedef typename T::const_iterator value_iter;
00251     typedef typename T::value_type value_type;
00252     typedef size_t index_type;
00253     typedef typename std::vector<index_type> indices_collection;
00254     typedef typename indices_collection::iterator index_iter;
00255     typedef typename std::set<index_type> indices_set;
00256 
00257     public:
00258 
00259     typedef std::auto_ptr<CombinatoricIterator<T> > CombIterPtr;
00260     typedef CombinatoricIterator<T> iterator;
00261     typedef typename iterator::value_type::ValueIter combo_iterator;
00262 
00263     explicit CombinatoricGenerator(const value_iter& begin, const value_iter& end, size_t choose)
00264     {
00265       // Make beginning and ending index collections
00266       indices_collection initialCombo(choose);
00267       indices_collection finalCombo(choose);
00268 
00269       size_t totalElements = end-begin;
00270 
00271       indices_collection allIndices(totalElements);
00272       for(size_t i=0; i < totalElements; ++i)
00273       {
00274         allIndices[i] = i;
00275       }
00276 
00277       for(size_t i=0; i < choose; ++i)
00278       {
00279         initialCombo[i] = i;
00280         // End conditions each is set at nElements
00281         finalCombo[i] = totalElements;
00282       }
00283 
00284       beginning_ = CombIterPtr(new CombinatoricIterator<T>(Combinatoric<T>(
00285               begin, allIndices, initialCombo, false)));
00286 
00287       ending_ = CombIterPtr(new CombinatoricIterator<T>(Combinatoric<T>(
00288               begin, allIndices, finalCombo, true)));
00289     }
00290 
00291     CombinatoricIterator<T> begin() {
00292       return *beginning_;
00293     }
00294 
00295     CombinatoricIterator<T> end() {
00296       return *ending_;
00297     }
00298 
00299     private:
00300     CombIterPtr beginning_;
00301     CombIterPtr ending_;
00302   }; 
00303 
00304 } } // end namespace reco::tau
00305 #endif