/
githubmirror
/
cmssw
Обзор
Документация
Войти
/
githubmirror
/
cmssw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
CommonTools/Statistics/interface/CombinationGenerator.h
262 строки
9 KB
Cms Build
Clang-Format
03 июн 2019, 06:44
03 июн 2019, 06:44
6a63925
Код
Авторство
О чём код?
#ifndef _CombinationGenerator_H_ #define _CombinationGenerator_H_ #include "CommonTools/Statistics/interface/PartitionGenerator.h" #include <vector> #include <stack> #include <algorithm> #include <functional> /** Class to compute all distinct Combinations * of a collection 'data' of objects of type 'T'. * A Combination is a set of collections, each collection * containing one or more objects, with any object in 'data' * assigned to exactly one collection. */ template <class T> class CombinationGenerator { public: typedef std::vector<T> Collection; typedef std::vector<Collection> Combination; typedef std::vector<Combination> VectorOfCombinations; /** Create combinations obtained by dividing 'data' * according to all partitions with 'numberOfCollections' collections. */ std::vector<Combination> combinations(const Collection& data, int numberOfCollections) const { std::vector<Combination> combinations; Collection sorted = data; // Sort if needed if (prev_permutation(sorted.begin(), sorted.end())) { sort(sorted.begin(), sorted.end()); } // Create sorted partitions PartitionGenerator aPartitionGenerator; std::vector<std::vector<PartitionGenerator::Partition> > partitions = aPartitionGenerator.sortedPartitions(data.size()); // Use partitions of size 'numberOfCollections' only for (std::vector<PartitionGenerator::Partition>::const_iterator idiv = partitions[numberOfCollections - 1].begin(); idiv != partitions[numberOfCollections - 1].end(); idiv++) { const PartitionGenerator::Partition& partition = *idiv; std::vector<Combination> subCombinations = this->combinations(data, partition); for (typename std::vector<Combination>::const_iterator iComb = subCombinations.begin(); iComb != subCombinations.end(); iComb++) { combinations.push_back(*iComb); } } return combinations; } /** Create all combinations obtained by dividing 'data' * according to Partition 'partition'. */ std::vector<Combination> combinations(const Collection& data, const PartitionGenerator::Partition& partition) const { std::vector<Combination> combinations; // Check that sum of collection sizes in 'partition' // amounts to number of elements in 'data' int nElts = 0; for (PartitionGenerator::Partition::const_iterator iSize = partition.begin(); iSize != partition.end(); iSize++) { nElts += *iSize; } if (nElts != data.size()) return combinations; Collection sortedData = data; // Sort if needed if (prev_permutation(sortedData.begin(), sortedData.end())) { sort(sortedData.begin(), sortedData.end()); } // Create initial combination and put it on the stack Combination comb; comb.push_back(sortedData); if (partition.size() == 1) { // Return only one combination with only one collection combinations.push_back(comb); return combinations; } std::stack<Combination> cStack; cStack.push(comb); // Sort partitions by size // Let 'sortedPartition' = ( n0, n1,... nk, nk+1,... nm ) // Ordering is >= to speed up partitioning: n0 >= n1 >=... >= nm PartitionGenerator::Partition sortedPartition = partition; sort(sortedPartition.begin(), sortedPartition.end(), std::greater_equal<int>()); while (!cStack.empty()) { // 'combination' popped out of the stack Combination combination = cStack.top(); cStack.pop(); // At this stage 'combination' is made of collections // of sizes ( n0+n1+...+nk, nk+1,... nm ) // Now generate all combinations obtained by splitting // the first collection of 'combination' in two, // according to Partition 'biPartition' = (n0+n1+...+nk-1, nk) int k = sortedPartition.size() - combination.size(); int size = 0; for (int iColl = 0; iColl != k; iColl++) { size += sortedPartition[iColl]; } PartitionGenerator::Partition biPartition(2); biPartition[0] = size; biPartition[1] = sortedPartition[k]; VectorOfCombinations subCombinations = splitInTwoCollections(combination[0], biPartition[0]); for (typename std::vector<Combination>::const_iterator iComb = subCombinations.begin(); iComb != subCombinations.end(); iComb++) { // Check ordering of successive bins of equal size if (combination.size() > 1) { if ((*iComb)[1].size() == combination[1].size()) { Collection adjBins; adjBins.push_back((*iComb)[1][0]); adjBins.push_back(combination[1][0]); // Drop 'combination' if successive bins of equal size not ordered // i.e. if previous permutation exists if (prev_permutation(adjBins.begin(), adjBins.end())) continue; } } // Append remaining collections of 'combination' Combination merged = *iComb; typename Combination::const_iterator it = combination.begin(); it++; for (; it != combination.end(); it++) { merged.push_back(*it); } // Store combination 'merged' if partitioning is complete, // otherwise put it on the stack for further partitioning. if (merged.size() == sortedPartition.size()) { combinations.push_back(merged); } else { cStack.push(merged); } } } return combinations; } /** Create all combinations of elements from 'data'. */ std::vector<Combination> combinations(const Collection& data) const { std::vector<Combination> combinations; Collection sorted = data; // Sort if needed if (prev_permutation(sorted.begin(), sorted.end())) { sort(sorted.begin(), sorted.end()); } PartitionGenerator aPartitionGenerator; std::vector<PartitionGenerator::Partition> partitions = aPartitionGenerator.partitions(data.size()); for (std::vector<PartitionGenerator::Partition>::const_iterator idiv = partitions.begin(); idiv != partitions.end(); idiv++) { const PartitionGenerator::Partition& partition = *idiv; std::vector<Combination> subCombinations = this->combinations(data, partition); for (typename std::vector<Combination>::const_iterator iComb = subCombinations.begin(); iComb != subCombinations.end(); iComb++) { combinations.push_back(*iComb); } } return combinations; } private: /** Create all combinations obtained by dividing 'data' * in two collections, the first one being of size 'sizeFirst' */ VectorOfCombinations splitInTwoCollections(const Collection& data, int sizeFirst) const { std::vector<Combination> combinations; std::stack<Combination> cStack; // Create first combination with 2 partitions Combination comb; comb.push_back(data); comb.push_back(Collection()); cStack.push(comb); while (!cStack.empty()) { Combination combination = cStack.top(); cStack.pop(); Collection collection = combination[0]; std::vector<Combination> subCombinations = separateOneElement(collection); for (typename std::vector<Combination>::const_iterator iComb = subCombinations.begin(); iComb != subCombinations.end(); iComb++) { Collection second = combination[1]; second.push_back((*iComb)[1][0]); // Abandon current combination if not ordered, // i.e. if previous permutation exists bool ordered = !prev_permutation(second.begin(), second.end()); if (!ordered) continue; next_permutation(second.begin(), second.end()); if ((*iComb)[0].size() == second.size()) { Collection adjBins; adjBins.push_back((*iComb)[0][0]); adjBins.push_back(second[0]); // Abandon current combination if successive bins of equal size // not ordered, i.e. if previous permutation exists if (prev_permutation(adjBins.begin(), adjBins.end())) continue; } Combination stored; stored.push_back((*iComb)[0]); stored.push_back(second); if (stored[0].size() == sizeFirst) { combinations.push_back(stored); } else { cStack.push(stored); } } } return combinations; } /** Create all combinations obtained by dividing 'data' in two collections, * the second one having only one element. */ std::vector<Combination> separateOneElement(const Collection& data) const { std::vector<Combination> combinations; for (typename Collection::const_iterator i = data.begin(); i != data.end(); i++) { Combination comb; Collection single; single.push_back(*i); Collection coll; typename Collection::const_iterator j = data.begin(); for (; j != i; j++) { coll.push_back(*j); } j++; for (; j != data.end(); j++) { coll.push_back(*j); } comb.push_back(coll); comb.push_back(single); combinations.push_back(comb); } return combinations; } }; #endif