numeric
Combinatorics.hpp
Go to the documentation of this file.
1 #ifndef __NUMERIC_COMBINATORICS_HPP__
2 #define __NUMERIC_COMBINATORICS_HPP__
3 
4 #include <algorithm>
5 #include <vector>
6 #include <map>
7 #include <set>
8 #include <string>
9 #include <stdexcept>
10 #include <stdint.h>
11 #include <math.h>
12 #include <base-logging/Logging.hpp>
13 
14 #include <iostream>
15 #include <numeric/Twiddle.hpp>
16 #include <boost/math/special_functions/binomial.hpp>
17 
18 namespace numeric {
19 
36 template <class T>
38 {
39 public:
40  typedef typename std::vector<T> ItemList;
41 
42 private:
43  ItemList mItems;
44 
45 public:
46 
51  Permutation(const std::vector<T> items)
52  : mItems(items)
53  {
54  std::sort(mItems.begin(), mItems.end());
55  }
56 
61  bool next()
62  {
63  return std::next_permutation(mItems.begin(), mItems.end());
64  }
65 
70  const ItemList& current() const
71  {
72  return mItems;
73  }
74 
79  uint64_t numberOfPermutations() const { return static_cast<uint64_t>( boost::math::factorial<double>(mItems.size()) ); }
80 };
81 
82 enum Mode { EXACT = 0, MAX, MIN };
83 extern std::map<Mode, std::string> ModeTxt;
84 
110 template <class T>
112 {
113 public:
114  typedef typename std::vector<T> ItemList;
115 
116 private:
117  std::vector<T> mItems;
118  uint32_t mSizeOfDraw;
119 
120  typedef std::vector<bool> Draw;
121  typedef std::vector< uint32_t > DrawList;
122 
123  Mode mMode;
124 
125  std::vector<T> mCurrentDraw;
126  // Keep record of items per draw -- and prevent duplicates
127  std::set< ItemList > mExistingDraws;
128 
129  int mCurrentDrawSize;
130  Twiddle mTwiddle;
131 
132  // In order to compute the power set we have to maintain a list
133  // of the draw for a corresponding combination size
134  //
135  // [a,a,b]
136  // First draw list: a b
137  // Second draw list: aa ab
138  // Third draw list: aab
139  DrawList mDrawList;
140  DrawList::const_iterator mCurrentDrawList;
141 
142 public:
149  Combination(const std::vector<T>& uniqueItems, size_t sizeOfDraw, Mode mode = EXACT)
150  : mItems(uniqueItems)
151  , mSizeOfDraw(sizeOfDraw)
152  , mMode(mode)
153  {
154  std::sort(mItems.begin(), mItems.end());
155  if(sizeOfDraw > uniqueItems.size())
156  {
157  throw std::invalid_argument("base::combinatorics::Combination: size of draw is greater than number of available items");
158  }
159 
160  uint32_t numberOfItems = mItems.size();
161  switch(mMode)
162  {
163  case EXACT:
164  {
165  createStartDraw(numberOfItems, mSizeOfDraw);
166  mDrawList.push_back(mSizeOfDraw);
167  break;
168  }
169  case MIN:
170  {
171  createStartDraw(numberOfItems, mSizeOfDraw);
172  mDrawList.push_back(mSizeOfDraw);
173 
174  for(uint32_t i = mSizeOfDraw + 1; i <= numberOfItems; ++i)
175  {
176  mDrawList.push_back(i);
177  }
178  break;
179  }
180  case MAX:
181  {
182  createStartDraw(numberOfItems, 1);
183  mDrawList.push_back(1);
184 
185  for(uint32_t i = 2; i <= mSizeOfDraw; ++i)
186  {
187  mDrawList.push_back(i);
188  }
189  break;
190  }
191  default:
192  throw std::runtime_error("Invalid type given to switch");
193 
194  }
195  mCurrentDrawList = mDrawList.begin();
196 
197  LOG_DEBUG_S << "Creating Combination: n = " << numberOfItems << ", k = " << sizeOfDraw << std::endl
198  << " expected number of combinations for (mode: " << ModeTxt[mode] << "): " << numberOfCombinations() << std::endl;
199  }
200 
201  void createStartDraw(uint32_t n, uint32_t k)
202  {
203  mCurrentDraw.clear();
204  mCurrentDrawSize = k;
205 
206  mTwiddle.init(k,n);
207 
208  for(size_t i = 0; i < n; ++i)
209  {
210  if(mTwiddle.isActivePosition(i))
211  {
212  mCurrentDraw.push_back( mItems[i]);
213  }
214  }
215 
216  mExistingDraws.clear();
217  mExistingDraws.insert(mCurrentDraw);
218  }
219 
220  bool next()
221  {
222  while(mTwiddle.next())
223  {
224  mCurrentDraw.clear();
225  for(size_t i = 0; i != mItems.size(); ++i)
226  {
227  if(mTwiddle.isActivePosition(i))
228  {
229  mCurrentDraw.push_back(mItems[i]);
230  }
231  }
232 
233  typename std::pair< typename std::set< std::vector<T> >::iterator, bool > result = mExistingDraws.insert(mCurrentDraw);
234  if(result.second)
235  {
236  return true;
237  }
238  continue;
239  }
240 
241  // Check if we have to increase the combination size, i.e.
242  // try the next draw list
243  //
244  // [a,a,b]
245  // First draw list: a b
246  // Second draw list: aa ab
247  // Third draw list: aab
248  if(mCurrentDrawList + 1 != mDrawList.end())
249  {
250  ++mCurrentDrawList;
251  createStartDraw(mItems.size(), *mCurrentDrawList);
252  return true;
253  }
254 
255  return false;
256  }
257 
258  ItemList current() const
259  {
260  return mCurrentDraw;
261  }
262 
263  uint64_t numberOfCombinations() const
264  {
265  uint32_t numberOfItems = mItems.size();
266  switch(mMode)
267  {
268  case EXACT:
269  {
270  return static_cast<uint64_t>( boost::math::binomial_coefficient<double>(numberOfItems, mSizeOfDraw) );
271  }
272  case MIN:
273  {
274  uint32_t sum = 0;
275  for(uint32_t i = mSizeOfDraw; i <= mItems.size(); ++i)
276  {
277  sum += static_cast<uint64_t>( boost::math::binomial_coefficient<double>(numberOfItems, i) );
278  }
279  return sum;
280  }
281  case MAX:
282  {
283  uint32_t sum = 0;
284  for(uint32_t i = 1; i <= mSizeOfDraw; ++i)
285  {
286  sum += static_cast<uint64_t>( boost::math::binomial_coefficient<double>(numberOfItems, i) );
287  }
288  return sum;
289  }
290  default:
291  throw std::runtime_error("Invalid type given to switch");
292  } // end switch
293  }
294 };
295 
296 } // end namespace numeric
297 #endif // __NUMERIC_COMBINATORICS_HPP__
Create permutation on a list of given types.
Definition: Combinatorics.hpp:37
Combination(const std::vector< T > &uniqueItems, size_t sizeOfDraw, Mode mode=EXACT)
Combination of a unique item map Binomialcoefficient (n k)
Definition: Combinatorics.hpp:149
Definition: Circle.hpp:6
std::vector< T > ItemList
Definition: Combinatorics.hpp:114
void createStartDraw(uint32_t n, uint32_t k)
Definition: Combinatorics.hpp:201
void init(int m, int n)
Definition: Twiddle.cpp:76
Permutation(const std::vector< T > items)
Definition: Combinatorics.hpp:51
bool next()
Definition: Combinatorics.hpp:220
Definition: Combinatorics.hpp:82
bool next()
Definition: Twiddle.cpp:21
Definition: Combinatorics.hpp:82
Twiddle algorithm – modifications applied only to simplify integration.
Definition: Twiddle.hpp:102
Mode
Definition: Combinatorics.hpp:82
uint64_t numberOfPermutations() const
Definition: Combinatorics.hpp:79
bool next()
Definition: Combinatorics.hpp:61
std::vector< T > ItemList
Definition: Combinatorics.hpp:40
std::map< Mode, std::string > ModeTxt
Definition: Combinatorics.cpp:15
Combination of a unique item map Binomialcoefficient (n k)
Definition: Combinatorics.hpp:111
bool isActivePosition(size_t position) const
Definition: Twiddle.cpp:16
uint64_t numberOfCombinations() const
Definition: Combinatorics.hpp:263
ItemList current() const
Definition: Combinatorics.hpp:258
const ItemList & current() const
Definition: Combinatorics.hpp:70
Definition: Combinatorics.hpp:82