CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_0/src/CommonTools/Statistics/interface/CombinationGenerator.h

Go to the documentation of this file.
00001 #ifndef _CombinationGenerator_H_
00002 #define _CombinationGenerator_H_
00003 
00004 #include "CommonTools/Statistics/interface/PartitionGenerator.h"
00005 #include <vector>
00006 #include <stack>
00007 #include <algorithm>
00008 #include <functional>
00009 
00018 template<class T>
00019 class CombinationGenerator {
00020 
00021 public:
00022 
00023   typedef std::vector<T> Collection;
00024 
00025   typedef std::vector<Collection> Combination;
00026   typedef std::vector<Combination> VectorOfCombinations;
00027 
00031   std::vector<Combination> 
00032   combinations(const Collection & data, int numberOfCollections) const 
00033   {
00034     std::vector<Combination> combinations;
00035     Collection sorted = data;
00036 
00037     // Sort if needed
00038     if (prev_permutation(sorted.begin(), sorted.end())) {
00039       sort(sorted.begin(), sorted.end());
00040     }
00041 
00042     // Create sorted partitions
00043     PartitionGenerator aPartitionGenerator;
00044     std::vector< std::vector<PartitionGenerator::Partition> > partitions 
00045       = aPartitionGenerator.sortedPartitions(data.size());
00046     
00047     // Use partitions of size 'numberOfCollections' only
00048     for (std::vector<PartitionGenerator::Partition>::const_iterator idiv 
00049            = partitions[numberOfCollections-1].begin(); 
00050          idiv != partitions[numberOfCollections-1].end(); idiv++) {
00051 
00052       const PartitionGenerator::Partition& partition = *idiv;
00053       std::vector<Combination> subCombinations 
00054         = this->combinations(data, partition);
00055       for ( typename std::vector<Combination>::const_iterator iComb 
00056              = subCombinations.begin(); 
00057            iComb != subCombinations.end(); iComb++) {
00058         combinations.push_back(*iComb);
00059       }
00060     }
00061     return combinations;
00062   }
00063 
00064 
00068   std::vector<Combination> 
00069   combinations(const Collection & data,
00070                const PartitionGenerator::Partition & partition) const
00071   {
00072 
00073     std::vector<Combination> combinations;
00074 
00075     // Check that sum of collection sizes in 'partition' 
00076     // amounts to number of elements in 'data' 
00077     int nElts = 0;
00078     for (PartitionGenerator::Partition::const_iterator iSize 
00079            = partition.begin(); iSize != partition.end(); iSize++) {
00080       nElts += *iSize;
00081     }
00082     if (nElts != data.size()) return combinations;
00083 
00084     Collection sortedData = data;
00085     // Sort if needed
00086     if (prev_permutation(sortedData.begin(), sortedData.end())) {
00087       sort(sortedData.begin(), sortedData.end());
00088     }
00089 
00090     // Create initial combination and put it on the stack
00091     Combination comb;
00092     comb.push_back(sortedData);
00093     if (partition.size() == 1) {
00094       // Return only one combination with only one collection
00095       combinations.push_back(comb);
00096       return combinations;
00097     }
00098     std::stack<Combination> cStack;
00099     cStack.push(comb);
00100 
00101     // Sort partitions by size 
00102     // Let 'sortedPartition' = ( n0, n1,... nk, nk+1,... nm ) 
00103     // Ordering is >= to speed up partitioning: n0 >= n1 >=... >= nm 
00104     PartitionGenerator::Partition sortedPartition = partition;
00105     sort(sortedPartition.begin(), sortedPartition.end(), std::greater_equal<int>());
00106 
00107     while (!cStack.empty()) {
00108 
00109       // 'combination' popped out of the stack 
00110       Combination combination = cStack.top(); cStack.pop();
00111 
00112       // At this stage 'combination' is made of collections 
00113       // of sizes ( n0+n1+...+nk, nk+1,... nm ) 
00114       // Now generate all combinations obtained by splitting 
00115       // the first collection of 'combination' in two, 
00116       // according to Partition 'biPartition' = (n0+n1+...+nk-1, nk) 
00117       int k = sortedPartition.size() - combination.size();
00118       int size = 0;
00119       for (int iColl = 0; iColl != k; iColl++) {
00120         size += sortedPartition[iColl];
00121       }
00122       PartitionGenerator::Partition biPartition(2);
00123       biPartition[0] = size; 
00124       biPartition[1] = sortedPartition[k];
00125 
00126       VectorOfCombinations subCombinations 
00127         = splitInTwoCollections(combination[0], biPartition[0]);
00128       for (typename std::vector<Combination>::const_iterator iComb = subCombinations.begin();
00129            iComb != subCombinations.end(); iComb++) { 
00130 
00131         // Check ordering of successive bins of equal size 
00132         if (combination.size() > 1) {
00133           if ((*iComb)[1].size() == combination[1].size()) {
00134             Collection adjBins;
00135             adjBins.push_back((*iComb)[1][0]);
00136             adjBins.push_back(combination[1][0]);
00137             // Drop 'combination' if successive bins of equal size not ordered 
00138             // i.e. if previous permutation exists 
00139             if (prev_permutation(adjBins.begin(), adjBins.end())) continue;
00140           }
00141         }
00142 
00143         // Append remaining collections of 'combination'
00144         Combination merged = *iComb;
00145         typename Combination::const_iterator it = combination.begin(); it++;
00146         for ( ; it != combination.end(); it++) { merged.push_back(*it); }
00147 
00148         // Store combination 'merged' if partitioning is complete, 
00149         // otherwise put it on the stack for further partitioning. 
00150         if (merged.size() == sortedPartition.size()) {
00151           combinations.push_back(merged);
00152         } else {
00153           cStack.push(merged);
00154         }
00155       }
00156     }
00157     return combinations;
00158   }
00159 
00160 
00163   std::vector<Combination> combinations(const Collection & data) const 
00164   {
00165 
00166     std::vector<Combination> combinations;
00167     Collection sorted = data;
00168     // Sort if needed
00169     if (prev_permutation(sorted.begin(), sorted.end())) {
00170       sort(sorted.begin(), sorted.end());
00171     }
00172 
00173     PartitionGenerator aPartitionGenerator;
00174     std::vector<PartitionGenerator::Partition> partitions 
00175       = aPartitionGenerator.partitions(data.size());
00176     
00177     for (std::vector<PartitionGenerator::Partition>::const_iterator idiv 
00178            = partitions.begin(); idiv != partitions.end(); idiv++) {
00179       const PartitionGenerator::Partition& partition = *idiv;
00180 
00181       std::vector<Combination> subCombinations 
00182         = this->combinations(data, partition);
00183       for ( typename std::vector<Combination>::const_iterator iComb 
00184              = subCombinations.begin(); 
00185            iComb != subCombinations.end(); iComb++) {
00186         combinations.push_back(*iComb);
00187       }
00188     }
00189     return combinations;
00190   }
00191 
00192 
00193 private:
00194 
00198   VectorOfCombinations splitInTwoCollections(const Collection & data, 
00199                                             int sizeFirst) const
00200   {
00201     std::vector<Combination> combinations;
00202     std::stack<Combination> cStack;
00203 
00204     // Create first combination with 2 partitions
00205     Combination comb; comb.push_back(data); comb.push_back(Collection());
00206     cStack.push(comb);
00207 
00208     while (!cStack.empty()) {
00209       Combination combination = cStack.top();
00210       cStack.pop();
00211 
00212       Collection collection = combination[0];
00213       std::vector<Combination> subCombinations = separateOneElement(collection);
00214       
00215       for ( typename std::vector<Combination>::const_iterator iComb = subCombinations.begin();
00216            iComb != subCombinations.end(); iComb++) {
00217 
00218         Collection second = combination[1];
00219         second.push_back((*iComb)[1][0]);
00220 
00221         // Abandon current combination if not ordered, 
00222         // i.e. if previous permutation exists 
00223         bool ordered = !prev_permutation(second.begin(), second.end());
00224         if (!ordered) continue;
00225         next_permutation(second.begin(), second.end());
00226 
00227         if ((*iComb)[0].size() == second.size()) {
00228           Collection adjBins;
00229           adjBins.push_back((*iComb)[0][0]);
00230           adjBins.push_back(second[0]);
00231           // Abandon current combination if successive bins of equal size 
00232           // not ordered, i.e. if previous permutation exists 
00233           if (prev_permutation(adjBins.begin(), adjBins.end())) continue;
00234         }
00235 
00236         Combination stored; 
00237         stored.push_back((*iComb)[0]);
00238         stored.push_back(second);
00239 
00240         if (stored[0].size() == sizeFirst) {
00241           combinations.push_back(stored);
00242         } else {
00243           cStack.push(stored);
00244         }
00245       }
00246     }
00247     return combinations;
00248   }
00249 
00253   std::vector<Combination> separateOneElement(const Collection & data) const
00254   {
00255     std::vector<Combination> combinations;
00256     for ( typename Collection::const_iterator i = data.begin(); i != data.end(); i++) {
00257       Combination comb;
00258       Collection single; single.push_back(*i);
00259       Collection coll; 
00260       typename Collection::const_iterator j = data.begin();
00261       for ( ; j != i; j++) { coll.push_back(*j); }
00262       j++;
00263       for ( ; j != data.end(); j++) { coll.push_back(*j); }
00264       comb.push_back(coll); comb.push_back(single);
00265       combinations.push_back(comb);
00266     }
00267     return combinations;
00268   }
00269 
00270 };
00271 
00272 #endif