C++ main module for mmsd Package  1.0
STAT_Combinatorial.hpp
Go to the documentation of this file.
1 #ifndef STAT_Combinatorial_HPP
2 #define STAT_Combinatorial_HPP
3 
4 #include <limits>
5 #include <stdexcept>
6 
7 template<class T>
9 
10 template<class T>
12 
13 template<class T>
15 
16 
17 
18 
19 // see http://howardhinnant.github.io/combinations.html
20 // for efficient code
21 
22 template<class T>
24  setType("STAT_Combinatorial");
25  mVector=null;
26  mSize=0;
27  mCount=0;
28  mFunction=COMBINATION;
29  mFirstIndex=0;
30  mLastIndex=0;
31  mDistanceIndex=0;
32  mCombinatorialList=null;
33  mIsDisplay=false;
34 }
35 
36 
37 template<class T>
39  if (mVector!=null) delete[] mVector;
40 }
41 
42 template<class T>
44 
45 
46  switch(mFunction) {
47  case COMBINATION:
48  return oneCombinationDone();
49  break;
50  case PERMUTATION:
51  return permute(mFirstIndex,mLastIndex,mDistanceIndex);
52  break;
53  case CIRCULAR_PERMUTATION:
54  if (mDistanceIndex<=1) return onePermutationDone();
55  return permute(mFirstIndex+1,mLastIndex,mDistanceIndex-1);
56  break;
57  }
58 
59 
60 
61  return false;
62 
63 }
64 template<class T>
66  cout << mCount<<": ";
67  size_t r=0;
68  T* iter=mFirstIndex;
69 
70  // print the 1st element
71  cout << *iter;
72  r++;
73  // print all the element until last Index
74  for (iter++; iter !=mLastIndex; iter++) {
75  cout << ", " << *iter;
76  r++;
77  }
78 
79  if (r<mSize) {
80  cout << " | ";
81  cout << *iter;
82  for (iter++; iter !=mEnd; iter++)
83  {
84  cout << ", " << *iter;
85  }
86  }
87  cout << "\n";
88 
89 
90 
91 }
92 
93 template <class T>
94 tBoolean STAT_Combinatorial<T>::permute_(T* first1,T* last1,const int& d1) {
95  using std::swap;
96  switch (d1) {
97  case 0:
98  case 1:
99  return onePermutationDone();
100  case 2:
101  if (onePermutationDone()) return true;
102 
103  swap(*first1, *(first1+1));
104  return onePermutationDone();
105  case 3:
106  {
107  if (onePermutationDone()) return true;
108 
109  T *f2 = first1+1;
110  T *f3 = f2+1;
111  swap(*f2, *f3);
112  if (onePermutationDone()) return true;
113 
114  swap(*first1, *f3);
115  swap(*f2, *f3);
116  if (onePermutationDone()) return true;
117 
118  swap(*f2, *f3);
119  if (onePermutationDone()) return true;
120 
121  swap(*first1, *f2);
122  swap(*f2, *f3);
123  if (onePermutationDone()) return true;
124 
125  swap(*f2, *f3);
126  return onePermutationDone();
127  }
128  }
129  T *fp1 = first1+1;
130  T *p;
131  for (p = fp1; p != last1; p++) {
132 
133  if (permute_(fp1, last1, d1-1)) return true;
134  std::reverse(fp1, last1);
135  swap(*first1, *p);
136  }
137  return permute_(fp1, last1, d1-1);
138 }
139 
140 
141 
142 template<class T>
143 tBoolean STAT_Combinatorial<T>::permute(T* first1,T* last1,const int& d1) {
144 
145 
146  using std::swap;
147  switch (d1) {
148  case 0:
149  case 1:
150  return onePermutationDone();
151  case 2:
152  {
153  if (onePermutationDone()) return true;
154  T* i = first1+1;
155  swap(*first1, *i);
156  if (onePermutationDone()) return true;
157  swap(*first1, *i);
158  }
159  break;
160  case 3:
161  {
162  if (onePermutationDone()) return true;
163  T *f2 = first1+1;
164  T *f3 = f2+1;
165  swap(*f2, *f3);
166  if (onePermutationDone()) return true;
167 
168  swap(*first1, *f3);
169  swap(*f2, *f3);
170  if (onePermutationDone()) return true;
171 
172  swap(*f2, *f3);
173  if (onePermutationDone()) return true;
174 
175  swap(*first1, *f2);
176  swap(*f2, *f3);
177  if (onePermutationDone()) return true;
178 
179  swap(*f2, *f3);
180  if (onePermutationDone()) return true;
181 
182  swap(*first1, *f3);
183  }
184  break;
185  default:
186  T* fp1 = first1+1;
187  T* p;
188  for (p = fp1; p != last1; p++)
189  {
190  if (permute_(fp1, last1, d1-1)) return true;
191  std::reverse(fp1, last1);
192  swap(*first1, *p);
193  }
194  if (permute_(fp1, last1, d1-1)) return true;
195  std::reverse(first1, last1);
196  break;
197  }
198  return false;
199 }
200 
201 
202 
203 template<class T>
205  ASSERT_IN(p>0);
206  ASSERT_IN(p<=(int)mSize);
207  mFirstIndex=&mVector[0];
208  mLastIndex=&mVector[p];
209  mDistanceIndex=p;
210  mCount=0;
211  mFunction=COMBINATION;
212  combine_discontinuous(mFirstIndex, mLastIndex, mDistanceIndex,
213  mLastIndex, mEnd, mSize-p);
214  return mCount;
215 }
216 
217 
218 
219 template<class T>
221  ASSERT_IN(p>0);
222  ASSERT_IN(p<=(int)mSize);
223  mFirstIndex=&mVector[0];
224  mLastIndex=&mVector[p];
225  mDistanceIndex=p;
226  mFunction=PERMUTATION;
227  mCount=0;
228  combine_discontinuous(mFirstIndex, mLastIndex, mDistanceIndex,
229  mLastIndex, mEnd, mSize-p);
230  return mCount;
231 }
232 template<class T>
234  ASSERT_IN(p>0);
235  ASSERT_IN(p<=(int)mSize);
236  mFirstIndex=&mVector[0];
237  mLastIndex=&mVector[p];
238  mDistanceIndex=p;
239  mFunction=CIRCULAR_PERMUTATION;
240  mCount=0;
241  combine_discontinuous(mFirstIndex, mLastIndex, mDistanceIndex,
242  mLastIndex, mEnd, mSize-p);
243  return mCount;
244 }
245 
246 
247 template<class T>
248 void STAT_Combinatorial<T>::rotate_discontinuous(T* first1, T* last1,const int& d1,
249  T* first2, T* last2,const int& d2)
250 {
251  using std::swap;
252  if (d1 <= d2)
253  std::rotate(first2, std::swap_ranges(first1, last1, first2), last2);
254  else
255  {
256  T* i1 = last1;
257  while (first2 != last2)
258  swap(*--i1, *--last2);
259  std::rotate(first1, i1, last1);
260  }
261 }
262 
263 
264 template<class T>
265 bool STAT_Combinatorial<T>::combine_discontinuous(T* first1, T* last1,const int& d1,
266  T* first2, T* last2,const int& d2,
267  const int& d)
268 {
269 
270  using std::swap;
271  if (d1 == 0 || d2 == 0)
272  return oneComputationDone();
273  if (d1 == 1)
274  {
275  T *i2=first2;
276  for ( i2= first2; i2 != last2; i2++)
277  {
278  if (oneComputationDone()) return true;
279  swap(*first1, *i2);
280  }
281  }
282  else
283  {
284  T *f1p = first1+1;
285  T *i2 = first2;
286  for (int d22 = d2; i2 != last2; ++i2, d22--)
287  {
288  if (combine_discontinuous(f1p, last1, d1-1, i2, last2, d22,d+1)) return true;
289  swap(*first1, *i2);
290  }
291  }
292  if (oneComputationDone()) return true;
293  if (d != 0)
294  rotate_discontinuous(first1, last1, d1, first2+1, last2, d2-1);
295  else
296  rotate_discontinuous(first1, last1, d1, first2, last2, d2);
297  return false;
298 }
299 template <class T>
300 template <class UINT>
301 UINT STAT_Combinatorial<T>::getCircularPermutationsNumber(const UINT& p, const UINT& n) {
302  UINT d1=p;
303  UINT d2=n-p;
304  // return d1 > 0 ? (d1+d2)!/(d1*d2!) : 1
305  if (d1 == 0)
306  return 1;
307  UINT r;
308  if (d1 <= d2)
309  {
310  try
311  {
312  r = getCombinationsNumber(d1, d1+d2);
313  }
314  catch (const std::overflow_error&)
315  {
316  throw std::overflow_error("overflow in STAT_Combinatorial::getCircularPermutationsNumber()");
317  }
318  for (--d1; d1 > 1; --d1)
319  {
320  if (r > std::numeric_limits<UINT>::max()/d1)
321  throw std::overflow_error("overflow in STAT_Combinatorial::getCircularPermutationsNumber()");
322  r *= d1;
323  }
324  }
325  else
326  { // functionally equivalent but faster algorithm
327  if (d1 > std::numeric_limits<UINT>::max() - d2)
328  throw std::overflow_error("overflow in STAT_Combinatorial::getCircularPermutationsNumber()");
329  UINT s = d1 + d2;
330  r = 1;
331  for (; s > d1; --s)
332  {
333  if (r > std::numeric_limits<UINT>::max()/s)
334  throw std::overflow_error("overflow in STAT_Combinatorial::getCircularPermutationsNumber()");
335  r *= s;
336  }
337  for (--s; s > d2; --s)
338  {
339  if (r > std::numeric_limits<UINT>::max()/s)
340  throw std::overflow_error("overflow in STAT_Combinatorial::getCircularPermutationsNumber()");
341  r *= s;
342  }
343  }
344  return r;
345 }
346 template <class T>
347 template <class UINT>
348 UINT STAT_Combinatorial<T>::getPermutationsNumber(const UINT& p, const UINT& n) {
349  UINT d1=p;
350  UINT d2=n-p;
351  // return (d1+d2)!/d2!
352  if (d1 > std::numeric_limits<UINT>::max() - d2)
353  throw std::overflow_error("overflow in STAT_Combinatorial::getPermutationsNumber");
354  UINT s = d1 + d2;
355  UINT r = 1;
356  for (; s > d2; --s)
357  {
358  if (r > std::numeric_limits<UINT>::max() / s)
359  throw std::overflow_error("overflow in STAT_Combinatorial::getPermutationsNumber");
360  r *= s;
361  }
362  return r;
363 }
364 
365 template<class T>
366 template<class UINT>
367 UINT STAT_Combinatorial<T>::getCombinationsNumber(const UINT& p,const UINT& n) {
368  UINT d1=p;
369  UINT d2=n-p;
370 
371  // return (d1+d2)!/(d1!*d2!)
372  if (d2 < d1)
373  std::swap(d1, d2);
374  if (d1 == 0)
375  return 1;
376  if (d1 > std::numeric_limits<UINT>::max() - d2)
377  throw std::overflow_error("overflow in STAT_Combinatorial::getCombinationsNumber");
378  UINT s = d1 + d2;
379  UINT r = s;
380  --s;
381  UINT k,g,t;
382  for (k = 2; k <= d1; ++k, --s) {
383  // r = r * n / k, known to not not have truncation error
384  g = greatestCommonDivisor(r, k);
385  r /= g;
386  t = s / (k / g);
387  if (r > std::numeric_limits<UINT>::max() / t)
388  throw std::overflow_error("overflow in STAT_Combinatorial::getCombinationsNumber");
389  r *= t;
390  }
391  return r;
392 
393 }
394 template<class T>
395 template<class UINT>
397  const UINT& n) {
398 
399  UINT x=p,y=n,t=0;
400  while (y != 0) {
401  t = x % y;
402  x = y;
403  y = t;
404  }
405  return x;
406 }
407 
408 #endif
void display()
display on screnn the computation
Definition: STAT_Combinatorial.hpp:65
static UINT getCircularPermutationsNumber(const UINT &p, const UINT &n)
compute the number of circular permutations to take p elements among n n!/(p*(n-p)!) ...
Definition: STAT_Combinatorial.hpp:301
STAT_Combinatorial(void)
create an object
Definition: STAT_Combinatorial.hpp:23
int computeCombinations(const int &p)
compute all combinations of size p
Definition: STAT_Combinatorial.hpp:204
#define tBoolean
Definition: types.h:48
int computePermutations(const int &p)
compute all permutations of size p
Definition: STAT_Combinatorial.hpp:220
#define null
Definition: types.h:13
virtual ~STAT_Combinatorial(void)
destroy an object.
Definition: STAT_Combinatorial.hpp:38
static UINT getPermutationsNumber(const UINT &p, const UINT &n)
compute the number of permutations to take p elements among n n!/(n-p)!
Definition: STAT_Combinatorial.hpp:348
abstract base class for most classes.
Definition: CORE_Object.h:30
This class is the class to generate combinations, permutation, etc...
Definition: STAT_Combinatorial.h:22
virtual void setType(tString type)
set the type of the object
Definition: CORE_Object.h:116
static UINT getCombinationsNumber(const UINT &p, const UINT &n)
compute the number of combinations to take p elements among n n!/(n-p)!*p!
Definition: STAT_Combinatorial.hpp:367
#define ASSERT_IN(a)
Definition: types.h:96
int computeCircularPermutations(const int &p)
compute all circular permutations of size p
Definition: STAT_Combinatorial.hpp:233
#define tFlag
Definition: types.h:14